aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/3c501.c2
-rw-r--r--drivers/net/3c505.c2
-rw-r--r--drivers/net/3c507.c2
-rw-r--r--drivers/net/3c509.c2
-rw-r--r--drivers/net/3c515.c4
-rw-r--r--drivers/net/3c523.c2
-rw-r--r--drivers/net/3c527.c4
-rw-r--r--drivers/net/3c59x.c4
-rw-r--r--drivers/net/7990.c2
-rw-r--r--drivers/net/8139cp.c2
-rw-r--r--drivers/net/8139too.c4
-rw-r--r--drivers/net/82596.c4
-rw-r--r--drivers/net/a2065.c4
-rw-r--r--drivers/net/amd8111e.c2
-rw-r--r--drivers/net/appletalk/cops.c2
-rw-r--r--drivers/net/appletalk/ipddp.c4
-rw-r--r--drivers/net/appletalk/ltpc.c2
-rw-r--r--drivers/net/ariadne.c4
-rw-r--r--drivers/net/arm/am79c961a.c2
-rw-r--r--drivers/net/arm/at91_ether.c2
-rw-r--r--drivers/net/arm/ether1.c2
-rw-r--r--drivers/net/arm/ether3.c4
-rw-r--r--drivers/net/at1700.c2
-rw-r--r--drivers/net/atarilance.c4
-rw-r--r--drivers/net/atp.c2
-rw-r--r--drivers/net/au1000_eth.c2
-rw-r--r--drivers/net/b44.c8
-rw-r--r--drivers/net/benet/Kconfig1
-rw-r--r--drivers/net/benet/be.h11
-rw-r--r--drivers/net/benet/be_ethtool.c9
-rw-r--r--drivers/net/benet/be_main.c104
-rw-r--r--drivers/net/bfin_mac.c2
-rw-r--r--drivers/net/bmac.c2
-rw-r--r--drivers/net/bnx2.c19
-rw-r--r--drivers/net/bnx2x.h3
-rw-r--r--drivers/net/bnx2x_hsi.h40
-rw-r--r--drivers/net/bnx2x_link.c1100
-rw-r--r--drivers/net/bnx2x_link.h14
-rw-r--r--drivers/net/bnx2x_main.c265
-rw-r--r--drivers/net/bnx2x_reg.h33
-rw-r--r--drivers/net/bonding/bond_3ad.c5
-rw-r--r--drivers/net/bonding/bond_alb.c2
-rw-r--r--drivers/net/bonding/bond_main.c8
-rw-r--r--drivers/net/can/Kconfig7
-rw-r--r--drivers/net/can/sja1000/ems_pci.c152
-rw-r--r--drivers/net/can/sja1000/sja1000.c2
-rw-r--r--drivers/net/cassini.c4
-rw-r--r--drivers/net/cris/eth_v10.c2
-rw-r--r--drivers/net/cs89x0.c4
-rw-r--r--drivers/net/cxgb3/adapter.h10
-rw-r--r--drivers/net/cxgb3/ael1002.c1193
-rw-r--r--drivers/net/cxgb3/aq100x.c7
-rw-r--r--drivers/net/cxgb3/common.h10
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c99
-rw-r--r--drivers/net/cxgb3/t3_hw.c2
-rw-r--r--drivers/net/cxgb3/xgmac.c11
-rw-r--r--drivers/net/de600.c2
-rw-r--r--drivers/net/de620.c2
-rw-r--r--drivers/net/declance.c4
-rw-r--r--drivers/net/defxx.c6
-rw-r--r--drivers/net/depca.c2
-rw-r--r--drivers/net/dm9000.c127
-rw-r--r--drivers/net/dm9000.h18
-rw-r--r--drivers/net/dnet.c2
-rw-r--r--drivers/net/dummy.c2
-rw-r--r--drivers/net/e100.c2
-rw-r--r--drivers/net/e1000/e1000.h7
-rw-r--r--drivers/net/e1000/e1000_ethtool.c51
-rw-r--r--drivers/net/e1000/e1000_hw.c2
-rw-r--r--drivers/net/e1000/e1000_hw.h3
-rw-r--r--drivers/net/e1000/e1000_main.c483
-rw-r--r--drivers/net/eepro.c4
-rw-r--r--drivers/net/eexpress.c4
-rw-r--r--drivers/net/enc28j60.c2
-rw-r--r--drivers/net/epic100.c4
-rw-r--r--drivers/net/eql.c2
-rw-r--r--drivers/net/eth16i.c4
-rw-r--r--drivers/net/ethoc.c2
-rw-r--r--drivers/net/ewrk3.c2
-rw-r--r--drivers/net/fealnx.c2
-rw-r--r--drivers/net/fec.c2
-rw-r--r--drivers/net/fs_enet/mii-fec.c37
-rw-r--r--drivers/net/gianfar.c1
-rw-r--r--drivers/net/hamachi.c2
-rw-r--r--drivers/net/hamradio/6pack.c2
-rw-r--r--drivers/net/hamradio/baycom_epp.c6
-rw-r--r--drivers/net/hamradio/bpqether.c2
-rw-r--r--drivers/net/hamradio/dmascc.c2
-rw-r--r--drivers/net/hamradio/hdlcdrv.c4
-rw-r--r--drivers/net/hamradio/mkiss.c2
-rw-r--r--drivers/net/hamradio/scc.c6
-rw-r--r--drivers/net/hamradio/yam.c2
-rw-r--r--drivers/net/hp100.c6
-rw-r--r--drivers/net/ibm_newemac/core.c2
-rw-r--r--drivers/net/ibmveth.c2
-rw-r--r--drivers/net/ifb.c2
-rw-r--r--drivers/net/igb/e1000_82575.c193
-rw-r--r--drivers/net/igb/e1000_82575.h6
-rw-r--r--drivers/net/igb/e1000_defines.h8
-rw-r--r--drivers/net/igb/e1000_hw.h18
-rw-r--r--drivers/net/igb/e1000_mac.c175
-rw-r--r--drivers/net/igb/e1000_mac.h3
-rw-r--r--drivers/net/igb/e1000_phy.c4
-rw-r--r--drivers/net/igb/e1000_regs.h1
-rw-r--r--drivers/net/igb/igb_ethtool.c65
-rw-r--r--drivers/net/igb/igb_main.c121
-rw-r--r--drivers/net/igbvf/netdev.c5
-rw-r--r--drivers/net/ioc3-eth.c2
-rw-r--r--drivers/net/irda/ali-ircc.c12
-rw-r--r--drivers/net/irda/au1k_ir.c4
-rw-r--r--drivers/net/irda/donauboe.c8
-rw-r--r--drivers/net/irda/irda-usb.c2
-rw-r--r--drivers/net/irda/nsc-ircc.c10
-rw-r--r--drivers/net/irda/pxaficp_ir.c4
-rw-r--r--drivers/net/irda/sa1100_ir.c4
-rw-r--r--drivers/net/irda/sir_dev.c6
-rw-r--r--drivers/net/irda/smsc-ircc2.c16
-rw-r--r--drivers/net/irda/stir4200.c2
-rw-r--r--drivers/net/irda/via-ircc.c12
-rw-r--r--drivers/net/irda/vlsi_ir.c6
-rw-r--r--drivers/net/irda/w83977af_ir.c4
-rw-r--r--drivers/net/isa-skeleton.c2
-rw-r--r--drivers/net/iseries_veth.c4
-rw-r--r--drivers/net/ixgb/ixgb_main.c2
-rw-r--r--drivers/net/ixgbe/ixgbe.h4
-rw-r--r--drivers/net/ixgbe/ixgbe_82598.c1
-rw-r--r--drivers/net/ixgbe/ixgbe_ethtool.c33
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c12
-rw-r--r--drivers/net/ixgbe/ixgbe_type.h32
-rw-r--r--drivers/net/ixp2000/ixpdev.c4
-rw-r--r--drivers/net/jazzsonic.c4
-rw-r--r--drivers/net/jme.c189
-rw-r--r--drivers/net/jme.h21
-rw-r--r--drivers/net/lance.c2
-rw-r--r--drivers/net/lib82596.c4
-rw-r--r--drivers/net/lib8390.c2
-rw-r--r--drivers/net/ll_temac_main.c2
-rw-r--r--drivers/net/loopback.c2
-rw-r--r--drivers/net/lp486e.c4
-rw-r--r--drivers/net/mac89x0.c2
-rw-r--r--drivers/net/macb.c2
-rw-r--r--drivers/net/mace.c2
-rw-r--r--drivers/net/meth.c4
-rw-r--r--drivers/net/mipsnet.c2
-rw-r--r--drivers/net/mlx4/en_tx.c2
-rw-r--r--drivers/net/myri10ge/myri10ge.c10
-rw-r--r--drivers/net/myri_sbus.c2
-rw-r--r--drivers/net/natsemi.c2
-rw-r--r--drivers/net/netx-eth.c2
-rw-r--r--drivers/net/netxen/netxen_nic.h177
-rw-r--r--drivers/net/netxen/netxen_nic_ctx.c6
-rw-r--r--drivers/net/netxen/netxen_nic_ethtool.c81
-rw-r--r--drivers/net/netxen/netxen_nic_hdr.h2
-rw-r--r--drivers/net/netxen/netxen_nic_hw.c28
-rw-r--r--drivers/net/netxen/netxen_nic_init.c130
-rw-r--r--drivers/net/netxen/netxen_nic_main.c588
-rw-r--r--drivers/net/ni5010.c2
-rw-r--r--drivers/net/ni52.c4
-rw-r--r--drivers/net/ni65.c2
-rw-r--r--drivers/net/pci-skeleton.c2
-rw-r--r--drivers/net/pcmcia/3c574_cs.c2
-rw-r--r--drivers/net/pcmcia/3c589_cs.c2
-rw-r--r--drivers/net/pcmcia/axnet_cs.c2
-rw-r--r--drivers/net/pcmcia/fmvj18x_cs.c4
-rw-r--r--drivers/net/pcmcia/nmclan_cs.c2
-rw-r--r--drivers/net/pcmcia/smc91c92_cs.c6
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c4
-rw-r--r--drivers/net/pcnet32.c2
-rw-r--r--drivers/net/phy/Kconfig6
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/bcm63xx.c132
-rw-r--r--drivers/net/plip.c2
-rw-r--r--drivers/net/ppp_generic.c4
-rw-r--r--drivers/net/r6040.c4
-rw-r--r--drivers/net/rionet.c7
-rw-r--r--drivers/net/rrunner.c2
-rw-r--r--drivers/net/s2io.c10
-rw-r--r--drivers/net/sb1000.c2
-rw-r--r--drivers/net/sb1250-mac.c4
-rw-r--r--drivers/net/seeq8005.c4
-rw-r--r--drivers/net/sgiseeq.c6
-rw-r--r--drivers/net/sh_eth.c2
-rw-r--r--drivers/net/sis900.c2
-rw-r--r--drivers/net/skfp/skfddi.c4
-rw-r--r--drivers/net/sky2.c2
-rw-r--r--drivers/net/slip.c6
-rw-r--r--drivers/net/smc911x.c6
-rw-r--r--drivers/net/smc9194.c8
-rw-r--r--drivers/net/smc91x.c4
-rw-r--r--drivers/net/sonic.c4
-rw-r--r--drivers/net/starfire.c2
-rw-r--r--drivers/net/sun3_82586.c4
-rw-r--r--drivers/net/sun3lance.c4
-rw-r--r--drivers/net/sunbmac.c2
-rw-r--r--drivers/net/sundance.c2
-rw-r--r--drivers/net/sunhme.c2
-rw-r--r--drivers/net/sunlance.c2
-rw-r--r--drivers/net/sunqe.c2
-rw-r--r--drivers/net/tc35815.c2
-rw-r--r--drivers/net/tlan.c6
-rw-r--r--drivers/net/tokenring/3c359.c2
-rw-r--r--drivers/net/tokenring/ibmtr.c2
-rw-r--r--drivers/net/tokenring/lanstreamer.c2
-rw-r--r--drivers/net/tokenring/olympic.c2
-rw-r--r--drivers/net/tokenring/smctr.c2
-rw-r--r--drivers/net/tokenring/tms380tr.c2
-rw-r--r--drivers/net/tulip/de2104x.c2
-rw-r--r--drivers/net/tulip/dmfe.c4
-rw-r--r--drivers/net/tulip/tulip_core.c2
-rw-r--r--drivers/net/tulip/uli526x.c4
-rw-r--r--drivers/net/tulip/winbond-840.c2
-rw-r--r--drivers/net/tulip/xircom_cb.c2
-rw-r--r--drivers/net/tun.c18
-rw-r--r--drivers/net/typhoon.c2
-rw-r--r--drivers/net/ucc_geth.c42
-rw-r--r--drivers/net/ucc_geth.h2
-rw-r--r--drivers/net/usb/catc.c2
-rw-r--r--drivers/net/usb/hso.c2
-rw-r--r--drivers/net/usb/kaweth.c4
-rw-r--r--drivers/net/usb/pegasus.c2
-rw-r--r--drivers/net/usb/rtl8150.c2
-rw-r--r--drivers/net/usb/usbnet.c14
-rw-r--r--drivers/net/veth.c7
-rw-r--r--drivers/net/via-rhine.c6
-rw-r--r--drivers/net/via-velocity.c3431
-rw-r--r--drivers/net/via-velocity.h6
-rw-r--r--drivers/net/virtio_net.c3
-rw-r--r--drivers/net/vxge/vxge-config.c10
-rw-r--r--drivers/net/vxge/vxge-config.h10
-rw-r--r--drivers/net/vxge/vxge-main.c100
-rw-r--r--drivers/net/vxge/vxge-main.h4
-rw-r--r--drivers/net/vxge/vxge-reg.h9
-rw-r--r--drivers/net/vxge/vxge-traffic.h2
-rw-r--r--drivers/net/vxge/vxge-version.h2
-rw-r--r--drivers/net/wan/cycx_x25.c2
-rw-r--r--drivers/net/wan/dlci.c4
-rw-r--r--drivers/net/wan/dscc4.c2
-rw-r--r--drivers/net/wan/farsync.c27
-rw-r--r--drivers/net/wan/hdlc_fr.c6
-rw-r--r--drivers/net/wan/lmc/lmc_main.c2
-rw-r--r--drivers/net/wan/sbni.c4
-rw-r--r--drivers/net/wan/wanxl.c2
-rw-r--r--drivers/net/wan/x25_asy.c10
-rw-r--r--drivers/net/wimax/i2400m/sdio.c12
-rw-r--r--drivers/net/wireless/Kconfig6
-rw-r--r--drivers/net/wireless/adm8211.c20
-rw-r--r--drivers/net/wireless/airo.c14
-rw-r--r--drivers/net/wireless/arlan-main.c4
-rw-r--r--drivers/net/wireless/at76c50x-usb.c3
-rw-r--r--drivers/net/wireless/ath/ar9170/ar9170.h52
-rw-r--r--drivers/net/wireless/ath/ar9170/main.c615
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h21
-rw-r--r--drivers/net/wireless/ath/ath5k/attach.c3
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c130
-rw-r--r--drivers/net/wireless/ath/ath5k/base.h10
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.c8
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c7
-rw-r--r--drivers/net/wireless/ath/ath5k/qcu.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/reg.h12
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h50
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c15
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.c13
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c10
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.c22
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c72
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h18
-rw-r--r--drivers/net/wireless/ath/ath9k/initvals.h47
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c30
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c97
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.c609
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.h29
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c92
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h93
-rw-r--r--drivers/net/wireless/ath/ath9k/virtual.c17
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c107
-rw-r--r--drivers/net/wireless/ath/regd.c2
-rw-r--r--drivers/net/wireless/atmel.c6
-rw-r--r--drivers/net/wireless/b43/main.c4
-rw-r--r--drivers/net/wireless/b43/xmit.c3
-rw-r--r--drivers/net/wireless/b43legacy/xmit.c3
-rw-r--r--drivers/net/wireless/hostap/hostap_80211_tx.c42
-rw-r--r--drivers/net/wireless/hostap/hostap_cs.c3
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c13
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_tx.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-hw.h7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-rs.c24
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c58
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c69
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c89
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c16
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c239
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-calib.c7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c487
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h21
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h22
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c78
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h36
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-helpers.h21
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.c34
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c13
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c31
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c19
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c22
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c177
-rw-r--r--drivers/net/wireless/iwmc3200wifi/cfg80211.c373
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.c148
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.h7
-rw-r--r--drivers/net/wireless/iwmc3200wifi/eeprom.c4
-rw-r--r--drivers/net/wireless/iwmc3200wifi/fw.c21
-rw-r--r--drivers/net/wireless/iwmc3200wifi/hal.c16
-rw-r--r--drivers/net/wireless/iwmc3200wifi/iwm.h37
-rw-r--r--drivers/net/wireless/iwmc3200wifi/lmac.h4
-rw-r--r--drivers/net/wireless/iwmc3200wifi/main.c45
-rw-r--r--drivers/net/wireless/iwmc3200wifi/netdev.c27
-rw-r--r--drivers/net/wireless/iwmc3200wifi/rx.c132
-rw-r--r--drivers/net/wireless/iwmc3200wifi/sdio.c10
-rw-r--r--drivers/net/wireless/iwmc3200wifi/sdio.h3
-rw-r--r--drivers/net/wireless/iwmc3200wifi/umac.h8
-rw-r--r--drivers/net/wireless/iwmc3200wifi/wext.c618
-rw-r--r--drivers/net/wireless/libertas/assoc.c16
-rw-r--r--drivers/net/wireless/libertas/dev.h1
-rw-r--r--drivers/net/wireless/libertas/if_cs.c3
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c5
-rw-r--r--drivers/net/wireless/libertas/if_spi.c8
-rw-r--r--drivers/net/wireless/libertas/if_usb.c3
-rw-r--r--drivers/net/wireless/libertas/wext.c2
-rw-r--r--drivers/net/wireless/libertas_tf/main.c3
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c91
-rw-r--r--drivers/net/wireless/mwl8k.c9
-rw-r--r--drivers/net/wireless/netwave_cs.c2
-rw-r--r--drivers/net/wireless/orinoco/Kconfig1
-rw-r--r--drivers/net/wireless/orinoco/Makefile2
-rw-r--r--drivers/net/wireless/orinoco/airport.c98
-rw-r--r--drivers/net/wireless/orinoco/cfg.c162
-rw-r--r--drivers/net/wireless/orinoco/cfg.h15
-rw-r--r--drivers/net/wireless/orinoco/fw.c41
-rw-r--r--drivers/net/wireless/orinoco/hermes.c2
-rw-r--r--drivers/net/wireless/orinoco/hermes.h2
-rw-r--r--drivers/net/wireless/orinoco/hermes_dld.c50
-rw-r--r--drivers/net/wireless/orinoco/hw.c668
-rw-r--r--drivers/net/wireless/orinoco/hw.h11
-rw-r--r--drivers/net/wireless/orinoco/main.c1132
-rw-r--r--drivers/net/wireless/orinoco/main.h3
-rw-r--r--drivers/net/wireless/orinoco/orinoco.h49
-rw-r--r--drivers/net/wireless/orinoco/orinoco_cs.c96
-rw-r--r--drivers/net/wireless/orinoco/orinoco_nortel.c38
-rw-r--r--drivers/net/wireless/orinoco/orinoco_pci.c38
-rw-r--r--drivers/net/wireless/orinoco/orinoco_pci.h57
-rw-r--r--drivers/net/wireless/orinoco/orinoco_plx.c38
-rw-r--r--drivers/net/wireless/orinoco/orinoco_tmd.c38
-rw-r--r--drivers/net/wireless/orinoco/scan.c291
-rw-r--r--drivers/net/wireless/orinoco/scan.h21
-rw-r--r--drivers/net/wireless/orinoco/spectrum_cs.c96
-rw-r--r--drivers/net/wireless/orinoco/wext.c878
-rw-r--r--drivers/net/wireless/p54/Makefile3
-rw-r--r--drivers/net/wireless/p54/eeprom.c753
-rw-r--r--drivers/net/wireless/p54/eeprom.h226
-rw-r--r--drivers/net/wireless/p54/fwio.c715
-rw-r--r--drivers/net/wireless/p54/led.c163
-rw-r--r--drivers/net/wireless/p54/lmac.h558
-rw-r--r--drivers/net/wireless/p54/main.c637
-rw-r--r--drivers/net/wireless/p54/p54.h151
-rw-r--r--drivers/net/wireless/p54/p54common.c2688
-rw-r--r--drivers/net/wireless/p54/p54common.h644
-rw-r--r--drivers/net/wireless/p54/p54pci.c9
-rw-r--r--drivers/net/wireless/p54/p54spi.c50
-rw-r--r--drivers/net/wireless/p54/p54usb.c42
-rw-r--r--drivers/net/wireless/p54/txrx.c860
-rw-r--r--drivers/net/wireless/prism54/islpci_eth.c2
-rw-r--r--drivers/net/wireless/prism54/islpci_hotplug.c4
-rw-r--r--drivers/net/wireless/ray_cs.c6
-rw-r--r--drivers/net/wireless/rndis_wlan.c298
-rw-r--r--drivers/net/wireless/rt2x00/Kconfig8
-rw-r--r--drivers/net/wireless/rt2x00/Makefile1
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c8
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c8
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c8
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c16
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h20
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00config.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00crypto.c8
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c8
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h21
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00link.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c26
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.h10
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00reg.h4
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00rfkill.c127
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c10
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c8
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.h4
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180_dev.c5
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_dev.c3
-rw-r--r--drivers/net/wireless/strip.c2
-rw-r--r--drivers/net/wireless/wavelan.c2
-rw-r--r--drivers/net/wireless/wavelan_cs.c4
-rw-r--r--drivers/net/wireless/wl12xx/Kconfig17
-rw-r--r--drivers/net/wireless/wl12xx/Makefile9
-rw-r--r--drivers/net/wireless/wl12xx/acx.c689
-rw-r--r--drivers/net/wireless/wl12xx/cmd.c353
-rw-r--r--drivers/net/wireless/wl12xx/reg.h1
-rw-r--r--drivers/net/wireless/wl12xx/wl1251.h479
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_acx.c840
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_acx.h (renamed from drivers/net/wireless/wl12xx/acx.h)199
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_boot.c (renamed from drivers/net/wireless/wl12xx/boot.c)114
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_boot.h (renamed from drivers/net/wireless/wl12xx/boot.h)12
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_cmd.c428
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_cmd.h (renamed from drivers/net/wireless/wl12xx/cmd.h)194
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_debugfs.c (renamed from drivers/net/wireless/wl12xx/debugfs.c)60
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_debugfs.h (renamed from drivers/net/wireless/wl12xx/debugfs.h)16
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_event.c (renamed from drivers/net/wireless/wl12xx/event.c)54
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_event.h (renamed from drivers/net/wireless/wl12xx/event.h)12
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_init.c (renamed from drivers/net/wireless/wl12xx/init.c)78
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_init.h (renamed from drivers/net/wireless/wl12xx/init.h)27
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_main.c (renamed from drivers/net/wireless/wl12xx/main.c)659
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_netlink.h30
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_ops.c (renamed from drivers/net/wireless/wl12xx/wl1251.c)299
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_ops.h165
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_ps.c (renamed from drivers/net/wireless/wl12xx/ps.c)64
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_ps.h (renamed from drivers/net/wireless/wl12xx/ps.h)18
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_rx.c (renamed from drivers/net/wireless/wl12xx/rx.c)90
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_rx.h (renamed from drivers/net/wireless/wl12xx/rx.h)24
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_spi.c (renamed from drivers/net/wireless/wl12xx/spi.c)179
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_spi.h (renamed from drivers/net/wireless/wl12xx/spi.h)62
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_tx.c (renamed from drivers/net/wireless/wl12xx/tx.c)124
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_tx.h (renamed from drivers/net/wireless/wl12xx/tx.h)21
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h409
-rw-r--r--drivers/net/wireless/wl3501_cs.c3
-rw-r--r--drivers/net/wireless/zd1201.c4
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c3
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c74
-rw-r--r--drivers/net/xen-netfront.c4
-rw-r--r--drivers/net/xtsonic.c2
-rw-r--r--drivers/net/yellowfin.c4
-rw-r--r--drivers/net/znet.c4
449 files changed, 17696 insertions, 15634 deletions
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index 367bec63620c..e29fb1a4a611 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -485,7 +485,7 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (el_debug > 2)
pr_debug(" queued xmit.\n");
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* A receive upset our load, despite our best efforts */
if (el_debug > 2)
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index f71b35402755..7bba480d7220 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -1101,7 +1101,7 @@ static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev)
prime_rx(dev);
spin_unlock_irqrestore(&adapter->lock, flags);
netif_start_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
/******************************************************
diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c
index 96b86659381a..9e93a0b39b6e 100644
--- a/drivers/net/3c507.c
+++ b/drivers/net/3c507.c
@@ -537,7 +537,7 @@ static int el16_send_packet (struct sk_buff *skb, struct net_device *dev)
/* You might need to clean up and record Tx statistics here. */
- return 0;
+ return NETDEV_TX_OK;
}
/* The typical workload of the driver:
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index d2137efbd455..d2515d840c00 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -892,7 +892,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
}
}
- return 0;
+ return NETDEV_TX_OK;
}
/* The EL3 interrupt handler. */
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index 4a7c32895be5..3116410b3499 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -1056,7 +1056,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
netif_wake_queue(dev);
}
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
/* Put out the doubleword header... */
outl(skb->len, ioaddr + TX_FIFO);
@@ -1119,7 +1119,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
}
}
- return 0;
+ return NETDEV_TX_OK;
}
/* The interrupt handler does all of the Rx thread work and cleans up
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index cdd955c4014c..70c701b80d99 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -1198,7 +1198,7 @@ static int elmc_send_packet(struct sk_buff *skb, struct net_device *dev)
netif_wake_queue(dev);
dev_kfree_skb(skb);
#endif
- return 0;
+ return NETDEV_TX_OK;
}
/*******************************************
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
index aaa8a9f405d4..72b9ed7f4641 100644
--- a/drivers/net/3c527.c
+++ b/drivers/net/3c527.c
@@ -1035,7 +1035,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev)
if (skb_padto(skb, ETH_ZLEN)) {
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
atomic_dec(&lp->tx_count);
@@ -1066,7 +1066,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev)
p->control &= ~CONTROL_EOL;
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index c34aee91250b..202048450eed 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -2083,7 +2083,7 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
iowrite8(0x00, ioaddr + TxStatus); /* Pop the status stack. */
}
}
- return 0;
+ return NETDEV_TX_OK;
}
static int
@@ -2173,7 +2173,7 @@ 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 0;
+ return NETDEV_TX_OK;
}
/* The interrupt handler does all of the Rx thread work and cleans up
diff --git a/drivers/net/7990.c b/drivers/net/7990.c
index 69f5b7d298a6..b1e5764628c6 100644
--- a/drivers/net/7990.c
+++ b/drivers/net/7990.c
@@ -585,7 +585,7 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
lp->tx_full = 1;
spin_unlock_irqrestore (&lp->devlock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
EXPORT_SYMBOL_GPL(lance_start_xmit);
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 50efde11ea6c..07919d0877ee 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -891,7 +891,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
cpw8(TxPoll, NormalTxPoll);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
/* Set or clear the multicast filter for this adaptor.
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 0e2ba21d4441..b39ec98345ea 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -1707,7 +1707,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
} else {
dev_kfree_skb(skb);
dev->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
spin_lock_irqsave(&tp->lock, flags);
@@ -1732,7 +1732,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
pr_debug("%s: Queued Tx packet size %u to slot %d.\n",
dev->name, len, entry);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index 77547545509b..996cc9102215 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -1068,7 +1068,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->len < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
netif_stop_queue(dev);
@@ -1110,7 +1110,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_start_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
static void print_eth(unsigned char *add, char *str)
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index 85a18175730b..7302e4385bc4 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -553,11 +553,11 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
volatile struct lance_regs *ll = lp->ll;
volatile struct lance_init_block *ib = lp->init_block;
int entry, skblen;
- int status = 0;
+ int status = NETDEV_TX_OK;
unsigned long flags;
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
skblen = max_t(unsigned, skb->len, ETH_ZLEN);
local_irq_save(flags);
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
index 19831bd64016..61ac671f97bf 100644
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -1346,7 +1346,7 @@ static int amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev)
netif_stop_queue(dev);
}
spin_unlock_irqrestore(&lp->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/*
This function returns all the memory mapped registers of the device.
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
index 7f8325419803..29b279f88efb 100644
--- a/drivers/net/appletalk/cops.c
+++ b/drivers/net/appletalk/cops.c
@@ -920,7 +920,7 @@ static int cops_send_packet(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_bytes += skb->len;
dev->trans_start = jiffies;
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c
index 78cea5e80b1d..6cfd961bb8de 100644
--- a/drivers/net/appletalk/ipddp.c
+++ b/drivers/net/appletalk/ipddp.c
@@ -132,7 +132,7 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
}
if(rt == NULL) {
spin_unlock(&ipddp_route_lock);
- return 0;
+ return NETDEV_TX_OK;
}
our_addr = atalk_find_dev_addr(rt->dev);
@@ -181,7 +181,7 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock(&ipddp_route_lock);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
index b642647170be..c80fb9cf8ffa 100644
--- a/drivers/net/appletalk/ltpc.c
+++ b/drivers/net/appletalk/ltpc.c
@@ -932,7 +932,7 @@ static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_bytes += skb->len;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* initialization stuff */
diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c
index 58e8d522e5bc..47d976cc3d7d 100644
--- a/drivers/net/ariadne.c
+++ b/drivers/net/ariadne.c
@@ -610,7 +610,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->len < ETH_ZLEN)
{
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
len = ETH_ZLEN;
}
@@ -685,7 +685,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
local_irq_restore(flags);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
index 627bc75da17d..164b37e85eea 100644
--- a/drivers/net/arm/am79c961a.c
+++ b/drivers/net/arm/am79c961a.c
@@ -482,7 +482,7 @@ am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
index 5041d10bae9d..c8bc60a7040c 100644
--- a/drivers/net/arm/at91_ether.c
+++ b/drivers/net/arm/at91_ether.c
@@ -834,7 +834,7 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
we free and return(0) or don't free and return 1 */
}
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c
index edf770f639fa..e47c0d962857 100644
--- a/drivers/net/arm/ether1.c
+++ b/drivers/net/arm/ether1.c
@@ -748,7 +748,7 @@ ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
out:
- return 0;
+ return NETDEV_TX_OK;
}
static void
diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c
index 455037134aa3..1f7a69c929a6 100644
--- a/drivers/net/arm/ether3.c
+++ b/drivers/net/arm/ether3.c
@@ -511,7 +511,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
priv(dev)->stats.tx_dropped ++;
netif_start_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
length = (length + 1) & ~1;
@@ -562,7 +562,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
out:
- return 0;
+ return NETDEV_TX_OK;
}
static irqreturn_t
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index cf30e278f182..5349c58d1fae 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -643,7 +643,7 @@ static int net_send_packet (struct sk_buff *skb, struct net_device *dev)
netif_start_queue (dev);
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* The typical workload of the driver:
diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c
index 5425ab0c38c0..0c0deceb6938 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/atarilance.c
@@ -796,7 +796,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
if (len > skb->len) {
if (skb_padto(skb, len))
- return 0;
+ return NETDEV_TX_OK;
}
netif_stop_queue (dev);
@@ -846,7 +846,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
lp->tx_full = 1;
spin_unlock_irqrestore (&lp->devlock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/* The LANCE interrupt handler. */
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index 4317b3edb3d7..4beacc9c909f 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -587,7 +587,7 @@ static int atp_send_packet(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index d3c734f4d679..2aab1ebc6cd1 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -988,7 +988,7 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
aup->tx_head = (aup->tx_head + 1) & (NUM_TX_DMA - 1);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 36d4d377ec2f..1f7f015442df 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -1756,15 +1756,15 @@ static void b44_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *inf
struct b44 *bp = netdev_priv(dev);
struct ssb_bus *bus = bp->sdev->bus;
- strncpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
- strncpy(info->version, DRV_MODULE_VERSION, sizeof(info->driver));
+ strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
switch (bus->bustype) {
case SSB_BUSTYPE_PCI:
- strncpy(info->bus_info, pci_name(bus->host_pci), sizeof(info->bus_info));
+ strlcpy(info->bus_info, pci_name(bus->host_pci), sizeof(info->bus_info));
break;
case SSB_BUSTYPE_PCMCIA:
case SSB_BUSTYPE_SSB:
- strncpy(info->bus_info, "SSB", sizeof(info->bus_info));
+ strlcpy(info->bus_info, "SSB", sizeof(info->bus_info));
break;
}
}
diff --git a/drivers/net/benet/Kconfig b/drivers/net/benet/Kconfig
index c6934f179c09..fdb6e81a4374 100644
--- a/drivers/net/benet/Kconfig
+++ b/drivers/net/benet/Kconfig
@@ -1,7 +1,6 @@
config BE2NET
tristate "ServerEngines' 10Gbps NIC - BladeEngine 2"
depends on PCI && INET
- select INET_LRO
help
This driver implements the NIC functionality for ServerEngines'
10Gbps network adapter - BladeEngine 2.
diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h
index 5b4bf3d2cdc2..41cddbedbf2b 100644
--- a/drivers/net/benet/be.h
+++ b/drivers/net/benet/be.h
@@ -28,11 +28,10 @@
#include <linux/if_vlan.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
-#include <linux/inet_lro.h>
#include "be_hw.h"
-#define DRV_VER "2.0.348"
+#define DRV_VER "2.0.400"
#define DRV_NAME "be2net"
#define BE_NAME "ServerEngines BladeEngine2 10Gbps NIC"
#define OC_NAME "Emulex OneConnect 10Gbps NIC"
@@ -72,9 +71,6 @@ static inline char *nic_name(struct pci_dev *pdev)
#define MAX_RX_POST BE_NAPI_WEIGHT /* Frags posted at a time */
#define RX_FRAGS_REFILL_WM (RX_Q_LEN - MAX_RX_POST)
-#define BE_MAX_LRO_DESCRIPTORS 16
-#define BE_MAX_FRAGS_PER_FRAME (min((u32) 16, (u32) MAX_SKB_FRAGS))
-
struct be_dma_mem {
void *va;
dma_addr_t dma;
@@ -189,8 +185,6 @@ struct be_drvr_stats {
u32 be_polls; /* number of times NAPI called poll function */
u32 be_rx_events; /* number of ucast rx completion events */
u32 be_rx_compl; /* number of rx completion entries processed */
- u32 be_lro_hgram_data[8]; /* histogram of LRO data packets */
- u32 be_lro_hgram_ack[8]; /* histogram of LRO ACKs */
ulong be_rx_jiffies;
u64 be_rx_bytes;
u64 be_rx_bytes_prev;
@@ -233,8 +227,6 @@ struct be_rx_obj {
struct be_queue_info q;
struct be_queue_info cq;
struct be_rx_page_info page_info_tbl[RX_Q_LEN];
- struct net_lro_mgr lro_mgr;
- struct net_lro_desc lro_desc[BE_MAX_LRO_DESCRIPTORS];
};
#define BE_NUM_MSIX_VECTORS 2 /* 1 each for Tx and Rx */
@@ -271,7 +263,6 @@ struct be_adapter {
/* Ethtool knobs and info */
bool rx_csum; /* BE card must perform rx-checksumming */
- u32 max_rx_coal;
char fw_ver[FW_VER_LEN];
u32 if_handle; /* Used to configure filtering */
u32 pmac_id; /* MAC addr handle used by BE card */
diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c
index cccc5419ad72..f3f0f91e38c4 100644
--- a/drivers/net/benet/be_ethtool.c
+++ b/drivers/net/benet/be_ethtool.c
@@ -127,8 +127,6 @@ be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
struct be_eq_obj *rx_eq = &adapter->rx_eq;
struct be_eq_obj *tx_eq = &adapter->tx_eq;
- coalesce->rx_max_coalesced_frames = adapter->max_rx_coal;
-
coalesce->rx_coalesce_usecs = rx_eq->cur_eqd;
coalesce->rx_coalesce_usecs_high = rx_eq->max_eqd;
coalesce->rx_coalesce_usecs_low = rx_eq->min_eqd;
@@ -144,8 +142,7 @@ be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
}
/*
- * This routine is used to set interrup coalescing delay *as well as*
- * the number of pkts to coalesce for LRO.
+ * This routine is used to set interrup coalescing delay
*/
static int
be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
@@ -161,10 +158,6 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
if (coalesce->use_adaptive_tx_coalesce == 1)
return -EINVAL;
- adapter->max_rx_coal = coalesce->rx_max_coalesced_frames;
- if (adapter->max_rx_coal > BE_MAX_FRAGS_PER_FRAME)
- adapter->max_rx_coal = BE_MAX_FRAGS_PER_FRAME;
-
/* if AIC is being turned on now, start with an EQD of 0 */
if (rx_eq->enable_aic == 0 &&
coalesce->use_adaptive_rx_coalesce == 1) {
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index dea3155688bb..c56487e3700b 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -742,7 +742,7 @@ done:
return;
}
-/* Process the RX completion indicated by rxcp when LRO is disabled */
+/* Process the RX completion indicated by rxcp when GRO is disabled */
static void be_rx_compl_process(struct be_adapter *adapter,
struct be_eth_rx_compl *rxcp)
{
@@ -789,13 +789,14 @@ static void be_rx_compl_process(struct be_adapter *adapter,
return;
}
-/* Process the RX completion indicated by rxcp when LRO is enabled */
-static void be_rx_compl_process_lro(struct be_adapter *adapter,
+/* Process the RX completion indicated by rxcp when GRO is enabled */
+static void be_rx_compl_process_gro(struct be_adapter *adapter,
struct be_eth_rx_compl *rxcp)
{
struct be_rx_page_info *page_info;
- struct skb_frag_struct rx_frags[BE_MAX_FRAGS_PER_FRAME];
+ struct sk_buff *skb = NULL;
struct be_queue_info *rxq = &adapter->rx_obj.q;
+ struct be_eq_obj *eq_obj = &adapter->rx_eq;
u32 num_rcvd, pkt_size, remaining, vlanf, curr_frag_len;
u16 i, rxq_idx = 0, vid, j;
@@ -804,6 +805,12 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter,
vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp);
rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
+ skb = napi_get_frags(&eq_obj->napi);
+ if (!skb) {
+ be_rx_compl_discard(adapter, rxcp);
+ return;
+ }
+
remaining = pkt_size;
for (i = 0, j = -1; i < num_rcvd; i++) {
page_info = get_rx_page_info(adapter, rxq_idx);
@@ -814,13 +821,14 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter,
if (i == 0 || page_info->page_offset == 0) {
/* First frag or Fresh page */
j++;
- rx_frags[j].page = page_info->page;
- rx_frags[j].page_offset = page_info->page_offset;
- rx_frags[j].size = 0;
+ skb_shinfo(skb)->frags[j].page = page_info->page;
+ skb_shinfo(skb)->frags[j].page_offset =
+ page_info->page_offset;
+ skb_shinfo(skb)->frags[j].size = 0;
} else {
put_page(page_info->page);
}
- rx_frags[j].size += curr_frag_len;
+ skb_shinfo(skb)->frags[j].size += curr_frag_len;
remaining -= curr_frag_len;
index_inc(&rxq_idx, rxq->len);
@@ -828,9 +836,14 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter,
}
BUG_ON(j > MAX_SKB_FRAGS);
+ skb_shinfo(skb)->nr_frags = j + 1;
+ skb->len = pkt_size;
+ skb->data_len = pkt_size;
+ skb->truesize += pkt_size;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
if (likely(!vlanf)) {
- lro_receive_frags(&adapter->rx_obj.lro_mgr, rx_frags, pkt_size,
- pkt_size, NULL, 0);
+ napi_gro_frags(&eq_obj->napi);
} else {
vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp);
vid = be16_to_cpu(vid);
@@ -838,9 +851,7 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter,
if (!adapter->vlan_grp || adapter->num_vlans == 0)
return;
- lro_vlan_hwaccel_receive_frags(&adapter->rx_obj.lro_mgr,
- rx_frags, pkt_size, pkt_size, adapter->vlan_grp,
- vid, NULL, 0);
+ vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, vid);
}
be_rx_stats_update(adapter, pkt_size, num_rcvd);
@@ -1183,7 +1194,6 @@ static int be_rx_queues_create(struct be_adapter *adapter)
struct be_queue_info *eq, *q, *cq;
int rc;
- adapter->max_rx_coal = BE_MAX_FRAGS_PER_FRAME;
adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE;
adapter->rx_eq.max_eqd = BE_MAX_EQD;
adapter->rx_eq.min_eqd = 0;
@@ -1305,7 +1315,7 @@ static irqreturn_t be_msix_tx_mcc(int irq, void *dev)
return IRQ_HANDLED;
}
-static inline bool do_lro(struct be_adapter *adapter,
+static inline bool do_gro(struct be_adapter *adapter,
struct be_eth_rx_compl *rxcp)
{
int err = AMAP_GET_BITS(struct amap_eth_rx_compl, err, rxcp);
@@ -1314,8 +1324,7 @@ static inline bool do_lro(struct be_adapter *adapter,
if (err)
drvr_stats(adapter)->be_rxcp_err++;
- return (!tcp_frame || err || (adapter->max_rx_coal <= 1)) ?
- false : true;
+ return (tcp_frame && !err) ? true : false;
}
int be_poll_rx(struct napi_struct *napi, int budget)
@@ -1332,16 +1341,14 @@ int be_poll_rx(struct napi_struct *napi, int budget)
if (!rxcp)
break;
- if (do_lro(adapter, rxcp))
- be_rx_compl_process_lro(adapter, rxcp);
+ if (do_gro(adapter, rxcp))
+ be_rx_compl_process_gro(adapter, rxcp);
else
be_rx_compl_process(adapter, rxcp);
be_rx_compl_reset(rxcp);
}
- lro_flush_all(&adapter->rx_obj.lro_mgr);
-
/* Refill the queue */
if (atomic_read(&adapter->rx_obj.q.used) < RX_FRAGS_REFILL_WM)
be_post_rx_frags(adapter);
@@ -1656,57 +1663,6 @@ static int be_close(struct net_device *netdev)
return 0;
}
-static int be_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr,
- void **ip_hdr, void **tcpudp_hdr,
- u64 *hdr_flags, void *priv)
-{
- struct ethhdr *eh;
- struct vlan_ethhdr *veh;
- struct iphdr *iph;
- u8 *va = page_address(frag->page) + frag->page_offset;
- unsigned long ll_hlen;
-
- prefetch(va);
- eh = (struct ethhdr *)va;
- *mac_hdr = eh;
- ll_hlen = ETH_HLEN;
- if (eh->h_proto != htons(ETH_P_IP)) {
- if (eh->h_proto == htons(ETH_P_8021Q)) {
- veh = (struct vlan_ethhdr *)va;
- if (veh->h_vlan_encapsulated_proto != htons(ETH_P_IP))
- return -1;
-
- ll_hlen += VLAN_HLEN;
- } else {
- return -1;
- }
- }
- *hdr_flags = LRO_IPV4;
- iph = (struct iphdr *)(va + ll_hlen);
- *ip_hdr = iph;
- if (iph->protocol != IPPROTO_TCP)
- return -1;
- *hdr_flags |= LRO_TCP;
- *tcpudp_hdr = (u8 *) (*ip_hdr) + (iph->ihl << 2);
-
- return 0;
-}
-
-static void be_lro_init(struct be_adapter *adapter, struct net_device *netdev)
-{
- struct net_lro_mgr *lro_mgr;
-
- lro_mgr = &adapter->rx_obj.lro_mgr;
- lro_mgr->dev = netdev;
- lro_mgr->features = LRO_F_NAPI;
- lro_mgr->ip_summed = CHECKSUM_UNNECESSARY;
- lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY;
- lro_mgr->max_desc = BE_MAX_LRO_DESCRIPTORS;
- lro_mgr->lro_arr = adapter->rx_obj.lro_desc;
- lro_mgr->get_frag_header = be_get_frag_header;
- lro_mgr->max_aggr = BE_MAX_FRAGS_PER_FRAME;
-}
-
static struct net_device_ops be_netdev_ops = {
.ndo_open = be_open,
.ndo_stop = be_close,
@@ -1727,7 +1683,7 @@ static void be_netdev_init(struct net_device *netdev)
netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO |
NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_IP_CSUM |
- NETIF_F_IPV6_CSUM;
+ NETIF_F_IPV6_CSUM | NETIF_F_GRO;
netdev->flags |= IFF_MULTICAST;
@@ -1737,8 +1693,6 @@ static void be_netdev_init(struct net_device *netdev)
SET_ETHTOOL_OPS(netdev, &be_ethtool_ops);
- be_lro_init(adapter, netdev);
-
netif_napi_add(netdev, &adapter->rx_eq.napi, be_poll_rx,
BE_NAPI_WEIGHT);
netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx_mcc,
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index c15fc281f79f..f580b21eabd1 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -656,7 +656,7 @@ out:
dev->trans_start = jiffies;
dev->stats.tx_packets++;
dev->stats.tx_bytes += (skb->len);
- return 0;
+ return NETDEV_TX_OK;
}
static void bfin_mac_rx(struct net_device *dev)
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
index 9578a3dfac01..41600011cfd0 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -1488,7 +1488,7 @@ bmac_output(struct sk_buff *skb, struct net_device *dev)
struct bmac_data *bp = netdev_priv(dev);
skb_queue_tail(bp->queue, skb);
bmac_start(dev);
- return 0;
+ return NETDEV_TX_OK;
}
static void bmac_tx_timeout(unsigned long data)
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index b70cc99962fc..cec1b1746ae0 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -8023,6 +8023,13 @@ static const struct net_device_ops bnx2_netdev_ops = {
#endif
};
+static void inline vlan_features_add(struct net_device *dev, unsigned long flags)
+{
+#ifdef BCM_VLAN
+ dev->vlan_features |= flags;
+#endif
+}
+
static int __devinit
bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -8064,16 +8071,20 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
memcpy(dev->perm_addr, bp->mac_addr, 6);
dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
- if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ vlan_features_add(dev, NETIF_F_IP_CSUM | NETIF_F_SG);
+ if (CHIP_NUM(bp) == CHIP_NUM_5709) {
dev->features |= NETIF_F_IPV6_CSUM;
-
+ vlan_features_add(dev, NETIF_F_IPV6_CSUM);
+ }
#ifdef BCM_VLAN
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
#endif
dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
- if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ vlan_features_add(dev, NETIF_F_TSO | NETIF_F_TSO_ECN);
+ if (CHIP_NUM(bp) == CHIP_NUM_5709) {
dev->features |= NETIF_F_TSO6;
-
+ vlan_features_add(dev, NETIF_F_TSO6);
+ }
if ((rc = register_netdev(dev))) {
dev_err(&pdev->dev, "Cannot register net device\n");
goto error;
diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h
index 85a737c5c23f..8bd80fca9788 100644
--- a/drivers/net/bnx2x.h
+++ b/drivers/net/bnx2x.h
@@ -160,7 +160,7 @@ struct sw_rx_page {
#define PAGES_PER_SGE (1 << PAGES_PER_SGE_SHIFT)
#define SGE_PAGE_SIZE PAGE_SIZE
#define SGE_PAGE_SHIFT PAGE_SHIFT
-#define SGE_PAGE_ALIGN(addr) PAGE_ALIGN((typeof(PAGE_SIZE))addr)
+#define SGE_PAGE_ALIGN(addr) PAGE_ALIGN((typeof(PAGE_SIZE))(addr))
/* SGE ring related macros */
#define NUM_RX_SGE_PAGES 2
@@ -1006,6 +1006,7 @@ void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port);
int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode, u8 port);
int bnx2x_set_gpio_int(struct bnx2x *bp, int gpio_num, u32 mode, u8 port);
+u32 bnx2x_fw_command(struct bnx2x *bp, u32 command);
static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
int wait)
diff --git a/drivers/net/bnx2x_hsi.h b/drivers/net/bnx2x_hsi.h
index 03c62421d999..7de83c4a557a 100644
--- a/drivers/net/bnx2x_hsi.h
+++ b/drivers/net/bnx2x_hsi.h
@@ -91,6 +91,21 @@ struct shared_hw_cfg { /* NVRAM Offset */
#define SHARED_HW_CFG_HIDE_PORT1 0x00002000
+ /* The fan failure mechanism is usually related to the PHY type
+ since the power consumption of the board is determined by the PHY.
+ Currently, fan is required for most designs with SFX7101, BCM8727
+ and BCM8481. If a fan is not required for a board which uses one
+ of those PHYs, this field should be set to "Disabled". If a fan is
+ required for a different PHY type, this option should be set to
+ "Enabled".
+ The fan failure indication is expected on
+ SPIO5 */
+#define SHARED_HW_CFG_FAN_FAILURE_MASK 0x00180000
+#define SHARED_HW_CFG_FAN_FAILURE_SHIFT 19
+#define SHARED_HW_CFG_FAN_FAILURE_PHY_TYPE 0x00000000
+#define SHARED_HW_CFG_FAN_FAILURE_DISABLED 0x00080000
+#define SHARED_HW_CFG_FAN_FAILURE_ENABLED 0x00100000
+
u32 power_dissipated; /* 0x11c */
#define SHARED_HW_CFG_POWER_DIS_CMN_MASK 0xff000000
#define SHARED_HW_CFG_POWER_DIS_CMN_SHIFT 24
@@ -233,6 +248,8 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726 0x00000600
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481 0x00000700
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101 0x00000800
+#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727 0x00000900
+#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC 0x00000a00
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE 0x0000fd00
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN 0x0000ff00
@@ -343,10 +360,16 @@ struct port_feat_cfg { /* port 0: 0x454 port 1: 0x4c8 */
#define PORT_FEATURE_MBA_ENABLED 0x02000000
#define PORT_FEATURE_MFW_ENABLED 0x04000000
- /* Check the optic vendor via i2c before allowing it to be used by
- SW */
-#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLED 0x00000000
-#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_ENABLED 0x08000000
+ /* Reserved bits: 28-29 */
+ /* Check the optic vendor via i2c against a list of approved modules
+ in a separate nvram image */
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK 0xE0000000
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_SHIFT 29
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT 0x00000000
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER 0x20000000
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_WARNING_MSG 0x40000000
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN 0x60000000
+
u32 wol_config;
/* Default is used when driver sets to "auto" mode */
@@ -642,6 +665,12 @@ struct drv_func_mb {
#define DRV_MSG_CODE_GET_UPGRADE_KEY 0x81000000
#define DRV_MSG_CODE_GET_MANUF_KEY 0x82000000
#define DRV_MSG_CODE_LOAD_L2B_PRAM 0x90000000
+ /*
+ * The optic module verification commands requris bootcode
+ * v5.0.6 or later
+ */
+#define DRV_MSG_CODE_VRFY_OPT_MDL 0xa0000000
+#define REQ_BC_VER_4_VRFY_OPT_MDL 0x00050006
#define BIOS_MSG_CODE_LIC_CHALLENGE 0xff010000
#define BIOS_MSG_CODE_LIC_RESPONSE 0xff020000
@@ -676,6 +705,9 @@ struct drv_func_mb {
#define FW_MSG_CODE_L2B_PRAM_C_LOAD_FAILURE 0x90220000
#define FW_MSG_CODE_L2B_PRAM_X_LOAD_FAILURE 0x90230000
#define FW_MSG_CODE_L2B_PRAM_U_LOAD_FAILURE 0x90240000
+#define FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS 0xa0100000
+#define FW_MSG_CODE_VRFY_OPT_MDL_INVLD_IMG 0xa0200000
+#define FW_MSG_CODE_VRFY_OPT_MDL_UNAPPROVED 0xa0300000
#define FW_MSG_CODE_LIC_CHALLENGE 0xff010000
#define FW_MSG_CODE_LIC_RESPONSE 0xff020000
diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c
index 2ee581a2cdec..1f17334c8f02 100644
--- a/drivers/net/bnx2x_link.c
+++ b/drivers/net/bnx2x_link.c
@@ -139,21 +139,26 @@
#define SFP_EEPROM_CON_TYPE_VAL_LC 0x7
#define SFP_EEPROM_CON_TYPE_VAL_COPPER 0x21
+
+#define SFP_EEPROM_COMP_CODE_ADDR 0x3
+ #define SFP_EEPROM_COMP_CODE_SR_MASK (1<<4)
+ #define SFP_EEPROM_COMP_CODE_LR_MASK (1<<5)
+ #define SFP_EEPROM_COMP_CODE_LRM_MASK (1<<6)
+
#define SFP_EEPROM_FC_TX_TECH_ADDR 0x8
#define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4
#define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE 0x8
-#define SFP_EEPROM_VENDOR_NAME_ADDR 0x14
-#define SFP_EEPROM_VENDOR_NAME_SIZE 16
+
#define SFP_EEPROM_OPTIONS_ADDR 0x40
#define SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1
#define SFP_EEPROM_OPTIONS_SIZE 2
-#define SFP_MODULE_TYPE_UNKNOWN 0x0
-#define SFP_MODULE_TYPE_LC 0x1
-#define SFP_MODULE_TYPE_ACTIVE_COPPER_CABLE 0x2
-#define SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE 0x3
+#define EDC_MODE_LINEAR 0x0022
+#define EDC_MODE_LIMITING 0x0044
+#define EDC_MODE_PASSIVE_DAC 0x0055
+
+
-#define SFP_LIMITING_MODE_VALUE 0x0044
/**********************************************************/
/* INTERFACE */
/**********************************************************/
@@ -793,6 +798,7 @@ static u32 bnx2x_get_emac_base(struct bnx2x *bp, u32 ext_phy_type, u8 port)
switch (ext_phy_type) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
/* All MDC/MDIO is directed through single EMAC */
if (REG_RD(bp, NIG_REG_PORT_SWAP))
emac_base = GRCBASE_EMAC0;
@@ -1887,6 +1893,10 @@ static void bnx2x_ext_phy_reset(struct link_params *params,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_CTRL, 0xa040);
break;
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+ break;
+
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
/* Restore normal power mode*/
@@ -2171,13 +2181,15 @@ static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)
}
-static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
- u8 ext_phy_addr, u32 shmem_base)
+static void bnx2x_bcm8073_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port,
+ u8 ext_phy_addr,
+ u32 ext_phy_type,
+ u32 shmem_base)
{
/* Boot port from external ROM */
/* EDC grst */
bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_GEN_CTRL,
@@ -2185,21 +2197,21 @@ static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
/* ucode reboot and rst */
bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_GEN_CTRL,
0x008c);
bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_MISC_CTRL1, 0x0001);
/* Reset internal microprocessor */
bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_GEN_CTRL,
@@ -2207,7 +2219,7 @@ static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
/* Release srst bit */
bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_GEN_CTRL,
@@ -2218,17 +2230,36 @@ static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
/* Clear ser_boot_ctl bit */
bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_MISC_CTRL1, 0x0000);
bnx2x_save_bcm_spirom_ver(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ ext_phy_type,
ext_phy_addr,
shmem_base);
}
+static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
+ u8 ext_phy_addr,
+ u32 shmem_base)
+{
+ bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ shmem_base);
+}
+
+static void bnx2x_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port,
+ u8 ext_phy_addr,
+ u32 shmem_base)
+{
+ bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ shmem_base);
+
+}
+
static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
{
struct bnx2x *bp = params->bp;
@@ -2258,9 +2289,10 @@ static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
MDIO_PMA_REG_GEN_CTRL,
MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
+ /* Set PLL register value to be same like in P13 ver */
bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
MDIO_PMA_DEVAD,
- MDIO_PMA_REG_GEN_CTRL2,
+ MDIO_PMA_REG_PLL_CTRL,
0x73A0);
/* Clear soft reset.
@@ -2285,15 +2317,16 @@ static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
params->shmem_base);
}
-static void bnx2x_bcm8726_set_transmitter(struct bnx2x *bp, u8 port,
- u8 ext_phy_addr, u8 tx_en)
+static void bnx2x_sfp_set_transmitter(struct bnx2x *bp, u8 port,
+ u32 ext_phy_type, u8 ext_phy_addr,
+ u8 tx_en)
{
u16 val;
DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
tx_en, port);
/* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
bnx2x_cl45_read(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
+ ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_PHY_IDENTIFIER,
@@ -2305,18 +2338,19 @@ static void bnx2x_bcm8726_set_transmitter(struct bnx2x *bp, u8 port,
val |= (1<<15);
bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
+ ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_PHY_IDENTIFIER,
val);
}
-
-static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
- u8 byte_cnt, u8 *o_buf) {
+static u8 bnx2x_8726_read_sfp_module_eeprom(struct link_params *params,
+ u16 addr, u8 byte_cnt, u8 *o_buf)
+{
struct bnx2x *bp = params->bp;
- u16 val, i;
+ u16 val = 0;
+ u16 i;
u8 port = params->port;
u8 ext_phy_addr = ((params->ext_phy_config &
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
@@ -2332,7 +2366,7 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8726_TWO_WIRE_BYTE_CNT,
+ MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
(byte_cnt | 0xa000));
/* Set the read command address */
@@ -2340,7 +2374,7 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8726_TWO_WIRE_MEM_ADDR,
+ MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
addr);
/* Activate read command */
@@ -2348,7 +2382,7 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8726_TWO_WIRE_CTRL,
+ MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
0x2c0f);
/* Wait up to 500us for command complete status */
@@ -2357,18 +2391,18 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val);
- if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) ==
- MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE)
+ MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
+ if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
+ MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
break;
udelay(5);
}
- if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) !=
- MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE) {
+ if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
+ MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
DP(NETIF_MSG_LINK,
"Got bad status 0x%x when reading from SFP+ EEPROM\n",
- (val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK));
+ (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
return -EINVAL;
}
@@ -2387,29 +2421,147 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val);
- if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) ==
- MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IDLE)
+ MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
+ if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
+ MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
return 0;;
msleep(1);
}
return -EINVAL;
}
+static u8 bnx2x_8727_read_sfp_module_eeprom(struct link_params *params,
+ u16 addr, u8 byte_cnt, u8 *o_buf)
+{
+ struct bnx2x *bp = params->bp;
+ u16 val, i;
+ u8 port = params->port;
+ u8 ext_phy_addr = ((params->ext_phy_config &
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+ u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
+
+ if (byte_cnt > 16) {
+ DP(NETIF_MSG_LINK, "Reading from eeprom is"
+ " is limited to 0xf\n");
+ return -EINVAL;
+ }
+
+ /* Need to read from 1.8000 to clear it */
+ bnx2x_cl45_read(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
+ &val);
-static u8 bnx2x_get_sfp_module_type(struct link_params *params,
- u8 *module_type)
+ /* Set the read command byte count */
+ bnx2x_cl45_write(bp, port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
+ ((byte_cnt < 2) ? 2 : byte_cnt));
+
+ /* Set the read command address */
+ bnx2x_cl45_write(bp, port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
+ addr);
+ /* Set the destination address */
+ bnx2x_cl45_write(bp, port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ 0x8004,
+ MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
+
+ /* Activate read command */
+ bnx2x_cl45_write(bp, port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
+ 0x8002);
+ /* Wait appropriate time for two-wire command to finish before
+ polling the status register */
+ msleep(1);
+
+ /* Wait up to 500us for command complete status */
+ for (i = 0; i < 100; i++) {
+ bnx2x_cl45_read(bp, port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
+ if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
+ MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
+ break;
+ udelay(5);
+ }
+
+ if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
+ MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
+ DP(NETIF_MSG_LINK,
+ "Got bad status 0x%x when reading from SFP+ EEPROM\n",
+ (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
+ return -EINVAL;
+ }
+
+ /* Read the buffer */
+ for (i = 0; i < byte_cnt; i++) {
+ bnx2x_cl45_read(bp, port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
+ o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
+ }
+
+ for (i = 0; i < 100; i++) {
+ bnx2x_cl45_read(bp, port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
+ if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
+ MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
+ return 0;;
+ msleep(1);
+ }
+
+ return -EINVAL;
+}
+
+u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
+ u8 byte_cnt, u8 *o_buf)
+{
+ u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
+
+ if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
+ return bnx2x_8726_read_sfp_module_eeprom(params, addr,
+ byte_cnt, o_buf);
+ else if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
+ return bnx2x_8727_read_sfp_module_eeprom(params, addr,
+ byte_cnt, o_buf);
+ return -EINVAL;
+}
+
+static u8 bnx2x_get_edc_mode(struct link_params *params,
+ u16 *edc_mode)
{
struct bnx2x *bp = params->bp;
- u8 val;
- *module_type = SFP_MODULE_TYPE_UNKNOWN;
+ u8 val, check_limiting_mode = 0;
+ *edc_mode = EDC_MODE_LIMITING;
/* First check for copper cable */
if (bnx2x_read_sfp_module_eeprom(params,
SFP_EEPROM_CON_TYPE_ADDR,
1,
&val) != 0) {
- DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM");
+ DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
return -EINVAL;
}
@@ -2433,13 +2585,13 @@ static u8 bnx2x_get_sfp_module_type(struct link_params *params,
if (copper_module_type &
SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
- *module_type = SFP_MODULE_TYPE_ACTIVE_COPPER_CABLE;
+ check_limiting_mode = 1;
} else if (copper_module_type &
SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
DP(NETIF_MSG_LINK, "Passive Copper"
" cable detected\n");
- *module_type =
- SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE;
+ *edc_mode =
+ EDC_MODE_PASSIVE_DAC;
} else {
DP(NETIF_MSG_LINK, "Unknown copper-cable-"
"type 0x%x !!!\n", copper_module_type);
@@ -2449,7 +2601,7 @@ static u8 bnx2x_get_sfp_module_type(struct link_params *params,
}
case SFP_EEPROM_CON_TYPE_VAL_LC:
DP(NETIF_MSG_LINK, "Optic module detected\n");
- *module_type = SFP_MODULE_TYPE_LC;
+ check_limiting_mode = 1;
break;
default:
@@ -2457,89 +2609,92 @@ static u8 bnx2x_get_sfp_module_type(struct link_params *params,
val);
return -EINVAL;
}
+
+ if (check_limiting_mode) {
+ u8 options[SFP_EEPROM_OPTIONS_SIZE];
+ if (bnx2x_read_sfp_module_eeprom(params,
+ SFP_EEPROM_OPTIONS_ADDR,
+ SFP_EEPROM_OPTIONS_SIZE,
+ options) != 0) {
+ DP(NETIF_MSG_LINK, "Failed to read Option"
+ " field from module EEPROM\n");
+ return -EINVAL;
+ }
+ if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK))
+ *edc_mode = EDC_MODE_LINEAR;
+ else
+ *edc_mode = EDC_MODE_LIMITING;
+ }
+ DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode);
return 0;
}
-
/* This function read the relevant field from the module ( SFP+ ),
and verify it is compliant with this board */
-static u8 bnx2x_verify_sfp_module(struct link_params *params,
- u8 module_type)
+static u8 bnx2x_verify_sfp_module(struct link_params *params)
{
struct bnx2x *bp = params->bp;
- u8 *str_p, *tmp_buf;
- u16 i;
-
-#define COMPLIANCE_STR_CNT 6
- u8 *compliance_str[] = {"Broadcom", "JDSU", "Molex Inc", "PICOLIGHT",
- "FINISAR CORP. ", "Amphenol"};
- u8 buf[SFP_EEPROM_VENDOR_NAME_SIZE];
- /* Passive Copper cables are allowed to participate,
- since the module is hardwired to the copper cable */
-
- if (!(params->feature_config_flags &
- FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) {
+ u32 val;
+ u32 fw_resp;
+ char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1];
+ char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
+
+ val = REG_RD(bp, params->shmem_base +
+ offsetof(struct shmem_region, dev_info.
+ port_feature_config[params->port].config));
+ if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+ PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) {
DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
return 0;
}
- if (module_type != SFP_MODULE_TYPE_LC) {
- DP(NETIF_MSG_LINK, "No need to verify copper cable\n");
+ /* Ask the FW to validate the module */
+ if (!(params->feature_config_flags &
+ FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY)) {
+ DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
+ "verification\n");
+ return -EINVAL;
+ }
+
+ fw_resp = bnx2x_fw_command(bp, DRV_MSG_CODE_VRFY_OPT_MDL);
+ if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) {
+ DP(NETIF_MSG_LINK, "Approved module\n");
return 0;
}
- /* In case of non copper cable or Active copper cable,
- verify that the SFP+ module is compliant with this board*/
+ /* format the warning message */
if (bnx2x_read_sfp_module_eeprom(params,
SFP_EEPROM_VENDOR_NAME_ADDR,
SFP_EEPROM_VENDOR_NAME_SIZE,
- buf) != 0) {
- DP(NETIF_MSG_LINK, "Failed to read Vendor-Name from"
- " module EEPROM\n");
- return -EINVAL;
- }
- for (i = 0; i < COMPLIANCE_STR_CNT; i++) {
- str_p = compliance_str[i];
- tmp_buf = buf;
- while (*str_p) {
- if ((u8)(*tmp_buf) != (u8)(*str_p))
- break;
- str_p++;
- tmp_buf++;
- }
+ (u8 *)vendor_name))
+ vendor_name[0] = '\0';
+ else
+ vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
+ if (bnx2x_read_sfp_module_eeprom(params,
+ SFP_EEPROM_PART_NO_ADDR,
+ SFP_EEPROM_PART_NO_SIZE,
+ (u8 *)vendor_pn))
+ vendor_pn[0] = '\0';
+ else
+ vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
- if (!(*str_p)) {
- DP(NETIF_MSG_LINK, "SFP+ Module verified, "
- "index=%x\n", i);
- return 0;
- }
- }
- DP(NETIF_MSG_LINK, "Incompliant SFP+ module. Disable module !!!\n");
+ printk(KERN_INFO PFX "Warning: "
+ "Unqualified SFP+ module "
+ "detected on %s, Port %d from %s part number %s\n"
+ , bp->dev->name, params->port,
+ vendor_name, vendor_pn);
return -EINVAL;
}
-
static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
- u8 module_type)
+ u16 edc_mode)
{
struct bnx2x *bp = params->bp;
u8 port = params->port;
- u8 options[SFP_EEPROM_OPTIONS_SIZE];
- u8 limiting_mode;
u8 ext_phy_addr = ((params->ext_phy_config &
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
u16 cur_limiting_mode;
- if (bnx2x_read_sfp_module_eeprom(params,
- SFP_EEPROM_OPTIONS_ADDR,
- SFP_EEPROM_OPTIONS_SIZE,
- options) != 0) {
- DP(NETIF_MSG_LINK, "Failed to read Option field from"
- " module EEPROM\n");
- return -EINVAL;
- }
- limiting_mode = !(options[0] &
- SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK);
bnx2x_cl45_read(bp, port,
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
@@ -2550,26 +2705,23 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n",
cur_limiting_mode);
- if (limiting_mode &&
- (module_type != SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE)) {
+ if (edc_mode == EDC_MODE_LIMITING) {
DP(NETIF_MSG_LINK,
- "Module options = 0x%x.Setting LIMITING MODE\n",
- options[0]);
+ "Setting LIMITING MODE\n");
bnx2x_cl45_write(bp, port,
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_ROM_VER2,
- SFP_LIMITING_MODE_VALUE);
+ EDC_MODE_LIMITING);
} else { /* LRM mode ( default )*/
- DP(NETIF_MSG_LINK, "Module options = 0x%x.Setting LRM MODE\n",
- options[0]);
+ DP(NETIF_MSG_LINK, "Setting LRM MODE\n");
/* Changing to LRM mode takes quite few seconds.
So do it only if current mode is limiting
( default is LRM )*/
- if (cur_limiting_mode != SFP_LIMITING_MODE_VALUE)
+ if (cur_limiting_mode != EDC_MODE_LIMITING)
return 0;
bnx2x_cl45_write(bp, port,
@@ -2600,6 +2752,56 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
return 0;
}
+static u8 bnx2x_bcm8727_set_limiting_mode(struct link_params *params,
+ u16 edc_mode)
+{
+ struct bnx2x *bp = params->bp;
+ u8 port = params->port;
+ u16 phy_identifier;
+ u16 rom_ver2_val;
+ u8 ext_phy_addr = ((params->ext_phy_config &
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+
+ bnx2x_cl45_read(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER,
+ &phy_identifier);
+
+ bnx2x_cl45_write(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER,
+ (phy_identifier & ~(1<<9)));
+
+ bnx2x_cl45_read(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_ROM_VER2,
+ &rom_ver2_val);
+ /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
+ bnx2x_cl45_write(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_ROM_VER2,
+ (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
+
+ bnx2x_cl45_write(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER,
+ (phy_identifier | (1<<9)));
+
+ return 0;
+}
+
+
static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params)
{
u8 val;
@@ -2619,61 +2821,114 @@ static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params)
return -EINVAL;
}
+static void bnx2x_8727_power_module(struct bnx2x *bp,
+ struct link_params *params,
+ u8 ext_phy_addr, u8 is_power_up) {
+ /* Make sure GPIOs are not using for LED mode */
+ u16 val;
+ u8 port = params->port;
+ /*
+ * In the GPIO register, bit 4 is use to detemine if the GPIOs are
+ * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
+ * output
+ * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0
+ * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1
+ * where the 1st bit is the over-current(only input), and 2nd bit is
+ * for power( only output )
+ */
+
+ /*
+ * In case of NOC feature is disabled and power is up, set GPIO control
+ * as input to enable listening of over-current indication
+ */
+
+ if (!(params->feature_config_flags &
+ FEATURE_CONFIG_BCM8727_NOC) && is_power_up)
+ val = (1<<4);
+ else
+ /*
+ * Set GPIO control to OUTPUT, and set the power bit
+ * to according to the is_power_up
+ */
+ val = ((!(is_power_up)) << 1);
+
+ bnx2x_cl45_write(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_GPIO_CTRL,
+ val);
+}
+
static u8 bnx2x_sfp_module_detection(struct link_params *params)
{
struct bnx2x *bp = params->bp;
- u8 module_type;
+ u16 edc_mode;
+ u8 rc = 0;
u8 ext_phy_addr = ((params->ext_phy_config &
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-
- if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
- DP(NETIF_MSG_LINK, "Module detection is not required "
- "for this phy\n");
- return 0;
- }
+ u32 val = REG_RD(bp, params->shmem_base +
+ offsetof(struct shmem_region, dev_info.
+ port_feature_config[params->port].config));
DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
params->port);
- if (bnx2x_get_sfp_module_type(params,
- &module_type) != 0) {
+ if (bnx2x_get_edc_mode(params, &edc_mode) != 0) {
DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
- if (!(params->feature_config_flags &
- FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) {
- /* In case module detection is disabled, it trys to
- link up. The issue that can happen here is LRM /
- LIMITING mode which set according to the module-type*/
- DP(NETIF_MSG_LINK, "Unable to read module-type."
- "Probably due to Bit Stretching."
- " Proceeding...\n");
- } else {
- return -EINVAL;
- }
- } else if (bnx2x_verify_sfp_module(params, module_type) !=
+ return -EINVAL;
+ } else if (bnx2x_verify_sfp_module(params) !=
0) {
/* check SFP+ module compatibility */
DP(NETIF_MSG_LINK, "Module verification failed!!\n");
+ rc = -EINVAL;
/* Turn on fault module-detected led */
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
MISC_REGISTERS_GPIO_HIGH,
params->port);
- return -EINVAL;
+ if ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) &&
+ ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+ PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN)) {
+ /* Shutdown SFP+ module */
+ DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
+ bnx2x_8727_power_module(bp, params,
+ ext_phy_addr, 0);
+ return rc;
+ }
+ } else {
+ /* Turn off fault module-detected led */
+ DP(NETIF_MSG_LINK, "Turn off fault module-detected led\n");
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
+ MISC_REGISTERS_GPIO_LOW,
+ params->port);
}
- /* Turn off fault module-detected led */
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
- MISC_REGISTERS_GPIO_LOW,
- params->port);
+ /* power up the SFP module */
+ if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
+ bnx2x_8727_power_module(bp, params, ext_phy_addr, 1);
- /* Check and set limiting mode / LRM mode */
- bnx2x_bcm8726_set_limiting_mode(params, module_type);
+ /* Check and set limiting mode / LRM mode on 8726.
+ On 8727 it is done automatically */
+ if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
+ bnx2x_bcm8726_set_limiting_mode(params, edc_mode);
+ else
+ bnx2x_bcm8727_set_limiting_mode(params, edc_mode);
+ /*
+ * Enable transmit for this module if the module is approved, or
+ * if unapproved modules should also enable the Tx laser
+ */
+ if (rc == 0 ||
+ (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
+ PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
+ bnx2x_sfp_set_transmitter(bp, params->port,
+ ext_phy_type, ext_phy_addr, 1);
+ else
+ bnx2x_sfp_set_transmitter(bp, params->port,
+ ext_phy_type, ext_phy_addr, 0);
- /* Enable transmit for this module */
- bnx2x_bcm8726_set_transmitter(bp, params->port,
- ext_phy_addr, 1);
- return 0;
+ return rc;
}
void bnx2x_handle_module_detect_int(struct link_params *params)
@@ -2696,8 +2951,8 @@ void bnx2x_handle_module_detect_int(struct link_params *params)
MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
port);
- if (bnx2x_wait_for_sfp_module_initialized(params)
- == 0)
+ if (bnx2x_wait_for_sfp_module_initialized(params) ==
+ 0)
bnx2x_sfp_module_detection(params);
else
DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
@@ -2705,13 +2960,22 @@ void bnx2x_handle_module_detect_int(struct link_params *params)
u8 ext_phy_addr = ((params->ext_phy_config &
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+ u32 ext_phy_type =
+ XGXS_EXT_PHY_TYPE(params->ext_phy_config);
+ u32 val = REG_RD(bp, params->shmem_base +
+ offsetof(struct shmem_region, dev_info.
+ port_feature_config[params->port].
+ config));
+
bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
port);
/* Module was plugged out. */
/* Disable transmit for this module */
- bnx2x_bcm8726_set_transmitter(bp, params->port,
- ext_phy_addr, 0);
+ if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+ PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
+ bnx2x_sfp_set_transmitter(bp, params->port,
+ ext_phy_type, ext_phy_addr, 0);
}
}
@@ -3160,6 +3424,9 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
driver is loaded, it reset all registers, including the
transmitter */
bnx2x_sfp_module_detection(params);
+
+ /* Set Flow control */
+ bnx2x_ext_phy_set_pause(params, vars);
if (params->req_line_speed == SPEED_1000) {
DP(NETIF_MSG_LINK, "Setting 1G force\n");
bnx2x_cl45_write(bp, params->port, ext_phy_type,
@@ -3450,6 +3717,187 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
((val & (1<<7)) > 0));
break;
}
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+ {
+ u16 tmp1;
+ u16 rx_alarm_ctrl_val;
+ u16 lasi_ctrl_val;
+
+ /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
+
+ u16 mod_abs;
+ rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
+ lasi_ctrl_val = 0x0004;
+
+ DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
+ /* enable LASI */
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM_CTRL,
+ rx_alarm_ctrl_val);
+
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_LASI_CTRL,
+ lasi_ctrl_val);
+
+ /* Initially configure MOD_ABS to interrupt when
+ module is presence( bit 8) */
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
+ /* Set EDC off by setting OPTXLOS signal input to low
+ (bit 9).
+ When the EDC is off it locks onto a reference clock and
+ avoids becoming 'lost'.*/
+ mod_abs &= ~((1<<8) | (1<<9));
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
+
+ /* Make MOD_ABS give interrupt on change */
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+ &val);
+ val |= (1<<12);
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+ val);
+
+ /* Set 8727 GPIOs to input to allow reading from the
+ 8727 GPIO0 status which reflect SFP+ module
+ over-current */
+
+ bnx2x_cl45_read(bp, params->port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+ &val);
+ val &= 0xff8f; /* Reset bits 4-6 */
+ bnx2x_cl45_write(bp, params->port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+ val);
+
+ bnx2x_8727_power_module(bp, params, ext_phy_addr, 1);
+ bnx2x_bcm8073_set_xaui_low_power_mode(params);
+
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_M8051_MSGOUT_REG,
+ &tmp1);
+
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM, &tmp1);
+
+ /* Set option 1G speed */
+ if (params->req_line_speed == SPEED_1000) {
+
+ DP(NETIF_MSG_LINK, "Setting 1G force\n");
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_CTRL, 0x40);
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_10G_CTRL2, 0xD);
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_10G_CTRL2, &tmp1);
+ DP(NETIF_MSG_LINK, "1.7 = 0x%x \n", tmp1);
+
+ } else if ((params->req_line_speed ==
+ SPEED_AUTO_NEG) &&
+ ((params->speed_cap_mask &
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) {
+
+ DP(NETIF_MSG_LINK, "Setting 1G clause37 \n");
+ bnx2x_cl45_write(bp, params->port, ext_phy_type,
+ ext_phy_addr, MDIO_AN_DEVAD,
+ MDIO_PMA_REG_8727_MISC_CTRL, 0);
+ bnx2x_cl45_write(bp, params->port, ext_phy_type,
+ ext_phy_addr, MDIO_AN_DEVAD,
+ MDIO_AN_REG_CL37_AN, 0x1300);
+ } else {
+ /* Since the 8727 has only single reset pin,
+ need to set the 10G registers although it is
+ default */
+ bnx2x_cl45_write(bp, params->port, ext_phy_type,
+ ext_phy_addr, MDIO_AN_DEVAD,
+ MDIO_AN_REG_CTRL, 0x0020);
+ bnx2x_cl45_write(bp, params->port, ext_phy_type,
+ ext_phy_addr, MDIO_AN_DEVAD,
+ 0x7, 0x0100);
+ bnx2x_cl45_write(bp, params->port, ext_phy_type,
+ ext_phy_addr, MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_CTRL, 0x2040);
+ bnx2x_cl45_write(bp, params->port, ext_phy_type,
+ ext_phy_addr, MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_10G_CTRL2, 0x0008);
+ }
+
+ /* Set 2-wire transfer rate to 400Khz since 100Khz
+ is not operational */
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
+ 0xa101);
+
+ /* Set TX PreEmphasis if needed */
+ if ((params->feature_config_flags &
+ FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
+ DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
+ "TX_CTRL2 0x%x\n",
+ params->xgxs_config_tx[0],
+ params->xgxs_config_tx[1]);
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_TX_CTRL1,
+ params->xgxs_config_tx[0]);
+
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_TX_CTRL2,
+ params->xgxs_config_tx[1]);
+ }
+
+ break;
+ }
+
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
{
u16 fw_ver1, fw_ver2;
@@ -3561,6 +4009,99 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
return rc;
}
+static void bnx2x_8727_handle_mod_abs(struct link_params *params)
+{
+ struct bnx2x *bp = params->bp;
+ u16 mod_abs, rx_alarm_status;
+ u8 ext_phy_addr = ((params->ext_phy_config &
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+ u32 val = REG_RD(bp, params->shmem_base +
+ offsetof(struct shmem_region, dev_info.
+ port_feature_config[params->port].
+ config));
+ bnx2x_cl45_read(bp, params->port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
+ if (mod_abs & (1<<8)) {
+
+ /* Module is absent */
+ DP(NETIF_MSG_LINK, "MOD_ABS indication "
+ "show module is absent\n");
+
+ /* 1. Set mod_abs to detect next module
+ presence event
+ 2. Set EDC off by setting OPTXLOS signal input to low
+ (bit 9).
+ When the EDC is off it locks onto a reference clock and
+ avoids becoming 'lost'.*/
+ mod_abs &= ~((1<<8)|(1<<9));
+ bnx2x_cl45_write(bp, params->port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
+
+ /* Clear RX alarm since it stays up as long as
+ the mod_abs wasn't changed */
+ bnx2x_cl45_read(bp, params->port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
+
+ } else {
+ /* Module is present */
+ DP(NETIF_MSG_LINK, "MOD_ABS indication "
+ "show module is present\n");
+ /* First thing, disable transmitter,
+ and if the module is ok, the
+ module_detection will enable it*/
+
+ /* 1. Set mod_abs to detect next module
+ absent event ( bit 8)
+ 2. Restore the default polarity of the OPRXLOS signal and
+ this signal will then correctly indicate the presence or
+ absence of the Rx signal. (bit 9) */
+ mod_abs |= ((1<<8)|(1<<9));
+ bnx2x_cl45_write(bp, params->port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
+
+ /* Clear RX alarm since it stays up as long as
+ the mod_abs wasn't changed. This is need to be done
+ before calling the module detection, otherwise it will clear
+ the link update alarm */
+ bnx2x_cl45_read(bp, params->port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
+
+
+ if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+ PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
+ bnx2x_sfp_set_transmitter(bp, params->port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr, 0);
+
+ if (bnx2x_wait_for_sfp_module_initialized(params)
+ == 0)
+ bnx2x_sfp_module_detection(params);
+ else
+ DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
+ }
+
+ DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
+ rx_alarm_status);
+ /* No need to check link status in case of
+ module plugged in/out */
+}
+
static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
struct link_vars *vars)
@@ -3602,8 +4143,19 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_RX_SD, &rx_sd);
- DP(NETIF_MSG_LINK, "8705 rx_sd 0x%x\n", rx_sd);
- ext_phy_link_up = (rx_sd & 0x1);
+
+ bnx2x_cl45_read(bp, params->port, ext_phy_type,
+ ext_phy_addr,
+ 1,
+ 0xc809, &val1);
+ bnx2x_cl45_read(bp, params->port, ext_phy_type,
+ ext_phy_addr,
+ 1,
+ 0xc809, &val1);
+
+ DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
+ ext_phy_link_up = ((rx_sd & 0x1) && (val1 & (1<<9))
+ && ((val1 & (1<<8)) == 0));
if (ext_phy_link_up)
vars->line_speed = SPEED_10000;
break;
@@ -3678,8 +4230,160 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
else
vars->line_speed = SPEED_10000;
}
+ break;
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+ {
+ u16 link_status = 0;
+ u16 rx_alarm_status;
+ /* Check the LASI */
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
+
+ DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
+ rx_alarm_status);
+
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_LASI_STATUS, &val1);
+
+ DP(NETIF_MSG_LINK,
+ "8727 LASI status 0x%x\n",
+ val1);
+
+ /* Clear MSG-OUT */
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_M8051_MSGOUT_REG,
+ &val1);
+
+ /*
+ * If a module is present and there is need to check
+ * for over current
+ */
+ if (!(params->feature_config_flags &
+ FEATURE_CONFIG_BCM8727_NOC) &&
+ !(rx_alarm_status & (1<<5))) {
+ /* Check over-current using 8727 GPIO0 input*/
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_GPIO_CTRL,
+ &val1);
+
+ if ((val1 & (1<<8)) == 0) {
+ DP(NETIF_MSG_LINK, "8727 Power fault"
+ " has been detected on port"
+ " %d\n", params->port);
+ printk(KERN_ERR PFX "Error: Power"
+ " fault on %s Port %d has"
+ " been detected and the"
+ " power to that SFP+ module"
+ " has been removed to prevent"
+ " failure of the card. Please"
+ " remove the SFP+ module and"
+ " restart the system to clear"
+ " this error.\n"
+ , bp->dev->name, params->port);
+ /*
+ * Disable all RX_ALARMs except for
+ * mod_abs
+ */
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM_CTRL,
+ (1<<5));
+
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER,
+ &val1);
+ /* Wait for module_absent_event */
+ val1 |= (1<<8);
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER,
+ val1);
+ /* Clear RX alarm */
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM,
+ &rx_alarm_status);
+ break;
+ }
+ } /* Over current check */
+
+ /* When module absent bit is set, check module */
+ if (rx_alarm_status & (1<<5)) {
+ bnx2x_8727_handle_mod_abs(params);
+ /* Enable all mod_abs and link detection bits */
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM_CTRL,
+ ((1<<5) | (1<<2)));
+ }
+
+ /* If transmitter is disabled,
+ ignore false link up indication */
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER,
+ &val1);
+ if (val1 & (1<<15)) {
+ DP(NETIF_MSG_LINK, "Tx is disabled\n");
+ ext_phy_link_up = 0;
+ break;
+ }
+
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
+ &link_status);
+ /* Bits 0..2 --> speed detected,
+ bits 13..15--> link is down */
+ if ((link_status & (1<<2)) &&
+ (!(link_status & (1<<15)))) {
+ ext_phy_link_up = 1;
+ vars->line_speed = SPEED_10000;
+ } else if ((link_status & (1<<0)) &&
+ (!(link_status & (1<<13)))) {
+ ext_phy_link_up = 1;
+ vars->line_speed = SPEED_1000;
+ DP(NETIF_MSG_LINK,
+ "port %x: External link"
+ " up in 1G\n", params->port);
+ } else {
+ ext_phy_link_up = 0;
+ DP(NETIF_MSG_LINK,
+ "port %x: External link"
+ " is down\n", params->port);
+ }
break;
+ }
+
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
{
@@ -4242,6 +4946,7 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
@@ -4790,6 +5495,11 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
}
REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
params->port*4, 0);
+
+ bnx2x_set_led(bp, params->port, LED_MODE_OPER,
+ vars->line_speed, params->hw_led_mode,
+ params->chip_id);
+
} else
/* No loopback */
{
@@ -4843,10 +5553,6 @@ static void bnx2x_8726_reset_phy(struct bnx2x *bp, u8 port, u8 ext_phy_addr)
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_GEN_CTRL, 0x0001);
-
- /* Disable Transmitter */
- bnx2x_bcm8726_set_transmitter(bp, port, ext_phy_addr, 0);
-
}
u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
@@ -4859,6 +5565,11 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
u32 chip_id = params->chip_id;
u8 port = params->port;
u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
+ u32 val = REG_RD(bp, params->shmem_base +
+ offsetof(struct shmem_region, dev_info.
+ port_feature_config[params->port].
+ config));
+
/* disable attentions */
vars->link_status = 0;
@@ -4893,6 +5604,21 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
break;
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+ {
+
+ /* Disable Transmitter */
+ u8 ext_phy_addr = ((params->ext_phy_config &
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+ if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+ PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
+ bnx2x_sfp_set_transmitter(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr, 0);
+ break;
+ }
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
DP(NETIF_MSG_LINK, "Setting 8073 port %d into "
"low power mode\n",
@@ -5217,6 +5943,74 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
}
+static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base)
+{
+ u8 ext_phy_addr[PORT_MAX];
+ s8 port;
+ u32 swap_val, swap_override;
+ DP(NETIF_MSG_LINK, "Executing BCM8727 common init\n");
+ swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
+ swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
+
+ bnx2x_hw_reset(bp, 1 ^ (swap_val && swap_override));
+ msleep(5);
+
+ /* PART1 - Reset both phys */
+ for (port = PORT_MAX - 1; port >= PORT_0; port--) {
+ /* Extract the ext phy address for the port */
+ u32 ext_phy_config = REG_RD(bp, shmem_base +
+ offsetof(struct shmem_region,
+ dev_info.port_hw_config[port].external_phy_config));
+
+ /* disable attentions */
+ bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
+ (NIG_MASK_XGXS0_LINK_STATUS |
+ NIG_MASK_XGXS0_LINK10G |
+ NIG_MASK_SERDES0_LINK_STATUS |
+ NIG_MASK_MI_INT));
+
+ ext_phy_addr[port] = ((ext_phy_config &
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+
+ /* Reset the phy */
+ bnx2x_cl45_write(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr[port],
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_CTRL,
+ 1<<15);
+ }
+
+ /* Add delay of 150ms after reset */
+ msleep(150);
+
+ /* PART2 - Download firmware to both phys */
+ for (port = PORT_MAX - 1; port >= PORT_0; port--) {
+ u16 fw_ver1;
+
+ bnx2x_bcm8727_external_rom_boot(bp, port,
+ ext_phy_addr[port], shmem_base);
+
+ bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr[port],
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_ROM_VER1, &fw_ver1);
+ if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
+ DP(NETIF_MSG_LINK,
+ "bnx2x_8073_common_init_phy port %x:"
+ "Download failed. fw version = 0x%x\n",
+ port, fw_ver1);
+ return -EINVAL;
+ }
+
+ }
+
+
+
+ return 0;
+}
+
static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base)
{
@@ -5275,6 +6069,12 @@ u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
rc = bnx2x_8073_common_init_phy(bp, shmem_base);
break;
}
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
+ rc = bnx2x_8727_common_init_phy(bp, shmem_base);
+ break;
+
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
/* GPIO1 affects both ports, so there's need to pull
it for single port alone */
diff --git a/drivers/net/bnx2x_link.h b/drivers/net/bnx2x_link.h
index 19a866dc10eb..d25ef45d793f 100644
--- a/drivers/net/bnx2x_link.h
+++ b/drivers/net/bnx2x_link.h
@@ -39,7 +39,13 @@
#define SPEED_15000 15000
#define SPEED_16000 16000
-
+#define SFP_EEPROM_VENDOR_NAME_ADDR 0x14
+#define SFP_EEPROM_VENDOR_NAME_SIZE 16
+#define SFP_EEPROM_VENDOR_OUI_ADDR 0x25
+#define SFP_EEPROM_VENDOR_OUI_SIZE 3
+#define SFP_EEPROM_PART_NO_ADDR 0x28
+#define SFP_EEPROM_PART_NO_SIZE 16
+#define PWR_FLT_ERR_MSG_LEN 250
/***********************************************************/
/* Structs */
/***********************************************************/
@@ -91,7 +97,8 @@ struct link_params {
u16 xgxs_config_tx[4]; /* preemphasis values for the tx side */
u32 feature_config_flags;
#define FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED (1<<0)
-#define FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED (2<<0)
+#define FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY (1<<2)
+#define FEATURE_CONFIG_BCM8727_NOC (1<<3)
/* Device pointer passed to all callback functions */
struct bnx2x *bp;
};
@@ -181,4 +188,7 @@ u8 bnx2x_test_link(struct link_params *input, struct link_vars *vars);
u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base);
+u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
+ u8 byte_cnt, u8 *o_buf);
+
#endif /* BNX2X_LINK_H */
diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index 6c67be679764..2d035d795f02 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x_main.c
@@ -56,8 +56,8 @@
#include "bnx2x_init_ops.h"
#include "bnx2x_dump.h"
-#define DRV_MODULE_VERSION "1.48.105-1"
-#define DRV_MODULE_RELDATE "2009/04/22"
+#define DRV_MODULE_VERSION "1.48.114-1"
+#define DRV_MODULE_RELDATE "2009/07/29"
#define BNX2X_BC_VER 0x040200
#include <linux/firmware.h>
@@ -652,6 +652,11 @@ static void bnx2x_int_enable(struct bnx2x *bp)
val, port, addr, (msix ? "MSI-X" : (msi ? "MSI" : "INTx")));
REG_WR(bp, addr, val);
+ /*
+ * Ensure that HC_CONFIG is written before leading/trailing edge config
+ */
+ mmiowb();
+ barrier();
if (CHIP_IS_E1H(bp)) {
/* init leading/trailing edge */
@@ -666,6 +671,9 @@ static void bnx2x_int_enable(struct bnx2x *bp)
REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val);
REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val);
}
+
+ /* Make sure that interrupts are indeed enabled from here on */
+ mmiowb();
}
static void bnx2x_int_disable(struct bnx2x *bp)
@@ -698,6 +706,8 @@ static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
/* disable interrupt handling */
atomic_inc(&bp->intr_sem);
+ smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
+
if (disable_hw)
/* prevent the HW from sending interrupts */
bnx2x_int_disable(bp);
@@ -739,6 +749,10 @@ static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 sb_id,
DP(BNX2X_MSG_OFF, "write 0x%08x to HC addr 0x%x\n",
(*(u32 *)&igu_ack), hc_addr);
REG_WR(bp, hc_addr, (*(u32 *)&igu_ack));
+
+ /* Make sure that ACK is written */
+ mmiowb();
+ barrier();
}
static inline u16 bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp)
@@ -2429,9 +2443,14 @@ static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
bp->spq_prod_idx++;
}
+ /* Make sure that BD data is updated before writing the producer */
+ wmb();
+
REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PROD_OFFSET(func),
bp->spq_prod_idx);
+ mmiowb();
+
spin_unlock_bh(&bp->spq_lock);
return 0;
}
@@ -2598,11 +2617,27 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
}
}
+static inline void bnx2x_fan_failure(struct bnx2x *bp)
+{
+ int port = BP_PORT(bp);
+
+ /* mark the failure */
+ bp->link_params.ext_phy_config &= ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
+ bp->link_params.ext_phy_config |= PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE;
+ SHMEM_WR(bp, dev_info.port_hw_config[port].external_phy_config,
+ bp->link_params.ext_phy_config);
+
+ /* log the failure */
+ printk(KERN_ERR PFX "Fan Failure on Network Controller %s has caused"
+ " the driver to shutdown the card to prevent permanent"
+ " damage. Please contact Dell Support for assistance\n",
+ bp->dev->name);
+}
static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
{
int port = BP_PORT(bp);
int reg_offset;
- u32 val;
+ u32 val, swap_val, swap_override;
reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
@@ -2615,36 +2650,32 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
BNX2X_ERR("SPIO5 hw attention\n");
+ /* Fan failure attention */
switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
- /* Fan failure attention */
-
+ /* Low power mode is controlled by GPIO 2 */
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+ MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
/* The PHY reset is controlled by GPIO 1 */
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
- /* Low power mode is controlled by GPIO 2 */
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+ break;
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+ /* The PHY reset is controlled by GPIO 1 */
+ /* fake the port number to cancel the swap done in
+ set_gpio() */
+ swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
+ swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
+ port = (swap_val && swap_override) ^ 1;
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
- /* mark the failure */
- bp->link_params.ext_phy_config &=
- ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
- bp->link_params.ext_phy_config |=
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE;
- SHMEM_WR(bp,
- dev_info.port_hw_config[port].
- external_phy_config,
- bp->link_params.ext_phy_config);
- /* log the failure */
- printk(KERN_ERR PFX "Fan Failure on Network"
- " Controller %s has caused the driver to"
- " shutdown the card to prevent permanent"
- " damage. Please contact Dell Support for"
- " assistance\n", bp->dev->name);
break;
default:
break;
}
+ bnx2x_fan_failure(bp);
}
if (attn & (AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 |
@@ -4800,7 +4831,14 @@ static void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
int mode = bp->rx_mode;
int mask = (1 << BP_L_ID(bp));
int func = BP_FUNC(bp);
+ int port = BP_PORT(bp);
int i;
+ /* All but management unicast packets should pass to the host as well */
+ u32 llh_mask =
+ NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_BRCST |
+ NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_MLCST |
+ NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_VLAN |
+ NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_NO_VLAN;
DP(NETIF_MSG_IFUP, "rx mode %d mask 0x%x\n", mode, mask);
@@ -4824,6 +4862,8 @@ static void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
tstorm_mac_filter.ucast_accept_all = mask;
tstorm_mac_filter.mcast_accept_all = mask;
tstorm_mac_filter.bcast_accept_all = mask;
+ /* pass management unicast packets as well */
+ llh_mask |= NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_UNCST;
break;
default:
@@ -4831,6 +4871,10 @@ static void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
break;
}
+ REG_WR(bp,
+ (port ? NIG_REG_LLH1_BRB1_DRV_MASK : NIG_REG_LLH0_BRB1_DRV_MASK),
+ llh_mask);
+
for (i = 0; i < sizeof(struct tstorm_eth_mac_filter_config)/4; i++) {
REG_WR(bp, BAR_TSTRORM_INTMEM +
TSTORM_MAC_FILTER_CONFIG_OFFSET(func) + i * 4,
@@ -5184,6 +5228,11 @@ static void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
mmiowb();
bnx2x_int_enable(bp);
+
+ /* Check for SPIO5 */
+ bnx2x_attn_int_deasserted0(bp,
+ REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + BP_PORT(bp)*4) &
+ AEU_INPUTS_ATTN_BITS_SPIO5);
}
/* end of nic init */
@@ -5509,6 +5558,60 @@ static void bnx2x_reset_common(struct bnx2x *bp)
REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, 0x1403);
}
+
+static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp)
+{
+ u32 val;
+ u8 port;
+ u8 is_required = 0;
+
+ val = SHMEM_RD(bp, dev_info.shared_hw_config.config2) &
+ SHARED_HW_CFG_FAN_FAILURE_MASK;
+
+ if (val == SHARED_HW_CFG_FAN_FAILURE_ENABLED)
+ is_required = 1;
+
+ /*
+ * The fan failure mechanism is usually related to the PHY type since
+ * the power consumption of the board is affected by the PHY. Currently,
+ * fan is required for most designs with SFX7101, BCM8727 and BCM8481.
+ */
+ else if (val == SHARED_HW_CFG_FAN_FAILURE_PHY_TYPE)
+ for (port = PORT_0; port < PORT_MAX; port++) {
+ u32 phy_type =
+ SHMEM_RD(bp, dev_info.port_hw_config[port].
+ external_phy_config) &
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
+ is_required |=
+ ((phy_type ==
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) ||
+ (phy_type ==
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) ||
+ (phy_type ==
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481));
+ }
+
+ DP(NETIF_MSG_HW, "fan detection setting: %d\n", is_required);
+
+ if (is_required == 0)
+ return;
+
+ /* Fan failure is indicated by SPIO 5 */
+ bnx2x_set_spio(bp, MISC_REGISTERS_SPIO_5,
+ MISC_REGISTERS_SPIO_INPUT_HI_Z);
+
+ /* 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);
+ REG_WR(bp, MISC_REG_SPIO_INT, val);
+
+ /* enable interrupt to signal the IGU */
+ val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN);
+ val |= (1 << MISC_REGISTERS_SPIO_5);
+ REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val);
+}
+
static int bnx2x_init_common(struct bnx2x *bp)
{
u32 val, i;
@@ -5735,30 +5838,16 @@ static int bnx2x_init_common(struct bnx2x *bp)
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
bp->port.need_hw_lock = 1;
break;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
- /* Fan failure is indicated by SPIO 5 */
- bnx2x_set_spio(bp, MISC_REGISTERS_SPIO_5,
- MISC_REGISTERS_SPIO_INPUT_HI_Z);
-
- /* 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);
- REG_WR(bp, MISC_REG_SPIO_INT, val);
-
- /* enable interrupt to signal the IGU */
- val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN);
- val |= (1 << MISC_REGISTERS_SPIO_5);
- REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val);
- break;
-
default:
break;
}
+ bnx2x_setup_fan_failure_detection(bp);
+
/* clear PXP2 attentions */
REG_RD(bp, PXP2_REG_PXP2_INT_STS_CLR_0);
@@ -5988,10 +6077,15 @@ static int bnx2x_init_port(struct bnx2x *bp)
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
/* add SPIO 5 to group 0 */
- val = REG_RD(bp, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
+ {
+ u32 reg_addr = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
+ MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
+ val = REG_RD(bp, reg_addr);
val |= AEU_INPUTS_ATTN_BITS_SPIO5;
- REG_WR(bp, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0, val);
+ REG_WR(bp, reg_addr, val);
+ }
break;
default:
@@ -6141,7 +6235,7 @@ init_hw_err:
}
/* send the MCP a request, block until there is a reply */
-static u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
+u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
{
int func = BP_FUNC(bp);
u32 seq = ++bp->fw_seq;
@@ -6582,7 +6676,12 @@ static void bnx2x_napi_disable(struct bnx2x *bp)
static void bnx2x_netif_start(struct bnx2x *bp)
{
- if (atomic_dec_and_test(&bp->intr_sem)) {
+ int intr_sem;
+
+ intr_sem = atomic_dec_and_test(&bp->intr_sem);
+ smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
+
+ if (intr_sem) {
if (netif_running(bp->dev)) {
bnx2x_napi_enable(bp);
bnx2x_int_enable(bp);
@@ -7255,17 +7354,17 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
for (i = 0; i < MC_HASH_SIZE; i++)
REG_WR(bp, MC_HASH_OFFSET(bp, i), 0);
+
+ REG_WR(bp, MISC_REG_E1HMF_MODE, 0);
}
if (unload_mode == UNLOAD_NORMAL)
reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
- else if (bp->flags & NO_WOL_FLAG) {
+ else if (bp->flags & NO_WOL_FLAG)
reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP;
- if (CHIP_IS_E1H(bp))
- REG_WR(bp, MISC_REG_E1HMF_MODE, 0);
- } else if (bp->wol) {
+ else if (bp->wol) {
u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
u8 *mac_addr = bp->dev->dev_addr;
u32 val;
@@ -7609,6 +7708,9 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
BNX2X_ERR("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) ?
+ FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY : 0;
if (BP_E1HVN(bp) == 0) {
pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_PMC, &pmc);
@@ -7769,6 +7871,18 @@ static void __devinit bnx2x_link_settings_supported(struct bnx2x *bp,
SUPPORTED_Asym_Pause);
break;
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+ BNX2X_DEV_INFO("ext_phy_type 0x%x (8727)\n",
+ ext_phy_type);
+
+ bp->port.supported |= (SUPPORTED_10000baseT_Full |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_Autoneg |
+ SUPPORTED_FIBRE |
+ SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause);
+ break;
+
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
BNX2X_DEV_INFO("ext_phy_type 0x%x (SFX7101)\n",
ext_phy_type);
@@ -8032,6 +8146,17 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
bp->link_params.ext_phy_config =
SHMEM_RD(bp,
dev_info.port_hw_config[port].external_phy_config);
+ /* BCM8727_NOC => BCM8727 no over current */
+ if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) ==
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC) {
+ bp->link_params.ext_phy_config &=
+ ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
+ bp->link_params.ext_phy_config |=
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727;
+ bp->link_params.feature_config_flags |=
+ FEATURE_CONFIG_BCM8727_NOC;
+ }
+
bp->link_params.speed_cap_mask =
SHMEM_RD(bp,
dev_info.port_hw_config[port].speed_capability_mask);
@@ -8052,17 +8177,10 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
bp->link_params.xgxs_config_tx[(i << 1) + 1] = (val & 0xffff);
}
- config = SHMEM_RD(bp, dev_info.port_feature_config[port].config);
- if (config & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_ENABLED)
- bp->link_params.feature_config_flags |=
- FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED;
- else
- bp->link_params.feature_config_flags &=
- ~FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED;
-
/* If the device is capable of WoL, set the default state according
* to the HW
*/
+ config = SHMEM_RD(bp, dev_info.port_feature_config[port].config);
bp->wol = (!(bp->flags & NO_WOL_FLAG) &&
(config & PORT_FEATURE_WOL_ENABLED));
@@ -8072,8 +8190,8 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
bp->link_params.ext_phy_config,
bp->link_params.speed_cap_mask, bp->port.link_config);
- bp->link_params.switch_cfg = (bp->port.link_config &
- PORT_FEATURE_CONNECTED_SWITCH_MASK);
+ bp->link_params.switch_cfg |= (bp->port.link_config &
+ PORT_FEATURE_CONNECTED_SWITCH_MASK);
bnx2x_link_settings_supported(bp, bp->link_params.switch_cfg);
bnx2x_link_settings_requested(bp);
@@ -8169,6 +8287,7 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
/* Disable interrupt handling until HW is initialized */
atomic_set(&bp->intr_sem, 1);
+ smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
mutex_init(&bp->port.phy_mutex);
@@ -8268,6 +8387,7 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
cmd->port = PORT_FIBRE;
break;
@@ -9295,10 +9415,9 @@ static int bnx2x_test_registers(struct bnx2x *bp)
{ XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 4, 0x00000001 },
{ XCM_REG_WU_DA_CNT_CMD00, 4, 0x00000003 },
{ XCM_REG_GLB_DEL_ACK_MAX_CNT_0, 4, 0x000000ff },
- { NIG_REG_EGRESS_MNG0_FIFO, 20, 0xffffffff },
{ NIG_REG_LLH0_T_BIT, 4, 0x00000001 },
-/* 20 */ { NIG_REG_EMAC0_IN_EN, 4, 0x00000001 },
- { NIG_REG_BMAC0_IN_EN, 4, 0x00000001 },
+ { NIG_REG_EMAC0_IN_EN, 4, 0x00000001 },
+/* 20 */ { NIG_REG_BMAC0_IN_EN, 4, 0x00000001 },
{ NIG_REG_XCM0_OUT_EN, 4, 0x00000001 },
{ NIG_REG_BRB0_OUT_EN, 4, 0x00000001 },
{ NIG_REG_LLH0_XCM_MASK, 4, 0x00000007 },
@@ -9307,8 +9426,8 @@ static int bnx2x_test_registers(struct bnx2x *bp)
{ NIG_REG_LLH0_DEST_MAC_0_0, 160, 0xffffffff },
{ NIG_REG_LLH0_DEST_IP_0_1, 160, 0xffffffff },
{ NIG_REG_LLH0_IPV4_IPV6_0, 160, 0x00000001 },
-/* 30 */ { NIG_REG_LLH0_DEST_UDP_0, 160, 0x0000ffff },
- { NIG_REG_LLH0_DEST_TCP_0, 160, 0x0000ffff },
+ { NIG_REG_LLH0_DEST_UDP_0, 160, 0x0000ffff },
+/* 30 */ { NIG_REG_LLH0_DEST_TCP_0, 160, 0x0000ffff },
{ NIG_REG_LLH0_VLAN_ID_0, 160, 0x00000fff },
{ NIG_REG_XGXS_SERDES0_MODE_SEL, 4, 0x00000001 },
{ NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0, 4, 0x00000001 },
@@ -9691,8 +9810,15 @@ static void bnx2x_self_test(struct net_device *dev,
etest->flags &= ~ETH_TEST_FL_OFFLINE;
if (etest->flags & ETH_TEST_FL_OFFLINE) {
+ int port = BP_PORT(bp);
+ u32 val;
u8 link_up;
+ /* save current value of input enable for TX port IF */
+ val = REG_RD(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4);
+ /* disable input for TX port IF */
+ REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, 0);
+
link_up = bp->link_vars.link_up;
bnx2x_nic_unload(bp, UNLOAD_NORMAL);
bnx2x_nic_load(bp, LOAD_DIAG);
@@ -9712,6 +9838,10 @@ static void bnx2x_self_test(struct net_device *dev,
etest->flags |= ETH_TEST_FL_FAILED;
bnx2x_nic_unload(bp, UNLOAD_NORMAL);
+
+ /* restore input for TX port IF */
+ REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, val);
+
bnx2x_nic_load(bp, LOAD_NORMAL);
/* wait until link state is restored */
bnx2x_wait_for_link(bp, link_up);
@@ -11064,12 +11194,19 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
dev->features |= NETIF_F_HW_CSUM;
if (bp->flags & USING_DAC_FLAG)
dev->features |= NETIF_F_HIGHDMA;
+ dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
+ dev->features |= NETIF_F_TSO6;
#ifdef BCM_VLAN
dev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
bp->flags |= (HW_VLAN_RX_FLAG | HW_VLAN_TX_FLAG);
+
+ dev->vlan_features |= NETIF_F_SG;
+ dev->vlan_features |= NETIF_F_HW_CSUM;
+ if (bp->flags & USING_DAC_FLAG)
+ dev->vlan_features |= NETIF_F_HIGHDMA;
+ dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
+ dev->vlan_features |= NETIF_F_TSO6;
#endif
- dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
- dev->features |= NETIF_F_TSO6;
return 0;
diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h
index b8ce6fc927a0..8e9e7a24f2fc 100644
--- a/drivers/net/bnx2x_reg.h
+++ b/drivers/net/bnx2x_reg.h
@@ -1616,6 +1616,11 @@
/* [RW 1] Set by the MCP to remember if one or more of the drivers is/are
loaded; 0-prepare; -unprepare */
#define MISC_REG_UNPREPARED 0xa424
+#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_BRCST (0x1<<0)
+#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_MLCST (0x1<<1)
+#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_NO_VLAN (0x1<<4)
+#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_UNCST (0x1<<2)
+#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_VLAN (0x1<<3)
#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT (0x1<<0)
#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS (0x1<<9)
#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G (0x1<<15)
@@ -1660,6 +1665,8 @@
#define NIG_REG_EGRESS_PBF0_IN_EN 0x100cc
/* [RW 1] Input enable for TX PBF user packet port1 IF */
#define NIG_REG_EGRESS_PBF1_IN_EN 0x100d0
+/* [RW 1] Input enable for TX UMP management packet port0 IF */
+#define NIG_REG_EGRESS_UMP0_IN_EN 0x100d4
/* [RW 1] Input enable for RX_EMAC0 IF */
#define NIG_REG_EMAC0_IN_EN 0x100a4
/* [RW 1] output enable for TX EMAC pause port 0 IF */
@@ -5843,25 +5850,33 @@ Theotherbitsarereservedandshouldbezero*/
#define MDIO_PMA_REG_ROM_VER2 0xca1a
#define MDIO_PMA_REG_EDC_FFE_MAIN 0xca1b
#define MDIO_PMA_REG_PLL_BANDWIDTH 0xca1d
-#define MDIO_PMA_REG_GEN_CTRL2 0xca1e
+#define MDIO_PMA_REG_PLL_CTRL 0xca1e
#define MDIO_PMA_REG_MISC_CTRL0 0xca23
#define MDIO_PMA_REG_LRM_MODE 0xca3f
#define MDIO_PMA_REG_CDR_BANDWIDTH 0xca46
#define MDIO_PMA_REG_MISC_CTRL1 0xca85
-#define MDIO_PMA_REG_8726_TWO_WIRE_CTRL 0x8000
-#define MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK 0x000c
-#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IDLE 0x0000
-#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE 0x0004
-#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IN_PROGRESS 0x0008
-#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_FAILED 0x000c
-#define MDIO_PMA_REG_8726_TWO_WIRE_BYTE_CNT 0x8002
-#define MDIO_PMA_REG_8726_TWO_WIRE_MEM_ADDR 0x8003
+#define MDIO_PMA_REG_SFP_TWO_WIRE_CTRL 0x8000
+#define MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK 0x000c
+#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE 0x0000
+#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE 0x0004
+#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IN_PROGRESS 0x0008
+#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_FAILED 0x000c
+#define MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT 0x8002
+#define MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR 0x8003
#define MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF 0xc820
#define MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK 0xff
#define MDIO_PMA_REG_8726_TX_CTRL1 0xca01
#define MDIO_PMA_REG_8726_TX_CTRL2 0xca05
+#define MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR 0x8005
+#define MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF 0x8007
+#define MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK 0xff
+#define MDIO_PMA_REG_8727_MISC_CTRL 0x8309
+#define MDIO_PMA_REG_8727_TX_CTRL1 0xca02
+#define MDIO_PMA_REG_8727_TX_CTRL2 0xca05
+#define MDIO_PMA_REG_8727_PCS_OPT_CTRL 0xc808
+#define MDIO_PMA_REG_8727_GPIO_CTRL 0xc80e
#define MDIO_PMA_REG_8073_CHIP_REV 0xc801
#define MDIO_PMA_REG_8073_SPEED_LINK_STATUS 0xc820
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index d4b570886c6e..be799d2a8a8d 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -1109,7 +1109,8 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
//mux machine in case of EXPIRED even if LINK_DOWN didn't arrive for the port.
port->partner_oper.port_state &= ~AD_STATE_SYNCHRONIZATION;
port->sm_vars &= ~AD_PORT_MATCHED;
- port->partner_oper.port_state |= AD_SHORT_TIMEOUT;
+ port->partner_oper.port_state |=
+ AD_STATE_LACP_ACTIVITY;
port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(AD_SHORT_TIMEOUT));
port->actor_oper_port_state |= AD_STATE_EXPIRED;
break;
@@ -2431,7 +2432,7 @@ out:
dev_kfree_skb(skb);
}
read_unlock(&bond->lock);
- return 0;
+ return NETDEV_TX_OK;
}
int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev)
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 46d312bedfb8..bf45d2002924 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -1413,7 +1413,7 @@ out:
}
read_unlock(&bond->curr_slave_lock);
read_unlock(&bond->lock);
- return 0;
+ return NETDEV_TX_OK;
}
void bond_alb_monitor(struct work_struct *work)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index aa1be1feceed..3bf0cc61e92c 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4285,7 +4285,7 @@ out:
dev_kfree_skb(skb);
}
read_unlock(&bond->lock);
- return 0;
+ return NETDEV_TX_OK;
}
@@ -4316,7 +4316,7 @@ out:
read_unlock(&bond->curr_slave_lock);
read_unlock(&bond->lock);
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -4362,7 +4362,7 @@ out:
dev_kfree_skb(skb);
}
read_unlock(&bond->lock);
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -4422,7 +4422,7 @@ out:
/* frame sent to all suitable interfaces */
read_unlock(&bond->lock);
- return 0;
+ return NETDEV_TX_OK;
}
/*------------------------- Device initialization ---------------------------*/
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index 33821a81cbf8..30ae55d71678 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -61,11 +61,12 @@ config CAN_SJA1000_OF_PLATFORM
you may want to enable this option.
config CAN_EMS_PCI
- tristate "EMS CPC-PCI and CPC-PCIe Card"
+ tristate "EMS CPC-PCI, CPC-PCIe and CPC-104P Card"
depends on PCI && CAN_SJA1000
---help---
- This driver is for the one or two channel CPC-PCI and CPC-PCIe
- cards from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de).
+ This driver is for the one, two or four channel CPC-PCI,
+ CPC-PCIe and CPC-104P cards from EMS Dr. Thomas Wuensche
+ (http://www.ems-wuensche.de).
config CAN_KVASER_PCI
tristate "Kvaser PCIcanx and Kvaser PCIcan PCI Cards"
diff --git a/drivers/net/can/sja1000/ems_pci.c b/drivers/net/can/sja1000/ems_pci.c
index 121b64101d72..7d84b8ac9c1c 100644
--- a/drivers/net/can/sja1000/ems_pci.c
+++ b/drivers/net/can/sja1000/ems_pci.c
@@ -32,13 +32,16 @@
#define DRV_NAME "ems_pci"
MODULE_AUTHOR("Sebastian Haas <haas@ems-wuenche.com>");
-MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-PCI/PCIe CAN cards");
-MODULE_SUPPORTED_DEVICE("EMS CPC-PCI/PCIe CAN card");
+MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-PCI/PCIe/104P CAN cards");
+MODULE_SUPPORTED_DEVICE("EMS CPC-PCI/PCIe/104P CAN card");
MODULE_LICENSE("GPL v2");
-#define EMS_PCI_MAX_CHAN 2
+#define EMS_PCI_V1_MAX_CHAN 2
+#define EMS_PCI_V2_MAX_CHAN 4
+#define EMS_PCI_MAX_CHAN EMS_PCI_V2_MAX_CHAN
struct ems_pci_card {
+ int version;
int channels;
struct pci_dev *pci_dev;
@@ -63,12 +66,22 @@ struct ems_pci_card {
#define PITA2_MISC_CONFIG 0x04000000 /* Multiplexed parallel interface */
/*
+ * Register definitions for the PLX 9030
+ */
+#define PLX_ICSR 0x4c /* Interrupt Control/Status register */
+#define PLX_ICSR_LINTI1_ENA 0x0001 /* LINTi1 Enable */
+#define PLX_ICSR_PCIINT_ENA 0x0040 /* PCI Interrupt Enable */
+#define PLX_ICSR_LINTI1_CLR 0x0400 /* Local Edge Triggerable Interrupt Clear */
+#define PLX_ICSR_ENA_CLR (PLX_ICSR_LINTI1_ENA | PLX_ICSR_PCIINT_ENA | \
+ PLX_ICSR_LINTI1_CLR)
+
+/*
* The board configuration is probably following:
* RX1 is connected to ground.
* TX1 is not connected.
* CLKO is not connected.
* Setting the OCR register to 0xDA is a good idea.
- * This means normal output mode , push-pull and the correct polarity.
+ * This means normal output mode, push-pull and the correct polarity.
*/
#define EMS_PCI_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
@@ -79,17 +92,21 @@ struct ems_pci_card {
* is driven by the first one CLKOUT output.
*/
#define EMS_PCI_CDR (CDR_CBP | CDR_CLKOUT_MASK)
-#define EMS_PCI_MEM_SIZE 4096 /* Size of the remapped io-memory */
+
+#define EMS_PCI_V1_BASE_BAR 1
+#define EMS_PCI_V1_MEM_SIZE 4096
+#define EMS_PCI_V2_BASE_BAR 2
+#define EMS_PCI_V2_MEM_SIZE 128
#define EMS_PCI_CAN_BASE_OFFSET 0x400 /* offset where the controllers starts */
#define EMS_PCI_CAN_CTRL_SIZE 0x200 /* memory size for each controller */
-#define EMS_PCI_PORT_BYTES 0x4 /* Each register occupies 4 bytes */
-
-#define EMS_PCI_VENDOR_ID 0x110a /* PCI device and vendor ID */
-#define EMS_PCI_DEVICE_ID 0x2104
-
static struct pci_device_id ems_pci_tbl[] = {
- {EMS_PCI_VENDOR_ID, EMS_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+ /* CPC-PCI v1 */
+ {PCI_VENDOR_ID_SIEMENS, 0x2104, PCI_ANY_ID, PCI_ANY_ID,},
+ /* CPC-PCI v2 */
+ {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_PLX, 0x4000},
+ /* CPC-104P v2 */
+ {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_PLX, 0x4002},
{0,}
};
MODULE_DEVICE_TABLE(pci, ems_pci_tbl);
@@ -97,28 +114,47 @@ MODULE_DEVICE_TABLE(pci, ems_pci_tbl);
/*
* Helper to read internal registers from card logic (not CAN)
*/
-static u8 ems_pci_readb(struct ems_pci_card *card, unsigned int port)
+static u8 ems_pci_v1_readb(struct ems_pci_card *card, unsigned int port)
{
- return readb(card->base_addr + (port * EMS_PCI_PORT_BYTES));
+ return readb(card->base_addr + (port * 4));
}
-static u8 ems_pci_read_reg(const struct sja1000_priv *priv, int port)
+static u8 ems_pci_v1_read_reg(const struct sja1000_priv *priv, int port)
{
- return readb(priv->reg_base + (port * EMS_PCI_PORT_BYTES));
+ return readb(priv->reg_base + (port * 4));
}
-static void ems_pci_write_reg(const struct sja1000_priv *priv, int port, u8 val)
+static void ems_pci_v1_write_reg(const struct sja1000_priv *priv,
+ int port, u8 val)
{
- writeb(val, priv->reg_base + (port * EMS_PCI_PORT_BYTES));
+ writeb(val, priv->reg_base + (port * 4));
}
-static void ems_pci_post_irq(const struct sja1000_priv *priv)
+static void ems_pci_v1_post_irq(const struct sja1000_priv *priv)
{
struct ems_pci_card *card = (struct ems_pci_card *)priv->priv;
/* reset int flag of pita */
- writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0, card->conf_addr
- + PITA2_ICR);
+ writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0,
+ card->conf_addr + PITA2_ICR);
+}
+
+static u8 ems_pci_v2_read_reg(const struct sja1000_priv *priv, int port)
+{
+ return readb(priv->reg_base + port);
+}
+
+static void ems_pci_v2_write_reg(const struct sja1000_priv *priv,
+ int port, u8 val)
+{
+ writeb(val, priv->reg_base + port);
+}
+
+static void ems_pci_v2_post_irq(const struct sja1000_priv *priv)
+{
+ struct ems_pci_card *card = (struct ems_pci_card *)priv->priv;
+
+ writel(PLX_ICSR_ENA_CLR, card->conf_addr + PLX_ICSR);
}
/*
@@ -130,12 +166,12 @@ static inline int ems_pci_check_chan(const struct sja1000_priv *priv)
unsigned char res;
/* Make sure SJA1000 is in reset mode */
- ems_pci_write_reg(priv, REG_MOD, 1);
+ priv->write_reg(priv, REG_MOD, 1);
- ems_pci_write_reg(priv, REG_CDR, CDR_PELICAN);
+ priv->write_reg(priv, REG_CDR, CDR_PELICAN);
/* read reset-values */
- res = ems_pci_read_reg(priv, REG_CDR);
+ res = priv->read_reg(priv, REG_CDR);
if (res == CDR_PELICAN)
return 1;
@@ -188,6 +224,7 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
struct sja1000_priv *priv;
struct net_device *dev;
struct ems_pci_card *card;
+ int max_chan, mem_size, base_bar;
int err, i;
/* Enabling PCI device */
@@ -210,37 +247,52 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
card->channels = 0;
- /* Remap PITA configuration space, and controller memory area */
- card->conf_addr = pci_iomap(pdev, 0, EMS_PCI_MEM_SIZE);
+ if (pdev->vendor == PCI_VENDOR_ID_PLX) {
+ card->version = 2; /* CPC-PCI v2 */
+ max_chan = EMS_PCI_V2_MAX_CHAN;
+ base_bar = EMS_PCI_V2_BASE_BAR;
+ mem_size = EMS_PCI_V2_MEM_SIZE;
+ } else {
+ card->version = 1; /* CPC-PCI v1 */
+ max_chan = EMS_PCI_V1_MAX_CHAN;
+ base_bar = EMS_PCI_V1_BASE_BAR;
+ mem_size = EMS_PCI_V1_MEM_SIZE;
+ }
+
+ /* Remap configuration space and controller memory area */
+ card->conf_addr = pci_iomap(pdev, 0, mem_size);
if (card->conf_addr == NULL) {
err = -ENOMEM;
goto failure_cleanup;
}
- card->base_addr = pci_iomap(pdev, 1, EMS_PCI_MEM_SIZE);
+ card->base_addr = pci_iomap(pdev, base_bar, mem_size);
if (card->base_addr == NULL) {
err = -ENOMEM;
goto failure_cleanup;
}
- /* Configure PITA-2 parallel interface (enable MUX) */
- writel(PITA2_MISC_CONFIG, card->conf_addr + PITA2_MISC);
-
- /* Check for unique EMS CAN signature */
- if (ems_pci_readb(card, 0) != 0x55 ||
- ems_pci_readb(card, 1) != 0xAA ||
- ems_pci_readb(card, 2) != 0x01 ||
- ems_pci_readb(card, 3) != 0xCB ||
- ems_pci_readb(card, 4) != 0x11) {
- dev_err(&pdev->dev, "Not EMS Dr. Thomas Wuensche interface\n");
- err = -ENODEV;
- goto failure_cleanup;
+ if (card->version == 1) {
+ /* Configure PITA-2 parallel interface (enable MUX) */
+ writel(PITA2_MISC_CONFIG, card->conf_addr + PITA2_MISC);
+
+ /* Check for unique EMS CAN signature */
+ if (ems_pci_v1_readb(card, 0) != 0x55 ||
+ ems_pci_v1_readb(card, 1) != 0xAA ||
+ ems_pci_v1_readb(card, 2) != 0x01 ||
+ ems_pci_v1_readb(card, 3) != 0xCB ||
+ ems_pci_v1_readb(card, 4) != 0x11) {
+ dev_err(&pdev->dev,
+ "Not EMS Dr. Thomas Wuensche interface\n");
+ err = -ENODEV;
+ goto failure_cleanup;
+ }
}
ems_pci_card_reset(card);
/* Detect available channels */
- for (i = 0; i < EMS_PCI_MAX_CHAN; i++) {
+ for (i = 0; i < max_chan; i++) {
dev = alloc_sja1000dev(0);
if (dev == NULL) {
err = -ENOMEM;
@@ -255,20 +307,32 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
dev->irq = pdev->irq;
priv->reg_base = card->base_addr + EMS_PCI_CAN_BASE_OFFSET
+ (i * EMS_PCI_CAN_CTRL_SIZE);
+ if (card->version == 1) {
+ priv->read_reg = ems_pci_v1_read_reg;
+ priv->write_reg = ems_pci_v1_write_reg;
+ priv->post_irq = ems_pci_v1_post_irq;
+ } else {
+ priv->read_reg = ems_pci_v2_read_reg;
+ priv->write_reg = ems_pci_v2_write_reg;
+ priv->post_irq = ems_pci_v2_post_irq;
+ }
/* Check if channel is present */
if (ems_pci_check_chan(priv)) {
- priv->read_reg = ems_pci_read_reg;
- priv->write_reg = ems_pci_write_reg;
- priv->post_irq = ems_pci_post_irq;
priv->can.clock.freq = EMS_PCI_CAN_CLOCK;
priv->ocr = EMS_PCI_OCR;
priv->cdr = EMS_PCI_CDR;
SET_NETDEV_DEV(dev, &pdev->dev);
- /* Enable interrupts from card */
- writel(PITA2_ICR_INT0_EN, card->conf_addr + PITA2_ICR);
+ if (card->version == 1)
+ /* reset int flag of pita */
+ writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0,
+ card->conf_addr + PITA2_ICR);
+ else
+ /* enable IRQ in PLX 9030 */
+ writel(PLX_ICSR_ENA_CLR,
+ card->conf_addr + PLX_ICSR);
/* Register SJA1000 device */
err = register_sja1000dev(dev);
diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c
index 08ebee79d8a6..b3004de1e5e4 100644
--- a/drivers/net/can/sja1000/sja1000.c
+++ b/drivers/net/can/sja1000/sja1000.c
@@ -282,7 +282,7 @@ static int sja1000_start_xmit(struct sk_buff *skb, struct net_device *dev)
priv->write_reg(priv, REG_CMR, CMD_TR);
- return 0;
+ return NETDEV_TX_OK;
}
static void sja1000_rx(struct net_device *dev)
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index eb066673c2a0..299a33b914f8 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -2928,7 +2928,7 @@ static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev)
static int ring;
if (skb_padto(skb, cp->min_frame_size))
- return 0;
+ return NETDEV_TX_OK;
/* XXX: we need some higher-level QoS hooks to steer packets to
* individual queues.
@@ -2936,7 +2936,7 @@ static int 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 0;
+ return NETDEV_TX_OK;
}
static void cas_init_tx_dma(struct cas *cp)
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
index 7a18dc7e5c7f..15c0195ebd31 100644
--- a/drivers/net/cris/eth_v10.c
+++ b/drivers/net/cris/eth_v10.c
@@ -1108,7 +1108,7 @@ e100_send_packet(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&np->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index 55445f980f9c..ecf88abbf99e 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -1367,7 +1367,7 @@ net_open(struct net_device *dev)
spin_lock_irqsave(&lp->lock, flags);
disable_dma(dev->dma);
clear_dma_ff(dev->dma);
- set_dma_mode(dev->dma, 0x14); /* auto_init as well */
+ set_dma_mode(dev->dma, DMA_RX_MODE); /* auto_init as well */
set_dma_addr(dev->dma, isa_virt_to_bus(lp->dma_buff));
set_dma_count(dev->dma, lp->dmasize*1024);
enable_dma(dev->dma);
@@ -1572,7 +1572,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
* to restart the netdevice layer
*/
- return 0;
+ return NETDEV_TX_OK;
}
/* The typical workload of the driver:
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
index 1694fad38720..74723f2e7431 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/cxgb3/adapter.h
@@ -276,6 +276,14 @@ static inline struct port_info *adap2pinfo(struct adapter *adap, int idx)
return netdev_priv(adap->port[idx]);
}
+static inline int phy2portid(struct cphy *phy)
+{
+ struct adapter *adap = phy->adapter;
+ struct port_info *port0 = adap2pinfo(adap, 0);
+
+ return &port0->phy == phy ? 0 : 1;
+}
+
#define OFFLOAD_DEVMAP_BIT 15
#define tdev2adap(d) container_of(d, struct adapter, tdev)
@@ -312,4 +320,6 @@ int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx,
unsigned char *data);
irqreturn_t t3_sge_intr_msix(int irq, void *cookie);
+int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size);
+
#endif /* __T3_ADAPTER_H__ */
diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c
index 9fe008ec9ba5..5248f9e0b2f4 100644
--- a/drivers/net/cxgb3/ael1002.c
+++ b/drivers/net/cxgb3/ael1002.c
@@ -224,12 +224,6 @@ static int ael1006_reset(struct cphy *phy, int wait)
return t3_phy_reset(phy, MDIO_MMD_PMAPMD, wait);
}
-static int ael1006_power_down(struct cphy *phy, int enable)
-{
- return mdio_set_flag(&phy->mdio, phy->mdio.prtad, MDIO_MMD_PMAPMD,
- MDIO_CTRL1, MDIO_CTRL1_LPOWER, enable);
-}
-
static struct cphy_ops ael1006_ops = {
.reset = ael1006_reset,
.intr_enable = t3_phy_lasi_intr_enable,
@@ -237,7 +231,7 @@ static struct cphy_ops ael1006_ops = {
.intr_clear = t3_phy_lasi_intr_clear,
.intr_handler = t3_phy_lasi_intr_handler,
.get_link_status = get_link_status_r,
- .power_down = ael1006_power_down,
+ .power_down = ael1002_power_down,
.mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
};
@@ -304,279 +298,7 @@ static int ael2005_setup_sr_edc(struct cphy *phy)
{ MDIO_MMD_PMAPMD, 0xc04a, 0xffff, 0x5200 },
{ 0, 0, 0, 0 }
};
- static u16 sr_edc[] = {
- 0xcc00, 0x2ff4,
- 0xcc01, 0x3cd4,
- 0xcc02, 0x2015,
- 0xcc03, 0x3105,
- 0xcc04, 0x6524,
- 0xcc05, 0x27ff,
- 0xcc06, 0x300f,
- 0xcc07, 0x2c8b,
- 0xcc08, 0x300b,
- 0xcc09, 0x4009,
- 0xcc0a, 0x400e,
- 0xcc0b, 0x2f72,
- 0xcc0c, 0x3002,
- 0xcc0d, 0x1002,
- 0xcc0e, 0x2172,
- 0xcc0f, 0x3012,
- 0xcc10, 0x1002,
- 0xcc11, 0x25d2,
- 0xcc12, 0x3012,
- 0xcc13, 0x1002,
- 0xcc14, 0xd01e,
- 0xcc15, 0x27d2,
- 0xcc16, 0x3012,
- 0xcc17, 0x1002,
- 0xcc18, 0x2004,
- 0xcc19, 0x3c84,
- 0xcc1a, 0x6436,
- 0xcc1b, 0x2007,
- 0xcc1c, 0x3f87,
- 0xcc1d, 0x8676,
- 0xcc1e, 0x40b7,
- 0xcc1f, 0xa746,
- 0xcc20, 0x4047,
- 0xcc21, 0x5673,
- 0xcc22, 0x2982,
- 0xcc23, 0x3002,
- 0xcc24, 0x13d2,
- 0xcc25, 0x8bbd,
- 0xcc26, 0x2862,
- 0xcc27, 0x3012,
- 0xcc28, 0x1002,
- 0xcc29, 0x2092,
- 0xcc2a, 0x3012,
- 0xcc2b, 0x1002,
- 0xcc2c, 0x5cc3,
- 0xcc2d, 0x314,
- 0xcc2e, 0x2942,
- 0xcc2f, 0x3002,
- 0xcc30, 0x1002,
- 0xcc31, 0xd019,
- 0xcc32, 0x2032,
- 0xcc33, 0x3012,
- 0xcc34, 0x1002,
- 0xcc35, 0x2a04,
- 0xcc36, 0x3c74,
- 0xcc37, 0x6435,
- 0xcc38, 0x2fa4,
- 0xcc39, 0x3cd4,
- 0xcc3a, 0x6624,
- 0xcc3b, 0x5563,
- 0xcc3c, 0x2d42,
- 0xcc3d, 0x3002,
- 0xcc3e, 0x13d2,
- 0xcc3f, 0x464d,
- 0xcc40, 0x2862,
- 0xcc41, 0x3012,
- 0xcc42, 0x1002,
- 0xcc43, 0x2032,
- 0xcc44, 0x3012,
- 0xcc45, 0x1002,
- 0xcc46, 0x2fb4,
- 0xcc47, 0x3cd4,
- 0xcc48, 0x6624,
- 0xcc49, 0x5563,
- 0xcc4a, 0x2d42,
- 0xcc4b, 0x3002,
- 0xcc4c, 0x13d2,
- 0xcc4d, 0x2ed2,
- 0xcc4e, 0x3002,
- 0xcc4f, 0x1002,
- 0xcc50, 0x2fd2,
- 0xcc51, 0x3002,
- 0xcc52, 0x1002,
- 0xcc53, 0x004,
- 0xcc54, 0x2942,
- 0xcc55, 0x3002,
- 0xcc56, 0x1002,
- 0xcc57, 0x2092,
- 0xcc58, 0x3012,
- 0xcc59, 0x1002,
- 0xcc5a, 0x5cc3,
- 0xcc5b, 0x317,
- 0xcc5c, 0x2f72,
- 0xcc5d, 0x3002,
- 0xcc5e, 0x1002,
- 0xcc5f, 0x2942,
- 0xcc60, 0x3002,
- 0xcc61, 0x1002,
- 0xcc62, 0x22cd,
- 0xcc63, 0x301d,
- 0xcc64, 0x2862,
- 0xcc65, 0x3012,
- 0xcc66, 0x1002,
- 0xcc67, 0x2ed2,
- 0xcc68, 0x3002,
- 0xcc69, 0x1002,
- 0xcc6a, 0x2d72,
- 0xcc6b, 0x3002,
- 0xcc6c, 0x1002,
- 0xcc6d, 0x628f,
- 0xcc6e, 0x2112,
- 0xcc6f, 0x3012,
- 0xcc70, 0x1002,
- 0xcc71, 0x5aa3,
- 0xcc72, 0x2dc2,
- 0xcc73, 0x3002,
- 0xcc74, 0x1312,
- 0xcc75, 0x6f72,
- 0xcc76, 0x1002,
- 0xcc77, 0x2807,
- 0xcc78, 0x31a7,
- 0xcc79, 0x20c4,
- 0xcc7a, 0x3c24,
- 0xcc7b, 0x6724,
- 0xcc7c, 0x1002,
- 0xcc7d, 0x2807,
- 0xcc7e, 0x3187,
- 0xcc7f, 0x20c4,
- 0xcc80, 0x3c24,
- 0xcc81, 0x6724,
- 0xcc82, 0x1002,
- 0xcc83, 0x2514,
- 0xcc84, 0x3c64,
- 0xcc85, 0x6436,
- 0xcc86, 0xdff4,
- 0xcc87, 0x6436,
- 0xcc88, 0x1002,
- 0xcc89, 0x40a4,
- 0xcc8a, 0x643c,
- 0xcc8b, 0x4016,
- 0xcc8c, 0x8c6c,
- 0xcc8d, 0x2b24,
- 0xcc8e, 0x3c24,
- 0xcc8f, 0x6435,
- 0xcc90, 0x1002,
- 0xcc91, 0x2b24,
- 0xcc92, 0x3c24,
- 0xcc93, 0x643a,
- 0xcc94, 0x4025,
- 0xcc95, 0x8a5a,
- 0xcc96, 0x1002,
- 0xcc97, 0x2731,
- 0xcc98, 0x3011,
- 0xcc99, 0x1001,
- 0xcc9a, 0xc7a0,
- 0xcc9b, 0x100,
- 0xcc9c, 0xc502,
- 0xcc9d, 0x53ac,
- 0xcc9e, 0xc503,
- 0xcc9f, 0xd5d5,
- 0xcca0, 0xc600,
- 0xcca1, 0x2a6d,
- 0xcca2, 0xc601,
- 0xcca3, 0x2a4c,
- 0xcca4, 0xc602,
- 0xcca5, 0x111,
- 0xcca6, 0xc60c,
- 0xcca7, 0x5900,
- 0xcca8, 0xc710,
- 0xcca9, 0x700,
- 0xccaa, 0xc718,
- 0xccab, 0x700,
- 0xccac, 0xc720,
- 0xccad, 0x4700,
- 0xccae, 0xc801,
- 0xccaf, 0x7f50,
- 0xccb0, 0xc802,
- 0xccb1, 0x7760,
- 0xccb2, 0xc803,
- 0xccb3, 0x7fce,
- 0xccb4, 0xc804,
- 0xccb5, 0x5700,
- 0xccb6, 0xc805,
- 0xccb7, 0x5f11,
- 0xccb8, 0xc806,
- 0xccb9, 0x4751,
- 0xccba, 0xc807,
- 0xccbb, 0x57e1,
- 0xccbc, 0xc808,
- 0xccbd, 0x2700,
- 0xccbe, 0xc809,
- 0xccbf, 0x000,
- 0xccc0, 0xc821,
- 0xccc1, 0x002,
- 0xccc2, 0xc822,
- 0xccc3, 0x014,
- 0xccc4, 0xc832,
- 0xccc5, 0x1186,
- 0xccc6, 0xc847,
- 0xccc7, 0x1e02,
- 0xccc8, 0xc013,
- 0xccc9, 0xf341,
- 0xccca, 0xc01a,
- 0xcccb, 0x446,
- 0xcccc, 0xc024,
- 0xcccd, 0x1000,
- 0xccce, 0xc025,
- 0xcccf, 0xa00,
- 0xccd0, 0xc026,
- 0xccd1, 0xc0c,
- 0xccd2, 0xc027,
- 0xccd3, 0xc0c,
- 0xccd4, 0xc029,
- 0xccd5, 0x0a0,
- 0xccd6, 0xc030,
- 0xccd7, 0xa00,
- 0xccd8, 0xc03c,
- 0xccd9, 0x01c,
- 0xccda, 0xc005,
- 0xccdb, 0x7a06,
- 0xccdc, 0x000,
- 0xccdd, 0x2731,
- 0xccde, 0x3011,
- 0xccdf, 0x1001,
- 0xcce0, 0xc620,
- 0xcce1, 0x000,
- 0xcce2, 0xc621,
- 0xcce3, 0x03f,
- 0xcce4, 0xc622,
- 0xcce5, 0x000,
- 0xcce6, 0xc623,
- 0xcce7, 0x000,
- 0xcce8, 0xc624,
- 0xcce9, 0x000,
- 0xccea, 0xc625,
- 0xcceb, 0x000,
- 0xccec, 0xc627,
- 0xcced, 0x000,
- 0xccee, 0xc628,
- 0xccef, 0x000,
- 0xccf0, 0xc62c,
- 0xccf1, 0x000,
- 0xccf2, 0x000,
- 0xccf3, 0x2806,
- 0xccf4, 0x3cb6,
- 0xccf5, 0xc161,
- 0xccf6, 0x6134,
- 0xccf7, 0x6135,
- 0xccf8, 0x5443,
- 0xccf9, 0x303,
- 0xccfa, 0x6524,
- 0xccfb, 0x00b,
- 0xccfc, 0x1002,
- 0xccfd, 0x2104,
- 0xccfe, 0x3c24,
- 0xccff, 0x2105,
- 0xcd00, 0x3805,
- 0xcd01, 0x6524,
- 0xcd02, 0xdff4,
- 0xcd03, 0x4005,
- 0xcd04, 0x6524,
- 0xcd05, 0x1002,
- 0xcd06, 0x5dd3,
- 0xcd07, 0x306,
- 0xcd08, 0x2ff7,
- 0xcd09, 0x38f7,
- 0xcd0a, 0x60b7,
- 0xcd0b, 0xdffd,
- 0xcd0c, 0x00a,
- 0xcd0d, 0x1002,
- 0xcd0e, 0
- };
+
int i, err;
err = set_phy_regs(phy, regs);
@@ -585,9 +307,16 @@ static int ael2005_setup_sr_edc(struct cphy *phy)
msleep(50);
- for (i = 0; i < ARRAY_SIZE(sr_edc) && !err; i += 2)
- err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, sr_edc[i],
- sr_edc[i + 1]);
+ if (phy->priv != edc_sr)
+ err = t3_get_edc_fw(phy, EDC_OPT_AEL2005,
+ EDC_OPT_AEL2005_SIZE);
+ if (err)
+ return err;
+
+ for (i = 0; i < EDC_OPT_AEL2005_SIZE / sizeof(u16) && !err; i += 2)
+ err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
+ phy->phy_cache[i],
+ phy->phy_cache[i + 1]);
if (!err)
phy->priv = edc_sr;
return err;
@@ -604,374 +333,6 @@ static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype)
{ MDIO_MMD_PMAPMD, 0xc015, 0xffff, 0xa000 },
{ 0, 0, 0, 0 }
};
- static u16 twinax_edc[] = {
- 0xcc00, 0x4009,
- 0xcc01, 0x27ff,
- 0xcc02, 0x300f,
- 0xcc03, 0x40aa,
- 0xcc04, 0x401c,
- 0xcc05, 0x401e,
- 0xcc06, 0x2ff4,
- 0xcc07, 0x3cd4,
- 0xcc08, 0x2035,
- 0xcc09, 0x3145,
- 0xcc0a, 0x6524,
- 0xcc0b, 0x26a2,
- 0xcc0c, 0x3012,
- 0xcc0d, 0x1002,
- 0xcc0e, 0x29c2,
- 0xcc0f, 0x3002,
- 0xcc10, 0x1002,
- 0xcc11, 0x2072,
- 0xcc12, 0x3012,
- 0xcc13, 0x1002,
- 0xcc14, 0x22cd,
- 0xcc15, 0x301d,
- 0xcc16, 0x2e52,
- 0xcc17, 0x3012,
- 0xcc18, 0x1002,
- 0xcc19, 0x28e2,
- 0xcc1a, 0x3002,
- 0xcc1b, 0x1002,
- 0xcc1c, 0x628f,
- 0xcc1d, 0x2ac2,
- 0xcc1e, 0x3012,
- 0xcc1f, 0x1002,
- 0xcc20, 0x5553,
- 0xcc21, 0x2ae2,
- 0xcc22, 0x3002,
- 0xcc23, 0x1302,
- 0xcc24, 0x401e,
- 0xcc25, 0x2be2,
- 0xcc26, 0x3012,
- 0xcc27, 0x1002,
- 0xcc28, 0x2da2,
- 0xcc29, 0x3012,
- 0xcc2a, 0x1002,
- 0xcc2b, 0x2ba2,
- 0xcc2c, 0x3002,
- 0xcc2d, 0x1002,
- 0xcc2e, 0x5ee3,
- 0xcc2f, 0x305,
- 0xcc30, 0x400e,
- 0xcc31, 0x2bc2,
- 0xcc32, 0x3002,
- 0xcc33, 0x1002,
- 0xcc34, 0x2b82,
- 0xcc35, 0x3012,
- 0xcc36, 0x1002,
- 0xcc37, 0x5663,
- 0xcc38, 0x302,
- 0xcc39, 0x401e,
- 0xcc3a, 0x6f72,
- 0xcc3b, 0x1002,
- 0xcc3c, 0x628f,
- 0xcc3d, 0x2be2,
- 0xcc3e, 0x3012,
- 0xcc3f, 0x1002,
- 0xcc40, 0x22cd,
- 0xcc41, 0x301d,
- 0xcc42, 0x2e52,
- 0xcc43, 0x3012,
- 0xcc44, 0x1002,
- 0xcc45, 0x2522,
- 0xcc46, 0x3012,
- 0xcc47, 0x1002,
- 0xcc48, 0x2da2,
- 0xcc49, 0x3012,
- 0xcc4a, 0x1002,
- 0xcc4b, 0x2ca2,
- 0xcc4c, 0x3012,
- 0xcc4d, 0x1002,
- 0xcc4e, 0x2fa4,
- 0xcc4f, 0x3cd4,
- 0xcc50, 0x6624,
- 0xcc51, 0x410b,
- 0xcc52, 0x56b3,
- 0xcc53, 0x3c4,
- 0xcc54, 0x2fb2,
- 0xcc55, 0x3002,
- 0xcc56, 0x1002,
- 0xcc57, 0x220b,
- 0xcc58, 0x303b,
- 0xcc59, 0x56b3,
- 0xcc5a, 0x3c3,
- 0xcc5b, 0x866b,
- 0xcc5c, 0x400c,
- 0xcc5d, 0x23a2,
- 0xcc5e, 0x3012,
- 0xcc5f, 0x1002,
- 0xcc60, 0x2da2,
- 0xcc61, 0x3012,
- 0xcc62, 0x1002,
- 0xcc63, 0x2ca2,
- 0xcc64, 0x3012,
- 0xcc65, 0x1002,
- 0xcc66, 0x2fb4,
- 0xcc67, 0x3cd4,
- 0xcc68, 0x6624,
- 0xcc69, 0x56b3,
- 0xcc6a, 0x3c3,
- 0xcc6b, 0x866b,
- 0xcc6c, 0x401c,
- 0xcc6d, 0x2205,
- 0xcc6e, 0x3035,
- 0xcc6f, 0x5b53,
- 0xcc70, 0x2c52,
- 0xcc71, 0x3002,
- 0xcc72, 0x13c2,
- 0xcc73, 0x5cc3,
- 0xcc74, 0x317,
- 0xcc75, 0x2522,
- 0xcc76, 0x3012,
- 0xcc77, 0x1002,
- 0xcc78, 0x2da2,
- 0xcc79, 0x3012,
- 0xcc7a, 0x1002,
- 0xcc7b, 0x2b82,
- 0xcc7c, 0x3012,
- 0xcc7d, 0x1002,
- 0xcc7e, 0x5663,
- 0xcc7f, 0x303,
- 0xcc80, 0x401e,
- 0xcc81, 0x004,
- 0xcc82, 0x2c42,
- 0xcc83, 0x3012,
- 0xcc84, 0x1002,
- 0xcc85, 0x6f72,
- 0xcc86, 0x1002,
- 0xcc87, 0x628f,
- 0xcc88, 0x2304,
- 0xcc89, 0x3c84,
- 0xcc8a, 0x6436,
- 0xcc8b, 0xdff4,
- 0xcc8c, 0x6436,
- 0xcc8d, 0x2ff5,
- 0xcc8e, 0x3005,
- 0xcc8f, 0x8656,
- 0xcc90, 0xdfba,
- 0xcc91, 0x56a3,
- 0xcc92, 0xd05a,
- 0xcc93, 0x21c2,
- 0xcc94, 0x3012,
- 0xcc95, 0x1392,
- 0xcc96, 0xd05a,
- 0xcc97, 0x56a3,
- 0xcc98, 0xdfba,
- 0xcc99, 0x383,
- 0xcc9a, 0x6f72,
- 0xcc9b, 0x1002,
- 0xcc9c, 0x28c5,
- 0xcc9d, 0x3005,
- 0xcc9e, 0x4178,
- 0xcc9f, 0x5653,
- 0xcca0, 0x384,
- 0xcca1, 0x22b2,
- 0xcca2, 0x3012,
- 0xcca3, 0x1002,
- 0xcca4, 0x2be5,
- 0xcca5, 0x3005,
- 0xcca6, 0x41e8,
- 0xcca7, 0x5653,
- 0xcca8, 0x382,
- 0xcca9, 0x002,
- 0xccaa, 0x4258,
- 0xccab, 0x2474,
- 0xccac, 0x3c84,
- 0xccad, 0x6437,
- 0xccae, 0xdff4,
- 0xccaf, 0x6437,
- 0xccb0, 0x2ff5,
- 0xccb1, 0x3c05,
- 0xccb2, 0x8757,
- 0xccb3, 0xb888,
- 0xccb4, 0x9787,
- 0xccb5, 0xdff4,
- 0xccb6, 0x6724,
- 0xccb7, 0x866a,
- 0xccb8, 0x6f72,
- 0xccb9, 0x1002,
- 0xccba, 0x2d01,
- 0xccbb, 0x3011,
- 0xccbc, 0x1001,
- 0xccbd, 0xc620,
- 0xccbe, 0x14e5,
- 0xccbf, 0xc621,
- 0xccc0, 0xc53d,
- 0xccc1, 0xc622,
- 0xccc2, 0x3cbe,
- 0xccc3, 0xc623,
- 0xccc4, 0x4452,
- 0xccc5, 0xc624,
- 0xccc6, 0xc5c5,
- 0xccc7, 0xc625,
- 0xccc8, 0xe01e,
- 0xccc9, 0xc627,
- 0xccca, 0x000,
- 0xcccb, 0xc628,
- 0xcccc, 0x000,
- 0xcccd, 0xc62b,
- 0xccce, 0x000,
- 0xcccf, 0xc62c,
- 0xccd0, 0x000,
- 0xccd1, 0x000,
- 0xccd2, 0x2d01,
- 0xccd3, 0x3011,
- 0xccd4, 0x1001,
- 0xccd5, 0xc620,
- 0xccd6, 0x000,
- 0xccd7, 0xc621,
- 0xccd8, 0x000,
- 0xccd9, 0xc622,
- 0xccda, 0x0ce,
- 0xccdb, 0xc623,
- 0xccdc, 0x07f,
- 0xccdd, 0xc624,
- 0xccde, 0x032,
- 0xccdf, 0xc625,
- 0xcce0, 0x000,
- 0xcce1, 0xc627,
- 0xcce2, 0x000,
- 0xcce3, 0xc628,
- 0xcce4, 0x000,
- 0xcce5, 0xc62b,
- 0xcce6, 0x000,
- 0xcce7, 0xc62c,
- 0xcce8, 0x000,
- 0xcce9, 0x000,
- 0xccea, 0x2d01,
- 0xcceb, 0x3011,
- 0xccec, 0x1001,
- 0xcced, 0xc502,
- 0xccee, 0x609f,
- 0xccef, 0xc600,
- 0xccf0, 0x2a6e,
- 0xccf1, 0xc601,
- 0xccf2, 0x2a2c,
- 0xccf3, 0xc60c,
- 0xccf4, 0x5400,
- 0xccf5, 0xc710,
- 0xccf6, 0x700,
- 0xccf7, 0xc718,
- 0xccf8, 0x700,
- 0xccf9, 0xc720,
- 0xccfa, 0x4700,
- 0xccfb, 0xc728,
- 0xccfc, 0x700,
- 0xccfd, 0xc729,
- 0xccfe, 0x1207,
- 0xccff, 0xc801,
- 0xcd00, 0x7f50,
- 0xcd01, 0xc802,
- 0xcd02, 0x7760,
- 0xcd03, 0xc803,
- 0xcd04, 0x7fce,
- 0xcd05, 0xc804,
- 0xcd06, 0x520e,
- 0xcd07, 0xc805,
- 0xcd08, 0x5c11,
- 0xcd09, 0xc806,
- 0xcd0a, 0x3c51,
- 0xcd0b, 0xc807,
- 0xcd0c, 0x4061,
- 0xcd0d, 0xc808,
- 0xcd0e, 0x49c1,
- 0xcd0f, 0xc809,
- 0xcd10, 0x3840,
- 0xcd11, 0xc80a,
- 0xcd12, 0x000,
- 0xcd13, 0xc821,
- 0xcd14, 0x002,
- 0xcd15, 0xc822,
- 0xcd16, 0x046,
- 0xcd17, 0xc844,
- 0xcd18, 0x182f,
- 0xcd19, 0xc013,
- 0xcd1a, 0xf341,
- 0xcd1b, 0xc01a,
- 0xcd1c, 0x446,
- 0xcd1d, 0xc024,
- 0xcd1e, 0x1000,
- 0xcd1f, 0xc025,
- 0xcd20, 0xa00,
- 0xcd21, 0xc026,
- 0xcd22, 0xc0c,
- 0xcd23, 0xc027,
- 0xcd24, 0xc0c,
- 0xcd25, 0xc029,
- 0xcd26, 0x0a0,
- 0xcd27, 0xc030,
- 0xcd28, 0xa00,
- 0xcd29, 0xc03c,
- 0xcd2a, 0x01c,
- 0xcd2b, 0x000,
- 0xcd2c, 0x2b84,
- 0xcd2d, 0x3c74,
- 0xcd2e, 0x6435,
- 0xcd2f, 0xdff4,
- 0xcd30, 0x6435,
- 0xcd31, 0x2806,
- 0xcd32, 0x3006,
- 0xcd33, 0x8565,
- 0xcd34, 0x2b24,
- 0xcd35, 0x3c24,
- 0xcd36, 0x6436,
- 0xcd37, 0x1002,
- 0xcd38, 0x2b24,
- 0xcd39, 0x3c24,
- 0xcd3a, 0x6436,
- 0xcd3b, 0x4045,
- 0xcd3c, 0x8656,
- 0xcd3d, 0x1002,
- 0xcd3e, 0x2807,
- 0xcd3f, 0x31a7,
- 0xcd40, 0x20c4,
- 0xcd41, 0x3c24,
- 0xcd42, 0x6724,
- 0xcd43, 0x1002,
- 0xcd44, 0x2807,
- 0xcd45, 0x3187,
- 0xcd46, 0x20c4,
- 0xcd47, 0x3c24,
- 0xcd48, 0x6724,
- 0xcd49, 0x1002,
- 0xcd4a, 0x2514,
- 0xcd4b, 0x3c64,
- 0xcd4c, 0x6436,
- 0xcd4d, 0xdff4,
- 0xcd4e, 0x6436,
- 0xcd4f, 0x1002,
- 0xcd50, 0x2806,
- 0xcd51, 0x3cb6,
- 0xcd52, 0xc161,
- 0xcd53, 0x6134,
- 0xcd54, 0x6135,
- 0xcd55, 0x5443,
- 0xcd56, 0x303,
- 0xcd57, 0x6524,
- 0xcd58, 0x00b,
- 0xcd59, 0x1002,
- 0xcd5a, 0xd019,
- 0xcd5b, 0x2104,
- 0xcd5c, 0x3c24,
- 0xcd5d, 0x2105,
- 0xcd5e, 0x3805,
- 0xcd5f, 0x6524,
- 0xcd60, 0xdff4,
- 0xcd61, 0x4005,
- 0xcd62, 0x6524,
- 0xcd63, 0x2e8d,
- 0xcd64, 0x303d,
- 0xcd65, 0x5dd3,
- 0xcd66, 0x306,
- 0xcd67, 0x2ff7,
- 0xcd68, 0x38f7,
- 0xcd69, 0x60b7,
- 0xcd6a, 0xdffd,
- 0xcd6b, 0x00a,
- 0xcd6c, 0x1002,
- 0xcd6d, 0
- };
int i, err;
err = set_phy_regs(phy, regs);
@@ -982,9 +343,16 @@ static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype)
msleep(50);
- for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2)
- err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, twinax_edc[i],
- twinax_edc[i + 1]);
+ if (phy->priv != edc_twinax)
+ err = t3_get_edc_fw(phy, EDC_TWX_AEL2005,
+ EDC_TWX_AEL2005_SIZE);
+ if (err)
+ return err;
+
+ for (i = 0; i < EDC_TWX_AEL2005_SIZE / sizeof(u16) && !err; i += 2)
+ err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
+ phy->phy_cache[i],
+ phy->phy_cache[i + 1]);
if (!err)
phy->priv = edc_twinax;
return err;
@@ -1201,405 +569,6 @@ static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype)
{ MDIO_MMD_PMAPMD, 0xd092, 0xffff, 0x0000 },
{ 0, 0, 0, 0 }
};
-
- /* TWINAX EDC firmware */
- static u16 twinax_edc[] = {
- 0xd800, 0x4009,
- 0xd801, 0x2fff,
- 0xd802, 0x300f,
- 0xd803, 0x40aa,
- 0xd804, 0x401c,
- 0xd805, 0x401e,
- 0xd806, 0x2ff4,
- 0xd807, 0x3dc4,
- 0xd808, 0x2035,
- 0xd809, 0x3035,
- 0xd80a, 0x6524,
- 0xd80b, 0x2cb2,
- 0xd80c, 0x3012,
- 0xd80d, 0x1002,
- 0xd80e, 0x26e2,
- 0xd80f, 0x3022,
- 0xd810, 0x1002,
- 0xd811, 0x27d2,
- 0xd812, 0x3022,
- 0xd813, 0x1002,
- 0xd814, 0x2822,
- 0xd815, 0x3012,
- 0xd816, 0x1002,
- 0xd817, 0x2492,
- 0xd818, 0x3022,
- 0xd819, 0x1002,
- 0xd81a, 0x2772,
- 0xd81b, 0x3012,
- 0xd81c, 0x1002,
- 0xd81d, 0x23d2,
- 0xd81e, 0x3022,
- 0xd81f, 0x1002,
- 0xd820, 0x22cd,
- 0xd821, 0x301d,
- 0xd822, 0x27f2,
- 0xd823, 0x3022,
- 0xd824, 0x1002,
- 0xd825, 0x5553,
- 0xd826, 0x0307,
- 0xd827, 0x2522,
- 0xd828, 0x3022,
- 0xd829, 0x1002,
- 0xd82a, 0x2142,
- 0xd82b, 0x3012,
- 0xd82c, 0x1002,
- 0xd82d, 0x4016,
- 0xd82e, 0x5e63,
- 0xd82f, 0x0344,
- 0xd830, 0x2142,
- 0xd831, 0x3012,
- 0xd832, 0x1002,
- 0xd833, 0x400e,
- 0xd834, 0x2522,
- 0xd835, 0x3022,
- 0xd836, 0x1002,
- 0xd837, 0x2b52,
- 0xd838, 0x3012,
- 0xd839, 0x1002,
- 0xd83a, 0x2742,
- 0xd83b, 0x3022,
- 0xd83c, 0x1002,
- 0xd83d, 0x25e2,
- 0xd83e, 0x3022,
- 0xd83f, 0x1002,
- 0xd840, 0x2fa4,
- 0xd841, 0x3dc4,
- 0xd842, 0x6624,
- 0xd843, 0x414b,
- 0xd844, 0x56b3,
- 0xd845, 0x03c6,
- 0xd846, 0x866b,
- 0xd847, 0x400c,
- 0xd848, 0x2712,
- 0xd849, 0x3012,
- 0xd84a, 0x1002,
- 0xd84b, 0x2c4b,
- 0xd84c, 0x309b,
- 0xd84d, 0x56b3,
- 0xd84e, 0x03c3,
- 0xd84f, 0x866b,
- 0xd850, 0x400c,
- 0xd851, 0x2272,
- 0xd852, 0x3022,
- 0xd853, 0x1002,
- 0xd854, 0x2742,
- 0xd855, 0x3022,
- 0xd856, 0x1002,
- 0xd857, 0x25e2,
- 0xd858, 0x3022,
- 0xd859, 0x1002,
- 0xd85a, 0x2fb4,
- 0xd85b, 0x3dc4,
- 0xd85c, 0x6624,
- 0xd85d, 0x56b3,
- 0xd85e, 0x03c3,
- 0xd85f, 0x866b,
- 0xd860, 0x401c,
- 0xd861, 0x2c45,
- 0xd862, 0x3095,
- 0xd863, 0x5b53,
- 0xd864, 0x2372,
- 0xd865, 0x3012,
- 0xd866, 0x13c2,
- 0xd867, 0x5cc3,
- 0xd868, 0x2712,
- 0xd869, 0x3012,
- 0xd86a, 0x1312,
- 0xd86b, 0x2b52,
- 0xd86c, 0x3012,
- 0xd86d, 0x1002,
- 0xd86e, 0x2742,
- 0xd86f, 0x3022,
- 0xd870, 0x1002,
- 0xd871, 0x2582,
- 0xd872, 0x3022,
- 0xd873, 0x1002,
- 0xd874, 0x2142,
- 0xd875, 0x3012,
- 0xd876, 0x1002,
- 0xd877, 0x628f,
- 0xd878, 0x2985,
- 0xd879, 0x33a5,
- 0xd87a, 0x25e2,
- 0xd87b, 0x3022,
- 0xd87c, 0x1002,
- 0xd87d, 0x5653,
- 0xd87e, 0x03d2,
- 0xd87f, 0x401e,
- 0xd880, 0x6f72,
- 0xd881, 0x1002,
- 0xd882, 0x628f,
- 0xd883, 0x2304,
- 0xd884, 0x3c84,
- 0xd885, 0x6436,
- 0xd886, 0xdff4,
- 0xd887, 0x6436,
- 0xd888, 0x2ff5,
- 0xd889, 0x3005,
- 0xd88a, 0x8656,
- 0xd88b, 0xdfba,
- 0xd88c, 0x56a3,
- 0xd88d, 0xd05a,
- 0xd88e, 0x2972,
- 0xd88f, 0x3012,
- 0xd890, 0x1392,
- 0xd891, 0xd05a,
- 0xd892, 0x56a3,
- 0xd893, 0xdfba,
- 0xd894, 0x0383,
- 0xd895, 0x6f72,
- 0xd896, 0x1002,
- 0xd897, 0x2b45,
- 0xd898, 0x3005,
- 0xd899, 0x4178,
- 0xd89a, 0x5653,
- 0xd89b, 0x0384,
- 0xd89c, 0x2a62,
- 0xd89d, 0x3012,
- 0xd89e, 0x1002,
- 0xd89f, 0x2f05,
- 0xd8a0, 0x3005,
- 0xd8a1, 0x41c8,
- 0xd8a2, 0x5653,
- 0xd8a3, 0x0382,
- 0xd8a4, 0x0002,
- 0xd8a5, 0x4218,
- 0xd8a6, 0x2474,
- 0xd8a7, 0x3c84,
- 0xd8a8, 0x6437,
- 0xd8a9, 0xdff4,
- 0xd8aa, 0x6437,
- 0xd8ab, 0x2ff5,
- 0xd8ac, 0x3c05,
- 0xd8ad, 0x8757,
- 0xd8ae, 0xb888,
- 0xd8af, 0x9787,
- 0xd8b0, 0xdff4,
- 0xd8b1, 0x6724,
- 0xd8b2, 0x866a,
- 0xd8b3, 0x6f72,
- 0xd8b4, 0x1002,
- 0xd8b5, 0x2641,
- 0xd8b6, 0x3021,
- 0xd8b7, 0x1001,
- 0xd8b8, 0xc620,
- 0xd8b9, 0x0000,
- 0xd8ba, 0xc621,
- 0xd8bb, 0x0000,
- 0xd8bc, 0xc622,
- 0xd8bd, 0x00ce,
- 0xd8be, 0xc623,
- 0xd8bf, 0x007f,
- 0xd8c0, 0xc624,
- 0xd8c1, 0x0032,
- 0xd8c2, 0xc625,
- 0xd8c3, 0x0000,
- 0xd8c4, 0xc627,
- 0xd8c5, 0x0000,
- 0xd8c6, 0xc628,
- 0xd8c7, 0x0000,
- 0xd8c8, 0xc62c,
- 0xd8c9, 0x0000,
- 0xd8ca, 0x0000,
- 0xd8cb, 0x2641,
- 0xd8cc, 0x3021,
- 0xd8cd, 0x1001,
- 0xd8ce, 0xc502,
- 0xd8cf, 0x53ac,
- 0xd8d0, 0xc503,
- 0xd8d1, 0x2cd3,
- 0xd8d2, 0xc600,
- 0xd8d3, 0x2a6e,
- 0xd8d4, 0xc601,
- 0xd8d5, 0x2a2c,
- 0xd8d6, 0xc605,
- 0xd8d7, 0x5557,
- 0xd8d8, 0xc60c,
- 0xd8d9, 0x5400,
- 0xd8da, 0xc710,
- 0xd8db, 0x0700,
- 0xd8dc, 0xc711,
- 0xd8dd, 0x0f06,
- 0xd8de, 0xc718,
- 0xd8df, 0x0700,
- 0xd8e0, 0xc719,
- 0xd8e1, 0x0f06,
- 0xd8e2, 0xc720,
- 0xd8e3, 0x4700,
- 0xd8e4, 0xc721,
- 0xd8e5, 0x0f06,
- 0xd8e6, 0xc728,
- 0xd8e7, 0x0700,
- 0xd8e8, 0xc729,
- 0xd8e9, 0x1207,
- 0xd8ea, 0xc801,
- 0xd8eb, 0x7f50,
- 0xd8ec, 0xc802,
- 0xd8ed, 0x7760,
- 0xd8ee, 0xc803,
- 0xd8ef, 0x7fce,
- 0xd8f0, 0xc804,
- 0xd8f1, 0x520e,
- 0xd8f2, 0xc805,
- 0xd8f3, 0x5c11,
- 0xd8f4, 0xc806,
- 0xd8f5, 0x3c51,
- 0xd8f6, 0xc807,
- 0xd8f7, 0x4061,
- 0xd8f8, 0xc808,
- 0xd8f9, 0x49c1,
- 0xd8fa, 0xc809,
- 0xd8fb, 0x3840,
- 0xd8fc, 0xc80a,
- 0xd8fd, 0x0000,
- 0xd8fe, 0xc821,
- 0xd8ff, 0x0002,
- 0xd900, 0xc822,
- 0xd901, 0x0046,
- 0xd902, 0xc844,
- 0xd903, 0x182f,
- 0xd904, 0xc013,
- 0xd905, 0xf341,
- 0xd906, 0xc084,
- 0xd907, 0x0030,
- 0xd908, 0xc904,
- 0xd909, 0x1401,
- 0xd90a, 0xcb0c,
- 0xd90b, 0x0004,
- 0xd90c, 0xcb0e,
- 0xd90d, 0xa00a,
- 0xd90e, 0xcb0f,
- 0xd90f, 0xc0c0,
- 0xd910, 0xcb10,
- 0xd911, 0xc0c0,
- 0xd912, 0xcb11,
- 0xd913, 0x00a0,
- 0xd914, 0xcb12,
- 0xd915, 0x0007,
- 0xd916, 0xc241,
- 0xd917, 0xa000,
- 0xd918, 0xc243,
- 0xd919, 0x7fe0,
- 0xd91a, 0xc604,
- 0xd91b, 0x000e,
- 0xd91c, 0xc609,
- 0xd91d, 0x00f5,
- 0xd91e, 0xc611,
- 0xd91f, 0x000e,
- 0xd920, 0xc660,
- 0xd921, 0x9600,
- 0xd922, 0xc687,
- 0xd923, 0x0004,
- 0xd924, 0xc60a,
- 0xd925, 0x04f5,
- 0xd926, 0x0000,
- 0xd927, 0x2641,
- 0xd928, 0x3021,
- 0xd929, 0x1001,
- 0xd92a, 0xc620,
- 0xd92b, 0x14e5,
- 0xd92c, 0xc621,
- 0xd92d, 0xc53d,
- 0xd92e, 0xc622,
- 0xd92f, 0x3cbe,
- 0xd930, 0xc623,
- 0xd931, 0x4452,
- 0xd932, 0xc624,
- 0xd933, 0xc5c5,
- 0xd934, 0xc625,
- 0xd935, 0xe01e,
- 0xd936, 0xc627,
- 0xd937, 0x0000,
- 0xd938, 0xc628,
- 0xd939, 0x0000,
- 0xd93a, 0xc62c,
- 0xd93b, 0x0000,
- 0xd93c, 0x0000,
- 0xd93d, 0x2b84,
- 0xd93e, 0x3c74,
- 0xd93f, 0x6435,
- 0xd940, 0xdff4,
- 0xd941, 0x6435,
- 0xd942, 0x2806,
- 0xd943, 0x3006,
- 0xd944, 0x8565,
- 0xd945, 0x2b24,
- 0xd946, 0x3c24,
- 0xd947, 0x6436,
- 0xd948, 0x1002,
- 0xd949, 0x2b24,
- 0xd94a, 0x3c24,
- 0xd94b, 0x6436,
- 0xd94c, 0x4045,
- 0xd94d, 0x8656,
- 0xd94e, 0x5663,
- 0xd94f, 0x0302,
- 0xd950, 0x401e,
- 0xd951, 0x1002,
- 0xd952, 0x2807,
- 0xd953, 0x31a7,
- 0xd954, 0x20c4,
- 0xd955, 0x3c24,
- 0xd956, 0x6724,
- 0xd957, 0x1002,
- 0xd958, 0x2807,
- 0xd959, 0x3187,
- 0xd95a, 0x20c4,
- 0xd95b, 0x3c24,
- 0xd95c, 0x6724,
- 0xd95d, 0x1002,
- 0xd95e, 0x24f4,
- 0xd95f, 0x3c64,
- 0xd960, 0x6436,
- 0xd961, 0xdff4,
- 0xd962, 0x6436,
- 0xd963, 0x1002,
- 0xd964, 0x2006,
- 0xd965, 0x3d76,
- 0xd966, 0xc161,
- 0xd967, 0x6134,
- 0xd968, 0x6135,
- 0xd969, 0x5443,
- 0xd96a, 0x0303,
- 0xd96b, 0x6524,
- 0xd96c, 0x00fb,
- 0xd96d, 0x1002,
- 0xd96e, 0x20d4,
- 0xd96f, 0x3c24,
- 0xd970, 0x2025,
- 0xd971, 0x3005,
- 0xd972, 0x6524,
- 0xd973, 0x1002,
- 0xd974, 0xd019,
- 0xd975, 0x2104,
- 0xd976, 0x3c24,
- 0xd977, 0x2105,
- 0xd978, 0x3805,
- 0xd979, 0x6524,
- 0xd97a, 0xdff4,
- 0xd97b, 0x4005,
- 0xd97c, 0x6524,
- 0xd97d, 0x2e8d,
- 0xd97e, 0x303d,
- 0xd97f, 0x2408,
- 0xd980, 0x35d8,
- 0xd981, 0x5dd3,
- 0xd982, 0x0307,
- 0xd983, 0x8887,
- 0xd984, 0x63a7,
- 0xd985, 0x8887,
- 0xd986, 0x63a7,
- 0xd987, 0xdffd,
- 0xd988, 0x00f9,
- 0xd989, 0x1002,
- 0xd98a, 0x0000,
- };
int i, err;
/* set uC clock and activate it */
@@ -1612,10 +581,16 @@ static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype)
if (err)
return err;
- /* write TWINAX EDC firmware into PHY */
- for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2)
- err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, twinax_edc[i],
- twinax_edc[i + 1]);
+ if (phy->priv != edc_twinax)
+ err = t3_get_edc_fw(phy, EDC_TWX_AEL2020,
+ EDC_TWX_AEL2020_SIZE);
+ if (err)
+ return err;
+
+ for (i = 0; i < EDC_TWX_AEL2020_SIZE / sizeof(u16) && !err; i += 2)
+ err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
+ phy->phy_cache[i],
+ phy->phy_cache[i + 1]);
/* activate uC */
err = set_phy_regs(phy, uCactivate);
if (!err)
@@ -1649,9 +624,39 @@ static int ael2020_get_module_type(struct cphy *phy, int delay_ms)
*/
static int ael2020_intr_enable(struct cphy *phy)
{
- int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
- 0x2 << (AEL2020_GPIO_MODDET*4));
- return err ? err : t3_phy_lasi_intr_enable(phy);
+ struct reg_val regs[] = {
+ /* output Module's Loss Of Signal (LOS) to LED */
+ { MDIO_MMD_PMAPMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT,
+ 0xffff, 0x4 },
+ { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
+ 0xffff, 0x8 << (AEL2020_GPIO_LSTAT*4) },
+
+ /* enable module detect status change interrupts */
+ { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
+ 0xffff, 0x2 << (AEL2020_GPIO_MODDET*4) },
+
+ /* end */
+ { 0, 0, 0, 0 }
+ };
+ int err, link_ok = 0;
+
+ /* set up "link status" LED and enable module change interrupts */
+ err = set_phy_regs(phy, regs);
+ if (err)
+ return err;
+
+ err = get_link_status_r(phy, &link_ok, NULL, NULL, NULL);
+ if (err)
+ return err;
+ if (link_ok)
+ t3_link_changed(phy->adapter,
+ phy2portid(phy));
+
+ err = t3_phy_lasi_intr_enable(phy);
+ if (err)
+ return err;
+
+ return 0;
}
/*
@@ -1659,9 +664,26 @@ static int ael2020_intr_enable(struct cphy *phy)
*/
static int ael2020_intr_disable(struct cphy *phy)
{
- int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
- 0x1 << (AEL2020_GPIO_MODDET*4));
- return err ? err : t3_phy_lasi_intr_disable(phy);
+ struct reg_val regs[] = {
+ /* reset "link status" LED to "off" */
+ { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
+ 0xffff, 0xb << (AEL2020_GPIO_LSTAT*4) },
+
+ /* disable module detect status change interrupts */
+ { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
+ 0xffff, 0x1 << (AEL2020_GPIO_MODDET*4) },
+
+ /* end */
+ { 0, 0, 0, 0 }
+ };
+ int err;
+
+ /* turn off "link status" LED and disable module change interrupts */
+ err = set_phy_regs(phy, regs);
+ if (err)
+ return err;
+
+ return t3_phy_lasi_intr_disable(phy);
}
/*
@@ -1679,31 +701,26 @@ static int ael2020_intr_clear(struct cphy *phy)
return err ? err : t3_phy_lasi_intr_clear(phy);
}
+static struct reg_val ael2020_reset_regs[] = {
+ /* Erratum #2: CDRLOL asserted, causing PMA link down status */
+ { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x3101 },
+
+ /* force XAUI to send LF when RX_LOS is asserted */
+ { MDIO_MMD_PMAPMD, 0xcd40, 0xffff, 0x0001 },
+
+ /* allow writes to transceiver module EEPROM on i2c bus */
+ { MDIO_MMD_PMAPMD, 0xff02, 0xffff, 0x0023 },
+ { MDIO_MMD_PMAPMD, 0xff03, 0xffff, 0x0000 },
+ { MDIO_MMD_PMAPMD, 0xff04, 0xffff, 0x0000 },
+
+ /* end */
+ { 0, 0, 0, 0 }
+};
/*
* Reset the PHY and put it into a canonical operating state.
*/
static int ael2020_reset(struct cphy *phy, int wait)
{
- static struct reg_val regs0[] = {
- /* Erratum #2: CDRLOL asserted, causing PMA link down status */
- { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x3101 },
-
- /* force XAUI to send LF when RX_LOS is asserted */
- { MDIO_MMD_PMAPMD, 0xcd40, 0xffff, 0x0001 },
-
- /* RX_LOS pin is active high */
- { MDIO_MMD_PMAPMD, AEL_OPT_SETTINGS,
- 0x0020, 0x0020 },
-
- /* output Module's Loss Of Signal (LOS) to LED */
- { MDIO_MMD_PMAPMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT,
- 0xffff, 0x0004 },
- { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
- 0xffff, 0x8 << (AEL2020_GPIO_LSTAT*4) },
-
- /* end */
- { 0, 0, 0, 0 }
- };
int err;
unsigned int lasi_ctrl;
@@ -1720,7 +737,7 @@ static int ael2020_reset(struct cphy *phy, int wait)
/* basic initialization for all module types */
phy->priv = edc_none;
- err = set_phy_regs(phy, regs0);
+ err = set_phy_regs(phy, ael2020_reset_regs);
if (err)
return err;
@@ -1798,10 +815,16 @@ static struct cphy_ops ael2020_ops = {
int t3_ael2020_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
const struct mdio_ops *mdio_ops)
{
+ int err;
+
cphy_init(phy, adapter, phy_addr, &ael2020_ops, mdio_ops,
SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE |
SUPPORTED_IRQ, "10GBASE-R");
msleep(125);
+
+ err = set_phy_regs(phy, ael2020_reset_regs);
+ if (err)
+ return err;
return 0;
}
@@ -1840,7 +863,7 @@ static struct cphy_ops qt2045_ops = {
.intr_clear = t3_phy_lasi_intr_clear,
.intr_handler = t3_phy_lasi_intr_handler,
.get_link_status = get_link_status_x,
- .power_down = ael1006_power_down,
+ .power_down = ael1002_power_down,
.mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
};
diff --git a/drivers/net/cxgb3/aq100x.c b/drivers/net/cxgb3/aq100x.c
index b1fd5bf836e4..341b7ef1508f 100644
--- a/drivers/net/cxgb3/aq100x.c
+++ b/drivers/net/cxgb3/aq100x.c
@@ -271,7 +271,8 @@ int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
cphy_init(phy, adapter, phy_addr, &aq100x_ops, mdio_ops,
SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full |
- SUPPORTED_Autoneg | SUPPORTED_AUI, "1000/10GBASE-T");
+ SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_AUI,
+ "1000/10GBASE-T");
/*
* The PHY has been out of reset ever since the system powered up. So
@@ -316,11 +317,9 @@ int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
/* Firmware version check. */
t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_FW_VERSION, &v);
- if (v != 30) {
+ if (v != 101)
CH_WARN(adapter, "PHY%d: unsupported firmware %d\n",
phy_addr, v);
- return 0; /* allow t3_prep_adapter to succeed */
- }
/*
* The PHY should start in really-low-power mode. Prepare it for normal
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
index d21b705501a9..1b2c305fb82b 100644
--- a/drivers/net/cxgb3/common.h
+++ b/drivers/net/cxgb3/common.h
@@ -566,6 +566,15 @@ struct cphy_ops {
u32 mmds;
};
+enum {
+ EDC_OPT_AEL2005 = 0,
+ EDC_OPT_AEL2005_SIZE = 1084,
+ EDC_TWX_AEL2005 = 1,
+ EDC_TWX_AEL2005_SIZE = 1464,
+ EDC_TWX_AEL2020 = 2,
+ EDC_TWX_AEL2020_SIZE = 1628,
+ EDC_MAX_SIZE = EDC_TWX_AEL2020_SIZE, /* Max cache size */
+};
/* A PHY instance */
struct cphy {
@@ -577,6 +586,7 @@ struct cphy {
unsigned long fifo_errors; /* FIFO over/under-flows */
const struct cphy_ops *ops; /* PHY operations */
struct mdio_if_info mdio;
+ u16 phy_cache[EDC_MAX_SIZE]; /* EDC cache */
};
/* Convenience MDIO read/write wrappers */
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index fb5df5c6203e..ec05149a9065 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -172,6 +172,23 @@ static void link_report(struct net_device *dev)
}
}
+static void enable_tx_fifo_drain(struct adapter *adapter,
+ struct port_info *pi)
+{
+ t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset, 0,
+ F_ENDROPPKT);
+ t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, 0);
+ t3_write_reg(adapter, A_XGM_TX_CTRL + pi->mac.offset, F_TXEN);
+ t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, F_RXEN);
+}
+
+static void disable_tx_fifo_drain(struct adapter *adapter,
+ struct port_info *pi)
+{
+ t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset,
+ F_ENDROPPKT, 0);
+}
+
void t3_os_link_fault(struct adapter *adap, int port_id, int state)
{
struct net_device *dev = adap->port[port_id];
@@ -185,6 +202,8 @@ void t3_os_link_fault(struct adapter *adap, int port_id, int state)
netif_carrier_on(dev);
+ disable_tx_fifo_drain(adap, pi);
+
/* Clear local faults */
t3_xgm_intr_disable(adap, pi->port_id);
t3_read_reg(adap, A_XGM_INT_STATUS +
@@ -200,9 +219,12 @@ void t3_os_link_fault(struct adapter *adap, int port_id, int state)
t3_xgm_intr_enable(adap, pi->port_id);
t3_mac_enable(mac, MAC_DIRECTION_TX);
- } else
+ } else {
netif_carrier_off(dev);
+ /* Flush TX FIFO */
+ enable_tx_fifo_drain(adap, pi);
+ }
link_report(dev);
}
@@ -232,6 +254,8 @@ void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
if (link_stat != netif_carrier_ok(dev)) {
if (link_stat) {
+ disable_tx_fifo_drain(adapter, pi);
+
t3_mac_enable(mac, MAC_DIRECTION_RX);
/* Clear local faults */
@@ -263,6 +287,9 @@ void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
t3_mac_disable(mac, MAC_DIRECTION_RX);
t3_link_start(&pi->phy, mac, &pi->link_config);
+
+ /* Flush TX FIFO */
+ enable_tx_fifo_drain(adapter, pi);
}
link_report(dev);
@@ -443,6 +470,7 @@ static int init_tp_parity(struct adapter *adap)
memset(req, 0, sizeof(*req));
req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i));
+ req->mtu_idx = NMTUS - 1;
req->iff = i;
t3_mgmt_tx(adap, skb);
if (skb == adap->nofail_skb) {
@@ -963,6 +991,75 @@ static int bind_qsets(struct adapter *adap)
#define FW_FNAME "cxgb3/t3fw-%d.%d.%d.bin"
#define TPSRAM_NAME "cxgb3/t3%c_psram-%d.%d.%d.bin"
+#define AEL2005_OPT_EDC_NAME "cxgb3/ael2005_opt_edc.bin"
+#define AEL2005_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin"
+#define AEL2020_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin"
+
+static inline const char *get_edc_fw_name(int edc_idx)
+{
+ const char *fw_name = NULL;
+
+ switch (edc_idx) {
+ case EDC_OPT_AEL2005:
+ fw_name = AEL2005_OPT_EDC_NAME;
+ break;
+ case EDC_TWX_AEL2005:
+ fw_name = AEL2005_TWX_EDC_NAME;
+ break;
+ case EDC_TWX_AEL2020:
+ fw_name = AEL2020_TWX_EDC_NAME;
+ break;
+ }
+ return fw_name;
+}
+
+int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size)
+{
+ struct adapter *adapter = phy->adapter;
+ const struct firmware *fw;
+ char buf[64];
+ u32 csum;
+ const __be32 *p;
+ u16 *cache = phy->phy_cache;
+ int i, ret;
+
+ snprintf(buf, sizeof(buf), get_edc_fw_name(edc_idx));
+
+ ret = request_firmware(&fw, buf, &adapter->pdev->dev);
+ if (ret < 0) {
+ dev_err(&adapter->pdev->dev,
+ "could not upgrade firmware: unable to load %s\n",
+ buf);
+ return ret;
+ }
+
+ /* check size, take checksum in account */
+ if (fw->size > size + 4) {
+ CH_ERR(adapter, "firmware image too large %u, expected %d\n",
+ (unsigned int)fw->size, size + 4);
+ ret = -EINVAL;
+ }
+
+ /* compute checksum */
+ p = (const __be32 *)fw->data;
+ for (csum = 0, i = 0; i < fw->size / sizeof(csum); i++)
+ csum += ntohl(p[i]);
+
+ if (csum != 0xffffffff) {
+ CH_ERR(adapter, "corrupted firmware image, checksum %u\n",
+ csum);
+ ret = -EINVAL;
+ }
+
+ for (i = 0; i < size / 4 ; i++) {
+ *cache++ = (be32_to_cpu(p[i]) & 0xffff0000) >> 16;
+ *cache++ = be32_to_cpu(p[i]) & 0xffff;
+ }
+
+ release_firmware(fw);
+
+ return ret;
+}
static int upgrade_fw(struct adapter *adap)
{
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
index 870d44992c70..e78d341cbd60 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -3682,6 +3682,8 @@ static void mc7_prep(struct adapter *adapter, struct mc7 *mc7,
void mac_prep(struct cmac *mac, struct adapter *adapter, int index)
{
mac->adapter = adapter;
+ if (!adapter->params.vpd.xauicfg[1])
+ index = 0;
mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index;
mac->nucast = 1;
diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c
index f87f9435049f..0109ee4f2f91 100644
--- a/drivers/net/cxgb3/xgmac.c
+++ b/drivers/net/cxgb3/xgmac.c
@@ -447,11 +447,12 @@ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
- if (fc & PAUSE_TX)
- val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(
- t3_read_reg(adap,
- A_XGM_RX_MAX_PKT_SIZE
- + oft)) / 8);
+ if (fc & PAUSE_TX) {
+ u32 rx_max_pkt_size =
+ G_RXMAXPKTSIZE(t3_read_reg(adap,
+ A_XGM_RX_MAX_PKT_SIZE + oft));
+ val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8);
+ }
t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
diff --git a/drivers/net/de600.c b/drivers/net/de600.c
index e1af089064bc..6b13f4fd2e96 100644
--- a/drivers/net/de600.c
+++ b/drivers/net/de600.c
@@ -226,7 +226,7 @@ static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
spin_unlock_irqrestore(&de600_lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/de620.c b/drivers/net/de620.c
index 55d2bb67cffa..45794f6cb0f6 100644
--- a/drivers/net/de620.c
+++ b/drivers/net/de620.c
@@ -542,7 +542,7 @@ static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_packets++;
spin_unlock_irqrestore(&de620_lock, flags);
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*****************************************************
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index 2b22e580c4de..a31696a3928e 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -902,7 +902,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (len < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
len = ETH_ZLEN;
}
@@ -933,7 +933,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void lance_load_multicast(struct net_device *dev)
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index 102b8d439714..b2e0a8fc21d7 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -3218,7 +3218,7 @@ static int dfx_xmt_queue_pkt(
bp->xmt_length_errors++; /* bump error counter */
netif_wake_queue(dev);
dev_kfree_skb(skb);
- return(0); /* return "success" */
+ return NETDEV_TX_OK; /* return "success" */
}
/*
* See if adapter link is available, if not, free buffer
@@ -3241,7 +3241,7 @@ static int dfx_xmt_queue_pkt(
bp->xmt_discards++; /* bump error counter */
dev_kfree_skb(skb); /* free sk_buff now */
netif_wake_queue(dev);
- return(0); /* return "success" */
+ return NETDEV_TX_OK; /* return "success" */
}
}
@@ -3345,7 +3345,7 @@ static int dfx_xmt_queue_pkt(
dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword);
spin_unlock_irqrestore(&bp->lock, flags);
netif_wake_queue(dev);
- return(0); /* packet queued to adapter */
+ return NETDEV_TX_OK; /* packet queued to adapter */
}
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index 97ea2d6d3fe1..adb997c5bb5d 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -1793,7 +1793,7 @@ static int __init get_hw_addr(struct net_device *dev)
static int load_packet(struct net_device *dev, struct sk_buff *skb)
{
struct depca_private *lp = netdev_priv(dev);
- int i, entry, end, len, status = 0;
+ int i, entry, end, len, status = NETDEV_TX_OK;
entry = lp->tx_new; /* Ring around buffer number. */
end = (entry + (skb->len - 1) / TX_BUFF_SZ) & lp->txRingMask;
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index dd771dea6ae6..a2bc4158259a 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -92,6 +92,7 @@ typedef struct board_info {
u16 tx_pkt_cnt;
u16 queue_pkt_len;
u16 queue_start_addr;
+ u16 queue_ip_summed;
u16 dbug_cnt;
u8 io_mode; /* 0:word, 2:byte */
u8 phy_addr;
@@ -124,6 +125,10 @@ typedef struct board_info {
struct mii_if_info mii;
u32 msg_enable;
+
+ int rx_csum;
+ int can_csum;
+ int ip_summed;
} board_info_t;
/* debug code */
@@ -460,6 +465,40 @@ static int dm9000_nway_reset(struct net_device *dev)
return mii_nway_restart(&dm->mii);
}
+static uint32_t dm9000_get_rx_csum(struct net_device *dev)
+{
+ board_info_t *dm = to_dm9000_board(dev);
+ return dm->rx_csum;
+}
+
+static int dm9000_set_rx_csum(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;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static int dm9000_set_tx_csum(struct net_device *dev, uint32_t data)
+{
+ board_info_t *dm = to_dm9000_board(dev);
+ int ret = -EOPNOTSUPP;
+
+ if (dm->can_csum)
+ ret = ethtool_op_set_tx_csum(dev, data);
+ return ret;
+}
+
static u32 dm9000_get_link(struct net_device *dev)
{
board_info_t *dm = to_dm9000_board(dev);
@@ -540,6 +579,10 @@ static const struct ethtool_ops dm9000_ethtool_ops = {
.get_eeprom_len = dm9000_get_eeprom_len,
.get_eeprom = dm9000_get_eeprom,
.set_eeprom = dm9000_set_eeprom,
+ .get_rx_csum = dm9000_get_rx_csum,
+ .set_rx_csum = dm9000_set_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = dm9000_set_tx_csum,
};
static void dm9000_show_carrier(board_info_t *db,
@@ -685,6 +728,9 @@ dm9000_init_dm9000(struct net_device *dev)
/* I/O mode */
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);
+
/* GPIO0 on pre-activate PHY */
iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */
iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */
@@ -743,6 +789,29 @@ static void dm9000_timeout(struct net_device *dev)
spin_unlock_irqrestore(&db->lock, flags);
}
+static void dm9000_send_packet(struct net_device *dev,
+ int ip_summed,
+ u16 pkt_len)
+{
+ board_info_t *dm = to_dm9000_board(dev);
+
+ /* The DM9000 is not smart enough to leave fragmented packets alone. */
+ if (dm->ip_summed != ip_summed) {
+ if (ip_summed == CHECKSUM_NONE)
+ iow(dm, DM9000_TCCR, 0);
+ else
+ iow(dm, DM9000_TCCR, TCCR_IP | TCCR_UDP | TCCR_TCP);
+ dm->ip_summed = ip_summed;
+ }
+
+ /* Set TX length to DM9000 */
+ iow(dm, DM9000_TXPLL, pkt_len);
+ iow(dm, DM9000_TXPLH, pkt_len >> 8);
+
+ /* Issue TX polling command */
+ iow(dm, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
+}
+
/*
* Hardware start transmission.
* Send a packet to media from the upper layer.
@@ -769,17 +838,11 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
db->tx_pkt_cnt++;
/* TX control: First packet immediately send, second packet queue */
if (db->tx_pkt_cnt == 1) {
- /* Set TX length to DM9000 */
- iow(db, DM9000_TXPLL, skb->len);
- iow(db, DM9000_TXPLH, skb->len >> 8);
-
- /* Issue TX polling command */
- iow(db, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
-
- dev->trans_start = jiffies; /* save the time stamp */
+ dm9000_send_packet(dev, skb->ip_summed, skb->len);
} else {
/* Second packet */
db->queue_pkt_len = skb->len;
+ db->queue_ip_summed = skb->ip_summed;
netif_stop_queue(dev);
}
@@ -788,7 +851,7 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* free this SKB */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -809,12 +872,9 @@ static void dm9000_tx_done(struct net_device *dev, board_info_t *db)
dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status);
/* Queue packet check & send */
- if (db->tx_pkt_cnt > 0) {
- iow(db, DM9000_TXPLL, db->queue_pkt_len);
- iow(db, DM9000_TXPLH, db->queue_pkt_len >> 8);
- iow(db, DM9000_TCR, TCR_TXREQ);
- dev->trans_start = jiffies;
- }
+ if (db->tx_pkt_cnt > 0)
+ dm9000_send_packet(dev, db->queue_ip_summed,
+ db->queue_pkt_len);
netif_wake_queue(dev);
}
}
@@ -846,14 +906,14 @@ dm9000_rx(struct net_device *dev)
rxbyte = readb(db->io_data);
/* Status check: this byte must be 0 or 1 */
- if (rxbyte > DM9000_PKT_RDY) {
+ if (rxbyte & DM9000_PKT_ERR) {
dev_warn(db->dev, "status check fail: %d\n", rxbyte);
iow(db, DM9000_RCR, 0x00); /* Stop Device */
iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */
return;
}
- if (rxbyte != DM9000_PKT_RDY)
+ if (!(rxbyte & DM9000_PKT_RDY))
return;
/* A packet ready now & Get status/length */
@@ -914,6 +974,12 @@ dm9000_rx(struct net_device *dev)
/* Pass to upper layer */
skb->protocol = eth_type_trans(skb, dev);
+ if (db->rx_csum) {
+ if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb->ip_summed = CHECKSUM_NONE;
+ }
netif_rx(skb);
dev->stats.rx_packets++;
@@ -922,7 +988,7 @@ dm9000_rx(struct net_device *dev)
(db->dumpblk)(db->io_data, RxLen);
}
- } while (rxbyte == DM9000_PKT_RDY);
+ } while (rxbyte & DM9000_PKT_RDY);
}
static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
@@ -1349,6 +1415,13 @@ dm9000_probe(struct platform_device *pdev)
db->type = TYPE_DM9000E;
}
+ /* dm9000a/b are capable of hardware checksum offload */
+ if (db->type == TYPE_DM9000A || db->type == TYPE_DM9000B) {
+ db->can_csum = 1;
+ db->rx_csum = 1;
+ ndev->features |= NETIF_F_IP_CSUM;
+ }
+
/* from this point we assume that we have found a DM9000 */
/* driver system function */
@@ -1410,9 +1483,10 @@ out:
}
static int
-dm9000_drv_suspend(struct platform_device *dev, pm_message_t state)
+dm9000_drv_suspend(struct device *dev)
{
- struct net_device *ndev = platform_get_drvdata(dev);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct net_device *ndev = platform_get_drvdata(pdev);
board_info_t *db;
if (ndev) {
@@ -1428,9 +1502,10 @@ dm9000_drv_suspend(struct platform_device *dev, pm_message_t state)
}
static int
-dm9000_drv_resume(struct platform_device *dev)
+dm9000_drv_resume(struct device *dev)
{
- struct net_device *ndev = platform_get_drvdata(dev);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct net_device *ndev = platform_get_drvdata(pdev);
board_info_t *db = netdev_priv(ndev);
if (ndev) {
@@ -1447,6 +1522,11 @@ dm9000_drv_resume(struct platform_device *dev)
return 0;
}
+static struct dev_pm_ops dm9000_drv_pm_ops = {
+ .suspend = dm9000_drv_suspend,
+ .resume = dm9000_drv_resume,
+};
+
static int __devexit
dm9000_drv_remove(struct platform_device *pdev)
{
@@ -1466,11 +1546,10 @@ static struct platform_driver dm9000_driver = {
.driver = {
.name = "dm9000",
.owner = THIS_MODULE,
+ .pm = &dm9000_drv_pm_ops,
},
.probe = dm9000_probe,
.remove = __devexit_p(dm9000_drv_remove),
- .suspend = dm9000_drv_suspend,
- .resume = dm9000_drv_resume,
};
static int __init
diff --git a/drivers/net/dm9000.h b/drivers/net/dm9000.h
index ba25cf541420..80817c2edfb3 100644
--- a/drivers/net/dm9000.h
+++ b/drivers/net/dm9000.h
@@ -45,6 +45,10 @@
#define DM9000_CHIPR 0x2C
#define DM9000_SMCR 0x2F
+#define DM9000_ETXCSR 0x30
+#define DM9000_TCCR 0x31
+#define DM9000_RCSR 0x32
+
#define CHIPR_DM9000A 0x19
#define CHIPR_DM9000B 0x1B
@@ -131,7 +135,21 @@
#define GPCR_GEP_CNTL (1<<0)
+#define TCCR_IP (1<<0)
+#define TCCR_TCP (1<<1)
+#define TCCR_UDP (1<<2)
+
+#define RCSR_UDP_BAD (1<<7)
+#define RCSR_TCP_BAD (1<<6)
+#define RCSR_IP_BAD (1<<5)
+#define RCSR_UDP (1<<4)
+#define RCSR_TCP (1<<3)
+#define RCSR_IP (1<<2)
+#define RCSR_CSUM (1<<1)
+#define RCSR_DISCARD (1<<0)
+
#define DM9000_PKT_RDY 0x01 /* Packet ready to receive */
+#define DM9000_PKT_ERR 0x02
#define DM9000_PKT_MAX 1536 /* Received packet max size */
/* DM9000A / DM9000B definitions */
diff --git a/drivers/net/dnet.c b/drivers/net/dnet.c
index 33fa9eee4cac..2818d5de3940 100644
--- a/drivers/net/dnet.c
+++ b/drivers/net/dnet.c
@@ -596,7 +596,7 @@ static int dnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static void dnet_reset_hw(struct dnet *bp)
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index 8ebd7d789405..713ce6c532c5 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -85,7 +85,7 @@ static int dummy_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_bytes += skb->len;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static int dummy_validate(struct nlattr *tb[], struct nlattr *data[])
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 41b648a67fec..569df19f0df5 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -1720,7 +1720,7 @@ static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
}
netdev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static int e100_tx_clean(struct nic *nic)
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index e9a416f40162..1a4f89c66a26 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -111,6 +111,9 @@ do { \
#define E1000_MIN_RXD 80
#define E1000_MAX_82544_RXD 4096
+#define E1000_MIN_ITR_USECS 10 /* 100000 irq/sec */
+#define E1000_MAX_ITR_USECS 10000 /* 100 irq/sec */
+
/* this is the size past which hardware will drop packets when setting LPE=0 */
#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
@@ -137,7 +140,7 @@ do { \
#define E1000_FC_HIGH_DIFF 0x1638 /* High: 5688 bytes below Rx FIFO size */
#define E1000_FC_LOW_DIFF 0x1640 /* Low: 5696 bytes below Rx FIFO size */
-#define E1000_FC_PAUSE_TIME 0x0680 /* 858 usec */
+#define E1000_FC_PAUSE_TIME 0xFFFF /* pause for the max or until send xon */
/* How many Tx Descriptors do we need to call netif_wake_queue ? */
#define E1000_TX_QUEUE_WAKE 16
@@ -161,6 +164,7 @@ do { \
struct e1000_buffer {
struct sk_buff *skb;
dma_addr_t dma;
+ struct page *page;
unsigned long time_stamp;
u16 length;
u16 next_to_watch;
@@ -202,6 +206,7 @@ struct e1000_rx_ring {
unsigned int next_to_clean;
/* array of buffer information structs */
struct e1000_buffer *buffer_info;
+ struct sk_buff *rx_skb_top;
/* cpu for rx queue */
int cpu;
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index c854c96f5ab3..27f996a2010f 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -1904,6 +1904,53 @@ static int e1000_phys_id(struct net_device *netdev, u32 data)
return 0;
}
+static int e1000_get_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ec)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ if (adapter->hw.mac_type < e1000_82545)
+ return -EOPNOTSUPP;
+
+ if (adapter->itr_setting <= 3)
+ ec->rx_coalesce_usecs = adapter->itr_setting;
+ else
+ ec->rx_coalesce_usecs = 1000000 / adapter->itr_setting;
+
+ return 0;
+}
+
+static int e1000_set_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ec)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+
+ if (hw->mac_type < e1000_82545)
+ return -EOPNOTSUPP;
+
+ if ((ec->rx_coalesce_usecs > E1000_MAX_ITR_USECS) ||
+ ((ec->rx_coalesce_usecs > 3) &&
+ (ec->rx_coalesce_usecs < E1000_MIN_ITR_USECS)) ||
+ (ec->rx_coalesce_usecs == 2))
+ return -EINVAL;
+
+ if (ec->rx_coalesce_usecs <= 3) {
+ adapter->itr = 20000;
+ adapter->itr_setting = ec->rx_coalesce_usecs;
+ } else {
+ adapter->itr = (1000000 / ec->rx_coalesce_usecs);
+ adapter->itr_setting = adapter->itr & ~3;
+ }
+
+ if (adapter->itr_setting != 0)
+ ew32(ITR, 1000000000 / (adapter->itr * 256));
+ else
+ ew32(ITR, 0);
+
+ return 0;
+}
+
static int e1000_nway_reset(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1978,7 +2025,9 @@ static const struct ethtool_ops e1000_ethtool_ops = {
.get_strings = e1000_get_strings,
.phys_id = e1000_phys_id,
.get_ethtool_stats = e1000_get_ethtool_stats,
- .get_sset_count = e1000_get_sset_count,
+ .get_sset_count = e1000_get_sset_count,
+ .get_coalesce = e1000_get_coalesce,
+ .set_coalesce = e1000_set_coalesce,
};
void e1000_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index e1a3fc1303ee..1e5ae112d57a 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -1955,7 +1955,7 @@ static s32 e1000_setup_copper_link(struct e1000_hw *hw)
s32 ret_val;
u16 i;
u16 phy_data;
- u16 reg_data;
+ u16 reg_data = 0;
DEBUGFUNC("e1000_setup_copper_link");
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index 99fce2c5dd26..a8866bdbb671 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -523,11 +523,8 @@ s32 e1000_check_phy_reset_block(struct e1000_hw *hw);
/* The sizes (in bytes) of a ethernet packet */
#define ENET_HEADER_SIZE 14
-#define MAXIMUM_ETHERNET_FRAME_SIZE 1518 /* With FCS */
#define MINIMUM_ETHERNET_FRAME_SIZE 64 /* With FCS */
#define ETHERNET_FCS_SIZE 4
-#define MAXIMUM_ETHERNET_PACKET_SIZE \
- (MAXIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
#define MINIMUM_ETHERNET_PACKET_SIZE \
(MINIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
#define CRC_LENGTH ETHERNET_FCS_SIZE
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 5b8cbdb4b520..d7df00c2dbd6 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -137,9 +137,15 @@ static int e1000_clean(struct napi_struct *napi, int budget);
static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
struct e1000_rx_ring *rx_ring,
int *work_done, int work_to_do);
+static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring,
+ int *work_done, int work_to_do);
static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
- struct e1000_rx_ring *rx_ring,
+ struct e1000_rx_ring *rx_ring,
int cleaned_count);
+static void e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring,
+ int cleaned_count);
static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
int cmd);
@@ -635,8 +641,8 @@ void e1000_reset(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
u32 pba = 0, tx_space, min_tx_space, min_rx_space;
- u16 fc_high_water_mark = E1000_FC_HIGH_DIFF;
bool legacy_pba_adjust = false;
+ u16 hwm;
/* Repartition Pba for greater than 9k mtu
* To take effect CTRL.RST is required.
@@ -680,7 +686,7 @@ void e1000_reset(struct e1000_adapter *adapter)
}
if (legacy_pba_adjust) {
- if (adapter->netdev->mtu > E1000_RXBUFFER_8192)
+ if (hw->max_frame_size > E1000_RXBUFFER_8192)
pba -= 8; /* allocate more FIFO for Tx */
if (hw->mac_type == e1000_82547) {
@@ -690,14 +696,14 @@ void e1000_reset(struct e1000_adapter *adapter)
(E1000_PBA_40K - pba) << E1000_PBA_BYTES_SHIFT;
atomic_set(&adapter->tx_fifo_stall, 0);
}
- } else if (hw->max_frame_size > MAXIMUM_ETHERNET_FRAME_SIZE) {
+ } else if (hw->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN) {
/* adjust PBA for jumbo frames */
ew32(PBA, pba);
/* To maintain wire speed transmits, the Tx FIFO should be
- * large enough to accomodate two full transmit packets,
+ * large enough to accommodate two full transmit packets,
* rounded up to the next 1KB and expressed in KB. Likewise,
- * the Rx FIFO should be large enough to accomodate at least
+ * the Rx FIFO should be large enough to accommodate at least
* one full receive packet and is similarly rounded up and
* expressed in KB. */
pba = er32(PBA);
@@ -705,13 +711,17 @@ void e1000_reset(struct e1000_adapter *adapter)
tx_space = pba >> 16;
/* lower 16 bits has Rx packet buffer allocation size in KB */
pba &= 0xffff;
- /* don't include ethernet FCS because hardware appends/strips */
- min_rx_space = adapter->netdev->mtu + ENET_HEADER_SIZE +
- VLAN_TAG_SIZE;
- min_tx_space = min_rx_space;
- min_tx_space *= 2;
+ /*
+ * the tx fifo also stores 16 bytes of information about the tx
+ * but don't include ethernet FCS because hardware appends it
+ */
+ min_tx_space = (hw->max_frame_size +
+ sizeof(struct e1000_tx_desc) -
+ ETH_FCS_LEN) * 2;
min_tx_space = ALIGN(min_tx_space, 1024);
min_tx_space >>= 10;
+ /* software strips receive CRC, so leave room for it */
+ min_rx_space = hw->max_frame_size;
min_rx_space = ALIGN(min_rx_space, 1024);
min_rx_space >>= 10;
@@ -748,23 +758,22 @@ void e1000_reset(struct e1000_adapter *adapter)
ew32(PBA, pba);
- /* flow control settings */
- /* Set the FC high water mark to 90% of the FIFO size.
- * Required to clear last 3 LSB */
- fc_high_water_mark = ((pba * 9216)/10) & 0xFFF8;
- /* We can't use 90% on small FIFOs because the remainder
- * would be less than 1 full frame. In this case, we size
- * it to allow at least a full frame above the high water
- * mark. */
- if (pba < E1000_PBA_16K)
- fc_high_water_mark = (pba * 1024) - 1600;
-
- hw->fc_high_water = fc_high_water_mark;
- hw->fc_low_water = fc_high_water_mark - 8;
- if (hw->mac_type == e1000_80003es2lan)
- hw->fc_pause_time = 0xFFFF;
- else
- hw->fc_pause_time = E1000_FC_PAUSE_TIME;
+ /*
+ * flow control settings:
+ * The high water mark must be low enough to fit one full frame
+ * (or the size used for early receive) above it in the Rx FIFO.
+ * Set it to the lower of:
+ * - 90% of the Rx FIFO size, and
+ * - the full Rx FIFO size minus the early receive size (for parts
+ * with ERT support assuming ERT set to E1000_ERT_2048), or
+ * - the full Rx FIFO size minus one full frame
+ */
+ hwm = min(((pba << 10) * 9 / 10),
+ ((pba << 10) - hw->max_frame_size));
+
+ hw->fc_high_water = hwm & 0xFFF8; /* 8-byte granularity */
+ hw->fc_low_water = hw->fc_high_water - 8;
+ hw->fc_pause_time = E1000_FC_PAUSE_TIME;
hw->fc_send_xon = 1;
hw->fc = hw->original_fc;
@@ -1862,6 +1871,7 @@ setup_rx_desc_die:
rxdr->next_to_clean = 0;
rxdr->next_to_use = 0;
+ rxdr->rx_skb_top = NULL;
return 0;
}
@@ -1968,10 +1978,17 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
struct e1000_hw *hw = &adapter->hw;
u32 rdlen, rctl, rxcsum, ctrl_ext;
- rdlen = adapter->rx_ring[0].count *
- sizeof(struct e1000_rx_desc);
- adapter->clean_rx = e1000_clean_rx_irq;
- adapter->alloc_rx_buf = e1000_alloc_rx_buffers;
+ if (adapter->netdev->mtu > ETH_DATA_LEN) {
+ rdlen = adapter->rx_ring[0].count *
+ sizeof(struct e1000_rx_desc);
+ adapter->clean_rx = e1000_clean_jumbo_rx_irq;
+ adapter->alloc_rx_buf = e1000_alloc_jumbo_rx_buffers;
+ } else {
+ rdlen = adapter->rx_ring[0].count *
+ sizeof(struct e1000_rx_desc);
+ adapter->clean_rx = e1000_clean_rx_irq;
+ adapter->alloc_rx_buf = e1000_alloc_rx_buffers;
+ }
/* disable receives while setting up the descriptors */
rctl = er32(RCTL);
@@ -2185,26 +2202,39 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter,
/* Free all the Rx ring sk_buffs */
for (i = 0; i < rx_ring->count; i++) {
buffer_info = &rx_ring->buffer_info[i];
- if (buffer_info->dma) {
- pci_unmap_single(pdev,
- buffer_info->dma,
- buffer_info->length,
- PCI_DMA_FROMDEVICE);
+ if (buffer_info->dma &&
+ adapter->clean_rx == e1000_clean_rx_irq) {
+ pci_unmap_single(pdev, buffer_info->dma,
+ buffer_info->length,
+ PCI_DMA_FROMDEVICE);
+ } 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);
}
buffer_info->dma = 0;
-
+ if (buffer_info->page) {
+ put_page(buffer_info->page);
+ buffer_info->page = NULL;
+ }
if (buffer_info->skb) {
dev_kfree_skb(buffer_info->skb);
buffer_info->skb = NULL;
}
}
+ /* there also may be some cached data from a chained receive */
+ if (rx_ring->rx_skb_top) {
+ dev_kfree_skb(rx_ring->rx_skb_top);
+ rx_ring->rx_skb_top = NULL;
+ }
+
size = sizeof(struct e1000_buffer) * rx_ring->count;
memset(rx_ring->buffer_info, 0, size);
/* Zero out the descriptor ring */
-
memset(rx_ring->desc, 0, rx_ring->size);
rx_ring->next_to_clean = 0;
@@ -3450,7 +3480,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
switch (hw->mac_type) {
case e1000_undefined ... e1000_82542_rev2_1:
case e1000_ich8lan:
- if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) {
+ if (max_frame > (ETH_FRAME_LEN + ETH_FCS_LEN)) {
DPRINTK(PROBE, ERR, "Jumbo Frames not supported.\n");
return -EINVAL;
}
@@ -3463,7 +3493,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
&eeprom_data);
if ((hw->device_id != E1000_DEV_ID_82573L) ||
(eeprom_data & EEPROM_WORD1A_ASPM_MASK)) {
- if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) {
+ if (max_frame > (ETH_FRAME_LEN + ETH_FCS_LEN)) {
DPRINTK(PROBE, ERR,
"Jumbo Frames not supported.\n");
return -EINVAL;
@@ -3489,8 +3519,10 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
/* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN
* means we reserve 2 more, this pushes us to allocate from the next
- * larger slab size
- * i.e. RXBUFFER_2048 --> size-4096 slab */
+ * larger slab size.
+ * i.e. RXBUFFER_2048 --> size-4096 slab
+ * however with the new *_jumbo_rx* routines, jumbo receives will use
+ * fragmented skbs */
if (max_frame <= E1000_RXBUFFER_256)
adapter->rx_buffer_len = E1000_RXBUFFER_256;
@@ -3500,16 +3532,16 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
adapter->rx_buffer_len = E1000_RXBUFFER_1024;
else if (max_frame <= E1000_RXBUFFER_2048)
adapter->rx_buffer_len = E1000_RXBUFFER_2048;
- else if (max_frame <= E1000_RXBUFFER_4096)
- adapter->rx_buffer_len = E1000_RXBUFFER_4096;
- else if (max_frame <= E1000_RXBUFFER_8192)
- adapter->rx_buffer_len = E1000_RXBUFFER_8192;
- else if (max_frame <= E1000_RXBUFFER_16384)
+ else
+#if (PAGE_SIZE >= E1000_RXBUFFER_16384)
adapter->rx_buffer_len = E1000_RXBUFFER_16384;
+#elif (PAGE_SIZE >= E1000_RXBUFFER_4096)
+ adapter->rx_buffer_len = PAGE_SIZE;
+#endif
/* adjust allocation if LPE protects us, and we aren't using SBP */
if (!hw->tbi_compatibility_on &&
- ((max_frame == MAXIMUM_ETHERNET_FRAME_SIZE) ||
+ ((max_frame == (ETH_FRAME_LEN + ETH_FCS_LEN)) ||
(max_frame == MAXIMUM_ETHERNET_VLAN_SIZE)))
adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
@@ -3987,9 +4019,227 @@ static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err,
}
/**
+ * e1000_consume_page - helper function
+ **/
+static void e1000_consume_page(struct e1000_buffer *bi, struct sk_buff *skb,
+ u16 length)
+{
+ bi->page = NULL;
+ skb->len += length;
+ skb->data_len += length;
+ skb->truesize += length;
+}
+
+/**
+ * e1000_receive_skb - helper function to handle rx indications
+ * @adapter: board private structure
+ * @status: descriptor status field as written by hardware
+ * @vlan: descriptor vlan field as written by hardware (no le/be conversion)
+ * @skb: pointer to sk_buff to be indicated to stack
+ */
+static void e1000_receive_skb(struct e1000_adapter *adapter, u8 status,
+ __le16 vlan, struct sk_buff *skb)
+{
+ if (unlikely(adapter->vlgrp && (status & E1000_RXD_STAT_VP))) {
+ vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
+ le16_to_cpu(vlan) &
+ E1000_RXD_SPC_VLAN_MASK);
+ } else {
+ netif_receive_skb(skb);
+ }
+}
+
+/**
+ * e1000_clean_jumbo_rx_irq - Send received data up the network stack; legacy
+ * @adapter: board private structure
+ * @rx_ring: ring to clean
+ * @work_done: amount of napi work completed this call
+ * @work_to_do: max amount of work allowed for this call to do
+ *
+ * the return value indicates whether actual cleaning was done, there
+ * is no guarantee that everything was cleaned
+ */
+static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring,
+ int *work_done, int work_to_do)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ struct e1000_rx_desc *rx_desc, *next_rxd;
+ struct e1000_buffer *buffer_info, *next_buffer;
+ unsigned long irq_flags;
+ u32 length;
+ unsigned int i;
+ int cleaned_count = 0;
+ bool cleaned = false;
+ unsigned int total_rx_bytes=0, total_rx_packets=0;
+
+ i = rx_ring->next_to_clean;
+ rx_desc = E1000_RX_DESC(*rx_ring, i);
+ buffer_info = &rx_ring->buffer_info[i];
+
+ while (rx_desc->status & E1000_RXD_STAT_DD) {
+ struct sk_buff *skb;
+ u8 status;
+
+ if (*work_done >= work_to_do)
+ break;
+ (*work_done)++;
+
+ status = rx_desc->status;
+ skb = buffer_info->skb;
+ buffer_info->skb = NULL;
+
+ if (++i == rx_ring->count) i = 0;
+ next_rxd = E1000_RX_DESC(*rx_ring, i);
+ prefetch(next_rxd);
+
+ next_buffer = &rx_ring->buffer_info[i];
+
+ cleaned = true;
+ cleaned_count++;
+ pci_unmap_page(pdev, buffer_info->dma, buffer_info->length,
+ PCI_DMA_FROMDEVICE);
+ buffer_info->dma = 0;
+
+ length = le16_to_cpu(rx_desc->length);
+
+ /* errors is only valid for DD + EOP descriptors */
+ if (unlikely((status & E1000_RXD_STAT_EOP) &&
+ (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK))) {
+ u8 last_byte = *(skb->data + length - 1);
+ if (TBI_ACCEPT(hw, status, rx_desc->errors, length,
+ last_byte)) {
+ spin_lock_irqsave(&adapter->stats_lock,
+ irq_flags);
+ e1000_tbi_adjust_stats(hw, &adapter->stats,
+ length, skb->data);
+ spin_unlock_irqrestore(&adapter->stats_lock,
+ irq_flags);
+ length--;
+ } else {
+ /* recycle both page and skb */
+ buffer_info->skb = skb;
+ /* an error means any chain goes out the window
+ * too */
+ if (rx_ring->rx_skb_top)
+ dev_kfree_skb(rx_ring->rx_skb_top);
+ rx_ring->rx_skb_top = NULL;
+ goto next_desc;
+ }
+ }
+
+#define rxtop rx_ring->rx_skb_top
+ if (!(status & E1000_RXD_STAT_EOP)) {
+ /* this descriptor is only the beginning (or middle) */
+ if (!rxtop) {
+ /* this is the beginning of a chain */
+ rxtop = skb;
+ skb_fill_page_desc(rxtop, 0, buffer_info->page,
+ 0, length);
+ } else {
+ /* this is the middle of a chain */
+ skb_fill_page_desc(rxtop,
+ skb_shinfo(rxtop)->nr_frags,
+ buffer_info->page, 0, length);
+ /* re-use the skb, only consumed the page */
+ buffer_info->skb = skb;
+ }
+ e1000_consume_page(buffer_info, rxtop, length);
+ goto next_desc;
+ } else {
+ if (rxtop) {
+ /* end of the chain */
+ skb_fill_page_desc(rxtop,
+ skb_shinfo(rxtop)->nr_frags,
+ buffer_info->page, 0, length);
+ /* re-use the current skb, we only consumed the
+ * page */
+ buffer_info->skb = skb;
+ skb = rxtop;
+ rxtop = NULL;
+ e1000_consume_page(buffer_info, skb, length);
+ } else {
+ /* no chain, got EOP, this buf is the packet
+ * copybreak to save the put_page/alloc_page */
+ if (length <= copybreak &&
+ skb_tailroom(skb) >= length) {
+ u8 *vaddr;
+ vaddr = kmap_atomic(buffer_info->page,
+ KM_SKB_DATA_SOFTIRQ);
+ memcpy(skb_tail_pointer(skb), vaddr, length);
+ kunmap_atomic(vaddr,
+ KM_SKB_DATA_SOFTIRQ);
+ /* re-use the page, so don't erase
+ * buffer_info->page */
+ skb_put(skb, length);
+ } else {
+ skb_fill_page_desc(skb, 0,
+ buffer_info->page, 0,
+ length);
+ e1000_consume_page(buffer_info, skb,
+ length);
+ }
+ }
+ }
+
+ /* Receive Checksum Offload XXX recompute due to CRC strip? */
+ e1000_rx_checksum(adapter,
+ (u32)(status) |
+ ((u32)(rx_desc->errors) << 24),
+ le16_to_cpu(rx_desc->csum), skb);
+
+ pskb_trim(skb, skb->len - 4);
+
+ /* probably a little skewed due to removing CRC */
+ total_rx_bytes += skb->len;
+ total_rx_packets++;
+
+ /* 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");
+ dev_kfree_skb(skb);
+ goto next_desc;
+ }
+
+ skb->protocol = eth_type_trans(skb, netdev);
+
+ e1000_receive_skb(adapter, status, rx_desc->special, skb);
+
+next_desc:
+ rx_desc->status = 0;
+
+ /* return some buffers to hardware, one at a time is too slow */
+ if (unlikely(cleaned_count >= E1000_RX_BUFFER_WRITE)) {
+ adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count);
+ cleaned_count = 0;
+ }
+
+ /* use prefetched values */
+ rx_desc = next_rxd;
+ buffer_info = next_buffer;
+ }
+ rx_ring->next_to_clean = i;
+
+ cleaned_count = E1000_DESC_UNUSED(rx_ring);
+ if (cleaned_count)
+ adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count);
+
+ adapter->total_rx_packets += total_rx_packets;
+ adapter->total_rx_bytes += total_rx_bytes;
+ adapter->net_stats.rx_bytes += total_rx_bytes;
+ adapter->net_stats.rx_packets += total_rx_packets;
+ return cleaned;
+}
+
+/**
* e1000_clean_rx_irq - Send received data up the network stack; legacy
* @adapter: board private structure
- **/
+ * @rx_ring: ring to clean
+ * @work_done: amount of napi work completed this call
+ * @work_to_do: max amount of work allowed for this call to do
+ */
static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
struct e1000_rx_ring *rx_ring,
int *work_done, int work_to_do)
@@ -4001,7 +4251,6 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
struct e1000_buffer *buffer_info, *next_buffer;
unsigned long flags;
u32 length;
- u8 last_byte;
unsigned int i;
int cleaned_count = 0;
bool cleaned = false;
@@ -4033,9 +4282,7 @@ 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_unmap_single(pdev, buffer_info->dma, buffer_info->length,
PCI_DMA_FROMDEVICE);
buffer_info->dma = 0;
@@ -4052,7 +4299,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
}
if (unlikely(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK)) {
- last_byte = *(skb->data + length - 1);
+ u8 last_byte = *(skb->data + length - 1);
if (TBI_ACCEPT(hw, status, rx_desc->errors, length,
last_byte)) {
spin_lock_irqsave(&adapter->stats_lock, flags);
@@ -4107,13 +4354,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
skb->protocol = eth_type_trans(skb, netdev);
- if (unlikely(adapter->vlgrp &&
- (status & E1000_RXD_STAT_VP))) {
- vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
- le16_to_cpu(rx_desc->special));
- } else {
- netif_receive_skb(skb);
- }
+ e1000_receive_skb(adapter, status, rx_desc->special, skb);
next_desc:
rx_desc->status = 0;
@@ -4142,6 +4383,114 @@ next_desc:
}
/**
+ * e1000_alloc_jumbo_rx_buffers - Replace used jumbo receive buffers
+ * @adapter: address of board private structure
+ * @rx_ring: pointer to receive ring structure
+ * @cleaned_count: number of buffers to allocate this pass
+ **/
+
+static void
+e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring, int cleaned_count)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ struct e1000_rx_desc *rx_desc;
+ struct e1000_buffer *buffer_info;
+ struct sk_buff *skb;
+ unsigned int i;
+ unsigned int bufsz = 256 -
+ 16 /*for skb_reserve */ -
+ NET_IP_ALIGN;
+
+ i = rx_ring->next_to_use;
+ buffer_info = &rx_ring->buffer_info[i];
+
+ while (cleaned_count--) {
+ skb = buffer_info->skb;
+ if (skb) {
+ skb_trim(skb, 0);
+ goto check_page;
+ }
+
+ skb = netdev_alloc_skb(netdev, bufsz);
+ if (unlikely(!skb)) {
+ /* Better luck next round */
+ adapter->alloc_rx_buff_failed++;
+ break;
+ }
+
+ /* 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);
+ /* Try again, without freeing the previous */
+ skb = netdev_alloc_skb(netdev, bufsz);
+ /* Failed allocation, critical failure */
+ if (!skb) {
+ dev_kfree_skb(oldskb);
+ adapter->alloc_rx_buff_failed++;
+ break;
+ }
+
+ if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) {
+ /* give up */
+ dev_kfree_skb(skb);
+ dev_kfree_skb(oldskb);
+ break; /* while (cleaned_count--) */
+ }
+
+ /* Use new allocation */
+ dev_kfree_skb(oldskb);
+ }
+ /* Make buffer alignment 2 beyond a 16 byte boundary
+ * this will result in a 16 byte aligned IP header after
+ * the 14 byte MAC header is removed
+ */
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ buffer_info->skb = skb;
+ buffer_info->length = adapter->rx_buffer_len;
+check_page:
+ /* allocate a new page if necessary */
+ if (!buffer_info->page) {
+ buffer_info->page = alloc_page(GFP_ATOMIC);
+ if (unlikely(!buffer_info->page)) {
+ adapter->alloc_rx_buff_failed++;
+ break;
+ }
+ }
+
+ if (!buffer_info->dma)
+ buffer_info->dma = pci_map_page(pdev,
+ buffer_info->page, 0,
+ buffer_info->length,
+ PCI_DMA_FROMDEVICE);
+
+ rx_desc = E1000_RX_DESC(*rx_ring, i);
+ rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+
+ if (unlikely(++i == rx_ring->count))
+ i = 0;
+ buffer_info = &rx_ring->buffer_info[i];
+ }
+
+ if (likely(rx_ring->next_to_use != i)) {
+ rx_ring->next_to_use = i;
+ if (unlikely(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->rdt);
+ }
+}
+
+/**
* e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended
* @adapter: address of board private structure
**/
@@ -4186,6 +4535,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
/* Failed allocation, critical failure */
if (!skb) {
dev_kfree_skb(oldskb);
+ adapter->alloc_rx_buff_failed++;
break;
}
@@ -4193,6 +4543,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
/* give up */
dev_kfree_skb(skb);
dev_kfree_skb(oldskb);
+ adapter->alloc_rx_buff_failed++;
break; /* while !buffer_info->skb */
}
@@ -4210,9 +4561,14 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
map_skb:
buffer_info->dma = pci_map_single(pdev,
skb->data,
- adapter->rx_buffer_len,
+ buffer_info->length,
PCI_DMA_FROMDEVICE);
+ /*
+ * XXX if it was allocated cleanly it will never map to a
+ * boundary crossing
+ */
+
/* Fix for errata 23, can't cross 64kB boundary */
if (!e1000_check_64k_bound(adapter,
(void *)(unsigned long)buffer_info->dma,
@@ -4229,6 +4585,7 @@ map_skb:
PCI_DMA_FROMDEVICE);
buffer_info->dma = 0;
+ adapter->alloc_rx_buff_failed++;
break; /* while !buffer_info->skb */
}
rx_desc = E1000_RX_DESC(*rx_ring, i);
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index 4f7003485348..53317a83857a 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -1145,7 +1145,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
netif_stop_queue (dev);
@@ -1178,7 +1178,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev)
eepro_en_int(ioaddr);
spin_unlock_irqrestore(&lp->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index 1f016d66684a..d1b6368faacd 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -664,7 +664,7 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev)
if (buf->len < ETH_ZLEN) {
if (skb_padto(buf, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
@@ -691,7 +691,7 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev)
spin_unlock_irqrestore(&lp->lock, flags);
#endif
enable_irq(dev->irq);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c
index fc6cc038c7b8..372d6c6a4e7f 100644
--- a/drivers/net/enc28j60.c
+++ b/drivers/net/enc28j60.c
@@ -1299,7 +1299,7 @@ static int enc28j60_send_packet(struct sk_buff *skb, struct net_device *dev)
priv->tx_skb = skb;
schedule_work(&priv->tx_work);
- return 0;
+ return NETDEV_TX_OK;
}
static void enc28j60_tx_work_handler(struct work_struct *work)
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index b60e27dfcfa7..d6a7aa3142f9 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -970,7 +970,7 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned long flags;
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
/* Caution: the write order is important here, set the field with the
"ownership" bit last. */
@@ -1014,7 +1014,7 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->name, (int)skb->len, entry, ctrl_word,
(int)inl(dev->base_addr + TxSTAT));
- return 0;
+ return NETDEV_TX_OK;
}
static void epic_tx_error(struct net_device *dev, struct epic_private *ep,
diff --git a/drivers/net/eql.c b/drivers/net/eql.c
index 19b7dd983944..c0e69c5cae84 100644
--- a/drivers/net/eql.c
+++ b/drivers/net/eql.c
@@ -348,7 +348,7 @@ static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock(&eql->queue.lock);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
index 0d8b6da046f2..97d5205edc8f 100644
--- a/drivers/net/eth16i.c
+++ b/drivers/net/eth16i.c
@@ -1064,7 +1064,7 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
buf = skb->data;
@@ -1126,7 +1126,7 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
/* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
status = 0;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void eth16i_rx(struct net_device *dev)
diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c
index ceb6a9c357ad..4dbe5f173273 100644
--- a/drivers/net/ethoc.c
+++ b/drivers/net/ethoc.c
@@ -894,7 +894,7 @@ static int ethoc_probe(struct platform_device *pdev)
mmio = devm_request_mem_region(&pdev->dev, res->start,
res->end - res->start + 1, res->name);
- if (!res) {
+ if (!mmio) {
dev_err(&pdev->dev, "cannot request I/O memory space\n");
ret = -ENXIO;
goto free;
diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
index 1e9723281405..9c51bc813ad3 100644
--- a/drivers/net/ewrk3.c
+++ b/drivers/net/ewrk3.c
@@ -868,7 +868,7 @@ static int ewrk3_queue_pkt (struct sk_buff *skb, struct net_device *dev)
if (inb (EWRK3_FMQC) == 0)
netif_stop_queue (dev);
- return 0;
+ return NETDEV_TX_OK;
err_out:
ENABLE_IRQs;
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
index ee51557e942b..b2d617206bd9 100644
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -1375,7 +1375,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
spin_unlock_irqrestore(&np->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index d4b98074b1b7..e3d99fe53ce6 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -366,7 +366,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&fep->hw_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
static void
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c
index 75a09994d665..a2d69c1cd07e 100644
--- a/drivers/net/fs_enet/mii-fec.c
+++ b/drivers/net/fs_enet/mii-fec.c
@@ -36,6 +36,7 @@
#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
+#include <asm/mpc5xxx.h>
#include "fs_enet.h"
#include "fec.h"
@@ -103,11 +104,11 @@ static int fs_enet_fec_mii_reset(struct mii_bus *bus)
static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
const struct of_device_id *match)
{
- struct device_node *np = NULL;
struct resource res;
struct mii_bus *new_bus;
struct fec_info *fec;
- int ret = -ENOMEM, i;
+ int (*get_bus_freq)(struct device_node *) = match->data;
+ int ret = -ENOMEM, clock, speed;
new_bus = mdiobus_alloc();
if (!new_bus)
@@ -133,13 +134,35 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
if (!fec->fecp)
goto out_fec;
- fec->mii_speed = ((ppc_proc_freq + 4999999) / 5000000) << 1;
+ if (get_bus_freq) {
+ clock = get_bus_freq(ofdev->node);
+ if (!clock) {
+ /* Use maximum divider if clock is unknown */
+ dev_warn(&ofdev->dev, "could not determine IPS clock\n");
+ clock = 0x3F * 5000000;
+ }
+ } else
+ clock = ppc_proc_freq;
+
+ /*
+ * Scale for a MII clock <= 2.5 MHz
+ * Note that only 6 bits (25:30) are available for MII speed.
+ */
+ speed = (clock + 4999999) / 5000000;
+ if (speed > 0x3F) {
+ speed = 0x3F;
+ dev_err(&ofdev->dev,
+ "MII clock (%d Hz) exceeds max (2.5 MHz)\n",
+ clock / speed);
+ }
+
+ fec->mii_speed = speed << 1;
setbits32(&fec->fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE);
setbits32(&fec->fecp->fec_ecntrl, FEC_ECNTRL_PINMUX |
FEC_ECNTRL_ETHER_EN);
out_be32(&fec->fecp->fec_ievent, FEC_ENET_MII);
- out_be32(&fec->fecp->fec_mii_speed, fec->mii_speed);
+ clrsetbits_be32(&fec->fecp->fec_mii_speed, 0x7E, fec->mii_speed);
new_bus->phy_mask = ~0;
new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
@@ -188,6 +211,12 @@ static struct of_device_id fs_enet_mdio_fec_match[] = {
{
.compatible = "fsl,pq1-fec-mdio",
},
+#if defined(CONFIG_PPC_MPC512x)
+ {
+ .compatible = "fsl,mpc5121-fec-mdio",
+ .data = mpc5xxx_get_bus_frequency,
+ },
+#endif
{},
};
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index f8ffcbf0bc39..056ba4625780 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -297,7 +297,6 @@ static int gfar_probe(struct of_device *ofdev,
u32 tempval;
struct net_device *dev = NULL;
struct gfar_private *priv = NULL;
- DECLARE_MAC_BUF(mac);
int err = 0;
int len_devname;
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index 9d5b62cb30f7..4e8d3728e820 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -1369,7 +1369,7 @@ static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: Hamachi transmit frame #%d queued in slot %d.\n",
dev->name, hmp->cur_tx, entry);
}
- return 0;
+ return NETDEV_TX_OK;
}
/* The interrupt handler does all of the Rx thread work and cleans up
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 981ab530e9ac..6cb2bdfd7b19 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -255,7 +255,7 @@ static int sp_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static int sp_open_dev(struct net_device *dev)
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
index 5e4b7afd0683..e229edf3261a 100644
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -774,18 +774,18 @@ static int baycom_send_packet(struct sk_buff *skb, struct net_device *dev)
if (skb->data[0] != 0) {
do_kiss_params(bc, skb->data, skb->len);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (bc->skb)
return NETDEV_TX_LOCKED;
/* strip KISS byte */
if (skb->len >= HDLCDRV_MAXFLEN+1 || skb->len < 3) {
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
netif_stop_queue(dev);
bc->skb = skb;
- return 0;
+ return NETDEV_TX_OK;
}
/* --------------------------------------------------------------------- */
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index abcd19a8bff9..4c5f4dfbe05e 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -305,7 +305,7 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev)
dev_queue_xmit(skb);
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index 7459b3ac77a9..950f3bb21f9d 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -959,7 +959,7 @@ static int scc_send_packet(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&priv->ring_lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c
index d034f8ca63cb..16b060b92117 100644
--- a/drivers/net/hamradio/hdlcdrv.c
+++ b/drivers/net/hamradio/hdlcdrv.c
@@ -406,13 +406,13 @@ static int hdlcdrv_send_packet(struct sk_buff *skb, struct net_device *dev)
if (skb->data[0] != 0) {
do_kiss_params(sm, skb->data, skb->len);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (sm->skb)
return NETDEV_TX_LOCKED;
netif_stop_queue(dev);
sm->skb = skb;
- return 0;
+ return NETDEV_TX_OK;
}
/* --------------------------------------------------------------------- */
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index fda2fc83e9a1..ac191ef2119b 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -560,7 +560,7 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev)
kfree_skb(skb);
}
- return 0;
+ return NETDEV_TX_OK;
}
static int ax_open_dev(struct net_device *dev)
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index d712e7af780c..c5406525c1ad 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -1643,7 +1643,7 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev)
if (skb->len > scc->stat.bufsize || skb->len < 2) {
scc->dev_stat.tx_dropped++; /* bogus frame */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
scc->dev_stat.tx_packets++;
@@ -1656,7 +1656,7 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev)
if (kisscmd) {
scc_set_param(scc, kisscmd, *skb->data);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
spin_lock_irqsave(&scc->lock, flags);
@@ -1684,7 +1684,7 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev)
__scc_start_tx_timer(scc, t_dwait, 0);
}
spin_unlock_irqrestore(&scc->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/* ----> ioctl functions <---- */
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index b06691937ce9..b85aa162314e 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -600,7 +600,7 @@ static int yam_send_packet(struct sk_buff *skb, struct net_device *dev)
skb_queue_tail(&yp->send_queue, skb);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static void yam_start_tx(struct net_device *dev, struct yam_port *yp)
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 1d3429a415e6..d1b63387e9bc 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -1499,7 +1499,7 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev)
goto drop;
if (lp->chip == HP100_CHIPID_SHASTA && skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
/* Get Tx ring tail pointer */
if (lp->txrtail->next == lp->txrhead) {
@@ -1585,7 +1585,7 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev)
lp->stats.tx_bytes += skb->len;
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
drop:
dev_kfree_skb(skb);
@@ -1752,7 +1752,7 @@ static int hp100_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk("hp100: %s: start_xmit: end\n", dev->name);
#endif
- return 0;
+ return NETDEV_TX_OK;
drop:
dev_kfree_skb(skb);
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index beb84213b671..5443558c439d 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -1342,7 +1342,7 @@ static inline int emac_xmit_finish(struct emac_instance *dev, int len)
++dev->stats.tx_packets;
dev->stats.tx_bytes += len;
- return 0;
+ return NETDEV_TX_OK;
}
/* Tx lock BH */
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index 0995c438f286..76b295a18185 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -971,7 +971,7 @@ out: spin_lock_irqsave(&adapter->stats_lock, flags);
spin_unlock_irqrestore(&adapter->stats_lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static int ibmveth_poll(struct napi_struct *napi, int budget)
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index 96713ef06298..0a79b4517804 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -164,7 +164,7 @@ static int ifb_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ifb_private *dp = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
- int ret = 0;
+ int ret = NETDEV_TX_OK;
u32 from = G_TC_FROM(skb->tc_verd);
stats->rx_packets++;
diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c
index ac28dd5a4fd1..6158c0f3b205 100644
--- a/drivers/net/igb/e1000_82575.c
+++ b/drivers/net/igb/e1000_82575.c
@@ -53,7 +53,7 @@ static s32 igb_setup_fiber_serdes_link_82575(struct e1000_hw *);
static s32 igb_write_phy_reg_sgmii_82575(struct e1000_hw *, u32, u16);
static void igb_clear_hw_cntrs_82575(struct e1000_hw *);
static s32 igb_acquire_swfw_sync_82575(struct e1000_hw *, u16);
-static s32 igb_configure_pcs_link_82575(struct e1000_hw *);
+static void igb_configure_pcs_link_82575(struct e1000_hw *);
static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *, u16 *,
u16 *);
static s32 igb_get_phy_id_82575(struct e1000_hw *);
@@ -61,6 +61,7 @@ static void igb_release_swfw_sync_82575(struct e1000_hw *, u16);
static bool igb_sgmii_active_82575(struct e1000_hw *);
static s32 igb_reset_init_script_82575(struct e1000_hw *);
static s32 igb_read_mac_addr_82575(struct e1000_hw *);
+static s32 igb_set_pcie_completion_timeout(struct e1000_hw *hw);
static s32 igb_get_invariants_82575(struct e1000_hw *hw)
{
@@ -84,6 +85,7 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
case E1000_DEV_ID_82576_FIBER:
case E1000_DEV_ID_82576_SERDES:
case E1000_DEV_ID_82576_QUAD_COPPER:
+ case E1000_DEV_ID_82576_SERDES_QUAD:
mac->type = e1000_82576;
break;
default:
@@ -170,6 +172,10 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
size = 14;
nvm->word_size = 1 << size;
+ /* if 82576 then initialize mailbox parameters */
+ if (mac->type == e1000_82576)
+ igb_init_mbx_params_pf(hw);
+
/* setup PHY parameters */
if (phy->media_type != e1000_media_type_copper) {
phy->type = e1000_phy_none;
@@ -219,10 +225,6 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
return -E1000_ERR_PHY;
}
- /* if 82576 then initialize mailbox parameters */
- if (mac->type == e1000_82576)
- igb_init_mbx_params_pf(hw);
-
return 0;
}
@@ -764,98 +766,6 @@ static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw, u16 *speed,
}
/**
- * igb_init_rx_addrs_82575 - Initialize receive address's
- * @hw: pointer to the HW structure
- * @rar_count: receive address registers
- *
- * Setups the receive address registers by setting the base receive address
- * register to the devices MAC address and clearing all the other receive
- * address registers to 0.
- **/
-static void igb_init_rx_addrs_82575(struct e1000_hw *hw, u16 rar_count)
-{
- u32 i;
- u8 addr[6] = {0,0,0,0,0,0};
- /*
- * This function is essentially the same as that of
- * e1000_init_rx_addrs_generic. However it also takes care
- * of the special case where the register offset of the
- * second set of RARs begins elsewhere. This is implicitly taken care by
- * function e1000_rar_set_generic.
- */
-
- hw_dbg("e1000_init_rx_addrs_82575");
-
- /* Setup the receive address */
- hw_dbg("Programming MAC Address into RAR[0]\n");
- hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
-
- /* Zero out the other (rar_entry_count - 1) receive addresses */
- hw_dbg("Clearing RAR[1-%u]\n", rar_count-1);
- for (i = 1; i < rar_count; i++)
- hw->mac.ops.rar_set(hw, addr, i);
-}
-
-/**
- * igb_update_mc_addr_list - Update Multicast addresses
- * @hw: pointer to the HW structure
- * @mc_addr_list: array of multicast addresses to program
- * @mc_addr_count: number of multicast addresses to program
- * @rar_used_count: the first RAR register free to program
- * @rar_count: total number of supported Receive Address Registers
- *
- * Updates the Receive Address Registers and Multicast Table Array.
- * The caller must have a packed mc_addr_list of multicast addresses.
- * The parameter rar_count will usually be hw->mac.rar_entry_count
- * unless there are workarounds that change this.
- **/
-void igb_update_mc_addr_list(struct e1000_hw *hw,
- u8 *mc_addr_list, u32 mc_addr_count,
- u32 rar_used_count, u32 rar_count)
-{
- u32 hash_value;
- u32 i;
- u8 addr[6] = {0,0,0,0,0,0};
- /*
- * This function is essentially the same as that of
- * igb_update_mc_addr_list_generic. However it also takes care
- * of the special case where the register offset of the
- * second set of RARs begins elsewhere. This is implicitly taken care by
- * function e1000_rar_set_generic.
- */
-
- /*
- * Load the first set of multicast addresses into the exact
- * filters (RAR). If there are not enough to fill the RAR
- * array, clear the filters.
- */
- for (i = rar_used_count; i < rar_count; i++) {
- if (mc_addr_count) {
- igb_rar_set(hw, mc_addr_list, i);
- mc_addr_count--;
- mc_addr_list += ETH_ALEN;
- } else {
- igb_rar_set(hw, addr, i);
- }
- }
-
- /* Clear the old settings from the MTA */
- hw_dbg("Clearing MTA\n");
- for (i = 0; i < hw->mac.mta_reg_count; i++) {
- array_wr32(E1000_MTA, i, 0);
- wrfl();
- }
-
- /* Load any remaining multicast addresses into the hash table. */
- for (; mc_addr_count > 0; mc_addr_count--) {
- hash_value = igb_hash_mc_addr(hw, mc_addr_list);
- hw_dbg("Hash value = 0x%03X\n", hash_value);
- igb_mta_set(hw, hash_value);
- mc_addr_list += ETH_ALEN;
- }
-}
-
-/**
* igb_shutdown_fiber_serdes_link_82575 - Remove link during power down
* @hw: pointer to the HW structure
*
@@ -866,9 +776,7 @@ void igb_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw)
{
u32 reg;
- if (hw->mac.type != e1000_82576 ||
- (hw->phy.media_type != e1000_media_type_fiber &&
- hw->phy.media_type != e1000_media_type_internal_serdes))
+ if (hw->phy.media_type != e1000_media_type_internal_serdes)
return;
/* if the management interface is not enabled, then power down */
@@ -911,6 +819,12 @@ static s32 igb_reset_hw_82575(struct e1000_hw *hw)
if (ret_val)
hw_dbg("PCI-E Master disable polling has failed.\n");
+ /* set the completion timeout for interface */
+ ret_val = igb_set_pcie_completion_timeout(hw);
+ if (ret_val) {
+ hw_dbg("PCI-E Set completion timeout has failed.\n");
+ }
+
hw_dbg("Masking off all interrupts\n");
wr32(E1000_IMC, 0xffffffff);
@@ -943,7 +857,8 @@ static s32 igb_reset_hw_82575(struct e1000_hw *hw)
wr32(E1000_IMC, 0xffffffff);
icr = rd32(E1000_ICR);
- igb_check_alt_mac_addr(hw);
+ /* Install any alternate MAC address into RAR0 */
+ ret_val = igb_check_alt_mac_addr(hw);
return ret_val;
}
@@ -972,7 +887,8 @@ static s32 igb_init_hw_82575(struct e1000_hw *hw)
igb_clear_vfta(hw);
/* Setup the receive address */
- igb_init_rx_addrs_82575(hw, rar_count);
+ igb_init_rx_addrs(hw, rar_count);
+
/* Zero out the Multicast HASH table */
hw_dbg("Zeroing the MTA\n");
for (i = 0; i < mac->mta_reg_count; i++)
@@ -1002,7 +918,7 @@ static s32 igb_init_hw_82575(struct e1000_hw *hw)
**/
static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
{
- u32 ctrl, led_ctrl;
+ u32 ctrl;
s32 ret_val;
bool link;
@@ -1017,11 +933,6 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
break;
case e1000_phy_igp_3:
ret_val = igb_copper_link_setup_igp(hw);
- /* Setup activity LED */
- led_ctrl = rd32(E1000_LEDCTL);
- led_ctrl &= IGP_ACTIVITY_LED_MASK;
- led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
- wr32(E1000_LEDCTL, led_ctrl);
break;
default:
ret_val = -E1000_ERR_PHY;
@@ -1052,9 +963,7 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
}
}
- ret_val = igb_configure_pcs_link_82575(hw);
- if (ret_val)
- goto out;
+ igb_configure_pcs_link_82575(hw);
/*
* Check link status. Wait up to 100 microseconds for link to become
@@ -1163,14 +1072,14 @@ static s32 igb_setup_fiber_serdes_link_82575(struct e1000_hw *hw)
* independent interface (sgmii) is being used. Configures the link
* for auto-negotiation or forces speed/duplex.
**/
-static s32 igb_configure_pcs_link_82575(struct e1000_hw *hw)
+static void igb_configure_pcs_link_82575(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
u32 reg = 0;
if (hw->phy.media_type != e1000_media_type_copper ||
!(igb_sgmii_active_82575(hw)))
- goto out;
+ return;
/* For SGMII, we need to issue a PCS autoneg restart */
reg = rd32(E1000_PCS_LCTL);
@@ -1213,9 +1122,6 @@ static s32 igb_configure_pcs_link_82575(struct e1000_hw *hw)
reg);
}
wr32(E1000_PCS_LCTL, reg);
-
-out:
- return 0;
}
/**
@@ -1229,10 +1135,6 @@ out:
static bool igb_sgmii_active_82575(struct e1000_hw *hw)
{
struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575;
-
- if (hw->mac.type != e1000_82575 && hw->mac.type != e1000_82576)
- return false;
-
return dev_spec->sgmii_active;
}
@@ -1424,6 +1326,57 @@ void igb_rx_fifo_flush_82575(struct e1000_hw *hw)
}
/**
+ * igb_set_pcie_completion_timeout - set pci-e completion timeout
+ * @hw: pointer to the HW structure
+ *
+ * The defaults for 82575 and 82576 should be in the range of 50us to 50ms,
+ * however the hardware default for these parts is 500us to 1ms which is less
+ * than the 10ms recommended by the pci-e spec. To address this we need to
+ * increase the value to either 10ms to 200ms for capability version 1 config,
+ * or 16ms to 55ms for version 2.
+ **/
+static s32 igb_set_pcie_completion_timeout(struct e1000_hw *hw)
+{
+ u32 gcr = rd32(E1000_GCR);
+ s32 ret_val = 0;
+ u16 pcie_devctl2;
+
+ /* only take action if timeout value is defaulted to 0 */
+ if (gcr & E1000_GCR_CMPL_TMOUT_MASK)
+ goto out;
+
+ /*
+ * if capababilities version is type 1 we can write the
+ * timeout of 10ms to 200ms through the GCR register
+ */
+ if (!(gcr & E1000_GCR_CAP_VER2)) {
+ gcr |= E1000_GCR_CMPL_TMOUT_10ms;
+ goto out;
+ }
+
+ /*
+ * for version 2 capabilities we need to write the config space
+ * directly in order to set the completion timeout value for
+ * 16ms to 55ms
+ */
+ ret_val = igb_read_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
+ &pcie_devctl2);
+ if (ret_val)
+ goto out;
+
+ pcie_devctl2 |= PCIE_DEVICE_CONTROL2_16ms;
+
+ ret_val = igb_write_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
+ &pcie_devctl2);
+out:
+ /* disable completion timeout resend */
+ gcr &= ~E1000_GCR_CMPL_TMOUT_RESEND;
+
+ wr32(E1000_GCR, gcr);
+ return ret_val;
+}
+
+/**
* igb_vmdq_set_loopback_pf - enable or disable vmdq loopback
* @hw: pointer to the hardware struct
* @enable: state to enter, either enabled or disabled
diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h
index 0f16abab2565..8a1e6597061f 100644
--- a/drivers/net/igb/e1000_82575.h
+++ b/drivers/net/igb/e1000_82575.h
@@ -28,10 +28,14 @@
#ifndef _E1000_82575_H_
#define _E1000_82575_H_
-void igb_update_mc_addr_list(struct e1000_hw*, u8*, u32, u32, u32);
extern void igb_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw);
extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw);
+#define ID_LED_DEFAULT_82575_SERDES ((ID_LED_DEF1_DEF2 << 12) | \
+ (ID_LED_DEF1_DEF2 << 8) | \
+ (ID_LED_DEF1_DEF2 << 4) | \
+ (ID_LED_OFF1_ON2))
+
#define E1000_RAR_ENTRIES_82575 16
#define E1000_RAR_ENTRIES_82576 24
diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h
index 3bda3db73f1f..c85829355d50 100644
--- a/drivers/net/igb/e1000_defines.h
+++ b/drivers/net/igb/e1000_defines.h
@@ -435,6 +435,12 @@
/* Flow Control */
#define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */
+/* PCI Express Control */
+#define E1000_GCR_CMPL_TMOUT_MASK 0x0000F000
+#define E1000_GCR_CMPL_TMOUT_10ms 0x00001000
+#define E1000_GCR_CMPL_TMOUT_RESEND 0x00010000
+#define E1000_GCR_CAP_VER2 0x00040000
+
/* PHY Control Register */
#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
@@ -569,9 +575,11 @@
/* 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 MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h
index 68aac20c31ca..119869b1124d 100644
--- a/drivers/net/igb/e1000_hw.h
+++ b/drivers/net/igb/e1000_hw.h
@@ -42,6 +42,7 @@ struct e1000_hw;
#define E1000_DEV_ID_82576_SERDES 0x10E7
#define E1000_DEV_ID_82576_QUAD_COPPER 0x10E8
#define E1000_DEV_ID_82576_NS 0x150A
+#define E1000_DEV_ID_82576_SERDES_QUAD 0x150D
#define E1000_DEV_ID_82575EB_COPPER 0x10A7
#define E1000_DEV_ID_82575EB_FIBER_SERDES 0x10A9
#define E1000_DEV_ID_82575GB_QUAD_COPPER 0x10D6
@@ -61,8 +62,7 @@ enum e1000_mac_type {
enum e1000_media_type {
e1000_media_type_unknown = 0,
e1000_media_type_copper = 1,
- e1000_media_type_fiber = 2,
- e1000_media_type_internal_serdes = 3,
+ e1000_media_type_internal_serdes = 2,
e1000_num_media_types
};
@@ -137,7 +137,7 @@ enum e1000_rev_polarity {
e1000_rev_polarity_undefined = 0xFF
};
-enum e1000_fc_type {
+enum e1000_fc_mode {
e1000_fc_none = 0,
e1000_fc_rx_pause,
e1000_fc_tx_pause,
@@ -339,6 +339,10 @@ struct e1000_mac_info {
u16 ifs_ratio;
u16 ifs_step_size;
u16 mta_reg_count;
+
+ /* Maximum size of the MTA register table in all supported adapters */
+ #define MAX_MTA_REG 128
+ u32 mta_shadow[MAX_MTA_REG];
u16 rar_entry_count;
u8 forced_speed_duplex;
@@ -425,8 +429,8 @@ struct e1000_fc_info {
u16 pause_time; /* Flow control pause timer */
bool send_xon; /* Flow control send XON */
bool strict_ieee; /* Strict IEEE mode */
- enum e1000_fc_type type; /* Type of flow control */
- enum e1000_fc_type original_type;
+ enum e1000_fc_mode current_mode; /* Type of flow control */
+ enum e1000_fc_mode requested_mode;
};
struct e1000_mbx_operations {
@@ -495,5 +499,7 @@ extern char *igb_get_hw_dev_name(struct e1000_hw *hw);
#else
#define hw_dbg(format, arg...)
#endif
-
#endif
+/* 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);
diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c
index 472f3f124840..a0231cd079f1 100644
--- a/drivers/net/igb/e1000_mac.c
+++ b/drivers/net/igb/e1000_mac.c
@@ -37,20 +37,6 @@
static s32 igb_set_default_fc(struct e1000_hw *hw);
static s32 igb_set_fc_watermarks(struct e1000_hw *hw);
-static s32 igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value)
-{
- struct igb_adapter *adapter = hw->back;
- u16 cap_offset;
-
- cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
- if (!cap_offset)
- return -E1000_ERR_CONFIG;
-
- pci_read_config_word(adapter->pdev, cap_offset + reg, value);
-
- return 0;
-}
-
/**
* igb_get_bus_info_pcie - Get PCIe bus information
* @hw: pointer to the HW structure
@@ -118,6 +104,31 @@ static void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
}
/**
+ * igb_init_rx_addrs - Initialize receive address's
+ * @hw: pointer to the HW structure
+ * @rar_count: receive address registers
+ *
+ * Setups the receive address registers by setting the base receive address
+ * register to the devices MAC address and clearing all the other receive
+ * address registers to 0.
+ **/
+void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count)
+{
+ u32 i;
+ u8 mac_addr[ETH_ALEN] = {0};
+
+ /* Setup the receive address */
+ hw_dbg("Programming MAC Address into RAR[0]\n");
+
+ hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
+
+ /* Zero out the other (rar_entry_count - 1) receive addresses */
+ hw_dbg("Clearing RAR[1-%u]\n", rar_count-1);
+ for (i = 1; i < rar_count; i++)
+ hw->mac.ops.rar_set(hw, mac_addr, i);
+}
+
+/**
* igb_vfta_set - enable or disable vlan in VLAN filter table
* @hw: pointer to the HW structure
* @vid: VLAN id to add or remove
@@ -275,6 +286,41 @@ void igb_mta_set(struct e1000_hw *hw, u32 hash_value)
}
/**
+ * igb_update_mc_addr_list - 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
+ *
+ * Updates entire Multicast Table Array.
+ * The caller must have a packed mc_addr_list of multicast addresses.
+ **/
+void igb_update_mc_addr_list(struct e1000_hw *hw,
+ u8 *mc_addr_list, u32 mc_addr_count)
+{
+ u32 hash_value, hash_bit, hash_reg;
+ int i;
+
+ /* clear mta_shadow */
+ memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow));
+
+ /* update mta_shadow from mc_addr_list */
+ for (i = 0; (u32) i < mc_addr_count; i++) {
+ hash_value = igb_hash_mc_addr(hw, mc_addr_list);
+
+ hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
+ hash_bit = hash_value & 0x1F;
+
+ hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit);
+ mc_addr_list += (ETH_ALEN);
+ }
+
+ /* replace the entire MTA table */
+ for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
+ array_wr32(E1000_MTA, i, hw->mac.mta_shadow[i]);
+ wrfl();
+}
+
+/**
* igb_hash_mc_addr - Generate a multicast hash value
* @hw: pointer to the HW structure
* @mc_addr: pointer to a multicast address
@@ -490,18 +536,24 @@ s32 igb_setup_link(struct e1000_hw *hw)
if (igb_check_reset_block(hw))
goto out;
- ret_val = igb_set_default_fc(hw);
- if (ret_val)
- goto out;
+ /*
+ * If requested flow control is set to default, set flow control
+ * based on the EEPROM flow control settings.
+ */
+ if (hw->fc.requested_mode == e1000_fc_default) {
+ ret_val = igb_set_default_fc(hw);
+ if (ret_val)
+ goto out;
+ }
/*
* We want to save off the original Flow Control configuration just
* in case we get disconnected and then reconnected into a different
* hub or switch with different Flow Control capabilities.
*/
- hw->fc.original_type = hw->fc.type;
+ hw->fc.current_mode = hw->fc.requested_mode;
- hw_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.type);
+ hw_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.current_mode);
/* Call the necessary media_type subroutine to configure the link. */
ret_val = hw->mac.ops.setup_physical_interface(hw);
@@ -568,7 +620,7 @@ static s32 igb_set_fc_watermarks(struct e1000_hw *hw)
* ability to transmit pause frames is not enabled, then these
* registers will be set to 0.
*/
- if (hw->fc.type & e1000_fc_tx_pause) {
+ if (hw->fc.current_mode & e1000_fc_tx_pause) {
/*
* We need to set up the Receive Threshold high and low water
* marks as well as (optionally) enabling the transmission of
@@ -615,12 +667,12 @@ static s32 igb_set_default_fc(struct e1000_hw *hw)
}
if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0)
- hw->fc.type = e1000_fc_none;
+ hw->fc.requested_mode = e1000_fc_none;
else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) ==
NVM_WORD0F_ASM_DIR)
- hw->fc.type = e1000_fc_tx_pause;
+ hw->fc.requested_mode = e1000_fc_tx_pause;
else
- hw->fc.type = e1000_fc_full;
+ hw->fc.requested_mode = e1000_fc_full;
out:
return ret_val;
@@ -650,7 +702,7 @@ s32 igb_force_mac_fc(struct e1000_hw *hw)
* receive flow control.
*
* The "Case" statement below enables/disable flow control
- * according to the "hw->fc.type" parameter.
+ * according to the "hw->fc.current_mode" parameter.
*
* The possible values of the "fc" parameter are:
* 0: Flow control is completely disabled
@@ -661,9 +713,9 @@ s32 igb_force_mac_fc(struct e1000_hw *hw)
* 3: Both Rx and TX flow control (symmetric) is enabled.
* other: No other values should be possible at this point.
*/
- hw_dbg("hw->fc.type = %u\n", hw->fc.type);
+ hw_dbg("hw->fc.current_mode = %u\n", hw->fc.current_mode);
- switch (hw->fc.type) {
+ switch (hw->fc.current_mode) {
case e1000_fc_none:
ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
break;
@@ -713,8 +765,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
* configuration of the MAC to match the "fc" parameter.
*/
if (mac->autoneg_failed) {
- if (hw->phy.media_type == e1000_media_type_fiber ||
- hw->phy.media_type == e1000_media_type_internal_serdes)
+ if (hw->phy.media_type == e1000_media_type_internal_serdes)
ret_val = igb_force_mac_fc(hw);
} else {
if (hw->phy.media_type == e1000_media_type_copper)
@@ -812,11 +863,11 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
* ONLY. Hence, we must now check to see if we need to
* turn OFF the TRANSMISSION of PAUSE frames.
*/
- if (hw->fc.original_type == e1000_fc_full) {
- hw->fc.type = e1000_fc_full;
+ if (hw->fc.requested_mode == e1000_fc_full) {
+ hw->fc.current_mode = e1000_fc_full;
hw_dbg("Flow Control = FULL.\r\n");
} else {
- hw->fc.type = e1000_fc_rx_pause;
+ hw->fc.current_mode = e1000_fc_rx_pause;
hw_dbg("Flow Control = "
"RX PAUSE frames only.\r\n");
}
@@ -833,7 +884,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
(mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
(mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
- hw->fc.type = e1000_fc_tx_pause;
+ hw->fc.current_mode = e1000_fc_tx_pause;
hw_dbg("Flow Control = TX PAUSE frames only.\r\n");
}
/*
@@ -848,7 +899,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
(mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
!(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
(mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
- hw->fc.type = e1000_fc_rx_pause;
+ hw->fc.current_mode = e1000_fc_rx_pause;
hw_dbg("Flow Control = RX PAUSE frames only.\r\n");
}
/*
@@ -872,13 +923,13 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
* be asked to delay transmission of packets than asking
* our link partner to pause transmission of frames.
*/
- else if ((hw->fc.original_type == e1000_fc_none ||
- hw->fc.original_type == e1000_fc_tx_pause) ||
+ else if ((hw->fc.requested_mode == e1000_fc_none ||
+ hw->fc.requested_mode == e1000_fc_tx_pause) ||
hw->fc.strict_ieee) {
- hw->fc.type = e1000_fc_none;
+ hw->fc.current_mode = e1000_fc_none;
hw_dbg("Flow Control = NONE.\r\n");
} else {
- hw->fc.type = e1000_fc_rx_pause;
+ hw->fc.current_mode = e1000_fc_rx_pause;
hw_dbg("Flow Control = RX PAUSE frames only.\r\n");
}
@@ -894,7 +945,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
}
if (duplex == HALF_DUPLEX)
- hw->fc.type = e1000_fc_none;
+ hw->fc.current_mode = e1000_fc_none;
/*
* Now we call a subroutine to actually force the MAC
@@ -1065,9 +1116,17 @@ static s32 igb_valid_led_default(struct e1000_hw *hw, u16 *data)
goto out;
}
- if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
- *data = ID_LED_DEFAULT;
-
+ if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) {
+ switch(hw->phy.media_type) {
+ case e1000_media_type_internal_serdes:
+ *data = ID_LED_DEFAULT_82575_SERDES;
+ break;
+ case e1000_media_type_copper:
+ default:
+ *data = ID_LED_DEFAULT;
+ break;
+ }
+ }
out:
return ret_val;
}
@@ -1161,22 +1220,16 @@ s32 igb_blink_led(struct e1000_hw *hw)
u32 ledctl_blink = 0;
u32 i;
- if (hw->phy.media_type == e1000_media_type_fiber) {
- /* always blink LED0 for PCI-E fiber */
- ledctl_blink = E1000_LEDCTL_LED0_BLINK |
- (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT);
- } else {
- /*
- * set the blink bit for each LED that's "on" (0x0E)
- * in ledctl_mode2
- */
- ledctl_blink = hw->mac.ledctl_mode2;
- for (i = 0; i < 4; i++)
- if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
- E1000_LEDCTL_MODE_LED_ON)
- ledctl_blink |= (E1000_LEDCTL_LED0_BLINK <<
- (i * 8));
- }
+ /*
+ * set the blink bit for each LED that's "on" (0x0E)
+ * in ledctl_mode2
+ */
+ ledctl_blink = hw->mac.ledctl_mode2;
+ for (i = 0; i < 4; i++)
+ if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
+ E1000_LEDCTL_MODE_LED_ON)
+ ledctl_blink |= (E1000_LEDCTL_LED0_BLINK <<
+ (i * 8));
wr32(E1000_LEDCTL, ledctl_blink);
@@ -1191,15 +1244,7 @@ s32 igb_blink_led(struct e1000_hw *hw)
**/
s32 igb_led_off(struct e1000_hw *hw)
{
- u32 ctrl;
-
switch (hw->phy.media_type) {
- case e1000_media_type_fiber:
- ctrl = rd32(E1000_CTRL);
- ctrl |= E1000_CTRL_SWDPIN0;
- ctrl |= E1000_CTRL_SWDPIO0;
- wr32(E1000_CTRL, ctrl);
- break;
case e1000_media_type_copper:
wr32(E1000_LEDCTL, hw->mac.ledctl_mode1);
break;
diff --git a/drivers/net/igb/e1000_mac.h b/drivers/net/igb/e1000_mac.h
index 1d690b4c9ae4..7518af8cbbf5 100644
--- a/drivers/net/igb/e1000_mac.h
+++ b/drivers/net/igb/e1000_mac.h
@@ -51,6 +51,8 @@ s32 igb_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed,
u16 *duplex);
s32 igb_id_led_init(struct e1000_hw *hw);
s32 igb_led_off(struct e1000_hw *hw);
+void igb_update_mc_addr_list(struct e1000_hw *hw,
+ u8 *mc_addr_list, u32 mc_addr_count);
s32 igb_setup_link(struct e1000_hw *hw);
s32 igb_validate_mdi_setting(struct e1000_hw *hw);
s32 igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg,
@@ -60,6 +62,7 @@ void igb_clear_hw_cntrs_base(struct e1000_hw *hw);
void igb_clear_vfta(struct e1000_hw *hw);
s32 igb_vfta_set(struct e1000_hw *hw, u32 vid, bool add);
void igb_config_collision_dist(struct e1000_hw *hw);
+void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
void igb_mta_set(struct e1000_hw *hw, u32 hash_value);
void igb_put_hw_semaphore(struct e1000_hw *hw);
void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index);
diff --git a/drivers/net/igb/e1000_phy.c b/drivers/net/igb/e1000_phy.c
index f50fac25be40..c1f4da630420 100644
--- a/drivers/net/igb/e1000_phy.c
+++ b/drivers/net/igb/e1000_phy.c
@@ -735,7 +735,7 @@ static s32 igb_phy_setup_autoneg(struct e1000_hw *hw)
* other: No software override. The flow control configuration
* in the EEPROM is used.
*/
- switch (hw->fc.type) {
+ switch (hw->fc.current_mode) {
case e1000_fc_none:
/*
* Flow control (RX & TX) is completely disabled by a
@@ -992,7 +992,7 @@ static void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw,
u32 ctrl;
/* Turn off flow control when forcing speed/duplex */
- hw->fc.type = e1000_fc_none;
+ hw->fc.current_mode = e1000_fc_none;
/* Force speed/duplex on the mac */
ctrl = rd32(E1000_CTRL);
diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h
index 6e5924511e40..345d1442d6d6 100644
--- a/drivers/net/igb/e1000_regs.h
+++ b/drivers/net/igb/e1000_regs.h
@@ -305,6 +305,7 @@ enum {
#define E1000_CCMCTL 0x05B48 /* CCM Control Register */
#define E1000_GIOCTL 0x05B44 /* GIO Analog Control Register */
#define E1000_SCCTL 0x05B4C /* PCIc PLL Configuration Register */
+#define E1000_GCR 0x05B00 /* PCI-Ex Control */
#define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */
#define E1000_SWSM 0x05B50 /* SW Semaphore */
#define E1000_FWSM 0x05B54 /* FW Semaphore */
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c
index 9598ac09f4b8..114ccab1f2be 100644
--- a/drivers/net/igb/igb_ethtool.c
+++ b/drivers/net/igb/igb_ethtool.c
@@ -168,8 +168,7 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
ecmd->duplex = -1;
}
- ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) ||
- hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+ ecmd->autoneg = hw->mac.autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE;
return 0;
}
@@ -191,23 +190,20 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
if (ecmd->autoneg == AUTONEG_ENABLE) {
hw->mac.autoneg = 1;
- if (hw->phy.media_type == e1000_media_type_fiber)
- hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full |
- ADVERTISED_FIBRE |
- ADVERTISED_Autoneg;
- else
- hw->phy.autoneg_advertised = ecmd->advertising |
- ADVERTISED_TP |
- ADVERTISED_Autoneg;
+ hw->phy.autoneg_advertised = ecmd->advertising |
+ ADVERTISED_TP |
+ ADVERTISED_Autoneg;
ecmd->advertising = hw->phy.autoneg_advertised;
- } else
+ if (adapter->fc_autoneg)
+ hw->fc.requested_mode = e1000_fc_default;
+ } else {
if (igb_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) {
clear_bit(__IGB_RESETTING, &adapter->state);
return -EINVAL;
}
+ }
/* reset the link */
-
if (netif_running(adapter->netdev)) {
igb_down(adapter);
igb_up(adapter);
@@ -227,11 +223,11 @@ static void igb_get_pauseparam(struct net_device *netdev,
pause->autoneg =
(adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
- if (hw->fc.type == e1000_fc_rx_pause)
+ if (hw->fc.current_mode == e1000_fc_rx_pause)
pause->rx_pause = 1;
- else if (hw->fc.type == e1000_fc_tx_pause)
+ else if (hw->fc.current_mode == e1000_fc_tx_pause)
pause->tx_pause = 1;
- else if (hw->fc.type == e1000_fc_full) {
+ else if (hw->fc.current_mode == e1000_fc_full) {
pause->rx_pause = 1;
pause->tx_pause = 1;
}
@@ -249,26 +245,28 @@ static int igb_set_pauseparam(struct net_device *netdev,
while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
msleep(1);
- if (pause->rx_pause && pause->tx_pause)
- hw->fc.type = e1000_fc_full;
- else if (pause->rx_pause && !pause->tx_pause)
- hw->fc.type = e1000_fc_rx_pause;
- else if (!pause->rx_pause && pause->tx_pause)
- hw->fc.type = e1000_fc_tx_pause;
- else if (!pause->rx_pause && !pause->tx_pause)
- hw->fc.type = e1000_fc_none;
-
- hw->fc.original_type = hw->fc.type;
-
if (adapter->fc_autoneg == AUTONEG_ENABLE) {
+ hw->fc.requested_mode = e1000_fc_default;
if (netif_running(adapter->netdev)) {
igb_down(adapter);
igb_up(adapter);
} else
igb_reset(adapter);
- } else
- retval = ((hw->phy.media_type == e1000_media_type_fiber) ?
- igb_setup_link(hw) : igb_force_mac_fc(hw));
+ } else {
+ if (pause->rx_pause && pause->tx_pause)
+ hw->fc.requested_mode = e1000_fc_full;
+ else if (pause->rx_pause && !pause->tx_pause)
+ hw->fc.requested_mode = e1000_fc_rx_pause;
+ else if (!pause->rx_pause && pause->tx_pause)
+ hw->fc.requested_mode = e1000_fc_tx_pause;
+ else if (!pause->rx_pause && !pause->tx_pause)
+ hw->fc.requested_mode = e1000_fc_none;
+
+ hw->fc.current_mode = hw->fc.requested_mode;
+
+ retval = ((hw->phy.media_type == e1000_media_type_copper) ?
+ igb_force_mac_fc(hw) : igb_setup_link(hw));
+ }
clear_bit(__IGB_RESETTING, &adapter->state);
return retval;
@@ -1483,8 +1481,7 @@ static int igb_setup_loopback_test(struct igb_adapter *adapter)
struct e1000_hw *hw = &adapter->hw;
u32 reg;
- if (hw->phy.media_type == e1000_media_type_fiber ||
- hw->phy.media_type == e1000_media_type_internal_serdes) {
+ if (hw->phy.media_type == e1000_media_type_internal_serdes) {
reg = rd32(E1000_RCTL);
reg |= E1000_RCTL_LBM_TCVR;
wr32(E1000_RCTL, reg);
@@ -1843,7 +1840,6 @@ static void igb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
{
struct igb_adapter *adapter = netdev_priv(netdev);
- struct e1000_hw *hw = &adapter->hw;
if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
return -EOPNOTSUPP;
@@ -1852,11 +1848,6 @@ static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
!device_can_wakeup(&adapter->pdev->dev))
return wol->wolopts ? -EOPNOTSUPP : 0;
- switch (hw->device_id) {
- default:
- break;
- }
-
/* these settings will always override what we currently have */
adapter->wol = 0;
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index adb09d32625d..fb3273517587 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -65,6 +65,7 @@ static struct pci_device_id igb_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_FIBER), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES), board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES_QUAD), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_QUAD_COPPER), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_COPPER), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_FIBER_SERDES), board_82575 },
@@ -127,7 +128,7 @@ static void igb_restore_vlan(struct igb_adapter *);
static void igb_ping_all_vfs(struct igb_adapter *);
static void igb_msg_task(struct igb_adapter *);
static int igb_rcv_msg_from_vf(struct igb_adapter *, u32);
-static void igb_set_mc_list_pools(struct igb_adapter *, int, u16);
+static inline void igb_set_rah_pool(struct e1000_hw *, int , int);
static void igb_vmm_control(struct igb_adapter *);
static int igb_set_vf_mac(struct igb_adapter *adapter, int, unsigned char *);
static void igb_restore_vf_multicasts(struct igb_adapter *adapter);
@@ -1129,7 +1130,7 @@ void igb_reset(struct igb_adapter *adapter)
}
fc->pause_time = 0xFFFF;
fc->send_xon = 1;
- fc->type = fc->original_type;
+ fc->current_mode = fc->requested_mode;
/* disable receive for all VFs and wait one second */
if (adapter->vfs_allocated_count) {
@@ -1426,8 +1427,8 @@ static int __devinit igb_probe(struct pci_dev *pdev,
hw->mac.autoneg = true;
hw->phy.autoneg_advertised = 0x2f;
- hw->fc.original_type = e1000_fc_default;
- hw->fc.type = e1000_fc_default;
+ hw->fc.requested_mode = e1000_fc_default;
+ hw->fc.current_mode = e1000_fc_default;
adapter->itr_setting = IGB_DEFAULT_ITR;
adapter->itr = IGB_START_ITR;
@@ -2535,7 +2536,6 @@ static void igb_set_multi(struct net_device *netdev)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
- struct e1000_mac_info *mac = &hw->mac;
struct dev_mc_list *mc_ptr;
u8 *mta_list = NULL;
u32 rctl;
@@ -2558,13 +2558,18 @@ static void igb_set_multi(struct net_device *netdev)
}
wr32(E1000_RCTL, rctl);
- if (netdev->mc_count) {
- mta_list = kzalloc(netdev->mc_count * 6, GFP_ATOMIC);
- if (!mta_list) {
- dev_err(&adapter->pdev->dev,
- "failed to allocate multicast filter list\n");
- return;
- }
+ if (!netdev->mc_count) {
+ /* nothing to program, so clear mc list */
+ igb_update_mc_addr_list(hw, NULL, 0);
+ igb_restore_vf_multicasts(adapter);
+ return;
+ }
+
+ mta_list = kzalloc(netdev->mc_count * 6, GFP_ATOMIC);
+ if (!mta_list) {
+ dev_err(&adapter->pdev->dev,
+ "failed to allocate multicast filter list\n");
+ return;
}
/* The shared function expects a packed array of only addresses. */
@@ -2576,14 +2581,9 @@ static void igb_set_multi(struct net_device *netdev)
memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr, ETH_ALEN);
mc_ptr = mc_ptr->next;
}
- igb_update_mc_addr_list(hw, mta_list, i,
- adapter->vfs_allocated_count + 1,
- mac->rar_entry_count);
-
- igb_set_mc_list_pools(adapter, i, mac->rar_entry_count);
- igb_restore_vf_multicasts(adapter);
-
+ igb_update_mc_addr_list(hw, mta_list, i);
kfree(mta_list);
+ igb_restore_vf_multicasts(adapter);
}
/* Need to wait a few seconds after link up to get diagnostic information from
@@ -2618,10 +2618,6 @@ static bool igb_has_link(struct igb_adapter *adapter)
link_active = true;
}
break;
- case e1000_media_type_fiber:
- ret_val = hw->mac.ops.check_for_link(hw);
- link_active = !!(rd32(E1000_STATUS) & E1000_STATUS_LU);
- break;
case e1000_media_type_internal_serdes:
ret_val = hw->mac.ops.check_for_link(hw);
link_active = hw->mac.serdes_has_link;
@@ -4542,6 +4538,20 @@ static inline void igb_rx_checksum_adv(struct igb_adapter *adapter,
adapter->hw_csum_good++;
}
+static inline u16 igb_get_hlen(struct igb_adapter *adapter,
+ union e1000_adv_rx_desc *rx_desc)
+{
+ /* HW will not DMA in data larger than the given buffer, even if it
+ * parses the (NFS, of course) header to be larger. In that case, it
+ * fills the header buffer and spills the rest into the page.
+ */
+ u16 hlen = (le16_to_cpu(rx_desc->wb.lower.lo_dword.hdr_info) &
+ E1000_RXDADV_HDRBUFLEN_MASK) >> E1000_RXDADV_HDRBUFLEN_SHIFT;
+ if (hlen > adapter->rx_ps_hdr_size)
+ hlen = adapter->rx_ps_hdr_size;
+ return hlen;
+}
+
static bool igb_clean_rx_irq_adv(struct igb_ring *rx_ring,
int *work_done, int budget)
{
@@ -4556,7 +4566,8 @@ static bool igb_clean_rx_irq_adv(struct igb_ring *rx_ring,
int cleaned_count = 0;
unsigned int total_bytes = 0, total_packets = 0;
unsigned int i;
- u32 length, hlen, staterr;
+ u32 staterr;
+ u16 length;
i = rx_ring->next_to_clean;
buffer_info = &rx_ring->buffer_info[i];
@@ -4593,17 +4604,8 @@ static bool igb_clean_rx_irq_adv(struct igb_ring *rx_ring,
goto send_up;
}
- /* HW will not DMA in data larger than the given buffer, even
- * if it parses the (NFS, of course) header to be larger. In
- * that case, it fills the header buffer and spills the rest
- * into the page.
- */
- hlen = (le16_to_cpu(rx_desc->wb.lower.lo_dword.hdr_info) &
- E1000_RXDADV_HDRBUFLEN_MASK) >> E1000_RXDADV_HDRBUFLEN_SHIFT;
- if (hlen > adapter->rx_ps_hdr_size)
- hlen = adapter->rx_ps_hdr_size;
-
- if (!skb_shinfo(skb)->nr_frags) {
+ if (buffer_info->dma) {
+ u16 hlen = igb_get_hlen(adapter, rx_desc);
pci_unmap_single(pdev, buffer_info->dma,
adapter->rx_ps_hdr_size,
PCI_DMA_FROMDEVICE);
@@ -5033,6 +5035,34 @@ static int igb_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
}
}
+s32 igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value)
+{
+ struct igb_adapter *adapter = hw->back;
+ u16 cap_offset;
+
+ cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+ if (!cap_offset)
+ return -E1000_ERR_CONFIG;
+
+ pci_read_config_word(adapter->pdev, cap_offset + reg, value);
+
+ return 0;
+}
+
+s32 igb_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value)
+{
+ struct igb_adapter *adapter = hw->back;
+ u16 cap_offset;
+
+ cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+ if (!cap_offset)
+ return -E1000_ERR_CONFIG;
+
+ pci_write_config_word(adapter->pdev, cap_offset + reg, *value);
+
+ return 0;
+}
+
static void igb_vlan_rx_register(struct net_device *netdev,
struct vlan_group *grp)
{
@@ -5136,14 +5166,6 @@ int igb_set_spd_dplx(struct igb_adapter *adapter, u16 spddplx)
mac->autoneg = 0;
- /* Fiber NICs only allow 1000 gbps Full duplex */
- if ((adapter->hw.phy.media_type == e1000_media_type_fiber) &&
- spddplx != (SPEED_1000 + DUPLEX_FULL)) {
- dev_err(&adapter->pdev->dev,
- "Unsupported Speed/Duplex configuration\n");
- return -EINVAL;
- }
-
switch (spddplx) {
case SPEED_10 + DUPLEX_HALF:
mac->forced_speed_duplex = ADVERTISE_10_HALF;
@@ -5452,19 +5474,6 @@ static void igb_io_resume(struct pci_dev *pdev)
igb_get_hw_control(adapter);
}
-static void igb_set_mc_list_pools(struct igb_adapter *adapter,
- int entry_count, u16 total_rar_filters)
-{
- struct e1000_hw *hw = &adapter->hw;
- int i = adapter->vfs_allocated_count + 1;
-
- if ((i + entry_count) < total_rar_filters)
- total_rar_filters = i + entry_count;
-
- for (; i < total_rar_filters; i++)
- igb_set_rah_pool(hw, adapter->vfs_allocated_count, i);
-}
-
static int igb_set_vf_mac(struct igb_adapter *adapter,
int vf, unsigned char *mac_addr)
{
diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c
index 2bc9d63027db..926c31b47261 100644
--- a/drivers/net/igbvf/netdev.c
+++ b/drivers/net/igbvf/netdev.c
@@ -149,7 +149,6 @@ static void igbvf_alloc_rx_buffers(struct igbvf_ring *rx_ring,
bufsz = adapter->rx_ps_hdr_size;
else
bufsz = adapter->rx_buffer_len;
- bufsz += NET_IP_ALIGN;
while (cleaned_count--) {
rx_desc = IGBVF_RX_DESC_ADV(*rx_ring, i);
@@ -173,7 +172,7 @@ static void igbvf_alloc_rx_buffers(struct igbvf_ring *rx_ring,
}
if (!buffer_info->skb) {
- skb = netdev_alloc_skb(netdev, bufsz);
+ skb = netdev_alloc_skb(netdev, bufsz + NET_IP_ALIGN);
if (!skb) {
adapter->alloc_rx_buff_failed++;
goto no_buffers;
@@ -286,7 +285,7 @@ static bool igbvf_clean_rx_irq(struct igbvf_adapter *adapter,
if (!skb_shinfo(skb)->nr_frags) {
pci_unmap_single(pdev, buffer_info->dma,
- adapter->rx_ps_hdr_size + NET_IP_ALIGN,
+ adapter->rx_ps_hdr_size,
PCI_DMA_FROMDEVICE);
skb_put(skb, hlen);
}
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index e3cfefab670c..8ec15ab8c8c2 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -1515,7 +1515,7 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irq(&ip->ioc3_lock);
- return 0;
+ return NETDEV_TX_OK;
}
static void ioc3_timeout(struct net_device *dev)
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
index ad1795580028..f0d0cea6e329 100644
--- a/drivers/net/irda/ali-ircc.c
+++ b/drivers/net/irda/ali-ircc.c
@@ -1466,7 +1466,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else
self->new_speed = speed;
}
@@ -1577,7 +1577,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ );
- return 0;
+ return NETDEV_TX_OK;
}
@@ -1966,10 +1966,10 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__ );
- IRDA_ASSERT(dev != NULL, return 0;);
+ IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;);
self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return 0;);
+ IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
iobase = self->io.sir_base;
@@ -1991,7 +1991,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else
self->new_speed = speed;
}
@@ -2015,7 +2015,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ );
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c
index c4361d466597..22baf65e1563 100644
--- a/drivers/net/irda/au1k_ir.c
+++ b/drivers/net/irda/au1k_ir.c
@@ -502,7 +502,7 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
aup->newspeed = 0;
}
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
ptxd = aup->tx_ring[aup->tx_head];
@@ -555,7 +555,7 @@ 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 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
index 9a0346e751ac..e4e905698dc7 100644
--- a/drivers/net/irda/donauboe.c
+++ b/drivers/net/irda/donauboe.c
@@ -981,7 +981,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev)
self = netdev_priv(dev);
- IRDA_ASSERT (self != NULL, return 0; );
+ IRDA_ASSERT (self != NULL, return NETDEV_TX_OK; );
IRDA_DEBUG (1, "%s.tx:%x(%x)%x\n", __func__
,skb->len,self->txpending,INB (OBOE_ENABLEH));
@@ -1021,7 +1021,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev)
{
spin_unlock_irqrestore(&self->spinlock, flags);
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* True packet, go on, but */
/* do not accept anything before change speed execution */
@@ -1036,7 +1036,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev)
toshoboe_setbaud (self);
spin_unlock_irqrestore(&self->spinlock, flags);
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
}
@@ -1143,7 +1143,7 @@ dumpbufs(skb->data,skb->len,'>');
spin_unlock_irqrestore(&self->spinlock, flags);
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*interrupt handler */
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 0c0831c03f64..6a1aa7a40fe2 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -534,7 +534,7 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
}
spin_unlock_irqrestore(&self->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
drop:
/* Drop silently the skb and exit */
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index 45fd9c1eb343..51ca89c9a0ba 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -1365,7 +1365,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return 0;);
+ IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
iobase = self->io.fir_base;
@@ -1397,7 +1397,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else
self->new_speed = speed;
}
@@ -1424,7 +1424,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
@@ -1467,7 +1467,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else {
/* Change speed after current frame */
self->new_speed = speed;
@@ -1554,7 +1554,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c
index 3376a4f39e0a..e76a083f901a 100644
--- a/drivers/net/irda/pxaficp_ir.c
+++ b/drivers/net/irda/pxaficp_ir.c
@@ -504,7 +504,7 @@ static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
pxa_irda_set_speed(si, speed);
}
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
netif_stop_queue(dev);
@@ -539,7 +539,7 @@ static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static int pxa_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index 2aeb2e6aec1b..70e6acc597b0 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -667,7 +667,7 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
sa1100_irda_set_speed(si, speed);
}
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (!IS_FIR(si)) {
@@ -715,7 +715,7 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static int
diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c
index fd0796c3db3c..71dce20e62be 100644
--- a/drivers/net/irda/sir_dev.c
+++ b/drivers/net/irda/sir_dev.c
@@ -590,7 +590,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
int err;
s32 speed;
- IRDA_ASSERT(dev != NULL, return 0;);
+ IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;);
netif_stop_queue(ndev);
@@ -621,7 +621,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
*/
dev_kfree_skb_any(skb);
- return 0;
+ return NETDEV_TX_OK;
} else
dev->new_speed = speed;
}
@@ -668,7 +668,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
}
spin_unlock_irqrestore(&dev->tx_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/* called from network layer with rtnl hold */
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index d0797adb5f8e..15f8a7f81600 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -886,10 +886,10 @@ static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
IRDA_DEBUG(1, "%s\n", __func__);
- IRDA_ASSERT(dev != NULL, return 0;);
+ IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;);
self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return 0;);
+ IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
netif_stop_queue(dev);
@@ -914,7 +914,7 @@ static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
smsc_ircc_change_speed(self, speed);
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
self->new_speed = speed;
}
@@ -935,7 +935,7 @@ static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -1190,9 +1190,9 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
s32 speed;
int mtt;
- IRDA_ASSERT(dev != NULL, return 0;);
+ IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;);
self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return 0;);
+ IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
netif_stop_queue(dev);
@@ -1210,7 +1210,7 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
smsc_ircc_change_speed(self, speed);
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
self->new_speed = speed;
@@ -1242,7 +1242,7 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index 8e5e45caf2f1..c475b23091bc 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -578,7 +578,7 @@ static int stir_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
dev_kfree_skb(skb);
}
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c
index 864798502ff9..36a60748447b 100644
--- a/drivers/net/irda/via-ircc.c
+++ b/drivers/net/irda/via-ircc.c
@@ -832,7 +832,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb,
__u32 speed;
self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return 0;);
+ IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
iobase = self->io.fir_base;
netif_stop_queue(dev);
@@ -844,7 +844,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb,
via_ircc_change_speed(self, speed);
dev->trans_start = jiffies;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else
self->new_speed = speed;
}
@@ -892,7 +892,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb,
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static int via_ircc_hard_xmit_fir(struct sk_buff *skb,
@@ -907,7 +907,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb,
iobase = self->io.fir_base;
if (self->st_fifo.len)
- return 0;
+ return NETDEV_TX_OK;
if (self->chip_id == 0x3076)
iodelay(1500);
else
@@ -919,7 +919,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb,
via_ircc_change_speed(self, speed);
dev->trans_start = jiffies;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else
self->new_speed = speed;
}
@@ -940,7 +940,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb,
dev->trans_start = jiffies;
dev_kfree_skb(skb);
spin_unlock_irqrestore(&self->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
index ac0e4b6b6b66..08e26f1297b4 100644
--- a/drivers/net/irda/vlsi_ir.c
+++ b/drivers/net/irda/vlsi_ir.c
@@ -915,7 +915,7 @@ static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
*/
spin_unlock_irqrestore(&idev->lock, flags);
dev_kfree_skb_any(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* sanity checks - simply drop the packet */
@@ -1044,7 +1044,7 @@ static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
}
spin_unlock_irqrestore(&idev->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
drop_unlock:
spin_unlock_irqrestore(&idev->lock, flags);
@@ -1058,7 +1058,7 @@ drop:
* packet for later retry of transmission - which isn't exactly
* what we want after we've just called dev_kfree_skb_any ;-)
*/
- return 0;
+ return NETDEV_TX_OK;
}
static void vlsi_tx_interrupt(struct net_device *ndev)
diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
index d0883835b0c6..49ef76320f51 100644
--- a/drivers/net/irda/w83977af_ir.c
+++ b/drivers/net/irda/w83977af_ir.c
@@ -516,7 +516,7 @@ static int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev)
w83977af_change_speed(self, speed);
dev->trans_start = jiffies;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else
self->new_speed = speed;
}
@@ -576,7 +576,7 @@ static int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev)
/* Restore set register */
outb(set, iobase+SSR);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c
index d12377b84358..9706e64e367b 100644
--- a/drivers/net/isa-skeleton.c
+++ b/drivers/net/isa-skeleton.c
@@ -468,7 +468,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb (skb);
#endif
- return 0;
+ return NETDEV_TX_OK;
}
#if TX_RING
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index e44215cb1882..e36e951cbc65 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -1205,7 +1205,7 @@ static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev)
if ( ! ((1 << rlp) & port->lpar_map) ) {
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
lpmask = 1 << rlp;
@@ -1217,7 +1217,7 @@ static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* You must hold the connection's lock when you call this function. */
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index 9c897cf86b9f..eb917f160274 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -1459,7 +1459,7 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if (skb->len <= 0) {
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (unlikely(ixgb_maybe_stop_tx(netdev, &adapter->tx_ring,
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
index e11d83d5852b..62b6c028ae81 100644
--- a/drivers/net/ixgbe/ixgbe.h
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -231,10 +231,6 @@ struct ixgbe_q_vector {
#define IXGBE_TX_CTXTDESC_ADV(R, i) \
(&(((struct ixgbe_adv_tx_context_desc *)((R).desc))[i]))
-#define IXGBE_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i]))
-#define IXGBE_TX_DESC(R, i) IXGBE_GET_DESC(R, i, ixgbe_legacy_tx_desc)
-#define IXGBE_RX_DESC(R, i) IXGBE_GET_DESC(R, i, ixgbe_legacy_rx_desc)
-
#define IXGBE_MAX_JUMBO_FRAME_SIZE 16128
#ifdef IXGBE_FCOE
/* Use 3K as the baby jumbo frame size for FCoE */
diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c
index b9923047ce11..ed0bb3b20255 100644
--- a/drivers/net/ixgbe/ixgbe_82598.c
+++ b/drivers/net/ixgbe/ixgbe_82598.c
@@ -269,6 +269,7 @@ static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw)
media_type = ixgbe_media_type_fiber;
break;
case IXGBE_DEV_ID_82598AT:
+ case IXGBE_DEV_ID_82598AT2:
media_type = ixgbe_media_type_copper;
break;
default:
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index 79144e950a34..c6db9a04187d 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -1440,7 +1440,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
goto err_nomem;
}
- tx_ring->size = tx_ring->count * sizeof(struct ixgbe_legacy_tx_desc);
+ 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))) {
@@ -1454,7 +1454,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDBAH(0),
((u64) tx_ring->dma >> 32));
IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDLEN(0),
- tx_ring->count * sizeof(struct ixgbe_legacy_tx_desc));
+ tx_ring->count * sizeof(union ixgbe_adv_tx_desc));
IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDH(0), 0);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDT(0), 0);
@@ -1472,7 +1472,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(&adapter->hw, IXGBE_TXDCTL(0), reg_data);
for (i = 0; i < tx_ring->count; i++) {
- struct ixgbe_legacy_tx_desc *desc = IXGBE_TX_DESC(*tx_ring, i);
+ union ixgbe_adv_tx_desc *desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
struct sk_buff *skb;
unsigned int size = 1024;
@@ -1486,13 +1486,18 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
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);
- desc->buffer_addr = cpu_to_le64(tx_ring->tx_buffer_info[i].dma);
- desc->lower.data = cpu_to_le32(skb->len);
- desc->lower.data |= cpu_to_le32(IXGBE_TXD_CMD_EOP |
- IXGBE_TXD_CMD_IFCS |
- IXGBE_TXD_CMD_RS);
- desc->upper.data = 0;
+ PCI_DMA_TODEVICE);
+ desc->read.buffer_addr =
+ cpu_to_le64(tx_ring->tx_buffer_info[i].dma);
+ desc->read.cmd_type_len = cpu_to_le32(skb->len);
+ desc->read.cmd_type_len |= cpu_to_le32(IXGBE_TXD_CMD_EOP |
+ IXGBE_TXD_CMD_IFCS |
+ IXGBE_TXD_CMD_RS);
+ desc->read.olinfo_status = 0;
+ if (adapter->hw.mac.type == ixgbe_mac_82599EB)
+ desc->read.olinfo_status |=
+ (skb->len << IXGBE_ADVTXD_PAYLEN_SHIFT);
+
}
/* Setup Rx Descriptor ring and Rx buffers */
@@ -1508,7 +1513,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
goto err_nomem;
}
- rx_ring->size = rx_ring->count * sizeof(struct ixgbe_legacy_rx_desc);
+ 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))) {
@@ -1566,8 +1571,8 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, rctl);
for (i = 0; i < rx_ring->count; i++) {
- struct ixgbe_legacy_rx_desc *rx_desc =
- IXGBE_RX_DESC(*rx_ring, i);
+ union ixgbe_adv_rx_desc *rx_desc =
+ IXGBE_RX_DESC_ADV(*rx_ring, i);
struct sk_buff *skb;
skb = alloc_skb(IXGBE_RXBUFFER_2048 + NET_IP_ALIGN, GFP_KERNEL);
@@ -1580,7 +1585,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
rx_ring->rx_buffer_info[i].dma =
pci_map_single(pdev, skb->data, IXGBE_RXBUFFER_2048,
PCI_DMA_FROMDEVICE);
- rx_desc->buffer_addr =
+ rx_desc->read.pkt_addr =
cpu_to_le64(rx_ring->rx_buffer_info[i].dma);
memset(skb->data, 0x00, skb->len);
}
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 110c65ab5cb5..44adc9862826 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -49,7 +49,7 @@ char ixgbe_driver_name[] = "ixgbe";
static const char ixgbe_driver_string[] =
"Intel(R) 10 Gigabit PCI Express Network Driver";
-#define DRV_VERSION "2.0.34-k2"
+#define DRV_VERSION "2.0.37-k2"
const char ixgbe_driver_version[] = DRV_VERSION;
static char ixgbe_copyright[] = "Copyright (c) 1999-2009 Intel Corporation.";
@@ -75,6 +75,8 @@ static struct pci_device_id ixgbe_pci_tbl[] = {
board_82598 },
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT),
board_82598 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT2),
+ board_82598 },
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_CX4),
board_82598 },
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_CX4_DUAL_PORT),
@@ -4658,13 +4660,13 @@ static void ixgbe_watchdog_task(struct work_struct *work)
if (hw->mac.type == ixgbe_mac_82599EB) {
u32 mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN);
u32 fccfg = IXGBE_READ_REG(hw, IXGBE_FCCFG);
- flow_rx = (mflcn & IXGBE_MFLCN_RFCE);
- flow_tx = (fccfg & IXGBE_FCCFG_TFCE_802_3X);
+ flow_rx = !!(mflcn & IXGBE_MFLCN_RFCE);
+ flow_tx = !!(fccfg & IXGBE_FCCFG_TFCE_802_3X);
} else {
u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS);
- flow_rx = (frctl & IXGBE_FCTRL_RFCE);
- flow_tx = (rmcs & IXGBE_RMCS_TFCE_802_3X);
+ flow_rx = !!(frctl & IXGBE_FCTRL_RFCE);
+ flow_tx = !!(rmcs & IXGBE_RMCS_TFCE_802_3X);
}
printk(KERN_INFO "ixgbe: %s NIC Link is Up %s, "
diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h
index fa87309dc087..17ee3890a0a1 100644
--- a/drivers/net/ixgbe/ixgbe_type.h
+++ b/drivers/net/ixgbe/ixgbe_type.h
@@ -42,6 +42,7 @@
#define IXGBE_DEV_ID_82598AF_SINGLE_PORT 0x10C7
#define IXGBE_DEV_ID_82598EB_SFP_LOM 0x10DB
#define IXGBE_DEV_ID_82598AT 0x10C8
+#define IXGBE_DEV_ID_82598AT2 0x150B
#define IXGBE_DEV_ID_82598EB_CX4 0x10DD
#define IXGBE_DEV_ID_82598_CX4_DUAL_PORT 0x10EC
#define IXGBE_DEV_ID_82598_DA_DUAL_PORT 0x10F1
@@ -1893,27 +1894,6 @@ enum ixgbe_fdir_pballoc_type {
#define IXGBE_FDIR_INIT_DONE_POLL 10
#define IXGBE_FDIRCMD_CMD_POLL 10
-/* Transmit Descriptor - Legacy */
-struct ixgbe_legacy_tx_desc {
- u64 buffer_addr; /* Address of the descriptor's data buffer */
- union {
- __le32 data;
- struct {
- __le16 length; /* Data buffer length */
- u8 cso; /* Checksum offset */
- u8 cmd; /* Descriptor control */
- } flags;
- } lower;
- union {
- __le32 data;
- struct {
- u8 status; /* Descriptor status */
- u8 css; /* Checksum start */
- __le16 vlan;
- } fields;
- } upper;
-};
-
/* Transmit Descriptor - Advanced */
union ixgbe_adv_tx_desc {
struct {
@@ -1928,16 +1908,6 @@ union ixgbe_adv_tx_desc {
} wb;
};
-/* Receive Descriptor - Legacy */
-struct ixgbe_legacy_rx_desc {
- __le64 buffer_addr; /* Address of the descriptor's data buffer */
- __le16 length; /* Length of data DMAed into data buffer */
- __le16 csum; /* Packet checksum */
- u8 status; /* Descriptor status */
- u8 errors; /* Descriptor Errors */
- __le16 vlan;
-};
-
/* Receive Descriptor - Advanced */
union ixgbe_adv_rx_desc {
struct {
diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c
index 2a0174b62e96..588b44d944ce 100644
--- a/drivers/net/ixp2000/ixpdev.c
+++ b/drivers/net/ixp2000/ixpdev.c
@@ -45,7 +45,7 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(skb->len > PAGE_SIZE)) {
/* @@@ Count drops. */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
entry = tx_pointer;
@@ -69,7 +69,7 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
local_irq_enable();
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c
index 2f286091394d..ec337b502fd9 100644
--- a/drivers/net/jazzsonic.c
+++ b/drivers/net/jazzsonic.c
@@ -108,7 +108,7 @@ static const struct net_device_ops sonic_netdev_ops = {
.ndo_set_mac_address = eth_mac_addr,
};
-static int __init sonic_probe1(struct net_device *dev)
+static int __devinit sonic_probe1(struct net_device *dev)
{
static unsigned version_printed;
unsigned int silicon_revision;
@@ -211,7 +211,7 @@ out:
* Probe for a SONIC ethernet controller on a Mips Jazz board.
* Actually probing is superfluous but we're paranoid.
*/
-static int __init jazz_sonic_probe(struct platform_device *pdev)
+static int __devinit jazz_sonic_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct sonic_local *lp;
diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index 1e3c63d67b91..e7068c7cd627 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -322,20 +322,6 @@ jme_stop_irq(struct jme_adapter *jme)
jwrite32f(jme, JME_IENC, INTR_ENABLE);
}
-static inline void
-jme_enable_shadow(struct jme_adapter *jme)
-{
- jwrite32(jme,
- JME_SHBA_LO,
- ((u32)jme->shadow_dma & ~((u32)0x1F)) | SHBA_POSTEN);
-}
-
-static inline void
-jme_disable_shadow(struct jme_adapter *jme)
-{
- jwrite32(jme, JME_SHBA_LO, 0x0);
-}
-
static u32
jme_linkstat_from_phy(struct jme_adapter *jme)
{
@@ -522,12 +508,8 @@ jme_setup_tx_resources(struct jme_adapter *jme)
&(txring->dmaalloc),
GFP_ATOMIC);
- if (!txring->alloc) {
- txring->desc = NULL;
- txring->dmaalloc = 0;
- txring->dma = 0;
- return -ENOMEM;
- }
+ if (!txring->alloc)
+ goto err_set_null;
/*
* 16 Bytes align
@@ -539,6 +521,11 @@ jme_setup_tx_resources(struct jme_adapter *jme)
atomic_set(&txring->next_to_clean, 0);
atomic_set(&txring->nr_free, jme->tx_ring_size);
+ txring->bufinf = kmalloc(sizeof(struct jme_buffer_info) *
+ jme->tx_ring_size, GFP_ATOMIC);
+ if (unlikely(!(txring->bufinf)))
+ goto err_free_txring;
+
/*
* Initialize Transmit Descriptors
*/
@@ -547,6 +534,20 @@ jme_setup_tx_resources(struct jme_adapter *jme)
sizeof(struct jme_buffer_info) * jme->tx_ring_size);
return 0;
+
+err_free_txring:
+ dma_free_coherent(&(jme->pdev->dev),
+ TX_RING_ALLOC_SIZE(jme->tx_ring_size),
+ txring->alloc,
+ txring->dmaalloc);
+
+err_set_null:
+ txring->desc = NULL;
+ txring->dmaalloc = 0;
+ txring->dma = 0;
+ txring->bufinf = NULL;
+
+ return -ENOMEM;
}
static void
@@ -554,19 +555,22 @@ jme_free_tx_resources(struct jme_adapter *jme)
{
int i;
struct jme_ring *txring = &(jme->txring[0]);
- struct jme_buffer_info *txbi = txring->bufinf;
+ struct jme_buffer_info *txbi;
if (txring->alloc) {
- for (i = 0 ; i < jme->tx_ring_size ; ++i) {
- txbi = txring->bufinf + i;
- if (txbi->skb) {
- dev_kfree_skb(txbi->skb);
- txbi->skb = NULL;
+ if (txring->bufinf) {
+ for (i = 0 ; i < jme->tx_ring_size ; ++i) {
+ txbi = txring->bufinf + i;
+ if (txbi->skb) {
+ dev_kfree_skb(txbi->skb);
+ txbi->skb = NULL;
+ }
+ txbi->mapping = 0;
+ txbi->len = 0;
+ txbi->nr_desc = 0;
+ txbi->start_xmit = 0;
}
- txbi->mapping = 0;
- txbi->len = 0;
- txbi->nr_desc = 0;
- txbi->start_xmit = 0;
+ kfree(txring->bufinf);
}
dma_free_coherent(&(jme->pdev->dev),
@@ -578,11 +582,11 @@ jme_free_tx_resources(struct jme_adapter *jme)
txring->desc = NULL;
txring->dmaalloc = 0;
txring->dma = 0;
+ txring->bufinf = NULL;
}
txring->next_to_use = 0;
atomic_set(&txring->next_to_clean, 0);
atomic_set(&txring->nr_free, 0);
-
}
static inline void
@@ -653,7 +657,7 @@ jme_disable_tx_engine(struct jme_adapter *jme)
static void
jme_set_clean_rxdesc(struct jme_adapter *jme, int i)
{
- struct jme_ring *rxring = jme->rxring;
+ struct jme_ring *rxring = &(jme->rxring[0]);
register struct rxdesc *rxdesc = rxring->desc;
struct jme_buffer_info *rxbi = rxring->bufinf;
rxdesc += i;
@@ -720,8 +724,11 @@ jme_free_rx_resources(struct jme_adapter *jme)
struct jme_ring *rxring = &(jme->rxring[0]);
if (rxring->alloc) {
- for (i = 0 ; i < jme->rx_ring_size ; ++i)
- jme_free_rx_buf(jme, i);
+ if (rxring->bufinf) {
+ for (i = 0 ; i < jme->rx_ring_size ; ++i)
+ jme_free_rx_buf(jme, i);
+ kfree(rxring->bufinf);
+ }
dma_free_coherent(&(jme->pdev->dev),
RX_RING_ALLOC_SIZE(jme->rx_ring_size),
@@ -731,6 +738,7 @@ jme_free_rx_resources(struct jme_adapter *jme)
rxring->desc = NULL;
rxring->dmaalloc = 0;
rxring->dma = 0;
+ rxring->bufinf = NULL;
}
rxring->next_to_use = 0;
atomic_set(&rxring->next_to_clean, 0);
@@ -746,12 +754,8 @@ jme_setup_rx_resources(struct jme_adapter *jme)
RX_RING_ALLOC_SIZE(jme->rx_ring_size),
&(rxring->dmaalloc),
GFP_ATOMIC);
- if (!rxring->alloc) {
- rxring->desc = NULL;
- rxring->dmaalloc = 0;
- rxring->dma = 0;
- return -ENOMEM;
- }
+ if (!rxring->alloc)
+ goto err_set_null;
/*
* 16 Bytes align
@@ -762,9 +766,16 @@ jme_setup_rx_resources(struct jme_adapter *jme)
rxring->next_to_use = 0;
atomic_set(&rxring->next_to_clean, 0);
+ rxring->bufinf = kmalloc(sizeof(struct jme_buffer_info) *
+ jme->rx_ring_size, GFP_ATOMIC);
+ if (unlikely(!(rxring->bufinf)))
+ goto err_free_rxring;
+
/*
* Initiallize Receive Descriptors
*/
+ memset(rxring->bufinf, 0,
+ sizeof(struct jme_buffer_info) * jme->rx_ring_size);
for (i = 0 ; i < jme->rx_ring_size ; ++i) {
if (unlikely(jme_make_new_rx_buf(jme, i))) {
jme_free_rx_resources(jme);
@@ -775,6 +786,19 @@ jme_setup_rx_resources(struct jme_adapter *jme)
}
return 0;
+
+err_free_rxring:
+ dma_free_coherent(&(jme->pdev->dev),
+ RX_RING_ALLOC_SIZE(jme->rx_ring_size),
+ rxring->alloc,
+ rxring->dmaalloc);
+err_set_null:
+ rxring->desc = NULL;
+ rxring->dmaalloc = 0;
+ rxring->dma = 0;
+ rxring->bufinf = NULL;
+
+ return -ENOMEM;
}
static inline void
@@ -790,9 +814,9 @@ jme_enable_rx_engine(struct jme_adapter *jme)
/*
* Setup RX DMA Bass Address
*/
- jwrite32(jme, JME_RXDBA_LO, (__u64)jme->rxring[0].dma & 0xFFFFFFFFUL);
+ jwrite32(jme, JME_RXDBA_LO, (__u64)(jme->rxring[0].dma) & 0xFFFFFFFFUL);
jwrite32(jme, JME_RXDBA_HI, (__u64)(jme->rxring[0].dma) >> 32);
- jwrite32(jme, JME_RXNDA, (__u64)jme->rxring[0].dma & 0xFFFFFFFFUL);
+ jwrite32(jme, JME_RXNDA, (__u64)(jme->rxring[0].dma) & 0xFFFFFFFFUL);
/*
* Setup RX Descriptor Count
@@ -856,27 +880,27 @@ jme_rxsum_ok(struct jme_adapter *jme, u16 flags)
if (!(flags & (RXWBFLAG_TCPON | RXWBFLAG_UDPON | RXWBFLAG_IPV4)))
return false;
- if (unlikely(!(flags & RXWBFLAG_MF) &&
- (flags & RXWBFLAG_TCPON) && !(flags & RXWBFLAG_TCPCS))) {
- msg_rx_err(jme, "TCP Checksum error.\n");
- goto out_sumerr;
+ if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_TCPON | RXWBFLAG_TCPCS))
+ == RXWBFLAG_TCPON)) {
+ if (flags & RXWBFLAG_IPV4)
+ msg_rx_err(jme, "TCP Checksum error\n");
+ return false;
}
- if (unlikely(!(flags & RXWBFLAG_MF) &&
- (flags & RXWBFLAG_UDPON) && !(flags & RXWBFLAG_UDPCS))) {
- msg_rx_err(jme, "UDP Checksum error.\n");
- goto out_sumerr;
+ if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_UDPON | RXWBFLAG_UDPCS))
+ == RXWBFLAG_UDPON)) {
+ if (flags & RXWBFLAG_IPV4)
+ msg_rx_err(jme, "UDP Checksum error.\n");
+ return false;
}
- if (unlikely((flags & RXWBFLAG_IPV4) && !(flags & RXWBFLAG_IPCS))) {
+ if (unlikely((flags & (RXWBFLAG_IPV4 | RXWBFLAG_IPCS))
+ == RXWBFLAG_IPV4)) {
msg_rx_err(jme, "IPv4 Checksum error.\n");
- goto out_sumerr;
+ return false;
}
return true;
-
-out_sumerr:
- return false;
}
static void
@@ -1296,7 +1320,7 @@ jme_rx_empty_tasklet(unsigned long arg)
static void
jme_wake_queue_if_stopped(struct jme_adapter *jme)
{
- struct jme_ring *txring = jme->txring;
+ struct jme_ring *txring = &(jme->txring[0]);
smp_wmb();
if (unlikely(netif_queue_stopped(jme->dev) &&
@@ -1483,12 +1507,7 @@ jme_msi(int irq, void *dev_id)
struct jme_adapter *jme = netdev_priv(netdev);
u32 intrstat;
- pci_dma_sync_single_for_cpu(jme->pdev,
- jme->shadow_dma,
- sizeof(u32) * SHADOW_REG_NR,
- PCI_DMA_FROMDEVICE);
- intrstat = jme->shadow_regs[SHADOW_IEVE];
- jme->shadow_regs[SHADOW_IEVE] = 0;
+ intrstat = jread32(jme, JME_IEVE);
jme_intr_msi(jme, intrstat);
@@ -1566,6 +1585,7 @@ jme_open(struct net_device *netdev)
jme_clear_pm(jme);
JME_NAPI_ENABLE(jme);
+ tasklet_enable(&jme->linkch_task);
tasklet_enable(&jme->txclean_task);
tasklet_hi_enable(&jme->rxclean_task);
tasklet_hi_enable(&jme->rxempty_task);
@@ -1574,7 +1594,6 @@ jme_open(struct net_device *netdev)
if (rc)
goto err_out;
- jme_enable_shadow(jme);
jme_start_irq(jme);
if (test_bit(JME_FLAG_SSET, &jme->flags))
@@ -1642,15 +1661,14 @@ jme_close(struct net_device *netdev)
netif_carrier_off(netdev);
jme_stop_irq(jme);
- jme_disable_shadow(jme);
jme_free_irq(jme);
JME_NAPI_DISABLE(jme);
- tasklet_kill(&jme->linkch_task);
- tasklet_kill(&jme->txclean_task);
- tasklet_kill(&jme->rxclean_task);
- tasklet_kill(&jme->rxempty_task);
+ tasklet_disable(&jme->linkch_task);
+ tasklet_disable(&jme->txclean_task);
+ tasklet_disable(&jme->rxclean_task);
+ tasklet_disable(&jme->rxempty_task);
jme_reset_ghc_speed(jme);
jme_disable_rx_engine(jme);
@@ -1668,7 +1686,7 @@ static int
jme_alloc_txdesc(struct jme_adapter *jme,
struct sk_buff *skb)
{
- struct jme_ring *txring = jme->txring;
+ struct jme_ring *txring = &(jme->txring[0]);
int idx, nr_alloc, mask = jme->tx_ring_mask;
idx = txring->next_to_use;
@@ -1722,7 +1740,7 @@ jme_fill_tx_map(struct pci_dev *pdev,
static void
jme_map_tx_skb(struct jme_adapter *jme, struct sk_buff *skb, int idx)
{
- struct jme_ring *txring = jme->txring;
+ struct jme_ring *txring = &(jme->txring[0]);
struct txdesc *txdesc = txring->desc, *ctxdesc;
struct jme_buffer_info *txbi = txring->bufinf, *ctxbi;
u8 hidma = jme->dev->features & NETIF_F_HIGHDMA;
@@ -1835,7 +1853,7 @@ jme_tx_vlan(struct sk_buff *skb, __le16 *vlan, u8 *flags)
static int
jme_fill_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx)
{
- struct jme_ring *txring = jme->txring;
+ struct jme_ring *txring = &(jme->txring[0]);
struct txdesc *txdesc;
struct jme_buffer_info *txbi;
u8 flags;
@@ -1883,7 +1901,7 @@ jme_fill_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx)
static void
jme_stop_queue_if_full(struct jme_adapter *jme)
{
- struct jme_ring *txring = jme->txring;
+ struct jme_ring *txring = &(jme->txring[0]);
struct jme_buffer_info *txbi = txring->bufinf;
int idx = atomic_read(&txring->next_to_clean);
@@ -2725,14 +2743,6 @@ jme_init_one(struct pci_dev *pdev,
rc = -ENOMEM;
goto err_out_free_netdev;
}
- jme->shadow_regs = pci_alloc_consistent(pdev,
- sizeof(u32) * SHADOW_REG_NR,
- &(jme->shadow_dma));
- if (!(jme->shadow_regs)) {
- jeprintk(pdev, "Allocating shadow register mapping error.\n");
- rc = -ENOMEM;
- goto err_out_unmap;
- }
if (no_pseudohp) {
apmc = jread32(jme, JME_APMC) & ~JME_APMC_PSEUDO_HP_EN;
@@ -2768,6 +2778,7 @@ jme_init_one(struct pci_dev *pdev,
tasklet_init(&jme->rxempty_task,
&jme_rx_empty_tasklet,
(unsigned long) jme);
+ tasklet_disable_nosync(&jme->linkch_task);
tasklet_disable_nosync(&jme->txclean_task);
tasklet_disable_nosync(&jme->rxclean_task);
tasklet_disable_nosync(&jme->rxempty_task);
@@ -2817,7 +2828,7 @@ jme_init_one(struct pci_dev *pdev,
if (!jme->mii_if.phy_id) {
rc = -EIO;
jeprintk(pdev, "Can not find phy_id.\n");
- goto err_out_free_shadow;
+ goto err_out_unmap;
}
jme->reg_ghc |= GHC_LINK_POLL;
@@ -2846,7 +2857,7 @@ jme_init_one(struct pci_dev *pdev,
if (rc) {
jeprintk(pdev,
"Reload eeprom for reading MAC Address error.\n");
- goto err_out_free_shadow;
+ goto err_out_unmap;
}
jme_load_macaddr(netdev);
@@ -2862,7 +2873,7 @@ jme_init_one(struct pci_dev *pdev,
rc = register_netdev(netdev);
if (rc) {
jeprintk(pdev, "Cannot register net device.\n");
- goto err_out_free_shadow;
+ goto err_out_unmap;
}
msg_probe(jme, "%s%s ver:%x rev:%x macaddr:%pM\n",
@@ -2876,11 +2887,6 @@ jme_init_one(struct pci_dev *pdev,
return 0;
-err_out_free_shadow:
- pci_free_consistent(pdev,
- sizeof(u32) * SHADOW_REG_NR,
- jme->shadow_regs,
- jme->shadow_dma);
err_out_unmap:
iounmap(jme->regs);
err_out_free_netdev:
@@ -2901,10 +2907,6 @@ jme_remove_one(struct pci_dev *pdev)
struct jme_adapter *jme = netdev_priv(netdev);
unregister_netdev(netdev);
- pci_free_consistent(pdev,
- sizeof(u32) * SHADOW_REG_NR,
- jme->shadow_regs,
- jme->shadow_dma);
iounmap(jme->regs);
pci_set_drvdata(pdev, NULL);
free_netdev(netdev);
@@ -2930,8 +2932,6 @@ jme_suspend(struct pci_dev *pdev, pm_message_t state)
tasklet_disable(&jme->rxclean_task);
tasklet_disable(&jme->rxempty_task);
- jme_disable_shadow(jme);
-
if (netif_carrier_ok(netdev)) {
if (test_bit(JME_FLAG_POLL, &jme->flags))
jme_polling_mode(jme);
@@ -2983,7 +2983,6 @@ jme_resume(struct pci_dev *pdev)
else
jme_reset_phy_processor(jme);
- jme_enable_shadow(jme);
jme_start_irq(jme);
netif_device_attach(netdev);
diff --git a/drivers/net/jme.h b/drivers/net/jme.h
index 0996a069ac7b..251abed3817e 100644
--- a/drivers/net/jme.h
+++ b/drivers/net/jme.h
@@ -25,7 +25,7 @@
#define __JME_H_INCLUDED__
#define DRV_NAME "jme"
-#define DRV_VERSION "1.0.4"
+#define DRV_VERSION "1.0.5"
#define PFX DRV_NAME ": "
#define PCI_DEVICE_ID_JMICRON_JMC250 0x0250
@@ -247,7 +247,7 @@ enum jme_txdesc_flags_bits {
};
#define TXDESC_MSS_SHIFT 2
-enum jme_rxdescwb_flags_bits {
+enum jme_txwbdesc_flags_bits {
TXWBFLAG_OWN = 0x80,
TXWBFLAG_INT = 0x40,
TXWBFLAG_TMOUT = 0x20,
@@ -372,7 +372,6 @@ struct jme_buffer_info {
/*
* The structure holding buffer information and ring descriptors all together.
*/
-#define MAX_RING_DESC_NR 1024
struct jme_ring {
void *alloc; /* pointer to allocated memory */
void *desc; /* pointer to ring memory */
@@ -380,7 +379,7 @@ struct jme_ring {
dma_addr_t dma; /* phys address for ring dma */
/* Buffer information corresponding to each descriptor */
- struct jme_buffer_info bufinf[MAX_RING_DESC_NR];
+ struct jme_buffer_info *bufinf;
int next_to_use;
atomic_t next_to_clean;
@@ -411,13 +410,10 @@ struct jme_ring {
/*
* Jmac Adapter Private data
*/
-#define SHADOW_REG_NR 8
struct jme_adapter {
struct pci_dev *pdev;
struct net_device *dev;
void __iomem *regs;
- dma_addr_t shadow_dma;
- u32 *shadow_regs;
struct mii_if_info mii_if;
struct jme_ring rxring[RX_RING_NR];
struct jme_ring txring[TX_RING_NR];
@@ -464,10 +460,6 @@ struct jme_adapter {
DECLARE_NET_DEVICE_STATS
};
-enum shadow_reg_val {
- SHADOW_IEVE = 0,
-};
-
enum jme_flags_bits {
JME_FLAG_MSI = 1,
JME_FLAG_SSET = 2,
@@ -1104,13 +1096,6 @@ enum jme_chipmode_shifts {
};
/*
- * Shadow base address register bits
- */
-enum jme_shadow_base_address_bits {
- SHBA_POSTEN = 0x1,
-};
-
-/*
* Aggressive Power Mode Control
*/
enum jme_apmc_bits {
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index 633808d447be..30fd4f5f1d5a 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -1016,7 +1016,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
out:
spin_unlock_irqrestore(&lp->devlock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/* The LANCE interrupt handler. */
diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c
index 070fa4500871..51e11c3e53e1 100644
--- a/drivers/net/lib82596.c
+++ b/drivers/net/lib82596.c
@@ -983,7 +983,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
@@ -1028,7 +1028,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_start_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
static void print_eth(unsigned char *add, char *str)
diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c
index f28c23343009..d6be36000c5c 100644
--- a/drivers/net/lib8390.c
+++ b/drivers/net/lib8390.c
@@ -414,7 +414,7 @@ static int __ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb (skb);
dev->stats.tx_bytes += send_length;
- return 0;
+ return NETDEV_TX_OK;
}
/**
diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c
index 96e7248876c1..da8d0a0ca94f 100644
--- a/drivers/net/ll_temac_main.c
+++ b/drivers/net/ll_temac_main.c
@@ -591,7 +591,7 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
/* Kick off the transfer */
temac_dma_out32(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index da472c687481..51bbce72bede 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -89,7 +89,7 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
} else
lb_stats->drops++;
- return 0;
+ return NETDEV_TX_OK;
}
static struct net_device_stats *loopback_get_stats(struct net_device *dev)
diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c
index d44bddbee373..c292bad411ee 100644
--- a/drivers/net/lp486e.c
+++ b/drivers/net/lp486e.c
@@ -871,7 +871,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
@@ -906,7 +906,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
dev->stats.tx_packets++;
}
- return 0;
+ return NETDEV_TX_OK;
}
static void
diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c
index dab45339d3a8..149e0ed4a055 100644
--- a/drivers/net/mac89x0.c
+++ b/drivers/net/mac89x0.c
@@ -411,7 +411,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* The typical workload of the driver:
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 5b5c25368d1e..d22952c78f13 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -678,7 +678,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static void macb_free_consistent(struct macb *bp)
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
index 1427755c224d..7d7577b598ea 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -581,7 +581,7 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
spin_unlock_irqrestore(&mp->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
static void mace_set_multicast(struct net_device *dev)
diff --git a/drivers/net/meth.c b/drivers/net/meth.c
index 5d04d94f2a21..92ceb689b4d4 100644
--- a/drivers/net/meth.c
+++ b/drivers/net/meth.c
@@ -715,7 +715,7 @@ static int meth_tx(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&priv->meth_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -784,7 +784,7 @@ static const struct net_device_ops meth_netdev_ops = {
/*
* The init function.
*/
-static int __init meth_probe(struct platform_device *pdev)
+static int __devinit meth_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct meth_private *priv;
diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c
index b3b9a147d09a..8ea98bd89ff1 100644
--- a/drivers/net/mipsnet.c
+++ b/drivers/net/mipsnet.c
@@ -141,7 +141,7 @@ static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
mipsnet_put_todevice(dev, skb);
- return 0;
+ return NETDEV_TX_OK;
}
static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t len)
diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c
index 08c43f2ae72b..d5c18c674255 100644
--- a/drivers/net/mlx4/en_tx.c
+++ b/drivers/net/mlx4/en_tx.c
@@ -764,7 +764,7 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
/* Poll CQ here */
mlx4_en_xmit_poll(priv, tx_ind);
- return 0;
+ return NETDEV_TX_OK;
tx_drop:
dev_kfree_skb_any(skb);
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 1f6e36ea669e..1a34f7e11d98 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -2748,7 +2748,7 @@ again:
/* The packet is gone, so we must
* return 0 */
ss->stats.tx_dropped += 1;
- return 0;
+ return NETDEV_TX_OK;
}
/* adjust the len to account for the zero pad
* so that the nic can know how long it is */
@@ -2892,7 +2892,7 @@ again:
tx->stop_queue++;
netif_tx_stop_queue(netdev_queue);
}
- return 0;
+ return NETDEV_TX_OK;
abort_linearize:
/* Free any DMA resources we've alloced and clear out the skb
@@ -2936,7 +2936,7 @@ abort_linearize:
drop:
dev_kfree_skb_any(skb);
ss->stats.tx_dropped += 1;
- return 0;
+ return NETDEV_TX_OK;
}
@@ -2968,13 +2968,13 @@ static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev)
}
}
dev_kfree_skb_any(skb);
- return 0;
+ return NETDEV_TX_OK;
drop:
ss = &mgp->ss[skb_get_queue_mapping(skb)];
dev_kfree_skb_any(skb);
ss->stats.tx_dropped += 1;
- return 0;
+ return NETDEV_TX_OK;
}
static struct net_device_stats *myri10ge_get_stats(struct net_device *dev)
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 5f0758bda6b3..29ebebc6a95b 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -692,7 +692,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev)
DTX(("tbusy=0, returning 0\n"));
netif_start_queue(dev);
spin_unlock_irqrestore(&mp->irq_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/* Create the MyriNet MAC header for an arbitrary protocol layer
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index c9bfe4eea189..481aa2d287a3 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -2125,7 +2125,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
dev->name, np->cur_tx, entry);
}
- return 0;
+ return NETDEV_TX_OK;
}
static void netdev_tx_done(struct net_device *dev)
diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c
index 946366dcc992..9f4235466d59 100644
--- a/drivers/net/netx-eth.c
+++ b/drivers/net/netx-eth.c
@@ -134,7 +134,7 @@ netx_eth_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
spin_unlock_irq(&priv->lock);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void netx_eth_receive(struct net_device *ndev)
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index f86e05047d19..e22d08615893 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -57,8 +57,8 @@
#define _NETXEN_NIC_LINUX_MAJOR 4
#define _NETXEN_NIC_LINUX_MINOR 0
-#define _NETXEN_NIC_LINUX_SUBVERSION 30
-#define NETXEN_NIC_LINUX_VERSIONID "4.0.30"
+#define _NETXEN_NIC_LINUX_SUBVERSION 41
+#define NETXEN_NIC_LINUX_VERSIONID "4.0.41"
#define NETXEN_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c))
#define _major(v) (((v) >> 24) & 0xff)
@@ -143,18 +143,13 @@
#define NX_ETHERMTU 1500
#define NX_MAX_ETHERHDR 32 /* This contains some padding */
-#define NX_RX_NORMAL_BUF_MAX_LEN (NX_MAX_ETHERHDR + NX_ETHERMTU)
+#define NX_P2_RX_BUF_MAX_LEN 1760
+#define NX_P3_RX_BUF_MAX_LEN (NX_MAX_ETHERHDR + NX_ETHERMTU)
#define NX_P2_RX_JUMBO_BUF_MAX_LEN (NX_MAX_ETHERHDR + P2_MAX_MTU)
#define NX_P3_RX_JUMBO_BUF_MAX_LEN (NX_MAX_ETHERHDR + P3_MAX_MTU)
#define NX_CT_DEFAULT_RX_BUF_LEN 2048
-#define MAX_RX_BUFFER_LENGTH 1760
-#define MAX_RX_JUMBO_BUFFER_LENGTH 8062
-#define MAX_RX_LRO_BUFFER_LENGTH (8062)
-#define RX_DMA_MAP_LEN (MAX_RX_BUFFER_LENGTH - 2)
-#define RX_JUMBO_DMA_MAP_LEN \
- (MAX_RX_JUMBO_BUFFER_LENGTH - 2)
-#define RX_LRO_DMA_MAP_LEN (MAX_RX_LRO_BUFFER_LENGTH - 2)
+#define NX_RX_LRO_BUFFER_LENGTH (8060)
/*
* Maximum number of ring contexts
@@ -200,13 +195,20 @@
#define RCV_RING_JUMBO 1
#define RCV_RING_LRO 2
-#define MAX_CMD_DESCRIPTORS 4096
-#define MAX_RCV_DESCRIPTORS 16384
-#define MAX_CMD_DESCRIPTORS_HOST 1024
-#define MAX_RCV_DESCRIPTORS_1G 2048
-#define MAX_RCV_DESCRIPTORS_10G 4096
-#define MAX_JUMBO_RCV_DESCRIPTORS 1024
+#define MIN_CMD_DESCRIPTORS 64
+#define MIN_RCV_DESCRIPTORS 64
+#define MIN_JUMBO_DESCRIPTORS 32
+
+#define MAX_CMD_DESCRIPTORS 1024
+#define MAX_RCV_DESCRIPTORS_1G 4096
+#define MAX_RCV_DESCRIPTORS_10G 8192
+#define MAX_JUMBO_RCV_DESCRIPTORS_1G 512
+#define MAX_JUMBO_RCV_DESCRIPTORS_10G 1024
#define MAX_LRO_RCV_DESCRIPTORS 8
+
+#define DEFAULT_RCV_DESCRIPTORS_1G 2048
+#define DEFAULT_RCV_DESCRIPTORS_10G 4096
+
#define NETXEN_CTX_SIGNATURE 0xdee0
#define NETXEN_CTX_SIGNATURE_V2 0x0002dee0
#define NETXEN_CTX_RESET 0xbad0
@@ -302,6 +304,10 @@ struct netxen_ring_ctx {
#define FLAGS_IPSEC_SA_ADD 0x04
#define FLAGS_IPSEC_SA_DELETE 0x08
#define FLAGS_VLAN_TAGGED 0x10
+#define FLAGS_VLAN_OOB 0x40
+
+#define netxen_set_tx_vlan_tci(cmd_desc, v) \
+ (cmd_desc)->vlan_TCI = cpu_to_le16(v);
#define netxen_set_cmd_desc_port(cmd_desc, var) \
((cmd_desc)->port_ctxid |= ((var) & 0x0F))
@@ -316,58 +322,33 @@ struct netxen_ring_ctx {
cpu_to_le16(((_flags) & 0x7f) | (((_opcode) & 0x3f) << 7))
#define netxen_set_tx_frags_len(_desc, _frags, _len) \
- (_desc)->num_of_buffers_total_length = \
+ (_desc)->nfrags__length = \
cpu_to_le32(((_frags) & 0xff) | (((_len) & 0xffffff) << 8))
struct cmd_desc_type0 {
u8 tcp_hdr_offset; /* For LSO only */
u8 ip_hdr_offset; /* For LSO only */
- /* Bit pattern: 0-6 flags, 7-12 opcode, 13-15 unused */
- __le16 flags_opcode;
- /* Bit pattern: 0-7 total number of segments,
- 8-31 Total size of the packet */
- __le32 num_of_buffers_total_length;
- union {
- struct {
- __le32 addr_low_part2;
- __le32 addr_high_part2;
- };
- __le64 addr_buffer2;
- };
+ __le16 flags_opcode; /* 15:13 unused, 12:7 opcode, 6:0 flags */
+ __le32 nfrags__length; /* 31:8 total len, 7:0 frag count */
+
+ __le64 addr_buffer2;
- __le16 reference_handle; /* changed to u16 to add mss */
- __le16 mss; /* passed by NDIS_PACKET for LSO */
- /* Bit pattern 0-3 port, 0-3 ctx id */
- u8 port_ctxid;
+ __le16 reference_handle;
+ __le16 mss;
+ u8 port_ctxid; /* 7:4 ctxid 3:0 port */
u8 total_hdr_length; /* LSO only : MAC+IP+TCP Hdr size */
__le16 conn_id; /* IPSec offoad only */
- union {
- struct {
- __le32 addr_low_part3;
- __le32 addr_high_part3;
- };
- __le64 addr_buffer3;
- };
- union {
- struct {
- __le32 addr_low_part1;
- __le32 addr_high_part1;
- };
- __le64 addr_buffer1;
- };
+ __le64 addr_buffer3;
+ __le64 addr_buffer1;
__le16 buffer_length[4];
- union {
- struct {
- __le32 addr_low_part4;
- __le32 addr_high_part4;
- };
- __le64 addr_buffer4;
- };
+ __le64 addr_buffer4;
- __le64 unused;
+ __le16 vlan_TCI;
+ __le16 reserved;
+ __le32 reserved2;
} __attribute__ ((aligned(64)));
@@ -380,6 +361,7 @@ struct rcv_desc {
};
/* opcode field in status_desc */
+#define NETXEN_NIC_SYN_OFFLOAD 0x03
#define NETXEN_NIC_RXPKT_DESC 0x04
#define NETXEN_OLD_RXPKT_DESC 0x3f
#define NETXEN_NIC_RESPONSE_DESC 0x05
@@ -1078,6 +1060,9 @@ typedef struct {
#define NX_MAC_EVENT 0x1
+#define NX_IP_UP 2
+#define NX_IP_DOWN 3
+
/*
* Driver --> Firmware
*/
@@ -1132,6 +1117,9 @@ typedef struct {
#define NX_FW_CAPABILITY_LINK_NOTIFICATION (1 << 5)
#define NX_FW_CAPABILITY_SWITCHING (1 << 6)
+#define NX_FW_CAPABILITY_PEXQ (1 << 7)
+#define NX_FW_CAPABILITY_BDG (1 << 8)
+#define NX_FW_CAPABILITY_FVLANTX (1 << 9)
/* module types */
#define LINKEVENT_MODULE_NOT_PRESENT 1
@@ -1315,29 +1303,11 @@ struct netxen_adapter {
nx_nic_intr_coalesce_t coal;
- u32 fw_major;
+ u32 resv5;
u32 fw_version;
const struct firmware *fw;
};
-/*
- * NetXen dma watchdog control structure
- *
- * Bit 0 : enabled => R/O: 1 watchdog active, 0 inactive
- * Bit 1 : disable_request => 1 req disable dma watchdog
- * Bit 2 : enable_request => 1 req enable dma watchdog
- * Bit 3-31 : unused
- */
-
-#define netxen_set_dma_watchdog_disable_req(config_word) \
- _netxen_set_bits(config_word, 1, 1, 1)
-#define netxen_set_dma_watchdog_enable_req(config_word) \
- _netxen_set_bits(config_word, 2, 1, 1)
-#define netxen_get_dma_watchdog_enabled(config_word) \
- ((config_word) & 0x1)
-#define netxen_get_dma_watchdog_disabled(config_word) \
- (((config_word) >> 1) & 0x1)
-
int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter);
int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter);
int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter);
@@ -1398,8 +1368,9 @@ unsigned long netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter,
unsigned long long addr);
/* Functions from netxen_nic_init.c */
-void netxen_free_adapter_offload(struct netxen_adapter *adapter);
-int netxen_initialize_adapter_offload(struct netxen_adapter *adapter);
+int netxen_init_dummy_dma(struct netxen_adapter *adapter);
+void netxen_free_dummy_dma(struct netxen_adapter *adapter);
+
int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val);
int netxen_load_firmware(struct netxen_adapter *adapter);
int netxen_need_fw_reset(struct netxen_adapter *adapter);
@@ -1443,6 +1414,7 @@ void netxen_p3_free_mac_list(struct netxen_adapter *adapter);
int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32);
int netxen_config_intr_coalesce(struct netxen_adapter *adapter);
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);
@@ -1455,6 +1427,9 @@ struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev);
void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter,
struct nx_host_tx_ring *tx_ring);
+/* Functions from netxen_nic_main.c */
+int netxen_nic_reset_context(struct netxen_adapter *);
+
/*
* NetXen Board information
*/
@@ -1505,56 +1480,6 @@ static inline void get_brd_name_by_type(u32 type, char *name)
name = "Unknown";
}
-static inline int
-dma_watchdog_shutdown_request(struct netxen_adapter *adapter)
-{
- u32 ctrl;
-
- /* check if already inactive */
- ctrl = adapter->hw_read_wx(adapter,
- NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL));
-
- if (netxen_get_dma_watchdog_enabled(ctrl) == 0)
- return 1;
-
- /* Send the disable request */
- netxen_set_dma_watchdog_disable_req(ctrl);
- NXWR32(adapter, NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), ctrl);
-
- return 0;
-}
-
-static inline int
-dma_watchdog_shutdown_poll_result(struct netxen_adapter *adapter)
-{
- u32 ctrl;
-
- ctrl = adapter->hw_read_wx(adapter,
- NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL));
-
- return (netxen_get_dma_watchdog_enabled(ctrl) == 0);
-}
-
-static inline int
-dma_watchdog_wakeup(struct netxen_adapter *adapter)
-{
- u32 ctrl;
-
- ctrl = adapter->hw_read_wx(adapter,
- NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL));
-
- if (netxen_get_dma_watchdog_enabled(ctrl))
- return 1;
-
- /* send the wakeup request */
- netxen_set_dma_watchdog_enable_req(ctrl);
-
- NXWR32(adapter, NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), ctrl);
-
- return 0;
-}
-
-
static inline u32 netxen_tx_avail(struct nx_host_tx_ring *tx_ring)
{
smp_mb();
diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c
index 9f8ae4719e2f..9e0469643d34 100644
--- a/drivers/net/netxen/netxen_nic_ctx.c
+++ b/drivers/net/netxen/netxen_nic_ctx.c
@@ -647,7 +647,7 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter)
}
rds_ring->desc_head = (struct rcv_desc *)addr;
- if (adapter->fw_major < 4)
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
rds_ring->crb_rcv_producer =
recv_crb_registers[port].crb_rcv_producer[ring];
}
@@ -675,7 +675,7 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter)
}
- if (adapter->fw_major >= 4) {
+ if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
err = nx_fw_cmd_create_rx_ctx(adapter);
if (err)
goto err_out_free;
@@ -705,7 +705,7 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter)
int port = adapter->portnum;
- if (adapter->fw_major >= 4) {
+ if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
nx_fw_cmd_destroy_rx_ctx(adapter);
nx_fw_cmd_destroy_tx_ctx(adapter);
} else {
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index e16ea46c24b8..39a308c363c7 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -490,28 +490,86 @@ netxen_nic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
}
static void
-netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
+netxen_nic_get_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *ring)
{
struct netxen_adapter *adapter = netdev_priv(dev);
- ring->rx_pending = 0;
- ring->rx_jumbo_pending = 0;
- ring->rx_pending += adapter->recv_ctx.
- rds_rings[RCV_RING_NORMAL].num_desc;
- ring->rx_jumbo_pending += adapter->recv_ctx.
- rds_rings[RCV_RING_JUMBO].num_desc;
+ 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 == NETXEN_NIC_GBE)
+ if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
ring->rx_max_pending = MAX_RCV_DESCRIPTORS_1G;
- else
+ ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+ } else {
ring->rx_max_pending = MAX_RCV_DESCRIPTORS_10G;
- ring->tx_max_pending = MAX_CMD_DESCRIPTORS_HOST;
- ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS;
+ ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+ }
+
+ ring->tx_max_pending = MAX_CMD_DESCRIPTORS;
+
ring->rx_mini_max_pending = 0;
ring->rx_mini_pending = 0;
}
+static u32
+netxen_validate_ringparam(u32 val, u32 min, u32 max, char *r_name)
+{
+ u32 num_desc;
+ num_desc = max(val, min);
+ num_desc = min(num_desc, max);
+ num_desc = roundup_pow_of_two(num_desc);
+
+ if (val != num_desc) {
+ printk(KERN_INFO "%s: setting %s ring size %d instead of %d\n",
+ netxen_nic_driver_name, r_name, num_desc, val);
+ }
+
+ return num_desc;
+}
+
+static int
+netxen_nic_set_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *ring)
+{
+ struct netxen_adapter *adapter = netdev_priv(dev);
+ u16 max_rcv_desc = MAX_RCV_DESCRIPTORS_10G;
+ u16 max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+ u16 num_rxd, num_jumbo_rxd, num_txd;
+
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
+ return -EOPNOTSUPP;
+
+ if (ring->rx_mini_pending)
+ return -EOPNOTSUPP;
+
+ if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
+ max_rcv_desc = MAX_RCV_DESCRIPTORS_1G;
+ max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+ }
+
+ num_rxd = netxen_validate_ringparam(ring->rx_pending,
+ MIN_RCV_DESCRIPTORS, max_rcv_desc, "rx");
+
+ num_jumbo_rxd = netxen_validate_ringparam(ring->rx_jumbo_pending,
+ MIN_JUMBO_DESCRIPTORS, max_jumbo_desc, "rx jumbo");
+
+ num_txd = netxen_validate_ringparam(ring->tx_pending,
+ MIN_CMD_DESCRIPTORS, MAX_CMD_DESCRIPTORS, "tx");
+
+ if (num_rxd == adapter->num_rxd && num_txd == adapter->num_txd &&
+ num_jumbo_rxd == adapter->num_jumbo_rxd)
+ return 0;
+
+ adapter->num_rxd = num_rxd;
+ adapter->num_jumbo_rxd = num_jumbo_rxd;
+ adapter->num_txd = num_txd;
+
+ return netxen_nic_reset_context(adapter);
+}
+
static void
netxen_nic_get_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *pause)
@@ -893,6 +951,7 @@ struct ethtool_ops netxen_nic_ethtool_ops = {
.get_eeprom_len = netxen_nic_get_eeprom_len,
.get_eeprom = netxen_nic_get_eeprom,
.get_ringparam = netxen_nic_get_ringparam,
+ .set_ringparam = netxen_nic_set_ringparam,
.get_pauseparam = netxen_nic_get_pauseparam,
.set_pauseparam = netxen_nic_set_pauseparam,
.set_tx_csum = ethtool_op_set_tx_csum,
diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h
index 824103675648..a7328584a21a 100644
--- a/drivers/net/netxen/netxen_nic_hdr.h
+++ b/drivers/net/netxen/netxen_nic_hdr.h
@@ -852,7 +852,7 @@ enum {
#define NX_PEG_TUNE_MN_PRESENT 0x1
#define NX_PEG_TUNE_CAPABILITY (NETXEN_CAM_RAM(0x02c))
-#define NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL (0x14)
+#define NETXEN_DMA_WATCHDOG_CTRL (NETXEN_CAM_RAM(0x14))
#define NETXEN_PEG_ALIVE_COUNTER (NETXEN_CAM_RAM(0xb0))
#define ISR_MSI_INT_TRIGGER(FUNC) (NETXEN_PCIX_PS_REG(PCIX_MSI_F(FUNC)))
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index b9123d445c96..ddb9deb12b33 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -706,6 +706,30 @@ int netxen_config_rss(struct netxen_adapter *adapter, int enable)
return rv;
}
+int netxen_config_ipaddr(struct netxen_adapter *adapter, u32 ip, int cmd)
+{
+ nx_nic_req_t req;
+ u64 word;
+ int rv;
+
+ memset(&req, 0, sizeof(nx_nic_req_t));
+ req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23);
+
+ word = NX_NIC_H2C_OPCODE_CONFIG_IPADDR | ((u64)adapter->portnum << 16);
+ req.req_hdr = cpu_to_le64(word);
+
+ req.words[0] = cpu_to_le64(cmd);
+ req.words[1] = cpu_to_le64(ip);
+
+ rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+ if (rv != 0) {
+ printk(KERN_ERR "%s: could not notify %s IP 0x%x reuqest\n",
+ adapter->netdev->name,
+ (cmd == NX_IP_UP) ? "Add" : "Remove", ip);
+ }
+ return rv;
+}
+
int netxen_linkevent_request(struct netxen_adapter *adapter, int enable)
{
nx_nic_req_t req;
@@ -2021,7 +2045,6 @@ void netxen_nic_get_firmware_info(struct netxen_adapter *adapter)
fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR);
fw_build = NXRD32(adapter, NETXEN_FW_VERSION_SUB);
- adapter->fw_major = fw_major;
adapter->fw_version = NETXEN_VERSION_CODE(fw_major, fw_minor, fw_build);
if (adapter->portnum == 0) {
@@ -2047,6 +2070,9 @@ void netxen_nic_get_firmware_info(struct netxen_adapter *adapter)
dev_info(&pdev->dev, "firmware running in %s mode\n",
adapter->ahw.cut_through ? "cut-through" : "legacy");
}
+
+ if (adapter->fw_version >= NETXEN_VERSION_CODE(4, 0, 222))
+ adapter->capabilities = NXRD32(adapter, CRB_FW_CAPABILITIES_1);
}
int
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index 7acf204e38c9..81253abbfa34 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -254,9 +254,14 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter)
rds_ring->skb_size =
NX_CT_DEFAULT_RX_BUF_LEN;
} else {
- rds_ring->dma_size = RX_DMA_MAP_LEN;
+ if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
+ rds_ring->dma_size =
+ NX_P3_RX_BUF_MAX_LEN;
+ else
+ rds_ring->dma_size =
+ NX_P2_RX_BUF_MAX_LEN;
rds_ring->skb_size =
- MAX_RX_BUFFER_LENGTH;
+ rds_ring->dma_size + NET_IP_ALIGN;
}
break;
@@ -274,8 +279,8 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter)
case RCV_RING_LRO:
rds_ring->num_desc = adapter->num_lro_rxd;
- rds_ring->dma_size = RX_LRO_DMA_MAP_LEN;
- rds_ring->skb_size = MAX_RX_LRO_BUFFER_LENGTH;
+ rds_ring->dma_size = NX_RX_LRO_BUFFER_LENGTH;
+ rds_ring->skb_size = rds_ring->dma_size + NET_IP_ALIGN;
break;
}
@@ -887,22 +892,10 @@ netxen_validate_firmware(struct netxen_adapter *adapter, const char *fwname)
return 0;
}
-void netxen_request_firmware(struct netxen_adapter *adapter)
+static int
+netxen_p3_has_mn(struct netxen_adapter *adapter)
{
u32 capability, flashed_ver;
- u8 fw_type;
- struct pci_dev *pdev = adapter->pdev;
- int rc = 0;
-
- if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
- fw_type = NX_P2_MN_ROMIMAGE;
- goto request_fw;
- } else {
- fw_type = NX_P3_CT_ROMIMAGE;
- goto request_fw;
- }
-
-request_mn:
capability = 0;
netxen_rom_fast_read(adapter,
@@ -910,23 +903,35 @@ request_mn:
flashed_ver = NETXEN_DECODE_VERSION(flashed_ver);
if (flashed_ver >= NETXEN_VERSION_CODE(4, 0, 220)) {
+
capability = NXRD32(adapter, NX_PEG_TUNE_CAPABILITY);
- if (capability & NX_PEG_TUNE_MN_PRESENT) {
- fw_type = NX_P3_MN_ROMIMAGE;
- goto request_fw;
- }
+ if (capability & NX_PEG_TUNE_MN_PRESENT)
+ return 1;
}
+ return 0;
+}
- fw_type = NX_FLASH_ROMIMAGE;
- adapter->fw = NULL;
- goto done;
+void netxen_request_firmware(struct netxen_adapter *adapter)
+{
+ u8 fw_type;
+ struct pci_dev *pdev = adapter->pdev;
+ int rc = 0;
+
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
+ fw_type = NX_P2_MN_ROMIMAGE;
+ goto request_fw;
+ }
+
+ fw_type = netxen_p3_has_mn(adapter) ?
+ NX_P3_MN_ROMIMAGE : NX_P3_CT_ROMIMAGE;
request_fw:
rc = request_firmware(&adapter->fw, fw_name[fw_type], &pdev->dev);
if (rc != 0) {
- if (fw_type == NX_P3_CT_ROMIMAGE) {
+ if (fw_type == NX_P3_MN_ROMIMAGE) {
msleep(1);
- goto request_mn;
+ fw_type = NX_P3_CT_ROMIMAGE;
+ goto request_fw;
}
fw_type = NX_FLASH_ROMIMAGE;
@@ -938,9 +943,10 @@ request_fw:
if (rc != 0) {
release_firmware(adapter->fw);
- if (fw_type == NX_P3_CT_ROMIMAGE) {
+ if (fw_type == NX_P3_MN_ROMIMAGE) {
msleep(1);
- goto request_mn;
+ fw_type = NX_P3_CT_ROMIMAGE;
+ goto request_fw;
}
fw_type = NX_FLASH_ROMIMAGE;
@@ -960,19 +966,20 @@ netxen_release_firmware(struct netxen_adapter *adapter)
release_firmware(adapter->fw);
}
-int netxen_initialize_adapter_offload(struct netxen_adapter *adapter)
+int netxen_init_dummy_dma(struct netxen_adapter *adapter)
{
- uint64_t addr;
- uint32_t hi;
- uint32_t lo;
+ u64 addr;
+ u32 hi, lo;
+
+ if (!NX_IS_REVISION_P2(adapter->ahw.revision_id))
+ return 0;
- adapter->dummy_dma.addr =
- pci_alloc_consistent(adapter->pdev,
+ adapter->dummy_dma.addr = pci_alloc_consistent(adapter->pdev,
NETXEN_HOST_DUMMY_DMA_SIZE,
&adapter->dummy_dma.phys_addr);
if (adapter->dummy_dma.addr == NULL) {
- printk("%s: ERROR: Could not allocate dummy DMA memory\n",
- __func__);
+ dev_err(&adapter->pdev->dev,
+ "ERROR: Could not allocate dummy DMA memory\n");
return -ENOMEM;
}
@@ -983,29 +990,41 @@ int netxen_initialize_adapter_offload(struct netxen_adapter *adapter)
NXWR32(adapter, CRB_HOST_DUMMY_BUF_ADDR_HI, hi);
NXWR32(adapter, CRB_HOST_DUMMY_BUF_ADDR_LO, lo);
- if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
- uint32_t temp = 0;
- NXWR32(adapter, CRB_HOST_DUMMY_BUF, temp);
- }
-
return 0;
}
-void netxen_free_adapter_offload(struct netxen_adapter *adapter)
+/*
+ * NetXen DMA watchdog control:
+ *
+ * Bit 0 : enabled => R/O: 1 watchdog active, 0 inactive
+ * Bit 1 : disable_request => 1 req disable dma watchdog
+ * Bit 2 : enable_request => 1 req enable dma watchdog
+ * Bit 3-31 : unused
+ */
+void netxen_free_dummy_dma(struct netxen_adapter *adapter)
{
int i = 100;
+ u32 ctrl;
+
+ if (!NX_IS_REVISION_P2(adapter->ahw.revision_id))
+ return;
if (!adapter->dummy_dma.addr)
return;
- if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
- do {
- if (dma_watchdog_shutdown_request(adapter) == 1)
- break;
+ ctrl = NXRD32(adapter, NETXEN_DMA_WATCHDOG_CTRL);
+ if ((ctrl & 0x1) != 0) {
+ NXWR32(adapter, NETXEN_DMA_WATCHDOG_CTRL, (ctrl | 0x2));
+
+ while ((ctrl & 0x1) != 0) {
+
msleep(50);
- if (dma_watchdog_shutdown_poll_result(adapter) == 1)
+
+ ctrl = NXRD32(adapter, NETXEN_DMA_WATCHDOG_CTRL);
+
+ if (--i == 0)
break;
- } while (--i);
+ };
}
if (i) {
@@ -1014,10 +1033,8 @@ void netxen_free_adapter_offload(struct netxen_adapter *adapter)
adapter->dummy_dma.addr,
adapter->dummy_dma.phys_addr);
adapter->dummy_dma.addr = NULL;
- } else {
- printk(KERN_ERR "%s: dma_watchdog_shutdown failed\n",
- adapter->netdev->name);
- }
+ } else
+ dev_err(&adapter->pdev->dev, "dma_watchdog_shutdown failed\n");
}
int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val)
@@ -1090,10 +1107,6 @@ int netxen_init_firmware(struct netxen_adapter *adapter)
NXWR32(adapter, CRB_MPORT_MODE, MPORT_MULTI_FUNCTION_MODE);
NXWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK);
- if (adapter->fw_version >= NETXEN_VERSION_CODE(4, 0, 222)) {
- adapter->capabilities = NXRD32(adapter, CRB_FW_CAPABILITIES_1);
- }
-
return err;
}
@@ -1303,6 +1316,7 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max)
switch (opcode) {
case NETXEN_NIC_RXPKT_DESC:
case NETXEN_OLD_RXPKT_DESC:
+ case NETXEN_NIC_SYN_OFFLOAD:
break;
case NETXEN_NIC_RESPONSE_DESC:
netxen_handle_fw_message(desc_cnt, consumer, sds_ring);
@@ -1475,7 +1489,7 @@ netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid,
NXWR32(adapter, rds_ring->crb_rcv_producer,
(producer-1) & (rds_ring->num_desc-1));
- if (adapter->fw_major < 4) {
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
/*
* Write a doorbell msg to tell phanmon of change in
* receive ring producer
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 637ac8b89bac..40549a0e9ff0 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -39,6 +39,7 @@
#include <linux/if_vlan.h>
#include <net/ip.h>
#include <linux/ipv6.h>
+#include <linux/inetdevice.h>
MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver");
MODULE_LICENSE("GPL");
@@ -65,7 +66,7 @@ static int netxen_nic_open(struct net_device *netdev);
static int netxen_nic_close(struct net_device *netdev);
static int netxen_nic_xmit_frame(struct sk_buff *, struct net_device *);
static void netxen_tx_timeout(struct net_device *netdev);
-static void netxen_tx_timeout_task(struct work_struct *work);
+static void netxen_reset_task(struct work_struct *work);
static void netxen_watchdog(unsigned long);
static int netxen_nic_poll(struct napi_struct *napi, int budget);
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -181,7 +182,7 @@ netxen_napi_add(struct netxen_adapter *adapter, struct net_device *netdev)
struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
if (netxen_alloc_sds_rings(recv_ctx, adapter->max_sds_rings))
- return 1;
+ return -ENOMEM;
for (ring = 0; ring < adapter->max_sds_rings; ring++) {
sds_ring = &recv_ctx->sds_rings[ring];
@@ -282,12 +283,16 @@ nx_update_dma_mask(struct netxen_adapter *adapter)
return 0;
}
-static void netxen_check_options(struct netxen_adapter *adapter)
+static void
+netxen_check_options(struct netxen_adapter *adapter)
{
- if (adapter->ahw.port_type == NETXEN_NIC_XGBE)
- adapter->num_rxd = MAX_RCV_DESCRIPTORS_10G;
- else if (adapter->ahw.port_type == NETXEN_NIC_GBE)
- adapter->num_rxd = MAX_RCV_DESCRIPTORS_1G;
+ if (adapter->ahw.port_type == NETXEN_NIC_XGBE) {
+ adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G;
+ adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+ } else if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
+ adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G;
+ adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+ }
adapter->msix_supported = 0;
if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
@@ -305,11 +310,15 @@ static void netxen_check_options(struct netxen_adapter *adapter)
}
}
- adapter->num_txd = MAX_CMD_DESCRIPTORS_HOST;
- adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS;
- adapter->num_lro_rxd = MAX_LRO_RCV_DESCRIPTORS;
+ adapter->num_txd = MAX_CMD_DESCRIPTORS;
- return;
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
+ adapter->num_lro_rxd = MAX_LRO_RCV_DESCRIPTORS;
+ adapter->max_rds_rings = 3;
+ } else {
+ adapter->num_lro_rxd = 0;
+ adapter->max_rds_rings = 2;
+ }
}
static int
@@ -744,7 +753,7 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw)
}
- err = netxen_initialize_adapter_offload(adapter);
+ err = netxen_init_dummy_dma(adapter);
if (err)
return err;
@@ -760,10 +769,14 @@ wait_init:
/* Handshake with the card before we register the devices. */
err = netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
if (err) {
- netxen_free_adapter_offload(adapter);
+ netxen_free_dummy_dma(adapter);
return err;
}
+ nx_update_dma_mask(adapter);
+
+ netxen_nic_get_firmware_info(adapter);
+
return 0;
}
@@ -814,6 +827,20 @@ netxen_nic_free_irq(struct netxen_adapter *adapter)
}
}
+static void
+netxen_nic_init_coalesce_defaults(struct netxen_adapter *adapter)
+{
+ adapter->coal.flags = NETXEN_NIC_INTR_DEFAULT;
+ adapter->coal.normal.data.rx_time_us =
+ NETXEN_DEFAULT_INTR_COALESCE_RX_TIME_US;
+ adapter->coal.normal.data.rx_packets =
+ NETXEN_DEFAULT_INTR_COALESCE_RX_PACKETS;
+ adapter->coal.normal.data.tx_time_us =
+ NETXEN_DEFAULT_INTR_COALESCE_TX_TIME_US;
+ adapter->coal.normal.data.tx_packets =
+ NETXEN_DEFAULT_INTR_COALESCE_TX_PACKETS;
+}
+
static int
netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev)
{
@@ -836,6 +863,9 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev)
if (adapter->max_sds_rings > 1)
netxen_config_rss(adapter, 1);
+ if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
+ netxen_config_intr_coalesce(adapter);
+
netxen_napi_enable(adapter);
if (adapter->capabilities & NX_FW_CAPABILITY_LINK_NOTIFICATION)
@@ -880,17 +910,15 @@ netxen_nic_attach(struct netxen_adapter *adapter)
struct nx_host_rds_ring *rds_ring;
struct nx_host_tx_ring *tx_ring;
+ if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC)
+ return 0;
+
err = netxen_init_firmware(adapter);
if (err != 0) {
printk(KERN_ERR "Failed to init firmware\n");
return -EIO;
}
- if (adapter->fw_major < 4)
- adapter->max_rds_rings = 3;
- else
- adapter->max_rds_rings = 2;
-
err = netxen_alloc_sw_resources(adapter);
if (err) {
printk(KERN_ERR "%s: Error in setting sw resources\n",
@@ -907,7 +935,7 @@ netxen_nic_attach(struct netxen_adapter *adapter)
goto err_out_free_sw;
}
- if (adapter->fw_major < 4) {
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
tx_ring = adapter->tx_ring;
tx_ring->crb_cmd_producer = crb_cmd_producer[adapter->portnum];
tx_ring->crb_cmd_consumer = crb_cmd_consumer[adapter->portnum];
@@ -931,6 +959,9 @@ netxen_nic_attach(struct netxen_adapter *adapter)
goto err_out_free_rxbuf;
}
+ if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
+ netxen_nic_init_coalesce_defaults(adapter);
+
adapter->is_up = NETXEN_ADAPTER_UP_MAGIC;
return 0;
@@ -945,6 +976,9 @@ err_out_free_sw:
static void
netxen_nic_detach(struct netxen_adapter *adapter)
{
+ if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
+ return;
+
netxen_free_hw_resources(adapter);
netxen_release_rx_buffers(adapter);
netxen_nic_free_irq(adapter);
@@ -953,6 +987,95 @@ netxen_nic_detach(struct netxen_adapter *adapter)
adapter->is_up = 0;
}
+int
+netxen_nic_reset_context(struct netxen_adapter *adapter)
+{
+ int err = 0;
+ struct net_device *netdev = adapter->netdev;
+
+ if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) {
+
+ if (netif_running(netdev))
+ netxen_nic_down(adapter, netdev);
+
+ netxen_nic_detach(adapter);
+
+ err = netxen_nic_attach(adapter);
+ if (err)
+ goto done;
+
+ if (netif_running(netdev))
+ err = netxen_nic_up(adapter, netdev);
+ }
+done:
+ return err;
+}
+
+static int
+netxen_setup_netdev(struct netxen_adapter *adapter,
+ struct net_device *netdev)
+{
+ int err = 0;
+ struct pci_dev *pdev = adapter->pdev;
+
+ adapter->rx_csum = 1;
+ adapter->mc_enabled = 0;
+ if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
+ adapter->max_mc_count = 38;
+ else
+ adapter->max_mc_count = 16;
+
+ netdev->netdev_ops = &netxen_netdev_ops;
+ netdev->watchdog_timeo = 2*HZ;
+
+ netxen_nic_change_mtu(netdev, netdev->mtu);
+
+ SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
+
+ netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
+ netdev->features |= (NETIF_F_GRO);
+ netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
+
+ if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
+ netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
+ netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
+ }
+
+ if (adapter->pci_using_dac) {
+ netdev->features |= NETIF_F_HIGHDMA;
+ netdev->vlan_features |= NETIF_F_HIGHDMA;
+ }
+
+ if (adapter->capabilities & NX_FW_CAPABILITY_FVLANTX)
+ netdev->features |= (NETIF_F_HW_VLAN_TX);
+
+ netdev->irq = adapter->msix_entries[0].vector;
+
+ err = netxen_napi_add(adapter, netdev);
+ if (err)
+ return err;
+
+ init_timer(&adapter->watchdog_timer);
+ adapter->watchdog_timer.function = &netxen_watchdog;
+ adapter->watchdog_timer.data = (unsigned long)adapter;
+ INIT_WORK(&adapter->watchdog_task, netxen_watchdog_task);
+ INIT_WORK(&adapter->tx_timeout_task, netxen_reset_task);
+
+ if (netxen_read_mac_addr(adapter))
+ dev_warn(&pdev->dev, "failed to read mac addr\n");
+
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ err = register_netdev(netdev);
+ if (err) {
+ dev_err(&pdev->dev, "failed to register net device\n");
+ return err;
+ }
+
+ return 0;
+}
+
static int __devinit
netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -990,9 +1113,8 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev = alloc_etherdev(sizeof(struct netxen_adapter));
if(!netdev) {
- printk(KERN_ERR"%s: Failed to allocate memory for the "
- "device block.Check system memory resource"
- " usage.\n", netxen_nic_driver_name);
+ dev_err(&pdev->dev, "failed to allocate net_device\n");
+ err = -ENOMEM;
goto err_out_free_res;
}
@@ -1020,38 +1142,10 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* This will be reset for mezz cards */
adapter->portnum = pci_func_id;
- adapter->rx_csum = 1;
- adapter->mc_enabled = 0;
- if (NX_IS_REVISION_P3(revision_id))
- adapter->max_mc_count = 38;
- else
- adapter->max_mc_count = 16;
-
- netdev->netdev_ops = &netxen_netdev_ops;
- netdev->watchdog_timeo = 2*HZ;
-
- netxen_nic_change_mtu(netdev, netdev->mtu);
- SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
-
- netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
- netdev->features |= (NETIF_F_GRO);
- netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
-
- if (NX_IS_REVISION_P3(revision_id)) {
- netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
- netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
- }
-
- if (adapter->pci_using_dac) {
- netdev->features |= NETIF_F_HIGHDMA;
- netdev->vlan_features |= NETIF_F_HIGHDMA;
- }
-
- if (netxen_nic_get_board_info(adapter) != 0) {
- printk("%s: Error getting board config info.\n",
- netxen_nic_driver_name);
- err = -EIO;
+ err = netxen_nic_get_board_info(adapter);
+ if (err) {
+ dev_err(&pdev->dev, "Error getting board config info.\n");
goto err_out_iounmap;
}
@@ -1072,15 +1166,11 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto err_out_iounmap;
- nx_update_dma_mask(adapter);
-
- netxen_nic_get_firmware_info(adapter);
-
/*
* See if the firmware gave us a virtual-physical port mapping.
*/
adapter->physical_port = adapter->portnum;
- if (adapter->fw_major < 4) {
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
i = NXRD32(adapter, CRB_V2P(adapter->portnum));
if (i != 0x55555555)
adapter->physical_port = i;
@@ -1090,31 +1180,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netxen_setup_intr(adapter);
- netdev->irq = adapter->msix_entries[0].vector;
-
- if (netxen_napi_add(adapter, netdev))
- goto err_out_disable_msi;
-
- init_timer(&adapter->watchdog_timer);
- adapter->watchdog_timer.function = &netxen_watchdog;
- adapter->watchdog_timer.data = (unsigned long)adapter;
- INIT_WORK(&adapter->watchdog_task, netxen_watchdog_task);
- INIT_WORK(&adapter->tx_timeout_task, netxen_tx_timeout_task);
-
- err = netxen_read_mac_addr(adapter);
+ err = netxen_setup_netdev(adapter, netdev);
if (err)
- dev_warn(&pdev->dev, "failed to read mac addr\n");
-
- netif_carrier_off(netdev);
- netif_stop_queue(netdev);
-
- if ((err = register_netdev(netdev))) {
- printk(KERN_ERR "%s: register_netdev failed port #%d"
- " aborting\n", netxen_nic_driver_name,
- adapter->portnum);
- err = -EIO;
goto err_out_disable_msi;
- }
pci_set_drvdata(pdev, adapter);
@@ -1134,7 +1202,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err_out_disable_msi:
netxen_teardown_intr(adapter);
- netxen_free_adapter_offload(adapter);
+ netxen_free_dummy_dma(adapter);
err_out_iounmap:
netxen_cleanup_pci_map(adapter);
@@ -1164,12 +1232,10 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
unregister_netdev(netdev);
- if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) {
- netxen_nic_detach(adapter);
- }
+ netxen_nic_detach(adapter);
if (adapter->portnum == 0)
- netxen_free_adapter_offload(adapter);
+ netxen_free_dummy_dma(adapter);
netxen_teardown_intr(adapter);
netxen_free_sds_rings(&adapter->recv_ctx);
@@ -1198,8 +1264,7 @@ netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state)
if (netif_running(netdev))
netxen_nic_down(adapter, netdev);
- if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC)
- netxen_nic_detach(adapter);
+ netxen_nic_detach(adapter);
pci_save_state(pdev);
@@ -1260,11 +1325,9 @@ static int netxen_nic_open(struct net_device *netdev)
if (adapter->driver_mismatch)
return -EIO;
- if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) {
- err = netxen_nic_attach(adapter);
- if (err)
- return err;
- }
+ err = netxen_nic_attach(adapter);
+ if (err)
+ return err;
err = netxen_nic_up(adapter, netdev);
if (err)
@@ -1290,30 +1353,52 @@ static int netxen_nic_close(struct net_device *netdev)
return 0;
}
-static bool netxen_tso_check(struct net_device *netdev,
- struct cmd_desc_type0 *desc, struct sk_buff *skb)
+static void
+netxen_tso_check(struct net_device *netdev,
+ struct nx_host_tx_ring *tx_ring,
+ struct cmd_desc_type0 *first_desc,
+ struct sk_buff *skb)
{
- bool tso = false;
u8 opcode = TX_ETHER_PKT;
__be16 protocol = skb->protocol;
- u16 flags = 0;
+ u16 flags = 0, vid = 0;
+ u32 producer;
+ int copied, offset, copy_len, hdr_len = 0, tso = 0, vlan_oob = 0;
+ struct cmd_desc_type0 *hwdesc;
+ struct vlan_ethhdr *vh;
if (protocol == cpu_to_be16(ETH_P_8021Q)) {
- struct vlan_ethhdr *vh = (struct vlan_ethhdr *)skb->data;
+
+ vh = (struct vlan_ethhdr *)skb->data;
protocol = vh->h_vlan_encapsulated_proto;
flags = FLAGS_VLAN_TAGGED;
+
+ } else if (vlan_tx_tag_present(skb)) {
+
+ flags = FLAGS_VLAN_OOB;
+ vid = vlan_tx_tag_get(skb);
+ netxen_set_tx_vlan_tci(first_desc, vid);
+ vlan_oob = 1;
}
if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
skb_shinfo(skb)->gso_size > 0) {
- desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
- desc->total_hdr_length =
- skb_transport_offset(skb) + tcp_hdrlen(skb);
+ hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+
+ first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
+ first_desc->total_hdr_length = hdr_len;
+ if (vlan_oob) {
+ first_desc->total_hdr_length += VLAN_HLEN;
+ first_desc->tcp_hdr_offset = VLAN_HLEN;
+ first_desc->ip_hdr_offset = VLAN_HLEN;
+ /* Only in case of TSO on vlan device */
+ flags |= FLAGS_VLAN_TAGGED;
+ }
opcode = (protocol == cpu_to_be16(ETH_P_IPV6)) ?
TX_TCP_LSO6 : TX_TCP_LSO;
- tso = true;
+ tso = 1;
} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
u8 l4proto;
@@ -1334,10 +1419,62 @@ static bool netxen_tso_check(struct net_device *netdev,
opcode = TX_UDPV6_PKT;
}
}
- desc->tcp_hdr_offset = skb_transport_offset(skb);
- desc->ip_hdr_offset = skb_network_offset(skb);
- netxen_set_tx_flags_opcode(desc, flags, opcode);
- return tso;
+
+ first_desc->tcp_hdr_offset += skb_transport_offset(skb);
+ first_desc->ip_hdr_offset += skb_network_offset(skb);
+ netxen_set_tx_flags_opcode(first_desc, flags, opcode);
+
+ if (!tso)
+ return;
+
+ /* For LSO, we need to copy the MAC/IP/TCP headers into
+ * the descriptor ring
+ */
+ producer = tx_ring->producer;
+ copied = 0;
+ offset = 2;
+
+ if (vlan_oob) {
+ /* Create a TSO vlan header template for firmware */
+
+ hwdesc = &tx_ring->desc_head[producer];
+ tx_ring->cmd_buf_arr[producer].skb = NULL;
+
+ copy_len = min((int)sizeof(struct cmd_desc_type0) - offset,
+ hdr_len + VLAN_HLEN);
+
+ vh = (struct vlan_ethhdr *)((char *)hwdesc + 2);
+ skb_copy_from_linear_data(skb, vh, 12);
+ vh->h_vlan_proto = htons(ETH_P_8021Q);
+ vh->h_vlan_TCI = htons(vid);
+ skb_copy_from_linear_data_offset(skb, 12,
+ (char *)vh + 16, copy_len - 16);
+
+ copied = copy_len;
+ offset = 0;
+
+ producer = get_next_index(producer, tx_ring->num_desc);
+ }
+
+ while (copied < hdr_len) {
+
+ copy_len = min((int)sizeof(struct cmd_desc_type0) - offset,
+ (hdr_len - copied));
+
+ hwdesc = &tx_ring->desc_head[producer];
+ tx_ring->cmd_buf_arr[producer].skb = NULL;
+
+ skb_copy_from_linear_data_offset(skb, copied,
+ (char *)hwdesc + offset, copy_len);
+
+ copied += copy_len;
+ offset = 0;
+
+ producer = get_next_index(producer, tx_ring->num_desc);
+ }
+
+ tx_ring->producer = producer;
+ barrier();
}
static void
@@ -1361,9 +1498,8 @@ netxen_clean_tx_dma_mapping(struct pci_dev *pdev,
static inline void
netxen_clear_cmddesc(u64 *desc)
{
- int i;
- for (i = 0; i < 8; i++)
- desc[i] = 0ULL;
+ desc[0] = 0ULL;
+ desc[2] = 0ULL;
}
static int
@@ -1371,18 +1507,18 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
struct netxen_adapter *adapter = netdev_priv(netdev);
struct nx_host_tx_ring *tx_ring = adapter->tx_ring;
- unsigned int first_seg_len = skb->len - skb->data_len;
+ struct skb_frag_struct *frag;
struct netxen_cmd_buffer *pbuf;
struct netxen_skb_frag *buffrag;
- struct cmd_desc_type0 *hwdesc;
- struct pci_dev *pdev = adapter->pdev;
+ struct cmd_desc_type0 *hwdesc, *first_desc;
+ struct pci_dev *pdev;
dma_addr_t temp_dma;
int i, k;
+ unsigned long offset;
u32 producer;
- int frag_count, no_of_desc;
+ int len, frag_count, no_of_desc;
u32 num_txd = tx_ring->num_desc;
- bool is_tso = false;
frag_count = skb_shinfo(skb)->nr_frags + 1;
@@ -1396,32 +1532,30 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
producer = tx_ring->producer;
- hwdesc = &tx_ring->desc_head[producer];
- netxen_clear_cmddesc((u64 *)hwdesc);
- pbuf = &tx_ring->cmd_buf_arr[producer];
+ pdev = adapter->pdev;
+ len = skb->len - skb->data_len;
- is_tso = netxen_tso_check(netdev, hwdesc, skb);
+ temp_dma = pci_map_single(pdev, skb->data, len, PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(pdev, temp_dma))
+ goto drop_packet;
+ pbuf = &tx_ring->cmd_buf_arr[producer];
pbuf->skb = skb;
pbuf->frag_count = frag_count;
- buffrag = &pbuf->frag_array[0];
- temp_dma = pci_map_single(pdev, skb->data, first_seg_len,
- PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(pdev, temp_dma))
- goto drop_packet;
+ buffrag = &pbuf->frag_array[0];
buffrag->dma = temp_dma;
- buffrag->length = first_seg_len;
+ buffrag->length = len;
+
+ first_desc = hwdesc = &tx_ring->desc_head[producer];
+ netxen_clear_cmddesc((u64 *)hwdesc);
netxen_set_tx_frags_len(hwdesc, frag_count, skb->len);
netxen_set_tx_port(hwdesc, adapter->portnum);
- hwdesc->buffer_length[0] = cpu_to_le16(first_seg_len);
- hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma);
+ hwdesc->buffer_length[0] = cpu_to_le16(len);
+ hwdesc->addr_buffer1 = cpu_to_le64(temp_dma);
for (i = 1, k = 1; i < frag_count; i++, k++) {
- struct skb_frag_struct *frag;
- int len, temp_len;
- unsigned long offset;
/* move to next desc. if there is a need */
if ((i & 0x3) == 0) {
@@ -1432,11 +1566,11 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
pbuf = &tx_ring->cmd_buf_arr[producer];
pbuf->skb = NULL;
}
+ buffrag = &pbuf->frag_array[i];
frag = &skb_shinfo(skb)->frags[i - 1];
len = frag->size;
offset = frag->page_offset;
- temp_len = len;
temp_dma = pci_map_page(pdev, frag->page, offset,
len, PCI_DMA_TODEVICE);
if (pci_dma_mapping_error(pdev, temp_dma)) {
@@ -1444,11 +1578,10 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
goto drop_packet;
}
- buffrag++;
buffrag->dma = temp_dma;
- buffrag->length = temp_len;
+ buffrag->length = len;
- hwdesc->buffer_length[k] = cpu_to_le16(temp_len);
+ hwdesc->buffer_length[k] = cpu_to_le16(len);
switch (k) {
case 0:
hwdesc->addr_buffer1 = cpu_to_le64(temp_dma);
@@ -1463,53 +1596,14 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
hwdesc->addr_buffer4 = cpu_to_le64(temp_dma);
break;
}
- frag++;
- }
- producer = get_next_index(producer, num_txd);
-
- /* For LSO, we need to copy the MAC/IP/TCP headers into
- * the descriptor ring
- */
- if (is_tso) {
- int hdr_len, first_hdr_len, more_hdr;
- hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
- if (hdr_len > (sizeof(struct cmd_desc_type0) - 2)) {
- first_hdr_len = sizeof(struct cmd_desc_type0) - 2;
- more_hdr = 1;
- } else {
- first_hdr_len = hdr_len;
- more_hdr = 0;
- }
- /* copy the MAC/IP/TCP headers to the cmd descriptor list */
- hwdesc = &tx_ring->desc_head[producer];
- pbuf = &tx_ring->cmd_buf_arr[producer];
- pbuf->skb = NULL;
-
- /* copy the first 64 bytes */
- memcpy(((void *)hwdesc) + 2,
- (void *)(skb->data), first_hdr_len);
- producer = get_next_index(producer, num_txd);
-
- if (more_hdr) {
- hwdesc = &tx_ring->desc_head[producer];
- pbuf = &tx_ring->cmd_buf_arr[producer];
- pbuf->skb = NULL;
- /* copy the next 64 bytes - should be enough except
- * for pathological case
- */
- skb_copy_from_linear_data_offset(skb, first_hdr_len,
- hwdesc,
- (hdr_len -
- first_hdr_len));
- producer = get_next_index(producer, num_txd);
- }
}
+ tx_ring->producer = get_next_index(producer, num_txd);
- tx_ring->producer = producer;
- adapter->stats.txbytes += skb->len;
+ netxen_tso_check(netdev, tx_ring, first_desc, skb);
netxen_nic_update_cmd_producer(adapter, tx_ring);
+ adapter->stats.txbytes += skb->len;
adapter->stats.xmitcalled++;
return NETDEV_TX_OK;
@@ -1641,10 +1735,13 @@ static void netxen_tx_timeout(struct net_device *netdev)
{
struct netxen_adapter *adapter = (struct netxen_adapter *)
netdev_priv(netdev);
+
+ dev_err(&netdev->dev, "transmit timeout, resetting.\n");
+
SCHEDULE_WORK(&adapter->tx_timeout_task);
}
-static void netxen_tx_timeout_task(struct work_struct *work)
+static void netxen_reset_task(struct work_struct *work)
{
struct netxen_adapter *adapter =
container_of(work, struct netxen_adapter, tx_timeout_task);
@@ -1652,9 +1749,6 @@ static void netxen_tx_timeout_task(struct work_struct *work)
if (!netif_running(adapter->netdev))
return;
- printk(KERN_ERR "%s %s: transmit timeout, resetting.\n",
- netxen_nic_driver_name, adapter->netdev->name);
-
netxen_napi_disable(adapter);
adapter->netdev->trans_start = jiffies;
@@ -1712,7 +1806,7 @@ static irqreturn_t netxen_intr(int irq, void *data)
}
/* clear interrupt */
- if (adapter->fw_major < 4)
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
netxen_nic_disable_int(sds_ring);
adapter->pci_write_immediate(adapter,
@@ -1781,6 +1875,128 @@ static void netxen_nic_poll_controller(struct net_device *netdev)
}
#endif
+#ifdef CONFIG_INET
+
+#define is_netxen_netdev(dev) (dev->netdev_ops == &netxen_netdev_ops)
+
+static int
+netxen_destip_supported(struct netxen_adapter *adapter)
+{
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
+ return 0;
+
+ if (adapter->ahw.cut_through)
+ return 0;
+
+ return 1;
+}
+
+static int netxen_netdev_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct netxen_adapter *adapter;
+ struct net_device *dev = (struct net_device *)ptr;
+ struct in_device *indev;
+
+recheck:
+ if (dev == NULL)
+ goto done;
+
+ if (dev->priv_flags & IFF_802_1Q_VLAN) {
+ dev = vlan_dev_real_dev(dev);
+ goto recheck;
+ }
+
+ if (!is_netxen_netdev(dev))
+ goto done;
+
+ adapter = netdev_priv(dev);
+
+ if (!adapter || !netxen_destip_supported(adapter))
+ goto done;
+
+ if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
+ goto done;
+
+ indev = in_dev_get(dev);
+ if (!indev)
+ goto done;
+
+ for_ifa(indev) {
+ switch (event) {
+ case NETDEV_UP:
+ netxen_config_ipaddr(adapter,
+ ifa->ifa_address, NX_IP_UP);
+ break;
+ case NETDEV_DOWN:
+ netxen_config_ipaddr(adapter,
+ ifa->ifa_address, NX_IP_DOWN);
+ break;
+ default:
+ break;
+ }
+ } endfor_ifa(indev);
+
+ in_dev_put(indev);
+done:
+ return NOTIFY_DONE;
+}
+
+static int
+netxen_inetaddr_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct netxen_adapter *adapter;
+ struct net_device *dev;
+
+ struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
+
+ dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL;
+
+recheck:
+ if (dev == NULL || !netif_running(dev))
+ goto done;
+
+ if (dev->priv_flags & IFF_802_1Q_VLAN) {
+ dev = vlan_dev_real_dev(dev);
+ goto recheck;
+ }
+
+ if (!is_netxen_netdev(dev))
+ goto done;
+
+ adapter = netdev_priv(dev);
+
+ if (!adapter || !netxen_destip_supported(adapter))
+ goto done;
+
+ if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
+ goto done;
+
+ switch (event) {
+ case NETDEV_UP:
+ netxen_config_ipaddr(adapter, ifa->ifa_address, NX_IP_UP);
+ break;
+ case NETDEV_DOWN:
+ netxen_config_ipaddr(adapter, ifa->ifa_address, NX_IP_DOWN);
+ break;
+ default:
+ break;
+ }
+
+done:
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block netxen_netdev_cb = {
+ .notifier_call = netxen_netdev_event,
+};
+
+static struct notifier_block netxen_inetaddr_cb = {
+ .notifier_call = netxen_inetaddr_event,
+};
+#endif
+
static struct pci_driver netxen_driver = {
.name = netxen_nic_driver_name,
.id_table = netxen_pci_tbl,
@@ -1792,8 +2008,6 @@ static struct pci_driver netxen_driver = {
#endif
};
-/* Driver Registration on NetXen card */
-
static int __init netxen_init_module(void)
{
printk(KERN_INFO "%s\n", netxen_nic_driver_string);
@@ -1801,6 +2015,11 @@ static int __init netxen_init_module(void)
if ((netxen_workq = create_singlethread_workqueue("netxen")) == NULL)
return -ENOMEM;
+#ifdef CONFIG_INET
+ register_netdevice_notifier(&netxen_netdev_cb);
+ register_inetaddr_notifier(&netxen_inetaddr_cb);
+#endif
+
return pci_register_driver(&netxen_driver);
}
@@ -1809,6 +2028,11 @@ module_init(netxen_init_module);
static void __exit netxen_exit_module(void)
{
pci_unregister_driver(&netxen_driver);
+
+#ifdef CONFIG_INET
+ unregister_inetaddr_notifier(&netxen_inetaddr_cb);
+ unregister_netdevice_notifier(&netxen_netdev_cb);
+#endif
destroy_workqueue(netxen_workq);
}
diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c
index 2a8da476ab3d..462d20f26436 100644
--- a/drivers/net/ni5010.c
+++ b/drivers/net/ni5010.c
@@ -463,7 +463,7 @@ static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev)
hardware_send_packet(dev, (unsigned char *)skb->data, skb->len, length-skb->len);
dev->trans_start = jiffies;
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c
index 77d44a061703..a0ac5d4f27d3 100644
--- a/drivers/net/ni52.c
+++ b/drivers/net/ni52.c
@@ -1183,7 +1183,7 @@ static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev)
if (skb->len > XMIT_BUFF_SIZE) {
printk(KERN_ERR "%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n", dev->name, XMIT_BUFF_SIZE, skb->len);
- return 0;
+ return NETDEV_TX_OK;
}
netif_stop_queue(dev);
@@ -1267,7 +1267,7 @@ static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev)
}
dev_kfree_skb(skb);
#endif
- return 0;
+ return NETDEV_TX_OK;
}
/*******************************************
diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c
index 1f10ed603e20..81a061785898 100644
--- a/drivers/net/ni65.c
+++ b/drivers/net/ni65.c
@@ -1216,7 +1216,7 @@ static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&p->ring_lock, flags);
}
- return 0;
+ return NETDEV_TX_OK;
}
static void set_multicast_list(struct net_device *dev)
diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
index 8c1f6988f398..e4a93b8ed485 100644
--- a/drivers/net/pci-skeleton.c
+++ b/drivers/net/pci-skeleton.c
@@ -1356,7 +1356,7 @@ static int netdrv_start_xmit (struct sk_buff *skb, struct net_device *dev)
DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n",
dev->name, skb->data, skb->len, entry);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index f35c609ba020..a23aa8724042 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -806,7 +806,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
pop_tx_status(dev);
spin_unlock_irqrestore(&lp->window_lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* The EL3 interrupt handler. */
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 690b9c76d34e..d2156ab3da2b 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -635,7 +635,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&priv->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* The EL3 interrupt handler. */
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 0e38d80fd255..b5cfac7c5179 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -1179,7 +1179,7 @@ static int axnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb (skb);
dev->stats.tx_bytes += send_length;
- return 0;
+ return NETDEV_TX_OK;
}
/**
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 479d5b494371..434d9407bfb3 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -865,7 +865,7 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN)
{
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
@@ -924,7 +924,7 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
} /* fjn_start_xmit */
/*====================================================================*/
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index 02ef63ed1f99..0f8118a82579 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -990,7 +990,7 @@ static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} /* mace_start_xmit */
/* ----------------------------------------------------------------------------
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index 37e05d3ab893..2f39244c17f2 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -1399,7 +1399,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb (skb);
smc->saved_skb = NULL;
dev->stats.tx_dropped++;
- return 0; /* Do not re-queue this packet. */
+ return NETDEV_TX_OK; /* Do not re-queue this packet. */
}
/* A packet is now waiting. */
smc->packets_waiting++;
@@ -1422,7 +1422,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
outw((ir&0xff00) | IM_ALLOC_INT, ioaddr + INTERRUPT);
smc_hardware_send_packet(dev); /* Send the packet now.. */
spin_unlock_irqrestore(&smc->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
}
@@ -1431,7 +1431,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT);
spin_unlock_irqrestore(&smc->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/*======================================================================
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index ef37d22c7e1d..eda7bf6047cd 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -1384,7 +1384,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (pktlen < ETH_ZLEN)
{
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
pktlen = ETH_ZLEN;
}
@@ -1414,7 +1414,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
dev->stats.tx_bytes += pktlen;
netif_start_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
/****************
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 1c35e1d637a0..955a87ac9afa 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -2536,7 +2536,7 @@ static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
}
spin_unlock_irqrestore(&lp->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/* The PCNET32 interrupt handler. */
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index de9cf5136fdc..d5d8e1c5bc91 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -56,6 +56,12 @@ config BROADCOM_PHY
Currently supports the BCM5411, BCM5421, BCM5461, BCM5464, BCM5481
and BCM5482 PHYs.
+config BCM63XX_PHY
+ tristate "Drivers for Broadcom 63xx SOCs internal PHY"
+ depends on BCM63XX
+ ---help---
+ Currently supports the 6348 and 6358 PHYs.
+
config ICPLUS_PHY
tristate "Drivers for ICPlus PHYs"
---help---
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 3a1bfefefbc3..edfaac48cbd5 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_QSEMI_PHY) += qsemi.o
obj-$(CONFIG_SMSC_PHY) += smsc.o
obj-$(CONFIG_VITESSE_PHY) += vitesse.o
obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
+obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o
obj-$(CONFIG_ICPLUS_PHY) += icplus.o
obj-$(CONFIG_REALTEK_PHY) += realtek.o
obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
diff --git a/drivers/net/phy/bcm63xx.c b/drivers/net/phy/bcm63xx.c
new file mode 100644
index 000000000000..4fed95e8350e
--- /dev/null
+++ b/drivers/net/phy/bcm63xx.c
@@ -0,0 +1,132 @@
+/*
+ * Driver for Broadcom 63xx SOCs integrated PHYs
+ *
+ * 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/phy.h>
+
+#define MII_BCM63XX_IR 0x1a /* interrupt register */
+#define MII_BCM63XX_IR_EN 0x4000 /* global interrupt enable */
+#define MII_BCM63XX_IR_DUPLEX 0x0800 /* duplex changed */
+#define MII_BCM63XX_IR_SPEED 0x0400 /* speed changed */
+#define MII_BCM63XX_IR_LINK 0x0200 /* link changed */
+#define MII_BCM63XX_IR_GMASK 0x0100 /* global interrupt mask */
+
+MODULE_DESCRIPTION("Broadcom 63xx internal PHY driver");
+MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>");
+MODULE_LICENSE("GPL");
+
+static int bcm63xx_config_init(struct phy_device *phydev)
+{
+ int reg, err;
+
+ reg = phy_read(phydev, MII_BCM63XX_IR);
+ if (reg < 0)
+ return reg;
+
+ /* Mask interrupts globally. */
+ reg |= MII_BCM63XX_IR_GMASK;
+ err = phy_write(phydev, MII_BCM63XX_IR, reg);
+ if (err < 0)
+ return err;
+
+ /* Unmask events we are interested in */
+ reg = ~(MII_BCM63XX_IR_DUPLEX |
+ MII_BCM63XX_IR_SPEED |
+ MII_BCM63XX_IR_LINK) |
+ MII_BCM63XX_IR_EN;
+ err = phy_write(phydev, MII_BCM63XX_IR, reg);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static int bcm63xx_ack_interrupt(struct phy_device *phydev)
+{
+ int reg;
+
+ /* Clear pending interrupts. */
+ reg = phy_read(phydev, MII_BCM63XX_IR);
+ if (reg < 0)
+ return reg;
+
+ return 0;
+}
+
+static int bcm63xx_config_intr(struct phy_device *phydev)
+{
+ int reg, err;
+
+ reg = phy_read(phydev, MII_BCM63XX_IR);
+ if (reg < 0)
+ return reg;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+ reg &= ~MII_BCM63XX_IR_GMASK;
+ else
+ reg |= MII_BCM63XX_IR_GMASK;
+
+ err = phy_write(phydev, MII_BCM63XX_IR, reg);
+ return err;
+}
+
+static struct phy_driver bcm63xx_1_driver = {
+ .phy_id = 0x00406000,
+ .phy_id_mask = 0xfffffc00,
+ .name = "Broadcom BCM63XX (1)",
+ /* ASYM_PAUSE bit is marked RO in datasheet, so don't cheat */
+ .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+ .flags = PHY_HAS_INTERRUPT,
+ .config_init = bcm63xx_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .ack_interrupt = bcm63xx_ack_interrupt,
+ .config_intr = bcm63xx_config_intr,
+ .driver = { .owner = THIS_MODULE },
+};
+
+/* same phy as above, with just a different OUI */
+static struct phy_driver bcm63xx_2_driver = {
+ .phy_id = 0x002bdc00,
+ .phy_id_mask = 0xfffffc00,
+ .name = "Broadcom BCM63XX (2)",
+ .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+ .flags = PHY_HAS_INTERRUPT,
+ .config_init = bcm63xx_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .ack_interrupt = bcm63xx_ack_interrupt,
+ .config_intr = bcm63xx_config_intr,
+ .driver = { .owner = THIS_MODULE },
+};
+
+static int __init bcm63xx_phy_init(void)
+{
+ int ret;
+
+ ret = phy_driver_register(&bcm63xx_1_driver);
+ if (ret)
+ goto out_63xx_1;
+ ret = phy_driver_register(&bcm63xx_2_driver);
+ if (ret)
+ goto out_63xx_2;
+ return ret;
+
+out_63xx_2:
+ phy_driver_unregister(&bcm63xx_1_driver);
+out_63xx_1:
+ return ret;
+}
+
+static void __exit bcm63xx_phy_exit(void)
+{
+ phy_driver_unregister(&bcm63xx_1_driver);
+ phy_driver_unregister(&bcm63xx_2_driver);
+}
+
+module_init(bcm63xx_phy_init);
+module_exit(bcm63xx_phy_exit);
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index 2ca8b0d84ee2..00487f569cfd 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -990,7 +990,7 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev)
schedule_work(&nl->immediate);
spin_unlock_irq(&nl->lock);
- return 0;
+ return NETDEV_TX_OK;
}
static void
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 639d11bc444e..d0b965517b46 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -988,12 +988,12 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
skb_queue_tail(&ppp->file.xq, skb);
ppp_xmit_process(ppp);
- return 0;
+ return NETDEV_TX_OK;
outf:
kfree_skb(skb);
++dev->stats.tx_dropped;
- return 0;
+ return NETDEV_TX_OK;
}
static int
diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c
index 961b5397a531..840677f5ee82 100644
--- a/drivers/net/r6040.c
+++ b/drivers/net/r6040.c
@@ -1115,13 +1115,13 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
}
/* IO Size check */
- if (pci_resource_len(pdev, 0) < io_size) {
+ if (pci_resource_len(pdev, bar) < io_size) {
printk(KERN_ERR DRV_NAME ": Insufficient PCI resources, aborting\n");
err = -EIO;
goto err_out;
}
- pioaddr = pci_resource_start(pdev, 0); /* IO map base address */
+ pioaddr = pci_resource_start(pdev, bar); /* IO map base address */
pci_set_master(pdev);
dev = alloc_etherdev(sizeof(struct r6040_private));
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
index 8702e7acdee6..bc98e7f69ee9 100644
--- a/drivers/net/rionet.c
+++ b/drivers/net/rionet.c
@@ -114,11 +114,6 @@ static int rionet_rx_clean(struct net_device *ndev)
if (error == NET_RX_DROP) {
ndev->stats.rx_dropped++;
- } else if (error == NET_RX_BAD) {
- if (netif_msg_rx_err(rnet))
- printk(KERN_WARNING "%s: bad rx packet\n",
- DRV_NAME);
- ndev->stats.rx_errors++;
} else {
ndev->stats.rx_packets++;
ndev->stats.rx_bytes += RIO_MAX_MSG_SIZE;
@@ -208,7 +203,7 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
spin_unlock_irqrestore(&rnet->tx_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u16 tid,
diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c
index 81dbcbb910f4..d95534655911 100644
--- a/drivers/net/rrunner.c
+++ b/drivers/net/rrunner.c
@@ -1466,7 +1466,7 @@ static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&rrpriv->lock, flags);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 458daa06ed41..d4df9330c447 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -4111,14 +4111,14 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(skb->len <= 0)) {
DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name);
dev_kfree_skb_any(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (!is_s2io_card_up(sp)) {
DBG_PRINT(TX_DBG, "%s: Card going down for reset\n",
dev->name);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
queue = 0;
@@ -4192,7 +4192,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
s2io_stop_tx_queue(sp, fifo->fifo_no);
dev_kfree_skb(skb);
spin_unlock_irqrestore(&fifo->tx_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
offload_type = s2io_offload_type(skb);
@@ -4304,14 +4304,14 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
if (sp->config.intr_type == MSI_X)
tx_intr_handler(fifo);
- return 0;
+ return NETDEV_TX_OK;
pci_map_failed:
stats->pci_map_fail_cnt++;
s2io_stop_tx_queue(sp, fifo->fifo_no);
stats->mem_freed += skb->truesize;
dev_kfree_skb(skb);
spin_unlock_irqrestore(&fifo->tx_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
static void
diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c
index fc0e38bddeeb..6a81aec645d9 100644
--- a/drivers/net/sb1000.c
+++ b/drivers/net/sb1000.c
@@ -1086,7 +1086,7 @@ sb1000_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_WARNING "%s: trying to transmit!!!\n", dev->name);
/* sb1000 can't xmit datagrams */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* SB1000 interrupt handler. */
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
index d8c9cf1b901d..508551f1b3fc 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -2091,7 +2091,7 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&sc->sbm_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/**********************************************************************
@@ -2688,7 +2688,7 @@ static int sbmac_poll(struct napi_struct *napi, int budget)
}
-static int __init sbmac_probe(struct platform_device *pldev)
+static int __devinit sbmac_probe(struct platform_device *pldev)
{
struct net_device *dev;
struct sbmac_softc *sc;
diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
index ebbbe09725fe..7cc8bb814137 100644
--- a/drivers/net/seeq8005.c
+++ b/drivers/net/seeq8005.c
@@ -401,7 +401,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
buf = skb->data;
@@ -415,7 +415,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb (skb);
/* You might need to clean up and record Tx statistics here. */
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index 5fb88ca6dd7f..ecf3279fbef5 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -594,7 +594,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)
len = skb->len;
if (len < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
len = ETH_ZLEN;
}
@@ -642,7 +642,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
spin_unlock_irqrestore(&sp->tx_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
static void timeout(struct net_device *dev)
@@ -720,7 +720,7 @@ static const struct net_device_ops sgiseeq_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
};
-static int __init sgiseeq_probe(struct platform_device *pdev)
+static int __devinit sgiseeq_probe(struct platform_device *pdev)
{
struct sgiseeq_platform_data *pd = pdev->dev.platform_data;
struct hpc3_regs *hpcregs = pd->hpc;
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index a2d82ddb3b4d..4c4dcbf19026 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -1133,7 +1133,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
ndev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
/* device close function */
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index a9a897bb42d5..61ceeaaf104d 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -1628,7 +1628,7 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
"to slot %d.\n",
net_dev->name, skb->data, (int)skb->len, entry);
- return 0;
+ return NETDEV_TX_OK;
}
/**
diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
index 088fe26484e7..888a14a045ef 100644
--- a/drivers/net/skfp/skfddi.c
+++ b/drivers/net/skfp/skfddi.c
@@ -1077,7 +1077,7 @@ static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev)
// dequeue packets from xmt queue and send them
netif_start_queue(dev);
dev_kfree_skb(skb);
- return (0); /* return "success" */
+ return NETDEV_TX_OK; /* return "success" */
}
if (bp->QueueSkb == 0) { // return with tbusy set: queue full
@@ -1091,7 +1091,7 @@ static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
}
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
} // skfp_send_pkt
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 3550c5dcd93c..661abd0492ae 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -4117,7 +4117,7 @@ static int sky2_debug_show(struct seq_file *seq, void *v)
seq_printf(seq, "\nRx ring hw get=%d put=%d last=%d\n",
sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_GET_IDX)),
- last = sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_PUT_IDX)),
+ sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_PUT_IDX)),
sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_LAST_IDX)));
sky2_read32(hw, B0_Y2_SP_LISR);
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 5c61d5fad908..899c4a2112c9 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -484,12 +484,12 @@ sl_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock(&sl->lock);
printk(KERN_WARNING "%s: xmit call when iface is down\n", dev->name);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (sl->tty == NULL) {
spin_unlock(&sl->lock);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
sl_lock(sl);
@@ -498,7 +498,7 @@ sl_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock(&sl->lock);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index bc4976ac8712..2a6b6de95339 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -553,7 +553,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_dropped++;
spin_unlock_irqrestore(&lp->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
#ifdef SMC_USE_DMA
@@ -566,7 +566,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
lp->pending_tx_skb = skb;
netif_stop_queue(dev);
spin_unlock_irqrestore(&lp->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
} else {
DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, "%s: Activating Tx DMA\n", dev->name);
lp->txdma_active = 1;
@@ -577,7 +577,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
smc911x_hardware_send_pkt(dev);
spin_unlock_irqrestore(&lp->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
index e02471b2f2b5..0a1b6f401087 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/smc9194.c
@@ -512,7 +512,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN)) {
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
length = ETH_ZLEN;
}
@@ -534,7 +534,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de
lp->saved_skb = NULL;
/* this IS an error, but, i don't want the skb saved */
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
/* either way, a packet is waiting now */
lp->packets_waiting++;
@@ -571,12 +571,12 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de
SMC_ENABLE_INT( IM_ALLOC_INT );
PRINTK2((CARDNAME": memory allocation deferred. \n"));
/* it's deferred, but I'll handle it later */
- return 0;
+ return NETDEV_TX_OK;
}
/* or YES! I can send the packet now.. */
smc_hardware_send_packet(dev);
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index 1c70e999cc50..0f2c52c2e044 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -655,7 +655,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_errors++;
dev->stats.tx_dropped++;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
smc_special_lock(&lp->lock);
@@ -692,7 +692,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
smc_hardware_send_pkt((unsigned long)dev);
}
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c
index 753a1fba4609..9599ce77ef85 100644
--- a/drivers/net/sonic.c
+++ b/drivers/net/sonic.c
@@ -211,7 +211,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev)
length = skb->len;
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
@@ -265,7 +265,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 838cce8b8fff..1018349a29dc 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -1311,7 +1311,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c
index 7bb27426dbd6..2f1eaaf7a727 100644
--- a/drivers/net/sun3_82586.c
+++ b/drivers/net/sun3_82586.c
@@ -1015,7 +1015,7 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev)
if(skb->len > XMIT_BUFF_SIZE)
{
printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len);
- return 0;
+ return NETDEV_TX_OK;
}
netif_stop_queue(dev);
@@ -1110,7 +1110,7 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
#endif
}
- return 0;
+ return NETDEV_TX_OK;
}
/*******************************************
diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c
index 534dfe3eef6f..0ca4241b4f63 100644
--- a/drivers/net/sun3lance.c
+++ b/drivers/net/sun3lance.c
@@ -562,7 +562,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
netif_start_queue(dev);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
@@ -648,7 +648,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
local_irq_restore(flags);
- return 0;
+ return NETDEV_TX_OK;
}
/* The LANCE interrupt handler. */
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index 5017d7fcb40c..536cf7e06bfd 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -984,7 +984,7 @@ static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static struct net_device_stats *bigmac_get_stats(struct net_device *dev)
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index 545f81b34ad7..0df6332ed9ce 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -1091,7 +1091,7 @@ start_tx (struct sk_buff *skb, struct net_device *dev)
"%s: Transmit frame #%d queued in slot %d.\n",
dev->name, np->cur_tx, entry);
}
- return 0;
+ return NETDEV_TX_OK;
}
/* Reset hardware tx and free all of tx buffers */
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index 4ef729198e10..008bd59fc64b 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -2338,7 +2338,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
tx_add_log(hp, TXLOG_ACTION_TXMIT, 0);
- return 0;
+ return NETDEV_TX_OK;
}
static struct net_device_stats *happy_meal_get_stats(struct net_device *dev)
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index afc7b351e5ec..9d6fd4760eab 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -1163,7 +1163,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* taken from the depca driver */
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index c6ec61e0accf..dcefb608a9f4 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -621,7 +621,7 @@ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void qe_set_multicast(struct net_device *dev)
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index d737f6b8f876..1ce2da172ca9 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -1509,7 +1509,7 @@ static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
*/
spin_unlock_irqrestore(&lp->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
#define FATAL_ERROR_INT \
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index 384cb5e28397..70c9ec45d8fb 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -1095,11 +1095,11 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev )
TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s PHY is not ready\n",
dev->name );
dev_kfree_skb_any(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (skb_padto(skb, TLAN_MIN_FRAME_SIZE))
- return 0;
+ return NETDEV_TX_OK;
txlen = max(skb->len, (unsigned int)TLAN_MIN_FRAME_SIZE);
tail_list = priv->txList + priv->txTail;
@@ -1150,7 +1150,7 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev )
CIRC_INC( priv->txTail, TLAN_NUM_TX_LISTS );
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
} /* TLan_StartTx */
diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c
index b40b6de2d086..1787d52941bc 100644
--- a/drivers/net/tokenring/3c359.c
+++ b/drivers/net/tokenring/3c359.c
@@ -1240,7 +1240,7 @@ static int xl_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ;
- return 0;
+ return NETDEV_TX_OK;
} else {
spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ;
return NETDEV_TX_BUSY;
diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
index 08a6c41c1599..96d00c8f8d3e 100644
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -1041,7 +1041,7 @@ static int tok_send_packet(struct sk_buff *skb, struct net_device *dev)
writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
spin_unlock_irqrestore(&(ti->lock), flags);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
/*****************************************************************************/
diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c
index b3715efdce56..d07e61a9499e 100644
--- a/drivers/net/tokenring/lanstreamer.c
+++ b/drivers/net/tokenring/lanstreamer.c
@@ -1183,7 +1183,7 @@ static int streamer_xmit(struct sk_buff *skb, struct net_device *dev)
streamer_priv->tx_ring_free = (streamer_priv->tx_ring_free + 1) & (STREAMER_TX_RING_SIZE - 1);
spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags);
- return 0;
+ return NETDEV_TX_OK;
} else {
netif_stop_queue(dev);
spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags);
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
index 451b54136ede..f73f4e684f33 100644
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -1052,7 +1052,7 @@ static int olympic_xmit(struct sk_buff *skb, struct net_device *dev)
writew((((readw(olympic_mmio+TXENQ_1)) & 0x8000) ^ 0x8000) | 1,olympic_mmio+TXENQ_1);
netif_wake_queue(dev);
spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags);
- return 0;
+ return NETDEV_TX_OK;
} else {
spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags);
return NETDEV_TX_BUSY;
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index 54ad4ed03374..6515894c83f5 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -4609,7 +4609,7 @@ static int smctr_send_packet(struct sk_buff *skb, struct net_device *dev)
if(tp->QueueSkb > 0)
netif_wake_queue(dev);
- return (0);
+ return NETDEV_TX_OK;
}
static int smctr_send_lobe_media_test(struct net_device *dev)
diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c
index a2eab72b507a..07f6dfd3ba0c 100644
--- a/drivers/net/tokenring/tms380tr.c
+++ b/drivers/net/tokenring/tms380tr.c
@@ -682,7 +682,7 @@ static int tms380tr_hardware_send_packet(struct sk_buff *skb, struct net_device
tms380tr_exec_sifcmd(dev, CMD_TX_VALID);
spin_unlock_irqrestore(&tp->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index 81f054dbb88d..769af558a345 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -651,7 +651,7 @@ static int de_start_xmit (struct sk_buff *skb, struct net_device *dev)
dw32(TxPoll, NormalTxPoll);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
/* Set or clear the multicast filter for this adaptor.
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index 8e78f003f08f..5e15fab58c17 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -676,7 +676,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev)
if (skb->len > MAX_PACKET_SIZE) {
printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
spin_lock_irqsave(&db->lock, flags);
@@ -722,7 +722,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev)
/* free this SKB */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index 2abb5d3becc6..9d46638d250e 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -690,7 +690,7 @@ tulip_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static void tulip_clean_tx_ring(struct tulip_private *tp)
diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c
index 9277ce8febe4..9074a34eb814 100644
--- a/drivers/net/tulip/uli526x.c
+++ b/drivers/net/tulip/uli526x.c
@@ -582,7 +582,7 @@ static int uli526x_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->len > MAX_PACKET_SIZE) {
printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
spin_lock_irqsave(&db->lock, flags);
@@ -624,7 +624,7 @@ static int uli526x_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* free this SKB */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index 842b1a2c40d4..6bc7540b216e 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -1058,7 +1058,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
dev->name, np->cur_tx, entry);
}
- return 0;
+ return NETDEV_TX_OK;
}
static void netdev_tx_done(struct net_device *dev)
diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
index c2ca9f40e40e..22b6a239fb33 100644
--- a/drivers/net/tulip/xircom_cb.c
+++ b/drivers/net/tulip/xircom_cb.c
@@ -434,7 +434,7 @@ static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev)
card->transmit_used = nextdescriptor;
leave("xircom-start_xmit - sent");
spin_unlock_irqrestore(&card->lock,flags);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 027f7aba26af..a998b6a9c245 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -398,12 +398,12 @@ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
if (tun->flags & TUN_FASYNC)
kill_fasync(&tun->fasync, SIGIO, POLL_IN);
wake_up_interruptible(&tun->socket.wait);
- return 0;
+ return NETDEV_TX_OK;
drop:
dev->stats.tx_dropped++;
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void tun_net_mclist(struct net_device *dev)
@@ -641,6 +641,9 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun,
case VIRTIO_NET_HDR_GSO_TCPV6:
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
break;
+ case VIRTIO_NET_HDR_GSO_UDP:
+ skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
+ break;
default:
tun->dev->stats.rx_frame_errors++;
kfree_skb(skb);
@@ -726,6 +729,8 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
else if (sinfo->gso_type & SKB_GSO_TCPV6)
gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
+ else if (sinfo->gso_type & SKB_GSO_UDP)
+ gso.gso_type = VIRTIO_NET_HDR_GSO_UDP;
else
BUG();
if (sinfo->gso_type & SKB_GSO_TCP_ECN)
@@ -997,7 +1002,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
goto err_free_sk;
}
- err = -EINVAL;
err = register_netdevice(tun->dev);
if (err < 0)
goto err_free_sk;
@@ -1074,7 +1078,8 @@ static int set_offload(struct net_device *dev, unsigned long arg)
old_features = dev->features;
/* Unset features, set them as we chew on the arg. */
features = (old_features & ~(NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST
- |NETIF_F_TSO_ECN|NETIF_F_TSO|NETIF_F_TSO6));
+ |NETIF_F_TSO_ECN|NETIF_F_TSO|NETIF_F_TSO6
+ |NETIF_F_UFO));
if (arg & TUN_F_CSUM) {
features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
@@ -1091,6 +1096,11 @@ static int set_offload(struct net_device *dev, unsigned long arg)
features |= NETIF_F_TSO6;
arg &= ~(TUN_F_TSO4|TUN_F_TSO6);
}
+
+ if (arg & TUN_F_UFO) {
+ features |= NETIF_F_UFO;
+ arg &= ~TUN_F_UFO;
+ }
}
/* This gives the user a way to test for new features in future by
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index cf25eb41b1ce..2c26b4577e8a 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -909,7 +909,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev)
netif_wake_queue(dev);
}
- return 0;
+ return NETDEV_TX_OK;
}
static void
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 3b957e6412ee..52a6750b8201 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -209,9 +209,10 @@ static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth,
{
struct sk_buff *skb = NULL;
- skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length +
- UCC_GETH_RX_DATA_BUF_ALIGNMENT);
-
+ skb = __skb_dequeue(&ugeth->rx_recycle);
+ if (!skb)
+ skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length +
+ UCC_GETH_RX_DATA_BUF_ALIGNMENT);
if (skb == NULL)
return NULL;
@@ -1986,6 +1987,8 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
iounmap(ugeth->ug_regs);
ugeth->ug_regs = NULL;
}
+
+ skb_queue_purge(&ugeth->rx_recycle);
}
static void ucc_geth_set_multi(struct net_device *dev)
@@ -2202,6 +2205,8 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
return -ENOMEM;
}
+ skb_queue_head_init(&ugeth->rx_recycle);
+
return 0;
}
@@ -3173,7 +3178,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
#endif
spin_unlock_irq(&ugeth->lock);
- return 0;
+ return NETDEV_TX_OK;
}
static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit)
@@ -3208,8 +3213,10 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
if (netif_msg_rx_err(ugeth))
ugeth_err("%s, %d: ERROR!!! skb - 0x%08x",
__func__, __LINE__, (u32) skb);
- if (skb)
- dev_kfree_skb_any(skb);
+ if (skb) {
+ skb->data = skb->head + NET_SKB_PAD;
+ __skb_queue_head(&ugeth->rx_recycle, skb);
+ }
ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] = NULL;
dev->stats.rx_dropped++;
@@ -3267,6 +3274,8 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
/* Normal processing. */
while ((bd_status & T_R) == 0) {
+ struct sk_buff *skb;
+
/* BD contains already transmitted buffer. */
/* Handle the transmitted buffer and release */
/* the BD to be used with the current frame */
@@ -3276,9 +3285,16 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
dev->stats.tx_packets++;
- /* Free the sk buffer associated with this TxBD */
- dev_kfree_skb(ugeth->
- tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]]);
+ skb = ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]];
+
+ if (skb_queue_len(&ugeth->rx_recycle) < RX_BD_RING_LEN &&
+ skb_recycle_check(skb,
+ ugeth->ug_info->uf_info.max_rx_buf_length +
+ UCC_GETH_RX_DATA_BUF_ALIGNMENT))
+ __skb_queue_head(&ugeth->rx_recycle, skb);
+ else
+ dev_kfree_skb(skb);
+
ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]] = NULL;
ugeth->skb_dirtytx[txQ] =
(ugeth->skb_dirtytx[txQ] +
@@ -3307,16 +3323,16 @@ static int ucc_geth_poll(struct napi_struct *napi, int budget)
ug_info = ugeth->ug_info;
- howmany = 0;
- for (i = 0; i < ug_info->numQueuesRx; i++)
- howmany += ucc_geth_rx(ugeth, i, budget - howmany);
-
/* Tx event processing */
spin_lock(&ugeth->lock);
for (i = 0; i < ug_info->numQueuesTx; i++)
ucc_geth_tx(ugeth->ndev, i);
spin_unlock(&ugeth->lock);
+ howmany = 0;
+ for (i = 0; i < ug_info->numQueuesRx; i++)
+ howmany += ucc_geth_rx(ugeth, i, budget - howmany);
+
if (howmany < budget) {
napi_complete(napi);
setbits32(ugeth->uccf->p_uccm, UCCE_RX_EVENTS | UCCE_TX_EVENTS);
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h
index 195ab267ead7..cfb31afc08a9 100644
--- a/drivers/net/ucc_geth.h
+++ b/drivers/net/ucc_geth.h
@@ -1212,6 +1212,8 @@ struct ucc_geth_private {
/* index of the first skb which hasn't been transmitted yet. */
u16 skb_dirtytx[NUM_TX_QUEUES];
+ struct sk_buff_head rx_recycle;
+
struct ugeth_mii_info *mii_info;
struct phy_device *phydev;
phy_interface_t phy_interface;
diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c
index b9dd42574288..7abdc4abbe07 100644
--- a/drivers/net/usb/catc.c
+++ b/drivers/net/usb/catc.c
@@ -448,7 +448,7 @@ static int catc_start_xmit(struct sk_buff *skb, struct net_device *netdev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void catc_tx_timeout(struct net_device *netdev)
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index f8c6d7ea7264..ffe410635735 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -780,7 +780,7 @@ static int hso_net_start_xmit(struct sk_buff *skb, struct net_device *net)
netif_stop_queue(net);
if (hso_get_activity(odev->parent) == -EAGAIN) {
odev->skb_tx_buf = skb;
- return 0;
+ return NETDEV_TX_OK;
}
/* log if asked */
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index 1f9ec29fce50..200fe3d525ca 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -829,7 +829,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
kaweth->stats.tx_errors++;
netif_start_queue(net);
spin_unlock_irq(&kaweth->device_lock);
- return 0;
+ return NETDEV_TX_OK;
}
}
@@ -864,7 +864,7 @@ skip:
spin_unlock_irq(&kaweth->device_lock);
- return 0;
+ return NETDEV_TX_OK;
}
/****************************************************************
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index 631d269ac980..69d2df95ac86 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -914,7 +914,7 @@ static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net)
}
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev)
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index fcc6fa0905d1..bac8b77fb25e 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -753,7 +753,7 @@ static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev)
netdev->trans_start = jiffies;
}
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index edfd9e10ceba..25e435c49040 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -575,7 +575,9 @@ EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs);
int usbnet_stop (struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
+ struct driver_info *info = dev->driver_info;
int temp;
+ int retval;
DECLARE_WAIT_QUEUE_HEAD_ONSTACK (unlink_wakeup);
DECLARE_WAITQUEUE (wait, current);
@@ -587,6 +589,18 @@ int usbnet_stop (struct net_device *net)
net->stats.rx_errors, net->stats.tx_errors
);
+ /* allow minidriver to stop correctly (wireless devices to turn off
+ * radio etc) */
+ if (info->stop) {
+ retval = info->stop(dev);
+ if (retval < 0 && netif_msg_ifdown(dev))
+ devinfo(dev,
+ "stop fail (%d) usbnet usb-%s-%s, %s",
+ retval,
+ dev->udev->bus->bus_name, dev->udev->devpath,
+ info->description);
+ }
+
// ensure there are no more active urbs
add_wait_queue (&unlink_wakeup, &wait);
dev->wait = &unlink_wakeup;
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 1097c72e44d5..190f784c9cfe 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -171,6 +171,7 @@ static int veth_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->len > (rcv->mtu + MTU_PAD))
goto rx_drop;
+ skb->tstamp.tv64 = 0;
skb->pkt_type = PACKET_HOST;
skb->protocol = eth_type_trans(skb, rcv);
if (dev->features & NETIF_F_NO_CSUM)
@@ -189,17 +190,17 @@ static int veth_xmit(struct sk_buff *skb, struct net_device *dev)
rcv_stats->rx_packets++;
netif_rx(skb);
- return 0;
+ return NETDEV_TX_OK;
tx_drop:
kfree_skb(skb);
stats->tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
rx_drop:
kfree_skb(skb);
rcv_stats->rx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 88c30a58b4bd..46eb618bbc90 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -1226,7 +1226,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
entry = rp->cur_tx % TX_RING_SIZE;
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
rp->tx_skbuff[entry] = skb;
@@ -1238,7 +1238,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
rp->tx_skbuff[entry] = NULL;
dev->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
/* Padding is not copied and so must be redone. */
@@ -1286,7 +1286,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
dev->name, rp->cur_tx-1, entry);
}
- return 0;
+ return NETDEV_TX_OK;
}
/* The interrupt handler does all of the Rx thread work and cleans up
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 3ba35956327a..47be41a39d35 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -61,9 +61,9 @@
#include <linux/interrupt.h>
#include <linux/string.h>
#include <linux/wait.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/if.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/inetdevice.h>
#include <linux/reboot.h>
@@ -81,7 +81,7 @@
#include "via-velocity.h"
-static int velocity_nics = 0;
+static int velocity_nics;
static int msglevel = MSG_LEVEL_INFO;
/**
@@ -92,8 +92,7 @@ static int msglevel = MSG_LEVEL_INFO;
* Fetch the mask bits of the selected CAM and store them into the
* provided mask buffer.
*/
-
-static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
+static void mac_get_cam_mask(struct mac_regs __iomem *regs, u8 *mask)
{
int i;
@@ -111,7 +110,6 @@ static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
/* Select mar */
BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-
}
@@ -122,8 +120,7 @@ static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
*
* Store a new mask into a CAM
*/
-
-static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
+static void mac_set_cam_mask(struct mac_regs __iomem *regs, u8 *mask)
{
int i;
/* Select CAM mask */
@@ -131,9 +128,9 @@ static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
writeb(CAMADDR_CAMEN, &regs->CAMADDR);
- for (i = 0; i < 8; i++) {
+ for (i = 0; i < 8; i++)
writeb(*mask++, &(regs->MARCAM[i]));
- }
+
/* disable CAMEN */
writeb(0, &regs->CAMADDR);
@@ -141,7 +138,7 @@ static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
}
-static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
+static void mac_set_vlan_cam_mask(struct mac_regs __iomem *regs, u8 *mask)
{
int i;
/* Select CAM mask */
@@ -149,9 +146,9 @@ static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL, &regs->CAMADDR);
- for (i = 0; i < 8; i++) {
+ for (i = 0; i < 8; i++)
writeb(*mask++, &(regs->MARCAM[i]));
- }
+
/* disable CAMEN */
writeb(0, &regs->CAMADDR);
@@ -167,8 +164,7 @@ static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
*
* Load an address or vlan tag into a CAM
*/
-
-static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr)
+static void mac_set_cam(struct mac_regs __iomem *regs, int idx, const u8 *addr)
{
int i;
@@ -179,9 +175,9 @@ static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr)
writeb(CAMADDR_CAMEN | idx, &regs->CAMADDR);
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < 6; i++)
writeb(*addr++, &(regs->MARCAM[i]));
- }
+
BYTE_REG_BITS_ON(CAMCR_CAMWR, &regs->CAMCR);
udelay(10);
@@ -192,7 +188,7 @@ static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr)
BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
}
-static void mac_set_vlan_cam(struct mac_regs __iomem * regs, int idx,
+static void mac_set_vlan_cam(struct mac_regs __iomem *regs, int idx,
const u8 *addr)
{
@@ -223,8 +219,7 @@ static void mac_set_vlan_cam(struct mac_regs __iomem * regs, int idx,
* reset the Wake on lan features. This function doesn't restore
* the rest of the logic from the result of sleep/wakeup
*/
-
-static void mac_wol_reset(struct mac_regs __iomem * regs)
+static void mac_wol_reset(struct mac_regs __iomem *regs)
{
/* Turn off SWPTAG right after leaving power mode */
@@ -242,7 +237,6 @@ static void mac_wol_reset(struct mac_regs __iomem * regs)
writew(0xFFFF, &regs->WOLSRClr);
}
-static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
static const struct ethtool_ops velocity_ethtool_ops;
/*
@@ -253,10 +247,10 @@ MODULE_AUTHOR("VIA Networking Technologies, Inc.");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("VIA Networking Velocity Family Gigabit Ethernet Adapter Driver");
-#define VELOCITY_PARAM(N,D) \
- static int N[MAX_UNITS]=OPTION_DEFAULT;\
+#define VELOCITY_PARAM(N, D) \
+ static int N[MAX_UNITS] = OPTION_DEFAULT;\
module_param_array(N, int, NULL, 0); \
- MODULE_PARM_DESC(N, D);
+ MODULE_PARM_DESC(N, D);
#define RX_DESC_MIN 64
#define RX_DESC_MAX 255
@@ -336,8 +330,8 @@ VELOCITY_PARAM(flow_control, "Enable flow control ability");
4: indicate 10Mbps full duplex mode
Note:
- if EEPROM have been set to the force mode, this option is ignored
- by driver.
+ if EEPROM have been set to the force mode, this option is ignored
+ by driver.
*/
VELOCITY_PARAM(speed_duplex, "Setting the speed and duplex mode");
@@ -370,76 +364,14 @@ static int rx_copybreak = 200;
module_param(rx_copybreak, int, 0644);
MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames");
-static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr,
- const struct velocity_info_tbl *info);
-static int velocity_get_pci_info(struct velocity_info *, struct pci_dev *pdev);
-static void velocity_print_info(struct velocity_info *vptr);
-static int velocity_open(struct net_device *dev);
-static int velocity_change_mtu(struct net_device *dev, int mtu);
-static int velocity_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t velocity_intr(int irq, void *dev_instance);
-static void velocity_set_multi(struct net_device *dev);
-static struct net_device_stats *velocity_get_stats(struct net_device *dev);
-static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static int velocity_close(struct net_device *dev);
-static int velocity_receive_frame(struct velocity_info *, int idx);
-static int velocity_alloc_rx_buf(struct velocity_info *, int idx);
-static void velocity_free_rd_ring(struct velocity_info *vptr);
-static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *);
-static int velocity_soft_reset(struct velocity_info *vptr);
-static void mii_init(struct velocity_info *vptr, u32 mii_status);
-static u32 velocity_get_link(struct net_device *dev);
-static u32 velocity_get_opt_media_mode(struct velocity_info *vptr);
-static void velocity_print_link_status(struct velocity_info *vptr);
-static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs);
-static void velocity_shutdown(struct velocity_info *vptr);
-static void enable_flow_control_ability(struct velocity_info *vptr);
-static void enable_mii_autopoll(struct mac_regs __iomem * regs);
-static int velocity_mii_read(struct mac_regs __iomem *, u8 byIdx, u16 * pdata);
-static int velocity_mii_write(struct mac_regs __iomem *, u8 byMiiAddr, u16 data);
-static u32 mii_check_media_mode(struct mac_regs __iomem * regs);
-static u32 check_connection_type(struct mac_regs __iomem * regs);
-static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status);
-
#ifdef CONFIG_PM
-
-static int velocity_suspend(struct pci_dev *pdev, pm_message_t state);
-static int velocity_resume(struct pci_dev *pdev);
-
static DEFINE_SPINLOCK(velocity_dev_list_lock);
static LIST_HEAD(velocity_dev_list);
-
-#endif
-
-#if defined(CONFIG_PM) && defined(CONFIG_INET)
-
-static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr);
-
-static struct notifier_block velocity_inetaddr_notifier = {
- .notifier_call = velocity_netdev_event,
-};
-
-static void velocity_register_notifier(void)
-{
- register_inetaddr_notifier(&velocity_inetaddr_notifier);
-}
-
-static void velocity_unregister_notifier(void)
-{
- unregister_inetaddr_notifier(&velocity_inetaddr_notifier);
-}
-
-#else
-
-#define velocity_register_notifier() do {} while (0)
-#define velocity_unregister_notifier() do {} while (0)
-
#endif
/*
* Internal board variants. At the moment we have only one
*/
-
static struct velocity_info_tbl chip_info_table[] = {
{CHIP_TYPE_VT6110, "VIA Networking Velocity Family Gigabit Ethernet Adapter", 1, 0x00FFFFFFUL},
{ }
@@ -449,7 +381,6 @@ static struct velocity_info_tbl chip_info_table[] = {
* Describe the PCI device identifiers that we support in this
* device driver. Used for hotplug autoloading.
*/
-
static const struct pci_device_id velocity_id_table[] __devinitdata = {
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X) },
{ }
@@ -464,7 +395,6 @@ MODULE_DEVICE_TABLE(pci, velocity_id_table);
* Given a chip identifier return a suitable description. Returns
* a pointer a static string valid while the driver is loaded.
*/
-
static const char __devinit *get_chip_name(enum chip_type chip_id)
{
int i;
@@ -482,7 +412,6 @@ static const char __devinit *get_chip_name(enum chip_type chip_id)
* unload for each active device that is present. Disconnects
* the device from the network layer and frees all the resources
*/
-
static void __devexit velocity_remove1(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
@@ -520,7 +449,6 @@ static void __devexit velocity_remove1(struct pci_dev *pdev)
* all the verification and checking as well as reporting so that
* we don't duplicate code for each option.
*/
-
static void __devinit velocity_set_int_opt(int *opt, int val, int min, int max, int def, char *name, const char *devname)
{
if (val == -1)
@@ -549,8 +477,7 @@ static void __devinit velocity_set_int_opt(int *opt, int val, int min, int max,
* all the verification and checking as well as reporting so that
* we don't duplicate code for each option.
*/
-
-static void __devinit velocity_set_bool_opt(u32 * opt, int val, int def, u32 flag, char *name, const char *devname)
+static void __devinit velocity_set_bool_opt(u32 *opt, int val, int def, u32 flag, char *name, const char *devname)
{
(*opt) &= (~flag);
if (val == -1)
@@ -575,7 +502,6 @@ static void __devinit velocity_set_bool_opt(u32 * opt, int val, int def, u32 fla
* Turn the module and command options into a single structure
* for the current device
*/
-
static void __devinit velocity_get_options(struct velocity_opt *opts, int index, const char *devname)
{
@@ -601,10 +527,9 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index,
* Initialize the content addressable memory used for filters. Load
* appropriately according to the presence of VLAN
*/
-
static void velocity_init_cam_filter(struct velocity_info *vptr)
{
- struct mac_regs __iomem * regs = vptr->mac_regs;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
/* Turn on MCFG_PQEN, turn off MCFG_RTGOPT */
WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, &regs->MCFG);
@@ -647,19 +572,19 @@ static void velocity_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
{
struct velocity_info *vptr = netdev_priv(dev);
- spin_lock_irq(&vptr->lock);
+ spin_lock_irq(&vptr->lock);
velocity_init_cam_filter(vptr);
- spin_unlock_irq(&vptr->lock);
+ spin_unlock_irq(&vptr->lock);
}
static void velocity_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
{
struct velocity_info *vptr = netdev_priv(dev);
- spin_lock_irq(&vptr->lock);
+ spin_lock_irq(&vptr->lock);
vlan_group_set_device(vptr->vlgrp, vid, NULL);
velocity_init_cam_filter(vptr);
- spin_unlock_irq(&vptr->lock);
+ spin_unlock_irq(&vptr->lock);
}
static void velocity_init_rx_ring_indexes(struct velocity_info *vptr)
@@ -674,11 +599,10 @@ static void velocity_init_rx_ring_indexes(struct velocity_info *vptr)
* Reset the ownership and status for the receive ring side.
* Hand all the receive queue to the NIC.
*/
-
static void velocity_rx_reset(struct velocity_info *vptr)
{
- struct mac_regs __iomem * regs = vptr->mac_regs;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
int i;
velocity_init_rx_ring_indexes(vptr);
@@ -696,6 +620,647 @@ static void velocity_rx_reset(struct velocity_info *vptr)
}
/**
+ * velocity_get_opt_media_mode - get media selection
+ * @vptr: velocity adapter
+ *
+ * Get the media mode stored in EEPROM or module options and load
+ * mii_status accordingly. The requested link state information
+ * is also returned.
+ */
+static u32 velocity_get_opt_media_mode(struct velocity_info *vptr)
+{
+ u32 status = 0;
+
+ switch (vptr->options.spd_dpx) {
+ case SPD_DPX_AUTO:
+ status = VELOCITY_AUTONEG_ENABLE;
+ break;
+ case SPD_DPX_100_FULL:
+ status = VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL;
+ break;
+ case SPD_DPX_10_FULL:
+ status = VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL;
+ break;
+ case SPD_DPX_100_HALF:
+ status = VELOCITY_SPEED_100;
+ break;
+ case SPD_DPX_10_HALF:
+ status = VELOCITY_SPEED_10;
+ break;
+ }
+ vptr->mii_status = status;
+ return status;
+}
+
+/**
+ * safe_disable_mii_autopoll - autopoll off
+ * @regs: velocity registers
+ *
+ * Turn off the autopoll and wait for it to disable on the chip
+ */
+static void safe_disable_mii_autopoll(struct mac_regs __iomem *regs)
+{
+ u16 ww;
+
+ /* turn off MAUTO */
+ writeb(0, &regs->MIICR);
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ udelay(1);
+ if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+ break;
+ }
+}
+
+/**
+ * enable_mii_autopoll - turn on autopolling
+ * @regs: velocity registers
+ *
+ * Enable the MII link status autopoll feature on the Velocity
+ * hardware. Wait for it to enable.
+ */
+static void enable_mii_autopoll(struct mac_regs __iomem *regs)
+{
+ int ii;
+
+ writeb(0, &(regs->MIICR));
+ writeb(MIIADR_SWMPL, &regs->MIIADR);
+
+ for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
+ udelay(1);
+ if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+ break;
+ }
+
+ writeb(MIICR_MAUTO, &regs->MIICR);
+
+ for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
+ udelay(1);
+ if (!BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+ break;
+ }
+
+}
+
+/**
+ * velocity_mii_read - read MII data
+ * @regs: velocity registers
+ * @index: MII register index
+ * @data: buffer for received data
+ *
+ * Perform a single read of an MII 16bit register. Returns zero
+ * on success or -ETIMEDOUT if the PHY did not respond.
+ */
+static int velocity_mii_read(struct mac_regs __iomem *regs, u8 index, u16 *data)
+{
+ u16 ww;
+
+ /*
+ * Disable MIICR_MAUTO, so that mii addr can be set normally
+ */
+ safe_disable_mii_autopoll(regs);
+
+ writeb(index, &regs->MIIADR);
+
+ BYTE_REG_BITS_ON(MIICR_RCMD, &regs->MIICR);
+
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ if (!(readb(&regs->MIICR) & MIICR_RCMD))
+ break;
+ }
+
+ *data = readw(&regs->MIIDATA);
+
+ enable_mii_autopoll(regs);
+ if (ww == W_MAX_TIMEOUT)
+ return -ETIMEDOUT;
+ return 0;
+}
+
+
+/**
+ * mii_check_media_mode - check media state
+ * @regs: velocity registers
+ *
+ * Check the current MII status and determine the link status
+ * accordingly
+ */
+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))
+ status |= VELOCITY_LINK_FAIL;
+
+ if (MII_REG_BITS_IS_ON(G1000CR_1000FD, MII_REG_G1000CR, regs))
+ status |= VELOCITY_SPEED_1000 | VELOCITY_DUPLEX_FULL;
+ else if (MII_REG_BITS_IS_ON(G1000CR_1000, MII_REG_G1000CR, regs))
+ status |= (VELOCITY_SPEED_1000);
+ else {
+ velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+ if (ANAR & ANAR_TXFD)
+ status |= (VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL);
+ else if (ANAR & ANAR_TX)
+ status |= VELOCITY_SPEED_100;
+ else if (ANAR & ANAR_10FD)
+ 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))
+ status |= VELOCITY_AUTONEG_ENABLE;
+ }
+ }
+
+ return status;
+}
+
+/**
+ * velocity_mii_write - write MII data
+ * @regs: velocity registers
+ * @index: MII register index
+ * @data: 16bit data for the MII register
+ *
+ * Perform a single write to an MII 16bit register. Returns zero
+ * on success or -ETIMEDOUT if the PHY did not respond.
+ */
+static int velocity_mii_write(struct mac_regs __iomem *regs, u8 mii_addr, u16 data)
+{
+ u16 ww;
+
+ /*
+ * Disable MIICR_MAUTO, so that mii addr can be set normally
+ */
+ safe_disable_mii_autopoll(regs);
+
+ /* MII reg offset */
+ writeb(mii_addr, &regs->MIIADR);
+ /* set MII data */
+ writew(data, &regs->MIIDATA);
+
+ /* turn on MIICR_WCMD */
+ BYTE_REG_BITS_ON(MIICR_WCMD, &regs->MIICR);
+
+ /* W_MAX_TIMEOUT is the timeout period */
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ udelay(5);
+ if (!(readb(&regs->MIICR) & MIICR_WCMD))
+ break;
+ }
+ enable_mii_autopoll(regs);
+
+ if (ww == W_MAX_TIMEOUT)
+ return -ETIMEDOUT;
+ return 0;
+}
+
+/**
+ * set_mii_flow_control - flow control setup
+ * @vptr: velocity interface
+ *
+ * Set up the flow control on this interface according to
+ * the supplied user/eeprom options.
+ */
+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);
+ 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);
+ break;
+
+ case FLOW_CNTL_TX_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);
+ 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);
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * mii_set_auto_on - autonegotiate on
+ * @vptr: velocity
+ *
+ * Enable autonegotation on this interface
+ */
+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);
+ else
+ MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
+}
+
+static u32 check_connection_type(struct mac_regs __iomem *regs)
+{
+ u32 status = 0;
+ u8 PHYSR0;
+ u16 ANAR;
+ PHYSR0 = readb(&regs->PHYSR0);
+
+ /*
+ if (!(PHYSR0 & PHYSR0_LINKGD))
+ status|=VELOCITY_LINK_FAIL;
+ */
+
+ if (PHYSR0 & PHYSR0_FDPX)
+ status |= VELOCITY_DUPLEX_FULL;
+
+ if (PHYSR0 & PHYSR0_SPDG)
+ status |= VELOCITY_SPEED_1000;
+ else if (PHYSR0 & PHYSR0_SPD10)
+ status |= VELOCITY_SPEED_10;
+ 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))
+ status |= VELOCITY_AUTONEG_ENABLE;
+ }
+ }
+
+ return status;
+}
+
+
+
+/**
+ * velocity_set_media_mode - set media mode
+ * @mii_status: old MII link state
+ *
+ * Check the media link state and configure the flow control
+ * PHY and also velocity hardware setup accordingly. In particular
+ * we need to set up CD polling and frame bursting.
+ */
+static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
+{
+ u32 curr_status;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+
+ vptr->mii_status = mii_check_media_mode(vptr->mac_regs);
+ curr_status = vptr->mii_status & (~VELOCITY_LINK_FAIL);
+
+ /* Set mii link status */
+ set_mii_flow_control(vptr);
+
+ /*
+ Check if new status is consisent with current status
+ if (((mii_status & curr_status) & VELOCITY_AUTONEG_ENABLE)
+ || (mii_status==curr_status)) {
+ vptr->mii_status=mii_check_media_mode(vptr->mac_regs);
+ vptr->mii_status=check_connection_type(vptr->mac_regs);
+ VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity link no change\n");
+ return 0;
+ }
+ */
+
+ if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201)
+ MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs);
+
+ /*
+ * If connection type is AUTO
+ */
+ if (mii_status & VELOCITY_AUTONEG_ENABLE) {
+ VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity is AUTO mode\n");
+ /* 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);
+
+ /* enable AUTO-NEGO mode */
+ mii_set_auto_on(vptr);
+ } else {
+ u16 ANAR;
+ u8 CHIPGCR;
+
+ /*
+ * 1. if it's 3119, disable frame bursting in halfduplex mode
+ * and enable it in fullduplex mode
+ * 2. set correct MII/GMII and half/full duplex mode in CHIPGCR
+ * 3. only enable CD heart beat counter in 10HD mode
+ */
+
+ /* set force MAC mode bit */
+ BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
+
+ CHIPGCR = readb(&regs->CHIPGCR);
+ CHIPGCR &= ~CHIPGCR_FCGMII;
+
+ if (mii_status & VELOCITY_DUPLEX_FULL) {
+ CHIPGCR |= CHIPGCR_FCFDX;
+ writeb(CHIPGCR, &regs->CHIPGCR);
+ VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced full mode\n");
+ if (vptr->rev_id < REV_ID_VT3216_A0)
+ BYTE_REG_BITS_OFF(TCR_TB2BDIS, &regs->TCR);
+ } else {
+ CHIPGCR &= ~CHIPGCR_FCFDX;
+ VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced half mode\n");
+ writeb(CHIPGCR, &regs->CHIPGCR);
+ if (vptr->rev_id < REV_ID_VT3216_A0)
+ BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
+ }
+
+ MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, 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));
+ if (mii_status & VELOCITY_SPEED_100) {
+ if (mii_status & VELOCITY_DUPLEX_FULL)
+ ANAR |= ANAR_TXFD;
+ else
+ ANAR |= ANAR_TX;
+ } else {
+ if (mii_status & VELOCITY_DUPLEX_FULL)
+ ANAR |= ANAR_10FD;
+ else
+ ANAR |= ANAR_10;
+ }
+ velocity_mii_write(vptr->mac_regs, MII_REG_ANAR, ANAR);
+ /* enable AUTO-NEGO mode */
+ mii_set_auto_on(vptr);
+ /* MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); */
+ }
+ /* vptr->mii_status=mii_check_media_mode(vptr->mac_regs); */
+ /* vptr->mii_status=check_connection_type(vptr->mac_regs); */
+ return VELOCITY_LINK_CHANGE;
+}
+
+/**
+ * velocity_print_link_status - link status reporting
+ * @vptr: velocity to report on
+ *
+ * Turn the link status of the velocity card into a kernel log
+ * description of the new link state, detailing speed and duplex
+ * status
+ */
+static void velocity_print_link_status(struct velocity_info *vptr)
+{
+
+ if (vptr->mii_status & VELOCITY_LINK_FAIL) {
+ VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: failed to detect cable link\n", vptr->dev->name);
+ } else if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
+ VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link auto-negotiation", vptr->dev->name);
+
+ if (vptr->mii_status & VELOCITY_SPEED_1000)
+ VELOCITY_PRT(MSG_LEVEL_INFO, " speed 1000M bps");
+ else if (vptr->mii_status & VELOCITY_SPEED_100)
+ VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps");
+ else
+ VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps");
+
+ if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+ VELOCITY_PRT(MSG_LEVEL_INFO, " full duplex\n");
+ else
+ VELOCITY_PRT(MSG_LEVEL_INFO, " half duplex\n");
+ } else {
+ VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced", vptr->dev->name);
+ switch (vptr->options.spd_dpx) {
+ case SPD_DPX_100_HALF:
+ VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps half duplex\n");
+ break;
+ case SPD_DPX_100_FULL:
+ VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps full duplex\n");
+ break;
+ case SPD_DPX_10_HALF:
+ VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps half duplex\n");
+ break;
+ case SPD_DPX_10_FULL:
+ VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps full duplex\n");
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/**
+ * enable_flow_control_ability - flow control
+ * @vptr: veloity to configure
+ *
+ * Set up flow control according to the flow control options
+ * determined by the eeprom/configuration.
+ */
+static void enable_flow_control_ability(struct velocity_info *vptr)
+{
+
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+
+ switch (vptr->options.flow_cntl) {
+
+ case FLOW_CNTL_DEFAULT:
+ if (BYTE_REG_BITS_IS_ON(PHYSR0_RXFLC, &regs->PHYSR0))
+ writel(CR0_FDXRFCEN, &regs->CR0Set);
+ else
+ writel(CR0_FDXRFCEN, &regs->CR0Clr);
+
+ if (BYTE_REG_BITS_IS_ON(PHYSR0_TXFLC, &regs->PHYSR0))
+ writel(CR0_FDXTFCEN, &regs->CR0Set);
+ else
+ writel(CR0_FDXTFCEN, &regs->CR0Clr);
+ break;
+
+ case FLOW_CNTL_TX:
+ writel(CR0_FDXTFCEN, &regs->CR0Set);
+ writel(CR0_FDXRFCEN, &regs->CR0Clr);
+ break;
+
+ case FLOW_CNTL_RX:
+ writel(CR0_FDXRFCEN, &regs->CR0Set);
+ writel(CR0_FDXTFCEN, &regs->CR0Clr);
+ break;
+
+ case FLOW_CNTL_TX_RX:
+ writel(CR0_FDXTFCEN, &regs->CR0Set);
+ writel(CR0_FDXRFCEN, &regs->CR0Set);
+ break;
+
+ case FLOW_CNTL_DISABLE:
+ writel(CR0_FDXRFCEN, &regs->CR0Clr);
+ writel(CR0_FDXTFCEN, &regs->CR0Clr);
+ break;
+
+ default:
+ break;
+ }
+
+}
+
+/**
+ * velocity_soft_reset - soft reset
+ * @vptr: velocity to reset
+ *
+ * Kick off a soft reset of the velocity adapter and then poll
+ * until the reset sequence has completed before returning.
+ */
+static int velocity_soft_reset(struct velocity_info *vptr)
+{
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ int i = 0;
+
+ writel(CR0_SFRST, &regs->CR0Set);
+
+ for (i = 0; i < W_MAX_TIMEOUT; i++) {
+ udelay(5);
+ if (!DWORD_REG_BITS_IS_ON(CR0_SFRST, &regs->CR0Set))
+ break;
+ }
+
+ if (i == W_MAX_TIMEOUT) {
+ writel(CR0_FORSRST, &regs->CR0Set);
+ /* FIXME: PCI POSTING */
+ /* delay 2ms */
+ mdelay(2);
+ }
+ return 0;
+}
+
+/**
+ * velocity_set_multi - filter list change callback
+ * @dev: network device
+ *
+ * Called by the network layer when the filter lists need to change
+ * for a velocity adapter. Reload the CAMs with the new address
+ * filter ruleset.
+ */
+static void velocity_set_multi(struct net_device *dev)
+{
+ struct velocity_info *vptr = netdev_priv(dev);
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ u8 rx_mode;
+ int i;
+ struct dev_mc_list *mclist;
+
+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+ writel(0xffffffff, &regs->MARCAM[0]);
+ writel(0xffffffff, &regs->MARCAM[4]);
+ rx_mode = (RCR_AM | RCR_AB | RCR_PROM);
+ } else if ((dev->mc_count > vptr->multicast_limit)
+ || (dev->flags & IFF_ALLMULTI)) {
+ writel(0xffffffff, &regs->MARCAM[0]);
+ writel(0xffffffff, &regs->MARCAM[4]);
+ rx_mode = (RCR_AM | RCR_AB);
+ } else {
+ int offset = MCAM_SIZE - vptr->multicast_limit;
+ mac_get_cam_mask(regs, vptr->mCAMmask);
+
+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) {
+ mac_set_cam(regs, i + offset, mclist->dmi_addr);
+ vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7);
+ }
+
+ mac_set_cam_mask(regs, vptr->mCAMmask);
+ rx_mode = RCR_AM | RCR_AB | RCR_AP;
+ }
+ if (dev->mtu > 1500)
+ rx_mode |= RCR_AL;
+
+ BYTE_REG_BITS_ON(rx_mode, &regs->RCR);
+
+}
+
+/*
+ * MII access , media link mode setting functions
+ */
+
+/**
+ * mii_init - set up MII
+ * @vptr: velocity adapter
+ * @mii_status: links tatus
+ *
+ * Set up the PHY for the current link state.
+ */
+static void mii_init(struct velocity_info *vptr, u32 mii_status)
+{
+ u16 BMCR;
+
+ switch (PHYID_GET_PHY_ID(vptr->phy_id)) {
+ case PHYID_CICADA_CS8201:
+ /*
+ * Reset to hardware default
+ */
+ MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, 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);
+ else
+ MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+ /*
+ * Turn on Link/Activity LED enable bit for CIS8201
+ */
+ MII_REG_BITS_ON(PLED_LALBE, MII_REG_PLED, 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);
+ /*
+ * 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);
+ else
+ MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+ break;
+
+ case PHYID_MARVELL_1000:
+ case PHYID_MARVELL_1000S:
+ /*
+ * Assert CRS on Transmit
+ */
+ MII_REG_BITS_ON(PSCR_ACRSTX, MII_REG_PSCR, vptr->mac_regs);
+ /*
+ * Reset to hardware default
+ */
+ MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, 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_init_registers - initialise MAC registers
* @vptr: velocity to init
* @type: type of initialisation (hot or cold)
@@ -703,11 +1268,10 @@ static void velocity_rx_reset(struct velocity_info *vptr)
* Initialise the MAC on a reset or on first set up on the
* hardware.
*/
-
static void velocity_init_registers(struct velocity_info *vptr,
enum velocity_init_type type)
{
- struct mac_regs __iomem * regs = vptr->mac_regs;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
int i, mii_status;
mac_wol_reset(regs);
@@ -750,9 +1314,9 @@ static void velocity_init_registers(struct velocity_info *vptr,
mdelay(5);
mac_eeprom_reload(regs);
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < 6; i++)
writeb(vptr->dev->dev_addr[i], &(regs->PAR[i]));
- }
+
/*
* clear Pre_ACPI bit.
*/
@@ -819,291 +1383,29 @@ static void velocity_init_registers(struct velocity_info *vptr,
}
}
-/**
- * velocity_soft_reset - soft reset
- * @vptr: velocity to reset
- *
- * Kick off a soft reset of the velocity adapter and then poll
- * until the reset sequence has completed before returning.
- */
-
-static int velocity_soft_reset(struct velocity_info *vptr)
-{
- struct mac_regs __iomem * regs = vptr->mac_regs;
- int i = 0;
-
- writel(CR0_SFRST, &regs->CR0Set);
-
- for (i = 0; i < W_MAX_TIMEOUT; i++) {
- udelay(5);
- if (!DWORD_REG_BITS_IS_ON(CR0_SFRST, &regs->CR0Set))
- break;
- }
-
- if (i == W_MAX_TIMEOUT) {
- writel(CR0_FORSRST, &regs->CR0Set);
- /* FIXME: PCI POSTING */
- /* delay 2ms */
- mdelay(2);
- }
- return 0;
-}
-
-static const struct net_device_ops velocity_netdev_ops = {
- .ndo_open = velocity_open,
- .ndo_stop = velocity_close,
- .ndo_start_xmit = velocity_xmit,
- .ndo_get_stats = velocity_get_stats,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_set_multicast_list = velocity_set_multi,
- .ndo_change_mtu = velocity_change_mtu,
- .ndo_do_ioctl = velocity_ioctl,
- .ndo_vlan_rx_add_vid = velocity_vlan_rx_add_vid,
- .ndo_vlan_rx_kill_vid = velocity_vlan_rx_kill_vid,
- .ndo_vlan_rx_register = velocity_vlan_rx_register,
-};
-
-/**
- * velocity_found1 - set up discovered velocity card
- * @pdev: PCI device
- * @ent: PCI device table entry that matched
- *
- * Configure a discovered adapter from scratch. Return a negative
- * errno error code on failure paths.
- */
-
-static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent)
+static void velocity_give_many_rx_descs(struct velocity_info *vptr)
{
- static int first = 1;
- struct net_device *dev;
- int i;
- const char *drv_string;
- const struct velocity_info_tbl *info = &chip_info_table[ent->driver_data];
- struct velocity_info *vptr;
- struct mac_regs __iomem * regs;
- int ret = -ENOMEM;
-
- /* FIXME: this driver, like almost all other ethernet drivers,
- * can support more than MAX_UNITS.
- */
- if (velocity_nics >= MAX_UNITS) {
- dev_notice(&pdev->dev, "already found %d NICs.\n",
- velocity_nics);
- return -ENODEV;
- }
-
- dev = alloc_etherdev(sizeof(struct velocity_info));
- if (!dev) {
- dev_err(&pdev->dev, "allocate net device failed.\n");
- goto out;
- }
-
- /* Chain it all together */
-
- SET_NETDEV_DEV(dev, &pdev->dev);
- vptr = netdev_priv(dev);
-
-
- if (first) {
- printk(KERN_INFO "%s Ver. %s\n",
- VELOCITY_FULL_DRV_NAM, VELOCITY_VERSION);
- printk(KERN_INFO "Copyright (c) 2002, 2003 VIA Networking Technologies, Inc.\n");
- printk(KERN_INFO "Copyright (c) 2004 Red Hat Inc.\n");
- first = 0;
- }
-
- velocity_init_info(pdev, vptr, info);
-
- vptr->dev = dev;
-
- dev->irq = pdev->irq;
-
- ret = pci_enable_device(pdev);
- if (ret < 0)
- goto err_free_dev;
-
- ret = velocity_get_pci_info(vptr, pdev);
- if (ret < 0) {
- /* error message already printed */
- goto err_disable;
- }
-
- ret = pci_request_regions(pdev, VELOCITY_NAME);
- if (ret < 0) {
- dev_err(&pdev->dev, "No PCI resources.\n");
- goto err_disable;
- }
-
- regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE);
- if (regs == NULL) {
- ret = -EIO;
- goto err_release_res;
- }
-
- vptr->mac_regs = regs;
-
- mac_wol_reset(regs);
-
- dev->base_addr = vptr->ioaddr;
-
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = readb(&regs->PAR[i]);
-
-
- drv_string = dev_driver_string(&pdev->dev);
-
- velocity_get_options(&vptr->options, velocity_nics, drv_string);
-
- /*
- * Mask out the options cannot be set to the chip
- */
-
- vptr->options.flags &= info->flags;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ int avail, dirty, unusable;
/*
- * Enable the chip specified capbilities
+ * RD number must be equal to 4X per hardware spec
+ * (programming guide rev 1.20, p.13)
*/
+ if (vptr->rx.filled < 4)
+ return;
- vptr->flags = vptr->options.flags | (info->flags & 0xFF000000UL);
-
- vptr->wol_opts = vptr->options.wol_opts;
- vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
-
- vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs);
-
- dev->irq = pdev->irq;
- dev->netdev_ops = &velocity_netdev_ops;
- dev->ethtool_ops = &velocity_ethtool_ops;
-
-#ifdef VELOCITY_ZERO_COPY_SUPPORT
- dev->features |= NETIF_F_SG;
-#endif
- dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER |
- NETIF_F_HW_VLAN_RX;
-
- if (vptr->flags & VELOCITY_FLAGS_TX_CSUM)
- dev->features |= NETIF_F_IP_CSUM;
-
- ret = register_netdev(dev);
- if (ret < 0)
- goto err_iounmap;
-
- if (!velocity_get_link(dev)) {
- netif_carrier_off(dev);
- vptr->mii_status |= VELOCITY_LINK_FAIL;
- }
-
- velocity_print_info(vptr);
- pci_set_drvdata(pdev, dev);
-
- /* and leave the chip powered down */
-
- pci_set_power_state(pdev, PCI_D3hot);
-#ifdef CONFIG_PM
- {
- unsigned long flags;
-
- spin_lock_irqsave(&velocity_dev_list_lock, flags);
- list_add(&vptr->list, &velocity_dev_list);
- spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
- }
-#endif
- velocity_nics++;
-out:
- return ret;
-
-err_iounmap:
- iounmap(regs);
-err_release_res:
- pci_release_regions(pdev);
-err_disable:
- pci_disable_device(pdev);
-err_free_dev:
- free_netdev(dev);
- goto out;
-}
-
-/**
- * velocity_print_info - per driver data
- * @vptr: velocity
- *
- * Print per driver data as the kernel driver finds Velocity
- * hardware
- */
-
-static void __devinit velocity_print_info(struct velocity_info *vptr)
-{
- struct net_device *dev = vptr->dev;
-
- printk(KERN_INFO "%s: %s\n", dev->name, get_chip_name(vptr->chip_id));
- printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
- dev->name,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
-}
-
-/**
- * velocity_init_info - init private data
- * @pdev: PCI device
- * @vptr: Velocity info
- * @info: Board type
- *
- * Set up the initial velocity_info struct for the device that has been
- * discovered.
- */
-
-static void __devinit velocity_init_info(struct pci_dev *pdev,
- struct velocity_info *vptr,
- const struct velocity_info_tbl *info)
-{
- memset(vptr, 0, sizeof(struct velocity_info));
-
- vptr->pdev = pdev;
- vptr->chip_id = info->chip_id;
- vptr->tx.numq = info->txqueue;
- vptr->multicast_limit = MCAM_SIZE;
- spin_lock_init(&vptr->lock);
- INIT_LIST_HEAD(&vptr->list);
-}
-
-/**
- * velocity_get_pci_info - retrieve PCI info for device
- * @vptr: velocity device
- * @pdev: PCI device it matches
- *
- * Retrieve the PCI configuration space data that interests us from
- * the kernel PCI layer
- */
-
-static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pci_dev *pdev)
-{
- vptr->rev_id = pdev->revision;
-
- pci_set_master(pdev);
-
- vptr->ioaddr = pci_resource_start(pdev, 0);
- vptr->memaddr = pci_resource_start(pdev, 1);
-
- if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
- dev_err(&pdev->dev,
- "region #0 is not an I/O resource, aborting.\n");
- return -EINVAL;
- }
-
- if ((pci_resource_flags(pdev, 1) & IORESOURCE_IO)) {
- dev_err(&pdev->dev,
- "region #1 is an I/O resource, aborting.\n");
- return -EINVAL;
- }
+ wmb();
- if (pci_resource_len(pdev, 1) < VELOCITY_IO_SIZE) {
- dev_err(&pdev->dev, "region #1 is too small.\n");
- return -EINVAL;
+ unusable = vptr->rx.filled & 0x0003;
+ dirty = vptr->rx.dirty - unusable;
+ for (avail = vptr->rx.filled & 0xfffc; avail; avail--) {
+ dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1;
+ vptr->rx.ring[dirty].rdesc0.len |= OWNED_BY_NIC;
}
- vptr->pdev = pdev;
- return 0;
+ writew(vptr->rx.filled & 0xfffc, &regs->RBRDU);
+ vptr->rx.filled = unusable;
}
/**
@@ -1113,7 +1415,6 @@ static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pc
* Allocate PCI mapped DMA rings for the receive and transmit layer
* to use.
*/
-
static int velocity_init_dma_rings(struct velocity_info *vptr)
{
struct velocity_opt *opt = &vptr->options;
@@ -1154,46 +1455,50 @@ static int velocity_init_dma_rings(struct velocity_info *vptr)
return 0;
}
+static void velocity_set_rxbufsize(struct velocity_info *vptr, int mtu)
+{
+ vptr->rx.buf_sz = (mtu <= ETH_DATA_LEN) ? PKT_BUF_SZ : mtu + 32;
+}
+
/**
- * velocity_free_dma_rings - free PCI ring pointers
- * @vptr: Velocity to free from
+ * velocity_alloc_rx_buf - allocate aligned receive buffer
+ * @vptr: velocity
+ * @idx: ring index
*
- * Clean up the PCI ring buffers allocated to this velocity.
+ * Allocate a new full sized buffer for the reception of a frame and
+ * map it into PCI space for the hardware to use. The hardware
+ * requires *64* byte alignment of the buffer which makes life
+ * less fun than would be ideal.
*/
-
-static void velocity_free_dma_rings(struct velocity_info *vptr)
+static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx)
{
- const int size = vptr->options.numrx * sizeof(struct rx_desc) +
- vptr->options.numtx * sizeof(struct tx_desc) * vptr->tx.numq;
-
- pci_free_consistent(vptr->pdev, size, vptr->rx.ring, vptr->rx.pool_dma);
-}
+ struct rx_desc *rd = &(vptr->rx.ring[idx]);
+ struct velocity_rd_info *rd_info = &(vptr->rx.info[idx]);
-static void velocity_give_many_rx_descs(struct velocity_info *vptr)
-{
- struct mac_regs __iomem *regs = vptr->mac_regs;
- int avail, dirty, unusable;
+ rd_info->skb = dev_alloc_skb(vptr->rx.buf_sz + 64);
+ if (rd_info->skb == NULL)
+ return -ENOMEM;
/*
- * RD number must be equal to 4X per hardware spec
- * (programming guide rev 1.20, p.13)
+ * Do the gymnastics to get the buffer head for data at
+ * 64byte alignment.
*/
- if (vptr->rx.filled < 4)
- return;
-
- wmb();
+ skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->data & 63);
+ rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->data,
+ vptr->rx.buf_sz, PCI_DMA_FROMDEVICE);
- unusable = vptr->rx.filled & 0x0003;
- dirty = vptr->rx.dirty - unusable;
- for (avail = vptr->rx.filled & 0xfffc; avail; avail--) {
- dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1;
- vptr->rx.ring[dirty].rdesc0.len |= OWNED_BY_NIC;
- }
+ /*
+ * Fill in the descriptor to match
+ */
- writew(vptr->rx.filled & 0xfffc, &regs->RBRDU);
- vptr->rx.filled = unusable;
+ *((u32 *) & (rd->rdesc0)) = 0;
+ rd->size = cpu_to_le16(vptr->rx.buf_sz) | RX_INTEN;
+ rd->pa_low = cpu_to_le32(rd_info->skb_dma);
+ rd->pa_high = 0;
+ return 0;
}
+
static int velocity_rx_refill(struct velocity_info *vptr)
{
int dirty = vptr->rx.dirty, done = 0;
@@ -1221,42 +1526,6 @@ static int velocity_rx_refill(struct velocity_info *vptr)
return done;
}
-static void velocity_set_rxbufsize(struct velocity_info *vptr, int mtu)
-{
- vptr->rx.buf_sz = (mtu <= ETH_DATA_LEN) ? PKT_BUF_SZ : mtu + 32;
-}
-
-/**
- * velocity_init_rd_ring - set up receive ring
- * @vptr: velocity to configure
- *
- * Allocate and set up the receive buffers for each ring slot and
- * assign them to the network adapter.
- */
-
-static int velocity_init_rd_ring(struct velocity_info *vptr)
-{
- int ret = -ENOMEM;
-
- vptr->rx.info = kcalloc(vptr->options.numrx,
- sizeof(struct velocity_rd_info), GFP_KERNEL);
- if (!vptr->rx.info)
- goto out;
-
- velocity_init_rx_ring_indexes(vptr);
-
- if (velocity_rx_refill(vptr) != vptr->options.numrx) {
- VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR
- "%s: failed to allocate RX buffer.\n", vptr->dev->name);
- velocity_free_rd_ring(vptr);
- goto out;
- }
-
- ret = 0;
-out:
- return ret;
-}
-
/**
* velocity_free_rd_ring - free receive ring
* @vptr: velocity to clean up
@@ -1264,7 +1533,6 @@ out:
* Free the receive buffers for each ring slot and any
* attached socket buffers that need to go away.
*/
-
static void velocity_free_rd_ring(struct velocity_info *vptr)
{
int i;
@@ -1292,6 +1560,38 @@ static void velocity_free_rd_ring(struct velocity_info *vptr)
vptr->rx.info = NULL;
}
+
+
+/**
+ * velocity_init_rd_ring - set up receive ring
+ * @vptr: velocity to configure
+ *
+ * Allocate and set up the receive buffers for each ring slot and
+ * assign them to the network adapter.
+ */
+static int velocity_init_rd_ring(struct velocity_info *vptr)
+{
+ int ret = -ENOMEM;
+
+ vptr->rx.info = kcalloc(vptr->options.numrx,
+ sizeof(struct velocity_rd_info), GFP_KERNEL);
+ if (!vptr->rx.info)
+ goto out;
+
+ velocity_init_rx_ring_indexes(vptr);
+
+ if (velocity_rx_refill(vptr) != vptr->options.numrx) {
+ VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR
+ "%s: failed to allocate RX buffer.\n", vptr->dev->name);
+ velocity_free_rd_ring(vptr);
+ goto out;
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
/**
* velocity_init_td_ring - set up transmit ring
* @vptr: velocity
@@ -1300,7 +1600,6 @@ static void velocity_free_rd_ring(struct velocity_info *vptr)
* Returns zero on success or a negative posix errno code for
* failure.
*/
-
static int velocity_init_td_ring(struct velocity_info *vptr)
{
dma_addr_t curr;
@@ -1314,7 +1613,7 @@ static int velocity_init_td_ring(struct velocity_info *vptr)
sizeof(struct velocity_td_info),
GFP_KERNEL);
if (!vptr->tx.infos[j]) {
- while(--j >= 0)
+ while (--j >= 0)
kfree(vptr->tx.infos[j]);
return -ENOMEM;
}
@@ -1324,22 +1623,92 @@ static int velocity_init_td_ring(struct velocity_info *vptr)
return 0;
}
+/**
+ * velocity_free_dma_rings - free PCI ring pointers
+ * @vptr: Velocity to free from
+ *
+ * Clean up the PCI ring buffers allocated to this velocity.
+ */
+static void velocity_free_dma_rings(struct velocity_info *vptr)
+{
+ const int size = vptr->options.numrx * sizeof(struct rx_desc) +
+ vptr->options.numtx * sizeof(struct tx_desc) * vptr->tx.numq;
+
+ pci_free_consistent(vptr->pdev, size, vptr->rx.ring, vptr->rx.pool_dma);
+}
+
+
+static int velocity_init_rings(struct velocity_info *vptr, int mtu)
+{
+ int ret;
+
+ velocity_set_rxbufsize(vptr, mtu);
+
+ ret = velocity_init_dma_rings(vptr);
+ if (ret < 0)
+ goto out;
+
+ ret = velocity_init_rd_ring(vptr);
+ if (ret < 0)
+ goto err_free_dma_rings_0;
+
+ ret = velocity_init_td_ring(vptr);
+ if (ret < 0)
+ goto err_free_rd_ring_1;
+out:
+ return ret;
+
+err_free_rd_ring_1:
+ velocity_free_rd_ring(vptr);
+err_free_dma_rings_0:
+ velocity_free_dma_rings(vptr);
+ goto out;
+}
+
+/**
+ * velocity_free_tx_buf - free transmit buffer
+ * @vptr: velocity
+ * @tdinfo: buffer
+ *
+ * Release an transmit buffer. If the buffer was preallocated then
+ * recycle it, if not then unmap the buffer.
+ */
+static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo)
+{
+ struct sk_buff *skb = tdinfo->skb;
+ int i;
+ int pktlen;
+
+ /*
+ * Don't unmap the pre-allocated tx_bufs
+ */
+ if (tdinfo->skb_dma) {
+
+ pktlen = max_t(unsigned int, skb->len, ETH_ZLEN);
+ for (i = 0; i < tdinfo->nskb_dma; i++) {
+ pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], pktlen, PCI_DMA_TODEVICE);
+ tdinfo->skb_dma[i] = 0;
+ }
+ }
+ dev_kfree_skb_irq(skb);
+ tdinfo->skb = NULL;
+}
+
+
/*
* FIXME: could we merge this with velocity_free_tx_buf ?
*/
-
static void velocity_free_td_ring_entry(struct velocity_info *vptr,
int q, int n)
{
- struct velocity_td_info * td_info = &(vptr->tx.infos[q][n]);
+ struct velocity_td_info *td_info = &(vptr->tx.infos[q][n]);
int i;
if (td_info == NULL)
return;
if (td_info->skb) {
- for (i = 0; i < td_info->nskb_dma; i++)
- {
+ for (i = 0; i < td_info->nskb_dma; i++) {
if (td_info->skb_dma[i]) {
pci_unmap_single(vptr->pdev, td_info->skb_dma[i],
td_info->skb->len, PCI_DMA_TODEVICE);
@@ -1358,7 +1727,6 @@ static void velocity_free_td_ring_entry(struct velocity_info *vptr,
* Free up the transmit ring for this particular velocity adapter.
* We free the ring contents but not the ring itself.
*/
-
static void velocity_free_td_ring(struct velocity_info *vptr)
{
int i, j;
@@ -1366,70 +1734,175 @@ static void velocity_free_td_ring(struct velocity_info *vptr)
for (j = 0; j < vptr->tx.numq; j++) {
if (vptr->tx.infos[j] == NULL)
continue;
- for (i = 0; i < vptr->options.numtx; i++) {
+ for (i = 0; i < vptr->options.numtx; i++)
velocity_free_td_ring_entry(vptr, j, i);
- }
kfree(vptr->tx.infos[j]);
vptr->tx.infos[j] = NULL;
}
}
+
+static void velocity_free_rings(struct velocity_info *vptr)
+{
+ velocity_free_td_ring(vptr);
+ velocity_free_rd_ring(vptr);
+ velocity_free_dma_rings(vptr);
+}
+
/**
- * velocity_rx_srv - service RX interrupt
+ * velocity_error - handle error from controller
* @vptr: velocity
- * @status: adapter status (unused)
+ * @status: card status
+ *
+ * Process an error report from the hardware and attempt to recover
+ * the card itself. At the moment we cannot recover from some
+ * theoretically impossible errors but this could be fixed using
+ * the pci_device_failed logic to bounce the hardware
*
- * Walk the receive ring of the velocity adapter and remove
- * any received packets from the receive queue. Hand the ring
- * slots back to the adapter for reuse.
*/
-
-static int velocity_rx_srv(struct velocity_info *vptr, int status)
+static void velocity_error(struct velocity_info *vptr, int status)
{
- struct net_device_stats *stats = &vptr->dev->stats;
- int rd_curr = vptr->rx.curr;
- int works = 0;
- do {
- struct rx_desc *rd = vptr->rx.ring + rd_curr;
+ if (status & ISR_TXSTLI) {
+ struct mac_regs __iomem *regs = vptr->mac_regs;
- if (!vptr->rx.info[rd_curr].skb)
- break;
+ printk(KERN_ERR "TD structure error TDindex=%hx\n", readw(&regs->TDIdx[0]));
+ BYTE_REG_BITS_ON(TXESR_TDSTR, &regs->TXESR);
+ writew(TRDCSR_RUN, &regs->TDCSRClr);
+ netif_stop_queue(vptr->dev);
- if (rd->rdesc0.len & OWNED_BY_NIC)
- break;
+ /* FIXME: port over the pci_device_failed code and use it
+ here */
+ }
- rmb();
+ if (status & ISR_SRCI) {
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ int linked;
+
+ if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
+ vptr->mii_status = check_connection_type(regs);
+ /*
+ * If it is a 3119, disable frame bursting in
+ * halfduplex mode and enable it in fullduplex
+ * mode
+ */
+ if (vptr->rev_id < REV_ID_VT3216_A0) {
+ if (vptr->mii_status | VELOCITY_DUPLEX_FULL)
+ BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
+ else
+ BYTE_REG_BITS_OFF(TCR_TB2BDIS, &regs->TCR);
+ }
+ /*
+ * Only enable CD heart beat counter in 10HD mode
+ */
+ if (!(vptr->mii_status & VELOCITY_DUPLEX_FULL) && (vptr->mii_status & VELOCITY_SPEED_10))
+ BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
+ else
+ BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
+ }
/*
- * Don't drop CE or RL error frame although RXOK is off
+ * Get link status from PHYSR0
*/
- if (rd->rdesc0.RSR & (RSR_RXOK | RSR_CE | RSR_RL)) {
- if (velocity_receive_frame(vptr, rd_curr) < 0)
- stats->rx_dropped++;
- } else {
- if (rd->rdesc0.RSR & RSR_CRC)
- stats->rx_crc_errors++;
- if (rd->rdesc0.RSR & RSR_FAE)
- stats->rx_frame_errors++;
+ linked = readb(&regs->PHYSR0) & PHYSR0_LINKGD;
- stats->rx_dropped++;
+ if (linked) {
+ vptr->mii_status &= ~VELOCITY_LINK_FAIL;
+ netif_carrier_on(vptr->dev);
+ } else {
+ vptr->mii_status |= VELOCITY_LINK_FAIL;
+ netif_carrier_off(vptr->dev);
}
- rd->size |= RX_INTEN;
+ velocity_print_link_status(vptr);
+ enable_flow_control_ability(vptr);
- rd_curr++;
- if (rd_curr >= vptr->options.numrx)
- rd_curr = 0;
- } while (++works <= 15);
+ /*
+ * Re-enable auto-polling because SRCI will disable
+ * auto-polling
+ */
- vptr->rx.curr = rd_curr;
+ enable_mii_autopoll(regs);
- if ((works > 0) && (velocity_rx_refill(vptr) > 0))
- velocity_give_many_rx_descs(vptr);
+ if (vptr->mii_status & VELOCITY_LINK_FAIL)
+ netif_stop_queue(vptr->dev);
+ else
+ netif_wake_queue(vptr->dev);
- VAR_USED(stats);
+ };
+ if (status & ISR_MIBFI)
+ velocity_update_hw_mibs(vptr);
+ if (status & ISR_LSTEI)
+ mac_rx_queue_wake(vptr->mac_regs);
+}
+
+/**
+ * tx_srv - transmit interrupt service
+ * @vptr; Velocity
+ * @status:
+ *
+ * Scan the queues looking for transmitted packets that
+ * we can complete and clean up. Update any statistics as
+ * necessary/
+ */
+static int velocity_tx_srv(struct velocity_info *vptr, u32 status)
+{
+ struct tx_desc *td;
+ int qnum;
+ int full = 0;
+ int idx;
+ int works = 0;
+ struct velocity_td_info *tdinfo;
+ struct net_device_stats *stats = &vptr->dev->stats;
+
+ for (qnum = 0; qnum < vptr->tx.numq; qnum++) {
+ for (idx = vptr->tx.tail[qnum]; vptr->tx.used[qnum] > 0;
+ idx = (idx + 1) % vptr->options.numtx) {
+
+ /*
+ * Get Tx Descriptor
+ */
+ td = &(vptr->tx.rings[qnum][idx]);
+ tdinfo = &(vptr->tx.infos[qnum][idx]);
+
+ if (td->tdesc0.len & OWNED_BY_NIC)
+ break;
+
+ if ((works++ > 15))
+ break;
+
+ if (td->tdesc0.TSR & TSR0_TERR) {
+ stats->tx_errors++;
+ stats->tx_dropped++;
+ if (td->tdesc0.TSR & TSR0_CDH)
+ stats->tx_heartbeat_errors++;
+ if (td->tdesc0.TSR & TSR0_CRS)
+ stats->tx_carrier_errors++;
+ if (td->tdesc0.TSR & TSR0_ABT)
+ stats->tx_aborted_errors++;
+ if (td->tdesc0.TSR & TSR0_OWC)
+ stats->tx_window_errors++;
+ } else {
+ stats->tx_packets++;
+ stats->tx_bytes += tdinfo->skb->len;
+ }
+ velocity_free_tx_buf(vptr, tdinfo);
+ vptr->tx.used[qnum]--;
+ }
+ vptr->tx.tail[qnum] = idx;
+
+ if (AVAIL_TD(vptr, qnum) < 1)
+ full = 1;
+ }
+ /*
+ * Look to see if we should kick the transmit network
+ * layer for more work.
+ */
+ if (netif_queue_stopped(vptr->dev) && (full == 0)
+ && (!(vptr->mii_status & VELOCITY_LINK_FAIL))) {
+ netif_wake_queue(vptr->dev);
+ }
return works;
}
@@ -1441,7 +1914,6 @@ static int velocity_rx_srv(struct velocity_info *vptr, int status)
* Process the status bits for the received packet and determine
* if the checksum was computed and verified by the hardware
*/
-
static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb)
{
skb->ip_summed = CHECKSUM_NONE;
@@ -1450,9 +1922,8 @@ static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb)
if (rd->rdesc1.CSM & CSM_IPOK) {
if ((rd->rdesc1.CSM & CSM_TCPKT) ||
(rd->rdesc1.CSM & CSM_UDPKT)) {
- if (!(rd->rdesc1.CSM & CSM_TUPOK)) {
+ if (!(rd->rdesc1.CSM & CSM_TUPOK))
return;
- }
}
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
@@ -1509,6 +1980,7 @@ static inline void velocity_iph_realign(struct velocity_info *vptr,
}
}
+
/**
* velocity_receive_frame - received packet processor
* @vptr: velocity we are handling
@@ -1517,7 +1989,6 @@ static inline void velocity_iph_realign(struct velocity_info *vptr,
* A packet has arrived. We process the packet and if appropriate
* pass the frame up the network stack
*/
-
static int velocity_receive_frame(struct velocity_info *vptr, int idx)
{
void (*pci_action)(struct pci_dev *, dma_addr_t, size_t, int);
@@ -1579,320 +2050,118 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
return 0;
}
-/**
- * velocity_alloc_rx_buf - allocate aligned receive buffer
- * @vptr: velocity
- * @idx: ring index
- *
- * Allocate a new full sized buffer for the reception of a frame and
- * map it into PCI space for the hardware to use. The hardware
- * requires *64* byte alignment of the buffer which makes life
- * less fun than would be ideal.
- */
-
-static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx)
-{
- struct rx_desc *rd = &(vptr->rx.ring[idx]);
- struct velocity_rd_info *rd_info = &(vptr->rx.info[idx]);
-
- rd_info->skb = dev_alloc_skb(vptr->rx.buf_sz + 64);
- if (rd_info->skb == NULL)
- return -ENOMEM;
-
- /*
- * Do the gymnastics to get the buffer head for data at
- * 64byte alignment.
- */
- skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->data & 63);
- rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->data,
- vptr->rx.buf_sz, PCI_DMA_FROMDEVICE);
-
- /*
- * Fill in the descriptor to match
- */
-
- *((u32 *) & (rd->rdesc0)) = 0;
- rd->size = cpu_to_le16(vptr->rx.buf_sz) | RX_INTEN;
- rd->pa_low = cpu_to_le32(rd_info->skb_dma);
- rd->pa_high = 0;
- return 0;
-}
/**
- * tx_srv - transmit interrupt service
- * @vptr; Velocity
- * @status:
+ * velocity_rx_srv - service RX interrupt
+ * @vptr: velocity
+ * @status: adapter status (unused)
*
- * Scan the queues looking for transmitted packets that
- * we can complete and clean up. Update any statistics as
- * necessary/
+ * Walk the receive ring of the velocity adapter and remove
+ * any received packets from the receive queue. Hand the ring
+ * slots back to the adapter for reuse.
*/
-
-static int velocity_tx_srv(struct velocity_info *vptr, u32 status)
+static int velocity_rx_srv(struct velocity_info *vptr, int status)
{
- struct tx_desc *td;
- int qnum;
- int full = 0;
- int idx;
- int works = 0;
- struct velocity_td_info *tdinfo;
struct net_device_stats *stats = &vptr->dev->stats;
+ int rd_curr = vptr->rx.curr;
+ int works = 0;
- for (qnum = 0; qnum < vptr->tx.numq; qnum++) {
- for (idx = vptr->tx.tail[qnum]; vptr->tx.used[qnum] > 0;
- idx = (idx + 1) % vptr->options.numtx) {
+ do {
+ struct rx_desc *rd = vptr->rx.ring + rd_curr;
- /*
- * Get Tx Descriptor
- */
- td = &(vptr->tx.rings[qnum][idx]);
- tdinfo = &(vptr->tx.infos[qnum][idx]);
+ if (!vptr->rx.info[rd_curr].skb)
+ break;
- if (td->tdesc0.len & OWNED_BY_NIC)
- break;
+ if (rd->rdesc0.len & OWNED_BY_NIC)
+ break;
- if ((works++ > 15))
- break;
+ rmb();
- if (td->tdesc0.TSR & TSR0_TERR) {
- stats->tx_errors++;
- stats->tx_dropped++;
- if (td->tdesc0.TSR & TSR0_CDH)
- stats->tx_heartbeat_errors++;
- if (td->tdesc0.TSR & TSR0_CRS)
- stats->tx_carrier_errors++;
- if (td->tdesc0.TSR & TSR0_ABT)
- stats->tx_aborted_errors++;
- if (td->tdesc0.TSR & TSR0_OWC)
- stats->tx_window_errors++;
- } else {
- stats->tx_packets++;
- stats->tx_bytes += tdinfo->skb->len;
- }
- velocity_free_tx_buf(vptr, tdinfo);
- vptr->tx.used[qnum]--;
- }
- vptr->tx.tail[qnum] = idx;
+ /*
+ * Don't drop CE or RL error frame although RXOK is off
+ */
+ if (rd->rdesc0.RSR & (RSR_RXOK | RSR_CE | RSR_RL)) {
+ if (velocity_receive_frame(vptr, rd_curr) < 0)
+ stats->rx_dropped++;
+ } else {
+ if (rd->rdesc0.RSR & RSR_CRC)
+ stats->rx_crc_errors++;
+ if (rd->rdesc0.RSR & RSR_FAE)
+ stats->rx_frame_errors++;
- if (AVAIL_TD(vptr, qnum) < 1) {
- full = 1;
+ stats->rx_dropped++;
}
- }
- /*
- * Look to see if we should kick the transmit network
- * layer for more work.
- */
- if (netif_queue_stopped(vptr->dev) && (full == 0)
- && (!(vptr->mii_status & VELOCITY_LINK_FAIL))) {
- netif_wake_queue(vptr->dev);
- }
- return works;
-}
-/**
- * velocity_print_link_status - link status reporting
- * @vptr: velocity to report on
- *
- * Turn the link status of the velocity card into a kernel log
- * description of the new link state, detailing speed and duplex
- * status
- */
+ rd->size |= RX_INTEN;
-static void velocity_print_link_status(struct velocity_info *vptr)
-{
+ rd_curr++;
+ if (rd_curr >= vptr->options.numrx)
+ rd_curr = 0;
+ } while (++works <= 15);
- if (vptr->mii_status & VELOCITY_LINK_FAIL) {
- VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: failed to detect cable link\n", vptr->dev->name);
- } else if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
- VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link auto-negotiation", vptr->dev->name);
+ vptr->rx.curr = rd_curr;
- if (vptr->mii_status & VELOCITY_SPEED_1000)
- VELOCITY_PRT(MSG_LEVEL_INFO, " speed 1000M bps");
- else if (vptr->mii_status & VELOCITY_SPEED_100)
- VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps");
- else
- VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps");
+ if ((works > 0) && (velocity_rx_refill(vptr) > 0))
+ velocity_give_many_rx_descs(vptr);
- if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
- VELOCITY_PRT(MSG_LEVEL_INFO, " full duplex\n");
- else
- VELOCITY_PRT(MSG_LEVEL_INFO, " half duplex\n");
- } else {
- VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced", vptr->dev->name);
- switch (vptr->options.spd_dpx) {
- case SPD_DPX_100_HALF:
- VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps half duplex\n");
- break;
- case SPD_DPX_100_FULL:
- VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps full duplex\n");
- break;
- case SPD_DPX_10_HALF:
- VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps half duplex\n");
- break;
- case SPD_DPX_10_FULL:
- VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps full duplex\n");
- break;
- default:
- break;
- }
- }
+ VAR_USED(stats);
+ return works;
}
+
/**
- * velocity_error - handle error from controller
- * @vptr: velocity
- * @status: card status
- *
- * Process an error report from the hardware and attempt to recover
- * the card itself. At the moment we cannot recover from some
- * theoretically impossible errors but this could be fixed using
- * the pci_device_failed logic to bounce the hardware
+ * velocity_intr - interrupt callback
+ * @irq: interrupt number
+ * @dev_instance: interrupting device
*
+ * Called whenever an interrupt is generated by the velocity
+ * adapter IRQ line. We may not be the source of the interrupt
+ * and need to identify initially if we are, and if not exit as
+ * efficiently as possible.
*/
-
-static void velocity_error(struct velocity_info *vptr, int status)
+static irqreturn_t velocity_intr(int irq, void *dev_instance)
{
+ struct net_device *dev = dev_instance;
+ struct velocity_info *vptr = netdev_priv(dev);
+ u32 isr_status;
+ int max_count = 0;
- if (status & ISR_TXSTLI) {
- struct mac_regs __iomem * regs = vptr->mac_regs;
- printk(KERN_ERR "TD structure error TDindex=%hx\n", readw(&regs->TDIdx[0]));
- BYTE_REG_BITS_ON(TXESR_TDSTR, &regs->TXESR);
- writew(TRDCSR_RUN, &regs->TDCSRClr);
- netif_stop_queue(vptr->dev);
+ spin_lock(&vptr->lock);
+ isr_status = mac_read_isr(vptr->mac_regs);
- /* FIXME: port over the pci_device_failed code and use it
- here */
+ /* Not us ? */
+ if (isr_status == 0) {
+ spin_unlock(&vptr->lock);
+ return IRQ_NONE;
}
- if (status & ISR_SRCI) {
- struct mac_regs __iomem * regs = vptr->mac_regs;
- int linked;
-
- if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
- vptr->mii_status = check_connection_type(regs);
-
- /*
- * If it is a 3119, disable frame bursting in
- * halfduplex mode and enable it in fullduplex
- * mode
- */
- if (vptr->rev_id < REV_ID_VT3216_A0) {
- if (vptr->mii_status | VELOCITY_DUPLEX_FULL)
- BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
- else
- BYTE_REG_BITS_OFF(TCR_TB2BDIS, &regs->TCR);
- }
- /*
- * Only enable CD heart beat counter in 10HD mode
- */
- if (!(vptr->mii_status & VELOCITY_DUPLEX_FULL) && (vptr->mii_status & VELOCITY_SPEED_10)) {
- BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
- } else {
- BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
- }
- }
- /*
- * Get link status from PHYSR0
- */
- linked = readb(&regs->PHYSR0) & PHYSR0_LINKGD;
-
- if (linked) {
- vptr->mii_status &= ~VELOCITY_LINK_FAIL;
- netif_carrier_on(vptr->dev);
- } else {
- vptr->mii_status |= VELOCITY_LINK_FAIL;
- netif_carrier_off(vptr->dev);
- }
-
- velocity_print_link_status(vptr);
- enable_flow_control_ability(vptr);
-
- /*
- * Re-enable auto-polling because SRCI will disable
- * auto-polling
- */
-
- enable_mii_autopoll(regs);
-
- if (vptr->mii_status & VELOCITY_LINK_FAIL)
- netif_stop_queue(vptr->dev);
- else
- netif_wake_queue(vptr->dev);
-
- };
- if (status & ISR_MIBFI)
- velocity_update_hw_mibs(vptr);
- if (status & ISR_LSTEI)
- mac_rx_queue_wake(vptr->mac_regs);
-}
-
-/**
- * velocity_free_tx_buf - free transmit buffer
- * @vptr: velocity
- * @tdinfo: buffer
- *
- * Release an transmit buffer. If the buffer was preallocated then
- * recycle it, if not then unmap the buffer.
- */
-
-static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo)
-{
- struct sk_buff *skb = tdinfo->skb;
- int i;
- int pktlen;
+ mac_disable_int(vptr->mac_regs);
/*
- * Don't unmap the pre-allocated tx_bufs
+ * Keep processing the ISR until we have completed
+ * processing and the isr_status becomes zero
*/
- if (tdinfo->skb_dma) {
- pktlen = max_t(unsigned int, skb->len, ETH_ZLEN);
- for (i = 0; i < tdinfo->nskb_dma; i++) {
-#ifdef VELOCITY_ZERO_COPY_SUPPORT
- pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], le16_to_cpu(td->tdesc1.len), PCI_DMA_TODEVICE);
-#else
- pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], pktlen, PCI_DMA_TODEVICE);
-#endif
- tdinfo->skb_dma[i] = 0;
+ while (isr_status != 0) {
+ mac_write_isr(vptr->mac_regs, isr_status);
+ if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI)))
+ velocity_error(vptr, isr_status);
+ if (isr_status & (ISR_PRXI | ISR_PPRXI))
+ max_count += velocity_rx_srv(vptr, isr_status);
+ if (isr_status & (ISR_PTXI | ISR_PPTXI))
+ max_count += velocity_tx_srv(vptr, isr_status);
+ isr_status = mac_read_isr(vptr->mac_regs);
+ if (max_count > vptr->options.int_works) {
+ printk(KERN_WARNING "%s: excessive work at interrupt.\n",
+ dev->name);
+ max_count = 0;
}
}
- dev_kfree_skb_irq(skb);
- tdinfo->skb = NULL;
-}
-
-static int velocity_init_rings(struct velocity_info *vptr, int mtu)
-{
- int ret;
-
- velocity_set_rxbufsize(vptr, mtu);
-
- ret = velocity_init_dma_rings(vptr);
- if (ret < 0)
- goto out;
-
- ret = velocity_init_rd_ring(vptr);
- if (ret < 0)
- goto err_free_dma_rings_0;
-
- ret = velocity_init_td_ring(vptr);
- if (ret < 0)
- goto err_free_rd_ring_1;
-out:
- return ret;
-
-err_free_rd_ring_1:
- velocity_free_rd_ring(vptr);
-err_free_dma_rings_0:
- velocity_free_dma_rings(vptr);
- goto out;
-}
+ spin_unlock(&vptr->lock);
+ mac_enable_int(vptr->mac_regs);
+ return IRQ_HANDLED;
-static void velocity_free_rings(struct velocity_info *vptr)
-{
- velocity_free_td_ring(vptr);
- velocity_free_rd_ring(vptr);
- velocity_free_dma_rings(vptr);
}
/**
@@ -1905,7 +2174,6 @@ static void velocity_free_rings(struct velocity_info *vptr)
* All the ring allocation and set up is done on open for this
* adapter to minimise memory usage when inactive
*/
-
static int velocity_open(struct net_device *dev)
{
struct velocity_info *vptr = netdev_priv(dev);
@@ -1939,6 +2207,24 @@ out:
}
/**
+ * velocity_shutdown - shut down the chip
+ * @vptr: velocity to deactivate
+ *
+ * Shuts down the internal operations of the velocity and
+ * disables interrupts, autopolling, transmit and receive
+ */
+static void velocity_shutdown(struct velocity_info *vptr)
+{
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ mac_disable_int(regs);
+ writel(CR0_STOP, &regs->CR0Set);
+ writew(0xFFFF, &regs->TDCSRClr);
+ writeb(0xFF, &regs->RDCSRClr);
+ safe_disable_mii_autopoll(regs);
+ mac_clear_isr(regs);
+}
+
+/**
* velocity_change_mtu - MTU change callback
* @dev: network device
* @new_mtu: desired MTU
@@ -1947,7 +2233,6 @@ out:
* this interface. It gets called on a change by the network layer.
* Return zero for success or negative posix error code.
*/
-
static int velocity_change_mtu(struct net_device *dev, int new_mtu)
{
struct velocity_info *vptr = netdev_priv(dev);
@@ -2021,22 +2306,127 @@ out_0:
}
/**
- * velocity_shutdown - shut down the chip
- * @vptr: velocity to deactivate
+ * velocity_mii_ioctl - MII ioctl handler
+ * @dev: network device
+ * @ifr: the ifreq block for the ioctl
+ * @cmd: the command
*
- * Shuts down the internal operations of the velocity and
- * disables interrupts, autopolling, transmit and receive
+ * Process MII requests made via ioctl from the network layer. These
+ * are used by tools like kudzu to interrogate the link state of the
+ * hardware
*/
+static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct velocity_info *vptr = netdev_priv(dev);
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ unsigned long flags;
+ struct mii_ioctl_data *miidata = if_mii(ifr);
+ int err;
-static void velocity_shutdown(struct velocity_info *vptr)
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ miidata->phy_id = readb(&regs->MIIADR) & 0x1f;
+ break;
+ case SIOCGMIIREG:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0)
+ return -ETIMEDOUT;
+ break;
+ case SIOCSMIIREG:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ spin_lock_irqsave(&vptr->lock, flags);
+ err = velocity_mii_write(vptr->mac_regs, miidata->reg_num & 0x1f, miidata->val_in);
+ spin_unlock_irqrestore(&vptr->lock, flags);
+ check_connection_type(vptr->mac_regs);
+ if (err)
+ return err;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+
+/**
+ * velocity_ioctl - ioctl entry point
+ * @dev: network device
+ * @rq: interface request ioctl
+ * @cmd: command code
+ *
+ * Called when the user issues an ioctl request to the network
+ * device in question. The velocity interface supports MII.
+ */
+static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
- struct mac_regs __iomem * regs = vptr->mac_regs;
- mac_disable_int(regs);
- writel(CR0_STOP, &regs->CR0Set);
- writew(0xFFFF, &regs->TDCSRClr);
- writeb(0xFF, &regs->RDCSRClr);
- safe_disable_mii_autopoll(regs);
- mac_clear_isr(regs);
+ struct velocity_info *vptr = netdev_priv(dev);
+ int ret;
+
+ /* If we are asked for information and the device is power
+ saving then we need to bring the device back up to talk to it */
+
+ if (!netif_running(dev))
+ pci_set_power_state(vptr->pdev, PCI_D0);
+
+ switch (cmd) {
+ case SIOCGMIIPHY: /* Get address of MII PHY in use. */
+ case SIOCGMIIREG: /* Read MII PHY register. */
+ case SIOCSMIIREG: /* Write to MII PHY register. */
+ ret = velocity_mii_ioctl(dev, rq, cmd);
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ }
+ if (!netif_running(dev))
+ pci_set_power_state(vptr->pdev, PCI_D3hot);
+
+
+ return ret;
+}
+
+/**
+ * velocity_get_status - statistics callback
+ * @dev: network device
+ *
+ * Callback from the network layer to allow driver statistics
+ * to be resynchronized with hardware collected state. In the
+ * case of the velocity we need to pull the MIB counters from
+ * the hardware into the counters before letting the network
+ * layer display them.
+ */
+static struct net_device_stats *velocity_get_stats(struct net_device *dev)
+{
+ struct velocity_info *vptr = netdev_priv(dev);
+
+ /* If the hardware is down, don't touch MII */
+ if (!netif_running(dev))
+ return &dev->stats;
+
+ spin_lock_irq(&vptr->lock);
+ velocity_update_hw_mibs(vptr);
+ spin_unlock_irq(&vptr->lock);
+
+ dev->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts];
+ dev->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts];
+ dev->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors];
+
+// unsigned long rx_dropped; /* no space in linux buffers */
+ dev->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions];
+ /* detailed rx_errors: */
+// unsigned long rx_length_errors;
+// unsigned long rx_over_errors; /* receiver ring buff overflow */
+ dev->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE];
+// unsigned long rx_frame_errors; /* recv'd frame alignment error */
+// unsigned long rx_fifo_errors; /* recv'r fifo overrun */
+// unsigned long rx_missed_errors; /* receiver missed packet */
+
+ /* detailed tx_errors */
+// unsigned long tx_fifo_errors;
+
+ return &dev->stats;
}
/**
@@ -2046,7 +2436,6 @@ static void velocity_shutdown(struct velocity_info *vptr)
* Callback from the network layer when the velocity is being
* deactivated by the network layer
*/
-
static int velocity_close(struct net_device *dev)
{
struct velocity_info *vptr = netdev_priv(dev);
@@ -2076,7 +2465,6 @@ static int velocity_close(struct net_device *dev)
* Called by the networ layer to request a packet is queued to
* the velocity. Returns zero on success.
*/
-
static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct velocity_info *vptr = netdev_priv(dev);
@@ -2088,20 +2476,12 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
__le16 len;
int index;
-
if (skb_padto(skb, ETH_ZLEN))
goto out;
pktlen = max_t(unsigned int, skb->len, ETH_ZLEN);
len = cpu_to_le16(pktlen);
-#ifdef VELOCITY_ZERO_COPY_SUPPORT
- if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) {
- kfree_skb(skb);
- return 0;
- }
-#endif
-
spin_lock_irqsave(&vptr->lock, flags);
index = vptr->tx.curr[qnum];
@@ -2111,59 +2491,18 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
td_ptr->tdesc1.TCR = TCR0_TIC;
td_ptr->td_buf[0].size &= ~TD_QUEUE;
-#ifdef VELOCITY_ZERO_COPY_SUPPORT
- if (skb_shinfo(skb)->nr_frags > 0) {
- int nfrags = skb_shinfo(skb)->nr_frags;
- tdinfo->skb = skb;
- if (nfrags > 6) {
- skb_copy_from_linear_data(skb, tdinfo->buf, skb->len);
- tdinfo->skb_dma[0] = tdinfo->buf_dma;
- td_ptr->tdesc0.len = len;
- td_ptr->tx.buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
- td_ptr->tx.buf[0].pa_high = 0;
- td_ptr->tx.buf[0].size = len; /* queue is 0 anyway */
- tdinfo->nskb_dma = 1;
- } else {
- int i = 0;
- tdinfo->nskb_dma = 0;
- tdinfo->skb_dma[i] = pci_map_single(vptr->pdev, skb->data,
- skb_headlen(skb), PCI_DMA_TODEVICE);
-
- td_ptr->tdesc0.len = len;
-
- /* FIXME: support 48bit DMA later */
- td_ptr->tx.buf[i].pa_low = cpu_to_le32(tdinfo->skb_dma);
- td_ptr->tx.buf[i].pa_high = 0;
- td_ptr->tx.buf[i].size = cpu_to_le16(skb_headlen(skb));
-
- for (i = 0; i < nfrags; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- void *addr = (void *)page_address(frag->page) + frag->page_offset;
-
- tdinfo->skb_dma[i + 1] = pci_map_single(vptr->pdev, addr, frag->size, PCI_DMA_TODEVICE);
-
- td_ptr->tx.buf[i + 1].pa_low = cpu_to_le32(tdinfo->skb_dma[i + 1]);
- td_ptr->tx.buf[i + 1].pa_high = 0;
- td_ptr->tx.buf[i + 1].size = cpu_to_le16(frag->size);
- }
- tdinfo->nskb_dma = i - 1;
- }
+ /*
+ * Map the linear network buffer into PCI space and
+ * add it to the transmit ring.
+ */
+ tdinfo->skb = skb;
+ tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE);
+ td_ptr->tdesc0.len = len;
+ td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
+ td_ptr->td_buf[0].pa_high = 0;
+ td_ptr->td_buf[0].size = len;
+ tdinfo->nskb_dma = 1;
- } else
-#endif
- {
- /*
- * Map the linear network buffer into PCI space and
- * add it to the transmit ring.
- */
- tdinfo->skb = skb;
- tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE);
- td_ptr->tdesc0.len = len;
- td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
- td_ptr->td_buf[0].pa_high = 0;
- td_ptr->td_buf[0].size = len;
- tdinfo->nskb_dma = 1;
- }
td_ptr->tdesc1.cmd = TCPLS_NORMAL + (tdinfo->nskb_dma + 1) * 16;
if (vptr->vlgrp && vlan_tx_tag_present(skb)) {
@@ -2206,782 +2545,533 @@ out:
return NETDEV_TX_OK;
}
+
+static const struct net_device_ops velocity_netdev_ops = {
+ .ndo_open = velocity_open,
+ .ndo_stop = velocity_close,
+ .ndo_start_xmit = velocity_xmit,
+ .ndo_get_stats = velocity_get_stats,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_set_multicast_list = velocity_set_multi,
+ .ndo_change_mtu = velocity_change_mtu,
+ .ndo_do_ioctl = velocity_ioctl,
+ .ndo_vlan_rx_add_vid = velocity_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = velocity_vlan_rx_kill_vid,
+ .ndo_vlan_rx_register = velocity_vlan_rx_register,
+};
+
/**
- * velocity_intr - interrupt callback
- * @irq: interrupt number
- * @dev_instance: interrupting device
+ * velocity_init_info - init private data
+ * @pdev: PCI device
+ * @vptr: Velocity info
+ * @info: Board type
*
- * Called whenever an interrupt is generated by the velocity
- * adapter IRQ line. We may not be the source of the interrupt
- * and need to identify initially if we are, and if not exit as
- * efficiently as possible.
+ * Set up the initial velocity_info struct for the device that has been
+ * discovered.
*/
-
-static irqreturn_t velocity_intr(int irq, void *dev_instance)
+static void __devinit velocity_init_info(struct pci_dev *pdev,
+ struct velocity_info *vptr,
+ const struct velocity_info_tbl *info)
{
- struct net_device *dev = dev_instance;
- struct velocity_info *vptr = netdev_priv(dev);
- u32 isr_status;
- int max_count = 0;
-
-
- spin_lock(&vptr->lock);
- isr_status = mac_read_isr(vptr->mac_regs);
-
- /* Not us ? */
- if (isr_status == 0) {
- spin_unlock(&vptr->lock);
- return IRQ_NONE;
- }
-
- mac_disable_int(vptr->mac_regs);
-
- /*
- * Keep processing the ISR until we have completed
- * processing and the isr_status becomes zero
- */
-
- while (isr_status != 0) {
- mac_write_isr(vptr->mac_regs, isr_status);
- if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI)))
- velocity_error(vptr, isr_status);
- if (isr_status & (ISR_PRXI | ISR_PPRXI))
- max_count += velocity_rx_srv(vptr, isr_status);
- if (isr_status & (ISR_PTXI | ISR_PPTXI))
- max_count += velocity_tx_srv(vptr, isr_status);
- isr_status = mac_read_isr(vptr->mac_regs);
- if (max_count > vptr->options.int_works)
- {
- printk(KERN_WARNING "%s: excessive work at interrupt.\n",
- dev->name);
- max_count = 0;
- }
- }
- spin_unlock(&vptr->lock);
- mac_enable_int(vptr->mac_regs);
- return IRQ_HANDLED;
+ memset(vptr, 0, sizeof(struct velocity_info));
+ vptr->pdev = pdev;
+ vptr->chip_id = info->chip_id;
+ vptr->tx.numq = info->txqueue;
+ vptr->multicast_limit = MCAM_SIZE;
+ spin_lock_init(&vptr->lock);
+ INIT_LIST_HEAD(&vptr->list);
}
-
/**
- * velocity_set_multi - filter list change callback
- * @dev: network device
+ * velocity_get_pci_info - retrieve PCI info for device
+ * @vptr: velocity device
+ * @pdev: PCI device it matches
*
- * Called by the network layer when the filter lists need to change
- * for a velocity adapter. Reload the CAMs with the new address
- * filter ruleset.
+ * Retrieve the PCI configuration space data that interests us from
+ * the kernel PCI layer
*/
-
-static void velocity_set_multi(struct net_device *dev)
+static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pci_dev *pdev)
{
- struct velocity_info *vptr = netdev_priv(dev);
- struct mac_regs __iomem * regs = vptr->mac_regs;
- u8 rx_mode;
- int i;
- struct dev_mc_list *mclist;
+ vptr->rev_id = pdev->revision;
- if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
- writel(0xffffffff, &regs->MARCAM[0]);
- writel(0xffffffff, &regs->MARCAM[4]);
- rx_mode = (RCR_AM | RCR_AB | RCR_PROM);
- } else if ((dev->mc_count > vptr->multicast_limit)
- || (dev->flags & IFF_ALLMULTI)) {
- writel(0xffffffff, &regs->MARCAM[0]);
- writel(0xffffffff, &regs->MARCAM[4]);
- rx_mode = (RCR_AM | RCR_AB);
- } else {
- int offset = MCAM_SIZE - vptr->multicast_limit;
- mac_get_cam_mask(regs, vptr->mCAMmask);
+ pci_set_master(pdev);
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) {
- mac_set_cam(regs, i + offset, mclist->dmi_addr);
- vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7);
- }
+ vptr->ioaddr = pci_resource_start(pdev, 0);
+ vptr->memaddr = pci_resource_start(pdev, 1);
- mac_set_cam_mask(regs, vptr->mCAMmask);
- rx_mode = RCR_AM | RCR_AB | RCR_AP;
+ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
+ dev_err(&pdev->dev,
+ "region #0 is not an I/O resource, aborting.\n");
+ return -EINVAL;
}
- if (dev->mtu > 1500)
- rx_mode |= RCR_AL;
- BYTE_REG_BITS_ON(rx_mode, &regs->RCR);
+ if ((pci_resource_flags(pdev, 1) & IORESOURCE_IO)) {
+ dev_err(&pdev->dev,
+ "region #1 is an I/O resource, aborting.\n");
+ return -EINVAL;
+ }
+ if (pci_resource_len(pdev, 1) < VELOCITY_IO_SIZE) {
+ dev_err(&pdev->dev, "region #1 is too small.\n");
+ return -EINVAL;
+ }
+ vptr->pdev = pdev;
+
+ return 0;
}
/**
- * velocity_get_status - statistics callback
- * @dev: network device
+ * velocity_print_info - per driver data
+ * @vptr: velocity
*
- * Callback from the network layer to allow driver statistics
- * to be resynchronized with hardware collected state. In the
- * case of the velocity we need to pull the MIB counters from
- * the hardware into the counters before letting the network
- * layer display them.
+ * Print per driver data as the kernel driver finds Velocity
+ * hardware
*/
-
-static struct net_device_stats *velocity_get_stats(struct net_device *dev)
+static void __devinit velocity_print_info(struct velocity_info *vptr)
{
- struct velocity_info *vptr = netdev_priv(dev);
-
- /* If the hardware is down, don't touch MII */
- if(!netif_running(dev))
- return &dev->stats;
-
- spin_lock_irq(&vptr->lock);
- velocity_update_hw_mibs(vptr);
- spin_unlock_irq(&vptr->lock);
-
- dev->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts];
- dev->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts];
- dev->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors];
-
-// unsigned long rx_dropped; /* no space in linux buffers */
- dev->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions];
- /* detailed rx_errors: */
-// unsigned long rx_length_errors;
-// unsigned long rx_over_errors; /* receiver ring buff overflow */
- dev->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE];
-// unsigned long rx_frame_errors; /* recv'd frame alignment error */
-// unsigned long rx_fifo_errors; /* recv'r fifo overrun */
-// unsigned long rx_missed_errors; /* receiver missed packet */
-
- /* detailed tx_errors */
-// unsigned long tx_fifo_errors;
+ struct net_device *dev = vptr->dev;
- return &dev->stats;
+ printk(KERN_INFO "%s: %s\n", dev->name, get_chip_name(vptr->chip_id));
+ printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
+ dev->name,
+ dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
}
-
-/**
- * velocity_ioctl - ioctl entry point
- * @dev: network device
- * @rq: interface request ioctl
- * @cmd: command code
- *
- * Called when the user issues an ioctl request to the network
- * device in question. The velocity interface supports MII.
- */
-
-static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static u32 velocity_get_link(struct net_device *dev)
{
struct velocity_info *vptr = netdev_priv(dev);
- int ret;
-
- /* If we are asked for information and the device is power
- saving then we need to bring the device back up to talk to it */
-
- if (!netif_running(dev))
- pci_set_power_state(vptr->pdev, PCI_D0);
-
- switch (cmd) {
- case SIOCGMIIPHY: /* Get address of MII PHY in use. */
- case SIOCGMIIREG: /* Read MII PHY register. */
- case SIOCSMIIREG: /* Write to MII PHY register. */
- ret = velocity_mii_ioctl(dev, rq, cmd);
- break;
-
- default:
- ret = -EOPNOTSUPP;
- }
- if (!netif_running(dev))
- pci_set_power_state(vptr->pdev, PCI_D3hot);
-
-
- return ret;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, &regs->PHYSR0) ? 1 : 0;
}
-/*
- * Definition for our device driver. The PCI layer interface
- * uses this to handle all our card discover and plugging
- */
-
-static struct pci_driver velocity_driver = {
- .name = VELOCITY_NAME,
- .id_table = velocity_id_table,
- .probe = velocity_found1,
- .remove = __devexit_p(velocity_remove1),
-#ifdef CONFIG_PM
- .suspend = velocity_suspend,
- .resume = velocity_resume,
-#endif
-};
/**
- * velocity_init_module - load time function
+ * velocity_found1 - set up discovered velocity card
+ * @pdev: PCI device
+ * @ent: PCI device table entry that matched
*
- * Called when the velocity module is loaded. The PCI driver
- * is registered with the PCI layer, and in turn will call
- * the probe functions for each velocity adapter installed
- * in the system.
+ * Configure a discovered adapter from scratch. Return a negative
+ * errno error code on failure paths.
*/
-
-static int __init velocity_init_module(void)
+static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- int ret;
+ static int first = 1;
+ struct net_device *dev;
+ int i;
+ const char *drv_string;
+ const struct velocity_info_tbl *info = &chip_info_table[ent->driver_data];
+ struct velocity_info *vptr;
+ struct mac_regs __iomem *regs;
+ int ret = -ENOMEM;
- velocity_register_notifier();
- ret = pci_register_driver(&velocity_driver);
- if (ret < 0)
- velocity_unregister_notifier();
- return ret;
-}
+ /* FIXME: this driver, like almost all other ethernet drivers,
+ * can support more than MAX_UNITS.
+ */
+ if (velocity_nics >= MAX_UNITS) {
+ dev_notice(&pdev->dev, "already found %d NICs.\n",
+ velocity_nics);
+ return -ENODEV;
+ }
-/**
- * velocity_cleanup - module unload
- *
- * When the velocity hardware is unloaded this function is called.
- * It will clean up the notifiers and the unregister the PCI
- * driver interface for this hardware. This in turn cleans up
- * all discovered interfaces before returning from the function
- */
+ dev = alloc_etherdev(sizeof(struct velocity_info));
+ if (!dev) {
+ dev_err(&pdev->dev, "allocate net device failed.\n");
+ goto out;
+ }
-static void __exit velocity_cleanup_module(void)
-{
- velocity_unregister_notifier();
- pci_unregister_driver(&velocity_driver);
-}
+ /* Chain it all together */
-module_init(velocity_init_module);
-module_exit(velocity_cleanup_module);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+ vptr = netdev_priv(dev);
-/*
- * MII access , media link mode setting functions
- */
+ if (first) {
+ printk(KERN_INFO "%s Ver. %s\n",
+ VELOCITY_FULL_DRV_NAM, VELOCITY_VERSION);
+ printk(KERN_INFO "Copyright (c) 2002, 2003 VIA Networking Technologies, Inc.\n");
+ printk(KERN_INFO "Copyright (c) 2004 Red Hat Inc.\n");
+ first = 0;
+ }
+ velocity_init_info(pdev, vptr, info);
-/**
- * mii_init - set up MII
- * @vptr: velocity adapter
- * @mii_status: links tatus
- *
- * Set up the PHY for the current link state.
- */
+ vptr->dev = dev;
-static void mii_init(struct velocity_info *vptr, u32 mii_status)
-{
- u16 BMCR;
+ dev->irq = pdev->irq;
- switch (PHYID_GET_PHY_ID(vptr->phy_id)) {
- case PHYID_CICADA_CS8201:
- /*
- * Reset to hardware default
- */
- MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, 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);
- else
- MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
- /*
- * Turn on Link/Activity LED enable bit for CIS8201
- */
- MII_REG_BITS_ON(PLED_LALBE, MII_REG_PLED, 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);
- /*
- * 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);
- else
- MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
- break;
+ ret = pci_enable_device(pdev);
+ if (ret < 0)
+ goto err_free_dev;
- case PHYID_MARVELL_1000:
- case PHYID_MARVELL_1000S:
- /*
- * Assert CRS on Transmit
- */
- MII_REG_BITS_ON(PSCR_ACRSTX, MII_REG_PSCR, vptr->mac_regs);
- /*
- * Reset to hardware default
- */
- MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, 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);
+ ret = velocity_get_pci_info(vptr, pdev);
+ if (ret < 0) {
+ /* error message already printed */
+ goto err_disable;
}
-}
-/**
- * safe_disable_mii_autopoll - autopoll off
- * @regs: velocity registers
- *
- * Turn off the autopoll and wait for it to disable on the chip
- */
-
-static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs)
-{
- u16 ww;
-
- /* turn off MAUTO */
- writeb(0, &regs->MIICR);
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- udelay(1);
- if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
- break;
+ ret = pci_request_regions(pdev, VELOCITY_NAME);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "No PCI resources.\n");
+ goto err_disable;
}
-}
-
-/**
- * enable_mii_autopoll - turn on autopolling
- * @regs: velocity registers
- *
- * Enable the MII link status autopoll feature on the Velocity
- * hardware. Wait for it to enable.
- */
-static void enable_mii_autopoll(struct mac_regs __iomem * regs)
-{
- int ii;
+ regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE);
+ if (regs == NULL) {
+ ret = -EIO;
+ goto err_release_res;
+ }
- writeb(0, &(regs->MIICR));
- writeb(MIIADR_SWMPL, &regs->MIIADR);
+ vptr->mac_regs = regs;
- for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
- udelay(1);
- if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
- break;
- }
+ mac_wol_reset(regs);
- writeb(MIICR_MAUTO, &regs->MIICR);
+ dev->base_addr = vptr->ioaddr;
- for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
- udelay(1);
- if (!BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
- break;
- }
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = readb(&regs->PAR[i]);
-}
-/**
- * velocity_mii_read - read MII data
- * @regs: velocity registers
- * @index: MII register index
- * @data: buffer for received data
- *
- * Perform a single read of an MII 16bit register. Returns zero
- * on success or -ETIMEDOUT if the PHY did not respond.
- */
+ drv_string = dev_driver_string(&pdev->dev);
-static int velocity_mii_read(struct mac_regs __iomem *regs, u8 index, u16 *data)
-{
- u16 ww;
+ velocity_get_options(&vptr->options, velocity_nics, drv_string);
/*
- * Disable MIICR_MAUTO, so that mii addr can be set normally
+ * Mask out the options cannot be set to the chip
*/
- safe_disable_mii_autopoll(regs);
-
- writeb(index, &regs->MIIADR);
- BYTE_REG_BITS_ON(MIICR_RCMD, &regs->MIICR);
+ vptr->options.flags &= info->flags;
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- if (!(readb(&regs->MIICR) & MIICR_RCMD))
- break;
- }
+ /*
+ * Enable the chip specified capbilities
+ */
- *data = readw(&regs->MIIDATA);
+ vptr->flags = vptr->options.flags | (info->flags & 0xFF000000UL);
- enable_mii_autopoll(regs);
- if (ww == W_MAX_TIMEOUT)
- return -ETIMEDOUT;
- return 0;
-}
+ vptr->wol_opts = vptr->options.wol_opts;
+ vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
-/**
- * velocity_mii_write - write MII data
- * @regs: velocity registers
- * @index: MII register index
- * @data: 16bit data for the MII register
- *
- * Perform a single write to an MII 16bit register. Returns zero
- * on success or -ETIMEDOUT if the PHY did not respond.
- */
+ vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs);
-static int velocity_mii_write(struct mac_regs __iomem *regs, u8 mii_addr, u16 data)
-{
- u16 ww;
+ dev->irq = pdev->irq;
+ dev->netdev_ops = &velocity_netdev_ops;
+ dev->ethtool_ops = &velocity_ethtool_ops;
- /*
- * Disable MIICR_MAUTO, so that mii addr can be set normally
- */
- safe_disable_mii_autopoll(regs);
+ dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER |
+ NETIF_F_HW_VLAN_RX;
- /* MII reg offset */
- writeb(mii_addr, &regs->MIIADR);
- /* set MII data */
- writew(data, &regs->MIIDATA);
+ if (vptr->flags & VELOCITY_FLAGS_TX_CSUM)
+ dev->features |= NETIF_F_IP_CSUM;
- /* turn on MIICR_WCMD */
- BYTE_REG_BITS_ON(MIICR_WCMD, &regs->MIICR);
+ ret = register_netdev(dev);
+ if (ret < 0)
+ goto err_iounmap;
- /* W_MAX_TIMEOUT is the timeout period */
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- udelay(5);
- if (!(readb(&regs->MIICR) & MIICR_WCMD))
- break;
+ if (!velocity_get_link(dev)) {
+ netif_carrier_off(dev);
+ vptr->mii_status |= VELOCITY_LINK_FAIL;
}
- enable_mii_autopoll(regs);
- if (ww == W_MAX_TIMEOUT)
- return -ETIMEDOUT;
- return 0;
-}
+ velocity_print_info(vptr);
+ pci_set_drvdata(pdev, dev);
-/**
- * velocity_get_opt_media_mode - get media selection
- * @vptr: velocity adapter
- *
- * Get the media mode stored in EEPROM or module options and load
- * mii_status accordingly. The requested link state information
- * is also returned.
- */
+ /* and leave the chip powered down */
-static u32 velocity_get_opt_media_mode(struct velocity_info *vptr)
-{
- u32 status = 0;
+ pci_set_power_state(pdev, PCI_D3hot);
+#ifdef CONFIG_PM
+ {
+ unsigned long flags;
- switch (vptr->options.spd_dpx) {
- case SPD_DPX_AUTO:
- status = VELOCITY_AUTONEG_ENABLE;
- break;
- case SPD_DPX_100_FULL:
- status = VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL;
- break;
- case SPD_DPX_10_FULL:
- status = VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL;
- break;
- case SPD_DPX_100_HALF:
- status = VELOCITY_SPEED_100;
- break;
- case SPD_DPX_10_HALF:
- status = VELOCITY_SPEED_10;
- break;
+ spin_lock_irqsave(&velocity_dev_list_lock, flags);
+ list_add(&vptr->list, &velocity_dev_list);
+ spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
}
- vptr->mii_status = status;
- return status;
-}
-
-/**
- * mii_set_auto_on - autonegotiate on
- * @vptr: velocity
- *
- * Enable autonegotation on this interface
- */
+#endif
+ velocity_nics++;
+out:
+ return ret;
-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);
- else
- MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
+err_iounmap:
+ iounmap(regs);
+err_release_res:
+ pci_release_regions(pdev);
+err_disable:
+ pci_disable_device(pdev);
+err_free_dev:
+ free_netdev(dev);
+ goto out;
}
-/*
-static void mii_set_auto_off(struct velocity_info * vptr)
-{
- MII_REG_BITS_OFF(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
-}
-*/
-
+#ifdef CONFIG_PM
/**
- * set_mii_flow_control - flow control setup
- * @vptr: velocity interface
+ * wol_calc_crc - WOL CRC
+ * @pattern: data pattern
+ * @mask_pattern: mask
*
- * Set up the flow control on this interface according to
- * the supplied user/eeprom options.
+ * Compute the wake on lan crc hashes for the packet header
+ * we are interested in.
*/
-
-static void set_mii_flow_control(struct velocity_info *vptr)
+static u16 wol_calc_crc(int size, u8 *pattern, u8 *mask_pattern)
{
- /*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);
- break;
+ u16 crc = 0xFFFF;
+ u8 mask;
+ int i, j;
- 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);
- break;
+ for (i = 0; i < size; i++) {
+ mask = mask_pattern[i];
- case FLOW_CNTL_TX_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);
- break;
+ /* Skip this loop if the mask equals to zero */
+ if (mask == 0x00)
+ continue;
- 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);
- break;
- default:
- break;
+ for (j = 0; j < 8; j++) {
+ if ((mask & 0x01) == 0) {
+ mask >>= 1;
+ continue;
+ }
+ mask >>= 1;
+ crc = crc_ccitt(crc, &(pattern[i * 8 + j]), 1);
+ }
}
+ /* Finally, invert the result once to get the correct data */
+ crc = ~crc;
+ return bitrev32(crc) >> 16;
}
/**
- * velocity_set_media_mode - set media mode
- * @mii_status: old MII link state
+ * velocity_set_wol - set up for wake on lan
+ * @vptr: velocity to set WOL status on
*
- * Check the media link state and configure the flow control
- * PHY and also velocity hardware setup accordingly. In particular
- * we need to set up CD polling and frame bursting.
+ * Set a card up for wake on lan either by unicast or by
+ * ARP packet.
+ *
+ * FIXME: check static buffer is safe here
*/
-
-static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
+static int velocity_set_wol(struct velocity_info *vptr)
{
- u32 curr_status;
- struct mac_regs __iomem * regs = vptr->mac_regs;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ static u8 buf[256];
+ int i;
- vptr->mii_status = mii_check_media_mode(vptr->mac_regs);
- curr_status = vptr->mii_status & (~VELOCITY_LINK_FAIL);
+ static u32 mask_pattern[2][4] = {
+ {0x00203000, 0x000003C0, 0x00000000, 0x0000000}, /* ARP */
+ {0xfffff000, 0xffffffff, 0xffffffff, 0x000ffff} /* Magic Packet */
+ };
- /* Set mii link status */
- set_mii_flow_control(vptr);
+ writew(0xFFFF, &regs->WOLCRClr);
+ writeb(WOLCFG_SAB | WOLCFG_SAM, &regs->WOLCFGSet);
+ writew(WOLCR_MAGIC_EN, &regs->WOLCRSet);
/*
- Check if new status is consisent with current status
- if (((mii_status & curr_status) & VELOCITY_AUTONEG_ENABLE)
- || (mii_status==curr_status)) {
- vptr->mii_status=mii_check_media_mode(vptr->mac_regs);
- vptr->mii_status=check_connection_type(vptr->mac_regs);
- VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity link no change\n");
- return 0;
- }
+ if (vptr->wol_opts & VELOCITY_WOL_PHY)
+ writew((WOLCR_LINKON_EN|WOLCR_LINKOFF_EN), &regs->WOLCRSet);
*/
- if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201) {
- MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs);
- }
+ if (vptr->wol_opts & VELOCITY_WOL_UCAST)
+ writew(WOLCR_UNICAST_EN, &regs->WOLCRSet);
- /*
- * If connection type is AUTO
- */
- if (mii_status & VELOCITY_AUTONEG_ENABLE) {
- VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity is AUTO mode\n");
- /* 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);
+ if (vptr->wol_opts & VELOCITY_WOL_ARP) {
+ struct arp_packet *arp = (struct arp_packet *) buf;
+ u16 crc;
+ memset(buf, 0, sizeof(struct arp_packet) + 7);
- /* enable AUTO-NEGO mode */
- mii_set_auto_on(vptr);
- } else {
- u16 ANAR;
- u8 CHIPGCR;
+ for (i = 0; i < 4; i++)
+ writel(mask_pattern[0][i], &regs->ByteMask[0][i]);
- /*
- * 1. if it's 3119, disable frame bursting in halfduplex mode
- * and enable it in fullduplex mode
- * 2. set correct MII/GMII and half/full duplex mode in CHIPGCR
- * 3. only enable CD heart beat counter in 10HD mode
- */
+ arp->type = htons(ETH_P_ARP);
+ arp->ar_op = htons(1);
- /* set force MAC mode bit */
- BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
+ memcpy(arp->ar_tip, vptr->ip_addr, 4);
- CHIPGCR = readb(&regs->CHIPGCR);
- CHIPGCR &= ~CHIPGCR_FCGMII;
+ crc = wol_calc_crc((sizeof(struct arp_packet) + 7) / 8, buf,
+ (u8 *) & mask_pattern[0][0]);
- if (mii_status & VELOCITY_DUPLEX_FULL) {
- CHIPGCR |= CHIPGCR_FCFDX;
- writeb(CHIPGCR, &regs->CHIPGCR);
- VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced full mode\n");
- if (vptr->rev_id < REV_ID_VT3216_A0)
- BYTE_REG_BITS_OFF(TCR_TB2BDIS, &regs->TCR);
- } else {
- CHIPGCR &= ~CHIPGCR_FCFDX;
- VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced half mode\n");
- writeb(CHIPGCR, &regs->CHIPGCR);
- if (vptr->rev_id < REV_ID_VT3216_A0)
- BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
- }
+ writew(crc, &regs->PatternCRC[0]);
+ writew(WOLCR_ARP_EN, &regs->WOLCRSet);
+ }
+
+ BYTE_REG_BITS_ON(PWCFG_WOLTYPE, &regs->PWCFGSet);
+ BYTE_REG_BITS_ON(PWCFG_LEGACY_WOLEN, &regs->PWCFGSet);
+
+ writew(0x0FFF, &regs->WOLSRClr);
+
+ 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_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, 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));
- if (mii_status & VELOCITY_SPEED_100) {
- if (mii_status & VELOCITY_DUPLEX_FULL)
- ANAR |= ANAR_TXFD;
- else
- ANAR |= ANAR_TX;
- } else {
- if (mii_status & VELOCITY_DUPLEX_FULL)
- ANAR |= ANAR_10FD;
- else
- ANAR |= ANAR_10;
- }
- velocity_mii_write(vptr->mac_regs, MII_REG_ANAR, ANAR);
- /* enable AUTO-NEGO mode */
- mii_set_auto_on(vptr);
- /* MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); */
+ if (vptr->mii_status & VELOCITY_SPEED_1000)
+ MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs);
+
+ BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
+
+ {
+ u8 GCR;
+ GCR = readb(&regs->CHIPGCR);
+ GCR = (GCR & ~CHIPGCR_FCGMII) | CHIPGCR_FCFDX;
+ writeb(GCR, &regs->CHIPGCR);
}
- /* vptr->mii_status=mii_check_media_mode(vptr->mac_regs); */
- /* vptr->mii_status=check_connection_type(vptr->mac_regs); */
- return VELOCITY_LINK_CHANGE;
+
+ BYTE_REG_BITS_OFF(ISR_PWEI, &regs->ISR);
+ /* Turn on SWPTAG just before entering power mode */
+ BYTE_REG_BITS_ON(STICKHW_SWPTAG, &regs->STICKHW);
+ /* Go to bed ..... */
+ BYTE_REG_BITS_ON((STICKHW_DS1 | STICKHW_DS0), &regs->STICKHW);
+
+ return 0;
}
/**
- * mii_check_media_mode - check media state
- * @regs: velocity registers
+ * velocity_save_context - save registers
+ * @vptr: velocity
+ * @context: buffer for stored context
*
- * Check the current MII status and determine the link status
- * accordingly
+ * Retrieve the current configuration from the velocity hardware
+ * and stash it in the context structure, for use by the context
+ * restore functions. This allows us to save things we need across
+ * power down states
*/
-
-static u32 mii_check_media_mode(struct mac_regs __iomem * regs)
+static void velocity_save_context(struct velocity_info *vptr, struct velocity_context *context)
{
- u32 status = 0;
- u16 ANAR;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ u16 i;
+ u8 __iomem *ptr = (u8 __iomem *)regs;
- if (!MII_REG_BITS_IS_ON(BMSR_LNK, MII_REG_BMSR, regs))
- status |= VELOCITY_LINK_FAIL;
+ for (i = MAC_REG_PAR; i < MAC_REG_CR0_CLR; i += 4)
+ *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
- if (MII_REG_BITS_IS_ON(G1000CR_1000FD, MII_REG_G1000CR, regs))
- status |= VELOCITY_SPEED_1000 | VELOCITY_DUPLEX_FULL;
- else if (MII_REG_BITS_IS_ON(G1000CR_1000, MII_REG_G1000CR, regs))
- status |= (VELOCITY_SPEED_1000);
- else {
- velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
- if (ANAR & ANAR_TXFD)
- status |= (VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL);
- else if (ANAR & ANAR_TX)
- status |= VELOCITY_SPEED_100;
- else if (ANAR & ANAR_10FD)
- status |= (VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL);
- else
- status |= (VELOCITY_SPEED_10);
- }
+ for (i = MAC_REG_MAR; i < MAC_REG_TDCSR_CLR; i += 4)
+ *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
- 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))
- status |= VELOCITY_AUTONEG_ENABLE;
- }
- }
+ for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4)
+ *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
- return status;
}
-static u32 check_connection_type(struct mac_regs __iomem * regs)
+static int velocity_suspend(struct pci_dev *pdev, pm_message_t state)
{
- u32 status = 0;
- u8 PHYSR0;
- u16 ANAR;
- PHYSR0 = readb(&regs->PHYSR0);
-
- /*
- if (!(PHYSR0 & PHYSR0_LINKGD))
- status|=VELOCITY_LINK_FAIL;
- */
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct velocity_info *vptr = netdev_priv(dev);
+ unsigned long flags;
- if (PHYSR0 & PHYSR0_FDPX)
- status |= VELOCITY_DUPLEX_FULL;
+ if (!netif_running(vptr->dev))
+ return 0;
- if (PHYSR0 & PHYSR0_SPDG)
- status |= VELOCITY_SPEED_1000;
- else if (PHYSR0 & PHYSR0_SPD10)
- status |= VELOCITY_SPEED_10;
- else
- status |= VELOCITY_SPEED_100;
+ netif_device_detach(vptr->dev);
- 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))
- status |= VELOCITY_AUTONEG_ENABLE;
- }
+ spin_lock_irqsave(&vptr->lock, flags);
+ pci_save_state(pdev);
+#ifdef ETHTOOL_GWOL
+ if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) {
+ velocity_get_ip(vptr);
+ velocity_save_context(vptr, &vptr->context);
+ velocity_shutdown(vptr);
+ velocity_set_wol(vptr);
+ pci_enable_wake(pdev, PCI_D3hot, 1);
+ pci_set_power_state(pdev, PCI_D3hot);
+ } else {
+ velocity_save_context(vptr, &vptr->context);
+ velocity_shutdown(vptr);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
}
-
- return status;
+#else
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+#endif
+ spin_unlock_irqrestore(&vptr->lock, flags);
+ return 0;
}
/**
- * enable_flow_control_ability - flow control
- * @vptr: veloity to configure
+ * velocity_restore_context - restore registers
+ * @vptr: velocity
+ * @context: buffer for stored context
*
- * Set up flow control according to the flow control options
- * determined by the eeprom/configuration.
+ * Reload the register configuration from the velocity context
+ * created by velocity_save_context.
*/
-
-static void enable_flow_control_ability(struct velocity_info *vptr)
+static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context)
{
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ int i;
+ u8 __iomem *ptr = (u8 __iomem *)regs;
- struct mac_regs __iomem * regs = vptr->mac_regs;
+ for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4)
+ writel(*((u32 *) (context->mac_reg + i)), ptr + i);
- switch (vptr->options.flow_cntl) {
+ /* Just skip cr0 */
+ for (i = MAC_REG_CR1_SET; i < MAC_REG_CR0_CLR; i++) {
+ /* Clear */
+ writeb(~(*((u8 *) (context->mac_reg + i))), ptr + i + 4);
+ /* Set */
+ writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
+ }
- case FLOW_CNTL_DEFAULT:
- if (BYTE_REG_BITS_IS_ON(PHYSR0_RXFLC, &regs->PHYSR0))
- writel(CR0_FDXRFCEN, &regs->CR0Set);
- else
- writel(CR0_FDXRFCEN, &regs->CR0Clr);
+ for (i = MAC_REG_MAR; i < MAC_REG_IMR; i += 4)
+ writel(*((u32 *) (context->mac_reg + i)), ptr + i);
- if (BYTE_REG_BITS_IS_ON(PHYSR0_TXFLC, &regs->PHYSR0))
- writel(CR0_FDXTFCEN, &regs->CR0Set);
- else
- writel(CR0_FDXTFCEN, &regs->CR0Clr);
- break;
+ for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4)
+ writel(*((u32 *) (context->mac_reg + i)), ptr + i);
- case FLOW_CNTL_TX:
- writel(CR0_FDXTFCEN, &regs->CR0Set);
- writel(CR0_FDXRFCEN, &regs->CR0Clr);
- break;
+ for (i = MAC_REG_TDCSR_SET; i <= MAC_REG_RDCSR_SET; i++)
+ writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
+}
- case FLOW_CNTL_RX:
- writel(CR0_FDXRFCEN, &regs->CR0Set);
- writel(CR0_FDXTFCEN, &regs->CR0Clr);
- break;
+static int velocity_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct velocity_info *vptr = netdev_priv(dev);
+ unsigned long flags;
+ int i;
- case FLOW_CNTL_TX_RX:
- writel(CR0_FDXTFCEN, &regs->CR0Set);
- writel(CR0_FDXRFCEN, &regs->CR0Set);
- break;
+ if (!netif_running(vptr->dev))
+ return 0;
- case FLOW_CNTL_DISABLE:
- writel(CR0_FDXRFCEN, &regs->CR0Clr);
- writel(CR0_FDXTFCEN, &regs->CR0Clr);
- break;
+ pci_set_power_state(pdev, PCI_D0);
+ pci_enable_wake(pdev, 0, 0);
+ pci_restore_state(pdev);
- default:
- break;
+ mac_wol_reset(vptr->mac_regs);
+
+ spin_lock_irqsave(&vptr->lock, flags);
+ velocity_restore_context(vptr, &vptr->context);
+ velocity_init_registers(vptr, VELOCITY_INIT_WOL);
+ mac_disable_int(vptr->mac_regs);
+
+ velocity_tx_srv(vptr, 0);
+
+ for (i = 0; i < vptr->tx.numq; i++) {
+ if (vptr->tx.used[i])
+ mac_tx_queue_wake(vptr->mac_regs, i);
}
+ mac_enable_int(vptr->mac_regs);
+ spin_unlock_irqrestore(&vptr->lock, flags);
+ netif_device_attach(vptr->dev);
+
+ return 0;
}
+#endif
+
+/*
+ * Definition for our device driver. The PCI layer interface
+ * uses this to handle all our card discover and plugging
+ */
+static struct pci_driver velocity_driver = {
+ .name = VELOCITY_NAME,
+ .id_table = velocity_id_table,
+ .probe = velocity_found1,
+ .remove = __devexit_p(velocity_remove1),
+#ifdef CONFIG_PM
+ .suspend = velocity_suspend,
+ .resume = velocity_resume,
+#endif
+};
/**
@@ -2991,7 +3081,6 @@ static void enable_flow_control_ability(struct velocity_info *vptr)
* Called before an ethtool operation. We need to make sure the
* chip is out of D3 state before we poke at it.
*/
-
static int velocity_ethtool_up(struct net_device *dev)
{
struct velocity_info *vptr = netdev_priv(dev);
@@ -3007,7 +3096,6 @@ static int velocity_ethtool_up(struct net_device *dev)
* Called after an ethtool operation. Restore the chip back to D3
* state if it isn't running.
*/
-
static void velocity_ethtool_down(struct net_device *dev)
{
struct velocity_info *vptr = netdev_priv(dev);
@@ -3018,7 +3106,7 @@ static void velocity_ethtool_down(struct net_device *dev)
static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct velocity_info *vptr = netdev_priv(dev);
- struct mac_regs __iomem * regs = vptr->mac_regs;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
u32 status;
status = check_connection_type(vptr->mac_regs);
@@ -3072,13 +3160,6 @@ static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd
return ret;
}
-static u32 velocity_get_link(struct net_device *dev)
-{
- struct velocity_info *vptr = netdev_priv(dev);
- struct mac_regs __iomem * regs = vptr->mac_regs;
- return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, &regs->PHYSR0) ? 1 : 0;
-}
-
static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct velocity_info *vptr = netdev_priv(dev);
@@ -3157,338 +3238,86 @@ static const struct ethtool_ops velocity_ethtool_ops = {
.complete = velocity_ethtool_down
};
-/**
- * velocity_mii_ioctl - MII ioctl handler
- * @dev: network device
- * @ifr: the ifreq block for the ioctl
- * @cmd: the command
- *
- * Process MII requests made via ioctl from the network layer. These
- * are used by tools like kudzu to interrogate the link state of the
- * hardware
- */
-
-static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+#ifdef CONFIG_PM
+#ifdef CONFIG_INET
+static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr)
{
- struct velocity_info *vptr = netdev_priv(dev);
- struct mac_regs __iomem * regs = vptr->mac_regs;
+ struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
+ struct net_device *dev = ifa->ifa_dev->dev;
+ struct velocity_info *vptr;
unsigned long flags;
- struct mii_ioctl_data *miidata = if_mii(ifr);
- int err;
- switch (cmd) {
- case SIOCGMIIPHY:
- miidata->phy_id = readb(&regs->MIIADR) & 0x1f;
- break;
- case SIOCGMIIREG:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- if(velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0)
- return -ETIMEDOUT;
- break;
- case SIOCSMIIREG:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- spin_lock_irqsave(&vptr->lock, flags);
- err = velocity_mii_write(vptr->mac_regs, miidata->reg_num & 0x1f, miidata->val_in);
- spin_unlock_irqrestore(&vptr->lock, flags);
- check_connection_type(vptr->mac_regs);
- if(err)
- return err;
- break;
- default:
- return -EOPNOTSUPP;
+ if (dev_net(dev) != &init_net)
+ return NOTIFY_DONE;
+
+ spin_lock_irqsave(&velocity_dev_list_lock, flags);
+ list_for_each_entry(vptr, &velocity_dev_list, list) {
+ if (vptr->dev == dev) {
+ velocity_get_ip(vptr);
+ break;
+ }
}
- return 0;
-}
+ spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
-#ifdef CONFIG_PM
+ return NOTIFY_DONE;
+}
+#endif /* CONFIG_INET */
+#endif /* CONFIG_PM */
-/**
- * velocity_save_context - save registers
- * @vptr: velocity
- * @context: buffer for stored context
- *
- * Retrieve the current configuration from the velocity hardware
- * and stash it in the context structure, for use by the context
- * restore functions. This allows us to save things we need across
- * power down states
- */
+#if defined(CONFIG_PM) && defined(CONFIG_INET)
+static struct notifier_block velocity_inetaddr_notifier = {
+ .notifier_call = velocity_netdev_event,
+};
-static void velocity_save_context(struct velocity_info *vptr, struct velocity_context * context)
+static void velocity_register_notifier(void)
{
- struct mac_regs __iomem * regs = vptr->mac_regs;
- u16 i;
- u8 __iomem *ptr = (u8 __iomem *)regs;
-
- for (i = MAC_REG_PAR; i < MAC_REG_CR0_CLR; i += 4)
- *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
-
- for (i = MAC_REG_MAR; i < MAC_REG_TDCSR_CLR; i += 4)
- *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
-
- for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4)
- *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
-
+ register_inetaddr_notifier(&velocity_inetaddr_notifier);
}
-/**
- * velocity_restore_context - restore registers
- * @vptr: velocity
- * @context: buffer for stored context
- *
- * Reload the register configuration from the velocity context
- * created by velocity_save_context.
- */
-
-static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context)
+static void velocity_unregister_notifier(void)
{
- struct mac_regs __iomem * regs = vptr->mac_regs;
- int i;
- u8 __iomem *ptr = (u8 __iomem *)regs;
-
- for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4) {
- writel(*((u32 *) (context->mac_reg + i)), ptr + i);
- }
-
- /* Just skip cr0 */
- for (i = MAC_REG_CR1_SET; i < MAC_REG_CR0_CLR; i++) {
- /* Clear */
- writeb(~(*((u8 *) (context->mac_reg + i))), ptr + i + 4);
- /* Set */
- writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
- }
-
- for (i = MAC_REG_MAR; i < MAC_REG_IMR; i += 4) {
- writel(*((u32 *) (context->mac_reg + i)), ptr + i);
- }
+ unregister_inetaddr_notifier(&velocity_inetaddr_notifier);
+}
- for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4) {
- writel(*((u32 *) (context->mac_reg + i)), ptr + i);
- }
+#else
- for (i = MAC_REG_TDCSR_SET; i <= MAC_REG_RDCSR_SET; i++) {
- writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
- }
+#define velocity_register_notifier() do {} while (0)
+#define velocity_unregister_notifier() do {} while (0)
-}
+#endif /* defined(CONFIG_PM) && defined(CONFIG_INET) */
/**
- * wol_calc_crc - WOL CRC
- * @pattern: data pattern
- * @mask_pattern: mask
+ * velocity_init_module - load time function
*
- * Compute the wake on lan crc hashes for the packet header
- * we are interested in.
+ * Called when the velocity module is loaded. The PCI driver
+ * is registered with the PCI layer, and in turn will call
+ * the probe functions for each velocity adapter installed
+ * in the system.
*/
-
-static u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern)
+static int __init velocity_init_module(void)
{
- u16 crc = 0xFFFF;
- u8 mask;
- int i, j;
-
- for (i = 0; i < size; i++) {
- mask = mask_pattern[i];
-
- /* Skip this loop if the mask equals to zero */
- if (mask == 0x00)
- continue;
+ int ret;
- for (j = 0; j < 8; j++) {
- if ((mask & 0x01) == 0) {
- mask >>= 1;
- continue;
- }
- mask >>= 1;
- crc = crc_ccitt(crc, &(pattern[i * 8 + j]), 1);
- }
- }
- /* Finally, invert the result once to get the correct data */
- crc = ~crc;
- return bitrev32(crc) >> 16;
+ velocity_register_notifier();
+ ret = pci_register_driver(&velocity_driver);
+ if (ret < 0)
+ velocity_unregister_notifier();
+ return ret;
}
/**
- * velocity_set_wol - set up for wake on lan
- * @vptr: velocity to set WOL status on
- *
- * Set a card up for wake on lan either by unicast or by
- * ARP packet.
+ * velocity_cleanup - module unload
*
- * FIXME: check static buffer is safe here
+ * When the velocity hardware is unloaded this function is called.
+ * It will clean up the notifiers and the unregister the PCI
+ * driver interface for this hardware. This in turn cleans up
+ * all discovered interfaces before returning from the function
*/
-
-static int velocity_set_wol(struct velocity_info *vptr)
-{
- struct mac_regs __iomem * regs = vptr->mac_regs;
- static u8 buf[256];
- int i;
-
- static u32 mask_pattern[2][4] = {
- {0x00203000, 0x000003C0, 0x00000000, 0x0000000}, /* ARP */
- {0xfffff000, 0xffffffff, 0xffffffff, 0x000ffff} /* Magic Packet */
- };
-
- writew(0xFFFF, &regs->WOLCRClr);
- writeb(WOLCFG_SAB | WOLCFG_SAM, &regs->WOLCFGSet);
- writew(WOLCR_MAGIC_EN, &regs->WOLCRSet);
-
- /*
- if (vptr->wol_opts & VELOCITY_WOL_PHY)
- writew((WOLCR_LINKON_EN|WOLCR_LINKOFF_EN), &regs->WOLCRSet);
- */
-
- if (vptr->wol_opts & VELOCITY_WOL_UCAST) {
- writew(WOLCR_UNICAST_EN, &regs->WOLCRSet);
- }
-
- if (vptr->wol_opts & VELOCITY_WOL_ARP) {
- struct arp_packet *arp = (struct arp_packet *) buf;
- u16 crc;
- memset(buf, 0, sizeof(struct arp_packet) + 7);
-
- for (i = 0; i < 4; i++)
- writel(mask_pattern[0][i], &regs->ByteMask[0][i]);
-
- arp->type = htons(ETH_P_ARP);
- arp->ar_op = htons(1);
-
- memcpy(arp->ar_tip, vptr->ip_addr, 4);
-
- crc = wol_calc_crc((sizeof(struct arp_packet) + 7) / 8, buf,
- (u8 *) & mask_pattern[0][0]);
-
- writew(crc, &regs->PatternCRC[0]);
- writew(WOLCR_ARP_EN, &regs->WOLCRSet);
- }
-
- BYTE_REG_BITS_ON(PWCFG_WOLTYPE, &regs->PWCFGSet);
- BYTE_REG_BITS_ON(PWCFG_LEGACY_WOLEN, &regs->PWCFGSet);
-
- writew(0x0FFF, &regs->WOLSRClr);
-
- 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_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
- }
-
- if (vptr->mii_status & VELOCITY_SPEED_1000)
- MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs);
-
- BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
-
- {
- u8 GCR;
- GCR = readb(&regs->CHIPGCR);
- GCR = (GCR & ~CHIPGCR_FCGMII) | CHIPGCR_FCFDX;
- writeb(GCR, &regs->CHIPGCR);
- }
-
- BYTE_REG_BITS_OFF(ISR_PWEI, &regs->ISR);
- /* Turn on SWPTAG just before entering power mode */
- BYTE_REG_BITS_ON(STICKHW_SWPTAG, &regs->STICKHW);
- /* Go to bed ..... */
- BYTE_REG_BITS_ON((STICKHW_DS1 | STICKHW_DS0), &regs->STICKHW);
-
- return 0;
-}
-
-static int velocity_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct velocity_info *vptr = netdev_priv(dev);
- unsigned long flags;
-
- if(!netif_running(vptr->dev))
- return 0;
-
- netif_device_detach(vptr->dev);
-
- spin_lock_irqsave(&vptr->lock, flags);
- pci_save_state(pdev);
-#ifdef ETHTOOL_GWOL
- if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) {
- velocity_get_ip(vptr);
- velocity_save_context(vptr, &vptr->context);
- velocity_shutdown(vptr);
- velocity_set_wol(vptr);
- pci_enable_wake(pdev, PCI_D3hot, 1);
- pci_set_power_state(pdev, PCI_D3hot);
- } else {
- velocity_save_context(vptr, &vptr->context);
- velocity_shutdown(vptr);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
- }
-#else
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
-#endif
- spin_unlock_irqrestore(&vptr->lock, flags);
- return 0;
-}
-
-static int velocity_resume(struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct velocity_info *vptr = netdev_priv(dev);
- unsigned long flags;
- int i;
-
- if(!netif_running(vptr->dev))
- return 0;
-
- pci_set_power_state(pdev, PCI_D0);
- pci_enable_wake(pdev, 0, 0);
- pci_restore_state(pdev);
-
- mac_wol_reset(vptr->mac_regs);
-
- spin_lock_irqsave(&vptr->lock, flags);
- velocity_restore_context(vptr, &vptr->context);
- velocity_init_registers(vptr, VELOCITY_INIT_WOL);
- mac_disable_int(vptr->mac_regs);
-
- velocity_tx_srv(vptr, 0);
-
- for (i = 0; i < vptr->tx.numq; i++) {
- if (vptr->tx.used[i]) {
- mac_tx_queue_wake(vptr->mac_regs, i);
- }
- }
-
- mac_enable_int(vptr->mac_regs);
- spin_unlock_irqrestore(&vptr->lock, flags);
- netif_device_attach(vptr->dev);
-
- return 0;
-}
-
-#ifdef CONFIG_INET
-
-static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr)
+static void __exit velocity_cleanup_module(void)
{
- struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
- struct net_device *dev = ifa->ifa_dev->dev;
- struct velocity_info *vptr;
- unsigned long flags;
-
- if (dev_net(dev) != &init_net)
- return NOTIFY_DONE;
-
- spin_lock_irqsave(&velocity_dev_list_lock, flags);
- list_for_each_entry(vptr, &velocity_dev_list, list) {
- if (vptr->dev == dev) {
- velocity_get_ip(vptr);
- break;
- }
- }
- spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
-
- return NOTIFY_DONE;
+ velocity_unregister_notifier();
+ pci_unregister_driver(&velocity_driver);
}
-#endif
-#endif
+module_init(velocity_init_module);
+module_exit(velocity_cleanup_module);
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index 4cd3f6c97379..2f00c13ab502 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -96,8 +96,8 @@
* Bits in the CSM register
*/
-#define CSM_IPOK 0x40 //IP Checkusm validatiaon ok
-#define CSM_TUPOK 0x20 //TCP/UDP Checkusm validatiaon ok
+#define CSM_IPOK 0x40 //IP Checksum validation ok
+#define CSM_TUPOK 0x20 //TCP/UDP Checksum validation ok
#define CSM_FRAG 0x10 //Fragment IP datagram
#define CSM_IPKT 0x04 //Received an IP packet
#define CSM_TCPKT 0x02 //Received a TCP packet
@@ -819,7 +819,7 @@ enum velocity_owner {
* Bits in the EECSR register
*/
-#define EECSR_EMBP 0x40 /* eeprom embeded programming */
+#define EECSR_EMBP 0x40 /* eeprom embedded programming */
#define EECSR_RELOAD 0x20 /* eeprom content reload */
#define EECSR_DPM 0x10 /* eeprom direct programming */
#define EECSR_ECS 0x08 /* eeprom CS pin */
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 2a6e81d5b579..a6f903f00924 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -774,6 +774,7 @@ static struct ethtool_ops virtnet_ethtool_ops = {
.set_tx_csum = virtnet_set_tx_csum,
.set_sg = ethtool_op_set_sg,
.set_tso = ethtool_op_set_tso,
+ .set_ufo = ethtool_op_set_ufo,
.get_link = ethtool_op_get_link,
};
@@ -1005,7 +1006,7 @@ static unsigned int features[] = {
VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC,
VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6,
VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6,
- VIRTIO_NET_F_GUEST_ECN, /* We don't yet handle UFO input. */
+ VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO,
VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ,
VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN,
VIRTIO_F_NOTIFY_ON_EMPTY,
diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c
index 58d2551c78ed..9e94c4b0fb18 100644
--- a/drivers/net/vxge/vxge-config.c
+++ b/drivers/net/vxge/vxge-config.c
@@ -313,14 +313,6 @@ __vxge_hw_device_reg_addr_get(struct __vxge_hw_device *hldev)
hldev->kdfc = (u8 __iomem *)(hldev->bar0 +
VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64));
break;
- case 2:
- hldev->kdfc = (u8 __iomem *)(hldev->bar1 +
- VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64));
- break;
- case 4:
- hldev->kdfc = (u8 __iomem *)(hldev->bar2 +
- VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64));
- break;
default:
break;
}
@@ -831,8 +823,6 @@ vxge_hw_device_initialize(
sizeof(struct vxge_hw_device_config));
hldev->bar0 = attr->bar0;
- hldev->bar1 = attr->bar1;
- hldev->bar2 = attr->bar2;
hldev->pdev = attr->pdev;
hldev->uld_callbacks.link_up = attr->uld_callbacks.link_up;
diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h
index afbdf6f4d224..224acea771ed 100644
--- a/drivers/net/vxge/vxge-config.h
+++ b/drivers/net/vxge/vxge-config.h
@@ -682,8 +682,6 @@ struct __vxge_hw_vpath_handle{
* @major_revision: PCI Device major revision
* @minor_revision: PCI Device minor revision
* @bar0: BAR0 virtual address.
- * @bar1: BAR1 virtual address.
- * @bar2: BAR2 virtual address.
* @pdev: Physical device handle
* @config: Confguration passed by the LL driver at initialization
* @link_state: Link state
@@ -698,8 +696,6 @@ struct __vxge_hw_device {
u8 major_revision;
u8 minor_revision;
void __iomem *bar0;
- void __iomem *bar1;
- void __iomem *bar2;
struct pci_dev *pdev;
struct net_device *ndev;
struct vxge_hw_device_config config;
@@ -788,17 +784,13 @@ struct vxge_hw_device_hw_info {
/**
* struct vxge_hw_device_attr - Device memory spaces.
* @bar0: BAR0 virtual address.
- * @bar1: BAR1 virtual address.
- * @bar2: BAR2 virtual address.
* @pdev: PCI device object.
*
- * Device memory spaces. Includes configuration, BAR0, BAR1, etc. per device
+ * Device memory spaces. Includes configuration, BAR0 etc. per device
* mapped memories. Also, includes a pointer to OS-specific PCI device object.
*/
struct vxge_hw_device_attr {
void __iomem *bar0;
- void __iomem *bar1;
- void __iomem *bar2;
struct pci_dev *pdev;
struct vxge_hw_uld_cbs uld_callbacks;
};
diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c
index 6034497536a4..7b5402b50d0a 100644
--- a/drivers/net/vxge/vxge-main.c
+++ b/drivers/net/vxge/vxge-main.c
@@ -374,10 +374,10 @@ vxge_rx_complete(struct vxge_ring *ring, struct sk_buff *skb, u16 vlan,
if (ring->vlgrp && ext_info->vlan &&
(ring->vlan_tag_strip ==
VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE))
- vlan_gro_receive(&ring->napi, ring->vlgrp,
+ vlan_gro_receive(ring->napi_p, ring->vlgrp,
ext_info->vlan, skb);
else
- napi_gro_receive(&ring->napi, skb);
+ napi_gro_receive(ring->napi_p, skb);
} else {
if (ring->vlgrp && vlan &&
(ring->vlan_tag_strip ==
@@ -454,6 +454,8 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
vxge_hw_ring_rxd_1b_get(ringh, dtr, &dma_sizes);
pkt_length = dma_sizes;
+ pkt_length -= ETH_FCS_LEN;
+
vxge_debug_rx(VXGE_TRACE,
"%s: %s:%d Packet Length = %d",
ring->ndev->name, __func__, __LINE__, pkt_length);
@@ -817,7 +819,6 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
u64 dma_pointer;
struct vxge_tx_priv *txdl_priv = NULL;
struct __vxge_hw_fifo *fifo_hw;
- u32 max_mss = 0x0;
int offload_type;
unsigned long flags = 0;
int vpath_no = 0;
@@ -969,10 +970,6 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
int mss = vxge_tcp_mss(skb);
if (mss) {
- max_mss = dev->mtu + ETH_HLEN -
- VXGE_HW_TCPIP_HEADER_MAX_SIZE;
- if (mss > max_mss)
- mss = max_mss;
vxge_debug_tx(VXGE_TRACE,
"%s: %s:%d mss = %d",
dev->name, __func__, __LINE__, mss);
@@ -1000,7 +997,7 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
VXGE_COMPLETE_VPATH_TX(fifo);
vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...",
dev->name, __func__, __LINE__);
- return 0;
+ return NETDEV_TX_OK;
_exit0:
vxge_debug_tx(VXGE_TRACE, "%s: pci_map_page failed", dev->name);
@@ -1024,7 +1021,7 @@ _exit2:
spin_unlock_irqrestore(&fifo->tx_lock, flags);
VXGE_COMPLETE_VPATH_TX(fifo);
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -2137,16 +2134,16 @@ int vxge_open_vpaths(struct vxgedev *vdev)
*/
static irqreturn_t vxge_isr_napi(int irq, void *dev_id)
{
- struct __vxge_hw_device *hldev = (struct __vxge_hw_device *)dev_id;
- struct vxgedev *vdev;
struct net_device *dev;
+ struct __vxge_hw_device *hldev;
u64 reason;
enum vxge_hw_status status;
+ struct vxgedev *vdev = (struct vxgedev *) dev_id;;
vxge_debug_intr(VXGE_TRACE, "%s:%d", __func__, __LINE__);
- dev = hldev->ndev;
- vdev = netdev_priv(dev);
+ dev = vdev->ndev;
+ hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev);
if (pci_channel_offline(vdev->pdev))
return IRQ_NONE;
@@ -2417,15 +2414,13 @@ static void vxge_rem_isr(struct vxgedev *vdev)
#endif
if (vdev->config.intr_type == INTA) {
synchronize_irq(vdev->pdev->irq);
- free_irq(vdev->pdev->irq, hldev);
+ free_irq(vdev->pdev->irq, vdev);
}
}
static int vxge_add_isr(struct vxgedev *vdev)
{
int ret = 0;
- struct __vxge_hw_device *hldev =
- (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev);
#ifdef CONFIG_PCI_MSI
int vp_idx = 0, intr_idx = 0, intr_cnt = 0, msix_idx = 0, irq_req = 0;
u64 function_mode = vdev->config.device_hw_info.function_mode;
@@ -2579,7 +2574,7 @@ INTA_MODE:
if (vdev->config.intr_type == INTA) {
ret = request_irq((int) vdev->pdev->irq,
vxge_isr_napi,
- IRQF_SHARED, vdev->desc[0], hldev);
+ IRQF_SHARED, vdev->desc[0], vdev);
if (ret) {
vxge_debug_init(VXGE_ERR,
"%s %s-%d: ISR registration failed",
@@ -2712,11 +2707,15 @@ vxge_open(struct net_device *dev)
netif_napi_add(dev, &vdev->napi, vxge_poll_inta,
vdev->config.napi_weight);
napi_enable(&vdev->napi);
+ for (i = 0; i < vdev->no_of_vpath; i++)
+ vdev->vpaths[i].ring.napi_p = &vdev->napi;
} else {
for (i = 0; i < vdev->no_of_vpath; i++) {
netif_napi_add(dev, &vdev->vpaths[i].ring.napi,
vxge_poll_msix, vdev->config.napi_weight);
napi_enable(&vdev->vpaths[i].ring.napi);
+ vdev->vpaths[i].ring.napi_p =
+ &vdev->vpaths[i].ring.napi;
}
}
@@ -2890,6 +2889,9 @@ int do_vxge_close(struct net_device *dev, int do_io)
vdev = (struct vxgedev *)netdev_priv(dev);
hldev = (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev);
+ if (unlikely(!is_vxge_card_up(vdev)))
+ return 0;
+
/* If vxge_handle_crit_err task is executing,
* wait till it completes. */
while (test_and_set_bit(__VXGE_STATE_RESET_CARD, &vdev->state))
@@ -4152,18 +4154,6 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
attr.bar0,
(unsigned long long)pci_resource_start(pdev, 0));
- attr.bar1 = pci_ioremap_bar(pdev, 2);
- if (!attr.bar1) {
- vxge_debug_init(VXGE_ERR,
- "%s : cannot remap io memory bar2", __func__);
- ret = -ENODEV;
- goto _exit3;
- }
- vxge_debug_ll_config(VXGE_TRACE,
- "pci ioremap bar1: %p:0x%llx",
- attr.bar1,
- (unsigned long long)pci_resource_start(pdev, 2));
-
status = vxge_hw_device_hw_info_get(attr.bar0,
&ll_config.device_hw_info);
if (status != VXGE_HW_OK) {
@@ -4171,17 +4161,17 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
"%s: Reading of hardware info failed."
"Please try upgrading the firmware.", VXGE_DRIVER_NAME);
ret = -EINVAL;
- goto _exit4;
+ goto _exit3;
}
if (ll_config.device_hw_info.fw_version.major !=
- VXGE_DRIVER_VERSION_MAJOR) {
+ VXGE_DRIVER_FW_VERSION_MAJOR) {
vxge_debug_init(VXGE_ERR,
- "FW Ver.(maj): %d not driver's expected version: %d",
- ll_config.device_hw_info.fw_version.major,
- VXGE_DRIVER_VERSION_MAJOR);
+ "%s: Incorrect firmware version."
+ "Please upgrade the firmware to version 1.x.x",
+ VXGE_DRIVER_NAME);
ret = -EINVAL;
- goto _exit4;
+ goto _exit3;
}
vpath_mask = ll_config.device_hw_info.vpath_mask;
@@ -4189,7 +4179,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
vxge_debug_ll_config(VXGE_TRACE,
"%s: No vpaths available in device", VXGE_DRIVER_NAME);
ret = -EINVAL;
- goto _exit4;
+ goto _exit3;
}
vxge_debug_ll_config(VXGE_TRACE,
@@ -4222,7 +4212,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
vxge_debug_ll_config(VXGE_ERR,
"%s: No more vpaths to configure", VXGE_DRIVER_NAME);
ret = 0;
- goto _exit4;
+ goto _exit3;
}
/* Setting driver callbacks */
@@ -4235,7 +4225,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
vxge_debug_init(VXGE_ERR,
"Failed to initialize device (%d)", status);
ret = -EINVAL;
- goto _exit4;
+ goto _exit3;
}
vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_LL);
@@ -4260,7 +4250,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
if (vxge_device_register(hldev, &ll_config, high_dma, no_of_vpath,
&vdev)) {
ret = -EINVAL;
- goto _exit5;
+ goto _exit4;
}
vxge_hw_device_debug_set(hldev, VXGE_TRACE, VXGE_COMPONENT_LL);
@@ -4271,7 +4261,6 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
hldev->ndev = vdev->ndev;
vdev->mtu = VXGE_HW_DEFAULT_MTU;
vdev->bar0 = attr.bar0;
- vdev->bar1 = attr.bar1;
vdev->max_vpath_supported = max_vpath_supported;
vdev->no_of_vpath = no_of_vpath;
@@ -4336,6 +4325,27 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
ll_config.device_hw_info.fw_version.version,
ll_config.device_hw_info.fw_date.date);
+ if (new_device) {
+ switch (ll_config.device_hw_info.function_mode) {
+ case VXGE_HW_FUNCTION_MODE_SINGLE_FUNCTION:
+ vxge_debug_init(VXGE_TRACE,
+ "%s: Single Function Mode Enabled", vdev->ndev->name);
+ break;
+ case VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION:
+ vxge_debug_init(VXGE_TRACE,
+ "%s: Multi Function Mode Enabled", vdev->ndev->name);
+ break;
+ case VXGE_HW_FUNCTION_MODE_SRIOV:
+ vxge_debug_init(VXGE_TRACE,
+ "%s: Single Root IOV Mode Enabled", vdev->ndev->name);
+ break;
+ case VXGE_HW_FUNCTION_MODE_MRIOV:
+ vxge_debug_init(VXGE_TRACE,
+ "%s: Multi Root IOV Mode Enabled", vdev->ndev->name);
+ break;
+ }
+ }
+
vxge_print_parm(vdev, vpath_mask);
/* Store the fw version for ethttool option */
@@ -4353,7 +4363,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
"%s: mac_addr_list : memory allocation failed",
vdev->ndev->name);
ret = -EPERM;
- goto _exit6;
+ goto _exit5;
}
macaddr = (u8 *)&entry->macaddr;
memcpy(macaddr, vdev->ndev->dev_addr, ETH_ALEN);
@@ -4361,6 +4371,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
vdev->vpaths[i].mac_addr_cnt = 1;
}
+ kfree(device_config);
vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...",
vdev->ndev->name, __func__, __LINE__);
@@ -4370,16 +4381,14 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
return 0;
-_exit6:
+_exit5:
for (i = 0; i < vdev->no_of_vpath; i++)
vxge_free_mac_add_list(&vdev->vpaths[i]);
vxge_device_unregister(hldev);
-_exit5:
+_exit4:
pci_disable_sriov(pdev);
vxge_hw_device_terminate(hldev);
-_exit4:
- iounmap(attr.bar1);
_exit3:
iounmap(attr.bar0);
_exit2:
@@ -4438,7 +4447,6 @@ vxge_remove(struct pci_dev *pdev)
kfree(vdev->vpaths);
iounmap(vdev->bar0);
- iounmap(vdev->bar1);
pci_disable_sriov(pdev);
diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h
index 9704b2bd4320..18d824c3ab93 100644
--- a/drivers/net/vxge/vxge-main.h
+++ b/drivers/net/vxge/vxge-main.h
@@ -21,7 +21,7 @@
#define VXGE_DRIVER_NAME "vxge"
#define VXGE_DRIVER_VENDOR "Neterion, Inc"
-#define VXGE_DRIVER_VERSION_MAJOR 0
+#define VXGE_DRIVER_FW_VERSION_MAJOR 1
#define DRV_VERSION VXGE_VERSION_MAJOR"."VXGE_VERSION_MINOR"."\
VXGE_VERSION_FIX"."VXGE_VERSION_BUILD"-"\
@@ -260,6 +260,7 @@ struct vxge_ring {
int gro_enable;
struct napi_struct napi;
+ struct napi_struct *napi_p;
#define VXGE_MAX_MAC_ADDR_COUNT 30
@@ -363,7 +364,6 @@ struct vxgedev {
struct __vxge_hw_vpath_handle *vp_handles[VXGE_HW_MAX_VIRTUAL_PATHS];
void __iomem *bar0;
- void __iomem *bar1;
struct vxge_sw_stats stats;
int mtu;
/* Below variables are used for vpath selection to transmit a packet */
diff --git a/drivers/net/vxge/vxge-reg.h b/drivers/net/vxge/vxge-reg.h
index 10f4da32929f..9a3b823e08d4 100644
--- a/drivers/net/vxge/vxge-reg.h
+++ b/drivers/net/vxge/vxge-reg.h
@@ -1784,7 +1784,7 @@ struct vxge_hw_mrpcim_reg {
#define VXGE_HW_XMAC_GEN_ERR_REG_XMACJ_XMAC_FSM_ERR vxge_mBIT(63)
/*0x01e18*/ u64 xmac_gen_err_mask;
/*0x01e20*/ u64 xmac_gen_err_alarm;
-/*0x01e28*/ u64 xmac_link_err_port_reg[2];
+/*0x01e28*/ u64 xmac_link_err_port0_reg;
#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_DOWN vxge_mBIT(3)
#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_UP vxge_mBIT(7)
#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_WENT_DOWN vxge_mBIT(11)
@@ -1798,8 +1798,11 @@ struct vxge_hw_mrpcim_reg {
#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_RATEMGMT_LASI_INV vxge_mBIT(39)
#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMDIO_MDIO_MGR_ACCESS_COMPLETE \
vxge_mBIT(47)
-/*0x01e30*/ u64 xmac_link_err_port_mask[2];
-/*0x01e38*/ u64 xmac_link_err_port_alarm[2];
+/*0x01e30*/ u64 xmac_link_err_port0_mask;
+/*0x01e38*/ u64 xmac_link_err_port0_alarm;
+/*0x01e40*/ u64 xmac_link_err_port1_reg;
+/*0x01e48*/ u64 xmac_link_err_port1_mask;
+/*0x01e50*/ u64 xmac_link_err_port1_alarm;
/*0x01e58*/ u64 xgxs_gen_err_reg;
#define VXGE_HW_XGXS_GEN_ERR_REG_XGXS_XGXS_FSM_ERR vxge_mBIT(63)
/*0x01e60*/ u64 xgxs_gen_err_mask;
diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h
index 7567a1140d07..8260b91fd795 100644
--- a/drivers/net/vxge/vxge-traffic.h
+++ b/drivers/net/vxge/vxge-traffic.h
@@ -35,8 +35,6 @@
VXGE_HW_HEADER_VLAN_SIZE + \
VXGE_HW_HEADER_SNAP_SIZE)
-#define VXGE_HW_TCPIP_HEADER_MAX_SIZE (64 + 64)
-
/* 32bit alignments */
#define VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN 2
#define VXGE_HW_HEADER_802_2_SNAP_ALIGN 2
diff --git a/drivers/net/vxge/vxge-version.h b/drivers/net/vxge/vxge-version.h
index 82786ffb7dd9..580c6eb077b9 100644
--- a/drivers/net/vxge/vxge-version.h
+++ b/drivers/net/vxge/vxge-version.h
@@ -18,6 +18,6 @@
#define VXGE_VERSION_MAJOR "2"
#define VXGE_VERSION_MINOR "0"
#define VXGE_VERSION_FIX "4"
-#define VXGE_VERSION_BUILD "17795"
+#define VXGE_VERSION_BUILD "17899"
#define VXGE_VERSION_FOR "k"
#endif
diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c
index f525f9fe74db..4ae9bd297cc2 100644
--- a/drivers/net/wan/cycx_x25.c
+++ b/drivers/net/wan/cycx_x25.c
@@ -663,7 +663,7 @@ static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb,
free_packet:
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* Get Ethernet-style interface statistics.
diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
index 2fa275a58f9d..8526b6d1ee4d 100644
--- a/drivers/net/wan/dlci.c
+++ b/drivers/net/wan/dlci.c
@@ -194,7 +194,7 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev)
ret = 0;
if (!skb || !dev)
- return(0);
+ return NETDEV_TX_OK;
dlp = netdev_priv(dev);
@@ -219,7 +219,7 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev)
/* Alan Cox recommends always returning 0, and always freeing the packet */
/* experience suggest a slightly more conservative approach */
- if (!ret)
+ if (ret == NETDEV_TX_OK)
{
dev_kfree_skb(skb);
netif_wake_queue(dev);
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index 8face5db8f32..e81946d98543 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -1182,7 +1182,7 @@ static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (dscc4_tx_quiescent(dpriv, dev))
dscc4_do_tx(dpriv, dev);
- return 0;
+ return NETDEV_TX_OK;
}
static int dscc4_close(struct net_device *dev)
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index 25c9ef6a1815..20a1237a3d74 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -792,25 +792,6 @@ fst_process_rx_status(int rx_status, char *name)
*/
break;
}
-
- case NET_RX_CN_LOW:
- {
- dbg(DBG_ASS, "%s: Receive Low Congestion\n", name);
- break;
- }
-
- case NET_RX_CN_MOD:
- {
- dbg(DBG_ASS, "%s: Receive Moderate Congestion\n", name);
- break;
- }
-
- case NET_RX_CN_HIGH:
- {
- dbg(DBG_ASS, "%s: Receive High Congestion\n", name);
- break;
- }
-
case NET_RX_DROP:
{
dbg(DBG_ASS, "%s: Received packet dropped\n", name);
@@ -2313,7 +2294,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev)
dbg(DBG_ASS,
"Tried to transmit but no carrier on card %d port %d\n",
card->card_no, port->index);
- return 0;
+ return NETDEV_TX_OK;
}
/* Drop it if it's too big! MTU failure ? */
@@ -2322,7 +2303,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev)
LEN_TX_BUFFER);
dev_kfree_skb(skb);
dev->stats.tx_errors++;
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -2356,7 +2337,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_errors++;
dbg(DBG_ASS, "Tx queue overflow card %d port %d\n",
card->card_no, port->index);
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -2373,7 +2354,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev)
fst_q_work_item(&fst_work_txq, card->card_no);
tasklet_schedule(&fst_tx_task);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index bfa0161a02d3..52438c76bf8a 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -421,7 +421,7 @@ static int pvc_xmit(struct sk_buff *skb, struct net_device *dev)
GFP_ATOMIC)) {
dev->stats.tx_dropped++;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
skb_put(skb, pad);
memset(skb->data + len, 0, pad);
@@ -435,13 +435,13 @@ static int pvc_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_compressed++;
skb->dev = pvc->frad;
dev_queue_xmit(skb);
- return 0;
+ return NETDEV_TX_OK;
}
}
dev->stats.tx_dropped++;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static inline void fr_log_dlci_active(pvc_device *pvc)
diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
index 45b1822c962d..d1492ae5d30a 100644
--- a/drivers/net/wan/lmc/lmc_main.c
+++ b/drivers/net/wan/lmc/lmc_main.c
@@ -1428,7 +1428,7 @@ static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev)
lmc_softc_t *sc = dev_to_sc(dev);
u32 flag;
int entry;
- int ret = 0;
+ int ret = NETDEV_TX_OK;
unsigned long flags;
lmc_trace(dev, "lmc_start_xmit in");
diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c
index 3fb9dbc88a1a..545178e6765d 100644
--- a/drivers/net/wan/sbni.c
+++ b/drivers/net/wan/sbni.c
@@ -465,7 +465,7 @@ sbni_start_xmit( struct sk_buff *skb, struct net_device *dev )
prepare_to_send( skb, p );
spin_unlock( &nl->lock );
netif_start_queue( dev );
- return 0;
+ return NETDEV_TX_OK;
}
}
@@ -485,7 +485,7 @@ sbni_start_xmit( struct sk_buff *skb, struct net_device *dev )
prepare_to_send( skb, dev );
spin_unlock( &nl->lock );
- return 0;
+ return NETDEV_TX_OK;
}
#endif /* CONFIG_SBNI_MULTILINE */
diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c
index e4ad7b6b52eb..03b76adbe5f0 100644
--- a/drivers/net/wan/wanxl.c
+++ b/drivers/net/wan/wanxl.c
@@ -310,7 +310,7 @@ static int wanxl_xmit(struct sk_buff *skb, struct net_device *dev)
}
spin_unlock(&port->lock);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index d67e208ab375..1047920e742c 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -308,7 +308,7 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_ERR "%s: xmit call when iface is down\n",
dev->name);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
switch (skb->data[0]) {
@@ -319,14 +319,14 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
if (err != LAPB_OK)
printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
case 0x02: /* Disconnect request .. 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);
default:
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
skb_pull(skb, 1); /* Remove control byte */
/*
@@ -344,9 +344,9 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
if (err != LAPB_OK) {
printk(KERN_ERR "x25_asy: lapb_data_request error - %d\n", err);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index 2538825d1c66..ea7b29034aab 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -58,6 +58,7 @@
*/
#include <linux/debugfs.h>
+#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sdio_func.h>
#include "i2400m-sdio.h"
@@ -501,15 +502,12 @@ void i2400ms_remove(struct sdio_func *func)
d_fnend(3, dev, "SDIO func %p\n", func);
}
-enum {
- I2400MS_INTEL_VID = 0x89,
-};
-
static
const struct sdio_device_id i2400ms_sdio_ids[] = {
- /* Intel: i2400m WiMAX over SDIO */
- { SDIO_DEVICE(I2400MS_INTEL_VID, 0x1402) },
- { }, /* end: all zeroes */
+ /* Intel: i2400m WiMAX (iwmc3200) over SDIO */
+ { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL,
+ SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX) },
+ { /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(sdio, i2400ms_sdio_ids);
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 5bc00db21b24..ca7a8a31d0b9 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -428,10 +428,12 @@ config RTL8187
Micronet SP907GK V5
Encore ENUWI-G2
Trendnet TEW-424UB
- ASUS P5B Deluxe
+ ASUS P5B Deluxe/P5K Premium motherboards
Toshiba Satellite Pro series of laptops
Asus Wireless Link
- Linksys WUSB54GC-EU
+ Linksys WUSB54GC-EU v2
+ (v1 = rt73usb; v3 is rt2070-based,
+ use staging/rt3070 or try rt2800usb)
Thanks to Realtek for their support!
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index 2b9e379994a1..5695911bc602 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -452,7 +452,8 @@ static void adm8211_interrupt_rci(struct ieee80211_hw *dev)
rx_status.freq = adm8211_channels[priv->channel - 1].center_freq;
rx_status.band = IEEE80211_BAND_2GHZ;
- ieee80211_rx_irqsafe(dev, skb, &rx_status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+ ieee80211_rx_irqsafe(dev, skb);
}
entry = (++priv->cur_rx) % priv->rx_ring_size;
@@ -1963,14 +1964,6 @@ static void __devexit adm8211_remove(struct pci_dev *pdev)
#ifdef CONFIG_PM
static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state)
{
- struct ieee80211_hw *dev = pci_get_drvdata(pdev);
- struct adm8211_priv *priv = dev->priv;
-
- if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) {
- ieee80211_stop_queues(dev);
- adm8211_stop(dev);
- }
-
pci_save_state(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
return 0;
@@ -1978,17 +1971,8 @@ static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state)
static int adm8211_resume(struct pci_dev *pdev)
{
- struct ieee80211_hw *dev = pci_get_drvdata(pdev);
- struct adm8211_priv *priv = dev->priv;
-
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
-
- if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) {
- adm8211_start(dev);
- ieee80211_wake_queues(dev);
- }
-
return 0;
}
#endif /* CONFIG_PM */
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 8ce5e4cee168..c150c4858576 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -1927,7 +1927,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
if (!skb) {
airo_print_err(dev->name, "%s: skb == NULL!",__func__);
- return 0;
+ return NETDEV_TX_OK;
}
npacks = skb_queue_len (&ai->txq);
@@ -1938,7 +1938,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
return NETDEV_TX_BUSY;
}
skb_queue_tail (&ai->txq, skb);
- return 0;
+ return NETDEV_TX_OK;
}
spin_lock_irqsave(&ai->aux_lock, flags);
@@ -1951,7 +1951,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
set_bit(FLAG_PENDING_XMIT, &ai->flags);
mpi_send_packet (dev);
}
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -2127,7 +2127,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
if ( skb == NULL ) {
airo_print_err(dev->name, "%s: skb == NULL!", __func__);
- return 0;
+ return NETDEV_TX_OK;
}
/* Find a vacant FID */
@@ -2155,7 +2155,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
wake_up_interruptible(&priv->thr_wait);
} else
airo_end_xmit(dev);
- return 0;
+ return NETDEV_TX_OK;
}
static void airo_end_xmit11(struct net_device *dev) {
@@ -2199,7 +2199,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
if ( skb == NULL ) {
airo_print_err(dev->name, "%s: skb == NULL!", __func__);
- return 0;
+ return NETDEV_TX_OK;
}
/* Find a vacant FID */
@@ -2227,7 +2227,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
wake_up_interruptible(&priv->thr_wait);
} else
airo_end_xmit11(dev);
- return 0;
+ return NETDEV_TX_OK;
}
static void airo_read_stats(struct net_device *dev)
diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c
index d84caf198a23..f96c634e2d35 100644
--- a/drivers/net/wireless/arlan-main.c
+++ b/drivers/net/wireless/arlan-main.c
@@ -1022,7 +1022,7 @@ static int arlan_mac_addr(struct net_device *dev, void *p)
ARLAN_DEBUG_ENTRY("arlan_mac_addr");
return -EINVAL;
- if (!netif_running(dev))
+ if (netif_running(dev))
return -EBUSY;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
@@ -1193,7 +1193,7 @@ static int arlan_tx(struct sk_buff *skb, struct net_device *dev)
arlan_process_interrupt(dev);
ARLAN_DEBUG_EXIT("arlan_tx");
- return 0;
+ return NETDEV_TX_OK;
bad_end:
arlan_process_interrupt(dev);
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 4efbdbe6d6bf..13303fa34734 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -1568,7 +1568,8 @@ static void at76_rx_tasklet(unsigned long param)
at76_dbg(DBG_MAC80211, "calling ieee80211_rx_irqsafe(): %d/%d",
priv->rx_skb->len, priv->rx_skb->data_len);
- ieee80211_rx_irqsafe(priv->hw, priv->rx_skb, &rx_status);
+ memcpy(IEEE80211_SKB_RXCB(priv->rx_skb), &rx_status, sizeof(rx_status));
+ ieee80211_rx_irqsafe(priv->hw, priv->rx_skb);
/* Use a new skb for the next receive */
priv->rx_skb = NULL;
diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h
index bb97981fb248..e6c3ee3e0581 100644
--- a/drivers/net/wireless/ath/ar9170/ar9170.h
+++ b/drivers/net/wireless/ath/ar9170/ar9170.h
@@ -109,11 +109,52 @@ struct ar9170_rxstream_mpdu_merge {
bool has_plcp;
};
+#define AR9170_NUM_MAX_BA_RETRY 5
+#define AR9170_NUM_TID 16
+#define WME_BA_BMP_SIZE 64
+#define AR9170_NUM_MAX_AGG_LEN (2 * WME_BA_BMP_SIZE)
+
+#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;
+ u8 retry;
+};
+
#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
+
struct ar9170 {
struct ieee80211_hw *hw;
struct mutex mutex;
@@ -187,14 +228,25 @@ 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;
+ unsigned int tx_ampdu_pending;
/* rxstream mpdu merge */
struct ar9170_rxstream_mpdu_merge rx_mpdu;
struct sk_buff *rx_failover;
int rx_failover_missing;
+
+ /* (cached) HW A-MPDU settings */
+ u8 global_ampdu_density;
+ u8 global_ampdu_factor;
};
struct ar9170_sta_info {
+ struct ar9170_sta_tid agg[AR9170_NUM_TID];
+ unsigned int ampdu_max_len;
};
#define AR9170_TX_FLAG_WAIT_FOR_ACK BIT(0)
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
index 9d38cf60a0db..c7287a883a48 100644
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ b/drivers/net/wireless/ath/ar9170/main.c
@@ -49,6 +49,10 @@ 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), \
@@ -148,12 +152,15 @@ static struct ieee80211_channel ar9170_5ghz_chantable[] = {
.cap = IEEE80211_HT_CAP_MAX_AMSDU | \
IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
IEEE80211_HT_CAP_SGI_40 | \
+ IEEE80211_HT_CAP_GRN_FLD | \
IEEE80211_HT_CAP_DSSSCCK40 | \
IEEE80211_HT_CAP_SM_PS, \
.ampdu_factor = 3, \
.ampdu_density = 6, \
.mcs = { \
- .rx_mask = { 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, }, \
+ .rx_mask = { 0xff, 0xff, 0, 0, 0x1, 0, 0, 0, 0, 0, }, \
+ .rx_highest = cpu_to_le16(300), \
+ .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
}, \
}
@@ -174,8 +181,31 @@ static struct ieee80211_supported_band ar9170_band_5GHz = {
};
static void ar9170_tx(struct ar9170 *ar);
+static bool ar9170_tx_ampdu(struct ar9170 *ar);
-#ifdef AR9170_QUEUE_DEBUG
+static inline u16 ar9170_get_seq_h(struct ieee80211_hdr *hdr)
+{
+ return le16_to_cpu(hdr->seq_ctrl) >> 4;
+}
+
+static inline u16 ar9170_get_seq(struct sk_buff *skb)
+{
+ struct ar9170_tx_control *txc = (void *) skb->data;
+ return ar9170_get_seq_h((void *) txc->frame_data);
+}
+
+static inline u16 ar9170_get_tid(struct sk_buff *skb)
+{
+ struct ar9170_tx_control *txc = (void *) skb->data;
+ struct ieee80211_hdr *hdr = (void *) txc->frame_data;
+
+ return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK;
+}
+
+#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)
static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
{
struct ar9170_tx_control *txc = (void *) skb->data;
@@ -183,10 +213,10 @@ static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
struct ieee80211_hdr *hdr = (void *) txc->frame_data;
- printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x "
+ printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x s:%d "
"mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n",
wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb),
- ieee80211_get_DA(hdr), arinfo->flags,
+ ieee80211_get_DA(hdr), arinfo->flags, ar9170_get_seq_h(hdr),
le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control),
jiffies_to_msecs(arinfo->timeout - jiffies));
}
@@ -210,7 +240,9 @@ 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 */
+#ifdef AR9170_QUEUE_DEBUG
static void ar9170_dump_txqueue(struct ar9170 *ar,
struct sk_buff_head *queue)
{
@@ -220,7 +252,9 @@ static void ar9170_dump_txqueue(struct ar9170 *ar,
__ar9170_dump_txqueue(ar, queue);
spin_unlock_irqrestore(&queue->lock, flags);
}
+#endif /* AR9170_QUEUE_DEBUG */
+#ifdef AR9170_QUEUE_STOP_DEBUG
static void __ar9170_dump_txstats(struct ar9170 *ar)
{
int i;
@@ -229,20 +263,27 @@ static void __ar9170_dump_txstats(struct ar9170 *ar)
wiphy_name(ar->hw->wiphy));
for (i = 0; i < __AR9170_NUM_TXQ; i++)
- printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d\n",
- wiphy_name(ar->hw->wiphy), i, ar->tx_stats[i].limit,
- ar->tx_stats[i].len, skb_queue_len(&ar->tx_status[i]));
+ printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d "
+ " stopped:%d\n", wiphy_name(ar->hw->wiphy), i,
+ ar->tx_stats[i].limit, ar->tx_stats[i].len,
+ skb_queue_len(&ar->tx_status[i]),
+ ieee80211_queue_stopped(ar->hw, i));
}
+#endif /* AR9170_QUEUE_STOP_DEBUG */
-static void ar9170_dump_txstats(struct ar9170 *ar)
+#ifdef AR9170_TXAGG_DEBUG
+static void ar9170_dump_tx_status_ampdu(struct ar9170 *ar)
{
unsigned long flags;
- spin_lock_irqsave(&ar->tx_stats_lock, flags);
- __ar9170_dump_txstats(ar);
- spin_unlock_irqrestore(&ar->tx_stats_lock, 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_QUEUE_DEBUG */
+
+#endif /* AR9170_TXAGG_DEBUG */
/* caller must guarantee exclusive access for _bin_ queue. */
static void ar9170_recycle_expired(struct ar9170 *ar,
@@ -315,6 +356,70 @@ 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_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);
+ ar->tx_ampdu_pending--;
+
+ if (!list_empty(&ar->tx_ampdu_list) && !ar->tx_ampdu_pending)
+ ar9170_tx_ampdu(ar);
+}
+
void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -336,7 +441,7 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
if (arinfo->flags & AR9170_TX_FLAG_BLOCK_ACK) {
- dev_kfree_skb_any(skb);
+ ar9170_tx_ampdu_callback(ar, skb);
} else if (arinfo->flags & AR9170_TX_FLAG_WAIT_FOR_ACK) {
arinfo->timeout = jiffies +
msecs_to_jiffies(AR9170_TX_TIMEOUT);
@@ -420,6 +525,38 @@ 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
@@ -456,6 +593,8 @@ static void ar9170_tx_janitor(struct work_struct *work)
resched = true;
}
+ ar9170_tx_fake_ampdu_status(ar);
+
if (resched)
queue_delayed_work(ar->hw->workqueue,
&ar->tx_janitor,
@@ -528,8 +667,15 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
break;
case 0xc4:
+ /* BlockACK bitmap */
+ break;
+
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:
@@ -917,8 +1063,10 @@ static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
ar9170_rx_phy_status(ar, phy, &status);
skb = ar9170_rx_copy_data(buf, mpdu_len);
- if (likely(skb))
- ieee80211_rx_irqsafe(ar->hw, skb, &status);
+ if (likely(skb)) {
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx_irqsafe(ar->hw, skb);
+ }
}
void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb)
@@ -1096,6 +1244,10 @@ static int ar9170_op_start(struct ieee80211_hw *hw)
AR9170_FILL_QUEUE(ar->edcf[3], 2, 3, 7, 47); /* VOICE */
AR9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */
+ /* set sane AMPDU defaults */
+ ar->global_ampdu_density = 6;
+ ar->global_ampdu_factor = 3;
+
ar->bad_hw_nagger = jiffies;
err = ar->open(ar);
@@ -1141,6 +1293,7 @@ static void ar9170_op_stop(struct ieee80211_hw *hw)
flush_workqueue(ar->hw->workqueue);
cancel_delayed_work_sync(&ar->tx_janitor);
+ cancel_delayed_work_sync(&ar->led_work);
cancel_work_sync(&ar->filter_config_work);
cancel_work_sync(&ar->beacon_work);
mutex_lock(&ar->mutex);
@@ -1157,9 +1310,40 @@ 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;
@@ -1228,6 +1412,7 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR);
arinfo->flags = AR9170_TX_FLAG_BLOCK_ACK;
+
goto out;
}
@@ -1358,6 +1543,159 @@ 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.
+ */
+ if (likely(skb_peek_tail(&agg)))
+ ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg));
+
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: generated A-MPDU looks like this:\n",
+ 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;
@@ -1382,11 +1720,17 @@ static void ar9170_tx(struct ar9170 *ar)
printk(KERN_DEBUG "%s: queue %d full\n",
wiphy_name(ar->hw->wiphy), i);
- __ar9170_dump_txstats(ar);
- printk(KERN_DEBUG "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]);
#endif /* AR9170_QUEUE_DEBUG */
+
+#ifdef AR9170_QUEUE_STOP_DEBUG
+ printk(KERN_DEBUG "%s: stop queue %d\n",
+ wiphy_name(ar->hw->wiphy), i);
+ __ar9170_dump_txstats(ar);
+#endif /* AR9170_QUEUE_STOP_DEBUG */
ieee80211_stop_queue(ar->hw, i);
spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
continue;
@@ -1401,8 +1745,6 @@ static void ar9170_tx(struct ar9170 *ar)
"remaining slots:%d, needed:%d\n",
wiphy_name(ar->hw->wiphy), i, remaining_space,
frames);
-
- ar9170_dump_txstats(ar);
#endif /* AR9170_QUEUE_DEBUG */
frames = remaining_space;
}
@@ -1430,6 +1772,9 @@ static void ar9170_tx(struct ar9170 *ar)
arinfo->timeout = jiffies +
msecs_to_jiffies(AR9170_TX_TIMEOUT);
+ if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
+ ar->tx_ampdu_pending++;
+
#ifdef AR9170_QUEUE_DEBUG
printk(KERN_DEBUG "%s: send frame q:%d =>\n",
wiphy_name(ar->hw->wiphy), i);
@@ -1438,6 +1783,9 @@ static void ar9170_tx(struct ar9170 *ar)
err = ar->tx(ar, skb);
if (unlikely(err)) {
+ if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
+ ar->tx_ampdu_pending--;
+
frames_failed++;
dev_kfree_skb_any(skb);
} else {
@@ -1459,13 +1807,18 @@ static void ar9170_tx(struct ar9170 *ar)
if (unlikely(frames_failed)) {
#ifdef AR9170_QUEUE_DEBUG
- printk(KERN_DEBUG "%s: frames failed =>\n",
+ printk(KERN_DEBUG "%s: frames failed %d =>\n",
wiphy_name(ar->hw->wiphy), frames_failed);
#endif /* AR9170_QUEUE_DEBUG */
spin_lock_irqsave(&ar->tx_stats_lock, flags);
ar->tx_stats[i].len -= frames_failed;
ar->tx_stats[i].count -= frames_failed;
+#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);
spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
}
@@ -1477,6 +1830,90 @@ 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;
@@ -1490,8 +1927,10 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
info = IEEE80211_SKB_CB(skb);
if (info->flags & IEEE80211_TX_CTL_AMPDU) {
- /* drop frame, we do not allow TX A-MPDU aggregation yet. */
- goto err_free;
+ bool run = ar9170_tx_ampdu_queue(ar, skb);
+
+ if (run || !ar->tx_ampdu_pending)
+ ar9170_tx_ampdu(ar);
} else {
unsigned int queue = skb_get_queue_mapping(skb);
@@ -1929,6 +2368,53 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw,
enum sta_notify_cmd cmd,
struct ieee80211_sta *sta)
{
+ struct ar9170 *ar = hw->priv;
+ struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
+ unsigned int i;
+
+ switch (cmd) {
+ case STA_NOTIFY_ADD:
+ memset(sta_info, 0, sizeof(*sta_info));
+
+ if (!sta->ht_cap.ht_supported)
+ break;
+
+ 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].retry = 0;
+ sta_info->agg[i].tid = i;
+ INIT_LIST_HEAD(&sta_info->agg[i].list);
+ skb_queue_head_init(&sta_info->agg[i].queue);
+ }
+
+ sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor);
+ break;
+
+ case STA_NOTIFY_REMOVE:
+ if (!sta->ht_cap.ht_supported)
+ break;
+
+ 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);
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ if (IS_STARTED(ar) && ar->filter_changed)
+ queue_work(ar->hw->workqueue, &ar->filter_config_work);
}
static int ar9170_get_stats(struct ieee80211_hw *hw,
@@ -1983,18 +2469,65 @@ 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(hw, 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(hw, 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:
- /*
- * Something goes wrong -- RX locks up
- * after a while of receiving aggregated
- * frames -- not enabling for now.
- */
- return -EOPNOTSUPP;
+ /* Handled by firmware */
+ break;
+
default:
return -EOPNOTSUPP;
}
+
+ return 0;
}
static const struct ieee80211_ops ar9170_ops = {
@@ -2043,6 +2576,8 @@ 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]);
@@ -2051,6 +2586,7 @@ void *ar9170_alloc(size_t priv_size)
INIT_WORK(&ar->filter_config_work, ar9170_set_filters);
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];
@@ -2064,6 +2600,13 @@ void *ar9170_alloc(size_t priv_size)
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;
+ }
+
ar->hw->queues = __AR9170_NUM_TXQ;
ar->hw->extra_tx_headroom = 8;
ar->hw->sta_data_size = sizeof(struct ar9170_sta_info);
@@ -2085,10 +2628,10 @@ static int ar9170_read_eeprom(struct ar9170 *ar)
{
#define RW 8 /* number of words to read at once */
#define RB (sizeof(u32) * RW)
- DECLARE_MAC_BUF(mbuf);
u8 *eeprom = (void *)&ar->eeprom;
u8 *addr = ar->eeprom.mac_address;
__le32 offsets[RW];
+ unsigned int rx_streams, tx_streams, tx_params = 0;
int i, j, err, bands = 0;
BUILD_BUG_ON(sizeof(ar->eeprom) & 3);
@@ -2125,6 +2668,20 @@ static int ar9170_read_eeprom(struct ar9170 *ar)
ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &ar9170_band_5GHz;
bands++;
}
+
+ rx_streams = hweight8(ar->eeprom.rx_mask);
+ tx_streams = hweight8(ar->eeprom.tx_mask);
+
+ if (rx_streams != tx_streams)
+ tx_params = IEEE80211_HT_MCS_TX_RX_DIFF;
+
+ if (tx_streams >= 1 && tx_streams <= IEEE80211_HT_MCS_TX_MAX_STREAMS)
+ tx_params = (tx_streams - 1) <<
+ IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
+
+ ar9170_band_2GHz.ht_cap.mcs.tx_params |= tx_params;
+ ar9170_band_5GHz.ht_cap.mcs.tx_params |= tx_params;
+
/*
* I measured this, a bandswitch takes roughly
* 135 ms and a frequency switch about 80.
diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c
index 754b1f8d8da9..1aec7afdffa7 100644
--- a/drivers/net/wireless/ath/ar9170/usb.c
+++ b/drivers/net/wireless/ath/ar9170/usb.c
@@ -779,7 +779,7 @@ static int ar9170_usb_probe(struct usb_interface *intf,
aru->req_one_stage_fw = ar9170_requires_one_stage(id);
usb_set_intfdata(intf, aru);
- SET_IEEE80211_DEV(ar->hw, &udev->dev);
+ SET_IEEE80211_DEV(ar->hw, &intf->dev);
init_usb_anchor(&aru->rx_submitted);
init_usb_anchor(&aru->tx_pending);
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 6358233bac99..91375113916b 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -713,8 +713,8 @@ struct ath5k_gain {
* Used internaly for reset_tx_queue).
* Also see struct struct ieee80211_channel.
*/
-#define IS_CHAN_XR(_c) ((_c.hw_value & CHANNEL_XR) != 0)
-#define IS_CHAN_B(_c) ((_c.hw_value & CHANNEL_B) != 0)
+#define IS_CHAN_XR(_c) ((_c->hw_value & CHANNEL_XR) != 0)
+#define IS_CHAN_B(_c) ((_c->hw_value & CHANNEL_B) != 0)
/*
* The following structure is used to map 2GHz channels to
@@ -1029,14 +1029,15 @@ struct ath5k_hw {
enum ath5k_int ah_imr;
enum nl80211_iftype ah_op_mode;
- enum ath5k_power_mode ah_power_mode;
- struct ieee80211_channel ah_current_channel;
+ struct ieee80211_channel *ah_current_channel;
bool ah_turbo;
bool ah_calibration;
- bool ah_running;
bool ah_single_chip;
bool ah_combined_mic;
+ enum ath5k_version ah_version;
+ enum ath5k_radio ah_radio;
+ u32 ah_phy;
u32 ah_mac_srev;
u16 ah_mac_version;
u16 ah_mac_revision;
@@ -1044,13 +1045,6 @@ struct ath5k_hw {
u16 ah_radio_5ghz_revision;
u16 ah_radio_2ghz_revision;
- enum ath5k_version ah_version;
- enum ath5k_radio ah_radio;
- u32 ah_phy;
-
- bool ah_5ghz;
- bool ah_2ghz;
-
#define ah_modes ah_capabilities.cap_mode
#define ah_ee_version ah_capabilities.cap_eeprom.ee_version
@@ -1058,7 +1052,6 @@ struct ath5k_hw {
u32 ah_aifs;
u32 ah_cw_min;
u32 ah_cw_max;
- bool ah_software_retry;
u32 ah_limit_tx_retries;
/* Antenna Control */
@@ -1066,6 +1059,7 @@ struct ath5k_hw {
u8 ah_ant_mode;
u8 ah_tx_ant;
u8 ah_def_ant;
+ bool ah_software_retry;
u8 ah_sta_id[ETH_ALEN];
@@ -1075,7 +1069,6 @@ struct ath5k_hw {
u8 ah_bssid[ETH_ALEN];
u8 ah_bssid_mask[ETH_ALEN];
- u32 ah_gpio[AR5K_MAX_GPIO];
int ah_gpio_npins;
struct ath_regulatory ah_regulatory;
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index c41ef58393e7..9a84d9410b27 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -319,6 +319,9 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
ath5k_hw_rfgain_opt_init(ah);
+ /* turn on HW LEDs */
+ ath5k_hw_set_ledstate(ah, AR5K_LED_INIT);
+
return ah;
err_free:
kfree(ah);
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 029c1bc7468f..7db32ce3dbd8 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -218,6 +218,8 @@ static struct pci_driver ath5k_pci_driver = {
* Prototypes - MAC 802.11 stack related functions
*/
static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
+static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ath5k_txq *txq);
static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan);
static int ath5k_reset_wake(struct ath5k_softc *sc);
static int ath5k_start(struct ieee80211_hw *hw);
@@ -248,6 +250,8 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
u32 changes);
+static void ath5k_sw_scan_start(struct ieee80211_hw *hw);
+static void ath5k_sw_scan_complete(struct ieee80211_hw *hw);
static const struct ieee80211_ops ath5k_hw_ops = {
.tx = ath5k_tx,
@@ -265,6 +269,8 @@ static const struct ieee80211_ops ath5k_hw_ops = {
.set_tsf = ath5k_set_tsf,
.reset_tsf = ath5k_reset_tsf,
.bss_info_changed = ath5k_bss_info_changed,
+ .sw_scan_start = ath5k_sw_scan_start,
+ .sw_scan_complete = ath5k_sw_scan_complete,
};
/*
@@ -297,7 +303,8 @@ static void ath5k_desc_free(struct ath5k_softc *sc,
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_buf *bf,
+ struct ath5k_txq *txq);
static inline void ath5k_txbuf_free(struct ath5k_softc *sc,
struct ath5k_buf *bf)
{
@@ -512,6 +519,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
/* Initialize driver private data */
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;
@@ -666,7 +674,6 @@ ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state)
ath5k_led_off(sc);
- free_irq(pdev->irq, sc);
pci_save_state(pdev);
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
@@ -694,18 +701,8 @@ ath5k_pci_resume(struct pci_dev *pdev)
*/
pci_write_config_byte(pdev, 0x41, 0);
- err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
- if (err) {
- ATH5K_ERR(sc, "request_irq failed\n");
- goto err_no_irq;
- }
-
ath5k_led_enable(sc);
return 0;
-
-err_no_irq:
- pci_disable_device(pdev);
- return err;
}
#endif /* CONFIG_PM */
@@ -785,12 +782,18 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
goto err_desc;
}
sc->bhalq = ret;
+ sc->cabq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_CAB, 0);
+ if (IS_ERR(sc->cabq)) {
+ ATH5K_ERR(sc, "can't setup cab queue\n");
+ ret = PTR_ERR(sc->cabq);
+ goto err_bhal;
+ }
sc->txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK);
if (IS_ERR(sc->txq)) {
ATH5K_ERR(sc, "can't setup xmit queue\n");
ret = PTR_ERR(sc->txq);
- goto err_bhal;
+ goto err_queues;
}
tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc);
@@ -1228,10 +1231,10 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
}
static int
-ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
+ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
+ struct ath5k_txq *txq)
{
struct ath5k_hw *ah = sc->ah;
- struct ath5k_txq *txq = sc->txq;
struct ath5k_desc *ds = bf->desc;
struct sk_buff *skb = bf->skb;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -1901,7 +1904,8 @@ accept:
if (sc->opmode == NL80211_IFTYPE_ADHOC)
ath5k_check_ibss_tsf(sc, skb, &rxs);
- __ieee80211_rx(sc->hw, skb, &rxs);
+ memcpy(IEEE80211_SKB_RXCB(skb), &rxs, sizeof(rxs));
+ ieee80211_rx(sc->hw, skb);
bf->skb = next_skb;
bf->skbaddr = next_skb_addr;
@@ -2078,13 +2082,6 @@ err_unmap:
return ret;
}
-static void ath5k_beacon_disable(struct ath5k_softc *sc)
-{
- sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA);
- ath5k_hw_set_imr(sc->ah, sc->imask);
- ath5k_hw_stop_tx_dma(sc->ah, sc->bhalq);
-}
-
/*
* Transmit a beacon frame at SWBA. Dynamic updates to the
* frame contents are done as needed and the slot time is
@@ -2098,6 +2095,7 @@ ath5k_beacon_send(struct ath5k_softc *sc)
{
struct ath5k_buf *bf = sc->bbuf;
struct ath5k_hw *ah = sc->ah;
+ struct sk_buff *skb;
ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n");
@@ -2151,6 +2149,12 @@ ath5k_beacon_send(struct ath5k_softc *sc)
ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n",
sc->bhalq, (unsigned long long)bf->daddr, bf->desc);
+ skb = ieee80211_get_buffered_bc(sc->hw, sc->vif);
+ while (skb) {
+ ath5k_tx_queue(sc->hw, skb, sc->cabq);
+ skb = ieee80211_get_buffered_bc(sc->hw, sc->vif);
+ }
+
sc->bsent++;
}
@@ -2271,13 +2275,11 @@ ath5k_beacon_config(struct ath5k_softc *sc)
struct ath5k_hw *ah = sc->ah;
unsigned long flags;
- ath5k_hw_set_imr(ah, 0);
+ spin_lock_irqsave(&sc->block, flags);
sc->bmisscount = 0;
sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA);
- if (sc->opmode == NL80211_IFTYPE_ADHOC ||
- sc->opmode == NL80211_IFTYPE_MESH_POINT ||
- sc->opmode == NL80211_IFTYPE_AP) {
+ if (sc->enable_beacon) {
/*
* In IBSS mode we use a self-linked tx descriptor and let the
* hardware send the beacons automatically. We have to load it
@@ -2290,16 +2292,17 @@ ath5k_beacon_config(struct ath5k_softc *sc)
sc->imask |= AR5K_INT_SWBA;
if (sc->opmode == NL80211_IFTYPE_ADHOC) {
- if (ath5k_hw_hasveol(ah)) {
- spin_lock_irqsave(&sc->block, flags);
+ if (ath5k_hw_hasveol(ah))
ath5k_beacon_send(sc);
- spin_unlock_irqrestore(&sc->block, flags);
- }
} else
ath5k_beacon_update_timers(sc, -1);
+ } else {
+ ath5k_hw_stop_tx_dma(sc->ah, sc->bhalq);
}
ath5k_hw_set_imr(ah, sc->imask);
+ mmiowb();
+ spin_unlock_irqrestore(&sc->block, flags);
}
static void ath5k_tasklet_beacon(unsigned long data)
@@ -2598,6 +2601,14 @@ static int
ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ath5k_softc *sc = hw->priv;
+
+ return ath5k_tx_queue(hw, skb, sc->txq);
+}
+
+static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ath5k_txq *txq)
+{
+ struct ath5k_softc *sc = hw->priv;
struct ath5k_buf *bf;
unsigned long flags;
int hdrlen;
@@ -2641,7 +2652,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
bf->skb = skb;
- if (ath5k_txbuf_setup(sc, bf)) {
+ if (ath5k_txbuf_setup(sc, bf, txq)) {
bf->skb = NULL;
spin_lock_irqsave(&sc->txbuflock, flags);
list_add_tail(&bf->list, &sc->txbuf);
@@ -2676,7 +2687,7 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan)
sc->curchan = chan;
sc->curband = &sc->sbands[chan->band];
}
- ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, true);
+ ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL);
if (ret) {
ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret);
goto err;
@@ -2776,7 +2787,6 @@ ath5k_remove_interface(struct ieee80211_hw *hw,
goto end;
ath5k_hw_set_lladdr(sc->ah, mac);
- ath5k_beacon_disable(sc);
sc->vif = NULL;
end:
mutex_unlock(&sc->lock);
@@ -3108,25 +3118,6 @@ out:
return ret;
}
-/*
- * Update the beacon and reconfigure the beacon queues.
- */
-static void
-ath5k_beacon_reconfig(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
-{
- int ret;
- unsigned long flags;
- struct ath5k_softc *sc = hw->priv;
-
- spin_lock_irqsave(&sc->block, flags);
- ret = ath5k_beacon_update(hw, vif);
- spin_unlock_irqrestore(&sc->block, flags);
- if (ret == 0) {
- ath5k_beacon_config(sc);
- mmiowb();
- }
-}
-
static void
set_beacon_filter(struct ieee80211_hw *hw, bool enable)
{
@@ -3149,6 +3140,7 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
+ unsigned long flags;
mutex_lock(&sc->lock);
if (WARN_ON(sc->vif != vif))
@@ -3170,15 +3162,37 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
sc->assoc = bss_conf->assoc;
if (sc->opmode == NL80211_IFTYPE_STATION)
set_beacon_filter(hw, sc->assoc);
+ ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
+ AR5K_LED_ASSOC : AR5K_LED_INIT);
}
- if (changes & BSS_CHANGED_BEACON &&
- (vif->type == NL80211_IFTYPE_ADHOC ||
- vif->type == NL80211_IFTYPE_MESH_POINT ||
- vif->type == NL80211_IFTYPE_AP)) {
- ath5k_beacon_reconfig(hw, vif);
+ if (changes & BSS_CHANGED_BEACON) {
+ spin_lock_irqsave(&sc->block, flags);
+ ath5k_beacon_update(hw, vif);
+ spin_unlock_irqrestore(&sc->block, flags);
}
+ if (changes & BSS_CHANGED_BEACON_ENABLED)
+ sc->enable_beacon = bss_conf->enable_beacon;
+
+ if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED |
+ BSS_CHANGED_BEACON_INT))
+ ath5k_beacon_config(sc);
+
unlock:
mutex_unlock(&sc->lock);
}
+
+static void ath5k_sw_scan_start(struct ieee80211_hw *hw)
+{
+ struct ath5k_softc *sc = hw->priv;
+ if (!sc->assoc)
+ ath5k_hw_set_ledstate(sc->ah, AR5K_LED_SCAN);
+}
+
+static void ath5k_sw_scan_complete(struct ieee80211_hw *hw)
+{
+ struct ath5k_softc *sc = hw->priv;
+ ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
+ AR5K_LED_ASSOC : AR5K_LED_INIT);
+}
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index f9b7f2f819b7..778e422946ab 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -114,8 +114,7 @@ struct ath5k_softc {
struct pci_dev *pdev; /* for dma mapping */
void __iomem *iobase; /* address of the device */
struct mutex lock; /* dev-level lock */
- /* FIXME: how many does it really need? */
- struct ieee80211_tx_queue_stats tx_stats[16];
+ struct ieee80211_tx_queue_stats tx_stats[AR5K_NUM_TX_QUEUES];
struct ieee80211_low_level_stats ll_stats;
struct ieee80211_hw *hw; /* IEEE 802.11 common */
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
@@ -171,9 +170,8 @@ struct ath5k_softc {
struct list_head txbuf; /* transmit buffer */
spinlock_t txbuflock;
unsigned int txbuf_len; /* buf count in txbuf list */
- struct ath5k_txq txqs[2]; /* beacon and tx */
-
- struct ath5k_txq *txq; /* beacon and tx*/
+ struct ath5k_txq txqs[AR5K_NUM_TX_QUEUES]; /* tx queues */
+ struct ath5k_txq *txq; /* main tx queue */
struct tasklet_struct txtq; /* tx intr tasklet */
struct ath5k_led tx_led; /* tx led */
@@ -187,10 +185,12 @@ struct ath5k_softc {
bintval, /* beacon interval in TU */
bsent;
unsigned int nexttbtt; /* next beacon time in TU */
+ struct ath5k_txq *cabq; /* content after beacon */
struct timer_list calib_tim; /* calibration timer */
int power_level; /* Requested tx power in dbm */
bool assoc; /* assocate state */
+ bool enable_beacon; /* true if beacons are on */
};
#define ath5k_hw_hasbssidmask(_ah) \
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index 4904a07e4b59..747508c15d34 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -380,13 +380,15 @@ ath5k_debug_init_device(struct ath5k_softc *sc)
sc->debug.debugfs_phydir = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
ath5k_global_debugfs);
- sc->debug.debugfs_debug = debugfs_create_file("debug", S_IWUSR | S_IRUGO,
+ sc->debug.debugfs_debug = debugfs_create_file("debug",
+ S_IWUSR | S_IRUSR,
sc->debug.debugfs_phydir, sc, &fops_debug);
- sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUGO,
+ sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUSR,
sc->debug.debugfs_phydir, sc, &fops_registers);
- sc->debug.debugfs_beacon = debugfs_create_file("beacon", S_IWUSR | S_IRUGO,
+ sc->debug.debugfs_beacon = debugfs_create_file("beacon",
+ S_IWUSR | S_IRUSR,
sc->debug.debugfs_phydir, sc, &fops_beacon);
sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR,
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index a876ca8d69ef..2075ba993966 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -1085,8 +1085,7 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
AR5K_PHY_CCKTXCTL_WORLD);
}
- ah->ah_current_channel.center_freq = channel->center_freq;
- ah->ah_current_channel.hw_value = channel->hw_value;
+ ah->ah_current_channel = channel;
ah->ah_turbo = channel->hw_value == CHANNEL_T ? true : false;
return 0;
@@ -1731,7 +1730,7 @@ ath5k_hw_set_fast_div(struct ath5k_hw *ah, u8 ee_mode, bool enable)
void
ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)
{
- struct ieee80211_channel *channel = &ah->ah_current_channel;
+ struct ieee80211_channel *channel = ah->ah_current_channel;
bool use_def_for_tx, update_def_on_tx, use_def_for_rts, fast_div;
bool use_def_for_sg;
u8 def_ant, tx_ant, ee_mode;
@@ -3011,7 +3010,7 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower)
{
/*Just a try M.F.*/
- struct ieee80211_channel *channel = &ah->ah_current_channel;
+ struct ieee80211_channel *channel = ah->ah_current_channel;
u8 ee_mode;
ATH5K_TRACE(ah->ah_sc);
diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c
index 73407b3f53ef..6d5aaf00d8bb 100644
--- a/drivers/net/wireless/ath/ath5k/qcu.c
+++ b/drivers/net/wireless/ath/ath5k/qcu.c
@@ -411,7 +411,6 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
AR5K_QCU_MISC_FRSHED_BCN_SENT_GT |
AR5K_QCU_MISC_CBREXP_DIS |
- AR5K_QCU_MISC_RDY_VEOL_POLICY |
AR5K_QCU_MISC_CBREXP_BCN_DIS);
ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL -
diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h
index 6809b54a2ad7..debad07d9900 100644
--- a/drivers/net/wireless/ath/ath5k/reg.h
+++ b/drivers/net/wireless/ath/ath5k/reg.h
@@ -339,9 +339,9 @@
#define AR5K_SISR2 0x008c /* Register Address [5211+] */
#define AR5K_SISR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */
#define AR5K_SISR2_QCU_TXURN_S 0
-#define AR5K_SISR2_MCABT 0x00100000 /* Master Cycle Abort */
-#define AR5K_SISR2_SSERR 0x00200000 /* Signaled System Error */
-#define AR5K_SISR2_DPERR 0x00400000 /* Bus parity error */
+#define AR5K_SISR2_MCABT 0x00010000 /* Master Cycle Abort */
+#define AR5K_SISR2_SSERR 0x00020000 /* Signaled System Error */
+#define AR5K_SISR2_DPERR 0x00040000 /* Bus parity error */
#define AR5K_SISR2_TIM 0x01000000 /* [5212+] */
#define AR5K_SISR2_CAB_END 0x02000000 /* [5212+] */
#define AR5K_SISR2_DTIM_SYNC 0x04000000 /* DTIM sync lost [5212+] */
@@ -430,9 +430,9 @@
#define AR5K_SIMR2 0x00ac /* Register Address [5211+] */
#define AR5K_SIMR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */
#define AR5K_SIMR2_QCU_TXURN_S 0
-#define AR5K_SIMR2_MCABT 0x00100000 /* Master Cycle Abort */
-#define AR5K_SIMR2_SSERR 0x00200000 /* Signaled System Error */
-#define AR5K_SIMR2_DPERR 0x00400000 /* Bus parity error */
+#define AR5K_SIMR2_MCABT 0x00010000 /* Master Cycle Abort */
+#define AR5K_SIMR2_SSERR 0x00020000 /* Signaled System Error */
+#define AR5K_SIMR2_DPERR 0x00040000 /* Bus parity error */
#define AR5K_SIMR2_TIM 0x01000000 /* [5212+] */
#define AR5K_SIMR2_CAB_END 0x02000000 /* [5212+] */
#define AR5K_SIMR2_DTIM_SYNC 0x04000000 /* DTIM Sync lost [5212+] */
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index bd0a97a38d34..86733fdb4774 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -290,7 +290,6 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
}
commit:
- ah->ah_power_mode = mode;
ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1);
return 0;
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 5efc9345ca0d..751885a5df47 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -164,7 +164,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
#define WME_NUM_TID 16
#define ATH_TXBUF 512
#define ATH_TXMAXTRY 13
-#define ATH_11N_TXMAXTRY 10
#define ATH_MGT_TXMAXTRY 4
#define WME_BA_BMP_SIZE 64
#define WME_MAX_BA WME_BA_BMP_SIZE
@@ -226,6 +225,8 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
#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
+
enum ATH_AGGR_STATUS {
ATH_AGGR_DONE,
ATH_AGGR_BAW_CLOSED,
@@ -241,6 +242,7 @@ struct ath_txq {
u8 axq_aggr_depth;
u32 axq_totalqueued;
bool stopped;
+ bool axq_tx_inprogress;
struct ath_buf *axq_linkbuf;
/* first desc of the last descriptor that contains CTS */
@@ -272,7 +274,6 @@ struct ath_atx_tid {
int sched;
int paused;
u8 state;
- int addba_exchangeattempts;
};
struct ath_atx_ac {
@@ -292,12 +293,28 @@ struct ath_tx_control {
#define ATH_TX_XRETRY 0x02
#define ATH_TX_BAR 0x04
+#define ATH_RSSI_LPF_LEN 10
+#define RSSI_LPF_THRESHOLD -20
+#define ATH9K_RSSI_BAD 0x80
+#define ATH_RSSI_EP_MULTIPLIER (1<<7)
+#define ATH_EP_MUL(x, mul) ((x) * (mul))
+#define ATH_RSSI_IN(x) (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER))
+#define ATH_LPF_RSSI(x, y, len) \
+ ((x != ATH_RSSI_DUMMY_MARKER) ? (((x) * ((len) - 1) + (y)) / (len)) : (y))
+#define ATH_RSSI_LPF(x, y) do { \
+ if ((y) >= RSSI_LPF_THRESHOLD) \
+ x = ATH_LPF_RSSI((x), ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \
+} while (0)
+#define ATH_EP_RND(x, mul) \
+ ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
+
struct ath_node {
struct ath_softc *an_sc;
struct ath_atx_tid tid[WME_NUM_TID];
struct ath_atx_ac ac[WME_NUM_AC];
u16 maxampdu;
u8 mpdudensity;
+ int last_rssi;
};
struct ath_tx {
@@ -541,6 +558,8 @@ struct ath_softc {
int irq;
spinlock_t sc_resetlock;
spinlock_t sc_serial_rw;
+ spinlock_t ani_lock;
+ spinlock_t sc_pm_lock;
struct mutex mutex;
u8 curbssid[ETH_ALEN];
@@ -557,7 +576,7 @@ struct ath_softc {
u32 keymax;
DECLARE_BITMAP(keymap, ATH_KEYMAX);
u8 splitmic;
- atomic_t ps_usecount;
+ unsigned long ps_usecount;
enum ath9k_int imask;
enum ath9k_ht_extprotspacing ht_extprotspacing;
enum ath9k_ht_macmode tx_chan_width;
@@ -590,6 +609,7 @@ struct ath_softc {
#endif
struct ath_bus_ops *bus_ops;
struct ath_beacon_config cur_beacon_conf;
+ struct delayed_work tx_complete_work;
};
struct ath_wiphy {
@@ -654,27 +674,8 @@ static inline int ath_ahb_init(void) { return 0; };
static inline void ath_ahb_exit(void) {};
#endif
-static inline void ath9k_ps_wakeup(struct ath_softc *sc)
-{
- if (atomic_inc_return(&sc->ps_usecount) == 1)
- if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) {
- sc->sc_ah->restore_mode = sc->sc_ah->power_mode;
- ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
- }
-}
-
-static inline void ath9k_ps_restore(struct ath_softc *sc)
-{
- if (atomic_dec_and_test(&sc->ps_usecount))
- if ((sc->hw->conf.flags & IEEE80211_CONF_PS) &&
- !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
- SC_OP_WAIT_FOR_CAB |
- SC_OP_WAIT_FOR_PSPOLL_DATA |
- SC_OP_WAIT_FOR_TX_ACK)))
- ath9k_hw_setpower(sc->sc_ah,
- sc->sc_ah->restore_mode);
-}
-
+void ath9k_ps_wakeup(struct ath_softc *sc);
+void ath9k_ps_restore(struct ath_softc *sc);
void ath9k_set_bssid_mask(struct ieee80211_hw *hw);
int ath9k_wiphy_add(struct ath_softc *sc);
@@ -690,6 +691,7 @@ void ath9k_wiphy_pause_all_forced(struct ath_softc *sc,
struct ath_wiphy *selected);
bool ath9k_wiphy_scanning(struct ath_softc *sc);
void ath9k_wiphy_work(struct work_struct *work);
+bool ath9k_all_wiphys_idle(struct ath_softc *sc);
void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val);
unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset);
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 3639a2e6987d..45c4ea57616b 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -674,13 +674,6 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
- /*
- * It looks like mac80211 may end up using beacon interval of zero in
- * some cases (at least for mesh point). Avoid getting into an
- * infinite loop by using a bit safer value instead..
- */
- if (intval == 0)
- intval = 100;
/* Pull nexttbtt forward to reflect the current TSF */
@@ -745,6 +738,14 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
iftype = sc->sc_ah->opmode;
}
+ /*
+ * It looks like mac80211 may end up using beacon interval of zero in
+ * some cases (at least for mesh point). Avoid getting into an
+ * infinite loop by using a bit safer value instead. To be safe,
+ * do sanity check on beacon interval for all operating modes.
+ */
+ if (cur_conf->beacon_interval == 0)
+ cur_conf->beacon_interval = 100;
switch (iftype) {
case NL80211_IFTYPE_AP:
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index a32d7e7fecbe..1f0c5fe4a68b 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -691,15 +691,22 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah)
{
int i, j;
+ s16 noise_floor;
+
+ if (AR_SREV_9280(ah))
+ noise_floor = AR_PHY_CCA_MAX_AR9280_GOOD_VALUE;
+ else if (AR_SREV_9285(ah))
+ noise_floor = AR_PHY_CCA_MAX_AR9285_GOOD_VALUE;
+ else
+ noise_floor = AR_PHY_CCA_MAX_AR5416_GOOD_VALUE;
for (i = 0; i < NUM_NF_READINGS; i++) {
ah->nfCalHist[i].currIndex = 0;
- ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE;
+ ah->nfCalHist[i].privNF = noise_floor;
ah->nfCalHist[i].invalidNFcount =
AR_PHY_CCA_FILTERWINDOW_LENGTH;
for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
- ah->nfCalHist[i].nfCalBuffer[j] =
- AR_PHY_CCA_MAX_GOOD_VALUE;
+ ah->nfCalHist[i].nfCalBuffer[j] = noise_floor;
}
}
}
diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h
index fe5367f14148..547e697b9055 100644
--- a/drivers/net/wireless/ath/ath9k/calib.h
+++ b/drivers/net/wireless/ath/ath9k/calib.h
@@ -25,7 +25,9 @@ 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_GOOD_VALUE -85
+#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
#define AR_PHY_CCA_MAX_HIGH_VALUE -62
#define AR_PHY_CCA_MIN_BAD_VALUE -140
#define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT 3
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 6d20725d6451..9f99f00c1447 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -500,31 +500,31 @@ int ath9k_init_debug(struct ath_softc *sc)
goto err;
sc->debug.debugfs_debug = debugfs_create_file("debug",
- S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug);
+ S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug);
if (!sc->debug.debugfs_debug)
goto err;
- sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO,
+ sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUSR,
sc->debug.debugfs_phy, sc, &fops_dma);
if (!sc->debug.debugfs_dma)
goto err;
sc->debug.debugfs_interrupt = debugfs_create_file("interrupt",
- S_IRUGO,
+ S_IRUSR,
sc->debug.debugfs_phy,
sc, &fops_interrupt);
if (!sc->debug.debugfs_interrupt)
goto err;
sc->debug.debugfs_rcstat = debugfs_create_file("rcstat",
- S_IRUGO,
+ S_IRUSR,
sc->debug.debugfs_phy,
sc, &fops_rcstat);
if (!sc->debug.debugfs_rcstat)
goto err;
sc->debug.debugfs_wiphy = debugfs_create_file(
- "wiphy", S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc,
+ "wiphy", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc,
&fops_wiphy);
if (!sc->debug.debugfs_wiphy)
goto err;
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c
index ce0e86c36a82..93e8ce0598a4 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -1208,6 +1208,19 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah,
pModal->xatten2Margin[0]);
REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]);
+
+ /* Set the block 1 value to block 0 value */
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+ AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
+ pModal->bswMargin[0]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+ AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+ AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
+ pModal->xatten2Margin[0]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+ AR_PHY_GAIN_2GHZ_XATTEN2_DB,
+ pModal->xatten2Db[0]);
}
REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
@@ -1215,6 +1228,11 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah,
REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]);
+ REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000,
+ AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);
+ REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000,
+ AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]);
+
if (AR_SREV_9285_11(ah))
REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
}
@@ -1239,7 +1257,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal, 0);
/* Initialize Ant Diversity settings from EEPROM */
- if (pModal->version == 3) {
+ if (pModal->version >= 3) {
ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf);
ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf);
regVal = REG_READ(ah, 0x99ac);
@@ -2516,10 +2534,8 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
targetPowerCck.tPow2x[1];
ratesArray[rate5_5s] = ratesArray[rate5_5l] =
targetPowerCck.tPow2x[2];
- ;
ratesArray[rate11s] = ratesArray[rate11l] =
targetPowerCck.tPow2x[3];
- ;
}
if (IS_CHAN_HT40(chan)) {
for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 34935a8ee59d..605803ae9ed8 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -2345,7 +2345,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_init_bb(ah, chan);
if (!ath9k_hw_init_cal(ah, chan))
- return -EIO;;
+ return -EIO;
rx_chainmask = ah->rxchainmask;
if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) {
@@ -2728,7 +2728,8 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
return true;
}
-bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
+static bool ath9k_hw_setpower_nolock(struct ath_hw *ah,
+ enum ath9k_power_mode mode)
{
int status = true, setChip = true;
static const char *modes[] = {
@@ -2762,6 +2763,55 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
return status;
}
+bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
+{
+ unsigned long flags;
+ bool ret;
+
+ spin_lock_irqsave(&ah->ah_sc->sc_pm_lock, flags);
+ ret = ath9k_hw_setpower_nolock(ah, mode);
+ spin_unlock_irqrestore(&ah->ah_sc->sc_pm_lock, flags);
+
+ return ret;
+}
+
+void ath9k_ps_wakeup(struct ath_softc *sc)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
+ if (++sc->ps_usecount != 1)
+ goto unlock;
+
+ if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) {
+ sc->sc_ah->restore_mode = sc->sc_ah->power_mode;
+ ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE);
+ }
+
+ unlock:
+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+}
+
+void ath9k_ps_restore(struct ath_softc *sc)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
+ if (--sc->ps_usecount != 0)
+ goto unlock;
+
+ if ((sc->hw->conf.flags & IEEE80211_CONF_PS) &&
+ !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
+ SC_OP_WAIT_FOR_CAB |
+ SC_OP_WAIT_FOR_PSPOLL_DATA |
+ SC_OP_WAIT_FOR_TX_ACK)))
+ ath9k_hw_setpower_nolock(sc->sc_ah,
+ sc->sc_ah->restore_mode);
+
+ unlock:
+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+}
+
/*
* Helper for ASPM support.
*
@@ -3305,7 +3355,6 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
}
if (eeval & AR5416_OPFLAGS_11G) {
- set_bit(ATH9K_MODE_11B, pCap->wireless_modes);
set_bit(ATH9K_MODE_11G, pCap->wireless_modes);
if (ah->config.ht_enable) {
if (!(eeval & AR5416_OPFLAGS_N_2G_HT20))
@@ -3791,19 +3840,14 @@ void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64)
void ath9k_hw_reset_tsf(struct ath_hw *ah)
{
- int count;
+ ath9k_ps_wakeup(ah->ah_sc);
+ if (!ath9k_hw_wait(ah, AR_SLP32_MODE, AR_SLP32_TSF_WRITE_STATUS, 0,
+ AH_TSF_WRITE_TIMEOUT))
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+ "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
- count = 0;
- while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) {
- count++;
- if (count > 10) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET,
- "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
- break;
- }
- udelay(10);
- }
REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
+ ath9k_ps_restore(ah->ah_sc);
}
bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting)
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 9d0b31ad4603..28bffdb365a2 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -95,6 +95,7 @@
#define MAX_RATE_POWER 63
#define AH_WAIT_TIMEOUT 100000 /* (us) */
+#define AH_TSF_WRITE_TIMEOUT 100 /* (us) */
#define AH_TIME_QUANTUM 10
#define AR_KEYTABLE_SIZE 128
#define POWER_UP_TIME 200000
@@ -113,15 +114,14 @@
enum wireless_mode {
ATH9K_MODE_11A = 0,
- ATH9K_MODE_11B = 2,
- ATH9K_MODE_11G = 3,
- ATH9K_MODE_11NA_HT20 = 6,
- ATH9K_MODE_11NG_HT20 = 7,
- ATH9K_MODE_11NA_HT40PLUS = 8,
- ATH9K_MODE_11NA_HT40MINUS = 9,
- ATH9K_MODE_11NG_HT40PLUS = 10,
- ATH9K_MODE_11NG_HT40MINUS = 11,
- ATH9K_MODE_MAX
+ ATH9K_MODE_11G,
+ ATH9K_MODE_11NA_HT20,
+ ATH9K_MODE_11NG_HT20,
+ ATH9K_MODE_11NA_HT40PLUS,
+ ATH9K_MODE_11NA_HT40MINUS,
+ ATH9K_MODE_11NG_HT40PLUS,
+ ATH9K_MODE_11NG_HT40MINUS,
+ ATH9K_MODE_MAX,
};
enum ath9k_hw_caps {
diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h
index e2f0a34b79a1..f67a2a96cc5c 100644
--- a/drivers/net/wireless/ath/ath9k/initvals.h
+++ b/drivers/net/wireless/ath/ath9k/initvals.h
@@ -2782,7 +2782,7 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x00008338, 0x00ff0000 },
{ 0x0000833c, 0x00000000 },
{ 0x00008340, 0x000107ff },
- { 0x00008344, 0x00581043 },
+ { 0x00008344, 0x00481043 },
{ 0x00009808, 0x00000000 },
{ 0x0000980c, 0xafa68e30 },
{ 0x00009810, 0xfd14e000 },
@@ -3439,7 +3439,7 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = {
{0x00004044, 0x00000000 },
};
-/* AR9285 */
+/* AR9285 Revsion 10*/
static const u_int32_t ar9285Modes_9285[][6] = {
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -3955,7 +3955,7 @@ static const u_int32_t ar9285Common_9285[][2] = {
{ 0x00008338, 0x00000000 },
{ 0x0000833c, 0x00000000 },
{ 0x00008340, 0x00010380 },
- { 0x00008344, 0x00581043 },
+ { 0x00008344, 0x00481043 },
{ 0x00009808, 0x00000000 },
{ 0x0000980c, 0xafe68e30 },
{ 0x00009810, 0xfd14e000 },
@@ -4121,8 +4121,9 @@ static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285[][2] = {
{0x00004044, 0x00000000 },
};
-/* AR9285 v1_2 PCI Register Writes. Created: 03/04/09 */
+/* AR9285 v1_2 PCI Register Writes. Created: 04/13/09 */
static const u_int32_t 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 },
{ 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
@@ -4139,6 +4140,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
{ 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e },
{ 0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0 },
{ 0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
+ { 0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
{ 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
{ 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
{ 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e },
@@ -4419,6 +4421,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
{ 0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
{ 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 },
{ 0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
+ { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
{ 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
{ 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
{ 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 },
@@ -4618,7 +4621,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
{ 0x00008338, 0x00ff0000 },
{ 0x0000833c, 0x00000000 },
{ 0x00008340, 0x00010380 },
- { 0x00008344, 0x00581043 },
+ { 0x00008344, 0x00481043 },
{ 0x00009808, 0x00000000 },
{ 0x0000980c, 0xafe68e30 },
{ 0x00009810, 0xfd14e000 },
@@ -4752,18 +4755,18 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
static const u_int32_t 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, 0x00005200, 0x00005200, 0x00000000 },
- { 0x0000a308, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 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, 0x0000f440, 0x0000f440, 0x00000000 },
- { 0x0000a318, 0x00000000, 0x00000000, 0x00014640, 0x00014640, 0x00000000 },
- { 0x0000a31c, 0x00000000, 0x00000000, 0x00018680, 0x00018680, 0x00000000 },
- { 0x0000a320, 0x00000000, 0x00000000, 0x00019841, 0x00019841, 0x00000000 },
- { 0x0000a324, 0x00000000, 0x00000000, 0x0001ca40, 0x0001ca40, 0x00000000 },
- { 0x0000a328, 0x00000000, 0x00000000, 0x0001fa80, 0x0001fa80, 0x00000000 },
- { 0x0000a32c, 0x00000000, 0x00000000, 0x00023ac0, 0x00023ac0, 0x00000000 },
- { 0x0000a330, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 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 },
@@ -4776,13 +4779,13 @@ static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = {
{ 0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803 },
{ 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe },
{ 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 },
- { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a21a652, 0x0a21a652, 0x0a22a652 },
- { 0x0000a278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce },
- { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce },
- { 0x0000a394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce },
- { 0x0000a398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce },
- { 0x0000a3dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce },
- { 0x0000a3e0, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce },
+ { 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 u_int32_t ar9285Modes_original_tx_gain_9285_1_2[][6] = {
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index 8ae4ec21667b..6f923e318727 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -825,13 +825,29 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp;
- ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
- ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00);
- ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01);
- ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02);
- ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10);
- ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11);
- ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12);
+ 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;
+ } else {
+ ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
+ ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0,
+ AR_RxRSSIAnt00);
+ ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0,
+ AR_RxRSSIAnt01);
+ ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0,
+ AR_RxRSSIAnt02);
+ ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4,
+ AR_RxRSSIAnt10);
+ ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4,
+ AR_RxRSSIAnt11);
+ ds->ds_rxstat.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);
else
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 66a6c1f5022a..3436295e0509 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -342,6 +342,7 @@ static void ath_ani_calibrate(unsigned long data)
* don't calibrate when we're scanning.
* we are most likely not on our home channel.
*/
+ spin_lock(&sc->ani_lock);
if (sc->sc_flags & SC_OP_SCANNING)
goto set_timer;
@@ -405,6 +406,7 @@ static void ath_ani_calibrate(unsigned long data)
ath9k_ps_restore(sc);
set_timer:
+ spin_unlock(&sc->ani_lock);
/*
* Set timer interval based on previous results.
* The interval must be the shortest necessary to satisfy ANI,
@@ -463,6 +465,7 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
sta->ht_cap.ampdu_factor);
an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density);
+ an->last_rssi = ATH_RSSI_DUMMY_MARKER;
}
}
@@ -887,6 +890,7 @@ static void setup_ht_cap(struct ath_softc *sc,
{
#define ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */
#define ATH9K_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */
+ u8 tx_streams, rx_streams;
ht_info->ht_supported = true;
ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
@@ -899,45 +903,43 @@ static void setup_ht_cap(struct ath_softc *sc,
/* set up supported mcs set */
memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
+ tx_streams = !(sc->tx_chainmask & (sc->tx_chainmask - 1)) ? 1 : 2;
+ rx_streams = !(sc->rx_chainmask & (sc->rx_chainmask - 1)) ? 1 : 2;
- switch(sc->rx_chainmask) {
- case 1:
- ht_info->mcs.rx_mask[0] = 0xff;
- break;
- case 3:
- case 5:
- case 7:
- default:
- ht_info->mcs.rx_mask[0] = 0xff;
- ht_info->mcs.rx_mask[1] = 0xff;
- break;
+ if (tx_streams != rx_streams) {
+ DPRINTF(sc, 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.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+ ht_info->mcs.rx_mask[0] = 0xff;
+ if (rx_streams >= 2)
+ ht_info->mcs.rx_mask[1] = 0xff;
+
+ ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
}
static void ath9k_bss_assoc_info(struct ath_softc *sc,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf)
{
- struct ath_vif *avp = (void *)vif->drv_priv;
if (bss_conf->assoc) {
DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n",
bss_conf->aid, sc->curbssid);
/* New association, store aid */
- if (avp->av_opmode == NL80211_IFTYPE_STATION) {
- sc->curaid = bss_conf->aid;
- ath9k_hw_write_associd(sc);
+ sc->curaid = bss_conf->aid;
+ ath9k_hw_write_associd(sc);
- /*
- * Request a re-configuration of Beacon related timers
- * on the receipt of the first Beacon frame (i.e.,
- * after time sync with the AP).
- */
- sc->sc_flags |= SC_OP_BEACON_SYNC;
- }
+ /*
+ * Request a re-configuration of Beacon related timers
+ * on the receipt of the first Beacon frame (i.e.,
+ * after time sync with the AP).
+ */
+ sc->sc_flags |= SC_OP_BEACON_SYNC;
/* Configure the beacon */
ath_beacon_config(sc, vif);
@@ -952,6 +954,8 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
} else {
DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISASSOC\n");
sc->curaid = 0;
+ /* Stop ANI */
+ del_timer_sync(&sc->ani.timer);
}
}
@@ -1255,6 +1259,7 @@ void ath_detach(struct ath_softc *sc)
ath_deinit_leds(sc);
cancel_work_sync(&sc->chan_work);
cancel_delayed_work_sync(&sc->wiphy_work);
+ cancel_delayed_work_sync(&sc->tx_complete_work);
for (i = 0; i < sc->num_sec_wiphy; i++) {
struct ath_wiphy *aphy = sc->sec_wiphy[i];
@@ -1281,7 +1286,6 @@ void ath_detach(struct ath_softc *sc)
ath9k_hw_detach(sc->sc_ah);
ath9k_exit_debug(sc);
- ath9k_ps_restore(sc);
}
static int ath9k_reg_notifier(struct wiphy *wiphy,
@@ -1311,6 +1315,8 @@ static int ath_init(u16 devid, struct ath_softc *sc)
spin_lock_init(&sc->wiphy_lock);
spin_lock_init(&sc->sc_resetlock);
spin_lock_init(&sc->sc_serial_rw);
+ spin_lock_init(&sc->ani_lock);
+ spin_lock_init(&sc->sc_pm_lock);
mutex_init(&sc->mutex);
tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
@@ -1536,7 +1542,8 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
hw->max_rates = 4;
hw->channel_change_time = 5000;
hw->max_listen_interval = 10;
- hw->max_rate_tries = ATH_11N_TXMAXTRY;
+ /* Hardware supports 10 but we use 4 */
+ hw->max_rate_tries = 4;
hw->sta_data_size = sizeof(struct ath_node);
hw->vif_data_size = sizeof(struct ath_vif);
@@ -1973,6 +1980,8 @@ static int ath9k_start(struct ieee80211_hw *hw)
ieee80211_wake_queues(hw);
+ queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work, 0);
+
mutex_unlock:
mutex_unlock(&sc->mutex);
@@ -2092,8 +2101,6 @@ static void ath9k_stop(struct ieee80211_hw *hw)
mutex_lock(&sc->mutex);
- ieee80211_stop_queues(hw);
-
if (ath9k_wiphy_started(sc)) {
mutex_unlock(&sc->mutex);
return; /* another wiphy still in use */
@@ -2196,7 +2203,9 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
- if (conf->type == NL80211_IFTYPE_AP)
+ if (conf->type == NL80211_IFTYPE_AP ||
+ conf->type == NL80211_IFTYPE_ADHOC ||
+ conf->type == NL80211_IFTYPE_MONITOR)
ath_start_ani(sc);
out:
@@ -2249,9 +2258,28 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
struct ath_softc *sc = aphy->sc;
struct ieee80211_conf *conf = &hw->conf;
struct ath_hw *ah = sc->sc_ah;
+ bool all_wiphys_idle = false, disable_radio = false;
mutex_lock(&sc->mutex);
+ /* Leave this as the first check */
+ if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+
+ spin_lock_bh(&sc->wiphy_lock);
+ all_wiphys_idle = ath9k_all_wiphys_idle(sc);
+ spin_unlock_bh(&sc->wiphy_lock);
+
+ if (conf->flags & IEEE80211_CONF_IDLE){
+ if (all_wiphys_idle)
+ disable_radio = true;
+ }
+ else if (all_wiphys_idle) {
+ ath_radio_enable(sc);
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "not-idle: enabling radio\n");
+ }
+ }
+
if (changed & IEEE80211_CONF_CHANGE_PS) {
if (conf->flags & IEEE80211_CONF_PS) {
if (!(ah->caps.hw_caps &
@@ -2319,6 +2347,11 @@ skip_chan_change:
if (changed & IEEE80211_CONF_CHANGE_POWER)
sc->config.txpowlimit = 2 * conf->power_level;
+ if (disable_radio) {
+ DPRINTF(sc, ATH_DBG_CONFIG, "idle: disabling radio\n");
+ ath_radio_disable(sc);
+ }
+
mutex_unlock(&sc->mutex);
return 0;
@@ -2681,9 +2714,9 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
aphy->state = ATH_WIPHY_SCAN;
ath9k_wiphy_pause_all_forced(sc, aphy);
- mutex_lock(&sc->mutex);
+ spin_lock_bh(&sc->ani_lock);
sc->sc_flags |= SC_OP_SCANNING;
- mutex_unlock(&sc->mutex);
+ spin_unlock_bh(&sc->ani_lock);
}
static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
@@ -2691,11 +2724,11 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
- mutex_lock(&sc->mutex);
+ spin_lock_bh(&sc->ani_lock);
aphy->state = ATH_WIPHY_ACTIVE;
sc->sc_flags &= ~SC_OP_SCANNING;
sc->sc_flags |= SC_OP_FULL_RESET;
- mutex_unlock(&sc->mutex);
+ spin_unlock_bh(&sc->ani_lock);
}
struct ieee80211_ops ath9k_ops = {
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index ba06e78b2f50..a07efa22551e 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -22,133 +22,132 @@ static const struct ath_rate_table ar5416_11na_ratetable = {
{
{ VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, 12,
- 0, 2, 1, 0, 0, 0, 0, 0 },
+ 0, 0, 0, 0, 0, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
- 0, 3, 1, 1, 1, 1, 1, 0 },
+ 0, 1, 1, 1, 1, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10000, 0x0a, 0x00, 24,
- 2, 4, 2, 2, 2, 2, 2, 0 },
+ 2, 2, 2, 2, 2, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
13900, 0x0e, 0x00, 36,
- 2, 6, 2, 3, 3, 3, 3, 0 },
+ 2, 3, 3, 3, 3, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17300, 0x09, 0x00, 48,
- 4, 10, 3, 4, 4, 4, 4, 0 },
+ 4, 4, 4, 4, 4, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23000, 0x0d, 0x00, 72,
- 4, 14, 3, 5, 5, 5, 5, 0 },
+ 4, 5, 5, 5, 5, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
- 4, 20, 3, 6, 6, 6, 6, 0 },
+ 4, 6, 6, 6, 6, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
29300, 0x0c, 0x00, 108,
- 4, 23, 3, 7, 7, 7, 7, 0 },
+ 4, 7, 7, 7, 7, 0 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
6400, 0x80, 0x00, 0,
- 0, 2, 3, 8, 24, 8, 24, 3216 },
+ 0, 8, 24, 8, 24, 3216 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
12700, 0x81, 0x00, 1,
- 2, 4, 3, 9, 25, 9, 25, 6434 },
+ 2, 9, 25, 9, 25, 6434 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
18800, 0x82, 0x00, 2,
- 2, 6, 3, 10, 26, 10, 26, 9650 },
+ 2, 10, 26, 10, 26, 9650 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
25000, 0x83, 0x00, 3,
- 4, 10, 3, 11, 27, 11, 27, 12868 },
+ 4, 11, 27, 11, 27, 12868 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
36700, 0x84, 0x00, 4,
- 4, 14, 3, 12, 28, 12, 28, 19304 },
+ 4, 12, 28, 12, 28, 19304 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
48100, 0x85, 0x00, 5,
- 4, 20, 3, 13, 29, 13, 29, 25740 },
+ 4, 13, 29, 13, 29, 25740 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
53500, 0x86, 0x00, 6,
- 4, 23, 3, 14, 30, 14, 30, 28956 },
+ 4, 14, 30, 14, 30, 28956 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
59000, 0x87, 0x00, 7,
- 4, 25, 3, 15, 31, 15, 32, 32180 },
+ 4, 15, 31, 15, 32, 32180 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
12700, 0x88, 0x00,
- 8, 0, 2, 3, 16, 33, 16, 33, 6430 },
+ 8, 3, 16, 33, 16, 33, 6430 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
24800, 0x89, 0x00, 9,
- 2, 4, 3, 17, 34, 17, 34, 12860 },
+ 2, 17, 34, 17, 34, 12860 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
36600, 0x8a, 0x00, 10,
- 2, 6, 3, 18, 35, 18, 35, 19300 },
+ 2, 18, 35, 18, 35, 19300 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
48100, 0x8b, 0x00, 11,
- 4, 10, 3, 19, 36, 19, 36, 25736 },
+ 4, 19, 36, 19, 36, 25736 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
69500, 0x8c, 0x00, 12,
- 4, 14, 3, 20, 37, 20, 37, 38600 },
+ 4, 20, 37, 20, 37, 38600 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
89500, 0x8d, 0x00, 13,
- 4, 20, 3, 21, 38, 21, 38, 51472 },
+ 4, 21, 38, 21, 38, 51472 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
98900, 0x8e, 0x00, 14,
- 4, 23, 3, 22, 39, 22, 39, 57890 },
+ 4, 22, 39, 22, 39, 57890 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
108300, 0x8f, 0x00, 15,
- 4, 25, 3, 23, 40, 23, 41, 64320 },
+ 4, 23, 40, 23, 41, 64320 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
13200, 0x80, 0x00, 0,
- 0, 2, 3, 8, 24, 24, 24, 6684 },
+ 0, 8, 24, 24, 24, 6684 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
25900, 0x81, 0x00, 1,
- 2, 4, 3, 9, 25, 25, 25, 13368 },
+ 2, 9, 25, 25, 25, 13368 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
38600, 0x82, 0x00, 2,
- 2, 6, 3, 10, 26, 26, 26, 20052 },
+ 2, 10, 26, 26, 26, 20052 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
49800, 0x83, 0x00, 3,
- 4, 10, 3, 11, 27, 27, 27, 26738 },
+ 4, 11, 27, 27, 27, 26738 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
72200, 0x84, 0x00, 4,
- 4, 14, 3, 12, 28, 28, 28, 40104 },
+ 4, 12, 28, 28, 28, 40104 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
92900, 0x85, 0x00, 5,
- 4, 20, 3, 13, 29, 29, 29, 53476 },
+ 4, 13, 29, 29, 29, 53476 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
102700, 0x86, 0x00, 6,
- 4, 23, 3, 14, 30, 30, 30, 60156 },
+ 4, 14, 30, 30, 30, 60156 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
112000, 0x87, 0x00, 7,
- 4, 25, 3, 15, 31, 32, 32, 66840 },
+ 4, 15, 31, 32, 32, 66840 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
122000, 0x87, 0x00, 7,
- 4, 25, 3, 15, 31, 32, 32, 74200 },
+ 4, 15, 31, 32, 32, 74200 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
25800, 0x88, 0x00, 8,
- 0, 2, 3, 16, 33, 33, 33, 13360 },
+ 0, 16, 33, 33, 33, 13360 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
49800, 0x89, 0x00, 9,
- 2, 4, 3, 17, 34, 34, 34, 26720 },
+ 2, 17, 34, 34, 34, 26720 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
71900, 0x8a, 0x00, 10,
- 2, 6, 3, 18, 35, 35, 35, 40080 },
+ 2, 18, 35, 35, 35, 40080 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
92500, 0x8b, 0x00, 11,
- 4, 10, 3, 19, 36, 36, 36, 53440 },
+ 4, 19, 36, 36, 36, 53440 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
130300, 0x8c, 0x00, 12,
- 4, 14, 3, 20, 37, 37, 37, 80160 },
+ 4, 20, 37, 37, 37, 80160 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
162800, 0x8d, 0x00, 13,
- 4, 20, 3, 21, 38, 38, 38, 106880 },
+ 4, 21, 38, 38, 38, 106880 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
178200, 0x8e, 0x00, 14,
- 4, 23, 3, 22, 39, 39, 39, 120240 },
+ 4, 22, 39, 39, 39, 120240 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
192100, 0x8f, 0x00, 15,
- 4, 25, 3, 23, 40, 41, 41, 133600 },
+ 4, 23, 40, 41, 41, 133600 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
207000, 0x8f, 0x00, 15,
- 4, 25, 3, 23, 40, 41, 41, 148400 },
+ 4, 23, 40, 41, 41, 148400 },
},
50, /* probe interval */
- 50, /* rssi reduce interval */
WLAN_RC_HT_FLAG, /* Phy rates allowed initially */
};
@@ -160,145 +159,144 @@ static const struct ath_rate_table ar5416_11ng_ratetable = {
{
{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
900, 0x1b, 0x00, 2,
- 0, 0, 1, 0, 0, 0, 0, 0 },
+ 0, 0, 0, 0, 0, 0 },
{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
1900, 0x1a, 0x04, 4,
- 1, 1, 1, 1, 1, 1, 1, 0 },
+ 1, 1, 1, 1, 1, 0 },
{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
4900, 0x19, 0x04, 11,
- 2, 2, 2, 2, 2, 2, 2, 0 },
+ 2, 2, 2, 2, 2, 0 },
{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
8100, 0x18, 0x04, 22,
- 3, 3, 2, 3, 3, 3, 3, 0 },
+ 3, 3, 3, 3, 3, 0 },
{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, 12,
- 4, 2, 1, 4, 4, 4, 4, 0 },
+ 4, 4, 4, 4, 4, 0 },
{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
- 4, 3, 1, 5, 5, 5, 5, 0 },
+ 4, 5, 5, 5, 5, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10100, 0x0a, 0x00, 24,
- 6, 4, 1, 6, 6, 6, 6, 0 },
+ 6, 6, 6, 6, 6, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
14100, 0x0e, 0x00, 36,
- 6, 6, 2, 7, 7, 7, 7, 0 },
+ 6, 7, 7, 7, 7, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17700, 0x09, 0x00, 48,
- 8, 10, 3, 8, 8, 8, 8, 0 },
+ 8, 8, 8, 8, 8, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23700, 0x0d, 0x00, 72,
- 8, 14, 3, 9, 9, 9, 9, 0 },
+ 8, 9, 9, 9, 9, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
- 8, 20, 3, 10, 10, 10, 10, 0 },
+ 8, 10, 10, 10, 10, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
30900, 0x0c, 0x00, 108,
- 8, 23, 3, 11, 11, 11, 11, 0 },
+ 8, 11, 11, 11, 11, 0 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
6400, 0x80, 0x00, 0,
- 4, 2, 3, 12, 28, 12, 28, 3216 },
+ 4, 12, 28, 12, 28, 3216 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
12700, 0x81, 0x00, 1,
- 6, 4, 3, 13, 29, 13, 29, 6434 },
+ 6, 13, 29, 13, 29, 6434 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
18800, 0x82, 0x00, 2,
- 6, 6, 3, 14, 30, 14, 30, 9650 },
+ 6, 14, 30, 14, 30, 9650 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
25000, 0x83, 0x00, 3,
- 8, 10, 3, 15, 31, 15, 31, 12868 },
+ 8, 15, 31, 15, 31, 12868 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
36700, 0x84, 0x00, 4,
- 8, 14, 3, 16, 32, 16, 32, 19304 },
+ 8, 16, 32, 16, 32, 19304 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
48100, 0x85, 0x00, 5,
- 8, 20, 3, 17, 33, 17, 33, 25740 },
+ 8, 17, 33, 17, 33, 25740 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
53500, 0x86, 0x00, 6,
- 8, 23, 3, 18, 34, 18, 34, 28956 },
+ 8, 18, 34, 18, 34, 28956 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
59000, 0x87, 0x00, 7,
- 8, 25, 3, 19, 35, 19, 36, 32180 },
+ 8, 19, 35, 19, 36, 32180 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
12700, 0x88, 0x00, 8,
- 4, 2, 3, 20, 37, 20, 37, 6430 },
+ 4, 20, 37, 20, 37, 6430 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
24800, 0x89, 0x00, 9,
- 6, 4, 3, 21, 38, 21, 38, 12860 },
+ 6, 21, 38, 21, 38, 12860 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
36600, 0x8a, 0x00, 10,
- 6, 6, 3, 22, 39, 22, 39, 19300 },
+ 6, 22, 39, 22, 39, 19300 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
48100, 0x8b, 0x00, 11,
- 8, 10, 3, 23, 40, 23, 40, 25736 },
+ 8, 23, 40, 23, 40, 25736 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
69500, 0x8c, 0x00, 12,
- 8, 14, 3, 24, 41, 24, 41, 38600 },
+ 8, 24, 41, 24, 41, 38600 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
89500, 0x8d, 0x00, 13,
- 8, 20, 3, 25, 42, 25, 42, 51472 },
+ 8, 25, 42, 25, 42, 51472 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
98900, 0x8e, 0x00, 14,
- 8, 23, 3, 26, 43, 26, 44, 57890 },
+ 8, 26, 43, 26, 44, 57890 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
108300, 0x8f, 0x00, 15,
- 8, 25, 3, 27, 44, 27, 45, 64320 },
+ 8, 27, 44, 27, 45, 64320 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
13200, 0x80, 0x00, 0,
- 8, 2, 3, 12, 28, 28, 28, 6684 },
+ 8, 12, 28, 28, 28, 6684 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
25900, 0x81, 0x00, 1,
- 8, 4, 3, 13, 29, 29, 29, 13368 },
+ 8, 13, 29, 29, 29, 13368 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
38600, 0x82, 0x00, 2,
- 8, 6, 3, 14, 30, 30, 30, 20052 },
+ 8, 14, 30, 30, 30, 20052 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
49800, 0x83, 0x00, 3,
- 8, 10, 3, 15, 31, 31, 31, 26738 },
+ 8, 15, 31, 31, 31, 26738 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
72200, 0x84, 0x00, 4,
- 8, 14, 3, 16, 32, 32, 32, 40104 },
+ 8, 16, 32, 32, 32, 40104 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
92900, 0x85, 0x00, 5,
- 8, 20, 3, 17, 33, 33, 33, 53476 },
+ 8, 17, 33, 33, 33, 53476 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
102700, 0x86, 0x00, 6,
- 8, 23, 3, 18, 34, 34, 34, 60156 },
+ 8, 18, 34, 34, 34, 60156 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
112000, 0x87, 0x00, 7,
- 8, 23, 3, 19, 35, 36, 36, 66840 },
+ 8, 19, 35, 36, 36, 66840 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
122000, 0x87, 0x00, 7,
- 8, 25, 3, 19, 35, 36, 36, 74200 },
+ 8, 19, 35, 36, 36, 74200 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
25800, 0x88, 0x00, 8,
- 8, 2, 3, 20, 37, 37, 37, 13360 },
+ 8, 20, 37, 37, 37, 13360 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
49800, 0x89, 0x00, 9,
- 8, 4, 3, 21, 38, 38, 38, 26720 },
+ 8, 21, 38, 38, 38, 26720 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
71900, 0x8a, 0x00, 10,
- 8, 6, 3, 22, 39, 39, 39, 40080 },
+ 8, 22, 39, 39, 39, 40080 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
92500, 0x8b, 0x00, 11,
- 8, 10, 3, 23, 40, 40, 40, 53440 },
+ 8, 23, 40, 40, 40, 53440 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
130300, 0x8c, 0x00, 12,
- 8, 14, 3, 24, 41, 41, 41, 80160 },
+ 8, 24, 41, 41, 41, 80160 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
162800, 0x8d, 0x00, 13,
- 8, 20, 3, 25, 42, 42, 42, 106880 },
+ 8, 25, 42, 42, 42, 106880 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
178200, 0x8e, 0x00, 14,
- 8, 23, 3, 26, 43, 43, 43, 120240 },
+ 8, 26, 43, 43, 43, 120240 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
192100, 0x8f, 0x00, 15,
- 8, 23, 3, 27, 44, 45, 45, 133600 },
+ 8, 27, 44, 45, 45, 133600 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
207000, 0x8f, 0x00, 15,
- 8, 25, 3, 27, 44, 45, 45, 148400 },
+ 8, 27, 44, 45, 45, 148400 },
},
50, /* probe interval */
- 50, /* rssi reduce interval */
WLAN_RC_HT_FLAG, /* Phy rates allowed initially */
};
@@ -307,31 +305,30 @@ static const struct ath_rate_table ar5416_11a_ratetable = {
{
{ VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, (0x80|12),
- 0, 2, 1, 0, 0 },
+ 0, 0, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
- 0, 3, 1, 1, 0 },
+ 0, 1, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10000, 0x0a, 0x00, (0x80|24),
- 2, 4, 2, 2, 0 },
+ 2, 2, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
13900, 0x0e, 0x00, 36,
- 2, 6, 2, 3, 0 },
+ 2, 3, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17300, 0x09, 0x00, (0x80|48),
- 4, 10, 3, 4, 0 },
+ 4, 4, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23000, 0x0d, 0x00, 72,
- 4, 14, 3, 5, 0 },
+ 4, 5, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
- 4, 19, 3, 6, 0 },
+ 4, 6, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
29300, 0x0c, 0x00, 108,
- 4, 23, 3, 7, 0 },
+ 4, 7, 0 },
},
50, /* probe interval */
- 50, /* rssi reduce interval */
0, /* Phy rates allowed initially */
};
@@ -340,64 +337,42 @@ static const struct ath_rate_table ar5416_11g_ratetable = {
{
{ VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
900, 0x1b, 0x00, 2,
- 0, 0, 1, 0, 0 },
+ 0, 0, 0 },
{ VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
1900, 0x1a, 0x04, 4,
- 1, 1, 1, 1, 0 },
+ 1, 1, 0 },
{ VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
4900, 0x19, 0x04, 11,
- 2, 2, 2, 2, 0 },
+ 2, 2, 0 },
{ VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
8100, 0x18, 0x04, 22,
- 3, 3, 2, 3, 0 },
+ 3, 3, 0 },
{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, 12,
- 4, 2, 1, 4, 0 },
+ 4, 4, 0 },
{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
- 4, 3, 1, 5, 0 },
+ 4, 5, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10000, 0x0a, 0x00, 24,
- 6, 4, 1, 6, 0 },
+ 6, 6, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
13900, 0x0e, 0x00, 36,
- 6, 6, 2, 7, 0 },
+ 6, 7, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17300, 0x09, 0x00, 48,
- 8, 10, 3, 8, 0 },
+ 8, 8, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23000, 0x0d, 0x00, 72,
- 8, 14, 3, 9, 0 },
+ 8, 9, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
- 8, 19, 3, 10, 0 },
+ 8, 10, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
29300, 0x0c, 0x00, 108,
- 8, 23, 3, 11, 0 },
+ 8, 11, 0 },
},
50, /* probe interval */
- 50, /* rssi reduce interval */
- 0, /* Phy rates allowed initially */
-};
-
-static const struct ath_rate_table ar5416_11b_ratetable = {
- 4,
- {
- { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
- 900, 0x1b, 0x00, (0x80|2),
- 0, 0, 1, 0, 0 },
- { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
- 1800, 0x1a, 0x04, (0x80|4),
- 1, 1, 1, 1, 0 },
- { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
- 4300, 0x19, 0x04, (0x80|11),
- 1, 2, 2, 2, 0 },
- { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
- 7100, 0x18, 0x04, (0x80|22),
- 1, 4, 100, 3, 0 },
- },
- 100, /* probe interval */
- 100, /* rssi reduce interval */
0, /* Phy rates allowed initially */
};
@@ -454,13 +429,6 @@ static inline void ath_rc_set_valid_txmask(struct ath_rate_priv *ath_rc_priv,
ath_rc_priv->valid_rate_index[index] = valid_tx_rate ? 1 : 0;
}
-static inline int ath_rc_isvalid_txmask(struct ath_rate_priv *ath_rc_priv,
- u8 index)
-{
- ASSERT(index <= ath_rc_priv->rate_table_size);
- return ath_rc_priv->valid_rate_index[index];
-}
-
static inline
int ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table,
struct ath_rate_priv *ath_rc_priv,
@@ -501,9 +469,9 @@ static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw)
}
static inline int
-ath_rc_get_nextlowervalid_txrate(const struct ath_rate_table *rate_table,
- struct ath_rate_priv *ath_rc_priv,
- u8 cur_valid_txrate, u8 *next_idx)
+ath_rc_get_lower_rix(const struct ath_rate_table *rate_table,
+ struct ath_rate_priv *ath_rc_priv,
+ u8 cur_valid_txrate, u8 *next_idx)
{
int8_t i;
@@ -629,52 +597,20 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv,
return hi;
}
-static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
- struct ath_rate_priv *ath_rc_priv,
- const struct ath_rate_table *rate_table,
- int *is_probing)
+/* Finds the highest rate index we can use */
+static u8 ath_rc_get_highest_rix(struct ath_softc *sc,
+ struct ath_rate_priv *ath_rc_priv,
+ const struct ath_rate_table *rate_table,
+ int *is_probing)
{
- u32 dt, best_thruput, this_thruput, now_msec;
+ u32 best_thruput, this_thruput, now_msec;
u8 rate, next_rate, best_rate, maxindex, minindex;
- int8_t rssi_last, rssi_reduce = 0, index = 0;
-
- *is_probing = 0;
-
- rssi_last = median(ath_rc_priv->rssi_last,
- ath_rc_priv->rssi_last_prev,
- ath_rc_priv->rssi_last_prev2);
-
- /*
- * Age (reduce) last ack rssi based on how old it is.
- * The bizarre numbers are so the delta is 160msec,
- * meaning we divide by 16.
- * 0msec <= dt <= 25msec: don't derate
- * 25msec <= dt <= 185msec: derate linearly from 0 to 10dB
- * 185msec <= dt: derate by 10dB
- */
+ int8_t index = 0;
now_msec = jiffies_to_msecs(jiffies);
- dt = now_msec - ath_rc_priv->rssi_time;
-
- if (dt >= 185)
- rssi_reduce = 10;
- else if (dt >= 25)
- rssi_reduce = (u8)((dt - 25) >> 4);
-
- /* Now reduce rssi_last by rssi_reduce */
- if (rssi_last < rssi_reduce)
- rssi_last = 0;
- else
- rssi_last -= rssi_reduce;
-
- /*
- * Now look up the rate in the rssi table and return it.
- * If no rates match then we return 0 (lowest rate)
- */
-
+ *is_probing = 0;
best_thruput = 0;
maxindex = ath_rc_priv->max_valid_rate-1;
-
minindex = 0;
best_rate = minindex;
@@ -700,7 +636,7 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
* 10-15 and we would be worse off then staying
* at the current rate.
*/
- per_thres = ath_rc_priv->state[rate].per;
+ per_thres = ath_rc_priv->per[rate];
if (per_thres < 12)
per_thres = 12;
@@ -714,7 +650,6 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
}
rate = best_rate;
- ath_rc_priv->rssi_last_lookup = rssi_last;
/*
* Must check the actual rate (ratekbps) to account for
@@ -741,10 +676,18 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
if (rate > (ath_rc_priv->rate_table_size - 1))
rate = ath_rc_priv->rate_table_size - 1;
- ASSERT((rate_table->info[rate].valid &&
- (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)) ||
- (rate_table->info[rate].valid_single_stream &&
- !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)));
+ if (rate_table->info[rate].valid &&
+ (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG))
+ return rate;
+
+ if (rate_table->info[rate].valid_single_stream &&
+ !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG));
+ return rate;
+
+ /* This should not happen */
+ WARN_ON(1);
+
+ rate = ath_rc_priv->valid_rate_index[0];
return rate;
}
@@ -796,7 +739,6 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc,
* just CTS. Note that this is only done for OFDM/HT unicast frames.
*/
if ((sc->sc_flags & SC_OP_PROTECT_ENABLE) &&
- !(tx_info->flags & IEEE80211_TX_CTL_NO_ACK) &&
(rate_table->info[rix].phy == WLAN_RC_PHY_OFDM ||
WLAN_RC_PHY_HT(rate_table->info[rix].phy))) {
rates[0].flags |= IEEE80211_TX_RC_USE_CTS_PROTECT;
@@ -806,50 +748,37 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc,
tx_info->control.rts_cts_rate_idx = cix;
}
-static u8 ath_rc_rate_getidx(struct ath_softc *sc,
- struct ath_rate_priv *ath_rc_priv,
- const struct ath_rate_table *rate_table,
- u8 rix, u16 stepdown,
- u16 min_rate)
-{
- u32 j;
- u8 nextindex = 0;
-
- if (min_rate) {
- for (j = RATE_TABLE_SIZE; j > 0; j--) {
- if (ath_rc_get_nextlowervalid_txrate(rate_table,
- ath_rc_priv, rix, &nextindex))
- rix = nextindex;
- else
- break;
- }
- } else {
- for (j = stepdown; j > 0; j--) {
- if (ath_rc_get_nextlowervalid_txrate(rate_table,
- ath_rc_priv, rix, &nextindex))
- rix = nextindex;
- else
- break;
- }
- }
- return rix;
-}
-
-static void ath_rc_ratefind(struct ath_softc *sc,
- struct ath_rate_priv *ath_rc_priv,
- struct ieee80211_tx_rate_control *txrc)
+static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
+ struct ieee80211_tx_rate_control *txrc)
{
+ struct ath_softc *sc = priv;
+ struct ath_rate_priv *ath_rc_priv = priv_sta;
const struct ath_rate_table *rate_table;
struct sk_buff *skb = txrc->skb;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_tx_rate *rates = tx_info->control.rates;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
__le16 fc = hdr->frame_control;
- u8 try_per_rate = 0, i = 0, rix, nrix;
+ u8 try_per_rate, i = 0, rix, nrix;
int is_probe = 0;
+ if (rate_control_send_low(sta, priv_sta, txrc))
+ return;
+
+ /*
+ * For Multi Rate Retry we use a different number of
+ * retry attempt counts. This ends up looking like this:
+ *
+ * MRR[0] = 2
+ * MRR[1] = 2
+ * MRR[2] = 2
+ * MRR[3] = 4
+ *
+ */
+ try_per_rate = sc->hw->max_rate_tries;
+
rate_table = sc->cur_rate_table;
- rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, &is_probe);
+ rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe);
nrix = rix;
if (is_probe) {
@@ -858,18 +787,15 @@ static void ath_rc_ratefind(struct ath_softc *sc,
ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
1, nrix, 0);
- try_per_rate = (ATH_11N_TXMAXTRY/4);
/* Get the next tried/allowed rate. No RTS for the next series
* after the probe rate
*/
- nrix = ath_rc_rate_getidx(sc, ath_rc_priv,
- rate_table, nrix, 1, 0);
+ ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix);
ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
try_per_rate, nrix, 0);
tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
} else {
- try_per_rate = (ATH_11N_TXMAXTRY/4);
/* Set the choosen rate. No RTS for first series entry. */
ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
try_per_rate, nrix, 0);
@@ -877,18 +803,14 @@ static void ath_rc_ratefind(struct ath_softc *sc,
/* Fill in the other rates for multirate retry */
for ( ; i < 4; i++) {
- u8 try_num;
- u8 min_rate;
-
- try_num = ((i + 1) == 4) ?
- ATH_11N_TXMAXTRY - (try_per_rate * i) : try_per_rate ;
- min_rate = (((i + 1) == 4) && 0);
+ /* Use twice the number of tries for the last MRR segment. */
+ if (i + 1 == 4)
+ try_per_rate = 4;
- nrix = ath_rc_rate_getidx(sc, ath_rc_priv,
- rate_table, nrix, 1, min_rate);
+ ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix);
/* All other rates in the series have RTS enabled */
ath_rc_rate_set_series(rate_table, &rates[i], txrc,
- try_num, nrix, 1);
+ try_per_rate, nrix, 1);
}
/*
@@ -925,9 +847,8 @@ static void ath_rc_ratefind(struct ath_softc *sc,
*
* FIXME: Fix duration
*/
- if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK) &&
- (ieee80211_has_morefrags(fc) ||
- (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG))) {
+ if (ieee80211_has_morefrags(fc) ||
+ (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) {
rates[1].count = rates[2].count = rates[3].count = 0;
rates[1].idx = rates[2].idx = rates[3].idx = 0;
rates[0].count = ATH_TXMAXTRY;
@@ -960,13 +881,13 @@ static bool ath_rc_update_per(struct ath_softc *sc,
100 * 9 / 10
};
- last_per = ath_rc_priv->state[tx_rate].per;
+ last_per = ath_rc_priv->per[tx_rate];
if (xretries) {
if (xretries == 1) {
- ath_rc_priv->state[tx_rate].per += 30;
- if (ath_rc_priv->state[tx_rate].per > 100)
- ath_rc_priv->state[tx_rate].per = 100;
+ ath_rc_priv->per[tx_rate] += 30;
+ if (ath_rc_priv->per[tx_rate] > 100)
+ ath_rc_priv->per[tx_rate] = 100;
} else {
/* xretries == 2 */
count = ARRAY_SIZE(nretry_to_per_lookup);
@@ -974,7 +895,7 @@ static bool ath_rc_update_per(struct ath_softc *sc,
retries = count - 1;
/* new_PER = 7/8*old_PER + 1/8*(currentPER) */
- ath_rc_priv->state[tx_rate].per =
+ ath_rc_priv->per[tx_rate] =
(u8)(last_per - (last_per >> 3) + (100 >> 3));
}
@@ -1010,18 +931,14 @@ static bool ath_rc_update_per(struct ath_softc *sc,
n_frames = tx_info_priv->n_frames * (retries + 1);
cur_per = (100 * n_bad_frames / n_frames) >> 3;
new_per = (u8)(last_per - (last_per >> 3) + cur_per);
- ath_rc_priv->state[tx_rate].per = new_per;
+ ath_rc_priv->per[tx_rate] = new_per;
}
} else {
- ath_rc_priv->state[tx_rate].per =
+ ath_rc_priv->per[tx_rate] =
(u8)(last_per - (last_per >> 3) +
(nretry_to_per_lookup[retries] >> 3));
}
- ath_rc_priv->rssi_last_prev2 = ath_rc_priv->rssi_last_prev;
- ath_rc_priv->rssi_last_prev = ath_rc_priv->rssi_last;
- ath_rc_priv->rssi_last = tx_info_priv->tx.ts_rssi;
- ath_rc_priv->rssi_time = now_msec;
/*
* If we got at most one retry then increase the max rate if
@@ -1045,8 +962,8 @@ static bool ath_rc_update_per(struct ath_softc *sc,
ath_rc_priv->probe_rate;
probe_rate = ath_rc_priv->probe_rate;
- if (ath_rc_priv->state[probe_rate].per > 30)
- ath_rc_priv->state[probe_rate].per = 20;
+ if (ath_rc_priv->per[probe_rate] > 30)
+ ath_rc_priv->per[probe_rate] = 20;
ath_rc_priv->probe_rate = 0;
@@ -1065,18 +982,9 @@ static bool ath_rc_update_per(struct ath_softc *sc,
/*
* Don't update anything. We don't know if
* this was because of collisions or poor signal.
- *
- * Later: if rssi_ack is close to
- * ath_rc_priv->state[txRate].rssi_thres and we see lots
- * of retries, then we could increase
- * ath_rc_priv->state[txRate].rssi_thres.
*/
ath_rc_priv->hw_maxretry_pktcnt = 0;
} else {
- int32_t rssi_ackAvg;
- int8_t rssi_thres;
- int8_t rssi_ack_vmin;
-
/*
* It worked with no retries. First ignore bogus (small)
* rssi_ack values.
@@ -1086,43 +994,9 @@ static bool ath_rc_update_per(struct ath_softc *sc,
ath_rc_priv->hw_maxretry_pktcnt++;
}
- if (tx_info_priv->tx.ts_rssi <
- rate_table->info[tx_rate].rssi_ack_validmin)
- goto exit;
-
- /* Average the rssi */
- if (tx_rate != ath_rc_priv->rssi_sum_rate) {
- ath_rc_priv->rssi_sum_rate = tx_rate;
- ath_rc_priv->rssi_sum =
- ath_rc_priv->rssi_sum_cnt = 0;
- }
-
- ath_rc_priv->rssi_sum += tx_info_priv->tx.ts_rssi;
- ath_rc_priv->rssi_sum_cnt++;
-
- if (ath_rc_priv->rssi_sum_cnt < 4)
- goto exit;
-
- rssi_ackAvg =
- (ath_rc_priv->rssi_sum + 2) / 4;
- rssi_thres =
- ath_rc_priv->state[tx_rate].rssi_thres;
- rssi_ack_vmin =
- rate_table->info[tx_rate].rssi_ack_validmin;
-
- ath_rc_priv->rssi_sum =
- ath_rc_priv->rssi_sum_cnt = 0;
-
- /* Now reduce the current rssi threshold */
- if ((rssi_ackAvg < rssi_thres + 2) &&
- (rssi_thres > rssi_ack_vmin)) {
- ath_rc_priv->state[tx_rate].rssi_thres--;
- }
-
- state_change = true;
}
}
-exit:
+
return state_change;
}
@@ -1134,11 +1008,6 @@ static void ath_rc_update_ht(struct ath_softc *sc,
struct ath_tx_info_priv *tx_info_priv,
int tx_rate, int xretries, int retries)
{
-#define CHK_RSSI(rate) \
- ((ath_rc_priv->state[(rate)].rssi_thres + \
- rate_table->info[(rate)].rssi_ack_deltamin) > \
- ath_rc_priv->state[(rate)+1].rssi_thres)
-
u32 now_msec = jiffies_to_msecs(jiffies);
int rate;
u8 last_per;
@@ -1149,14 +1018,7 @@ static void ath_rc_update_ht(struct ath_softc *sc,
if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt))
return;
- /* To compensate for some imbalance between ctrl and ext. channel */
-
- if (WLAN_RC_PHY_40(rate_table->info[tx_rate].phy))
- tx_info_priv->tx.ts_rssi =
- tx_info_priv->tx.ts_rssi < 3 ? 0 :
- tx_info_priv->tx.ts_rssi - 3;
-
- last_per = ath_rc_priv->state[tx_rate].per;
+ last_per = ath_rc_priv->per[tx_rate];
/* Update PER first */
state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv,
@@ -1167,114 +1029,55 @@ static void ath_rc_update_ht(struct ath_softc *sc,
* If this rate looks bad (high PER) then stop using it for
* a while (except if we are probing).
*/
- if (ath_rc_priv->state[tx_rate].per >= 55 && tx_rate > 0 &&
+ if (ath_rc_priv->per[tx_rate] >= 55 && tx_rate > 0 &&
rate_table->info[tx_rate].ratekbps <=
rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) {
- ath_rc_get_nextlowervalid_txrate(rate_table, ath_rc_priv,
- (u8)tx_rate, &ath_rc_priv->rate_max_phy);
+ ath_rc_get_lower_rix(rate_table, ath_rc_priv,
+ (u8)tx_rate, &ath_rc_priv->rate_max_phy);
/* Don't probe for a little while. */
ath_rc_priv->probe_time = now_msec;
}
- if (state_change) {
- /*
- * Make sure the rates above this have higher rssi thresholds.
- * (Note: Monotonicity is kept within the OFDM rates and
- * within the CCK rates. However, no adjustment is
- * made to keep the rssi thresholds monotonically
- * increasing between the CCK and OFDM rates.)
- */
- for (rate = tx_rate; rate < size - 1; rate++) {
- if (rate_table->info[rate+1].phy !=
- rate_table->info[tx_rate].phy)
- break;
-
- if (CHK_RSSI(rate)) {
- ath_rc_priv->state[rate+1].rssi_thres =
- ath_rc_priv->state[rate].rssi_thres +
- rate_table->info[rate].rssi_ack_deltamin;
- }
- }
-
- /* Make sure the rates below this have lower rssi thresholds. */
- for (rate = tx_rate - 1; rate >= 0; rate--) {
- if (rate_table->info[rate].phy !=
- rate_table->info[tx_rate].phy)
- break;
-
- if (CHK_RSSI(rate)) {
- if (ath_rc_priv->state[rate+1].rssi_thres <
- rate_table->info[rate].rssi_ack_deltamin)
- ath_rc_priv->state[rate].rssi_thres = 0;
- else {
- ath_rc_priv->state[rate].rssi_thres =
- ath_rc_priv->state[rate+1].rssi_thres -
- rate_table->info[rate].rssi_ack_deltamin;
- }
-
- if (ath_rc_priv->state[rate].rssi_thres <
- rate_table->info[rate].rssi_ack_validmin) {
- ath_rc_priv->state[rate].rssi_thres =
- rate_table->info[rate].rssi_ack_validmin;
- }
- }
- }
- }
-
/* Make sure the rates below this have lower PER */
/* Monotonicity is kept only for rates below the current rate. */
- if (ath_rc_priv->state[tx_rate].per < last_per) {
+ if (ath_rc_priv->per[tx_rate] < last_per) {
for (rate = tx_rate - 1; rate >= 0; rate--) {
if (rate_table->info[rate].phy !=
rate_table->info[tx_rate].phy)
break;
- if (ath_rc_priv->state[rate].per >
- ath_rc_priv->state[rate+1].per) {
- ath_rc_priv->state[rate].per =
- ath_rc_priv->state[rate+1].per;
+ if (ath_rc_priv->per[rate] >
+ ath_rc_priv->per[rate+1]) {
+ ath_rc_priv->per[rate] =
+ ath_rc_priv->per[rate+1];
}
}
}
/* Maintain monotonicity for rates above the current rate */
for (rate = tx_rate; rate < size - 1; rate++) {
- if (ath_rc_priv->state[rate+1].per <
- ath_rc_priv->state[rate].per)
- ath_rc_priv->state[rate+1].per =
- ath_rc_priv->state[rate].per;
- }
-
- /* Every so often, we reduce the thresholds and
- * PER (different for CCK and OFDM). */
- if (now_msec - ath_rc_priv->rssi_down_time >=
- rate_table->rssi_reduce_interval) {
-
- for (rate = 0; rate < size; rate++) {
- if (ath_rc_priv->state[rate].rssi_thres >
- rate_table->info[rate].rssi_ack_validmin)
- ath_rc_priv->state[rate].rssi_thres -= 1;
- }
- ath_rc_priv->rssi_down_time = now_msec;
+ if (ath_rc_priv->per[rate+1] <
+ ath_rc_priv->per[rate])
+ ath_rc_priv->per[rate+1] =
+ ath_rc_priv->per[rate];
}
/* Every so often, we reduce the thresholds
* and PER (different for CCK and OFDM). */
if (now_msec - ath_rc_priv->per_down_time >=
- rate_table->rssi_reduce_interval) {
+ rate_table->probe_interval) {
for (rate = 0; rate < size; rate++) {
- ath_rc_priv->state[rate].per =
- 7 * ath_rc_priv->state[rate].per / 8;
+ ath_rc_priv->per[rate] =
+ 7 * ath_rc_priv->per[rate] / 8;
}
ath_rc_priv->per_down_time = now_msec;
}
ath_debug_stat_retries(sc, tx_rate, xretries, retries,
- ath_rc_priv->state[tx_rate].per);
+ ath_rc_priv->per[tx_rate]);
-#undef CHK_RSSI
}
static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table,
@@ -1410,9 +1213,7 @@ static void ath_rc_init(struct ath_softc *sc,
/* Initialize thresholds according to the global rate table */
for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) {
- ath_rc_priv->state[i].rssi_thres =
- rate_table->info[i].rssi_ack_validmin;
- ath_rc_priv->state[i].per = 0;
+ ath_rc_priv->per[i] = 0;
}
/* Determine the valid rates */
@@ -1521,7 +1322,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
/*
* If underrun error is seen assume it as an excessive retry only
* if prefetch trigger level have reached the max (0x3f for 5416)
- * Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY
+ * Adjust the long retry as if the frame was tried hw->max_rate_tries
* times. This affects how ratectrl updates PER for the failed rate.
*/
if (tx_info_priv->tx.ts_flags &
@@ -1536,7 +1337,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
tx_status = 1;
ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status,
- (is_underrun) ? ATH_11N_TXMAXTRY :
+ (is_underrun) ? sc->hw->max_rate_tries :
tx_info_priv->tx.ts_longretry);
/* Check if aggregation has to be enabled for this tid */
@@ -1560,31 +1361,6 @@ exit:
kfree(tx_info_priv);
}
-static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
- struct ieee80211_tx_rate_control *txrc)
-{
- struct ieee80211_supported_band *sband = txrc->sband;
- struct sk_buff *skb = txrc->skb;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct ath_softc *sc = priv;
- struct ath_rate_priv *ath_rc_priv = priv_sta;
- __le16 fc = hdr->frame_control;
-
- /* lowest rate for management and NO_ACK frames */
- if (!ieee80211_is_data(fc) ||
- tx_info->flags & IEEE80211_TX_CTL_NO_ACK || !sta) {
- tx_info->control.rates[0].idx = rate_lowest_index(sband, sta);
- tx_info->control.rates[0].count =
- (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) ?
- 1 : ATH_MGT_TXMAXTRY;
- return;
- }
-
- /* Find tx rate for unicast frames */
- ath_rc_ratefind(sc, ath_rc_priv, txrc);
-}
-
static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta)
{
@@ -1697,7 +1473,6 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp
return NULL;
}
- rate_priv->rssi_down_time = jiffies_to_msecs(jiffies);
rate_priv->tx_triglevel_max = sc->sc_ah->caps.tx_triglevel_max;
return rate_priv;
@@ -1725,8 +1500,6 @@ static struct rate_control_ops ath_rate_ops = {
void ath_rate_attach(struct ath_softc *sc)
{
- sc->hw_rate_table[ATH9K_MODE_11B] =
- &ar5416_11b_ratetable;
sc->hw_rate_table[ATH9K_MODE_11A] =
&ar5416_11a_ratetable;
sc->hw_rate_table[ATH9K_MODE_11G] =
diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h
index e3abd76103fd..fa21a628ddd0 100644
--- a/drivers/net/wireless/ath/ath9k/rc.h
+++ b/drivers/net/wireless/ath/ath9k/rc.h
@@ -112,8 +112,6 @@ struct ath_rate_table {
u8 short_preamble;
u8 dot11rate;
u8 ctrl_rate;
- int8_t rssi_ack_validmin;
- int8_t rssi_ack_deltamin;
u8 base_index;
u8 cw40index;
u8 sgi_index;
@@ -121,15 +119,9 @@ struct ath_rate_table {
u32 max_4ms_framelen;
} info[RATE_TABLE_SIZE];
u32 probe_interval;
- u32 rssi_reduce_interval;
u8 initial_ratemax;
};
-struct ath_tx_ratectrl_state {
- int8_t rssi_thres; /* required rssi for this rate (dB) */
- u8 per; /* recent estimate of packet error rate (%) */
-};
-
struct ath_rateset {
u8 rs_nrates;
u8 rs_rates[ATH_RATE_MAX];
@@ -138,22 +130,14 @@ struct ath_rateset {
/**
* struct ath_rate_priv - Rate Control priv data
* @state: RC state
- * @rssi_last: last ACK rssi
- * @rssi_last_lookup: last ACK rssi used for lookup
- * @rssi_last_prev: previous last ACK rssi
- * @rssi_last_prev2: 2nd previous last ACK rssi
- * @rssi_sum_cnt: count of rssi_sum for averaging
- * @rssi_sum_rate: rate that we are averaging
- * @rssi_sum: running sum of rssi for averaging
* @probe_rate: rate we are probing at
- * @rssi_time: msec timestamp for last ack rssi
- * @rssi_down_time: msec timestamp for last down step
* @probe_time: msec timestamp for last probe
* @hw_maxretry_pktcnt: num of packets since we got HW max retry error
* @max_valid_rate: maximum number of valid rate
* @per_down_time: msec timestamp for last PER down step
* @valid_phy_ratecnt: valid rate count
* @rate_max_phy: phy index for the max rate
+ * @per: PER for every valid rate in %
* @probe_interval: interval for ratectrl to probe for other rates
* @prev_data_rix: rate idx of last data frame
* @ht_cap: HT capabilities
@@ -161,13 +145,6 @@ struct ath_rateset {
* @neg_ht_rates: Negotiated HT rates
*/
struct ath_rate_priv {
- int8_t rssi_last;
- int8_t rssi_last_lookup;
- int8_t rssi_last_prev;
- int8_t rssi_last_prev2;
- int32_t rssi_sum_cnt;
- int32_t rssi_sum_rate;
- int32_t rssi_sum;
u8 rate_table_size;
u8 probe_rate;
u8 hw_maxretry_pktcnt;
@@ -177,14 +154,12 @@ struct ath_rate_priv {
u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX];
u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE];
u8 rate_max_phy;
- u32 rssi_time;
- u32 rssi_down_time;
+ u8 per[RATE_TABLE_SIZE];
u32 probe_time;
u32 per_down_time;
u32 probe_interval;
u32 prev_data_rix;
u32 tx_triglevel_max;
- struct ath_tx_ratectrl_state state[RATE_TABLE_SIZE];
struct ath_rateset neg_rates;
struct ath_rateset neg_ht_rates;
struct ath_rate_softc *asc;
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index cece1c4c6bda..61edfab20ffc 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -145,6 +145,10 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
u8 ratecode;
__le16 fc;
struct ieee80211_hw *hw;
+ struct ieee80211_sta *sta;
+ struct ath_node *an;
+ int last_rssi = ATH_RSSI_DUMMY_MARKER;
+
hdr = (struct ieee80211_hdr *)skb->data;
fc = hdr->frame_control;
@@ -229,17 +233,57 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
}
}
+ rcu_read_lock();
+ sta = ieee80211_find_sta(sc->hw, hdr->addr2);
+ if (sta) {
+ an = (struct ath_node *) sta->drv_priv;
+ if (ds->ds_rxstat.rs_rssi != ATH9K_RSSI_BAD &&
+ !ds->ds_rxstat.rs_moreaggr)
+ ATH_RSSI_LPF(an->last_rssi, ds->ds_rxstat.rs_rssi);
+ last_rssi = an->last_rssi;
+ }
+ rcu_read_unlock();
+
+ if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
+ ds->ds_rxstat.rs_rssi = ATH_EP_RND(last_rssi,
+ ATH_RSSI_EP_MULTIPLIER);
+ if (ds->ds_rxstat.rs_rssi < 0)
+ ds->ds_rxstat.rs_rssi = 0;
+ else if (ds->ds_rxstat.rs_rssi > 127)
+ ds->ds_rxstat.rs_rssi = 127;
+
rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
rx_status->band = hw->conf.channel->band;
rx_status->freq = hw->conf.channel->center_freq;
rx_status->noise = sc->ani.noise_floor;
- rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi;
+ rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + ds->ds_rxstat.rs_rssi;
rx_status->antenna = ds->ds_rxstat.rs_antenna;
- /* at 45 you will be able to use MCS 15 reliably. A more elaborate
- * scheme can be used here but it requires tables of SNR/throughput for
- * each possible mode used. */
- rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45;
+ /*
+ * Theory for reporting quality:
+ *
+ * At a hardware RSSI of 45 you will be able to use MCS 7 reliably.
+ * At a hardware RSSI of 45 you will be able to use MCS 15 reliably.
+ * At a hardware RSSI of 35 you should be able use 54 Mbps reliably.
+ *
+ * MCS 7 is the highets MCS index usable by a 1-stream device.
+ * MCS 15 is the highest MCS index usable by a 2-stream device.
+ *
+ * All ath9k devices are either 1-stream or 2-stream.
+ *
+ * How many bars you see is derived from the qual reporting.
+ *
+ * A more elaborate scheme can be used here but it requires tables
+ * of SNR/throughput for each possible mode used. For the MCS table
+ * you can refer to the wireless wiki:
+ *
+ * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n
+ *
+ */
+ if (conf_is_ht(&hw->conf))
+ rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45;
+ else
+ rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 35;
/* rssi can be more than 45 though, anything above that
* should be considered at 100% */
@@ -505,11 +549,6 @@ static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
return false;
}
-static void ath_rx_ps_back_to_sleep(struct ath_softc *sc)
-{
- sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB);
-}
-
static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
{
struct ieee80211_mgmt *mgmt;
@@ -521,6 +560,8 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
if (memcmp(sc->curbssid, mgmt->bssid, ETH_ALEN) != 0)
return; /* not from our current AP */
+ sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON;
+
if (sc->sc_flags & SC_OP_BEACON_SYNC) {
sc->sc_flags &= ~SC_OP_BEACON_SYNC;
DPRINTF(sc, ATH_DBG_PS, "Reconfigure Beacon timers based on "
@@ -528,14 +569,6 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
ath_beacon_config(sc, NULL);
}
- if (!(sc->hw->conf.flags & IEEE80211_CONF_PS)) {
- /* We are not in PS mode anymore; remain awake */
- DPRINTF(sc, ATH_DBG_PS, "Not in PS mode anymore, remain "
- "awake\n");
- sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB);
- return;
- }
-
if (ath_beacon_dtim_pending_cab(skb)) {
/*
* Remain awake waiting for buffered broadcast/multicast
@@ -556,11 +589,9 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
* fails to send a frame indicating that all CAB frames have
* been delivered.
*/
+ sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB;
DPRINTF(sc, ATH_DBG_PS, "PS wait for CAB frames timed out\n");
}
-
- /* No more broadcast/multicast frames to be received at this point. */
- ath_rx_ps_back_to_sleep(sc);
}
static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
@@ -578,13 +609,13 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
ieee80211_is_action(hdr->frame_control)) &&
is_multicast_ether_addr(hdr->addr1) &&
!ieee80211_has_moredata(hdr->frame_control)) {
- DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to "
- "sleep\n");
/*
* No more broadcast/multicast frames to be received at this
* point.
*/
- ath_rx_ps_back_to_sleep(sc);
+ sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB;
+ DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to "
+ "sleep\n");
} else if ((sc->sc_flags & SC_OP_WAIT_FOR_PSPOLL_DATA) &&
!is_multicast_ether_addr(hdr->addr1) &&
!ieee80211_has_morefrags(hdr->frame_control)) {
@@ -619,13 +650,18 @@ static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb,
if (aphy == NULL)
continue;
nskb = skb_copy(skb, GFP_ATOMIC);
- if (nskb)
- __ieee80211_rx(aphy->hw, nskb, rx_status);
+ if (nskb) {
+ memcpy(IEEE80211_SKB_RXCB(nskb), rx_status,
+ sizeof(*rx_status));
+ ieee80211_rx(aphy->hw, nskb);
+ }
}
- __ieee80211_rx(sc->hw, skb, rx_status);
+ memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status));
+ ieee80211_rx(sc->hw, skb);
} else {
/* Deliver unicast frames based on receiver address */
- __ieee80211_rx(ath_get_virt_hw(sc, hdr), skb, rx_status);
+ memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status));
+ ieee80211_rx(ath_get_virt_hw(sc, hdr), skb);
}
}
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index 52605246679f..8302aeb62e5d 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -574,6 +574,7 @@
#define AR_D_GBL_IFS_SIFS 0x1030
#define AR_D_GBL_IFS_SIFS_M 0x0000FFFF
+#define AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR 0x000003AB
#define AR_D_GBL_IFS_SIFS_RESV0 0xFFFFFFFF
#define AR_D_TXBLK_BASE 0x1038
@@ -589,10 +590,12 @@
#define AR_D_GBL_IFS_SLOT 0x1070
#define AR_D_GBL_IFS_SLOT_M 0x0000FFFF
#define AR_D_GBL_IFS_SLOT_RESV0 0xFFFF0000
+#define AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR 0x00000420
#define AR_D_GBL_IFS_EIFS 0x10b0
#define AR_D_GBL_IFS_EIFS_M 0x0000FFFF
#define AR_D_GBL_IFS_EIFS_RESV0 0xFFFF0000
+#define AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR 0x0000A5EB
#define AR_D_GBL_IFS_MISC 0x10f0
#define AR_D_GBL_IFS_MISC_LFSR_SLICE_SEL 0x00000007
@@ -738,6 +741,9 @@
#define AR_SREV_REVISION_9285_10 0
#define AR_SREV_REVISION_9285_11 1
#define AR_SREV_REVISION_9285_12 2
+#define AR_SREV_VERSION_9287 0x180
+#define AR_SREV_REVISION_9287_10 0
+#define AR_SREV_REVISION_9287_11 1
#define AR_SREV_5416(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
@@ -794,6 +800,21 @@
(AR_SREV_9285(ah) && ((_ah)->hw_version.macRev >= \
AR_SREV_REVISION_9285_12)))
+#define AR_SREV_9287(_ah) \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287))
+#define AR_SREV_9287_10_OR_LATER(_ah) \
+ (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9287))
+#define AR_SREV_9287_10(_ah) \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_10))
+#define AR_SREV_9287_11(_ah) \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_11))
+#define AR_SREV_9287_11_OR_LATER(_ah) \
+ (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_11)))
+
#define AR_RADIO_SREV_MAJOR 0xf0
#define AR_RAD5133_SREV_MAJOR 0xc0
#define AR_RAD2133_SREV_MAJOR 0xd0
@@ -809,6 +830,9 @@
#define AR_AHB_PAGE_SIZE_1K 0x00000000
#define AR_AHB_PAGE_SIZE_2K 0x00000008
#define AR_AHB_PAGE_SIZE_4K 0x00000010
+#define AR_AHB_CUSTOM_BURST_EN 0x000000C0
+#define AR_AHB_CUSTOM_BURST_EN_S 6
+#define AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL 3
#define AR_INTR_RTC_IRQ 0x00000001
#define AR_INTR_MAC_IRQ 0x00000002
@@ -885,6 +909,7 @@ enum {
#define AR_NUM_GPIO 14
#define AR928X_NUM_GPIO 10
#define AR9285_NUM_GPIO 12
+#define AR9287_NUM_GPIO 11
#define AR_GPIO_IN_OUT 0x4048
#define AR_GPIO_IN_VAL 0x0FFFC000
@@ -893,6 +918,8 @@ enum {
#define AR928X_GPIO_IN_VAL_S 10
#define AR9285_GPIO_IN_VAL 0x00FFF000
#define AR9285_GPIO_IN_VAL_S 12
+#define AR9287_GPIO_IN_VAL 0x003FF800
+#define AR9287_GPIO_IN_VAL_S 11
#define AR_GPIO_OE_OUT 0x404c
#define AR_GPIO_OE_OUT_DRV 0x3
@@ -1154,6 +1181,33 @@ enum {
#define AR9285_AN_TOP4 0x7870
#define AR9285_AN_TOP4_DEFAULT 0x10142c00
+#define AR9287_AN_RF2G3_CH0 0x7808
+#define AR9287_AN_RF2G3_CH1 0x785c
+#define AR9287_AN_RF2G3_DB1 0xE0000000
+#define AR9287_AN_RF2G3_DB1_S 29
+#define AR9287_AN_RF2G3_DB2 0x1C000000
+#define AR9287_AN_RF2G3_DB2_S 26
+#define AR9287_AN_RF2G3_OB_CCK 0x03800000
+#define AR9287_AN_RF2G3_OB_CCK_S 23
+#define AR9287_AN_RF2G3_OB_PSK 0x00700000
+#define AR9287_AN_RF2G3_OB_PSK_S 20
+#define AR9287_AN_RF2G3_OB_QAM 0x000E0000
+#define AR9287_AN_RF2G3_OB_QAM_S 17
+#define AR9287_AN_RF2G3_OB_PAL_OFF 0x0001C000
+#define AR9287_AN_RF2G3_OB_PAL_OFF_S 14
+
+#define AR9287_AN_TXPC0 0x7898
+#define AR9287_AN_TXPC0_TXPCMODE 0x0000C000
+#define AR9287_AN_TXPC0_TXPCMODE_S 14
+#define AR9287_AN_TXPC0_TXPCMODE_NORMAL 0
+#define AR9287_AN_TXPC0_TXPCMODE_TEST 1
+#define AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE 2
+#define AR9287_AN_TXPC0_TXPCMODE_ATBTEST 3
+
+#define AR9287_AN_TOP2 0x78b4
+#define AR9287_AN_TOP2_XPABIAS_LVL 0xC0000000
+#define AR9287_AN_TOP2_XPABIAS_LVL_S 30
+
#define AR_STA_ID0 0x8000
#define AR_STA_ID1 0x8004
#define AR_STA_ID1_SADH_MASK 0x0000FFFF
@@ -1188,6 +1242,7 @@ enum {
#define AR_TIME_OUT_ACK_S 0
#define AR_TIME_OUT_CTS 0x3FFF0000
#define AR_TIME_OUT_CTS_S 16
+#define AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR 0x16001D56
#define AR_RSSI_THR 0x8018
#define AR_RSSI_THR_MASK 0x000000FF
@@ -1203,6 +1258,7 @@ enum {
#define AR_USEC_TX_LAT_S 14
#define AR_USEC_RX_LAT 0x1F800000
#define AR_USEC_RX_LAT_S 23
+#define AR_USEC_ASYNC_FIFO_DUR 0x12e00074
#define AR_RESET_TSF 0x8020
#define AR_RESET_TSF_ONCE 0x01000000
@@ -1468,6 +1524,10 @@ enum {
#define AR_SLP_MIB_CLEAR 0x00000001
#define AR_SLP_MIB_PENDING 0x00000002
+#define AR_MAC_PCU_LOGIC_ANALYZER 0x8264
+#define AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768 0x20000000
+
+
#define AR_2040_MODE 0x8318
#define AR_2040_JOINED_RX_CLEAR 0x00000001
@@ -1485,6 +1545,39 @@ enum {
#define AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE 0x00000002
#define AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT 0x00000004
+#define AR_PCU_MISC_MODE2_RESERVED 0x00000038
+#define AR_PCU_MISC_MODE2_ADHOC_MCAST_KEYID_ENABLE 0x00000040
+#define AR_PCU_MISC_MODE2_CFP_IGNORE 0x00000080
+#define AR_PCU_MISC_MODE2_MGMT_QOS 0x0000FF00
+#define AR_PCU_MISC_MODE2_MGMT_QOS_S 8
+#define AR_PCU_MISC_MODE2_ENABLE_LOAD_NAV_BEACON_DURATION 0x00010000
+#define AR_PCU_MISC_MODE2_ENABLE_AGGWEP 0x00020000
+#define AR_PCU_MISC_MODE2_HWWAR1 0x00100000
+#define AR_PCU_MISC_MODE2_HWWAR2 0x02000000
+#define AR_PCU_MISC_MODE2_RESERVED2 0xFFFE0000
+
+#define AR_MAC_PCU_ASYNC_FIFO_REG3 0x8358
+#define AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL 0x00000400
+#define AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET 0x80000000
+
+
+#define AR_AES_MUTE_MASK0 0x805c
+#define AR_AES_MUTE_MASK0_FC 0x0000FFFF
+#define AR_AES_MUTE_MASK0_QOS 0xFFFF0000
+#define AR_AES_MUTE_MASK0_QOS_S 16
+
+#define AR_AES_MUTE_MASK1 0x8060
+#define AR_AES_MUTE_MASK1_SEQ 0x0000FFFF
+#define AR_AES_MUTE_MASK1_SEQ_S 0
+#define AR_AES_MUTE_MASK1_FC_MGMT 0xFFFF0000
+#define AR_AES_MUTE_MASK1_FC_MGMT_S 16
+
+#define AR_RATE_DURATION_0 0x8700
+#define AR_RATE_DURATION_31 0x87CC
+#define AR_RATE_DURATION_32 0x8780
+#define AR_RATE_DURATION(_n) (AR_RATE_DURATION_0 + ((_n)<<2))
+
+
#define AR_KEYTABLE_0 0x8800
#define AR_KEYTABLE(_n) (AR_KEYTABLE_0 + ((_n)*32))
#define AR_KEY_CACHE_SIZE 128
diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c
index 1ff429b027d7..e1d419e02b4a 100644
--- a/drivers/net/wireless/ath/ath9k/virtual.c
+++ b/drivers/net/wireless/ath/ath9k/virtual.c
@@ -660,3 +660,20 @@ void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int)
queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work,
sc->wiphy_scheduler_int);
}
+
+/* caller must hold wiphy_lock */
+bool ath9k_all_wiphys_idle(struct ath_softc *sc)
+{
+ unsigned int i;
+ if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) {
+ return false;
+ }
+ for (i = 0; i < sc->num_sec_wiphy; i++) {
+ struct ath_wiphy *aphy = sc->sec_wiphy[i];
+ if (!aphy)
+ continue;
+ if (aphy->state != ATH_WIPHY_INACTIVE)
+ return false;
+ }
+ return true;
+}
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 4ccf48e396df..4ff155e8ee59 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -73,18 +73,6 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
/* Aggregation logic */
/*********************/
-static int ath_aggr_query(struct ath_softc *sc, struct ath_node *an, u8 tidno)
-{
- struct ath_atx_tid *tid;
- tid = ATH_AN_2_TID(an, tidno);
-
- if (tid->state & AGGR_ADDBA_COMPLETE ||
- tid->state & AGGR_ADDBA_PROGRESS)
- return 1;
- else
- return 0;
-}
-
static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
{
struct ath_atx_ac *ac = tid->ac;
@@ -250,7 +238,10 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
struct ath_buf *tbf;
spin_lock_bh(&sc->tx.txbuflock);
- ASSERT(!list_empty((&sc->tx.txbuf)));
+ if (WARN_ON(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);
spin_unlock_bh(&sc->tx.txbuflock);
@@ -391,6 +382,24 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
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, &bf_head,
+ 0, 0);
+ break;
+ }
+
ath9k_hw_cleartxdesc(sc->sc_ah, tbf->bf_desc);
list_add_tail(&tbf->list, &bf_head);
} else {
@@ -414,7 +423,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
if (tid->state & AGGR_CLEANUP) {
if (tid->baw_head == tid->baw_tail) {
tid->state &= ~AGGR_ADDBA_COMPLETE;
- tid->addba_exchangeattempts = 0;
tid->state &= ~AGGR_CLEANUP;
/* send buffered frames as singles */
@@ -719,7 +727,6 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
txtid->state &= ~AGGR_ADDBA_PROGRESS;
- txtid->addba_exchangeattempts = 0;
return 0;
}
@@ -747,7 +754,6 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
txtid->state |= AGGR_CLEANUP;
} else {
txtid->state &= ~AGGR_ADDBA_COMPLETE;
- txtid->addba_exchangeattempts = 0;
ath_tx_flush_tid(sc, txtid);
}
@@ -780,14 +786,8 @@ bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno)
txtid = ATH_AN_2_TID(an, tidno);
- if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
- if (!(txtid->state & AGGR_ADDBA_PROGRESS) &&
- (txtid->addba_exchangeattempts < ADDBA_EXCHANGE_ATTEMPTS)) {
- txtid->addba_exchangeattempts++;
+ if (!(txtid->state & (AGGR_ADDBA_COMPLETE | AGGR_ADDBA_PROGRESS)))
return true;
- }
- }
-
return false;
}
@@ -872,6 +872,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
txq->axq_aggr_depth = 0;
txq->axq_totalqueued = 0;
txq->axq_linkbuf = NULL;
+ txq->axq_tx_inprogress = false;
sc->tx.txqsetup |= 1<<qnum;
}
return &sc->tx.txq[qnum];
@@ -1038,6 +1039,10 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
ath_tx_complete_buf(sc, bf, &bf_head, 0, 0);
}
+ spin_lock_bh(&txq->axq_lock);
+ txq->axq_tx_inprogress = false;
+ spin_unlock_bh(&txq->axq_lock);
+
/* flush any pending frames if aggregation is enabled */
if (sc->sc_flags & SC_OP_TXAGGR) {
if (!retry_tx) {
@@ -1118,8 +1123,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
if (tid->paused)
continue;
- if ((txq->axq_depth % 2) == 0)
- ath_tx_sched_aggr(sc, txq, tid);
+ ath_tx_sched_aggr(sc, txq, tid);
/*
* add tid to round-robin queue if more frames
@@ -1636,7 +1640,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
goto tx_done;
}
- if (ath_aggr_query(sc, an, bf->bf_tidno)) {
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
/*
* Try aggregation if it's a unicast data frame
* and the destination is HT capable.
@@ -1962,19 +1966,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
if (bf->bf_stale) {
bf_held = bf;
if (list_is_last(&bf_held->list, &txq->axq_q)) {
- txq->axq_link = NULL;
- txq->axq_linkbuf = NULL;
spin_unlock_bh(&txq->axq_lock);
-
- /*
- * The holding descriptor is the last
- * descriptor in queue. It's safe to remove
- * the last holding descriptor in BH context.
- */
- spin_lock_bh(&sc->tx.txbuflock);
- list_move_tail(&bf_held->list, &sc->tx.txbuf);
- spin_unlock_bh(&sc->tx.txbuflock);
-
break;
} else {
bf = list_entry(bf_held->list.next,
@@ -2011,6 +2003,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
txq->axq_aggr_depth--;
txok = (ds->ds_txstat.ts_status == 0);
+ txq->axq_tx_inprogress = false;
spin_unlock_bh(&txq->axq_lock);
if (bf_held) {
@@ -2044,6 +2037,40 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
}
}
+void ath_tx_complete_poll_work(struct work_struct *work)
+{
+ struct ath_softc *sc = container_of(work, struct ath_softc,
+ tx_complete_work.work);
+ struct ath_txq *txq;
+ int i;
+ bool needreset = false;
+
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+ if (ATH_TXQ_SETUP(sc, i)) {
+ txq = &sc->tx.txq[i];
+ spin_lock_bh(&txq->axq_lock);
+ if (txq->axq_depth) {
+ if (txq->axq_tx_inprogress) {
+ needreset = true;
+ spin_unlock_bh(&txq->axq_lock);
+ break;
+ } else {
+ txq->axq_tx_inprogress = true;
+ }
+ }
+ spin_unlock_bh(&txq->axq_lock);
+ }
+
+ if (needreset) {
+ DPRINTF(sc, ATH_DBG_RESET, "tx hung, resetting the chip\n");
+ ath_reset(sc, false);
+ }
+
+ queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work,
+ msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
+}
+
+
void ath_tx_tasklet(struct ath_softc *sc)
{
@@ -2084,6 +2111,8 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
goto err;
}
+ INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
+
err:
if (error != 0)
ath_tx_cleanup(sc);
@@ -2122,7 +2151,6 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
tid->ac = &an->ac[acno];
tid->state &= ~AGGR_ADDBA_COMPLETE;
tid->state &= ~AGGR_ADDBA_PROGRESS;
- tid->addba_exchangeattempts = 0;
}
for (acno = 0, ac = &an->ac[acno];
@@ -2179,7 +2207,6 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
tid->sched = false;
ath_tid_drain(sc, txq, tid);
tid->state &= ~AGGR_ADDBA_COMPLETE;
- tid->addba_exchangeattempts = 0;
tid->state &= ~AGGR_CLEANUP;
}
}
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
index bf3d25ba7be1..077bcc142cde 100644
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -586,7 +586,5 @@ u32 ath_regd_get_band_ctl(struct ath_regulatory *reg,
default:
return NO_CTL;
}
-
- return NO_CTL;
}
EXPORT_SYMBOL(ath_regd_get_band_ctl);
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index 291a94bd46fd..05813bc3e308 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -793,13 +793,13 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
!(*priv->present_callback)(priv->card)) {
dev->stats.tx_errors++;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (priv->station_state != STATION_STATE_READY) {
dev->stats.tx_errors++;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* first ensure the timer func cannot run */
@@ -856,7 +856,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
spin_unlock_bh(&priv->timerlock);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void atmel_transmit_management_frame(struct atmel_private *priv,
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index e71c8d9cd706..3f4360ad0e4e 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -938,7 +938,6 @@ static void b43_clear_keys(struct b43_wldev *dev)
static void b43_dump_keymemory(struct b43_wldev *dev)
{
unsigned int i, index, offset;
- DECLARE_MAC_BUF(macbuf);
u8 mac[ETH_ALEN];
u16 algo;
u32 rcmta0;
@@ -973,8 +972,7 @@ static void b43_dump_keymemory(struct b43_wldev *dev)
((index - 4) * 2) + 1);
*((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0);
*((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1);
- printk(" MAC: %s",
- print_mac(macbuf, mac));
+ printk(" MAC: %pM", mac);
} else
printk(" DEFAULT KEY");
printk("\n");
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
index 55f36a7254d9..5b85e7d73592 100644
--- a/drivers/net/wireless/b43/xmit.c
+++ b/drivers/net/wireless/b43/xmit.c
@@ -670,7 +670,8 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
goto drop;
}
- ieee80211_rx_irqsafe(dev->wl->hw, skb, &status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx_irqsafe(dev->wl->hw, skb);
return;
drop:
diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c
index b8e39dd06e99..f79cee82601b 100644
--- a/drivers/net/wireless/b43legacy/xmit.c
+++ b/drivers/net/wireless/b43legacy/xmit.c
@@ -591,7 +591,8 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
}
dev->stats.last_rx = jiffies;
- ieee80211_rx_irqsafe(dev->wl->hw, skb, &status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx_irqsafe(dev->wl->hw, skb);
return;
drop:
diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c
index d313b005114e..1fe1bbabb907 100644
--- a/drivers/net/wireless/hostap/hostap_80211_tx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_tx.c
@@ -75,7 +75,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: hostap_data_start_xmit: short skb "
"(len=%d)\n", dev->name, skb->len);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (local->ddev != dev) {
@@ -89,14 +89,14 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: prism2_tx: trying to use "
"AP device with Ethernet net dev\n", dev->name);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
} else {
if (local->iw_mode == IW_MODE_REPEAT) {
printk(KERN_DEBUG "%s: prism2_tx: trying to use "
"non-WDS link in Repeater mode\n", dev->name);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else if (local->iw_mode == IW_MODE_INFRA &&
(local->wds_type & HOSTAP_WDS_AP_CLIENT) &&
memcmp(skb->data + ETH_ALEN, dev->dev_addr,
@@ -210,13 +210,13 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb = skb_unshare(skb, GFP_ATOMIC);
if (skb == NULL) {
iface->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
if (pskb_expand_head(skb, need_headroom, need_tailroom,
GFP_ATOMIC)) {
kfree_skb(skb);
iface->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
} else if (skb_headroom(skb) < need_headroom) {
struct sk_buff *tmp = skb;
@@ -224,13 +224,13 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
kfree_skb(tmp);
if (skb == NULL) {
iface->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
} else {
skb = skb_unshare(skb, GFP_ATOMIC);
if (skb == NULL) {
iface->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
}
@@ -256,7 +256,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Send IEEE 802.11 encapsulated frame using the master radio device */
skb->dev = local->dev;
dev_queue_xmit(skb);
- return 0;
+ return NETDEV_TX_OK;
}
@@ -276,7 +276,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: hostap_mgmt_start_xmit: short skb "
"(len=%d)\n", dev->name, skb->len);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
iface->stats.tx_packets++;
@@ -301,7 +301,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Send IEEE 802.11 encapsulated frame using the master radio device */
skb->dev = local->dev;
dev_queue_xmit(skb);
- return 0;
+ return NETDEV_TX_OK;
}
@@ -396,7 +396,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, "
"expected 0x%08x)\n",
dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC);
- ret = 0;
+ ret = NETDEV_TX_OK;
iface->stats.tx_dropped++;
goto fail;
}
@@ -414,7 +414,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->len < 24) {
printk(KERN_DEBUG "%s: hostap_master_start_xmit: short skb "
"(len=%d)\n", dev->name, skb->len);
- ret = 0;
+ ret = NETDEV_TX_OK;
iface->stats.tx_dropped++;
goto fail;
}
@@ -441,13 +441,13 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->name, meta->ethertype);
hostap_dump_tx_80211(dev->name, skb);
- ret = 0; /* drop packet */
+ ret = NETDEV_TX_OK; /* drop packet */
iface->stats.tx_dropped++;
goto fail;
}
break;
case AP_TX_DROP:
- ret = 0; /* drop packet */
+ ret = NETDEV_TX_OK; /* drop packet */
iface->stats.tx_dropped++;
goto fail;
case AP_TX_RETRY:
@@ -455,7 +455,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
case AP_TX_BUFFERED:
/* do not free skb here, it will be freed when the
* buffered frame is sent/timed out */
- ret = 0;
+ ret = NETDEV_TX_OK;
goto tx_exit;
}
@@ -501,7 +501,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
"frame (drop_unencrypted=1)\n", dev->name);
}
iface->stats.tx_dropped++;
- ret = 0;
+ ret = NETDEV_TX_OK;
goto fail;
}
@@ -510,7 +510,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb == NULL) {
printk(KERN_DEBUG "%s: TX - encryption failed\n",
dev->name);
- ret = 0;
+ ret = NETDEV_TX_OK;
goto fail;
}
meta = (struct hostap_skb_tx_data *) skb->cb;
@@ -519,23 +519,23 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
"expected 0x%08x) after hostap_tx_encrypt\n",
dev->name, meta->magic,
HOSTAP_SKB_TX_DATA_MAGIC);
- ret = 0;
+ ret = NETDEV_TX_OK;
iface->stats.tx_dropped++;
goto fail;
}
}
if (local->func->tx == NULL || local->func->tx(skb, dev)) {
- ret = 0;
+ ret = NETDEV_TX_OK;
iface->stats.tx_dropped++;
} else {
- ret = 0;
+ ret = NETDEV_TX_OK;
iface->stats.tx_packets++;
iface->stats.tx_bytes += skb->len;
}
fail:
- if (!ret && skb)
+ if (ret == NETDEV_TX_OK && skb)
dev_kfree_skb(skb);
tx_exit:
if (tx.sta_ptr)
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 633740277352..ad8eab4a639b 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -666,7 +666,8 @@ static int prism2_config(struct pcmcia_device *link)
* irq structure is initialized.
*/
if (link->conf.Attributes & CONF_ENABLE_IRQ) {
- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING |
+ IRQ_HANDLE_PRESENT;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = prism2_interrupt;
link->irq.Instance = dev;
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 44c29b3f6728..2dc1cdbb4939 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -7250,9 +7250,6 @@ static void ipw_bg_qos_activate(struct work_struct *work)
struct ipw_priv *priv =
container_of(work, struct ipw_priv, qos_activate);
- if (priv == NULL)
- return;
-
mutex_lock(&priv->mutex);
if (priv->status & STATUS_ASSOCIATED)
@@ -11436,11 +11433,11 @@ static struct pci_device_id card_ids[] = {
{PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2754, 0, 0, 0},
{PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2761, 0, 0, 0},
{PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2762, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x104f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x4220, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */
- {PCI_VENDOR_ID_INTEL, 0x4221, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */
- {PCI_VENDOR_ID_INTEL, 0x4223, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */
- {PCI_VENDOR_ID_INTEL, 0x4224, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */
+ {PCI_VDEVICE(INTEL, 0x104f), 0},
+ {PCI_VDEVICE(INTEL, 0x4220), 0}, /* BG */
+ {PCI_VDEVICE(INTEL, 0x4221), 0}, /* BG */
+ {PCI_VDEVICE(INTEL, 0x4223), 0}, /* ABG */
+ {PCI_VDEVICE(INTEL, 0x4224), 0}, /* ABG */
/* required last entry */
{0,}
diff --git a/drivers/net/wireless/ipw2x00/libipw_tx.c b/drivers/net/wireless/ipw2x00/libipw_tx.c
index da2ad5437ce5..2e8f84fb29fa 100644
--- a/drivers/net/wireless/ipw2x00/libipw_tx.c
+++ b/drivers/net/wireless/ipw2x00/libipw_tx.c
@@ -527,13 +527,13 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
if (ret == 0) {
dev->stats.tx_packets++;
dev->stats.tx_bytes += txb->payload_size;
- return 0;
+ return NETDEV_TX_OK;
}
ieee80211_txb_free(txb);
}
- return 0;
+ return NETDEV_TX_OK;
failed:
spin_unlock_irqrestore(&ieee->lock, flags);
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 7da52f1cc1d6..a899be914ebf 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -46,7 +46,7 @@
#include "iwl-5000-hw.h"
/* Highest firmware API version supported */
-#define IWL1000_UCODE_API_MAX 2
+#define IWL1000_UCODE_API_MAX 3
/* Lowest firmware API version supported */
#define IWL1000_UCODE_API_MIN 1
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
index 73f93a0ff2df..b569c6f38e5c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
@@ -232,9 +232,8 @@ struct iwl3945_eeprom {
#define PCI_CFG_REV_ID_BIT_BASIC_SKU (0x40) /* bit 6 */
#define PCI_CFG_REV_ID_BIT_RTP (0x80) /* bit 7 */
-#define TFD_QUEUE_MIN 0
-#define TFD_QUEUE_MAX 5 /* 4 DATA + 1 CMD */
-
+/* 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
@@ -280,8 +279,6 @@ struct iwl3945_eeprom {
/* Size of uCode instruction memory in bootstrap state machine */
#define IWL39_MAX_BSM_SIZE IWL39_RTC_INST_SIZE
-#define IWL39_MAX_NUM_QUEUES 8
-
static inline int iwl3945_hw_valid_rtc_data_addr(u32 addr)
{
return (addr >= IWL39_RTC_DATA_LOWER_BOUND) &&
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
index 5eb538d18a80..a16bd4147eac 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
@@ -673,33 +673,17 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
s8 scale_action = 0;
unsigned long flags;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- u16 fc;
- u16 rate_mask = 0;
+ 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 ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
IWL_DEBUG_RATE(priv, "enter\n");
- if (sta)
- rate_mask = sta->supp_rates[sband->band];
-
- /* Send management frames and NO_ACK data using lowest rate. */
- fc = le16_to_cpu(hdr->frame_control);
- if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
- info->flags & IEEE80211_TX_CTL_NO_ACK ||
- !sta || !priv_sta) {
- IWL_DEBUG_RATE(priv, "leave: No STA priv data to update!\n");
- if (!rate_mask)
- info->control.rates[0].idx =
- rate_lowest_index(sband, NULL);
- else
- info->control.rates[0].idx =
- rate_lowest_index(sband, sta);
- if (info->flags & IEEE80211_TX_CTL_NO_ACK)
- info->control.rates[0].count = 1;
+ if (rate_control_send_low(sta, priv_sta, txrc))
return;
- }
+
+ rate_mask = sta->supp_rates[sband->band];
/* get user max rate if set */
max_rate_idx = txrc->max_rate_idx;
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 46288e724889..8ee403cd9b99 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -502,14 +502,14 @@ static void _iwl3945_dbg_report_frame(struct iwl_priv *priv,
}
}
if (print_dump)
- iwl_print_hex_dump(priv, IWL_DL_RX, data, length);
+ iwl_print_hex_dump(IWL_DL_RX, data, length);
}
static void iwl3945_dbg_report_frame(struct iwl_priv *priv,
struct iwl_rx_packet *pkt,
struct ieee80211_hdr *header, int group100)
{
- if (priv->debug_level & IWL_DL_RX)
+ if (iwl_debug_level & IWL_DL_RX)
_iwl3945_dbg_report_frame(priv, pkt, header, group100);
}
@@ -577,7 +577,8 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
if (ieee80211_is_data(hdr->frame_control))
priv->rxtxpackets += len;
#endif
- ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
+ memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats));
+ ieee80211_rx_irqsafe(priv->hw, rxb->skb);
rxb->skb = NULL;
}
@@ -962,7 +963,7 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
goto error;
/* Tx queue(s) */
- for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++) {
+ 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;
rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
@@ -1139,7 +1140,7 @@ void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv)
int txq_id;
/* Tx queues */
- for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++)
+ 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
@@ -1155,7 +1156,7 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv)
iwl_write_prph(priv, ALM_SCD_MODE_REG, 0);
/* reset TFD queues */
- for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++) {
+ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
iwl_write_direct32(priv, FH39_TCSR_CONFIG(txq_id), 0x0);
iwl_poll_direct_bit(priv, FH39_TSSR_TX_STATUS,
FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(txq_id),
@@ -1986,7 +1987,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
staging_rxon->reserved4 = 0;
staging_rxon->reserved5 = 0;
- iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto);
+ iwl_set_rxon_hwcrypto(priv, !iwl3945_mod_params.sw_crypto);
/* Apply the new configuration */
rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
@@ -2551,7 +2552,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
}
/* Assign number of Usable TX queues */
- priv->hw_params.max_txq_num = TFD_QUEUE_MAX;
+ priv->hw_params.max_txq_num = IWL39_NUM_QUEUES;
priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd);
priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_3K;
@@ -2562,6 +2563,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.bcast_sta_id = IWL3945_BROADCAST_ID;
priv->hw_params.rx_wrt_ptr_reg = FH39_RSCSR_CHNL0_WPTR;
+ priv->hw_params.max_beacon_itrvl = IWL39_MAX_UCODE_BEACON_INTERVAL;
return 0;
}
@@ -2784,11 +2786,50 @@ 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,
+};
+
static struct iwl_lib_ops iwl3945_lib = {
.txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd,
.txq_free_tfd = iwl3945_hw_txq_free_tfd,
@@ -2829,6 +2870,7 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
};
static struct iwl_ops iwl3945_ops = {
+ .ucode = &iwl3945_ucode,
.lib = &iwl3945_lib,
.hcmd = &iwl3945_hcmd,
.utils = &iwl3945_hcmd_utils,
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index 2de6471d4be9..f2ffc48cbaf8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -111,9 +111,6 @@ enum iwl3945_antenna {
#define IWL_TX_FIFO_HCCA_2 6
#define IWL_TX_FIFO_NONE 7
-/* Minimum number of queues. MAX_NUM is defined in hw specific files */
-#define IWL39_MIN_NUM_QUEUES 4
-
#define IEEE80211_DATA_LEN 2304
#define IEEE80211_4ADDR_LEN 30
#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN)
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 8f3d4bc6a03f..c30a1b960576 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -146,7 +146,7 @@ static int iwl4965_load_bsm(struct iwl_priv *priv)
IWL_DEBUG_INFO(priv, "Begin load bsm\n");
- priv->ucode_type = UCODE_RT;
+ priv->ucode_type = UCODE_INIT;
/* make sure bootstrap program is no larger than BSM's SRAM size */
if (len > IWL49_MAX_BSM_SIZE)
@@ -256,6 +256,8 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv)
*/
static void iwl4965_init_alive_start(struct iwl_priv *priv)
{
+ int ret;
+
/* 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
@@ -287,6 +289,28 @@ static void iwl4965_init_alive_start(struct iwl_priv *priv)
IWL_DEBUG_INFO(priv, "Couldn't set up uCode pointers.\n");
goto restart;
}
+ priv->ucode_type = UCODE_RT;
+ if (test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) {
+ IWL_WARN(priv, "Runtime uCode already alive? "
+ "Waiting for alive anyway\n");
+ clear_bit(STATUS_RT_UCODE_ALIVE, &priv->status);
+ }
+ ret = wait_event_interruptible_timeout(
+ priv->wait_command_queue,
+ test_bit(STATUS_RT_UCODE_ALIVE, &priv->status),
+ UCODE_ALIVE_TIMEOUT);
+ if (!ret) {
+ /* FIXME: if STATUS_RT_UCODE_ALIVE timeout
+ * go back to restart the download Init uCode again
+ * this might cause to trap in the restart loop
+ */
+ priv->ucode_type = UCODE_NONE;
+ if (!test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) {
+ IWL_ERR(priv, "Runtime timeout after %dms\n",
+ jiffies_to_msecs(UCODE_ALIVE_TIMEOUT));
+ goto restart;
+ }
+ }
return;
restart:
@@ -728,7 +752,7 @@ static int iwl4965_alive_notify(struct iwl_priv *priv)
static struct iwl_sensitivity_ranges iwl4965_sensitivity = {
.min_nrg_cck = 97,
- .max_nrg_cck = 0,
+ .max_nrg_cck = 0, /* not used, set to 0 */
.auto_corr_min_ofdm = 85,
.auto_corr_min_ofdm_mrc = 170,
@@ -2221,12 +2245,50 @@ 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,
};
+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,
@@ -2287,6 +2349,7 @@ static struct iwl_lib_ops iwl4965_lib = {
};
static struct iwl_ops iwl4965_ops = {
+ .ucode = &iwl4965_ucode,
.lib = &iwl4965_lib,
.hcmd = &iwl4965_hcmd,
.utils = &iwl4965_hcmd_utils,
@@ -2313,8 +2376,6 @@ module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444);
MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444);
MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
-module_param_named(debug, iwl4965_mod_params.debug, uint, 0444);
-MODULE_PARM_DESC(debug, "debug output mask");
module_param_named(
disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, 0444);
MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index b3c648ce8c7b..702db07fa382 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -239,6 +239,13 @@ static void iwl5000_nic_config(struct iwl_priv *priv)
APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
+ if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_1000) {
+ /* Setting digital SVR for 1000 card to 1.32V */
+ iwl_set_bits_mask_prph(priv, APMG_DIGITAL_SVR_REG,
+ APMG_SVR_DIGITAL_VOLTAGE_1_32,
+ ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK);
+ }
+
spin_unlock_irqrestore(&priv->lock, flags);
}
@@ -388,7 +395,7 @@ void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
.min_nrg_cck = 95,
- .max_nrg_cck = 0,
+ .max_nrg_cck = 0, /* not used, set to 0 */
.auto_corr_min_ofdm = 90,
.auto_corr_min_ofdm_mrc = 170,
.auto_corr_min_ofdm_x1 = 120,
@@ -407,6 +414,28 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
.nrg_th_ofdm = 95,
};
+static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
+ .min_nrg_cck = 95,
+ .max_nrg_cck = 0, /* not used, set to 0 */
+ .auto_corr_min_ofdm = 90,
+ .auto_corr_min_ofdm_mrc = 170,
+ .auto_corr_min_ofdm_x1 = 105,
+ .auto_corr_min_ofdm_mrc_x1 = 220,
+
+ .auto_corr_max_ofdm = 120,
+ .auto_corr_max_ofdm_mrc = 210,
+ /* max = min for performance bug in 5150 DSP */
+ .auto_corr_max_ofdm_x1 = 105,
+ .auto_corr_max_ofdm_mrc_x1 = 220,
+
+ .auto_corr_min_cck = 125,
+ .auto_corr_max_cck = 200,
+ .auto_corr_min_cck_mrc = 170,
+ .auto_corr_max_cck_mrc = 400,
+ .nrg_th_cck = 95,
+ .nrg_th_ofdm = 95,
+};
+
static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
size_t offset)
{
@@ -826,8 +855,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
BIT(IEEE80211_BAND_5GHZ);
priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
- priv->hw_params.sens = &iwl5000_sensitivity;
-
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;
@@ -836,9 +863,11 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
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 */
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) |
@@ -847,6 +876,7 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
break;
default:
+ priv->hw_params.sens = &iwl5000_sensitivity;
priv->hw_params.calib_init_cfg =
BIT(IWL_CALIB_XTAL) |
BIT(IWL_CALIB_LO) |
@@ -1426,6 +1456,44 @@ int iwl5000_calc_rssi(struct iwl_priv *priv,
return max_rssi - agc - IWL49_RSSI_OFFSET;
}
+#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);
+
struct iwl_hcmd_ops iwl5000_hcmd = {
.rxon_assoc = iwl5000_send_rxon_assoc,
.commit_rxon = iwl_commit_rxon,
@@ -1441,6 +1509,17 @@ struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
.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 = {
.set_hw_params = iwl5000_hw_set_hw_params,
.txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
@@ -1542,12 +1621,14 @@ static struct iwl_lib_ops iwl5150_lib = {
};
struct iwl_ops iwl5000_ops = {
+ .ucode = &iwl5000_ucode,
.lib = &iwl5000_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils,
};
static struct iwl_ops iwl5150_ops = {
+ .ucode = &iwl5000_ucode,
.lib = &iwl5150_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils,
@@ -1664,8 +1745,6 @@ MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX));
module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444);
MODULE_PARM_DESC(swcrypto50,
"using software crypto engine (default 0 [hardware])\n");
-module_param_named(debug50, iwl50_mod_params.debug, uint, 0444);
-MODULE_PARM_DESC(debug50, "50XX debug output mask");
module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444);
MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series");
module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, 0444);
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index bd438d8acf55..26c5d4a60d17 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -46,8 +46,8 @@
#include "iwl-5000-hw.h"
/* Highest firmware API version supported */
-#define IWL6000_UCODE_API_MAX 2
-#define IWL6050_UCODE_API_MAX 2
+#define IWL6000_UCODE_API_MAX 3
+#define IWL6050_UCODE_API_MAX 3
/* Lowest firmware API version supported */
#define IWL6000_UCODE_API_MIN 1
@@ -69,6 +69,7 @@ static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = {
};
static struct iwl_ops iwl6000_ops = {
+ .ucode = &iwl5000_ucode,
.lib = &iwl5000_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl6000_hcmd_utils,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index ff20e5048a55..63280411fd58 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -2466,7 +2466,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl_lq_sta *lq_sta = priv_sta;
int rate_idx;
- u64 mask_bit = 0;
IWL_DEBUG_RATE_LIMIT(priv, "rate scale calculate new rate for skb\n");
@@ -2481,22 +2480,9 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
lq_sta->max_rate_idx = -1;
}
- if (sta)
- mask_bit = sta->supp_rates[sband->band];
-
/* Send management frames and NO_ACK data using lowest rate. */
- if (!ieee80211_is_data(hdr->frame_control) ||
- info->flags & IEEE80211_TX_CTL_NO_ACK || !sta || !lq_sta) {
- if (!mask_bit)
- info->control.rates[0].idx =
- rate_lowest_index(sband, NULL);
- else
- info->control.rates[0].idx =
- rate_lowest_index(sband, sta);
- if (info->flags & IEEE80211_TX_CTL_NO_ACK)
- info->control.rates[0].count = 1;
+ if (rate_control_send_low(sta, priv_sta, txrc))
return;
- }
rate_idx = lq_sta->last_txrate_idx;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 355f50ea7fef..44c7f236a7a3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -171,7 +171,7 @@ int iwl_commit_rxon(struct iwl_priv *priv)
le16_to_cpu(priv->staging_rxon.channel),
priv->staging_rxon.bssid_addr);
- iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto);
+ 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
@@ -512,70 +512,6 @@ int iwl_hw_tx_queue_init(struct iwl_priv *priv,
return 0;
}
-
-/******************************************************************************
- *
- * Misc. internal state and helper functions
- *
- ******************************************************************************/
-
-#define MAX_UCODE_BEACON_INTERVAL 4096
-
-static u16 iwl_adjust_beacon_interval(u16 beacon_val)
-{
- u16 new_val = 0;
- u16 beacon_factor = 0;
-
- beacon_factor = (beacon_val + MAX_UCODE_BEACON_INTERVAL)
- / MAX_UCODE_BEACON_INTERVAL;
- new_val = beacon_val / beacon_factor;
-
- if (!new_val)
- new_val = MAX_UCODE_BEACON_INTERVAL;
-
- return new_val;
-}
-
-static void iwl_setup_rxon_timing(struct iwl_priv *priv)
-{
- u64 tsf;
- s32 interval_tm, rem;
- unsigned long flags;
- struct ieee80211_conf *conf = NULL;
- u16 beacon_int = 0;
-
- conf = ieee80211_get_hw_conf(priv->hw);
-
- spin_lock_irqsave(&priv->lock, flags);
- priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
- priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval);
-
- if (priv->iw_mode == NL80211_IFTYPE_STATION) {
- beacon_int = iwl_adjust_beacon_interval(priv->beacon_int);
- priv->rxon_timing.atim_window = 0;
- } else {
- beacon_int = iwl_adjust_beacon_interval(
- priv->vif->bss_conf.beacon_int);
-
- /* TODO: we need to get atim_window from upper stack
- * for now we set to 0 */
- priv->rxon_timing.atim_window = 0;
- }
-
- priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int);
-
- tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
- interval_tm = beacon_int * 1024;
- rem = do_div(tsf, interval_tm);
- priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
-
- spin_unlock_irqrestore(&priv->lock, flags);
- IWL_DEBUG_ASSOC(priv, "beacon interval %d beacon timer %d beacon tim %d\n",
- le16_to_cpu(priv->rxon_timing.beacon_interval),
- le32_to_cpu(priv->rxon_timing.beacon_init_val),
- le16_to_cpu(priv->rxon_timing.atim_window));
-}
-
/******************************************************************************
*
* Generic RX handler implementations
@@ -597,12 +533,16 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv,
if (palive->ver_subtype == INITIALIZE_SUBTYPE) {
IWL_DEBUG_INFO(priv, "Initialization Alive received.\n");
+ set_bit(STATUS_INIT_UCODE_ALIVE, &priv->status);
+ wake_up_interruptible(&priv->wait_command_queue);
memcpy(&priv->card_alive_init,
&pkt->u.alive_frame,
sizeof(struct iwl_init_alive_resp));
pwork = &priv->init_alive_start;
} else {
IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
+ set_bit(STATUS_RT_UCODE_ALIVE, &priv->status);
+ wake_up_interruptible(&priv->wait_command_queue);
memcpy(&priv->card_alive, &pkt->u.alive_frame,
sizeof(struct iwl_alive_resp));
pwork = &priv->alive_start;
@@ -964,7 +904,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & IWL_DL_ISR) {
+ if (iwl_debug_level & IWL_DL_ISR) {
/* just for debug */
inta_mask = iwl_read32(priv, CSR_INT_MASK);
IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
@@ -983,7 +923,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
/* Now service all interrupt bits discovered above. */
if (inta & CSR_INT_BIT_HW_ERR) {
- IWL_ERR(priv, "Microcode HW error detected. Restarting.\n");
+ IWL_ERR(priv, "Hardware error detected. Restarting.\n");
/* Tell the device to stop sending interrupts */
iwl_disable_interrupts(priv);
@@ -999,7 +939,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
}
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & (IWL_DL_ISR)) {
+ if (iwl_debug_level & (IWL_DL_ISR)) {
/* NIC fires this, but we don't use it, redundant with WAKEUP */
if (inta & CSR_INT_BIT_SCD) {
IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
@@ -1024,7 +964,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
hw_rf_kill = 1;
- IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n",
+ IWL_WARN(priv, "RF_KILL bit toggled to %s.\n",
hw_rf_kill ? "disable radio" : "enable radio");
priv->isr_stats.rfkill++;
@@ -1113,7 +1053,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
iwl_enable_interrupts(priv);
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & (IWL_DL_ISR)) {
+ if (iwl_debug_level & (IWL_DL_ISR)) {
inta = iwl_read32(priv, CSR_INT);
inta_mask = iwl_read32(priv, CSR_INT_MASK);
inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
@@ -1144,7 +1084,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
inta = priv->inta;
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & IWL_DL_ISR) {
+ if (iwl_debug_level & IWL_DL_ISR) {
/* just for debug */
inta_mask = iwl_read32(priv, CSR_INT_MASK);
IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x\n ",
@@ -1156,7 +1096,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
/* Now service all interrupt bits discovered above. */
if (inta & CSR_INT_BIT_HW_ERR) {
- IWL_ERR(priv, "Microcode HW error detected. Restarting.\n");
+ IWL_ERR(priv, "Hardware error detected. Restarting.\n");
/* Tell the device to stop sending interrupts */
iwl_disable_interrupts(priv);
@@ -1172,7 +1112,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
}
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & (IWL_DL_ISR)) {
+ if (iwl_debug_level & (IWL_DL_ISR)) {
/* NIC fires this, but we don't use it, redundant with WAKEUP */
if (inta & CSR_INT_BIT_SCD) {
IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
@@ -1197,7 +1137,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
hw_rf_kill = 1;
- IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n",
+ IWL_WARN(priv, "RF_KILL bit toggled to %s.\n",
hw_rf_kill ? "disable radio" : "enable radio");
priv->isr_stats.rfkill++;
@@ -1348,7 +1288,7 @@ static void iwl_nic_start(struct iwl_priv *priv)
*/
static int iwl_read_ucode(struct iwl_priv *priv)
{
- struct iwl_ucode *ucode;
+ struct iwl_ucode_header *ucode;
int ret = -EINVAL, index;
const struct firmware *ucode_raw;
const char *name_pre = priv->cfg->fw_name_pre;
@@ -1357,7 +1297,8 @@ static int iwl_read_ucode(struct iwl_priv *priv)
char buf[25];
u8 *src;
size_t len;
- u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size;
+ u32 api_ver, build;
+ u32 inst_size, data_size, init_size, init_data_size, boot_size;
/* Ask kernel firmware_class module to get the boot firmware off disk.
* request_firmware() is synchronous, file is in memory on return. */
@@ -1387,23 +1328,26 @@ static int iwl_read_ucode(struct iwl_priv *priv)
if (ret < 0)
goto error;
- /* Make sure that we got at least our header! */
- if (ucode_raw->size < sizeof(*ucode)) {
+ /* Make sure that we got at least the v1 header! */
+ if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) {
IWL_ERR(priv, "File size way too small!\n");
ret = -EINVAL;
goto err_release;
}
/* Data from ucode file: header followed by uCode images */
- ucode = (void *)ucode_raw->data;
+ ucode = (struct iwl_ucode_header *)ucode_raw->data;
priv->ucode_ver = le32_to_cpu(ucode->ver);
api_ver = IWL_UCODE_API(priv->ucode_ver);
- inst_size = le32_to_cpu(ucode->inst_size);
- data_size = le32_to_cpu(ucode->data_size);
- init_size = le32_to_cpu(ucode->init_size);
- init_data_size = le32_to_cpu(ucode->init_data_size);
- boot_size = le32_to_cpu(ucode->boot_size);
+ 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
@@ -1429,6 +1373,9 @@ static int iwl_read_ucode(struct iwl_priv *priv)
IWL_UCODE_API(priv->ucode_ver),
IWL_UCODE_SERIAL(priv->ucode_ver));
+ if (build)
+ IWL_DEBUG_INFO(priv, "Build %u\n", build);
+
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",
@@ -1443,12 +1390,14 @@ static int iwl_read_ucode(struct iwl_priv *priv)
boot_size);
/* Verify size of file vs. image size info in file's header */
- if (ucode_raw->size < sizeof(*ucode) +
+ 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 too small\n",
- (int)ucode_raw->size);
+ IWL_DEBUG_INFO(priv,
+ "uCode file size %d does not match expected size\n",
+ (int)ucode_raw->size);
ret = -EINVAL;
goto err_release;
}
@@ -1528,42 +1477,42 @@ static int iwl_read_ucode(struct iwl_priv *priv)
/* Copy images into buffers for card's bus-master reads ... */
/* Runtime instructions (first block of data in file) */
- src = &ucode->data[0];
- len = priv->ucode_code.len;
+ 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, "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() */
- src = &ucode->data[inst_size];
- len = priv->ucode_data.len;
+ 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) {
- src = &ucode->data[inst_size + data_size];
- len = priv->ucode_init.len;
+ len = 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;
}
/* Initialization data (4th block) */
if (init_data_size) {
- src = &ucode->data[inst_size + data_size + init_size];
- len = priv->ucode_init_data.len;
+ len = 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;
}
/* Bootstrap instructions (5th block) */
- src = &ucode->data[inst_size + data_size + init_size + init_data_size];
- len = priv->ucode_boot.len;
+ 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);
@@ -1812,6 +1761,11 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv)
IWL_DEBUG_INFO(priv, "iwl_prepare_card_hw enter \n");
+ ret = iwl_set_hw_ready(priv);
+ if (priv->hw_ready)
+ return ret;
+
+ /* If HW is not ready, prepare the conditions to check again */
iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_PREPARE);
@@ -1819,6 +1773,7 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv)
~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE,
CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000);
+ /* HW should be ready by now, check again. */
if (ret != -ETIMEDOUT)
iwl_set_hw_ready(priv);
@@ -1831,6 +1786,7 @@ static int __iwl_up(struct iwl_priv *priv)
{
int i;
int ret;
+ unsigned long status;
if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
@@ -1908,6 +1864,51 @@ static int __iwl_up(struct iwl_priv *priv)
/* start card; "initialize" will load runtime ucode */
iwl_nic_start(priv);
+ /* Just finish download Init or Runtime uCode image to device
+ * now we wait here for uCode send REPLY_ALIVE notification
+ * to indicate uCode is ready.
+ * 1) For Init uCode image, all iwlagn devices should wait here
+ * on STATUS_INIT_UCODE_ALIVE status bit; if timeout before
+ * receive the REPLY_ALIVE notification, go back and try to
+ * download the Init uCode image again.
+ * 2) For Runtime uCode image, all iwlagn devices except 4965
+ * wait here on STATUS_RT_UCODE_ALIVE status bit; if
+ * timeout before receive the REPLY_ALIVE notification, go back
+ * and download the Runtime uCode image again.
+ * 3) For 4965 Runtime uCode, it will not go through this path,
+ * need to wait for STATUS_RT_UCODE_ALIVE status bit in
+ * iwl4965_init_alive_start() function; if timeout, need to
+ * restart and download Init uCode image.
+ */
+ if (priv->ucode_type == UCODE_INIT)
+ status = STATUS_INIT_UCODE_ALIVE;
+ else
+ status = STATUS_RT_UCODE_ALIVE;
+ if (test_bit(status, &priv->status)) {
+ IWL_WARN(priv,
+ "%s uCode already alive? "
+ "Waiting for alive anyway\n",
+ (status == STATUS_INIT_UCODE_ALIVE)
+ ? "INIT" : "Runtime");
+ clear_bit(status, &priv->status);
+ }
+ ret = wait_event_interruptible_timeout(
+ priv->wait_command_queue,
+ test_bit(status, &priv->status),
+ UCODE_ALIVE_TIMEOUT);
+ if (!ret) {
+ if (!test_bit(status, &priv->status)) {
+ priv->ucode_type =
+ (status == STATUS_INIT_UCODE_ALIVE)
+ ? UCODE_NONE : UCODE_INIT;
+ IWL_ERR(priv,
+ "%s timeout after %dms\n",
+ (status == STATUS_INIT_UCODE_ALIVE)
+ ? "INIT" : "Runtime",
+ jiffies_to_msecs(UCODE_ALIVE_TIMEOUT));
+ continue;
+ }
+ }
IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n");
return 0;
@@ -2331,7 +2332,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
IWL_DEBUG_MAC80211(priv, "enter\n");
- if (priv->hw_params.sw_crypto) {
+ if (priv->cfg->mod_params->sw_crypto) {
IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n");
return -EOPNOTSUPP;
}
@@ -2455,14 +2456,16 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw,
* used for controlling the debug level.
*
* See the level definitions in iwl for details.
+ *
+ * FIXME This file can be deprecated as the module parameter is
+ * writable and users can thus also change the debug level
+ * using the /sys/module/iwl3945/parameters/debug file.
*/
static ssize_t show_debug_level(struct device *d,
struct device_attribute *attr, char *buf)
{
- struct iwl_priv *priv = dev_get_drvdata(d);
-
- return sprintf(buf, "0x%08X\n", priv->debug_level);
+ return sprintf(buf, "0x%08X\n", iwl_debug_level);
}
static ssize_t store_debug_level(struct device *d,
struct device_attribute *attr,
@@ -2476,7 +2479,7 @@ static ssize_t store_debug_level(struct device *d,
if (ret)
IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf);
else
- priv->debug_level = val;
+ iwl_debug_level = val;
return strnlen(buf, count);
}
@@ -2685,26 +2688,6 @@ static ssize_t show_power_level(struct device *d,
static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
store_power_level);
-static ssize_t show_qos(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
- char *p = buf;
- int q;
-
- for (q = 0; q < AC_NUM; q++) {
- p += sprintf(p, "\tcw_min\tcw_max\taifsn\ttxop\n");
- p += sprintf(p, "AC[%d]\t%u\t%u\t%u\t%u\n", q,
- priv->qos_data.def_qos_parm.ac[q].cw_min,
- priv->qos_data.def_qos_parm.ac[q].cw_max,
- priv->qos_data.def_qos_parm.ac[q].aifsn,
- priv->qos_data.def_qos_parm.ac[q].edca_txop);
- }
-
- return p - buf + 1;
-}
-
-static DEVICE_ATTR(qos, S_IRUGO, show_qos, NULL);
static ssize_t show_statistics(struct device *d,
struct device_attribute *attr, char *buf)
@@ -2805,7 +2788,6 @@ static struct attribute *iwl_sysfs_entries[] = {
&dev_attr_debug_level.attr,
#endif
&dev_attr_version.attr,
- &dev_attr_qos.attr,
NULL
};
@@ -2849,7 +2831,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Disabling hardware scan means that mac80211 will perform scans
* "the hard way", rather than using device's scan. */
if (cfg->mod_params->disable_hw_scan) {
- if (cfg->mod_params->debug & IWL_DL_INFO)
+ if (iwl_debug_level & IWL_DL_INFO)
dev_printk(KERN_DEBUG, &(pdev->dev),
"Disabling hw_scan\n");
iwl_hw_ops.hw_scan = NULL;
@@ -2871,7 +2853,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
priv->inta_mask = CSR_INI_SET_MASK;
#ifdef CONFIG_IWLWIFI_DEBUG
- priv->debug_level = priv->cfg->mod_params->debug;
atomic_set(&priv->restrict_refcnt, 0);
#endif
@@ -3231,3 +3212,11 @@ static void __exit iwl_exit(void)
module_exit(iwl_exit);
module_init(iwl_init);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+module_param_named(debug50, iwl_debug_level, uint, 0444);
+MODULE_PARM_DESC(debug50, "50XX debug output mask (deprecated)");
+module_param_named(debug, iwl_debug_level, uint, 0644);
+MODULE_PARM_DESC(debug, "debug output mask");
+#endif
+
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c
index a5d63672ad39..f8bf592e939c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.c
@@ -251,12 +251,7 @@ static int iwl_sens_energy_cck(struct iwl_priv *priv,
/* increase energy threshold (reduce nrg value)
* to decrease sensitivity */
- if (data->nrg_th_cck >
- (ranges->max_nrg_cck + NRG_STEP_CCK))
- data->nrg_th_cck = data->nrg_th_cck
- - NRG_STEP_CCK;
- else
- data->nrg_th_cck = ranges->max_nrg_cck;
+ data->nrg_th_cck = data->nrg_th_cck - NRG_STEP_CCK;
/* Else if we got fewer than desired, increase sensitivity */
} else if (false_alarms < min_false_alarms) {
data->nrg_curr_state = IWL_FA_TOO_FEW;
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index c87033bf3ad2..ebb2fbce5365 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -765,6 +765,8 @@ struct iwl5000_rxon_assoc_cmd {
} __attribute__ ((packed));
#define IWL_CONN_MAX_LISTEN_INTERVAL 10
+#define IWL_MAX_UCODE_BEACON_INTERVAL 4 /* 4096 */
+#define IWL39_MAX_UCODE_BEACON_INTERVAL 1 /* 1024 */
/*
* REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
@@ -1922,7 +1924,7 @@ struct iwl_link_qual_general_params {
#define LINK_QUAL_AGG_DISABLE_START_MIN (0)
#define LINK_QUAL_AGG_FRAME_LIMIT_DEF (31)
-#define LINK_QUAL_AGG_FRAME_LIMIT_MAX (64)
+#define LINK_QUAL_AGG_FRAME_LIMIT_MAX (63)
#define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0)
/**
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 6ab07165ea28..6aea02644809 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -59,6 +59,9 @@ MODULE_LICENSE("GPL");
IWL_RATE_##pp##M_INDEX, \
IWL_RATE_##np##M_INDEX }
+u32 iwl_debug_level;
+EXPORT_SYMBOL(iwl_debug_level);
+
static irqreturn_t iwl_isr(int irq, void *data);
/*
@@ -635,6 +638,63 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
}
EXPORT_SYMBOL(iwl_is_fat_tx_allowed);
+static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val)
+{
+ u16 new_val = 0;
+ u16 beacon_factor = 0;
+
+ beacon_factor = (beacon_val + max_beacon_val) / max_beacon_val;
+ new_val = beacon_val / beacon_factor;
+
+ if (!new_val)
+ new_val = max_beacon_val;
+
+ return new_val;
+}
+
+void iwl_setup_rxon_timing(struct iwl_priv *priv)
+{
+ u64 tsf;
+ s32 interval_tm, rem;
+ unsigned long flags;
+ struct ieee80211_conf *conf = NULL;
+ u16 beacon_int;
+
+ conf = ieee80211_get_hw_conf(priv->hw);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
+ priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval);
+
+ 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;
+
+ /* TODO: we need to get atim_window from upper stack
+ * for now we set to 0 */
+ priv->rxon_timing.atim_window = 0;
+ }
+
+ beacon_int = iwl_adjust_beacon_interval(beacon_int,
+ priv->hw_params.max_beacon_itrvl * 1024);
+ priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int);
+
+ tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
+ interval_tm = beacon_int * 1024;
+ rem = do_div(tsf, interval_tm);
+ priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ IWL_DEBUG_ASSOC(priv,
+ "beacon interval %d beacon timer %d beacon tim %d\n",
+ le16_to_cpu(priv->rxon_timing.beacon_interval),
+ le32_to_cpu(priv->rxon_timing.beacon_init_val),
+ le16_to_cpu(priv->rxon_timing.atim_window));
+}
+EXPORT_SYMBOL(iwl_setup_rxon_timing);
+
void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
{
struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
@@ -1218,7 +1278,7 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv)
struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
IWL_DEBUG_RADIO(priv, "RX CONFIG:\n");
- iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
+ iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n",
@@ -1233,6 +1293,209 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv)
}
#endif
+static const char *desc_lookup_text[] = {
+ "OK",
+ "FAIL",
+ "BAD_PARAM",
+ "BAD_CHECKSUM",
+ "NMI_INTERRUPT_WDG",
+ "SYSASSERT",
+ "FATAL_ERROR",
+ "BAD_COMMAND",
+ "HW_ERROR_TUNE_LOCK",
+ "HW_ERROR_TEMPERATURE",
+ "ILLEGAL_CHAN_FREQ",
+ "VCC_NOT_STABLE",
+ "FH_ERROR",
+ "NMI_INTERRUPT_HOST",
+ "NMI_INTERRUPT_ACTION_PT",
+ "NMI_INTERRUPT_UNKNOWN",
+ "UCODE_VERSION_MISMATCH",
+ "HW_ERROR_ABS_LOCK",
+ "HW_ERROR_CAL_LOCK_FAIL",
+ "NMI_INTERRUPT_INST_ACTION_PT",
+ "NMI_INTERRUPT_DATA_ACTION_PT",
+ "NMI_TRM_HW_ER",
+ "NMI_INTERRUPT_TRM",
+ "NMI_INTERRUPT_BREAK_POINT"
+ "DEBUG_0",
+ "DEBUG_1",
+ "DEBUG_2",
+ "DEBUG_3",
+ "UNKNOWN"
+};
+
+static const char *desc_lookup(int i)
+{
+ int max = ARRAY_SIZE(desc_lookup_text) - 1;
+
+ if (i < 0 || i > max)
+ i = max;
+
+ return desc_lookup_text[i];
+}
+
+#define ERROR_START_OFFSET (1 * sizeof(u32))
+#define ERROR_ELEM_SIZE (7 * sizeof(u32))
+
+static void iwl_dump_nic_error_log(struct iwl_priv *priv)
+{
+ u32 data2, line;
+ u32 desc, time, count, base, data1;
+ u32 blink1, blink2, ilink1, ilink2;
+
+ switch (priv->ucode_type) {
+ case UCODE_RT:
+ base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
+ break;
+ case UCODE_INIT:
+ base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
+ break;
+ default:
+ IWL_ERR(priv, "uCode image not available\n");
+ return;
+ }
+
+ if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
+ IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base);
+ return;
+ }
+
+ count = iwl_read_targ_mem(priv, base);
+
+ if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
+ IWL_ERR(priv, "Start IWL Error Log Dump:\n");
+ IWL_ERR(priv, "Status: 0x%08lX, count: %d\n",
+ priv->status, count);
+ }
+
+ desc = iwl_read_targ_mem(priv, base + 1 * 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));
+ ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32));
+ data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32));
+ 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));
+
+ IWL_ERR(priv, "Desc Time "
+ "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);
+
+}
+
+#define EVENT_START_OFFSET (4 * sizeof(u32))
+
+/**
+ * iwl_print_event_log - Dump error event log to syslog
+ *
+ */
+static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+ u32 num_events, u32 mode)
+{
+ u32 i;
+ u32 base; /* SRAM byte address of event log header */
+ u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
+ u32 ptr; /* SRAM byte address of log data */
+ u32 ev, time, data; /* event log data */
+
+ if (num_events == 0)
+ return;
+ switch (priv->ucode_type) {
+ case UCODE_RT:
+ base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+ break;
+ case UCODE_INIT:
+ base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
+ break;
+ default:
+ IWL_ERR(priv, "uCode image not available\n");
+ return;
+ }
+
+ if (mode == 0)
+ event_size = 2 * sizeof(u32);
+ else
+ event_size = 3 * sizeof(u32);
+
+ ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
+
+ /* "time" is actually "data" for mode 0 (no timestamp).
+ * place event id # at far right for easier visual parsing. */
+ for (i = 0; i < num_events; i++) {
+ ev = iwl_read_targ_mem(priv, ptr);
+ ptr += sizeof(u32);
+ time = iwl_read_targ_mem(priv, ptr);
+ ptr += sizeof(u32);
+ if (mode == 0) {
+ /* data, ev */
+ IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev);
+ } else {
+ data = iwl_read_targ_mem(priv, ptr);
+ ptr += sizeof(u32);
+ IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
+ time, data, ev);
+ }
+ }
+}
+
+void iwl_dump_nic_event_log(struct iwl_priv *priv)
+{
+ u32 base; /* SRAM byte address of event log header */
+ u32 capacity; /* event log capacity in # entries */
+ u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
+ u32 num_wraps; /* # times uCode wrapped to top of log */
+ u32 next_entry; /* index of next entry to be written by uCode */
+ u32 size; /* # entries that we'll print */
+
+ switch (priv->ucode_type) {
+ case UCODE_RT:
+ base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+ break;
+ case UCODE_INIT:
+ base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
+ break;
+ default:
+ IWL_ERR(priv, "uCode image not available\n");
+ return;
+ }
+
+ if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
+ IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base);
+ return;
+ }
+
+ /* event log header */
+ capacity = iwl_read_targ_mem(priv, base);
+ mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
+ num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
+ next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
+
+ size = num_wraps ? capacity : next_entry;
+
+ /* bail out if nothing in log */
+ if (size == 0) {
+ IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
+ return;
+ }
+
+ IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n",
+ size, num_wraps);
+
+ /* if uCode has wrapped back to top of log, start at the oldest entry,
+ * i.e the next one that uCode would fill. */
+ if (num_wraps)
+ iwl_print_event_log(priv, next_entry,
+ capacity - next_entry, mode);
+ /* (then/else) start at top of log */
+ iwl_print_event_log(priv, 0, next_entry, mode);
+
+}
/**
* iwl_irq_handle_error - called for HW or SW error interrupt from card
*/
@@ -1245,7 +1508,7 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & IWL_DL_FW_ERRORS) {
+ if (iwl_debug_level & IWL_DL_FW_ERRORS) {
iwl_dump_nic_error_log(priv);
iwl_dump_nic_event_log(priv);
iwl_print_rx_config_cmd(priv);
@@ -1325,7 +1588,8 @@ int iwl_setup_mac(struct iwl_priv *priv)
hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM |
IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_SPECTRUM_MGMT;
+ IEEE80211_HW_SPECTRUM_MGMT |
+ IEEE80211_HW_SUPPORTS_PS;
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
@@ -1361,7 +1625,6 @@ EXPORT_SYMBOL(iwl_setup_mac);
int iwl_set_hw_params(struct iwl_priv *priv)
{
- priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto;
priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
if (priv->cfg->mod_params->amsdu_size_8K)
@@ -1370,6 +1633,8 @@ int iwl_set_hw_params(struct iwl_priv *priv)
priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K;
priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256;
+ priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL;
+
if (priv->cfg->mod_params->disable_11n)
priv->cfg->sku &= ~IWL_SKU_N;
@@ -1484,31 +1749,6 @@ void iwl_uninit_drv(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_uninit_drv);
-
-void iwl_disable_interrupts(struct iwl_priv *priv)
-{
- clear_bit(STATUS_INT_ENABLED, &priv->status);
-
- /* disable interrupts from uCode/NIC to host */
- iwl_write32(priv, CSR_INT_MASK, 0x00000000);
-
- /* acknowledge/clear/reset any interrupts still pending
- * from uCode or flow handler (Rx/Tx DMA) */
- iwl_write32(priv, CSR_INT, 0xffffffff);
- iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
- IWL_DEBUG_ISR(priv, "Disabled interrupts\n");
-}
-EXPORT_SYMBOL(iwl_disable_interrupts);
-
-void iwl_enable_interrupts(struct iwl_priv *priv)
-{
- IWL_DEBUG_ISR(priv, "Enabling interrupts\n");
- set_bit(STATUS_INT_ENABLED, &priv->status);
- iwl_write32(priv, CSR_INT_MASK, priv->inta_mask);
-}
-EXPORT_SYMBOL(iwl_enable_interrupts);
-
-
#define ICT_COUNT (PAGE_SIZE/sizeof(u32))
/* Free dram table */
@@ -1742,7 +1982,7 @@ static irqreturn_t iwl_isr(int irq, void *data)
}
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & (IWL_DL_ISR)) {
+ if (iwl_debug_level & (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);
@@ -1981,191 +2221,6 @@ int iwl_verify_ucode(struct iwl_priv *priv)
EXPORT_SYMBOL(iwl_verify_ucode);
-static const char *desc_lookup_text[] = {
- "OK",
- "FAIL",
- "BAD_PARAM",
- "BAD_CHECKSUM",
- "NMI_INTERRUPT_WDG",
- "SYSASSERT",
- "FATAL_ERROR",
- "BAD_COMMAND",
- "HW_ERROR_TUNE_LOCK",
- "HW_ERROR_TEMPERATURE",
- "ILLEGAL_CHAN_FREQ",
- "VCC_NOT_STABLE",
- "FH_ERROR",
- "NMI_INTERRUPT_HOST",
- "NMI_INTERRUPT_ACTION_PT",
- "NMI_INTERRUPT_UNKNOWN",
- "UCODE_VERSION_MISMATCH",
- "HW_ERROR_ABS_LOCK",
- "HW_ERROR_CAL_LOCK_FAIL",
- "NMI_INTERRUPT_INST_ACTION_PT",
- "NMI_INTERRUPT_DATA_ACTION_PT",
- "NMI_TRM_HW_ER",
- "NMI_INTERRUPT_TRM",
- "NMI_INTERRUPT_BREAK_POINT"
- "DEBUG_0",
- "DEBUG_1",
- "DEBUG_2",
- "DEBUG_3",
- "UNKNOWN"
-};
-
-static const char *desc_lookup(int i)
-{
- int max = ARRAY_SIZE(desc_lookup_text) - 1;
-
- if (i < 0 || i > max)
- i = max;
-
- return desc_lookup_text[i];
-}
-
-#define ERROR_START_OFFSET (1 * sizeof(u32))
-#define ERROR_ELEM_SIZE (7 * sizeof(u32))
-
-void iwl_dump_nic_error_log(struct iwl_priv *priv)
-{
- u32 data2, line;
- u32 desc, time, count, base, data1;
- u32 blink1, blink2, ilink1, ilink2;
-
- if (priv->ucode_type == UCODE_INIT)
- base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
- else
- base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
-
- if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
- IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base);
- return;
- }
-
- count = iwl_read_targ_mem(priv, base);
-
- if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
- IWL_ERR(priv, "Start IWL Error Log Dump:\n");
- IWL_ERR(priv, "Status: 0x%08lX, count: %d\n",
- priv->status, count);
- }
-
- desc = iwl_read_targ_mem(priv, base + 1 * 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));
- ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32));
- data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32));
- 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));
-
- IWL_ERR(priv, "Desc Time "
- "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);
-
-}
-EXPORT_SYMBOL(iwl_dump_nic_error_log);
-
-#define EVENT_START_OFFSET (4 * sizeof(u32))
-
-/**
- * iwl_print_event_log - Dump error event log to syslog
- *
- */
-static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
- u32 num_events, u32 mode)
-{
- u32 i;
- u32 base; /* SRAM byte address of event log header */
- u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
- u32 ptr; /* SRAM byte address of log data */
- u32 ev, time, data; /* event log data */
-
- if (num_events == 0)
- return;
- if (priv->ucode_type == UCODE_INIT)
- base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
- else
- base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
-
- if (mode == 0)
- event_size = 2 * sizeof(u32);
- else
- event_size = 3 * sizeof(u32);
-
- ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
-
- /* "time" is actually "data" for mode 0 (no timestamp).
- * place event id # at far right for easier visual parsing. */
- for (i = 0; i < num_events; i++) {
- ev = iwl_read_targ_mem(priv, ptr);
- ptr += sizeof(u32);
- time = iwl_read_targ_mem(priv, ptr);
- ptr += sizeof(u32);
- if (mode == 0) {
- /* data, ev */
- IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev);
- } else {
- data = iwl_read_targ_mem(priv, ptr);
- ptr += sizeof(u32);
- IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
- time, data, ev);
- }
- }
-}
-
-void iwl_dump_nic_event_log(struct iwl_priv *priv)
-{
- u32 base; /* SRAM byte address of event log header */
- u32 capacity; /* event log capacity in # entries */
- u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
- u32 num_wraps; /* # times uCode wrapped to top of log */
- u32 next_entry; /* index of next entry to be written by uCode */
- u32 size; /* # entries that we'll print */
-
- if (priv->ucode_type == UCODE_INIT)
- base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
- else
- base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
-
- if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
- IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base);
- return;
- }
-
- /* event log header */
- capacity = iwl_read_targ_mem(priv, base);
- mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
- num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
- next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
-
- size = num_wraps ? capacity : next_entry;
-
- /* bail out if nothing in log */
- if (size == 0) {
- IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
- return;
- }
-
- IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n",
- size, num_wraps);
-
- /* if uCode has wrapped back to top of log, start at the oldest entry,
- * i.e the next one that uCode would fill. */
- if (num_wraps)
- iwl_print_event_log(priv, next_entry,
- capacity - next_entry, mode);
- /* (then/else) start at top of log */
- iwl_print_event_log(priv, 0, next_entry, mode);
-
-}
-EXPORT_SYMBOL(iwl_dump_nic_event_log);
-
void iwl_rf_kill_ct_config(struct iwl_priv *priv)
{
struct iwl_ct_kill_config cmd;
@@ -2234,7 +2289,7 @@ void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
"notification for %s:\n",
le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
- iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
+ iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
}
EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif);
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index dabf663e36e5..614ec7cc5b31 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -116,6 +116,17 @@ struct iwl_temp_ops {
void (*set_ct_kill)(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);
@@ -171,6 +182,7 @@ struct iwl_lib_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;
@@ -178,7 +190,6 @@ struct iwl_ops {
struct iwl_mod_params {
int sw_crypto; /* def: 0 = using hardware encryption */
- u32 debug; /* def: 0 = minimal debug log messages */
int disable_hw_scan; /* def: 0 = use h/w scan */
int num_of_queues; /* def: HW dependent */
int num_of_ampdu_queues;/* def: HW dependent */
@@ -384,7 +395,6 @@ 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_scan_initiate(struct iwl_priv *priv);
int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req);
u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
const u8 *ie, int ie_len, int left);
@@ -398,7 +408,6 @@ void iwl_bg_scan_check(struct work_struct *data);
void iwl_bg_abort_scan(struct work_struct *work);
void iwl_bg_scan_completed(struct work_struct *work);
void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
-int iwl_send_scan_abort(struct iwl_priv *priv);
/* For faster active scanning, scan will move to the next channel if fewer than
* PLCP_QUIET_THRESH packets are heard on this channel within
@@ -449,8 +458,6 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags,
/*****************************************************
* PCI *
*****************************************************/
-void iwl_disable_interrupts(struct iwl_priv *priv);
-void iwl_enable_interrupts(struct iwl_priv *priv);
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);
@@ -474,7 +481,6 @@ int iwl_pci_resume(struct pci_dev *pdev);
/*****************************************************
* Error Handling Debugging
******************************************************/
-void iwl_dump_nic_error_log(struct iwl_priv *priv);
void iwl_dump_nic_event_log(struct iwl_priv *priv);
void iwl_clear_isr_stats(struct iwl_priv *priv);
@@ -503,6 +509,8 @@ void iwlcore_free_geos(struct iwl_priv *priv);
#define STATUS_POWER_PMI 16
#define STATUS_FW_ERROR 17
#define STATUS_MODE_PENDING 18
+#define STATUS_INIT_UCODE_ALIVE 19
+#define STATUS_RT_UCODE_ALIVE 20
static inline int iwl_is_ready(struct iwl_priv *priv)
@@ -556,6 +564,7 @@ extern void iwl_rx_reply_rx_phy(struct iwl_priv *priv,
void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
+void iwl_setup_rxon_timing(struct iwl_priv *priv);
static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
{
return priv->cfg->ops->hcmd->rxon_assoc(priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index 2cf014f523be..9faf0c2ff608 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -30,16 +30,23 @@
#define __iwl_debug_h__
struct iwl_priv;
+extern u32 iwl_debug_level;
#define IWL_ERR(p, f, a...) dev_err(&((p)->pci_dev->dev), f, ## a)
#define IWL_WARN(p, f, a...) dev_warn(&((p)->pci_dev->dev), f, ## a)
#define IWL_INFO(p, f, a...) dev_info(&((p)->pci_dev->dev), f, ## a)
#define IWL_CRIT(p, f, a...) dev_crit(&((p)->pci_dev->dev), f, ## a)
+#define iwl_print_hex_error(priv, p, len) \
+do { \
+ print_hex_dump(KERN_ERR, "iwl data: ", \
+ DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \
+} while (0)
+
#ifdef CONFIG_IWLWIFI_DEBUG
#define IWL_DEBUG(__priv, level, fmt, args...) \
do { \
- if (__priv->debug_level & (level)) \
+ if (iwl_debug_level & (level)) \
dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \
"%c %s " fmt, in_interrupt() ? 'I' : 'U', \
__func__ , ## args); \
@@ -47,15 +54,15 @@ do { \
#define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) \
do { \
- if ((__priv->debug_level & (level)) && net_ratelimit()) \
+ if ((iwl_debug_level & (level)) && net_ratelimit()) \
dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \
"%c %s " fmt, in_interrupt() ? 'I' : 'U', \
__func__ , ## args); \
} while (0)
-#define iwl_print_hex_dump(priv, level, p, len) \
+#define iwl_print_hex_dump(level, p, len) \
do { \
- if (priv->debug_level & level) \
+ if (iwl_debug_level & level) \
print_hex_dump(KERN_DEBUG, "iwl data: ", \
DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \
} while (0)
@@ -76,6 +83,10 @@ struct iwl_debugfs {
struct dentry *file_channels;
struct dentry *file_status;
struct dentry *file_interrupt;
+ struct dentry *file_qos;
+#ifdef CONFIG_IWLWIFI_LEDS
+ struct dentry *file_led;
+#endif
} dbgfs_data_files;
struct dir_rf_files {
struct dentry *file_disable_sensitivity;
@@ -93,8 +104,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv);
#else
#define IWL_DEBUG(__priv, level, fmt, args...)
#define IWL_DEBUG_LIMIT(__priv, level, fmt, args...)
-static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level,
- void *p, u32 len)
+static inline void iwl_print_hex_dump(int level, void *p, u32 len)
{}
#endif /* CONFIG_IWLWIFI_DEBUG */
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 11e08c068917..0ab3463aa07e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -49,7 +49,8 @@
#define DEBUGFS_ADD_FILE(name, parent) do { \
dbgfs->dbgfs_##parent##_files.file_##name = \
- debugfs_create_file(#name, 0644, dbgfs->dir_##parent, priv, \
+ debugfs_create_file(#name, S_IWUSR | S_IRUSR, \
+ dbgfs->dir_##parent, priv, \
&iwl_dbgfs_##name##_ops); \
if (!(dbgfs->dbgfs_##parent##_files.file_##name)) \
goto err; \
@@ -57,7 +58,8 @@
#define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \
dbgfs->dbgfs_##parent##_files.file_##name = \
- debugfs_create_bool(#name, 0644, dbgfs->dir_##parent, ptr); \
+ debugfs_create_bool(#name, S_IWUSR | S_IRUSR, \
+ dbgfs->dir_##parent, ptr); \
if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \
|| !dbgfs->dbgfs_##parent##_files.file_##name) \
goto err; \
@@ -65,7 +67,7 @@
#define DEBUGFS_ADD_X32(name, parent, ptr) do { \
dbgfs->dbgfs_##parent##_files.file_##name = \
- debugfs_create_x32(#name, 0444, dbgfs->dir_##parent, ptr); \
+ debugfs_create_x32(#name, S_IRUSR, dbgfs->dir_##parent, ptr); \
if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \
|| !dbgfs->dbgfs_##parent##_files.file_##name) \
goto err; \
@@ -566,6 +568,55 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
return count;
}
+static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ 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,
+ "\tcw_min\tcw_max\taifsn\ttxop\n");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "AC[%d]\t%u\t%u\t%u\t%u\n", i,
+ priv->qos_data.def_qos_parm.ac[i].cw_min,
+ priv->qos_data.def_qos_parm.ac[i].cw_max,
+ priv->qos_data.def_qos_parm.ac[i].aifsn,
+ priv->qos_data.def_qos_parm.ac[i].edca_txop);
+ }
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ return ret;
+}
+
+#ifdef CONFIG_IWLWIFI_LEDS
+static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ 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",
+ (priv->allow_blinking) ? "True" : "False");
+ if (priv->allow_blinking) {
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "Led blinking rate: %u\n",
+ priv->last_blink_rate);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "Last blink time: %lu\n",
+ priv->last_blink_time);
+ }
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ return ret;
+}
+#endif
DEBUGFS_READ_WRITE_FILE_OPS(sram);
DEBUGFS_WRITE_FILE_OPS(log_event);
@@ -576,6 +627,10 @@ DEBUGFS_READ_FILE_OPS(tx_statistics);
DEBUGFS_READ_FILE_OPS(channels);
DEBUGFS_READ_FILE_OPS(status);
DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
+DEBUGFS_READ_FILE_OPS(qos);
+#ifdef CONFIG_IWLWIFI_LEDS
+DEBUGFS_READ_FILE_OPS(led);
+#endif
/*
* Create the debugfs files and directories
@@ -612,10 +667,17 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(channels, data);
DEBUGFS_ADD_FILE(status, data);
DEBUGFS_ADD_FILE(interrupt, data);
+ DEBUGFS_ADD_FILE(qos, data);
+#ifdef CONFIG_IWLWIFI_LEDS
+ DEBUGFS_ADD_FILE(led, data);
+#endif
DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
&priv->disable_chain_noise_cal);
- DEBUGFS_ADD_BOOL(disable_tx_power, rf, &priv->disable_tx_power_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_BOOL(disable_tx_power, rf,
+ &priv->disable_tx_power_cal);
return 0;
err:
@@ -643,10 +705,16 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_interrupt);
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_qos);
+#ifdef CONFIG_IWLWIFI_LEDS
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led);
+#endif
DEBUGFS_REMOVE(priv->dbgfs->dir_data);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_tx_power);
+ 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_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_tx_power);
DEBUGFS_REMOVE(priv->dbgfs->dir_rf);
DEBUGFS_REMOVE(priv->dbgfs->dir_drv);
kfree(priv->dbgfs);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 650e20af20fa..0751891f4ab7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -66,6 +66,7 @@ extern struct iwl_cfg iwl1000_bgn_cfg;
/* shared structures from iwl-5000.c */
extern struct iwl_mod_params iwl50_mod_params;
extern struct iwl_ops iwl5000_ops;
+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;
@@ -525,15 +526,29 @@ struct fw_desc {
};
/* uCode file layout */
-struct iwl_ucode {
- __le32 ver; /* major/minor/API/serial */
- __le32 inst_size; /* bytes of runtime instructions */
- __le32 data_size; /* bytes of runtime data */
- __le32 init_size; /* bytes of initialization instructions */
- __le32 init_data_size; /* bytes of initialization data */
- __le32 boot_size; /* bytes of bootstrap instructions */
- u8 data[0]; /* data in same order as "size" elements */
+struct iwl_ucode_header {
+ __le32 ver; /* major/minor/API/serial */
+ union {
+ struct {
+ __le32 inst_size; /* bytes of runtime code */
+ __le32 data_size; /* bytes of runtime data */
+ __le32 init_size; /* bytes of init code */
+ __le32 init_data_size; /* bytes of init data */
+ __le32 boot_size; /* bytes of bootstrap code */
+ u8 data[0]; /* in same order as sizes */
+ } v1;
+ struct {
+ __le32 build; /* build number */
+ __le32 inst_size; /* bytes of runtime code */
+ __le32 data_size; /* bytes of runtime data */
+ __le32 init_size; /* bytes of init code */
+ __le32 init_data_size; /* bytes of init data */
+ __le32 boot_size; /* bytes of bootstrap code */
+ u8 data[0]; /* in same order as sizes */
+ } v2;
+ } u;
};
+#define UCODE_HEADER_SIZE(ver) ((ver) == 1 ? 24 : 28)
struct iwl4965_ibss_seq {
u8 mac[ETH_ALEN];
@@ -610,7 +625,7 @@ struct iwl_hw_params {
u8 max_stations;
u8 bcast_sta_id;
u8 fat_channel;
- u8 sw_crypto;
+ u8 max_beacon_itrvl; /* in 1024 ms */
u32 max_inst_size;
u32 max_data_size;
u32 max_bsm_size;
@@ -757,6 +772,8 @@ struct iwl_calib_result {
size_t buf_len;
};
+#define UCODE_ALIVE_TIMEOUT (5 * HZ)
+
enum ucode_type {
UCODE_NONE = 0,
UCODE_INIT,
@@ -1094,7 +1111,6 @@ struct iwl_priv {
#ifdef CONFIG_IWLWIFI_DEBUG
/* debugging info */
- u32 debug_level;
u32 framecnt_to_us;
atomic_t restrict_refcnt;
#ifdef CONFIG_IWLWIFI_DEBUGFS
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index 7d7554a2f341..51eed7226669 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -159,6 +159,9 @@ static int iwlcore_get_nvm_type(struct iwl_priv *priv)
/* OTP only valid for CP/PP and after */
switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
+ case CSR_HW_REV_TYPE_NONE:
+ IWL_ERR(priv, "Unknown hardware type\n");
+ return -ENOENT;
case CSR_HW_REV_TYPE_3945:
case CSR_HW_REV_TYPE_4965:
case CSR_HW_REV_TYPE_5300:
@@ -266,7 +269,8 @@ int iwl_eeprom_init(struct iwl_priv *priv)
u32 otpgp;
priv->nvm_device_type = iwlcore_get_nvm_type(priv);
-
+ if (priv->nvm_device_type == -ENOENT)
+ return -ENOENT;
/* allocate eeprom */
if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
priv->cfg->eeprom_size =
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
index a1328c3c81ae..bd0b12efb5c7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-helpers.h
+++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h
@@ -145,4 +145,25 @@ static inline void iwl_stop_queue(struct iwl_priv *priv, u8 queue)
#define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue
#define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue
+static inline void iwl_disable_interrupts(struct iwl_priv *priv)
+{
+ clear_bit(STATUS_INT_ENABLED, &priv->status);
+
+ /* disable interrupts from uCode/NIC to host */
+ iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+ /* acknowledge/clear/reset any interrupts still pending
+ * from uCode or flow handler (Rx/Tx DMA) */
+ iwl_write32(priv, CSR_INT, 0xffffffff);
+ iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
+ IWL_DEBUG_ISR(priv, "Disabled interrupts\n");
+}
+
+static inline void iwl_enable_interrupts(struct iwl_priv *priv)
+{
+ IWL_DEBUG_ISR(priv, "Enabling interrupts\n");
+ set_bit(STATUS_INT_ENABLED, &priv->status);
+ iwl_write32(priv, CSR_INT_MASK, priv->inta_mask);
+}
+
#endif /* __iwl_helpers_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index 5e64252f80f6..8c8115293b3c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -54,7 +54,7 @@ static const char *led_type_str[] = {
static const struct {
- u16 tpt;
+ u16 tpt; /* Mb/s */
u8 on_time;
u8 off_time;
} blink_tbl[] =
@@ -104,7 +104,7 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
}
/* Set led pattern command */
-static int iwl4965_led_pattern(struct iwl_priv *priv, int led_id,
+static int iwl_led_pattern(struct iwl_priv *priv, int led_id,
unsigned int idx)
{
struct iwl_led_cmd led_cmd = {
@@ -121,7 +121,7 @@ static int iwl4965_led_pattern(struct iwl_priv *priv, int led_id,
}
/* Set led register off */
-static int iwl4965_led_on_reg(struct iwl_priv *priv, int led_id)
+static int iwl_led_on_reg(struct iwl_priv *priv, int led_id)
{
IWL_DEBUG_LED(priv, "led on %d\n", led_id);
iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
@@ -130,7 +130,7 @@ static int iwl4965_led_on_reg(struct iwl_priv *priv, int led_id)
#if 0
/* Set led on command */
-static int iwl4965_led_on(struct iwl_priv *priv, int led_id)
+static int iwl_led_on(struct iwl_priv *priv, int led_id)
{
struct iwl_led_cmd led_cmd = {
.id = led_id,
@@ -142,7 +142,7 @@ static int iwl4965_led_on(struct iwl_priv *priv, int led_id)
}
/* Set led off command */
-int iwl4965_led_off(struct iwl_priv *priv, int led_id)
+int iwl_led_off(struct iwl_priv *priv, int led_id)
{
struct iwl_led_cmd led_cmd = {
.id = led_id,
@@ -157,7 +157,7 @@ int iwl4965_led_off(struct iwl_priv *priv, int led_id)
/* Set led register off */
-static int iwl4965_led_off_reg(struct iwl_priv *priv, int led_id)
+static int iwl_led_off_reg(struct iwl_priv *priv, int led_id)
{
IWL_DEBUG_LED(priv, "LED Reg off\n");
iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF);
@@ -171,7 +171,7 @@ static int iwl_led_associate(struct iwl_priv *priv, int led_id)
{
IWL_DEBUG_LED(priv, "Associated\n");
priv->allow_blinking = 1;
- return iwl4965_led_on_reg(priv, led_id);
+ return iwl_led_on_reg(priv, led_id);
}
static int iwl_led_disassociate(struct iwl_priv *priv, int led_id)
{
@@ -264,13 +264,15 @@ static int iwl_leds_register_led(struct iwl_priv *priv, struct iwl_led *led,
/*
- * calculate blink rate according to last 2 sec Tx/Rx activities
+ * calculate blink rate according to last second Tx/Rx activities
*/
static int iwl_get_blink_rate(struct iwl_priv *priv)
{
int i;
- u64 current_tpt = priv->tx_stats[2].bytes;
- /* FIXME: + priv->rx_stats[2].bytes; */
+ /* count both tx and rx traffic to be able to
+ * handle traffic in either direction
+ */
+ u64 current_tpt = priv->tx_stats[2].bytes + priv->rx_stats[2].bytes;
s64 tpt = current_tpt - priv->led_tpt;
if (tpt < 0) /* wraparound */
@@ -314,7 +316,7 @@ void iwl_leds_background(struct iwl_priv *priv)
priv->last_blink_time = 0;
if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) {
priv->last_blink_rate = IWL_SOLID_BLINK_IDX;
- iwl4965_led_pattern(priv, IWL_LED_LINK,
+ iwl_led_pattern(priv, IWL_LED_LINK,
IWL_SOLID_BLINK_IDX);
}
return;
@@ -328,7 +330,7 @@ void iwl_leds_background(struct iwl_priv *priv)
/* call only if blink rate change */
if (blink_idx != priv->last_blink_rate)
- iwl4965_led_pattern(priv, IWL_LED_LINK, blink_idx);
+ iwl_led_pattern(priv, IWL_LED_LINK, blink_idx);
priv->last_blink_time = jiffies;
priv->last_blink_rate = blink_idx;
@@ -351,8 +353,8 @@ int iwl_leds_register(struct iwl_priv *priv)
sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s::radio",
wiphy_name(priv->hw->wiphy));
- priv->led[IWL_LED_TRG_RADIO].led_on = iwl4965_led_on_reg;
- priv->led[IWL_LED_TRG_RADIO].led_off = iwl4965_led_off_reg;
+ priv->led[IWL_LED_TRG_RADIO].led_on = iwl_led_on_reg;
+ priv->led[IWL_LED_TRG_RADIO].led_off = iwl_led_off_reg;
priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL;
ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RADIO],
@@ -386,7 +388,7 @@ int iwl_leds_register(struct iwl_priv *priv)
priv->led[IWL_LED_TRG_RX].led_on = iwl_led_associated;
priv->led[IWL_LED_TRG_RX].led_off = iwl_led_associated;
- priv->led[IWL_LED_TRG_RX].led_pattern = iwl4965_led_pattern;
+ priv->led[IWL_LED_TRG_RX].led_pattern = iwl_led_pattern;
if (ret)
goto exit_fail;
@@ -401,7 +403,7 @@ int iwl_leds_register(struct iwl_priv *priv)
priv->led[IWL_LED_TRG_TX].led_on = iwl_led_associated;
priv->led[IWL_LED_TRG_TX].led_off = iwl_led_associated;
- priv->led[IWL_LED_TRG_TX].led_pattern = iwl4965_led_pattern;
+ priv->led[IWL_LED_TRG_TX].led_pattern = iwl_led_pattern;
if (ret)
goto exit_fail;
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index 3b9cac3fd216..d393e8f02102 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -80,6 +80,8 @@
#define APMG_RFKILL_REG (APMG_BASE + 0x0014)
#define APMG_RTC_INT_STT_REG (APMG_BASE + 0x001c)
#define APMG_RTC_INT_MSK_REG (APMG_BASE + 0x0020)
+#define APMG_DIGITAL_SVR_REG (APMG_BASE + 0x0058)
+#define APMG_ANALOG_SVR_REG (APMG_BASE + 0x006C)
#define APMG_CLK_VAL_DMA_CLK_RQT (0x00000200)
#define APMG_CLK_VAL_BSM_CLK_RQT (0x00000800)
@@ -91,7 +93,8 @@
#define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000)
#define APMG_PS_CTRL_VAL_PWR_SRC_MAX (0x01000000) /* 3945 only */
#define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x02000000)
-
+#define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */
+#define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060)
#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800)
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 2b8d40b37a1c..5d5f2153f445 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -646,7 +646,7 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv,
u32 tsf_low;
int rssi;
- if (likely(!(priv->debug_level & IWL_DL_RX)))
+ if (likely(!(iwl_debug_level & IWL_DL_RX)))
return;
/* MAC header */
@@ -742,7 +742,7 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv,
}
}
if (print_dump)
- iwl_print_hex_dump(priv, IWL_DL_RX, header, length);
+ iwl_print_hex_dump(IWL_DL_RX, header, length);
}
#endif
@@ -927,12 +927,13 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
hdr = (struct ieee80211_hdr *)rxb->skb->data;
/* in case of HW accelerated crypto and bad decryption, drop */
- if (!priv->hw_params.sw_crypto &&
+ if (!priv->cfg->mod_params->sw_crypto &&
iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats))
return;
iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len);
- ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
+ memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats));
+ ieee80211_rx_irqsafe(priv->hw, rxb->skb);
priv->alloc_rxb_skb--;
rxb->skb = NULL;
}
@@ -1060,11 +1061,11 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
/* Set "1" to report good data frames in groups of 100 */
#ifdef CONFIG_IWLWIFI_DEBUG
- if (unlikely(priv->debug_level & IWL_DL_RX))
+ if (unlikely(iwl_debug_level & IWL_DL_RX))
iwl_dbg_report_frame(priv, rx_start, len, header, 1);
#endif
IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n",
- rx_status.signal, rx_status.noise, rx_status.signal,
+ rx_status.signal, rx_status.noise, rx_status.qual,
(unsigned long long)rx_status.mactime);
/*
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index e26875dbe859..00398d973a07 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -109,7 +109,7 @@ int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
}
EXPORT_SYMBOL(iwl_scan_cancel_timeout);
-int iwl_send_scan_abort(struct iwl_priv *priv)
+static int iwl_send_scan_abort(struct iwl_priv *priv)
{
int ret = 0;
struct iwl_rx_packet *res;
@@ -150,7 +150,6 @@ int iwl_send_scan_abort(struct iwl_priv *priv)
return ret;
}
-EXPORT_SYMBOL(iwl_send_scan_abort);
/* Service response to REPLY_SCAN_CMD (0x80) */
static void iwl_rx_reply_scan(struct iwl_priv *priv,
@@ -322,7 +321,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
u8 is_active, u8 n_probes,
struct iwl_scan_channel *scan_ch)
{
- const struct ieee80211_channel *channels = NULL;
+ struct ieee80211_channel *chan;
const struct ieee80211_supported_band *sband;
const struct iwl_channel_info *ch_info;
u16 passive_dwell = 0;
@@ -334,20 +333,19 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
if (!sband)
return 0;
- channels = sband->channels;
-
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 < sband->n_channels; i++) {
- if (channels[i].flags & IEEE80211_CHAN_DISABLED)
+ 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(channels[i].center_freq);
+ channel = ieee80211_frequency_to_channel(chan->center_freq);
scan_ch->channel = cpu_to_le16(channel);
ch_info = iwl_get_channel_info(priv, band, channel);
@@ -358,7 +356,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
}
if (!is_active || is_channel_passive(ch_info) ||
- (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN))
+ (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
else
scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
@@ -405,7 +403,7 @@ void iwl_init_scan_params(struct iwl_priv *priv)
priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx;
}
-int iwl_scan_initiate(struct iwl_priv *priv)
+static int iwl_scan_initiate(struct iwl_priv *priv)
{
if (!iwl_is_ready_rf(priv)) {
IWL_DEBUG_SCAN(priv, "Aborting scan due to not ready.\n");
@@ -423,10 +421,6 @@ int iwl_scan_initiate(struct iwl_priv *priv)
}
IWL_DEBUG_INFO(priv, "Starting scan...\n");
- if (priv->cfg->sku & IWL_SKU_G)
- priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ);
- if (priv->cfg->sku & IWL_SKU_A)
- priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ);
set_bit(STATUS_SCANNING, &priv->status);
priv->scan_start = jiffies;
priv->scan_pass_start = priv->scan_start;
@@ -435,7 +429,6 @@ int iwl_scan_initiate(struct iwl_priv *priv)
return 0;
}
-EXPORT_SYMBOL(iwl_scan_initiate);
#define IWL_DELAY_NEXT_SCAN (HZ*2)
@@ -444,7 +437,7 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
{
unsigned long flags;
struct iwl_priv *priv = hw->priv;
- int ret;
+ int ret, i;
IWL_DEBUG_MAC80211(priv, "enter\n");
@@ -478,6 +471,10 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
goto out_unlock;
}
+ priv->scan_bands = 0;
+ for (i = 0; i < req->n_channels; i++)
+ priv->scan_bands |= BIT(req->channels[i]->band);
+
priv->scan_request = req;
ret = iwl_scan_initiate(priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index 2addf735b193..cbe4e26d053f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -566,6 +566,8 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
unsigned long flags;
spin_lock_irqsave(&priv->sta_lock, flags);
+ 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",
@@ -573,6 +575,11 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
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);
+ 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);
@@ -853,6 +860,11 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
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");
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return 0;
+ }
ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
spin_unlock_irqrestore(&priv->sta_lock, flags);
return ret;
@@ -1044,11 +1056,10 @@ EXPORT_SYMBOL(iwl_rxon_add_station);
int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
{
int sta_id;
- u16 fc = le16_to_cpu(hdr->frame_control);
+ __le16 fc = hdr->frame_control;
/* If this frame is broadcast or management, use broadcast station id */
- if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
- is_multicast_ether_addr(hdr->addr1))
+ if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1))
return priv->hw_params.bcast_sta_id;
switch (priv->iw_mode) {
@@ -1082,7 +1093,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
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));
+ iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
return priv->hw_params.bcast_sta_id;
default:
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 2e89040e63be..c7100b9dcede 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -348,6 +348,10 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
txq->need_update = 0;
+ /* aggregation TX queues will get their ID when aggregation begins */
+ if (txq_id <= IWL_TX_FIFO_AC3)
+ txq->swq_id = txq_id;
+
/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
* iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
@@ -732,8 +736,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
- swq_id = skb_get_queue_mapping(skb);
- txq_id = swq_id;
+ 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;
@@ -744,15 +747,13 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
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) {
+ if (info->flags & IEEE80211_TX_CTL_AMPDU)
txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
- swq_id = iwl_virtual_agg_queue_num(swq_id, txq_id);
- }
}
txq = &priv->txq[txq_id];
+ swq_id = txq->swq_id;
q = &txq->q;
- txq->swq_id = swq_id;
if (unlikely(iwl_queue_space(q) < q->high_mark))
goto drop_unlock;
@@ -869,8 +870,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
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);
+ iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
+ iwl_print_hex_dump(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)
@@ -939,7 +940,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
!(cmd->meta.flags & CMD_SIZE_HUGE));
if (iwl_is_rfkill(priv)) {
- IWL_DEBUG_INFO(priv, "Not sending command - RF KILL");
+ IWL_DEBUG_INFO(priv, "Not sending command - RF KILL\n");
return -EIO;
}
@@ -1109,7 +1110,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
txq_id, sequence,
priv->txq[IWL_CMD_QUEUE_NUM].q.read_ptr,
priv->txq[IWL_CMD_QUEUE_NUM].q.write_ptr)) {
- iwl_print_hex_dump(priv, IWL_DL_INFO , rxb, 32);
+ iwl_print_hex_error(priv, rxb, 32);
return;
}
@@ -1189,6 +1190,7 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
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,
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 2f50ab60bfdf..2cc7e30d7743 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -89,7 +89,7 @@ MODULE_LICENSE("GPL");
/* module parameters */
struct iwl_mod_params iwl3945_mod_params = {
- .num_of_queues = IWL39_MAX_NUM_QUEUES,
+ .num_of_queues = IWL39_NUM_QUEUES, /* Not used */
.sw_crypto = 1,
.restart_fw = 1,
/* the rest are 0 by default */
@@ -361,76 +361,6 @@ static void iwl3945_unset_hw_params(struct iwl_priv *priv)
priv->shared_phys);
}
-#define MAX_UCODE_BEACON_INTERVAL 1024
-#define INTEL_CONN_LISTEN_INTERVAL cpu_to_le16(0xA)
-
-static __le16 iwl3945_adjust_beacon_interval(u16 beacon_val)
-{
- u16 new_val = 0;
- u16 beacon_factor = 0;
-
- beacon_factor =
- (beacon_val + MAX_UCODE_BEACON_INTERVAL)
- / MAX_UCODE_BEACON_INTERVAL;
- new_val = beacon_val / beacon_factor;
-
- return cpu_to_le16(new_val);
-}
-
-static void iwl3945_setup_rxon_timing(struct iwl_priv *priv)
-{
- u64 interval_tm_unit;
- u64 tsf, result;
- unsigned long flags;
- struct ieee80211_conf *conf = NULL;
- u16 beacon_int = 0;
-
- conf = ieee80211_get_hw_conf(priv->hw);
-
- spin_lock_irqsave(&priv->lock, flags);
- priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
- priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL;
-
- tsf = priv->timestamp;
-
- beacon_int = priv->beacon_int;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- if (priv->iw_mode == NL80211_IFTYPE_STATION) {
- if (beacon_int == 0) {
- priv->rxon_timing.beacon_interval = cpu_to_le16(100);
- priv->rxon_timing.beacon_init_val = cpu_to_le32(102400);
- } else {
- priv->rxon_timing.beacon_interval =
- cpu_to_le16(beacon_int);
- priv->rxon_timing.beacon_interval =
- iwl3945_adjust_beacon_interval(
- le16_to_cpu(priv->rxon_timing.beacon_interval));
- }
-
- priv->rxon_timing.atim_window = 0;
- } else {
- priv->rxon_timing.beacon_interval =
- iwl3945_adjust_beacon_interval(
- priv->vif->bss_conf.beacon_int);
- /* TODO: we need to get atim_window from upper stack
- * for now we set to 0 */
- priv->rxon_timing.atim_window = 0;
- }
-
- interval_tm_unit =
- (le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024);
- result = do_div(tsf, interval_tm_unit);
- priv->rxon_timing.beacon_init_val =
- cpu_to_le32((u32) ((u64) interval_tm_unit - result));
-
- IWL_DEBUG_ASSOC(priv,
- "beacon interval %d beacon timer %d beacon tim %d\n",
- le16_to_cpu(priv->rxon_timing.beacon_interval),
- le32_to_cpu(priv->rxon_timing.beacon_init_val),
- le16_to_cpu(priv->rxon_timing.atim_window));
-}
-
static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
struct ieee80211_tx_info *info,
struct iwl_cmd *cmd,
@@ -682,8 +612,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
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->tx_flags));
- iwl_print_hex_dump(priv, IWL_DL_TX, tx, sizeof(*tx));
- iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx->hdr,
+ iwl_print_hex_dump(IWL_DL_TX, tx, sizeof(*tx));
+ iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx->hdr,
ieee80211_hdrlen(fc));
/*
@@ -996,7 +926,7 @@ static void iwl3945_rx_card_state_notif(struct iwl_priv *priv,
u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
unsigned long status = priv->status;
- IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n",
+ IWL_WARN(priv, "Card state received: HW:%s SW:%s\n",
(flags & HW_CARD_DISABLED) ? "Kill" : "On",
(flags & SW_CARD_DISABLED) ? "Kill" : "On");
@@ -1714,7 +1644,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & IWL_DL_ISR) {
+ if (iwl_debug_level & IWL_DL_ISR) {
/* just for debug */
inta_mask = iwl_read32(priv, CSR_INT_MASK);
IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
@@ -1733,7 +1663,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
/* Now service all interrupt bits discovered above. */
if (inta & CSR_INT_BIT_HW_ERR) {
- IWL_ERR(priv, "Microcode HW error detected. Restarting.\n");
+ IWL_ERR(priv, "Hardware error detected. Restarting.\n");
/* Tell the device to stop sending interrupts */
iwl_disable_interrupts(priv);
@@ -1749,7 +1679,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
}
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & (IWL_DL_ISR)) {
+ if (iwl_debug_level & (IWL_DL_ISR)) {
/* NIC fires this, but we don't use it, redundant with WAKEUP */
if (inta & CSR_INT_BIT_SCD) {
IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
@@ -1828,7 +1758,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
iwl_enable_interrupts(priv);
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & (IWL_DL_ISR)) {
+ if (iwl_debug_level & (IWL_DL_ISR)) {
inta = iwl_read32(priv, CSR_INT);
inta_mask = iwl_read32(priv, CSR_INT_MASK);
inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
@@ -1844,7 +1774,7 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
u8 is_active, u8 n_probes,
struct iwl3945_scan_channel *scan_ch)
{
- const struct ieee80211_channel *channels = NULL;
+ struct ieee80211_channel *chan;
const struct ieee80211_supported_band *sband;
const struct iwl_channel_info *ch_info;
u16 passive_dwell = 0;
@@ -1855,19 +1785,19 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
if (!sband)
return 0;
- channels = sband->channels;
-
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 < sband->n_channels; i++) {
- if (channels[i].flags & IEEE80211_CHAN_DISABLED)
+ for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) {
+ chan = priv->scan_request->channels[i];
+
+ if (chan->band != band)
continue;
- scan_ch->channel = channels[i].hw_value;
+ scan_ch->channel = chan->hw_value;
ch_info = iwl_get_channel_info(priv, band, scan_ch->channel);
if (!is_channel_valid(ch_info)) {
@@ -1882,7 +1812,7 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
* and use long active_dwell time.
*/
if (!is_active || is_channel_passive(ch_info) ||
- (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) {
+ (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)) {
scan_ch->type = 0; /* passive */
if (IWL_UCODE_API(priv->ucode_ver) == 1)
scan_ch->active_dwell = cpu_to_le16(passive_dwell - 1);
@@ -2111,7 +2041,7 @@ static void iwl3945_nic_start(struct iwl_priv *priv)
*/
static int iwl3945_read_ucode(struct iwl_priv *priv)
{
- struct iwl_ucode *ucode;
+ const struct iwl_ucode_header *ucode;
int ret = -EINVAL, index;
const struct firmware *ucode_raw;
/* firmware file name contains uCode/driver compatibility version */
@@ -2152,22 +2082,24 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
goto error;
/* Make sure that we got at least our header! */
- if (ucode_raw->size < sizeof(*ucode)) {
+ if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) {
IWL_ERR(priv, "File size way too small!\n");
ret = -EINVAL;
goto err_release;
}
/* Data from ucode file: header followed by uCode images */
- ucode = (void *)ucode_raw->data;
+ ucode = (struct iwl_ucode_header *)ucode_raw->data;
priv->ucode_ver = le32_to_cpu(ucode->ver);
api_ver = IWL_UCODE_API(priv->ucode_ver);
- inst_size = le32_to_cpu(ucode->inst_size);
- data_size = le32_to_cpu(ucode->data_size);
- init_size = le32_to_cpu(ucode->init_size);
- init_data_size = le32_to_cpu(ucode->init_data_size);
- boot_size = le32_to_cpu(ucode->boot_size);
+ 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
@@ -2208,12 +2140,13 @@ 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 < sizeof(*ucode) +
+ 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 %zd too small\n",
- ucode_raw->size);
+ IWL_DEBUG_INFO(priv,
+ "uCode file size %zd does not match expected size\n",
+ ucode_raw->size);
ret = -EINVAL;
goto err_release;
}
@@ -2296,44 +2229,44 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
/* Copy images into buffers for card's bus-master reads ... */
/* Runtime instructions (first block of data in file) */
- src = &ucode->data[0];
- len = priv->ucode_code.len;
+ 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, "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 iwl3945_up() */
- src = &ucode->data[inst_size];
- len = priv->ucode_data.len;
+ 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) {
- src = &ucode->data[inst_size + data_size];
- len = priv->ucode_init.len;
+ len = 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;
}
/* Initialization data (4th block) */
if (init_data_size) {
- src = &ucode->data[inst_size + data_size + init_size];
- len = priv->ucode_init_data.len;
+ len = 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;
}
/* Bootstrap instructions (5th block) */
- src = &ucode->data[inst_size + data_size + init_size + init_data_size];
- len = priv->ucode_boot.len;
+ 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);
@@ -3066,7 +2999,7 @@ void iwl3945_post_associate(struct iwl_priv *priv)
iwlcore_commit_rxon(priv);
memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
- iwl3945_setup_rxon_timing(priv);
+ iwl_setup_rxon_timing(priv);
rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
sizeof(priv->rxon_timing), &priv->rxon_timing);
if (rc)
@@ -3261,7 +3194,7 @@ void iwl3945_config_ap(struct iwl_priv *priv)
/* RXON Timing */
memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
- iwl3945_setup_rxon_timing(priv);
+ iwl_setup_rxon_timing(priv);
rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
sizeof(priv->rxon_timing),
&priv->rxon_timing);
@@ -3375,13 +3308,15 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
* used for controlling the debug level.
*
* See the level definitions in iwl for details.
+ *
+ * FIXME This file can be deprecated as the module parameter is
+ * writable and users can thus also change the debug level
+ * using the /sys/module/iwl3945/parameters/debug file.
*/
static ssize_t show_debug_level(struct device *d,
struct device_attribute *attr, char *buf)
{
- struct iwl_priv *priv = dev_get_drvdata(d);
-
- return sprintf(buf, "0x%08X\n", priv->debug_level);
+ return sprintf(buf, "0x%08X\n", iwl_debug_level);
}
static ssize_t store_debug_level(struct device *d,
struct device_attribute *attr,
@@ -3395,7 +3330,7 @@ static ssize_t store_debug_level(struct device *d,
if (ret)
IWL_INFO(priv, "%s is not in hex or decimal form.\n", buf);
else
- priv->debug_level = val;
+ iwl_debug_level = val;
return strnlen(buf, count);
}
@@ -4017,15 +3952,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
priv = hw->priv;
SET_IEEE80211_DEV(hw, &pdev->dev);
- if ((iwl3945_mod_params.num_of_queues > IWL39_MAX_NUM_QUEUES) ||
- (iwl3945_mod_params.num_of_queues < IWL39_MIN_NUM_QUEUES)) {
- IWL_ERR(priv,
- "invalid queues_num, should be between %d and %d\n",
- IWL39_MIN_NUM_QUEUES, IWL39_MAX_NUM_QUEUES);
- err = -EINVAL;
- goto out_ieee80211_free_hw;
- }
-
/*
* Disabling hardware scan means that mac80211 will perform scans
* "the hard way", rather than using device's scan.
@@ -4042,7 +3968,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
priv->inta_mask = CSR_INI_SET_MASK;
#ifdef CONFIG_IWLWIFI_DEBUG
- priv->debug_level = iwl3945_mod_params.debug;
atomic_set(&priv->restrict_refcnt, 0);
#endif
@@ -4338,14 +4263,12 @@ MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
module_param_named(swcrypto, iwl3945_mod_params.sw_crypto, int, 0444);
MODULE_PARM_DESC(swcrypto,
"using software crypto (default 1 [software])\n");
-module_param_named(debug, iwl3945_mod_params.debug, uint, 0444);
+#ifdef CONFIG_IWLWIFI_DEBUG
+module_param_named(debug, iwl_debug_level, uint, 0644);
MODULE_PARM_DESC(debug, "debug output mask");
+#endif
module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan, int, 0444);
MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
-
-module_param_named(queues_num, iwl3945_mod_params.num_of_queues, int, 0444);
-MODULE_PARM_DESC(queues_num, "number of hw queues.");
-
module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, 0444);
MODULE_PARM_DESC(fw_restart3945, "restart firmware in case of error");
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
index 96f714e6e12b..3f5a08fa401f 100644
--- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c
+++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
@@ -23,6 +23,7 @@
#include <linux/kernel.h>
#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
#include <linux/wireless.h>
#include <linux/ieee80211.h>
#include <net/cfg80211.h>
@@ -130,6 +131,133 @@ static struct ieee80211_supported_band iwm_band_5ghz = {
.n_bitrates = iwm_a_rates_size,
};
+static int iwm_key_init(struct iwm_key *key, u8 key_index,
+ const u8 *mac_addr, struct key_params *params)
+{
+ key->hdr.key_idx = key_index;
+ if (!mac_addr || is_broadcast_ether_addr(mac_addr)) {
+ key->hdr.multicast = 1;
+ memset(key->hdr.mac, 0xff, ETH_ALEN);
+ } else {
+ key->hdr.multicast = 0;
+ memcpy(key->hdr.mac, mac_addr, ETH_ALEN);
+ }
+
+ if (params) {
+ if (params->key_len > WLAN_MAX_KEY_LEN ||
+ params->seq_len > IW_ENCODE_SEQ_MAX_SIZE)
+ return -EINVAL;
+
+ key->cipher = params->cipher;
+ key->key_len = params->key_len;
+ key->seq_len = params->seq_len;
+ memcpy(key->key, params->key, key->key_len);
+ memcpy(key->seq, params->seq, key->seq_len);
+ }
+
+ return 0;
+}
+
+static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_index, const u8 *mac_addr,
+ struct key_params *params)
+{
+ struct iwm_priv *iwm = ndev_to_iwm(ndev);
+ struct iwm_key *key = &iwm->keys[key_index];
+ int ret;
+
+ IWM_DBG_WEXT(iwm, DBG, "Adding key for %pM\n", mac_addr);
+
+ memset(key, 0, sizeof(struct iwm_key));
+ ret = iwm_key_init(key, key_index, mac_addr, params);
+ if (ret < 0) {
+ IWM_ERR(iwm, "Invalid key_params\n");
+ return ret;
+ }
+
+ return iwm_set_key(iwm, 0, key);
+}
+
+static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_index, const u8 *mac_addr, void *cookie,
+ void (*callback)(void *cookie,
+ struct key_params*))
+{
+ struct iwm_priv *iwm = ndev_to_iwm(ndev);
+ struct iwm_key *key = &iwm->keys[key_index];
+ struct key_params params;
+
+ IWM_DBG_WEXT(iwm, DBG, "Getting key %d\n", key_index);
+
+ memset(&params, 0, sizeof(params));
+
+ params.cipher = key->cipher;
+ params.key_len = key->key_len;
+ params.seq_len = key->seq_len;
+ params.seq = key->seq;
+ params.key = key->key;
+
+ callback(cookie, &params);
+
+ return key->key_len ? 0 : -ENOENT;
+}
+
+
+static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_index, const u8 *mac_addr)
+{
+ struct iwm_priv *iwm = ndev_to_iwm(ndev);
+ struct iwm_key *key = &iwm->keys[key_index];
+
+ if (!iwm->keys[key_index].key_len) {
+ IWM_DBG_WEXT(iwm, DBG, "Key %d not used\n", key_index);
+ return 0;
+ }
+
+ if (key_index == iwm->default_key)
+ iwm->default_key = -1;
+
+ return iwm_set_key(iwm, 1, key);
+}
+
+static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
+ struct net_device *ndev,
+ u8 key_index)
+{
+ struct iwm_priv *iwm = ndev_to_iwm(ndev);
+
+ IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index);
+
+ if (!iwm->keys[key_index].key_len) {
+ IWM_ERR(iwm, "Key %d not used\n", key_index);
+ return -EINVAL;
+ }
+
+ iwm->default_key = key_index;
+
+ return iwm_set_tx_key(iwm, key_index);
+}
+
+int iwm_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
+ u8 *mac, struct station_info *sinfo)
+{
+ struct iwm_priv *iwm = ndev_to_iwm(ndev);
+
+ if (memcmp(mac, iwm->bssid, ETH_ALEN))
+ return -ENOENT;
+
+ sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->txrate.legacy = iwm->rate * 10;
+
+ if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
+ sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->signal = iwm->wstats.qual.level;
+ }
+
+ return 0;
+}
+
+
int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
{
struct wiphy *wiphy = iwm_to_wiphy(iwm);
@@ -167,20 +295,15 @@ int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
return 0;
}
-static int iwm_cfg80211_change_iface(struct wiphy *wiphy, int ifindex,
+static int iwm_cfg80211_change_iface(struct wiphy *wiphy,
+ struct net_device *ndev,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params)
{
- struct net_device *ndev;
struct wireless_dev *wdev;
struct iwm_priv *iwm;
u32 old_mode;
- /* we're under RTNL */
- ndev = __dev_get_by_index(&init_net, ifindex);
- if (!ndev)
- return -ENODEV;
-
wdev = ndev->ieee80211_ptr;
iwm = ndev_to_iwm(ndev);
old_mode = iwm->conf.mode;
@@ -329,12 +452,245 @@ static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
return 0;
}
+static int iwm_set_auth_type(struct iwm_priv *iwm,
+ enum nl80211_auth_type sme_auth_type)
+{
+ u8 *auth_type = &iwm->umac_profile->sec.auth_type;
+
+ switch (sme_auth_type) {
+ case NL80211_AUTHTYPE_AUTOMATIC:
+ case NL80211_AUTHTYPE_OPEN_SYSTEM:
+ IWM_DBG_WEXT(iwm, DBG, "OPEN auth\n");
+ *auth_type = UMAC_AUTH_TYPE_OPEN;
+ break;
+ case NL80211_AUTHTYPE_SHARED_KEY:
+ if (iwm->umac_profile->sec.flags &
+ (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
+ IWM_DBG_WEXT(iwm, DBG, "WPA auth alg\n");
+ *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
+ } else {
+ IWM_DBG_WEXT(iwm, DBG, "WEP shared key auth alg\n");
+ *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
+ }
+
+ break;
+ default:
+ IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", sme_auth_type);
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version)
+{
+ if (!wpa_version) {
+ iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
+ return 0;
+ }
+
+ if (wpa_version & NL80211_WPA_VERSION_2)
+ iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
+
+ if (wpa_version & NL80211_WPA_VERSION_1)
+ iwm->umac_profile->sec.flags |= UMAC_SEC_FLG_WPA_ON_MSK;
+
+ return 0;
+}
+
+static int iwm_set_cipher(struct iwm_priv *iwm, u32 cipher, bool ucast)
+{
+ u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
+ &iwm->umac_profile->sec.mcast_cipher;
+
+ if (!cipher) {
+ *profile_cipher = UMAC_CIPHER_TYPE_NONE;
+ return 0;
+ }
+
+ switch (cipher) {
+ case IW_AUTH_CIPHER_NONE:
+ *profile_cipher = UMAC_CIPHER_TYPE_NONE;
+ break;
+ case WLAN_CIPHER_SUITE_WEP40:
+ *profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ *profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ *profile_cipher = UMAC_CIPHER_TYPE_TKIP;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ *profile_cipher = UMAC_CIPHER_TYPE_CCMP;
+ break;
+ default:
+ IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int iwm_set_key_mgt(struct iwm_priv *iwm, u32 key_mgt)
+{
+ u8 *auth_type = &iwm->umac_profile->sec.auth_type;
+
+ IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt);
+
+ if (key_mgt == WLAN_AKM_SUITE_8021X)
+ *auth_type = UMAC_AUTH_TYPE_8021X;
+ else if (key_mgt == WLAN_AKM_SUITE_PSK) {
+ if (iwm->umac_profile->sec.flags &
+ (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
+ *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
+ else
+ *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
+ } else {
+ IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme)
+{
+ struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+ struct ieee80211_channel *chan = sme->channel;
+ int ret;
+
+ if (!test_bit(IWM_STATUS_READY, &iwm->status))
+ return -EIO;
+
+ if (!sme->ssid)
+ return -EINVAL;
+
+ if (chan)
+ iwm->channel =
+ ieee80211_frequency_to_channel(chan->center_freq);
+
+ iwm->umac_profile->ssid.ssid_len = sme->ssid_len;
+ memcpy(iwm->umac_profile->ssid.ssid, sme->ssid, sme->ssid_len);
+
+ if (sme->bssid) {
+ IWM_DBG_WEXT(iwm, DBG, "BSSID: %pM\n", sme->bssid);
+ memcpy(&iwm->umac_profile->bssid[0], sme->bssid, ETH_ALEN);
+ iwm->umac_profile->bss_num = 1;
+ } else {
+ memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
+ iwm->umac_profile->bss_num = 0;
+ }
+
+ ret = iwm_set_auth_type(iwm, sme->auth_type);
+ if (ret < 0)
+ return ret;
+
+ ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions);
+ if (ret < 0)
+ return ret;
+
+ if (sme->crypto.n_ciphers_pairwise) {
+ ret = iwm_set_cipher(iwm, sme->crypto.ciphers_pairwise[0],
+ true);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = iwm_set_cipher(iwm, sme->crypto.cipher_group, false);
+ if (ret < 0)
+ return ret;
+
+ if (sme->crypto.n_akm_suites) {
+ ret = iwm_set_key_mgt(iwm, sme->crypto.akm_suites[0]);
+ if (ret < 0)
+ return ret;
+ }
+
+ return iwm_send_mlme_profile(iwm);
+}
+
+static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ u16 reason_code)
+{
+ struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+
+ IWM_DBG_WEXT(iwm, DBG, "Active: %d\n", iwm->umac_profile_active);
+
+ if (iwm->umac_profile_active)
+ return iwm_invalidate_mlme_profile(iwm);
+
+ return 0;
+}
+
+static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
+ enum tx_power_setting type, int dbm)
+{
+ switch (type) {
+ case TX_POWER_AUTOMATIC:
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
+{
+ struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+
+ *dbm = iwm->txpower;
+
+ return 0;
+}
+
+static int iwm_cfg80211_set_power_mgmt(struct wiphy *wiphy,
+ struct net_device *dev,
+ bool enabled, int timeout)
+{
+ struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+ u32 power_index;
+
+ if (enabled)
+ power_index = IWM_POWER_INDEX_DEFAULT;
+ else
+ power_index = IWM_POWER_INDEX_MIN;
+
+ if (power_index == iwm->conf.power_index)
+ return 0;
+
+ iwm->conf.power_index = power_index;
+
+ return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+ CFG_POWER_INDEX, iwm->conf.power_index);
+}
+
static struct cfg80211_ops iwm_cfg80211_ops = {
.change_virtual_intf = iwm_cfg80211_change_iface,
+ .add_key = iwm_cfg80211_add_key,
+ .get_key = iwm_cfg80211_get_key,
+ .del_key = iwm_cfg80211_del_key,
+ .set_default_key = iwm_cfg80211_set_default_key,
+ .get_station = iwm_cfg80211_get_station,
.scan = iwm_cfg80211_scan,
.set_wiphy_params = iwm_cfg80211_set_wiphy_params,
+ .connect = iwm_cfg80211_connect,
+ .disconnect = iwm_cfg80211_disconnect,
.join_ibss = iwm_cfg80211_join_ibss,
.leave_ibss = iwm_cfg80211_leave_ibss,
+ .set_tx_power = iwm_cfg80211_set_txpower,
+ .get_tx_power = iwm_cfg80211_get_txpower,
+ .set_power_mgmt = iwm_cfg80211_set_power_mgmt,
+};
+
+static const u32 cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
};
struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
@@ -379,6 +735,9 @@ struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz;
wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ wdev->wiphy->cipher_suites = cipher_suites;
+ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+
ret = wiphy_register(wdev->wiphy);
if (ret < 0) {
dev_err(dev, "Couldn't register wiphy device\n");
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c
index 834a7f544e5d..0d6637005f42 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.c
+++ b/drivers/net/wireless/iwmc3200wifi/commands.c
@@ -70,14 +70,27 @@ static int iwm_send_lmac_ptrough_cmd(struct iwm_priv *iwm,
int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
bool resp)
{
+ struct iwm_umac_wifi_if *hdr = (struct iwm_umac_wifi_if *)payload;
struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
struct iwm_umac_cmd umac_cmd;
+ int ret;
+ u8 oid = hdr->oid;
umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER;
umac_cmd.resp = resp;
- return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd,
- payload, payload_size);
+ ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd,
+ payload, payload_size);
+
+ if (resp) {
+ ret = wait_event_interruptible_timeout(iwm->wifi_ntfy_queue,
+ test_and_clear_bit(oid, &iwm->wifi_ntfy[0]),
+ 3 * HZ);
+
+ return ret ? 0 : -EBUSY;
+ }
+
+ return ret;
}
static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] =
@@ -106,7 +119,7 @@ static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] =
{4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS},
{3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS},
{5, 5, 0, COEX_CALIBRATION_FLAGS},
- {4, 4, 0, COEX_PERIODIC_CALIBRATION_FLAGS},
+ {3, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS},
{5, 4, 0, COEX_CONNECTION_ESTAB_FLAGS},
{4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS},
{4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS},
@@ -331,8 +344,7 @@ int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key,
return ret;
}
-int iwm_send_umac_config(struct iwm_priv *iwm,
- __le32 reset_flags)
+int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags)
{
int ret;
@@ -360,6 +372,12 @@ int iwm_send_umac_config(struct iwm_priv *iwm,
return ret;
ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+ CFG_WIRELESS_MODE,
+ iwm->conf.wireless_mode);
+ if (ret < 0)
+ return ret;
+
+ ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
CFG_COEX_MODE, iwm->conf.coexist_mode);
if (ret < 0)
return ret;
@@ -401,7 +419,7 @@ int iwm_send_umac_config(struct iwm_priv *iwm,
return ret;
ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
- CFG_PM_CTRL_FLAGS, 0x30001);
+ CFG_PM_CTRL_FLAGS, 0x1);
if (ret < 0)
return ret;
@@ -461,8 +479,10 @@ static int iwm_target_read(struct iwm_priv *iwm, __le32 address,
target_cmd.eop = 1;
ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL);
- if (ret < 0)
+ if (ret < 0) {
IWM_ERR(iwm, "Couldn't send READ command\n");
+ return ret;
+ }
/* When succeding, the send_target routine returns the seq number */
seq_num = ret;
@@ -482,7 +502,7 @@ static int iwm_target_read(struct iwm_priv *iwm, __le32 address,
kfree(cmd);
- return ret;
+ return 0;
}
int iwm_read_mac(struct iwm_priv *iwm, u8 *mac)
@@ -492,7 +512,7 @@ int iwm_read_mac(struct iwm_priv *iwm, u8 *mac)
ret = iwm_target_read(iwm, cpu_to_le32(WICO_MAC_ADDRESS_ADDR),
mac_align, sizeof(mac_align));
- if (ret < 0)
+ if (ret)
return ret;
if (is_valid_ether_addr(mac_align))
@@ -510,9 +530,6 @@ int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx)
{
struct iwm_umac_tx_key_id tx_key_id;
- if (!iwm->default_key || !iwm->default_key->in_use)
- return -EINVAL;
-
tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID;
tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) -
sizeof(struct iwm_umac_wifi_if));
@@ -555,10 +572,9 @@ static int iwm_check_profile(struct iwm_priv *iwm)
return 0;
}
-int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
- struct iwm_key *key)
+int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key)
{
- int ret;
+ int ret = 0;
u8 cmd[64], *sta_addr, *key_data, key_len;
s8 key_idx;
u16 cmd_size = 0;
@@ -568,15 +584,6 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd;
struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd;
- if (set_tx_key)
- iwm->default_key = key;
-
- /*
- * We check if our current profile is valid.
- * If not, we dont push the key, we just cache them,
- * so that with the next siwsessid call, the keys
- * will be actually pushed.
- */
if (!remove) {
ret = iwm_check_profile(iwm);
if (ret < 0)
@@ -589,8 +596,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
key_idx = key->hdr.key_idx;
if (!remove) {
- IWM_DBG_WEXT(iwm, DBG, "key_idx:%d set tx key:%d\n",
- key_idx, set_tx_key);
+ IWM_DBG_WEXT(iwm, DBG, "key_idx:%d\n", key_idx);
IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len);
IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n",
key_hdr->mac, key_hdr->key_idx, key_hdr->multicast);
@@ -602,8 +608,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
iwm->umac_profile->sec.auth_type,
iwm->umac_profile->sec.flags);
- switch (key->alg) {
- case UMAC_CIPHER_TYPE_WEP_40:
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
wep40->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP40_KEY;
wep40->hdr.buf_size =
cpu_to_le16(sizeof(struct iwm_umac_key_wep40) -
@@ -617,7 +623,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
cmd_size = sizeof(struct iwm_umac_key_wep40);
break;
- case UMAC_CIPHER_TYPE_WEP_104:
+ case WLAN_CIPHER_SUITE_WEP104:
wep104->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP104_KEY;
wep104->hdr.buf_size =
cpu_to_le16(sizeof(struct iwm_umac_key_wep104) -
@@ -631,7 +637,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
cmd_size = sizeof(struct iwm_umac_key_wep104);
break;
- case UMAC_CIPHER_TYPE_CCMP:
+ case WLAN_CIPHER_SUITE_CCMP:
key_hdr->key_idx++;
ccmp->hdr.oid = UMAC_WIFI_IF_CMD_ADD_CCMP_KEY;
ccmp->hdr.buf_size =
@@ -643,13 +649,13 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
memcpy(ccmp->key, key_data, key_len);
- if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID)
- memcpy(ccmp->iv_count, key->rx_seq, 6);
+ if (key->seq_len)
+ memcpy(ccmp->iv_count, key->seq, key->seq_len);
cmd_size = sizeof(struct iwm_umac_key_ccmp);
break;
- case UMAC_CIPHER_TYPE_TKIP:
+ case WLAN_CIPHER_SUITE_TKIP:
key_hdr->key_idx++;
tkip->hdr.oid = UMAC_WIFI_IF_CMD_ADD_TKIP_KEY;
tkip->hdr.buf_size =
@@ -666,8 +672,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
key_data + IWM_TKIP_KEY_SIZE + IWM_TKIP_MIC_SIZE,
IWM_TKIP_MIC_SIZE);
- if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID)
- memcpy(ccmp->iv_count, key->rx_seq, 6);
+ if (key->seq_len)
+ memcpy(ccmp->iv_count, key->seq, key->seq_len);
cmd_size = sizeof(struct iwm_umac_key_tkip);
break;
@@ -676,8 +682,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
return -ENOTSUPP;
}
- if ((key->alg == UMAC_CIPHER_TYPE_CCMP) ||
- (key->alg == UMAC_CIPHER_TYPE_TKIP))
+ if ((key->cipher == WLAN_CIPHER_SUITE_TKIP) ||
+ (key->cipher == WLAN_CIPHER_SUITE_CCMP))
/*
* UGLY_UGLY_UGLY
* Copied HACK from the MWG driver.
@@ -688,23 +694,11 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
schedule_timeout_interruptible(usecs_to_jiffies(300));
ret = iwm_send_wifi_if_cmd(iwm, cmd, cmd_size, 1);
- if (ret < 0)
- goto err;
-
- /*
- * We need a default key only if it is set and
- * if we're doing WEP.
- */
- if (iwm->default_key == key &&
- ((key->alg == UMAC_CIPHER_TYPE_WEP_40) ||
- (key->alg == UMAC_CIPHER_TYPE_WEP_104))) {
- ret = iwm_set_tx_key(iwm, key_idx);
- if (ret < 0)
- goto err;
- }
} else {
struct iwm_umac_key_remove key_remove;
+ IWM_DBG_WEXT(iwm, ERR, "Removing key_idx:%d\n", key_idx);
+
key_remove.hdr.oid = UMAC_WIFI_IF_CMD_REMOVE_KEY;
key_remove.hdr.buf_size =
cpu_to_le16(sizeof(struct iwm_umac_key_remove) -
@@ -715,23 +709,19 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
ret = iwm_send_wifi_if_cmd(iwm, &key_remove,
sizeof(struct iwm_umac_key_remove),
1);
- if (ret < 0)
+ if (ret)
return ret;
- iwm->keys[key_idx].in_use = 0;
+ iwm->keys[key_idx].key_len = 0;
}
- return 0;
-
- err:
- kfree(key);
return ret;
}
int iwm_send_mlme_profile(struct iwm_priv *iwm)
{
- int ret, i;
+ int ret;
struct iwm_umac_profile profile;
memcpy(&profile, iwm->umac_profile, sizeof(profile));
@@ -741,45 +731,18 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm)
sizeof(struct iwm_umac_wifi_if));
ret = iwm_send_wifi_if_cmd(iwm, &profile, sizeof(profile), 1);
- if (ret < 0) {
+ if (ret) {
IWM_ERR(iwm, "Send profile command failed\n");
return ret;
}
- /* Wait for the profile to be active */
- ret = wait_event_interruptible_timeout(iwm->mlme_queue,
- iwm->umac_profile_active == 1,
- 3 * HZ);
- if (!ret)
- return -EBUSY;
-
-
- for (i = 0; i < IWM_NUM_KEYS; i++)
- if (iwm->keys[i].in_use) {
- int default_key = 0;
- struct iwm_key *key = &iwm->keys[i];
-
- if (key == iwm->default_key)
- default_key = 1;
-
- /* Wait for the profile before sending the keys */
- wait_event_interruptible_timeout(iwm->mlme_queue,
- (test_bit(IWM_STATUS_ASSOCIATING, &iwm->status) ||
- test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)),
- 3 * HZ);
-
- ret = iwm_set_key(iwm, 0, default_key, key);
- if (ret < 0)
- return ret;
- }
-
return 0;
}
int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
{
- int ret;
struct iwm_umac_invalidate_profile invalid;
+ int ret;
invalid.hdr.oid = UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE;
invalid.hdr.buf_size =
@@ -789,16 +752,13 @@ 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);
- if (ret < 0)
+ if (ret)
return ret;
ret = wait_event_interruptible_timeout(iwm->mlme_queue,
- (iwm->umac_profile_active == 0),
- 2 * HZ);
- if (!ret)
- return -EBUSY;
+ (iwm->umac_profile_active == 0), 2 * HZ);
- return 0;
+ return ret ? 0 : -EBUSY;
}
int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags)
@@ -881,7 +841,7 @@ int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
}
ret = iwm_send_wifi_if_cmd(iwm, &req, sizeof(req), 0);
- if (ret < 0) {
+ if (ret) {
IWM_ERR(iwm, "Couldn't send scan request\n");
return ret;
}
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h
index 36b13a130595..e24d5b633997 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.h
+++ b/drivers/net/wireless/iwmc3200wifi/commands.h
@@ -106,8 +106,7 @@ enum {
CFG_TLC_SPATIAL_STREAM_SUPPORTED,
CFG_TLC_RETRY_PER_RATE,
CFG_TLC_RETRY_PER_HT_RATE,
- CFG_TLC_FIXED_RATE,
- CFG_TLC_FIXED_RATE_FLAGS,
+ CFG_TLC_FIXED_MCS,
CFG_TLC_CONTROL_FLAGS,
CFG_TLC_SR_MIN_FAIL,
CFG_TLC_SR_MIN_PASS,
@@ -232,6 +231,7 @@ struct iwm_umac_cmd_get_channel_list {
/* Wireless mode */
#define WIRELESS_MODE_11A 0x1
#define WIRELESS_MODE_11G 0x2
+#define WIRELESS_MODE_11N 0x4
#define UMAC_PROFILE_EX_IE_REQUIRED 0x1
#define UMAC_PROFILE_QOS_ALLOWED 0x2
@@ -406,8 +406,7 @@ int iwm_send_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);
-int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
- struct iwm_key *key);
+int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key);
int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags);
int iwm_send_umac_channel_list(struct iwm_priv *iwm);
int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.c b/drivers/net/wireless/iwmc3200wifi/eeprom.c
index 0f34b84fd2eb..365910fbe01e 100644
--- a/drivers/net/wireless/iwmc3200wifi/eeprom.c
+++ b/drivers/net/wireless/iwmc3200wifi/eeprom.c
@@ -156,10 +156,6 @@ int iwm_eeprom_init(struct iwm_priv *iwm)
return -ENOMEM;
for (i = IWM_EEPROM_FIRST; i < IWM_EEPROM_LAST; i++) {
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
- if (iwm->conf.hw_b0 && (i >= IWM_EEPROM_INDIRECT_OFFSET))
- break;
-#endif
ret = iwm_eeprom_read(iwm, i);
if (ret < 0) {
IWM_ERR(iwm, "Couldn't read eeprom entry #%d: %s\n",
diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c
index ec1a15a5a0e4..0f32cab9ced4 100644
--- a/drivers/net/wireless/iwmc3200wifi/fw.c
+++ b/drivers/net/wireless/iwmc3200wifi/fw.c
@@ -275,6 +275,7 @@ static int iwm_load_lmac(struct iwm_priv *iwm, const char *img_name)
*/
int iwm_load_fw(struct iwm_priv *iwm)
{
+ unsigned long init_calib_map, periodic_calib_map;
int ret;
/* We first start downloading the UMAC */
@@ -315,23 +316,19 @@ int iwm_load_fw(struct iwm_priv *iwm)
return ret;
}
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
- if (iwm->conf.hw_b0) {
- clear_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map);
- clear_bit(PHY_CALIBRATE_RX_IQ_CMD,
- &iwm->conf.periodic_calib_map);
- }
-#endif
+ init_calib_map = iwm->conf.calib_map & IWM_CALIB_MAP_INIT_MSK;
+ periodic_calib_map = IWM_CALIB_MAP_PER_LMAC(iwm->conf.calib_map);
+
/* Read RX IQ calibration result from EEPROM */
- if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map)) {
+ if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &init_calib_map)) {
iwm_store_rxiq_calib_result(iwm);
set_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->calib_done_map);
}
iwm_send_prio_table(iwm);
- iwm_send_init_calib_cfg(iwm, iwm->conf.init_calib_map);
+ iwm_send_init_calib_cfg(iwm, init_calib_map);
- while (iwm->calib_done_map != iwm->conf.init_calib_map) {
+ while (iwm->calib_done_map != init_calib_map) {
ret = iwm_notif_handle(iwm, CALIBRATION_RES_NOTIFICATION,
IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT);
if (ret) {
@@ -340,7 +337,7 @@ int iwm_load_fw(struct iwm_priv *iwm)
}
IWM_DBG_FW(iwm, DBG, "Got calibration result. calib_done_map: "
"0x%lx, requested calibrations: 0x%lx\n",
- iwm->calib_done_map, iwm->conf.init_calib_map);
+ iwm->calib_done_map, init_calib_map);
}
/* Handle LMAC CALIBRATION_COMPLETE notification */
@@ -378,7 +375,7 @@ int iwm_load_fw(struct iwm_priv *iwm)
iwm_send_prio_table(iwm);
iwm_send_calib_results(iwm);
- iwm_send_periodic_calib_cfg(iwm, iwm->conf.periodic_calib_map);
+ iwm_send_periodic_calib_cfg(iwm, periodic_calib_map);
return 0;
diff --git a/drivers/net/wireless/iwmc3200wifi/hal.c b/drivers/net/wireless/iwmc3200wifi/hal.c
index ee127fe4f43f..c430418248b4 100644
--- a/drivers/net/wireless/iwmc3200wifi/hal.c
+++ b/drivers/net/wireless/iwmc3200wifi/hal.c
@@ -105,9 +105,9 @@
#include "umac.h"
#include "debug.h"
-static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
- struct iwm_nonwifi_cmd *cmd,
- struct iwm_udma_nonwifi_cmd *udma_cmd)
+static int iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
+ struct iwm_nonwifi_cmd *cmd,
+ struct iwm_udma_nonwifi_cmd *udma_cmd)
{
INIT_LIST_HEAD(&cmd->pending);
@@ -118,7 +118,7 @@ static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
cmd->seq_num = iwm->nonwifi_seq_num;
udma_cmd->seq_num = cpu_to_le16(cmd->seq_num);
- cmd->seq_num = iwm->nonwifi_seq_num++;
+ iwm->nonwifi_seq_num++;
iwm->nonwifi_seq_num %= UMAC_NONWIFI_SEQ_NUM_MAX;
if (udma_cmd->resp)
@@ -130,6 +130,8 @@ static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
cmd->buf.len = 0;
memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd));
+
+ return cmd->seq_num;
}
u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm)
@@ -369,7 +371,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
const void *payload)
{
struct iwm_nonwifi_cmd *cmd;
- int ret;
+ int ret, seq_num;
cmd = kzalloc(sizeof(struct iwm_nonwifi_cmd), GFP_KERNEL);
if (!cmd) {
@@ -377,7 +379,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
return -ENOMEM;
}
- iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd);
+ seq_num = iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd);
if (cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE ||
cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT) {
@@ -393,7 +395,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
if (ret < 0)
return ret;
- return cmd->seq_num;
+ return seq_num;
}
static void iwm_build_lmac_hdr(struct iwm_priv *iwm, struct iwm_lmac_hdr *hdr,
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h
index 77c339f8516c..2175a481d2f4 100644
--- a/drivers/net/wireless/iwmc3200wifi/iwm.h
+++ b/drivers/net/wireless/iwmc3200wifi/iwm.h
@@ -52,8 +52,6 @@
#define IWM_COPYRIGHT "Copyright(c) 2009 Intel Corporation"
#define IWM_AUTHOR "<ilw@linux.intel.com>"
-#define CONFIG_IWM_B0_HW_SUPPORT 1
-
#define IWM_SRC_LMAC UMAC_HDI_IN_SOURCE_FHRX
#define IWM_SRC_UDMA UMAC_HDI_IN_SOURCE_UDMA
#define IWM_SRC_UMAC UMAC_HDI_IN_SOURCE_FW
@@ -65,8 +63,7 @@
struct iwm_conf {
u32 sdio_ior_timeout;
- unsigned long init_calib_map;
- unsigned long periodic_calib_map;
+ unsigned long calib_map;
bool reset_on_fatal_err;
bool auto_connect;
bool wimax_not_present;
@@ -87,9 +84,6 @@ struct iwm_conf {
u8 ibss_channel;
u8 mac_addr[ETH_ALEN];
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
- bool hw_b0;
-#endif
};
enum {
@@ -162,13 +156,11 @@ struct iwm_umac_key_hdr {
struct iwm_key {
struct iwm_umac_key_hdr hdr;
- u8 in_use;
- u8 alg;
- u32 flags;
- u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE];
- u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE];
- u8 key_len;
- u8 key[32];
+ u32 cipher;
+ u8 key[WLAN_MAX_KEY_LEN];
+ u8 seq[IW_ENCODE_SEQ_MAX_SIZE];
+ int key_len;
+ int seq_len;
};
#define IWM_RX_ID_HASH 0xff
@@ -186,10 +178,6 @@ struct iwm_key {
#define IWM_STATUS_ASSOCIATING 3
#define IWM_STATUS_ASSOCIATED 4
-#define IWM_RADIO_RFKILL_OFF 0
-#define IWM_RADIO_RFKILL_HW 1
-#define IWM_RADIO_RFKILL_SW 2
-
struct iwm_tx_queue {
int id;
struct sk_buff_head queue;
@@ -223,7 +211,6 @@ struct iwm_priv {
struct iwm_conf conf;
unsigned long status;
- unsigned long radio;
struct list_head pending_notif;
wait_queue_head_t notif_queue;
@@ -242,6 +229,7 @@ struct iwm_priv {
u8 bssid[ETH_ALEN];
u8 channel;
u16 rate;
+ u32 txpower;
struct iwm_sta_info sta_table[IWM_STA_TABLE_NUM];
struct list_head bss_list;
@@ -276,7 +264,10 @@ struct iwm_priv {
struct iwm_tx_queue txq[IWM_TX_QUEUES];
struct iwm_key keys[IWM_NUM_KEYS];
- struct iwm_key *default_key;
+ s8 default_key;
+
+ DECLARE_BITMAP(wifi_ntfy, WIFI_IF_NTFY_MAX);
+ wait_queue_head_t wifi_ntfy_queue;
wait_queue_head_t mlme_queue;
@@ -289,7 +280,11 @@ struct iwm_priv {
struct timer_list watchdog;
struct work_struct reset_worker;
struct mutex mutex;
- struct rfkill *rfkill;
+
+ u8 *req_ie;
+ int req_ie_len;
+ u8 *resp_ie;
+ int resp_ie_len;
char private[0] __attribute__((__aligned__(NETDEV_ALIGN)));
};
diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h
index db2e5eea1895..19213e165f5f 100644
--- a/drivers/net/wireless/iwmc3200wifi/lmac.h
+++ b/drivers/net/wireless/iwmc3200wifi/lmac.h
@@ -396,6 +396,10 @@ enum {
CALIBRATION_CMD_NUM,
};
+#define IWM_CALIB_MAP_INIT_MSK 0xFFFF
+#define IWM_CALIB_MAP_PER_LMAC(m) ((m & 0xFF0000) >> 16)
+#define IWM_CALIB_MAP_PER_UMAC(m) ((m & 0xFF000000) >> 24)
+
struct iwm_lmac_calib_hdr {
u8 opcode;
u8 first_grp;
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c
index 8be206d58222..cf2574442b57 100644
--- a/drivers/net/wireless/iwmc3200wifi/main.c
+++ b/drivers/net/wireless/iwmc3200wifi/main.c
@@ -53,11 +53,7 @@
static struct iwm_conf def_iwm_conf = {
.sdio_ior_timeout = 5000,
- .init_calib_map = BIT(PHY_CALIBRATE_DC_CMD) |
- BIT(PHY_CALIBRATE_LO_CMD) |
- BIT(PHY_CALIBRATE_TX_IQ_CMD) |
- BIT(PHY_CALIBRATE_RX_IQ_CMD),
- .periodic_calib_map = BIT(PHY_CALIBRATE_DC_CMD) |
+ .calib_map = BIT(PHY_CALIBRATE_DC_CMD) |
BIT(PHY_CALIBRATE_LO_CMD) |
BIT(PHY_CALIBRATE_TX_IQ_CMD) |
BIT(PHY_CALIBRATE_RX_IQ_CMD) |
@@ -191,6 +187,7 @@ int iwm_priv_init(struct iwm_priv *iwm)
INIT_LIST_HEAD(&iwm->pending_notif);
init_waitqueue_head(&iwm->notif_queue);
init_waitqueue_head(&iwm->nonwifi_queue);
+ init_waitqueue_head(&iwm->wifi_ntfy_queue);
init_waitqueue_head(&iwm->mlme_queue);
memcpy(&iwm->conf, &def_iwm_conf, sizeof(struct iwm_conf));
spin_lock_init(&iwm->tx_credit.lock);
@@ -229,7 +226,7 @@ int iwm_priv_init(struct iwm_priv *iwm)
for (i = 0; i < IWM_NUM_KEYS; i++)
memset(&iwm->keys[i], 0, sizeof(struct iwm_key));
- iwm->default_key = NULL;
+ iwm->default_key = -1;
init_timer(&iwm->watchdog);
iwm->watchdog.function = iwm_watchdog;
@@ -500,6 +497,13 @@ void iwm_link_off(struct iwm_priv *iwm)
memset(wstats, 0, sizeof(struct iw_statistics));
wstats->qual.updated = IW_QUAL_ALL_INVALID;
+ kfree(iwm->req_ie);
+ iwm->req_ie = NULL;
+ iwm->req_ie_len = 0;
+ kfree(iwm->resp_ie);
+ iwm->resp_ie = NULL;
+ iwm->resp_ie_len = 0;
+
del_timer_sync(&iwm->watchdog);
}
@@ -518,13 +522,6 @@ static int iwm_channels_init(struct iwm_priv *iwm)
{
int ret;
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
- if (iwm->conf.hw_b0) {
- IWM_INFO(iwm, "Workaround EEPROM channels for B0 hardware\n");
- return 0;
- }
-#endif
-
ret = iwm_send_umac_channel_list(iwm);
if (ret) {
IWM_ERR(iwm, "Send channel list failed\n");
@@ -642,19 +639,10 @@ int __iwm_up(struct iwm_priv *iwm)
}
}
- iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile),
- GFP_KERNEL);
- if (!iwm->umac_profile) {
- IWM_ERR(iwm, "Couldn't alloc memory for profile\n");
- goto err_fw;
- }
-
- iwm_init_default_profile(iwm, iwm->umac_profile);
-
ret = iwm_channels_init(iwm);
if (ret < 0) {
IWM_ERR(iwm, "Couldn't init channels\n");
- goto err_profile;
+ goto err_fw;
}
/* Set the READY bit to indicate interface is brought up successfully */
@@ -662,10 +650,6 @@ int __iwm_up(struct iwm_priv *iwm)
return 0;
- err_profile:
- kfree(iwm->umac_profile);
- iwm->umac_profile = NULL;
-
err_fw:
iwm_eeprom_exit(iwm);
@@ -704,11 +688,10 @@ int __iwm_down(struct iwm_priv *iwm)
clear_bit(IWM_STATUS_READY, &iwm->status);
iwm_eeprom_exit(iwm);
- kfree(iwm->umac_profile);
- iwm->umac_profile = NULL;
iwm_bss_list_clean(iwm);
-
- iwm->default_key = NULL;
+ iwm_init_default_profile(iwm, iwm->umac_profile);
+ iwm->umac_profile_active = false;
+ iwm->default_key = -1;
iwm->core_enabled = 0;
ret = iwm_bus_disable(iwm);
diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c
index bf294e41753b..93cc1b3e7f48 100644
--- a/drivers/net/wireless/iwmc3200wifi/netdev.c
+++ b/drivers/net/wireless/iwmc3200wifi/netdev.c
@@ -48,29 +48,22 @@
#include <linux/netdevice.h>
#include "iwm.h"
+#include "commands.h"
#include "cfg80211.h"
#include "debug.h"
static int iwm_open(struct net_device *ndev)
{
struct iwm_priv *iwm = ndev_to_iwm(ndev);
- int ret = 0;
-
- if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio))
- ret = iwm_up(iwm);
- return ret;
+ return iwm_up(iwm);
}
static int iwm_stop(struct net_device *ndev)
{
struct iwm_priv *iwm = ndev_to_iwm(ndev);
- int ret = 0;
-
- if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio))
- ret = iwm_down(iwm);
- return ret;
+ return iwm_down(iwm);
}
/*
@@ -133,8 +126,20 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
wdev->netdev = ndev;
+ iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile),
+ GFP_KERNEL);
+ if (!iwm->umac_profile) {
+ dev_err(dev, "Couldn't alloc memory for profile\n");
+ goto out_profile;
+ }
+
+ iwm_init_default_profile(iwm, iwm->umac_profile);
+
return iwm;
+ out_profile:
+ free_netdev(ndev);
+
out_priv:
iwm_priv_deinit(iwm);
@@ -150,6 +155,8 @@ void iwm_if_free(struct iwm_priv *iwm)
free_netdev(iwm_to_ndev(iwm));
iwm_priv_deinit(iwm);
+ kfree(iwm->umac_profile);
+ iwm->umac_profile = NULL;
iwm_wdev_free(iwm);
}
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index d73cf96c6dc6..86079a187eef 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -102,7 +102,6 @@ static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf,
error = (struct iwm_umac_notif_error *)buf;
fw_err = &error->err;
-
IWM_ERR(iwm, "%cMAC FW ERROR:\n",
(le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U');
IWM_ERR(iwm, "\tCategory: %d\n", le32_to_cpu(fw_err->category));
@@ -143,17 +142,18 @@ static int iwm_ntf_init_complete(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size,
struct iwm_wifi_cmd *cmd)
{
+ struct wiphy *wiphy = iwm_to_wiphy(iwm);
struct iwm_umac_notif_init_complete *init_complete =
(struct iwm_umac_notif_init_complete *)(buf);
u16 status = le16_to_cpu(init_complete->status);
+ bool blocked = (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR);
- if (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR) {
+ if (blocked)
IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is on (radio off)\n");
- set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
- } else {
+ else
IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is off (radio on)\n");
- clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
- }
+
+ wiphy_rfkill_set_hw_state(wiphy, blocked);
return 0;
}
@@ -218,17 +218,17 @@ static int iwm_ntf_tx(struct iwm_priv *iwm, u8 *buf,
(buf + sizeof(struct iwm_umac_wifi_in_hdr));
hdr = (struct iwm_umac_wifi_in_hdr *)buf;
- IWM_DBG_NTF(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size);
+ IWM_DBG_TX(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size);
- IWM_DBG_NTF(iwm, DBG, "Seqnum: %d\n",
- le16_to_cpu(hdr->sw_hdr.cmd.seq_num));
- IWM_DBG_NTF(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt);
- IWM_DBG_NTF(iwm, DBG, "\tRetry cnt: %d\n",
- le16_to_cpu(tx_resp->retry_cnt));
- IWM_DBG_NTF(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl));
- IWM_DBG_NTF(iwm, DBG, "\tByte cnt: %d\n",
- le16_to_cpu(tx_resp->byte_cnt));
- IWM_DBG_NTF(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status));
+ IWM_DBG_TX(iwm, DBG, "Seqnum: %d\n",
+ le16_to_cpu(hdr->sw_hdr.cmd.seq_num));
+ IWM_DBG_TX(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt);
+ IWM_DBG_TX(iwm, DBG, "\tRetry cnt: %d\n",
+ le16_to_cpu(tx_resp->retry_cnt));
+ IWM_DBG_TX(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl));
+ IWM_DBG_TX(iwm, DBG, "\tByte cnt: %d\n",
+ le16_to_cpu(tx_resp->byte_cnt));
+ IWM_DBG_TX(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status));
return 0;
}
@@ -418,8 +418,8 @@ static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf,
if (IS_ERR(ticket_node))
return PTR_ERR(ticket_node);
- IWM_DBG_NTF(iwm, DBG, "TICKET RELEASE(%d)\n",
- ticket->id);
+ IWM_DBG_RX(iwm, DBG, "TICKET RELEASE(%d)\n",
+ ticket->id);
list_add_tail(&ticket_node->node, &iwm->rx_tickets);
/*
@@ -454,15 +454,15 @@ static int iwm_ntf_rx_packet(struct iwm_priv *iwm, u8 *buf,
u16 id, buf_offset;
u32 packet_size;
- IWM_DBG_NTF(iwm, DBG, "\n");
+ IWM_DBG_RX(iwm, DBG, "\n");
wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf;
id = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num);
buf_offset = sizeof(struct iwm_umac_wifi_in_hdr);
packet_size = buf_size - sizeof(struct iwm_umac_wifi_in_hdr);
- IWM_DBG_NTF(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n",
- wifi_hdr->sw_hdr.cmd.cmd, id, packet_size);
+ IWM_DBG_RX(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n",
+ wifi_hdr->sw_hdr.cmd.cmd, id, packet_size);
IWM_DBG_RX(iwm, DBG, "Packet id: %d\n", id);
IWM_HEXDUMP(iwm, DBG, RX, "PACKET: ", buf + buf_offset, packet_size);
@@ -503,13 +503,10 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
{
struct iwm_umac_notif_assoc_complete *complete =
(struct iwm_umac_notif_assoc_complete *)buf;
- union iwreq_data wrqu;
IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n",
complete->bssid, complete->status);
- memset(&wrqu, 0, sizeof(wrqu));
-
clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status);
switch (le32_to_cpu(complete->status)) {
@@ -520,7 +517,14 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
iwm_link_on(iwm);
- memcpy(wrqu.ap_addr.sa_data, complete->bssid, ETH_ALEN);
+ if (iwm->conf.mode == UMAC_MODE_IBSS)
+ goto ibss;
+
+ cfg80211_connect_result(iwm_to_ndev(iwm),
+ complete->bssid,
+ iwm->req_ie, iwm->req_ie_len,
+ iwm->resp_ie, iwm->resp_ie_len,
+ WLAN_STATUS_SUCCESS, GFP_KERNEL);
break;
case UMAC_ASSOC_COMPLETE_FAILURE:
clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
@@ -528,18 +532,22 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
iwm->channel = 0;
iwm_link_off(iwm);
+
+ if (iwm->conf.mode == UMAC_MODE_IBSS)
+ goto ibss;
+
+ cfg80211_connect_result(iwm_to_ndev(iwm), complete->bssid,
+ NULL, 0, NULL, 0,
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
+ GFP_KERNEL);
default:
break;
}
- if (iwm->conf.mode == UMAC_MODE_IBSS) {
- cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL);
- return 0;
- }
-
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(iwm_to_ndev(iwm), SIOCGIWAP, &wrqu, NULL);
+ return 0;
+ ibss:
+ cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL);
return 0;
}
@@ -769,37 +777,46 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size, struct iwm_wifi_cmd *cmd)
{
struct iwm_umac_notif_mgt_frame *mgt_frame =
- (struct iwm_umac_notif_mgt_frame *)buf;
+ (struct iwm_umac_notif_mgt_frame *)buf;
struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame;
u8 *ie;
- unsigned int event;
- union iwreq_data wrqu;
IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame,
le16_to_cpu(mgt_frame->len));
if (ieee80211_is_assoc_req(mgt->frame_control)) {
ie = mgt->u.assoc_req.variable;;
- event = IWEVASSOCREQIE;
+ iwm->req_ie_len =
+ le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+ kfree(iwm->req_ie);
+ iwm->req_ie = kmemdup(mgt->u.assoc_req.variable,
+ iwm->req_ie_len, GFP_KERNEL);
} else if (ieee80211_is_reassoc_req(mgt->frame_control)) {
ie = mgt->u.reassoc_req.variable;;
- event = IWEVASSOCREQIE;
+ iwm->req_ie_len =
+ le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+ kfree(iwm->req_ie);
+ iwm->req_ie = kmemdup(mgt->u.reassoc_req.variable,
+ iwm->req_ie_len, GFP_KERNEL);
} else if (ieee80211_is_assoc_resp(mgt->frame_control)) {
ie = mgt->u.assoc_resp.variable;;
- event = IWEVASSOCRESPIE;
+ iwm->resp_ie_len =
+ le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+ kfree(iwm->resp_ie);
+ iwm->resp_ie = kmemdup(mgt->u.assoc_resp.variable,
+ iwm->resp_ie_len, GFP_KERNEL);
} else if (ieee80211_is_reassoc_resp(mgt->frame_control)) {
ie = mgt->u.reassoc_resp.variable;;
- event = IWEVASSOCRESPIE;
+ iwm->resp_ie_len =
+ le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+ kfree(iwm->resp_ie);
+ iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable,
+ iwm->resp_ie_len, GFP_KERNEL);
} else {
IWM_ERR(iwm, "Unsupported management frame");
return 0;
}
- wrqu.data.length = le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
-
- IWM_HEXDUMP(iwm, DBG, MLME, "EVT: ", ie, wrqu.data.length);
- wireless_send_event(iwm_to_ndev(iwm), event, &wrqu, ie);
-
return 0;
}
@@ -875,6 +892,7 @@ static int iwm_ntf_statistics(struct iwm_priv *iwm, u8 *buf,
/* UMAC passes rate info multiplies by 2 */
iwm->rate = max_rate >> 1;
}
+ iwm->txpower = le32_to_cpu(stats->tx_power);
wstats->status = 0;
@@ -922,13 +940,6 @@ static int iwm_ntf_eeprom_proxy(struct iwm_priv *iwm, u8 *buf,
if ((hdr_offset + hdr_len) > IWM_EEPROM_LEN)
return -EINVAL;
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
- if (hdr_offset == IWM_EEPROM_SKU_CAP_OFF) {
- if (eeprom_proxy->buf[0] == 0xff)
- iwm->conf.hw_b0 = 1;
- }
-#endif
-
switch (hdr_type) {
case IWM_UMAC_CMD_EEPROM_TYPE_READ:
memcpy(iwm->eeprom + hdr_offset, eeprom_proxy->buf, hdr_len);
@@ -993,12 +1004,17 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
(struct iwm_umac_wifi_if *)cmd->buf.payload;
IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: "
- "oid is %d\n", hdr->oid);
+ "oid is 0x%x\n", hdr->oid);
+
+ if (hdr->oid <= WIFI_IF_NTFY_MAX) {
+ set_bit(hdr->oid, &iwm->wifi_ntfy[0]);
+ wake_up_interruptible(&iwm->wifi_ntfy_queue);
+ } else
+ return -EINVAL;
switch (hdr->oid) {
case UMAC_WIFI_IF_CMD_SET_PROFILE:
iwm->umac_profile_active = 1;
- wake_up_interruptible(&iwm->mlme_queue);
break;
default:
break;
@@ -1010,6 +1026,7 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size, struct iwm_wifi_cmd *cmd)
{
+ struct wiphy *wiphy = iwm_to_wiphy(iwm);
struct iwm_lmac_card_state *state = (struct iwm_lmac_card_state *)
(buf + sizeof(struct iwm_umac_wifi_in_hdr));
u32 flags = le32_to_cpu(state->flags);
@@ -1018,10 +1035,7 @@ static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF",
flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF");
- if (flags & IWM_CARD_STATE_HW_DISABLED)
- set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
- else
- clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
+ wiphy_rfkill_set_hw_state(wiphy, flags & IWM_CARD_STATE_HW_DISABLED);
return 0;
}
@@ -1362,13 +1376,13 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm,
skb->dev = iwm_to_ndev(iwm);
skb->protocol = eth_type_trans(skb, ndev);
- skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->ip_summed = CHECKSUM_NONE;
memset(skb->cb, 0, sizeof(skb->cb));
ndev->stats.rx_packets++;
ndev->stats.rx_bytes += skb->len;
- if (netif_rx(skb) == NET_RX_DROP) {
+ if (netif_rx_ni(skb) == NET_RX_DROP) {
IWM_ERR(iwm, "Packet dropped\n");
ndev->stats.rx_dropped++;
}
diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c
index 916681837fd2..8b1de84003ca 100644
--- a/drivers/net/wireless/iwmc3200wifi/sdio.c
+++ b/drivers/net/wireless/iwmc3200wifi/sdio.c
@@ -65,6 +65,7 @@
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/debugfs.h>
+#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sdio_func.h>
@@ -492,7 +493,8 @@ static void iwm_sdio_remove(struct sdio_func *func)
}
static const struct sdio_device_id iwm_sdio_ids[] = {
- { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, SDIO_DEVICE_ID_IWM) },
+ { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL,
+ SDIO_DEVICE_ID_INTEL_IWMC3200WIFI) },
{ /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(sdio, iwm_sdio_ids);
@@ -506,11 +508,7 @@ static struct sdio_driver iwm_sdio_driver = {
static int __init iwm_sdio_init_module(void)
{
- int ret;
-
- ret = sdio_register_driver(&iwm_sdio_driver);
-
- return ret;
+ return sdio_register_driver(&iwm_sdio_driver);
}
static void __exit iwm_sdio_exit_module(void)
diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.h b/drivers/net/wireless/iwmc3200wifi/sdio.h
index b3c156b08dda..aab6b6892e45 100644
--- a/drivers/net/wireless/iwmc3200wifi/sdio.h
+++ b/drivers/net/wireless/iwmc3200wifi/sdio.h
@@ -39,9 +39,6 @@
#ifndef __IWM_SDIO_H__
#define __IWM_SDIO_H__
-#define SDIO_VENDOR_ID_INTEL 0x89
-#define SDIO_DEVICE_ID_IWM 0x1403
-
#define IWM_SDIO_DATA_ADDR 0x0
#define IWM_SDIO_INTR_ENABLE_ADDR 0x14
#define IWM_SDIO_INTR_STATUS_ADDR 0x13
diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h
index 4a95cce1f0a6..c5a14ae3160a 100644
--- a/drivers/net/wireless/iwmc3200wifi/umac.h
+++ b/drivers/net/wireless/iwmc3200wifi/umac.h
@@ -495,6 +495,8 @@ struct iwm_fw_alive_hdr {
#define WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP 0xE8
#define WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP 0xE9
+#define WIFI_IF_NTFY_MAX 0xff
+
/* Notification structures */
struct iwm_umac_notif_wifi_if {
struct iwm_umac_wifi_in_hdr hdr;
@@ -613,6 +615,7 @@ struct iwm_umac_notif_alive {
} __attribute__ ((packed));
struct iwm_umac_notif_init_complete {
+ struct iwm_umac_wifi_in_hdr hdr;
__le16 status;
__le16 reserved;
} __attribute__ ((packed));
@@ -641,6 +644,11 @@ struct iwm_fw_error_hdr {
__le32 umac_status;
__le32 lmac_status;
__le32 sdio_status;
+ __le32 dbm_sample_ctrl;
+ __le32 dbm_buf_base;
+ __le32 dbm_buf_end;
+ __le32 dbm_buf_write_ptr;
+ __le32 dbm_buf_cycle_cnt;
} __attribute__ ((packed));
struct iwm_umac_notif_error {
diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c
index 584c94d0f399..c3c90d5963bf 100644
--- a/drivers/net/wireless/iwmc3200wifi/wext.c
+++ b/drivers/net/wireless/iwmc3200wifi/wext.c
@@ -21,31 +21,11 @@
*
*/
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
#include <linux/wireless.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
#include <net/cfg80211.h>
-#include <net/iw_handler.h>
#include "iwm.h"
-#include "umac.h"
#include "commands.h"
-#include "debug.h"
-
-static struct iw_statistics *iwm_get_wireless_stats(struct net_device *dev)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- struct iw_statistics *wstats = &iwm->wstats;
-
- if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
- memset(wstats, 0, sizeof(struct iw_statistics));
- wstats->qual.updated = IW_QUAL_ALL_INVALID;
- }
-
- return wstats;
-}
static int iwm_wext_siwfreq(struct net_device *dev,
struct iw_request_info *info,
@@ -53,14 +33,12 @@ static int iwm_wext_siwfreq(struct net_device *dev,
{
struct iwm_priv *iwm = ndev_to_iwm(dev);
- if (freq->flags == IW_FREQ_AUTO)
- return 0;
-
- /* frequency/channel can only be set in IBSS mode */
- if (iwm->conf.mode != UMAC_MODE_IBSS)
+ switch (iwm->conf.mode) {
+ case UMAC_MODE_IBSS:
+ return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
+ default:
return -EOPNOTSUPP;
-
- return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
+ }
}
static int iwm_wext_giwfreq(struct net_device *dev,
@@ -69,13 +47,14 @@ static int iwm_wext_giwfreq(struct net_device *dev,
{
struct iwm_priv *iwm = ndev_to_iwm(dev);
- if (iwm->conf.mode == UMAC_MODE_IBSS)
+ switch (iwm->conf.mode) {
+ case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
-
- freq->e = 0;
- freq->m = iwm->channel;
-
- return 0;
+ case UMAC_MODE_BSS:
+ return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra);
+ default:
+ return -EOPNOTSUPP;
+ }
}
static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info,
@@ -83,37 +62,14 @@ static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info,
{
struct iwm_priv *iwm = ndev_to_iwm(dev);
- if (iwm->conf.mode == UMAC_MODE_IBSS)
+ switch (iwm->conf.mode) {
+ case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
-
- if (!test_bit(IWM_STATUS_READY, &iwm->status))
- return -EIO;
-
- if (is_zero_ether_addr(ap_addr->sa_data) ||
- is_broadcast_ether_addr(ap_addr->sa_data)) {
- IWM_DBG_WEXT(iwm, DBG, "clear mandatory bssid %pM\n",
- iwm->umac_profile->bssid[0]);
- memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
- iwm->umac_profile->bss_num = 0;
- } else {
- IWM_DBG_WEXT(iwm, DBG, "add mandatory bssid %pM\n",
- ap_addr->sa_data);
- memcpy(&iwm->umac_profile->bssid[0], ap_addr->sa_data,
- ETH_ALEN);
- iwm->umac_profile->bss_num = 1;
- }
-
- if (iwm->umac_profile_active) {
- if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN))
- return 0;
-
- iwm_invalidate_mlme_profile(iwm);
+ case UMAC_MODE_BSS:
+ return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra);
+ default:
+ return -EOPNOTSUPP;
}
-
- if (iwm->umac_profile->ssid.ssid_len)
- return iwm_send_mlme_profile(iwm);
-
- return 0;
}
static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info,
@@ -125,17 +81,10 @@ static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info,
case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
case UMAC_MODE_BSS:
- if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
- ap_addr->sa_family = ARPHRD_ETHER;
- memcpy(&ap_addr->sa_data, iwm->bssid, ETH_ALEN);
- } else
- memset(&ap_addr->sa_data, 0, ETH_ALEN);
- break;
+ return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra);
default:
return -EOPNOTSUPP;
}
-
- return 0;
}
static int iwm_wext_siwessid(struct net_device *dev,
@@ -143,34 +92,15 @@ static int iwm_wext_siwessid(struct net_device *dev,
struct iw_point *data, char *ssid)
{
struct iwm_priv *iwm = ndev_to_iwm(dev);
- size_t len = data->length;
- int ret;
- if (iwm->conf.mode == UMAC_MODE_IBSS)
+ switch (iwm->conf.mode) {
+ case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
-
- if (!test_bit(IWM_STATUS_READY, &iwm->status))
- return -EIO;
-
- if (len > 0 && ssid[len - 1] == '\0')
- len--;
-
- if (iwm->umac_profile_active) {
- if (iwm->umac_profile->ssid.ssid_len == len &&
- !memcmp(iwm->umac_profile->ssid.ssid, ssid, len))
- return 0;
-
- ret = iwm_invalidate_mlme_profile(iwm);
- if (ret < 0) {
- IWM_ERR(iwm, "Couldn't invalidate profile\n");
- return ret;
- }
+ case UMAC_MODE_BSS:
+ return cfg80211_mgd_wext_siwessid(dev, info, data, ssid);
+ default:
+ return -EOPNOTSUPP;
}
-
- iwm->umac_profile->ssid.ssid_len = len;
- memcpy(iwm->umac_profile->ssid.ssid, ssid, len);
-
- return iwm_send_mlme_profile(iwm);
}
static int iwm_wext_giwessid(struct net_device *dev,
@@ -179,480 +109,14 @@ static int iwm_wext_giwessid(struct net_device *dev,
{
struct iwm_priv *iwm = ndev_to_iwm(dev);
- if (iwm->conf.mode == UMAC_MODE_IBSS)
+ switch (iwm->conf.mode) {
+ case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
-
- if (!test_bit(IWM_STATUS_READY, &iwm->status))
- return -EIO;
-
- data->length = iwm->umac_profile->ssid.ssid_len;
- if (data->length) {
- memcpy(ssid, iwm->umac_profile->ssid.ssid, data->length);
- data->flags = 1;
- } else
- data->flags = 0;
-
- return 0;
-}
-
-static struct iwm_key *
-iwm_key_init(struct iwm_priv *iwm, u8 key_idx, bool in_use,
- struct iw_encode_ext *ext, u8 alg)
-{
- struct iwm_key *key = &iwm->keys[key_idx];
-
- memset(key, 0, sizeof(struct iwm_key));
- memcpy(key->hdr.mac, ext->addr.sa_data, ETH_ALEN);
- key->hdr.key_idx = key_idx;
- if (is_broadcast_ether_addr(ext->addr.sa_data))
- key->hdr.multicast = 1;
-
- key->in_use = in_use;
- key->flags = ext->ext_flags;
- key->alg = alg;
- key->key_len = ext->key_len;
- memcpy(key->key, ext->key, ext->key_len);
-
- return key;
-}
-
-static int iwm_wext_giwrate(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *rate, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
-
- rate->value = iwm->rate * 1000000;
-
- return 0;
-}
-
-static int iwm_wext_siwencode(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq, char *key_buf)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- struct iwm_key *uninitialized_var(key);
- int idx, i, uninitialized_var(alg), remove = 0, ret;
-
- IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", erq->length);
- IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags);
-
- if (!iwm->umac_profile) {
- IWM_ERR(iwm, "UMAC profile not allocated yet\n");
- return -ENODEV;
- }
-
- if (erq->length == WLAN_KEY_LEN_WEP40) {
- alg = UMAC_CIPHER_TYPE_WEP_40;
- iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_40;
- iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_40;
- } else if (erq->length == WLAN_KEY_LEN_WEP104) {
- alg = UMAC_CIPHER_TYPE_WEP_104;
- iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_104;
- iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_104;
- }
-
- if (erq->flags & IW_ENCODE_RESTRICTED)
- iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
- else
- iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN;
-
- idx = erq->flags & IW_ENCODE_INDEX;
- if (idx == 0) {
- if (iwm->default_key)
- for (i = 0; i < IWM_NUM_KEYS; i++) {
- if (iwm->default_key == &iwm->keys[i]) {
- idx = i;
- break;
- }
- }
- else
- iwm->default_key = &iwm->keys[idx];
- } else if (idx < 1 || idx > 4) {
- return -EINVAL;
- } else
- idx--;
-
- if (erq->flags & IW_ENCODE_DISABLED)
- remove = 1;
- else if (erq->length == 0) {
- if (!iwm->keys[idx].in_use)
- return -EINVAL;
- iwm->default_key = &iwm->keys[idx];
- }
-
- if (erq->length) {
- key = &iwm->keys[idx];
- memset(key, 0, sizeof(struct iwm_key));
- memset(key->hdr.mac, 0xff, ETH_ALEN);
- key->hdr.key_idx = idx;
- key->hdr.multicast = 1;
- key->in_use = !remove;
- key->alg = alg;
- key->key_len = erq->length;
- memcpy(key->key, key_buf, erq->length);
-
- IWM_DBG_WEXT(iwm, DBG, "Setting key %d, default: %d\n",
- idx, !!iwm->default_key);
- }
-
- if (remove) {
- if ((erq->flags & IW_ENCODE_NOKEY) || (erq->length == 0)) {
- int j;
- for (j = 0; j < IWM_NUM_KEYS; j++)
- if (iwm->keys[j].in_use) {
- struct iwm_key *k = &iwm->keys[j];
-
- k->in_use = 0;
- ret = iwm_set_key(iwm, remove, 0, k);
- if (ret < 0)
- return ret;
- }
-
- iwm->umac_profile->sec.ucast_cipher =
- UMAC_CIPHER_TYPE_NONE;
- iwm->umac_profile->sec.mcast_cipher =
- UMAC_CIPHER_TYPE_NONE;
- iwm->umac_profile->sec.auth_type =
- UMAC_AUTH_TYPE_OPEN;
-
- return 0;
- } else {
- key->in_use = 0;
- return iwm_set_key(iwm, remove, 0, key);
- }
- }
-
- /*
- * If we havent set a profile yet, we cant set keys.
- * Keys will be pushed after we're associated.
- */
- if (!iwm->umac_profile_active)
- return 0;
-
- /*
- * If there is a current active profile, but no
- * default key, it's not worth trying to associate again.
- */
- if (!iwm->default_key)
- return 0;
-
- /*
- * Here we have an active profile, but a key setting changed.
- * We thus have to invalidate the current profile, and push the
- * new one. Keys will be pushed when association takes place.
- */
- ret = iwm_invalidate_mlme_profile(iwm);
- if (ret < 0) {
- IWM_ERR(iwm, "Couldn't invalidate profile\n");
- return ret;
- }
-
- return iwm_send_mlme_profile(iwm);
-}
-
-static int iwm_wext_giwencode(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq, char *key)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- int idx, i;
-
- idx = erq->flags & IW_ENCODE_INDEX;
- if (idx < 1 || idx > 4) {
- idx = -1;
- if (!iwm->default_key) {
- erq->length = 0;
- erq->flags |= IW_ENCODE_NOKEY;
- return 0;
- } else
- for (i = 0; i < IWM_NUM_KEYS; i++) {
- if (iwm->default_key == &iwm->keys[i]) {
- idx = i;
- break;
- }
- }
- if (idx < 0)
- return -EINVAL;
- } else
- idx--;
-
- erq->flags = idx + 1;
-
- if (!iwm->keys[idx].in_use) {
- erq->length = 0;
- erq->flags |= IW_ENCODE_DISABLED;
- return 0;
- }
-
- memcpy(key, iwm->keys[idx].key,
- min_t(int, erq->length, iwm->keys[idx].key_len));
- erq->length = iwm->keys[idx].key_len;
- erq->flags |= IW_ENCODE_ENABLED;
-
- if (iwm->umac_profile->mode == UMAC_MODE_BSS) {
- switch (iwm->umac_profile->sec.auth_type) {
- case UMAC_AUTH_TYPE_OPEN:
- erq->flags |= IW_ENCODE_OPEN;
- break;
- default:
- erq->flags |= IW_ENCODE_RESTRICTED;
- break;
- }
- }
-
- return 0;
-}
-
-static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version)
-{
- if (wpa_version & IW_AUTH_WPA_VERSION_WPA2)
- iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
- else if (wpa_version & IW_AUTH_WPA_VERSION_WPA)
- iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK;
- else
- iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
-
- return 0;
-}
-
-static int iwm_wext_siwpower(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- u32 power_index;
-
- if (wrq->disabled) {
- power_index = IWM_POWER_INDEX_MIN;
- goto set;
- } else
- power_index = IWM_POWER_INDEX_DEFAULT;
-
- switch (wrq->flags & IW_POWER_MODE) {
- case IW_POWER_ON:
- case IW_POWER_MODE:
- case IW_POWER_ALL_R:
- break;
- default:
- return -EINVAL;
- }
-
- set:
- if (power_index == iwm->conf.power_index)
- return 0;
-
- iwm->conf.power_index = power_index;
-
- return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
- CFG_POWER_INDEX, iwm->conf.power_index);
-}
-
-static int iwm_wext_giwpower(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
-
- wrqu->power.disabled = (iwm->conf.power_index == IWM_POWER_INDEX_MIN);
-
- return 0;
-}
-
-static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt)
-{
- u8 *auth_type = &iwm->umac_profile->sec.auth_type;
-
- if (key_mgt == IW_AUTH_KEY_MGMT_802_1X)
- *auth_type = UMAC_AUTH_TYPE_8021X;
- else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) {
- if (iwm->umac_profile->sec.flags &
- (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
- *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
- else
- *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
- } else {
- IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int iwm_set_cipher(struct iwm_priv *iwm, u8 cipher, u8 ucast)
-{
- u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
- &iwm->umac_profile->sec.mcast_cipher;
-
- switch (cipher) {
- case IW_AUTH_CIPHER_NONE:
- *profile_cipher = UMAC_CIPHER_TYPE_NONE;
- break;
- case IW_AUTH_CIPHER_WEP40:
- *profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
- break;
- case IW_AUTH_CIPHER_TKIP:
- *profile_cipher = UMAC_CIPHER_TYPE_TKIP;
- break;
- case IW_AUTH_CIPHER_CCMP:
- *profile_cipher = UMAC_CIPHER_TYPE_CCMP;
- break;
- case IW_AUTH_CIPHER_WEP104:
- *profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
- break;
- default:
- IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
- return -ENOTSUPP;
- }
-
- return 0;
-}
-
-static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg)
-{
- u8 *auth_type = &iwm->umac_profile->sec.auth_type;
-
- switch (auth_alg) {
- case IW_AUTH_ALG_OPEN_SYSTEM:
- *auth_type = UMAC_AUTH_TYPE_OPEN;
- break;
- case IW_AUTH_ALG_SHARED_KEY:
- if (iwm->umac_profile->sec.flags &
- (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
- if (*auth_type == UMAC_AUTH_TYPE_8021X)
- return -EINVAL;
- *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
- } else {
- *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
- }
- break;
- case IW_AUTH_ALG_LEAP:
- default:
- IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", auth_alg);
- return -ENOTSUPP;
- }
-
- return 0;
-}
-
-static int iwm_wext_siwauth(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *data, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- int ret;
-
- if ((data->flags) &
- (IW_AUTH_WPA_VERSION | IW_AUTH_KEY_MGMT |
- IW_AUTH_WPA_ENABLED | IW_AUTH_80211_AUTH_ALG)) {
- /* We need to invalidate the current profile */
- if (iwm->umac_profile_active) {
- ret = iwm_invalidate_mlme_profile(iwm);
- if (ret < 0) {
- IWM_ERR(iwm, "Couldn't invalidate profile\n");
- return ret;
- }
- }
- }
-
- switch (data->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- return iwm_set_wpa_version(iwm, data->value);
- break;
- case IW_AUTH_CIPHER_PAIRWISE:
- return iwm_set_cipher(iwm, data->value, 1);
- break;
- case IW_AUTH_CIPHER_GROUP:
- return iwm_set_cipher(iwm, data->value, 0);
- break;
- case IW_AUTH_KEY_MGMT:
- return iwm_set_key_mgt(iwm, data->value);
- break;
- case IW_AUTH_80211_AUTH_ALG:
- return iwm_set_auth_alg(iwm, data->value);
- break;
- default:
- return -ENOTSUPP;
- }
-
- return 0;
-}
-
-static int iwm_wext_giwauth(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *data, char *extra)
-{
- return 0;
-}
-
-static int iwm_wext_siwencodeext(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- struct iwm_key *key;
- struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
- int uninitialized_var(alg), idx, i, remove = 0;
-
- IWM_DBG_WEXT(iwm, DBG, "alg: 0x%x\n", ext->alg);
- IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", ext->key_len);
- IWM_DBG_WEXT(iwm, DBG, "ext_flags: 0x%x\n", ext->ext_flags);
- IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags);
- IWM_DBG_WEXT(iwm, DBG, "length: 0x%x\n", erq->length);
-
- switch (ext->alg) {
- case IW_ENCODE_ALG_NONE:
- remove = 1;
- break;
- case IW_ENCODE_ALG_WEP:
- if (ext->key_len == WLAN_KEY_LEN_WEP40)
- alg = UMAC_CIPHER_TYPE_WEP_40;
- else if (ext->key_len == WLAN_KEY_LEN_WEP104)
- alg = UMAC_CIPHER_TYPE_WEP_104;
- else {
- IWM_ERR(iwm, "Invalid key length: %d\n", ext->key_len);
- return -EINVAL;
- }
-
- break;
- case IW_ENCODE_ALG_TKIP:
- alg = UMAC_CIPHER_TYPE_TKIP;
- break;
- case IW_ENCODE_ALG_CCMP:
- alg = UMAC_CIPHER_TYPE_CCMP;
- break;
+ case UMAC_MODE_BSS:
+ return cfg80211_mgd_wext_giwessid(dev, info, data, ssid);
default:
return -EOPNOTSUPP;
}
-
- idx = erq->flags & IW_ENCODE_INDEX;
-
- if (idx == 0) {
- if (iwm->default_key)
- for (i = 0; i < IWM_NUM_KEYS; i++) {
- if (iwm->default_key == &iwm->keys[i]) {
- idx = i;
- break;
- }
- }
- } else if (idx < 1 || idx > 4) {
- return -EINVAL;
- } else
- idx--;
-
- if (erq->flags & IW_ENCODE_DISABLED)
- remove = 1;
- else if ((erq->length == 0) ||
- (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) {
- iwm->default_key = &iwm->keys[idx];
- if (iwm->umac_profile_active && ext->alg == IW_ENCODE_ALG_WEP)
- return iwm_set_tx_key(iwm, idx);
- }
-
- key = iwm_key_init(iwm, idx, !remove, ext, alg);
-
- return iwm_set_key(iwm, remove, !iwm->default_key, key);
}
static const iw_handler iwm_handlers[] =
@@ -690,26 +154,26 @@ static const iw_handler iwm_handlers[] =
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* SIOCSIWRATE */
- (iw_handler) iwm_wext_giwrate, /* SIOCGIWRATE */
+ (iw_handler) cfg80211_wext_giwrate, /* SIOCGIWRATE */
(iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */
(iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */
(iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */
(iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */
- (iw_handler) NULL, /* SIOCSIWTXPOW */
- (iw_handler) NULL, /* SIOCGIWTXPOW */
+ (iw_handler) cfg80211_wext_siwtxpower, /* SIOCSIWTXPOW */
+ (iw_handler) cfg80211_wext_giwtxpower, /* SIOCGIWTXPOW */
(iw_handler) NULL, /* SIOCSIWRETRY */
(iw_handler) NULL, /* SIOCGIWRETRY */
- (iw_handler) iwm_wext_siwencode, /* SIOCSIWENCODE */
- (iw_handler) iwm_wext_giwencode, /* SIOCGIWENCODE */
- (iw_handler) iwm_wext_siwpower, /* SIOCSIWPOWER */
- (iw_handler) iwm_wext_giwpower, /* SIOCGIWPOWER */
+ (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */
+ (iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */
+ (iw_handler) cfg80211_wext_siwpower, /* SIOCSIWPOWER */
+ (iw_handler) cfg80211_wext_giwpower, /* SIOCGIWPOWER */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* -- hole -- */
- (iw_handler) NULL, /* SIOCSIWGENIE */
+ (iw_handler) cfg80211_wext_siwgenie, /* SIOCSIWGENIE */
(iw_handler) NULL, /* SIOCGIWGENIE */
- (iw_handler) iwm_wext_siwauth, /* SIOCSIWAUTH */
- (iw_handler) iwm_wext_giwauth, /* SIOCGIWAUTH */
- (iw_handler) iwm_wext_siwencodeext, /* SIOCSIWENCODEEXT */
+ (iw_handler) cfg80211_wext_siwauth, /* SIOCSIWAUTH */
+ (iw_handler) cfg80211_wext_giwauth, /* SIOCGIWAUTH */
+ (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */
(iw_handler) NULL, /* SIOCGIWENCODEEXT */
(iw_handler) NULL, /* SIOCSIWPMKSA */
(iw_handler) NULL, /* -- hole -- */
@@ -718,6 +182,6 @@ static const iw_handler iwm_handlers[] =
const struct iw_handler_def iwm_iw_handler_def = {
.num_standard = ARRAY_SIZE(iwm_handlers),
.standard = (iw_handler *) iwm_handlers,
- .get_wireless_stats = iwm_get_wireless_stats,
+ .get_wireless_stats = cfg80211_wireless_stats,
};
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index d6997371c27e..1902b6f0b78c 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -127,7 +127,6 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth
{
struct cmd_ds_802_11_authenticate cmd;
int ret = -1;
- DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_JOIN);
@@ -136,8 +135,7 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth
cmd.authtype = iw_auth_to_ieee_auth(auth);
- lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
- print_mac(mac, bssid), cmd.authtype);
+ lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", bssid, cmd.authtype);
ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd);
@@ -340,8 +338,6 @@ static int lbs_associate(struct lbs_private *priv,
/* Firmware v9+ indicate authentication suites as a TLV */
if (priv->fwrelease >= 0x09000000) {
- DECLARE_MAC_BUF(mac);
-
auth = (struct mrvl_ie_auth_type *) pos;
auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
auth->header.len = cpu_to_le16(2);
@@ -349,8 +345,8 @@ static int lbs_associate(struct lbs_private *priv,
auth->auth = cpu_to_le16(tmpauth);
pos += sizeof(auth->header) + 2;
- lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
- print_mac(mac, bss->bssid), priv->secinfo.auth_mode);
+ lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n",
+ bss->bssid, priv->secinfo.auth_mode);
}
/* WPA/WPA2 IEs */
@@ -1366,11 +1362,17 @@ static int assoc_helper_wpa_keys(struct lbs_private *priv,
if (ret)
goto out;
+ memcpy(&priv->wpa_unicast_key, &assoc_req->wpa_unicast_key,
+ sizeof(struct enc_key));
+
if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req);
assoc_req->flags = flags;
+
+ memcpy(&priv->wpa_mcast_key, &assoc_req->wpa_mcast_key,
+ sizeof(struct enc_key));
}
out:
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index f9ec69e04734..578c69783589 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -260,7 +260,6 @@ struct lbs_private {
u16 psmode; /* Wlan802_11PowermodeCAM=disable
Wlan802_11PowermodeMAX_PSP=enable */
u32 psstate;
- char ps_supported;
u8 needtowakeup;
struct assoc_request * pending_assoc_req;
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index 2a5b083bf9bd..f658fd6a2c0c 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -933,9 +933,6 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
goto out3;
}
- /* The firmware for the CF card supports powersave */
- priv->ps_supported = 1;
-
ret = 0;
goto out;
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 8cdb88c6ca28..485a8d406525 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -1039,9 +1039,6 @@ static int if_sdio_probe(struct sdio_func *func,
if (ret)
goto err_activate_card;
- if (priv->fwcapinfo & FW_CAPINFO_PS)
- priv->ps_supported = 1;
-
out:
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
@@ -1096,11 +1093,11 @@ static void if_sdio_remove(struct sdio_func *func)
lbs_pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n");
}
- card->priv->surpriseremoved = 1;
lbs_deb_sdio("call remove card\n");
lbs_stop_card(card->priv);
lbs_remove_card(card->priv);
+ card->priv->surpriseremoved = 1;
flush_workqueue(card->workqueue);
destroy_workqueue(card->workqueue);
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index 6564282ce476..963c20125fc9 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -737,7 +737,7 @@ static int if_spi_c2h_data(struct if_spi_card *card)
goto out;
} else if (len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
lbs_pr_err("%s: error: card has %d bytes of data, but "
- "our maximum skb size is %lu\n",
+ "our maximum skb size is %zu\n",
__func__, len, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE);
err = -EINVAL;
goto out;
@@ -1118,7 +1118,6 @@ static int __devinit if_spi_probe(struct spi_device *spi)
priv->card = card;
priv->hw_host_to_card = if_spi_host_to_card;
priv->fw_ready = 1;
- priv->ps_supported = 1;
/* Initialize interrupt handling stuff. */
card->run_thread = 1;
@@ -1171,12 +1170,13 @@ static int __devexit libertas_spi_remove(struct spi_device *spi)
lbs_deb_spi("libertas_spi_remove\n");
lbs_deb_enter(LBS_DEB_SPI);
- priv->surpriseremoved = 1;
lbs_stop_card(priv);
+ lbs_remove_card(priv); /* will call free_netdev */
+
+ priv->surpriseremoved = 1;
free_irq(spi->irq, card);
if_spi_terminate_spi_thread(card);
- lbs_remove_card(priv); /* will call free_netdev */
if (card->pdata->teardown)
card->pdata->teardown(spi);
free_if_spi_card(card);
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 1844c5adf6e9..92bc8c5f1ca2 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -181,13 +181,14 @@ static void if_usb_setup_firmware(struct lbs_private *priv)
wake_method.action = cpu_to_le16(CMD_ACT_GET);
if (lbs_cmd_with_response(priv, CMD_802_11_FW_WAKE_METHOD, &wake_method)) {
lbs_pr_info("Firmware does not seem to support PS mode\n");
+ priv->fwcapinfo &= ~FW_CAPINFO_PS;
} else {
if (le16_to_cpu(wake_method.method) == CMD_WAKE_METHOD_COMMAND_INT) {
lbs_deb_usb("Firmware seems to support PS with wake-via-command\n");
- priv->ps_supported = 1;
} else {
/* The versions which boot up this way don't seem to
work even if we set it to the command interrupt */
+ priv->fwcapinfo &= ~FW_CAPINFO_PS;
lbs_pr_info("Firmware doesn't wake via command interrupt; disabling PS mode\n");
}
}
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index 8bc1907458b1..e96451ce470b 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -712,7 +712,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
- if (!priv->ps_supported) {
+ if (!(priv->fwcapinfo & FW_CAPINFO_PS)) {
if (vwrq->disabled)
return 0;
else
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index 10a99e26d392..4872345a2f61 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -503,7 +503,8 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb)
skb_reserve(skb, 2);
}
- ieee80211_rx_irqsafe(priv->hw, skb, &stats);
+ memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats));
+ ieee80211_rx_irqsafe(priv->hw, skb);
return 0;
}
EXPORT_SYMBOL_GPL(lbtf_rx);
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 7916ca3f84c8..930f5c7da4a6 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -15,6 +15,8 @@
#include <linux/list.h>
#include <linux/spinlock.h>
+#include <net/dst.h>
+#include <net/xfrm.h>
#include <net/mac80211.h>
#include <net/ieee80211_radiotap.h>
#include <linux/if_arp.h>
@@ -314,7 +316,7 @@ static int hwsim_mon_xmit(struct sk_buff *skb, struct net_device *dev)
{
/* TODO: allow packet injection */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
@@ -404,11 +406,19 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
rx_status.freq = data->channel->center_freq;
rx_status.band = data->channel->band;
rx_status.rate_idx = info->control.rates[0].idx;
- /* TODO: simulate signal strength (and optional packet drop) */
+ /* TODO: simulate real signal strength (and optional packet loss) */
+ rx_status.signal = -50;
if (data->ps != PS_DISABLED)
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
+ /* release the skb's source info */
+ skb_orphan(skb);
+ skb_dst_drop(skb);
+ skb->mark = 0;
+ secpath_reset(skb);
+ nf_reset(skb);
+
/* Copy skb to all enabled radios that are on the current frequency */
spin_lock(&hwsim_radio_lock);
list_for_each_entry(data2, &hwsim_radios, list) {
@@ -430,7 +440,8 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
if (memcmp(hdr->addr1, data2->hw->wiphy->perm_addr,
ETH_ALEN) == 0)
ack = true;
- ieee80211_rx_irqsafe(data2->hw, nskb, &rx_status);
+ memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status));
+ ieee80211_rx_irqsafe(data2->hw, nskb);
}
spin_unlock(&hwsim_radio_lock);
@@ -690,6 +701,74 @@ static int mac80211_hwsim_conf_tx(
return 0;
}
+#ifdef CONFIG_NL80211_TESTMODE
+/*
+ * This section contains example code for using netlink
+ * attributes with the testmode command in nl80211.
+ */
+
+/* These enums need to be kept in sync with userspace */
+enum hwsim_testmode_attr {
+ __HWSIM_TM_ATTR_INVALID = 0,
+ HWSIM_TM_ATTR_CMD = 1,
+ HWSIM_TM_ATTR_PS = 2,
+
+ /* keep last */
+ __HWSIM_TM_ATTR_AFTER_LAST,
+ HWSIM_TM_ATTR_MAX = __HWSIM_TM_ATTR_AFTER_LAST - 1
+};
+
+enum hwsim_testmode_cmd {
+ HWSIM_TM_CMD_SET_PS = 0,
+ HWSIM_TM_CMD_GET_PS = 1,
+};
+
+static const struct nla_policy hwsim_testmode_policy[HWSIM_TM_ATTR_MAX + 1] = {
+ [HWSIM_TM_ATTR_CMD] = { .type = NLA_U32 },
+ [HWSIM_TM_ATTR_PS] = { .type = NLA_U32 },
+};
+
+static int hwsim_fops_ps_write(void *dat, u64 val);
+
+static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw,
+ void *data, int len)
+{
+ struct mac80211_hwsim_data *hwsim = hw->priv;
+ struct nlattr *tb[HWSIM_TM_ATTR_MAX + 1];
+ struct sk_buff *skb;
+ int err, ps;
+
+ err = nla_parse(tb, HWSIM_TM_ATTR_MAX, data, len,
+ hwsim_testmode_policy);
+ if (err)
+ return err;
+
+ if (!tb[HWSIM_TM_ATTR_CMD])
+ return -EINVAL;
+
+ switch (nla_get_u32(tb[HWSIM_TM_ATTR_CMD])) {
+ case HWSIM_TM_CMD_SET_PS:
+ if (!tb[HWSIM_TM_ATTR_PS])
+ return -EINVAL;
+ ps = nla_get_u32(tb[HWSIM_TM_ATTR_PS]);
+ return hwsim_fops_ps_write(hwsim, ps);
+ case HWSIM_TM_CMD_GET_PS:
+ skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
+ nla_total_size(sizeof(u32)));
+ if (!skb)
+ return -ENOMEM;
+ NLA_PUT_U32(skb, HWSIM_TM_ATTR_PS, hwsim->ps);
+ return cfg80211_testmode_reply(skb);
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ nla_put_failure:
+ kfree_skb(skb);
+ return -ENOBUFS;
+}
+#endif
+
static const struct ieee80211_ops mac80211_hwsim_ops =
{
.tx = mac80211_hwsim_tx,
@@ -703,6 +782,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops =
.sta_notify = mac80211_hwsim_sta_notify,
.set_tim = mac80211_hwsim_set_tim,
.conf_tx = mac80211_hwsim_conf_tx,
+ CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd)
};
@@ -757,7 +837,6 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
{
struct mac80211_hwsim_data *data = dat;
struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
- DECLARE_MAC_BUF(buf);
struct sk_buff *skb;
struct ieee80211_pspoll *pspoll;
@@ -787,7 +866,6 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
struct ieee80211_vif *vif, int ps)
{
struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
- DECLARE_MAC_BUF(buf);
struct sk_buff *skb;
struct ieee80211_hdr *hdr;
@@ -945,7 +1023,8 @@ static int __init init_mac80211_hwsim(void)
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_MESH_POINT);
- hw->flags = IEEE80211_HW_MFP_CAPABLE;
+ hw->flags = IEEE80211_HW_MFP_CAPABLE |
+ IEEE80211_HW_SIGNAL_DBM;
/* ask mac80211 to reserve space for magic */
hw->vif_data_size = sizeof(struct hwsim_vif_priv);
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index a263d5c84c08..4f725473fb73 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -1047,7 +1047,8 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
status.flag = 0;
status.band = IEEE80211_BAND_2GHZ;
status.freq = ieee80211_channel_to_frequency(rx_desc->channel);
- ieee80211_rx_irqsafe(hw, skb, &status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx_irqsafe(hw, skb);
processed++;
}
@@ -2270,7 +2271,6 @@ static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw,
struct mwl8k_cmd_update_sta_db *cmd;
struct peer_capability_info *peer_info;
struct ieee80211_rate *bitrates = mv_vif->legacy_rates;
- DECLARE_MAC_BUF(mac);
int rc;
__u8 count, *rates;
@@ -3479,7 +3479,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
{
struct ieee80211_hw *hw;
struct mwl8k_priv *priv;
- DECLARE_MAC_BUF(mac);
int rc;
int i;
u8 *fw;
@@ -3668,8 +3667,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
MWL8K_DESC);
printk(KERN_INFO "%s: Driver Ver:%s Firmware Ver:%u.%u.%u.%u\n",
priv->name, MWL8K_VERSION, fw[3], fw[2], fw[1], fw[0]);
- printk(KERN_INFO "%s: MAC Address: %s\n", priv->name,
- print_mac(mac, hw->wiphy->perm_addr));
+ printk(KERN_INFO "%s: MAC Address: %pM\n", priv->name,
+ hw->wiphy->perm_addr);
return 0;
diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c
index d63c8992f229..712f26eef35d 100644
--- a/drivers/net/wireless/netwave_cs.c
+++ b/drivers/net/wireless/netwave_cs.c
@@ -1047,7 +1047,7 @@ static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) {
}
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} /* netwave_start_xmit */
/*
diff --git a/drivers/net/wireless/orinoco/Kconfig b/drivers/net/wireless/orinoco/Kconfig
index 44411eb4e91b..83b635fd7784 100644
--- a/drivers/net/wireless/orinoco/Kconfig
+++ b/drivers/net/wireless/orinoco/Kconfig
@@ -1,6 +1,7 @@
config HERMES
tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)"
depends on (PPC_PMAC || PCI || PCMCIA) && WLAN_80211
+ depends on CFG80211
select WIRELESS_EXT
select FW_LOADER
select CRYPTO
diff --git a/drivers/net/wireless/orinoco/Makefile b/drivers/net/wireless/orinoco/Makefile
index 1fc7409d6699..9abd6329bcbd 100644
--- a/drivers/net/wireless/orinoco/Makefile
+++ b/drivers/net/wireless/orinoco/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for the orinoco wireless device drivers.
#
-orinoco-objs := main.o fw.o hw.o mic.o scan.o wext.o hermes_dld.o hermes.o
+orinoco-objs := main.o fw.o hw.o mic.o scan.o wext.o hermes_dld.o hermes.o cfg.o
obj-$(CONFIG_HERMES) += orinoco.o
obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o
diff --git a/drivers/net/wireless/orinoco/airport.c b/drivers/net/wireless/orinoco/airport.c
index 8c4065f1b0d0..c60df2c1aca3 100644
--- a/drivers/net/wireless/orinoco/airport.c
+++ b/drivers/net/wireless/orinoco/airport.c
@@ -27,6 +27,7 @@
struct airport {
struct macio_dev *mdev;
void __iomem *vaddr;
+ unsigned int irq;
int irq_requested;
int ndev_registered;
};
@@ -34,8 +35,9 @@ struct airport {
static int
airport_suspend(struct macio_dev *mdev, pm_message_t state)
{
- struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
+ struct net_device *dev = priv->ndev;
+ struct airport *card = priv->card;
unsigned long flags;
int err;
@@ -48,18 +50,10 @@ airport_suspend(struct macio_dev *mdev, pm_message_t state)
return 0;
}
- err = __orinoco_down(dev);
- if (err)
- printk(KERN_WARNING "%s: PBOOK_SLEEP_NOW: Error %d downing interface\n",
- dev->name, err);
-
- netif_device_detach(dev);
-
- priv->hw_unavailable++;
-
+ orinoco_down(priv);
orinoco_unlock(priv, &flags);
- disable_irq(dev->irq);
+ disable_irq(card->irq);
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
macio_get_of_node(mdev), 0, 0);
@@ -69,8 +63,9 @@ airport_suspend(struct macio_dev *mdev, pm_message_t state)
static int
airport_resume(struct macio_dev *mdev)
{
- struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
+ struct net_device *dev = priv->ndev;
+ struct airport *card = priv->card;
unsigned long flags;
int err;
@@ -80,47 +75,27 @@ airport_resume(struct macio_dev *mdev)
macio_get_of_node(mdev), 0, 1);
msleep(200);
- enable_irq(dev->irq);
-
- err = orinoco_reinit_firmware(dev);
- if (err) {
- printk(KERN_ERR "%s: Error %d re-initializing firmware on PBOOK_WAKE\n",
- dev->name, err);
- return 0;
- }
+ enable_irq(card->irq);
spin_lock_irqsave(&priv->lock, flags);
-
- netif_device_attach(dev);
-
- priv->hw_unavailable--;
-
- if (priv->open && (!priv->hw_unavailable)) {
- err = __orinoco_up(dev);
- if (err)
- printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n",
- dev->name, err);
- }
-
-
+ err = orinoco_up(priv);
spin_unlock_irqrestore(&priv->lock, flags);
- return 0;
+ return err;
}
static int
airport_detach(struct macio_dev *mdev)
{
- struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
struct airport *card = priv->card;
if (card->ndev_registered)
- unregister_netdev(dev);
+ orinoco_if_del(priv);
card->ndev_registered = 0;
if (card->irq_requested)
- free_irq(dev->irq, dev);
+ free_irq(card->irq, priv);
card->irq_requested = 0;
if (card->vaddr)
@@ -134,7 +109,7 @@ airport_detach(struct macio_dev *mdev)
ssleep(1);
macio_set_drvdata(mdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
return 0;
}
@@ -146,7 +121,6 @@ static int airport_hard_reset(struct orinoco_private *priv)
* re-initialize properly, it falls in a screaming heap
* shortly afterwards. */
#if 0
- struct net_device *dev = priv->ndev;
struct airport *card = priv->card;
/* Vitally important. If we don't do this it seems we get an
@@ -154,7 +128,7 @@ static int airport_hard_reset(struct orinoco_private *priv)
* hw_unavailable is already set it doesn't get ACKed, we get
* into an interrupt loop and the PMU decides to turn us
* off. */
- disable_irq(dev->irq);
+ disable_irq(card->irq);
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
macio_get_of_node(card->mdev), 0, 0);
@@ -163,7 +137,7 @@ static int airport_hard_reset(struct orinoco_private *priv)
macio_get_of_node(card->mdev), 0, 1);
ssleep(1);
- enable_irq(dev->irq);
+ enable_irq(card->irq);
ssleep(1);
#endif
@@ -174,7 +148,6 @@ static int
airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
{
struct orinoco_private *priv;
- struct net_device *dev;
struct airport *card;
unsigned long phys_addr;
hermes_t *hw;
@@ -185,33 +158,29 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
}
/* Allocate space for private device-specific data */
- dev = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev,
- airport_hard_reset, NULL);
- if (!dev) {
+ priv = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev,
+ airport_hard_reset, NULL);
+ if (!priv) {
printk(KERN_ERR PFX "Cannot allocate network device\n");
return -ENODEV;
}
- priv = netdev_priv(dev);
card = priv->card;
hw = &priv->hw;
card->mdev = mdev;
- if (macio_request_resource(mdev, 0, "airport")) {
+ if (macio_request_resource(mdev, 0, DRIVER_NAME)) {
printk(KERN_ERR PFX "can't request IO resource !\n");
- free_orinocodev(dev);
+ free_orinocodev(priv);
return -EBUSY;
}
- SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
-
- macio_set_drvdata(mdev, dev);
+ macio_set_drvdata(mdev, priv);
/* Setup interrupts & base address */
- dev->irq = macio_irq(mdev, 0);
+ card->irq = macio_irq(mdev, 0);
phys_addr = macio_resource_start(mdev, 0); /* Physical address */
printk(KERN_DEBUG PFX "Physical address %lx\n", phys_addr);
- dev->base_addr = phys_addr;
card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN);
if (!card->vaddr) {
printk(KERN_ERR PFX "ioremap() failed\n");
@@ -228,18 +197,23 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
/* Reset it before we get the interrupt */
hermes_init(hw);
- if (request_irq(dev->irq, orinoco_interrupt, 0, dev->name, dev)) {
- printk(KERN_ERR PFX "Couldn't get IRQ %d\n", dev->irq);
+ if (request_irq(card->irq, orinoco_interrupt, 0, DRIVER_NAME, priv)) {
+ printk(KERN_ERR PFX "Couldn't get IRQ %d\n", card->irq);
goto failed;
}
card->irq_requested = 1;
- /* Tell the stack we exist */
- if (register_netdev(dev) != 0) {
- printk(KERN_ERR PFX "register_netdev() failed\n");
+ /* Initialise the main driver */
+ if (orinoco_init(priv) != 0) {
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
+ goto failed;
+ }
+
+ /* Register an interface with the stack */
+ if (orinoco_if_add(priv, phys_addr, card->irq) != 0) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
goto failed;
}
- printk(KERN_DEBUG PFX "Card registered for interface %s\n", dev->name);
card->ndev_registered = 1;
return 0;
failed:
diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c
new file mode 100644
index 000000000000..1a87d3a0967c
--- /dev/null
+++ b/drivers/net/wireless/orinoco/cfg.c
@@ -0,0 +1,162 @@
+/* cfg80211 support
+ *
+ * See copyright notice in main.c
+ */
+#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
+#include "hw.h"
+#include "main.h"
+#include "orinoco.h"
+
+#include "cfg.h"
+
+/* Supported bitrates. Must agree with hw.c */
+static struct ieee80211_rate orinoco_rates[] = {
+ { .bitrate = 10 },
+ { .bitrate = 20 },
+ { .bitrate = 55 },
+ { .bitrate = 110 },
+};
+
+static const void * const orinoco_wiphy_privid = &orinoco_wiphy_privid;
+
+/* Called after orinoco_private is allocated. */
+void orinoco_wiphy_init(struct wiphy *wiphy)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+
+ wiphy->privid = orinoco_wiphy_privid;
+
+ set_wiphy_dev(wiphy, priv->dev);
+}
+
+/* Called after firmware is initialised */
+int orinoco_wiphy_register(struct wiphy *wiphy)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+ int i, channels = 0;
+
+ if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
+ wiphy->max_scan_ssids = 1;
+ else
+ wiphy->max_scan_ssids = 0;
+
+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+
+ /* TODO: should we set if we only have demo ad-hoc?
+ * (priv->has_port3)
+ */
+ if (priv->has_ibss)
+ wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
+
+ if (!priv->broken_monitor || force_monitor)
+ wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
+
+ priv->band.bitrates = orinoco_rates;
+ priv->band.n_bitrates = ARRAY_SIZE(orinoco_rates);
+
+ /* Only support channels allowed by the card EEPROM */
+ for (i = 0; i < NUM_CHANNELS; i++) {
+ if (priv->channel_mask & (1 << i)) {
+ priv->channels[i].center_freq =
+ ieee80211_dsss_chan_to_freq(i+1);
+ channels++;
+ }
+ }
+ priv->band.channels = priv->channels;
+ priv->band.n_channels = channels;
+
+ wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
+ wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+
+ i = 0;
+ if (priv->has_wep) {
+ priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP40;
+ i++;
+
+ if (priv->has_big_wep) {
+ priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP104;
+ i++;
+ }
+ }
+ if (priv->has_wpa) {
+ priv->cipher_suites[i] = WLAN_CIPHER_SUITE_TKIP;
+ i++;
+ }
+ wiphy->cipher_suites = priv->cipher_suites;
+ wiphy->n_cipher_suites = i;
+
+ wiphy->rts_threshold = priv->rts_thresh;
+ if (!priv->has_mwo)
+ wiphy->frag_threshold = priv->frag_thresh;
+
+ return wiphy_register(wiphy);
+}
+
+static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+ int err = 0;
+ unsigned long lock;
+
+ if (orinoco_lock(priv, &lock) != 0)
+ return -EBUSY;
+
+ switch (type) {
+ case NL80211_IFTYPE_ADHOC:
+ if (!priv->has_ibss && !priv->has_port3)
+ err = -EINVAL;
+ break;
+
+ case NL80211_IFTYPE_STATION:
+ break;
+
+ case NL80211_IFTYPE_MONITOR:
+ if (priv->broken_monitor && !force_monitor) {
+ printk(KERN_WARNING "%s: Monitor mode support is "
+ "buggy in this firmware, not enabling\n",
+ wiphy_name(wiphy));
+ err = -EINVAL;
+ }
+ break;
+
+ default:
+ err = -EINVAL;
+ }
+
+ if (!err) {
+ priv->iw_mode = type;
+ set_port_type(priv);
+ err = orinoco_commit(priv);
+ }
+
+ orinoco_unlock(priv, &lock);
+
+ return err;
+}
+
+static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_scan_request *request)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+ int err;
+
+ if (!request)
+ return -EINVAL;
+
+ if (priv->scan_request && priv->scan_request != request)
+ return -EBUSY;
+
+ priv->scan_request = request;
+
+ err = orinoco_hw_trigger_scan(priv, request->ssids);
+
+ return err;
+}
+
+const struct cfg80211_ops orinoco_cfg_ops = {
+ .change_virtual_intf = orinoco_change_vif,
+ .scan = orinoco_scan,
+};
diff --git a/drivers/net/wireless/orinoco/cfg.h b/drivers/net/wireless/orinoco/cfg.h
new file mode 100644
index 000000000000..3ddc96a06cd7
--- /dev/null
+++ b/drivers/net/wireless/orinoco/cfg.h
@@ -0,0 +1,15 @@
+/* cfg80211 support.
+ *
+ * See copyright notice in main.c
+ */
+#ifndef ORINOCO_CFG_H
+#define ORINOCO_CFG_H
+
+#include <net/cfg80211.h>
+
+extern const struct cfg80211_ops orinoco_cfg_ops;
+
+void orinoco_wiphy_init(struct wiphy *wiphy);
+int orinoco_wiphy_register(struct wiphy *wiphy);
+
+#endif /* ORINOCO_CFG_H */
diff --git a/drivers/net/wireless/orinoco/fw.c b/drivers/net/wireless/orinoco/fw.c
index 1084b43e04bc..1257250a1e22 100644
--- a/drivers/net/wireless/orinoco/fw.c
+++ b/drivers/net/wireless/orinoco/fw.c
@@ -4,6 +4,7 @@
*/
#include <linux/kernel.h>
#include <linux/firmware.h>
+#include <linux/device.h>
#include "hermes.h"
#include "hermes_dld.h"
@@ -99,7 +100,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
const void *end;
const char *firmware;
const char *fw_err;
- struct net_device *dev = priv->ndev;
+ struct device *dev = priv->dev;
int err = 0;
pda = kzalloc(fw->pda_size, GFP_KERNEL);
@@ -111,12 +112,11 @@ orinoco_dl_firmware(struct orinoco_private *priv,
else
firmware = fw->sta_fw;
- printk(KERN_DEBUG "%s: Attempting to download firmware %s\n",
- dev->name, firmware);
+ 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);
- printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err);
+ dev_dbg(dev, "Read PDA returned %d\n", err);
if (err)
goto free;
@@ -124,8 +124,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
err = request_firmware(&fw_entry, firmware, priv->dev);
if (err) {
- printk(KERN_ERR "%s: Cannot find firmware %s\n",
- dev->name, firmware);
+ dev_err(dev, "Cannot find firmware %s\n", firmware);
err = -ENOENT;
goto free;
}
@@ -136,16 +135,15 @@ orinoco_dl_firmware(struct orinoco_private *priv,
fw_err = validate_fw(hdr, fw_entry->size);
if (fw_err) {
- printk(KERN_WARNING "%s: Invalid firmware image detected (%s). "
- "Aborting download\n",
- dev->name, fw_err);
+ dev_warn(dev, "Invalid firmware image detected (%s). "
+ "Aborting download\n", fw_err);
err = -EINVAL;
goto abort;
}
/* Enable aux port to allow programming */
err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point));
- printk(KERN_DEBUG "%s: Program init returned %d\n", dev->name, err);
+ dev_dbg(dev, "Program init returned %d\n", err);
if (err != 0)
goto abort;
@@ -156,7 +154,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
end = fw_entry->data + fw_entry->size;
err = hermes_program(hw, first_block, end);
- printk(KERN_DEBUG "%s: Program returned %d\n", dev->name, err);
+ dev_dbg(dev, "Program returned %d\n", err);
if (err != 0)
goto abort;
@@ -167,19 +165,18 @@ orinoco_dl_firmware(struct orinoco_private *priv,
err = hermes_apply_pda_with_defaults(hw, first_block, end, pda,
&pda[fw->pda_size / sizeof(*pda)]);
- printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err);
+ dev_dbg(dev, "Apply PDA returned %d\n", err);
if (err)
goto abort;
/* Tell card we've finished */
err = hermesi_program_end(hw);
- printk(KERN_DEBUG "%s: Program end returned %d\n", dev->name, err);
+ dev_dbg(dev, "Program end returned %d\n", err);
if (err != 0)
goto abort;
/* Check if we're running */
- printk(KERN_DEBUG "%s: hermes_present returned %d\n",
- dev->name, hermes_present(hw));
+ dev_dbg(dev, "hermes_present returned %d\n", hermes_present(hw));
abort:
/* If we requested the firmware, release it. */
@@ -282,14 +279,13 @@ static int
symbol_dl_firmware(struct orinoco_private *priv,
const struct fw_info *fw)
{
- struct net_device *dev = priv->ndev;
+ struct device *dev = priv->dev;
int ret;
const struct firmware *fw_entry;
if (!orinoco_cached_fw_get(priv, true)) {
if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) {
- printk(KERN_ERR "%s: Cannot find firmware: %s\n",
- dev->name, fw->pri_fw);
+ dev_err(dev, "Cannot find firmware: %s\n", fw->pri_fw);
return -ENOENT;
}
} else
@@ -302,15 +298,13 @@ symbol_dl_firmware(struct orinoco_private *priv,
if (!orinoco_cached_fw_get(priv, true))
release_firmware(fw_entry);
if (ret) {
- printk(KERN_ERR "%s: Primary firmware download failed\n",
- dev->name);
+ dev_err(dev, "Primary firmware download failed\n");
return ret;
}
if (!orinoco_cached_fw_get(priv, false)) {
if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) {
- printk(KERN_ERR "%s: Cannot find firmware: %s\n",
- dev->name, fw->sta_fw);
+ dev_err(dev, "Cannot find firmware: %s\n", fw->sta_fw);
return -ENOENT;
}
} else
@@ -322,8 +316,7 @@ symbol_dl_firmware(struct orinoco_private *priv,
if (!orinoco_cached_fw_get(priv, false))
release_firmware(fw_entry);
if (ret) {
- printk(KERN_ERR "%s: Secondary firmware download failed\n",
- dev->name);
+ dev_err(dev, "Secondary firmware download failed\n");
}
return ret;
diff --git a/drivers/net/wireless/orinoco/hermes.c b/drivers/net/wireless/orinoco/hermes.c
index f2c918c2572d..1a2fca76fd3c 100644
--- a/drivers/net/wireless/orinoco/hermes.c
+++ b/drivers/net/wireless/orinoco/hermes.c
@@ -469,7 +469,7 @@ int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize,
u16 rlength, rtype;
unsigned nwords;
- if ((bufsize < 0) || (bufsize % 2))
+ if (bufsize % 2)
return -EINVAL;
err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
diff --git a/drivers/net/wireless/orinoco/hermes.h b/drivers/net/wireless/orinoco/hermes.h
index c78c442a02c8..2dddbb597c4d 100644
--- a/drivers/net/wireless/orinoco/hermes.h
+++ b/drivers/net/wireless/orinoco/hermes.h
@@ -342,7 +342,7 @@ struct agere_ext_scan_info {
__le64 timestamp;
__le16 beacon_interval;
__le16 capabilities;
- u8 data[316];
+ u8 data[0];
} __attribute__ ((packed));
#define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000)
diff --git a/drivers/net/wireless/orinoco/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c
index a9ba195cdada..a3eefe109df4 100644
--- a/drivers/net/wireless/orinoco/hermes_dld.c
+++ b/drivers/net/wireless/orinoco/hermes_dld.c
@@ -309,7 +309,7 @@ int hermes_read_pda(hermes_t *hw,
/* Open auxiliary port */
ret = hermes_aux_control(hw, 1);
- printk(KERN_DEBUG PFX "AUX enable returned %d\n", ret);
+ pr_debug(PFX "AUX enable returned %d\n", ret);
if (ret)
return ret;
@@ -319,12 +319,12 @@ int hermes_read_pda(hermes_t *hw,
/* Close aux port */
ret = hermes_aux_control(hw, 0);
- printk(KERN_DEBUG PFX "AUX disable returned %d\n", ret);
+ pr_debug(PFX "AUX disable returned %d\n", ret);
/* Check PDA length */
pda_size = le16_to_cpu(pda[0]);
- printk(KERN_DEBUG PFX "Actual PDA length %d, Max allowed %d\n",
- pda_size, pda_len);
+ pr_debug(PFX "Actual PDA length %d, Max allowed %d\n",
+ pda_size, pda_len);
if (pda_size > pda_len)
return -EINVAL;
@@ -422,20 +422,19 @@ int hermesi_program_init(hermes_t *hw, u32 offset)
return err;
err = hermes_aux_control(hw, 1);
- printk(KERN_DEBUG PFX "AUX enable returned %d\n", err);
+ pr_debug(PFX "AUX enable returned %d\n", err);
if (err)
return err;
- printk(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset);
+ pr_debug(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset);
err = hermes_doicmd_wait(hw,
HERMES_PROGRAM_ENABLE_VOLATILE,
offset & 0xFFFFu,
offset >> 16,
0,
NULL);
- printk(KERN_DEBUG PFX "PROGRAM_ENABLE returned %d\n",
- err);
+ pr_debug(PFX "PROGRAM_ENABLE returned %d\n", err);
return err;
}
@@ -454,16 +453,16 @@ int hermesi_program_end(hermes_t *hw)
rc = hermes_docmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
- printk(KERN_DEBUG PFX "PROGRAM_DISABLE returned %d, "
- "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
- rc, resp.resp0, resp.resp1, resp.resp2);
+ 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);
- printk(KERN_DEBUG PFX "AUX disable returned %d\n", err);
+ pr_debug(PFX "AUX disable returned %d\n", err);
/* Acknowledge any outstanding command */
hermes_write_regn(hw, EVACK, 0xFFFF);
@@ -496,9 +495,8 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end)
while ((blkaddr != BLOCK_END) &&
(((void *) blk + blklen) <= end)) {
- printk(KERN_DEBUG PFX
- "Programming block of length %d to address 0x%08x\n",
- blklen, blkaddr);
+ 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 */
@@ -510,10 +508,9 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end)
addr = blkaddr;
while (addr < (blkaddr + blklen)) {
- printk(KERN_DEBUG PFX
- "Programming subblock of length %d "
- "to address 0x%08x. Data @ %p\n",
- len, addr, &blk->data[addr - blkaddr]);
+ 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,
@@ -643,8 +640,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
pdi = hermes_find_pdi(first_pdi, record_id, pda_end);
if (pdi)
- printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n",
- record_id, pdi);
+ pr_debug(PFX "Found record 0x%04x at %p\n",
+ record_id, pdi);
switch (record_id) {
case 0x110: /* Modem REFDAC values */
@@ -654,9 +651,9 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
default_pdi = NULL;
if (outdoor_pdi) {
pdi = outdoor_pdi;
- printk(KERN_DEBUG PFX
- "Using outdoor record 0x%04x at %p\n",
- record_id + 1, pdi);
+ pr_debug(PFX
+ "Using outdoor record 0x%04x at %p\n",
+ record_id + 1, pdi);
}
break;
case 0x5: /* HWIF Compatiblity */
@@ -684,9 +681,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
if (!pdi && default_pdi) {
/* Use default */
pdi = default_pdi;
- printk(KERN_DEBUG PFX
- "Using default record 0x%04x at %p\n",
- record_id, pdi);
+ pr_debug(PFX "Using default record 0x%04x at %p\n",
+ record_id, pdi);
}
if (pdi) {
diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c
index 632fac86a308..fa508af1a351 100644
--- a/drivers/net/wireless/orinoco/hw.c
+++ b/drivers/net/wireless/orinoco/hw.c
@@ -3,16 +3,22 @@
* See copyright notice in main.c
*/
#include <linux/kernel.h>
+#include <linux/device.h>
#include <linux/if_arp.h>
#include <linux/ieee80211.h>
#include <linux/wireless.h>
-
+#include <net/cfg80211.h>
#include "hermes.h"
#include "hermes_rid.h"
#include "orinoco.h"
#include "hw.h"
+#define SYMBOL_MAX_VER_LEN (14)
+
+/* Symbol firmware has a bug allocating buffers larger than this */
+#define TX_NICBUF_SIZE_BUG 1585
+
/********************************************************************/
/* Data tables */
/********************************************************************/
@@ -36,6 +42,343 @@ static const struct {
};
#define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table)
+/* Firmware version encoding */
+struct comp_id {
+ u16 id, variant, major, minor;
+} __attribute__ ((packed));
+
+static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
+{
+ if (nic_id->id < 0x8000)
+ return FIRMWARE_TYPE_AGERE;
+ else if (nic_id->id == 0x8000 && nic_id->major == 0)
+ return FIRMWARE_TYPE_SYMBOL;
+ else
+ return FIRMWARE_TYPE_INTERSIL;
+}
+
+/* Set priv->firmware type, determine firmware properties
+ * This function can be called before we have registerred with netdev,
+ * so all errors go out with dev_* rather than printk
+ */
+int determine_fw_capabilities(struct orinoco_private *priv)
+{
+ struct device *dev = priv->dev;
+ hermes_t *hw = &priv->hw;
+ int err;
+ struct comp_id nic_id, sta_id;
+ unsigned int firmver;
+ char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2)));
+
+ /* Get the hardware version */
+ err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
+ if (err) {
+ dev_err(dev, "Cannot read hardware identity: error %d\n",
+ err);
+ return err;
+ }
+
+ le16_to_cpus(&nic_id.id);
+ le16_to_cpus(&nic_id.variant);
+ le16_to_cpus(&nic_id.major);
+ le16_to_cpus(&nic_id.minor);
+ dev_info(dev, "Hardware identity %04x:%04x:%04x:%04x\n",
+ nic_id.id, nic_id.variant, nic_id.major, nic_id.minor);
+
+ priv->firmware_type = determine_firmware_type(&nic_id);
+
+ /* Get the firmware version */
+ err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
+ if (err) {
+ dev_err(dev, "Cannot read station identity: error %d\n",
+ err);
+ return err;
+ }
+
+ le16_to_cpus(&sta_id.id);
+ le16_to_cpus(&sta_id.variant);
+ le16_to_cpus(&sta_id.major);
+ le16_to_cpus(&sta_id.minor);
+ dev_info(dev, "Station identity %04x:%04x:%04x:%04x\n",
+ sta_id.id, sta_id.variant, sta_id.major, sta_id.minor);
+
+ switch (sta_id.id) {
+ case 0x15:
+ dev_err(dev, "Primary firmware is active\n");
+ return -ENODEV;
+ case 0x14b:
+ dev_err(dev, "Tertiary firmware is active\n");
+ return -ENODEV;
+ case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */
+ case 0x21: /* Symbol Spectrum24 Trilogy */
+ break;
+ default:
+ dev_notice(dev, "Unknown station ID, please report\n");
+ break;
+ }
+
+ /* Default capabilities */
+ priv->has_sensitivity = 1;
+ priv->has_mwo = 0;
+ priv->has_preamble = 0;
+ priv->has_port3 = 1;
+ priv->has_ibss = 1;
+ priv->has_wep = 0;
+ priv->has_big_wep = 0;
+ priv->has_alt_txcntl = 0;
+ priv->has_ext_scan = 0;
+ priv->has_wpa = 0;
+ priv->do_fw_download = 0;
+
+ /* Determine capabilities from the firmware version */
+ switch (priv->firmware_type) {
+ case FIRMWARE_TYPE_AGERE:
+ /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
+ ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
+ snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+ "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor);
+
+ firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
+
+ priv->has_ibss = (firmver >= 0x60006);
+ priv->has_wep = (firmver >= 0x40020);
+ priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
+ Gold cards from the others? */
+ priv->has_mwo = (firmver >= 0x60000);
+ priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
+ priv->ibss_port = 1;
+ priv->has_hostscan = (firmver >= 0x8000a);
+ priv->do_fw_download = 1;
+ priv->broken_monitor = (firmver >= 0x80000);
+ priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */
+ priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */
+ priv->has_wpa = (firmver >= 0x9002a);
+ /* Tested with Agere firmware :
+ * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
+ * Tested CableTron firmware : 4.32 => Anton */
+ break;
+ case FIRMWARE_TYPE_SYMBOL:
+ /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
+ /* Intel MAC : 00:02:B3:* */
+ /* 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);
+ if (err) {
+ dev_warn(dev, "Error %d reading Symbol firmware info. "
+ "Wildly guessing capabilities...\n", err);
+ firmver = 0;
+ tmp[0] = '\0';
+ } else {
+ /* The firmware revision is a string, the format is
+ * something like : "V2.20-01".
+ * Quick and dirty parsing... - Jean II
+ */
+ firmver = ((tmp[1] - '0') << 16)
+ | ((tmp[3] - '0') << 12)
+ | ((tmp[4] - '0') << 8)
+ | ((tmp[6] - '0') << 4)
+ | (tmp[7] - '0');
+
+ tmp[SYMBOL_MAX_VER_LEN] = '\0';
+ }
+
+ snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+ "Symbol %s", tmp);
+
+ priv->has_ibss = (firmver >= 0x20000);
+ priv->has_wep = (firmver >= 0x15012);
+ priv->has_big_wep = (firmver >= 0x20000);
+ priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) ||
+ (firmver >= 0x29000 && firmver < 0x30000) ||
+ firmver >= 0x31000;
+ priv->has_preamble = (firmver >= 0x20000);
+ priv->ibss_port = 4;
+
+ /* Symbol firmware is found on various cards, but
+ * there has been no attempt to check firmware
+ * download on non-spectrum_cs based cards.
+ *
+ * Given that the Agere firmware download works
+ * differently, we should avoid doing a firmware
+ * download with the Symbol algorithm on non-spectrum
+ * cards.
+ *
+ * For now we can identify a spectrum_cs based card
+ * because it has a firmware reset function.
+ */
+ priv->do_fw_download = (priv->stop_fw != NULL);
+
+ priv->broken_disableport = (firmver == 0x25013) ||
+ (firmver >= 0x30000 && firmver <= 0x31000);
+ priv->has_hostscan = (firmver >= 0x31001) ||
+ (firmver >= 0x29057 && firmver < 0x30000);
+ /* Tested with Intel firmware : 0x20015 => Jean II */
+ /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
+ break;
+ case FIRMWARE_TYPE_INTERSIL:
+ /* D-Link, Linksys, Adtron, ZoomAir, and many others...
+ * Samsung, Compaq 100/200 and Proxim are slightly
+ * different and less well tested */
+ /* D-Link MAC : 00:40:05:* */
+ /* Addtron MAC : 00:90:D1:* */
+ snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+ "Intersil %d.%d.%d", sta_id.major, sta_id.minor,
+ sta_id.variant);
+
+ firmver = ((unsigned long)sta_id.major << 16) |
+ ((unsigned long)sta_id.minor << 8) | sta_id.variant;
+
+ priv->has_ibss = (firmver >= 0x000700); /* FIXME */
+ priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
+ priv->has_pm = (firmver >= 0x000700);
+ priv->has_hostscan = (firmver >= 0x010301);
+
+ if (firmver >= 0x000800)
+ priv->ibss_port = 0;
+ else {
+ dev_notice(dev, "Intersil firmware earlier than v0.8.x"
+ " - several features not supported\n");
+ priv->ibss_port = 1;
+ }
+ break;
+ }
+ dev_info(dev, "Firmware determined as %s\n", priv->fw_name);
+
+ return 0;
+}
+
+/* Read settings from EEPROM into our private structure.
+ * MAC address gets dropped into callers buffer
+ * Can be called before netdev registration.
+ */
+int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
+{
+ struct device *dev = priv->dev;
+ struct hermes_idstring nickbuf;
+ hermes_t *hw = &priv->hw;
+ int len;
+ int err;
+ u16 reclen;
+
+ /* Get the MAC address */
+ err = hermes_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;
+ }
+
+ 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);
+ if (err) {
+ dev_err(dev, "failed to read station name\n");
+ goto out;
+ }
+ if (nickbuf.len)
+ len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len));
+ else
+ len = min(IW_ESSID_MAX_SIZE, 2 * reclen);
+ memcpy(priv->nick, &nickbuf.val, len);
+ priv->nick[len] = '\0';
+
+ dev_dbg(dev, "Station name \"%s\"\n", priv->nick);
+
+ /* Get allowed channels */
+ err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST,
+ &priv->channel_mask);
+ if (err) {
+ dev_err(dev, "Failed to read channel list!\n");
+ goto out;
+ }
+
+ /* Get initial AP density */
+ err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
+ &priv->ap_density);
+ if (err || priv->ap_density < 1 || priv->ap_density > 3)
+ priv->has_sensitivity = 0;
+
+ /* Get initial RTS threshold */
+ err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
+ &priv->rts_thresh);
+ if (err) {
+ dev_err(dev, "Failed to read RTS threshold!\n");
+ goto out;
+ }
+
+ /* Get initial fragmentation settings */
+ if (priv->has_mwo)
+ err = hermes_read_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFMWOROBUST_AGERE,
+ &priv->mwo_robust);
+ else
+ err = hermes_read_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
+ &priv->frag_thresh);
+ if (err) {
+ dev_err(dev, "Failed to read fragmentation settings!\n");
+ goto out;
+ }
+
+ /* Power management setup */
+ if (priv->has_pm) {
+ priv->pm_on = 0;
+ priv->pm_mcast = 1;
+ err = hermes_read_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFMAXSLEEPDURATION,
+ &priv->pm_period);
+ if (err) {
+ dev_err(dev, "Failed to read power management "
+ "period!\n");
+ goto out;
+ }
+ err = hermes_read_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFPMHOLDOVERDURATION,
+ &priv->pm_timeout);
+ if (err) {
+ dev_err(dev, "Failed to read power management "
+ "timeout!\n");
+ goto out;
+ }
+ }
+
+ /* Preamble setup */
+ if (priv->has_preamble) {
+ err = hermes_read_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFPREAMBLE_SYMBOL,
+ &priv->preamble);
+ }
+
+out:
+ return err;
+}
+
+/* Can be called before netdev registration */
+int orinoco_hw_allocate_fid(struct orinoco_private *priv)
+{
+ struct device *dev = priv->dev;
+ struct hermes *hw = &priv->hw;
+ int err;
+
+ err = hermes_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);
+
+ dev_warn(dev, "Firmware ALLOC bug detected "
+ "(old Symbol firmware?). Work around %s\n",
+ err ? "failed!" : "ok.");
+ }
+
+ return err;
+}
+
int orinoco_get_bitratemode(int bitrate, int automatic)
{
int ratemode = -1;
@@ -63,6 +406,237 @@ void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic)
*automatic = bitrate_table[ratemode].automatic;
}
+int orinoco_hw_program_rids(struct orinoco_private *priv)
+{
+ struct net_device *dev = priv->ndev;
+ struct wireless_dev *wdev = netdev_priv(dev);
+ hermes_t *hw = &priv->hw;
+ int err;
+ 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);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting MAC address\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set up the link mode */
+ err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE,
+ priv->port_type);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting port type\n",
+ dev->name, err);
+ return err;
+ }
+ /* Set the channel/frequency */
+ if (priv->channel != 0 && priv->iw_mode != NL80211_IFTYPE_STATION) {
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFOWNCHANNEL,
+ priv->channel);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting channel %d\n",
+ dev->name, err, priv->channel);
+ return err;
+ }
+ }
+
+ if (priv->has_ibss) {
+ u16 createibss;
+
+ if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) {
+ printk(KERN_WARNING "%s: This firmware requires an "
+ "ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
+ /* With wvlan_cs, in this case, we would crash.
+ * hopefully, this driver will behave better...
+ * Jean II */
+ createibss = 0;
+ } else {
+ createibss = priv->createibss;
+ }
+
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFCREATEIBSS,
+ createibss);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n",
+ dev->name, err);
+ return err;
+ }
+ }
+
+ /* Set the desired BSSID */
+ err = __orinoco_hw_set_wap(priv);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting AP address\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set the desired ESSID */
+ 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,
+ HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
+ &idbuf);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting OWNSSID\n",
+ dev->name, err);
+ return err;
+ }
+ err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
+ HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
+ &idbuf);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* 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);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting nickname\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set AP density */
+ if (priv->has_sensitivity) {
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFSYSTEMSCALE,
+ priv->ap_density);
+ if (err) {
+ printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. "
+ "Disabling sensitivity control\n",
+ dev->name, err);
+
+ priv->has_sensitivity = 0;
+ }
+ }
+
+ /* Set RTS threshold */
+ err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
+ priv->rts_thresh);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting RTS threshold\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set fragmentation threshold or MWO robustness */
+ if (priv->has_mwo)
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFMWOROBUST_AGERE,
+ priv->mwo_robust);
+ else
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
+ priv->frag_thresh);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting fragmentation\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set bitrate */
+ err = __orinoco_hw_set_bitrate(priv);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting bitrate\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set power management */
+ if (priv->has_pm) {
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFPMENABLED,
+ priv->pm_on);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting up PM\n",
+ dev->name, err);
+ return err;
+ }
+
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFMULTICASTRECEIVE,
+ priv->pm_mcast);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting up PM\n",
+ dev->name, err);
+ return err;
+ }
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFMAXSLEEPDURATION,
+ priv->pm_period);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting up PM\n",
+ dev->name, err);
+ return err;
+ }
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFPMHOLDOVERDURATION,
+ priv->pm_timeout);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting up PM\n",
+ dev->name, err);
+ return err;
+ }
+ }
+
+ /* Set preamble - only for Symbol so far... */
+ if (priv->has_preamble) {
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFPREAMBLE_SYMBOL,
+ priv->preamble);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting preamble\n",
+ dev->name, err);
+ return err;
+ }
+ }
+
+ /* Set up encryption */
+ if (priv->has_wep || priv->has_wpa) {
+ err = __orinoco_hw_setup_enc(priv);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d activating encryption\n",
+ dev->name, err);
+ return err;
+ }
+ }
+
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
+ /* Enable monitor mode */
+ dev->type = ARPHRD_IEEE80211;
+ err = hermes_docmd_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 |
+ HERMES_TEST_STOP, 0, NULL);
+ }
+ if (err)
+ return err;
+
+ /* Reset promiscuity / multicast*/
+ priv->promiscuous = 0;
+ priv->mc_count = 0;
+
+ /* Record mode change */
+ wdev->iftype = priv->iw_mode;
+
+ return 0;
+}
+
/* Get tsc from the firmware */
int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc)
{
@@ -314,7 +888,7 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv)
} else
master_wep_flag = 0;
- if (priv->iw_mode == IW_MODE_MONITOR)
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
master_wep_flag |= HERMES_WEP_HOST_DECRYPT;
/* Master WEP setting : on/off */
@@ -334,8 +908,8 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv)
* rsc must be 8 bytes
* tsc must be 8 bytes or NULL
*/
-int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
- u8 *key, u8 *rsc, u8 *tsc)
+int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
+ int set_tx, u8 *key, u8 *rsc, u8 *tsc)
{
struct {
__le16 idx;
@@ -345,6 +919,7 @@ int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
u8 rx_mic[MIC_KEYLEN];
u8 tsc[IW_ENCODE_SEQ_MAX_SIZE];
} __attribute__ ((packed)) buf;
+ hermes_t *hw = &priv->hw;
int ret;
int err;
int k;
@@ -582,3 +1157,88 @@ int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
return 0;
}
+
+int orinoco_hw_trigger_scan(struct orinoco_private *priv,
+ const struct cfg80211_ssid *ssid)
+{
+ struct net_device *dev = priv->ndev;
+ hermes_t *hw = &priv->hw;
+ unsigned long flags;
+ int err = 0;
+
+ if (orinoco_lock(priv, &flags) != 0)
+ return -EBUSY;
+
+ /* Scanning with port 0 disabled would fail */
+ if (!netif_running(dev)) {
+ err = -ENETDOWN;
+ goto out;
+ }
+
+ /* In monitor mode, the scan results are always empty.
+ * Probe responses are passed to the driver as received
+ * frames and could be processed in software. */
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (priv->has_hostscan) {
+ switch (priv->firmware_type) {
+ case FIRMWARE_TYPE_SYMBOL:
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFHOSTSCAN_SYMBOL,
+ HERMES_HOSTSCAN_SYMBOL_ONCE |
+ HERMES_HOSTSCAN_SYMBOL_BCAST);
+ break;
+ case FIRMWARE_TYPE_INTERSIL: {
+ __le16 req[3];
+
+ req[0] = cpu_to_le16(0x3fff); /* All channels */
+ req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */
+ req[2] = 0; /* Any ESSID */
+ err = HERMES_WRITE_RECORD(hw, USER_BAP,
+ HERMES_RID_CNFHOSTSCAN, &req);
+ break;
+ }
+ case FIRMWARE_TYPE_AGERE:
+ if (ssid->ssid_len > 0) {
+ struct hermes_idstring idbuf;
+ size_t len = ssid->ssid_len;
+
+ idbuf.len = cpu_to_le16(len);
+ memcpy(idbuf.val, ssid->ssid, len);
+
+ err = hermes_write_ltv(hw, USER_BAP,
+ HERMES_RID_CNFSCANSSID_AGERE,
+ HERMES_BYTES_TO_RECLEN(len + 2),
+ &idbuf);
+ } else
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFSCANSSID_AGERE,
+ 0); /* Any ESSID */
+ if (err)
+ break;
+
+ if (priv->has_ext_scan) {
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFSCANCHANNELS2GHZ,
+ 0x7FFF);
+ if (err)
+ goto out;
+
+ err = hermes_inquire(hw,
+ HERMES_INQ_CHANNELINFO);
+ } else
+ err = hermes_inquire(hw, HERMES_INQ_SCAN);
+
+ break;
+ }
+ } else
+ err = hermes_inquire(hw, HERMES_INQ_SCAN);
+
+ out:
+ orinoco_unlock(priv, &flags);
+
+ return err;
+}
diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h
index dc3f23a9c1c7..27b427649d1b 100644
--- a/drivers/net/wireless/orinoco/hw.h
+++ b/drivers/net/wireless/orinoco/hw.h
@@ -7,6 +7,7 @@
#include <linux/types.h>
#include <linux/wireless.h>
+#include <net/cfg80211.h>
/* Hardware BAPs */
#define USER_BAP 0
@@ -23,17 +24,21 @@
struct orinoco_private;
struct dev_addr_list;
+int determine_fw_capabilities(struct orinoco_private *priv);
+int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr);
+int orinoco_hw_allocate_fid(struct orinoco_private *priv);
int orinoco_get_bitratemode(int bitrate, int automatic);
void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic);
+int orinoco_hw_program_rids(struct orinoco_private *priv);
int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc);
int __orinoco_hw_set_bitrate(struct orinoco_private *priv);
int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate);
int __orinoco_hw_set_wap(struct orinoco_private *priv);
int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv);
int __orinoco_hw_setup_enc(struct orinoco_private *priv);
-int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
- u8 *key, u8 *rsc, u8 *tsc);
+int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
+ int set_tx, u8 *key, u8 *rsc, u8 *tsc);
int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx);
int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
struct dev_addr_list *mc_list,
@@ -43,5 +48,7 @@ int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
int orinoco_hw_get_freq(struct orinoco_private *priv);
int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
int *numrates, s32 *rates, int max);
+int orinoco_hw_trigger_scan(struct orinoco_private *priv,
+ const struct cfg80211_ssid *ssid);
#endif /* _ORINOCO_HW_H_ */
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index a370e510f19f..e8c550a61f33 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -80,6 +80,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/device.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
@@ -88,6 +89,7 @@
#include <linux/wireless.h>
#include <linux/ieee80211.h>
#include <net/iw_handler.h>
+#include <net/cfg80211.h>
#include "hermes_rid.h"
#include "hermes_dld.h"
@@ -96,6 +98,7 @@
#include "mic.h"
#include "fw.h"
#include "wext.h"
+#include "cfg.h"
#include "main.h"
#include "orinoco.h"
@@ -142,13 +145,11 @@ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
#define ORINOCO_MIN_MTU 256
#define ORINOCO_MAX_MTU (IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD)
-#define SYMBOL_MAX_VER_LEN (14)
#define MAX_IRQLOOPS_PER_IRQ 10
#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of
* how many events the
* device could
* legitimately generate */
-#define TX_NICBUF_SIZE_BUG 1585 /* Bug in Symbol firmware */
#define DUMMY_FID 0xFFFF
@@ -205,11 +206,21 @@ struct orinoco_rx_data {
struct list_head list;
};
+struct orinoco_scan_data {
+ void *buf;
+ size_t len;
+ int type;
+ struct list_head list;
+};
+
/********************************************************************/
/* Function prototypes */
/********************************************************************/
-static void __orinoco_set_multicast_list(struct net_device *dev);
+static int __orinoco_set_multicast_list(struct net_device *dev);
+static int __orinoco_up(struct orinoco_private *priv);
+static int __orinoco_down(struct orinoco_private *priv);
+static int __orinoco_commit(struct orinoco_private *priv);
/********************************************************************/
/* Internal helper functions */
@@ -218,11 +229,11 @@ static void __orinoco_set_multicast_list(struct net_device *dev);
void set_port_type(struct orinoco_private *priv)
{
switch (priv->iw_mode) {
- case IW_MODE_INFRA:
+ case NL80211_IFTYPE_STATION:
priv->port_type = 1;
priv->createibss = 0;
break;
- case IW_MODE_ADHOC:
+ case NL80211_IFTYPE_ADHOC:
if (priv->prefer_port3) {
priv->port_type = 3;
priv->createibss = 0;
@@ -231,7 +242,7 @@ void set_port_type(struct orinoco_private *priv)
priv->createibss = 1;
}
break;
- case IW_MODE_MONITOR:
+ case NL80211_IFTYPE_MONITOR:
priv->port_type = 3;
priv->createibss = 0;
break;
@@ -247,14 +258,14 @@ void set_port_type(struct orinoco_private *priv)
static int orinoco_open(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
unsigned long flags;
int err;
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
- err = __orinoco_up(dev);
+ err = __orinoco_up(priv);
if (!err)
priv->open = 1;
@@ -266,7 +277,7 @@ static int orinoco_open(struct net_device *dev)
static int orinoco_stop(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int err = 0;
/* We mustn't use orinoco_lock() here, because we need to be
@@ -276,7 +287,7 @@ static int orinoco_stop(struct net_device *dev)
priv->open = 0;
- err = __orinoco_down(dev);
+ err = __orinoco_down(priv);
spin_unlock_irq(&priv->lock);
@@ -285,14 +296,14 @@ static int orinoco_stop(struct net_device *dev)
static struct net_device_stats *orinoco_get_stats(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
return &priv->stats;
}
static void orinoco_set_multicast_list(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
unsigned long flags;
if (orinoco_lock(priv, &flags) != 0) {
@@ -307,7 +318,7 @@ static void orinoco_set_multicast_list(struct net_device *dev)
static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
if ((new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU))
return -EINVAL;
@@ -328,7 +339,7 @@ static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
hermes_t *hw = &priv->hw;
int err = 0;
@@ -355,7 +366,8 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_BUSY;
}
- if (!netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) {
+ 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). */
@@ -518,7 +530,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
u16 fid = hermes_read_regn(hw, ALLOCFID);
if (fid != priv->txfid) {
@@ -533,7 +545,7 @@ static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw)
static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
stats->tx_packets++;
@@ -545,7 +557,7 @@ static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw)
static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
u16 fid = hermes_read_regn(hw, TXCOMPLFID);
u16 status;
@@ -601,7 +613,7 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
static void orinoco_tx_timeout(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
struct hermes *hw = &priv->hw;
@@ -650,7 +662,7 @@ static void orinoco_stat_gather(struct net_device *dev,
struct sk_buff *skb,
struct hermes_rx_descriptor *desc)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
/* Using spy support with lots of Rx packets, like in an
* infrastructure (AP), will really slow down everything, because
@@ -687,7 +699,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
int err;
int len;
struct sk_buff *skb;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
hermes_t *hw = &priv->hw;
@@ -778,7 +790,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
struct iw_statistics *wstats = &priv->wstats;
struct sk_buff *skb = NULL;
@@ -816,7 +828,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
}
/* Handle frames in monitor mode */
- if (priv->iw_mode == IW_MODE_MONITOR) {
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
orinoco_rx_monitor(dev, rxfid, desc);
goto out;
}
@@ -902,7 +914,7 @@ static void orinoco_rx(struct net_device *dev,
struct hermes_rx_descriptor *desc,
struct sk_buff *skb)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
u16 status, fc;
int length;
@@ -1016,8 +1028,8 @@ static void orinoco_rx(struct net_device *dev,
static void orinoco_rx_isr_tasklet(unsigned long data)
{
- struct net_device *dev = (struct net_device *) data;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = (struct orinoco_private *) data;
+ struct net_device *dev = priv->ndev;
struct orinoco_rx_data *rx_data, *temp;
struct hermes_rx_descriptor *desc;
struct sk_buff *skb;
@@ -1260,9 +1272,81 @@ static void orinoco_send_wevents(struct work_struct *work)
orinoco_unlock(priv, &flags);
}
+static void qbuf_scan(struct orinoco_private *priv, void *buf,
+ int len, int type)
+{
+ struct orinoco_scan_data *sd;
+ unsigned long flags;
+
+ sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
+ sd->buf = buf;
+ sd->len = len;
+ sd->type = type;
+
+ spin_lock_irqsave(&priv->scan_lock, flags);
+ list_add_tail(&sd->list, &priv->scan_list);
+ spin_unlock_irqrestore(&priv->scan_lock, flags);
+
+ schedule_work(&priv->process_scan);
+}
+
+static void qabort_scan(struct orinoco_private *priv)
+{
+ struct orinoco_scan_data *sd;
+ unsigned long flags;
+
+ sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
+ sd->len = -1; /* Abort */
+
+ spin_lock_irqsave(&priv->scan_lock, flags);
+ list_add_tail(&sd->list, &priv->scan_list);
+ spin_unlock_irqrestore(&priv->scan_lock, flags);
+
+ schedule_work(&priv->process_scan);
+}
+
+static void orinoco_process_scan_results(struct work_struct *work)
+{
+ struct orinoco_private *priv =
+ container_of(work, struct orinoco_private, process_scan);
+ struct orinoco_scan_data *sd, *temp;
+ unsigned long flags;
+ void *buf;
+ int len;
+ int type;
+
+ spin_lock_irqsave(&priv->scan_lock, flags);
+ list_for_each_entry_safe(sd, temp, &priv->scan_list, list) {
+ spin_unlock_irqrestore(&priv->scan_lock, flags);
+
+ buf = sd->buf;
+ len = sd->len;
+ type = sd->type;
+
+ list_del(&sd->list);
+ kfree(sd);
+
+ if (len > 0) {
+ if (type == HERMES_INQ_CHANNELINFO)
+ orinoco_add_extscan_result(priv, buf, len);
+ else
+ orinoco_add_hostscan_results(priv, buf, len);
+
+ kfree(buf);
+ } else if (priv->scan_request) {
+ /* Either abort or complete the scan */
+ cfg80211_scan_done(priv->scan_request, (len < 0));
+ priv->scan_request = NULL;
+ }
+
+ spin_lock_irqsave(&priv->scan_lock, flags);
+ }
+ spin_unlock_irqrestore(&priv->scan_lock, flags);
+}
+
static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
u16 infofid;
struct {
__le16 len;
@@ -1327,7 +1411,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
u16 newstatus;
int connected;
- if (priv->iw_mode == IW_MODE_MONITOR)
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
break;
if (len != sizeof(linkstatus)) {
@@ -1346,7 +1430,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
* the hostscan frame can be requested. */
if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE &&
priv->firmware_type == FIRMWARE_TYPE_SYMBOL &&
- priv->has_hostscan && priv->scan_inprogress) {
+ priv->has_hostscan && priv->scan_request) {
hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL);
break;
}
@@ -1372,7 +1456,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
}
break;
case HERMES_INQ_SCAN:
- if (!priv->scan_inprogress && priv->bssid_fixed &&
+ if (!priv->scan_request && priv->bssid_fixed &&
priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
schedule_work(&priv->join_work);
break;
@@ -1382,30 +1466,30 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
case HERMES_INQ_HOSTSCAN_SYMBOL: {
/* Result of a scanning. Contains information about
* cells in the vicinity - Jean II */
- union iwreq_data wrqu;
unsigned char *buf;
- /* Scan is no longer in progress */
- priv->scan_inprogress = 0;
-
/* Sanity check */
if (len > 4096) {
printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
dev->name, len);
+ qabort_scan(priv);
break;
}
/* Allocate buffer for results */
buf = kmalloc(len, GFP_ATOMIC);
- if (buf == NULL)
+ if (buf == NULL) {
/* No memory, so can't printk()... */
+ qabort_scan(priv);
break;
+ }
/* Read scan data */
err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
infofid, sizeof(info));
if (err) {
kfree(buf);
+ qabort_scan(priv);
break;
}
@@ -1419,24 +1503,14 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
}
#endif /* ORINOCO_DEBUG */
- if (orinoco_process_scan_results(priv, buf, len) == 0) {
- /* Send an empty event to user space.
- * We don't send the received data on the event because
- * it would require us to do complex transcoding, and
- * we want to minimise the work done in the irq handler
- * Use a request to extract the data - Jean II */
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
- }
- kfree(buf);
+ qbuf_scan(priv, buf, len, type);
}
break;
case HERMES_INQ_CHANNELINFO:
{
struct agere_ext_scan_info *bss;
- if (!priv->scan_inprogress) {
+ if (!priv->scan_request) {
printk(KERN_DEBUG "%s: Got chaninfo without scan, "
"len=%d\n", dev->name, len);
break;
@@ -1444,25 +1518,12 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
/* An empty result indicates that the scan is complete */
if (len == 0) {
- union iwreq_data wrqu;
-
- /* Scan is no longer in progress */
- priv->scan_inprogress = 0;
-
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
+ qbuf_scan(priv, NULL, len, type);
break;
}
/* Sanity check */
- else if (len > sizeof(*bss)) {
- printk(KERN_WARNING
- "%s: Ext scan results too large (%d bytes). "
- "Truncating results to %zd bytes.\n",
- dev->name, len, sizeof(*bss));
- len = sizeof(*bss);
- } else if (len < (offsetof(struct agere_ext_scan_info,
+ else if (len < (offsetof(struct agere_ext_scan_info,
data) + 2)) {
/* Drop this result now so we don't have to
* keep checking later */
@@ -1472,21 +1533,18 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
break;
}
- bss = kmalloc(sizeof(*bss), GFP_ATOMIC);
+ bss = kmalloc(len, GFP_ATOMIC);
if (bss == NULL)
break;
/* Read scan data */
err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len,
infofid, sizeof(info));
- if (err) {
+ if (err)
kfree(bss);
- break;
- }
-
- orinoco_add_ext_scan_result(priv, bss);
+ else
+ qbuf_scan(priv, bss, len, type);
- kfree(bss);
break;
}
case HERMES_INQ_SEC_STAT_AGERE:
@@ -1501,6 +1559,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
/* We don't actually do anything about it */
break;
}
+
+ return;
}
static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
@@ -1513,15 +1573,15 @@ static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
/* Internal hardware control routines */
/********************************************************************/
-int __orinoco_up(struct net_device *dev)
+static int __orinoco_up(struct orinoco_private *priv)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct net_device *dev = priv->ndev;
struct hermes *hw = &priv->hw;
int err;
netif_carrier_off(dev); /* just to make sure */
- err = __orinoco_program_rids(dev);
+ err = __orinoco_commit(priv);
if (err) {
printk(KERN_ERR "%s: Error %d configuring card\n",
dev->name, err);
@@ -1541,11 +1601,10 @@ int __orinoco_up(struct net_device *dev)
return 0;
}
-EXPORT_SYMBOL(__orinoco_up);
-int __orinoco_down(struct net_device *dev)
+static int __orinoco_down(struct orinoco_private *priv)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct net_device *dev = priv->ndev;
struct hermes *hw = &priv->hw;
int err;
@@ -1573,31 +1632,9 @@ int __orinoco_down(struct net_device *dev)
return 0;
}
-EXPORT_SYMBOL(__orinoco_down);
-static int orinoco_allocate_fid(struct net_device *dev)
+static int orinoco_reinit_firmware(struct orinoco_private *priv)
{
- struct orinoco_private *priv = netdev_priv(dev);
- struct hermes *hw = &priv->hw;
- int err;
-
- err = hermes_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);
-
- printk(KERN_WARNING "%s: firmware ALLOC bug detected "
- "(old Symbol firmware?). Work around %s\n",
- dev->name, err ? "failed!" : "ok.");
- }
-
- return err;
-}
-
-int orinoco_reinit_firmware(struct net_device *dev)
-{
- struct orinoco_private *priv = netdev_priv(dev);
struct hermes *hw = &priv->hw;
int err;
@@ -1608,246 +1645,15 @@ int orinoco_reinit_firmware(struct net_device *dev)
priv->do_fw_download = 0;
}
if (!err)
- err = orinoco_allocate_fid(dev);
+ err = orinoco_hw_allocate_fid(priv);
return err;
}
-EXPORT_SYMBOL(orinoco_reinit_firmware);
-
-int __orinoco_program_rids(struct net_device *dev)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- hermes_t *hw = &priv->hw;
- int err;
- 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);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting MAC address\n",
- dev->name, err);
- return err;
- }
-
- /* Set up the link mode */
- err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE,
- priv->port_type);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting port type\n",
- dev->name, err);
- return err;
- }
- /* Set the channel/frequency */
- if (priv->channel != 0 && priv->iw_mode != IW_MODE_INFRA) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFOWNCHANNEL,
- priv->channel);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting channel %d\n",
- dev->name, err, priv->channel);
- return err;
- }
- }
-
- if (priv->has_ibss) {
- u16 createibss;
-
- if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) {
- printk(KERN_WARNING "%s: This firmware requires an "
- "ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
- /* With wvlan_cs, in this case, we would crash.
- * hopefully, this driver will behave better...
- * Jean II */
- createibss = 0;
- } else {
- createibss = priv->createibss;
- }
-
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFCREATEIBSS,
- createibss);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n",
- dev->name, err);
- return err;
- }
- }
-
- /* Set the desired BSSID */
- err = __orinoco_hw_set_wap(priv);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting AP address\n",
- dev->name, err);
- return err;
- }
- /* Set the desired ESSID */
- 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,
- HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
- &idbuf);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting OWNSSID\n",
- dev->name, err);
- return err;
- }
- err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
- HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
- &idbuf);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n",
- dev->name, err);
- return err;
- }
-
- /* 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);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting nickname\n",
- dev->name, err);
- return err;
- }
-
- /* Set AP density */
- if (priv->has_sensitivity) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFSYSTEMSCALE,
- priv->ap_density);
- if (err) {
- printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. "
- "Disabling sensitivity control\n",
- dev->name, err);
-
- priv->has_sensitivity = 0;
- }
- }
-
- /* Set RTS threshold */
- err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
- priv->rts_thresh);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting RTS threshold\n",
- dev->name, err);
- return err;
- }
-
- /* Set fragmentation threshold or MWO robustness */
- if (priv->has_mwo)
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMWOROBUST_AGERE,
- priv->mwo_robust);
- else
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
- priv->frag_thresh);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting fragmentation\n",
- dev->name, err);
- return err;
- }
-
- /* Set bitrate */
- err = __orinoco_hw_set_bitrate(priv);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting bitrate\n",
- dev->name, err);
- return err;
- }
-
- /* Set power management */
- if (priv->has_pm) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPMENABLED,
- priv->pm_on);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting up PM\n",
- dev->name, err);
- return err;
- }
-
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMULTICASTRECEIVE,
- priv->pm_mcast);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting up PM\n",
- dev->name, err);
- return err;
- }
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMAXSLEEPDURATION,
- priv->pm_period);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting up PM\n",
- dev->name, err);
- return err;
- }
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPMHOLDOVERDURATION,
- priv->pm_timeout);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting up PM\n",
- dev->name, err);
- return err;
- }
- }
-
- /* Set preamble - only for Symbol so far... */
- if (priv->has_preamble) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPREAMBLE_SYMBOL,
- priv->preamble);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting preamble\n",
- dev->name, err);
- return err;
- }
- }
-
- /* Set up encryption */
- if (priv->has_wep || priv->has_wpa) {
- err = __orinoco_hw_setup_enc(priv);
- if (err) {
- printk(KERN_ERR "%s: Error %d activating encryption\n",
- dev->name, err);
- return err;
- }
- }
-
- if (priv->iw_mode == IW_MODE_MONITOR) {
- /* Enable monitor mode */
- dev->type = ARPHRD_IEEE80211;
- err = hermes_docmd_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 |
- HERMES_TEST_STOP, 0, NULL);
- }
- if (err)
- return err;
-
- /* Set promiscuity / multicast*/
- priv->promiscuous = 0;
- priv->mc_count = 0;
-
- /* FIXME: what about netif_tx_lock */
- __orinoco_set_multicast_list(dev);
-
- return 0;
-}
-/* FIXME: return int? */
-static void
+static int
__orinoco_set_multicast_list(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int err = 0;
int promisc, mc_count;
@@ -1864,6 +1670,8 @@ __orinoco_set_multicast_list(struct net_device *dev)
err = __orinoco_hw_set_multicast_list(priv, dev->mc_list, mc_count,
promisc);
+
+ return err;
}
/* This must be called from user context, without locks held - use
@@ -1896,9 +1704,11 @@ void orinoco_reset(struct work_struct *work)
orinoco_unlock(priv, &flags);
- /* Scanning support: Cleanup of driver struct */
- orinoco_clear_scan_results(priv, 0);
- priv->scan_inprogress = 0;
+ /* Scanning support: Notify scan cancellation */
+ if (priv->scan_request) {
+ cfg80211_scan_done(priv->scan_request, 1);
+ priv->scan_request = NULL;
+ }
if (priv->hard_reset) {
err = (*priv->hard_reset)(priv);
@@ -1909,7 +1719,7 @@ void orinoco_reset(struct work_struct *work)
}
}
- err = orinoco_reinit_firmware(dev);
+ err = orinoco_reinit_firmware(priv);
if (err) {
printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n",
dev->name, err);
@@ -1924,7 +1734,7 @@ void orinoco_reset(struct work_struct *work)
/* priv->open or priv->hw_unavailable might have changed while
* we dropped the lock */
if (priv->open && (!priv->hw_unavailable)) {
- err = __orinoco_up(dev);
+ err = __orinoco_up(priv);
if (err) {
printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n",
dev->name, err);
@@ -1941,6 +1751,64 @@ void orinoco_reset(struct work_struct *work)
printk(KERN_ERR "%s: Device has been disabled!\n", dev->name);
}
+static int __orinoco_commit(struct orinoco_private *priv)
+{
+ struct net_device *dev = priv->ndev;
+ int err = 0;
+
+ err = orinoco_hw_program_rids(priv);
+
+ /* FIXME: what about netif_tx_lock */
+ (void) __orinoco_set_multicast_list(dev);
+
+ return err;
+}
+
+/* Ensures configuration changes are applied. May result in a reset.
+ * The caller should hold priv->lock
+ */
+int orinoco_commit(struct orinoco_private *priv)
+{
+ struct net_device *dev = priv->ndev;
+ hermes_t *hw = &priv->hw;
+ int err;
+
+ if (priv->broken_disableport) {
+ schedule_work(&priv->reset_work);
+ return 0;
+ }
+
+ err = hermes_disable_port(hw, 0);
+ if (err) {
+ printk(KERN_WARNING "%s: Unable to disable port "
+ "while reconfiguring card\n", dev->name);
+ priv->broken_disableport = 1;
+ goto out;
+ }
+
+ err = __orinoco_commit(priv);
+ if (err) {
+ printk(KERN_WARNING "%s: Unable to reconfigure card\n",
+ dev->name);
+ goto out;
+ }
+
+ err = hermes_enable_port(hw, 0);
+ if (err) {
+ printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
+ dev->name);
+ goto out;
+ }
+
+ out:
+ if (err) {
+ printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
+ schedule_work(&priv->reset_work);
+ err = 0;
+ }
+ return err;
+}
+
/********************************************************************/
/* Interrupt handler */
/********************************************************************/
@@ -1960,8 +1828,8 @@ static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw)
irqreturn_t orinoco_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = dev_id;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = dev_id;
+ struct net_device *dev = priv->ndev;
hermes_t *hw = &priv->hw;
int count = MAX_IRQLOOPS_PER_IRQ;
u16 evstat, events;
@@ -2096,227 +1964,12 @@ static void orinoco_unregister_pm_notifier(struct orinoco_private *priv)
/* Initialization */
/********************************************************************/
-struct comp_id {
- u16 id, variant, major, minor;
-} __attribute__ ((packed));
-
-static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
-{
- if (nic_id->id < 0x8000)
- return FIRMWARE_TYPE_AGERE;
- else if (nic_id->id == 0x8000 && nic_id->major == 0)
- return FIRMWARE_TYPE_SYMBOL;
- else
- return FIRMWARE_TYPE_INTERSIL;
-}
-
-/* Set priv->firmware type, determine firmware properties */
-static int determine_firmware(struct net_device *dev)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- hermes_t *hw = &priv->hw;
- int err;
- struct comp_id nic_id, sta_id;
- unsigned int firmver;
- char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2)));
-
- /* Get the hardware version */
- err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
- if (err) {
- printk(KERN_ERR "%s: Cannot read hardware identity: error %d\n",
- dev->name, err);
- return err;
- }
-
- le16_to_cpus(&nic_id.id);
- le16_to_cpus(&nic_id.variant);
- le16_to_cpus(&nic_id.major);
- le16_to_cpus(&nic_id.minor);
- printk(KERN_DEBUG "%s: Hardware identity %04x:%04x:%04x:%04x\n",
- dev->name, nic_id.id, nic_id.variant,
- nic_id.major, nic_id.minor);
-
- priv->firmware_type = determine_firmware_type(&nic_id);
-
- /* Get the firmware version */
- err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
- if (err) {
- printk(KERN_ERR "%s: Cannot read station identity: error %d\n",
- dev->name, err);
- return err;
- }
-
- le16_to_cpus(&sta_id.id);
- le16_to_cpus(&sta_id.variant);
- le16_to_cpus(&sta_id.major);
- le16_to_cpus(&sta_id.minor);
- printk(KERN_DEBUG "%s: Station identity %04x:%04x:%04x:%04x\n",
- dev->name, sta_id.id, sta_id.variant,
- sta_id.major, sta_id.minor);
-
- switch (sta_id.id) {
- case 0x15:
- printk(KERN_ERR "%s: Primary firmware is active\n",
- dev->name);
- return -ENODEV;
- case 0x14b:
- printk(KERN_ERR "%s: Tertiary firmware is active\n",
- dev->name);
- return -ENODEV;
- case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */
- case 0x21: /* Symbol Spectrum24 Trilogy */
- break;
- default:
- printk(KERN_NOTICE "%s: Unknown station ID, please report\n",
- dev->name);
- break;
- }
-
- /* Default capabilities */
- priv->has_sensitivity = 1;
- priv->has_mwo = 0;
- priv->has_preamble = 0;
- priv->has_port3 = 1;
- priv->has_ibss = 1;
- priv->has_wep = 0;
- priv->has_big_wep = 0;
- priv->has_alt_txcntl = 0;
- priv->has_ext_scan = 0;
- priv->has_wpa = 0;
- priv->do_fw_download = 0;
-
- /* Determine capabilities from the firmware version */
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_AGERE:
- /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
- ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
- snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
- "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor);
-
- firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
-
- priv->has_ibss = (firmver >= 0x60006);
- priv->has_wep = (firmver >= 0x40020);
- priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
- Gold cards from the others? */
- priv->has_mwo = (firmver >= 0x60000);
- priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
- priv->ibss_port = 1;
- priv->has_hostscan = (firmver >= 0x8000a);
- priv->do_fw_download = 1;
- priv->broken_monitor = (firmver >= 0x80000);
- priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */
- priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */
- priv->has_wpa = (firmver >= 0x9002a);
- /* Tested with Agere firmware :
- * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
- * Tested CableTron firmware : 4.32 => Anton */
- break;
- case FIRMWARE_TYPE_SYMBOL:
- /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
- /* Intel MAC : 00:02:B3:* */
- /* 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);
- if (err) {
- printk(KERN_WARNING
- "%s: Error %d reading Symbol firmware info. "
- "Wildly guessing capabilities...\n",
- dev->name, err);
- firmver = 0;
- tmp[0] = '\0';
- } else {
- /* The firmware revision is a string, the format is
- * something like : "V2.20-01".
- * Quick and dirty parsing... - Jean II
- */
- firmver = ((tmp[1] - '0') << 16)
- | ((tmp[3] - '0') << 12)
- | ((tmp[4] - '0') << 8)
- | ((tmp[6] - '0') << 4)
- | (tmp[7] - '0');
-
- tmp[SYMBOL_MAX_VER_LEN] = '\0';
- }
-
- snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
- "Symbol %s", tmp);
-
- priv->has_ibss = (firmver >= 0x20000);
- priv->has_wep = (firmver >= 0x15012);
- priv->has_big_wep = (firmver >= 0x20000);
- priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) ||
- (firmver >= 0x29000 && firmver < 0x30000) ||
- firmver >= 0x31000;
- priv->has_preamble = (firmver >= 0x20000);
- priv->ibss_port = 4;
-
- /* Symbol firmware is found on various cards, but
- * there has been no attempt to check firmware
- * download on non-spectrum_cs based cards.
- *
- * Given that the Agere firmware download works
- * differently, we should avoid doing a firmware
- * download with the Symbol algorithm on non-spectrum
- * cards.
- *
- * For now we can identify a spectrum_cs based card
- * because it has a firmware reset function.
- */
- priv->do_fw_download = (priv->stop_fw != NULL);
-
- priv->broken_disableport = (firmver == 0x25013) ||
- (firmver >= 0x30000 && firmver <= 0x31000);
- priv->has_hostscan = (firmver >= 0x31001) ||
- (firmver >= 0x29057 && firmver < 0x30000);
- /* Tested with Intel firmware : 0x20015 => Jean II */
- /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
- break;
- case FIRMWARE_TYPE_INTERSIL:
- /* D-Link, Linksys, Adtron, ZoomAir, and many others...
- * Samsung, Compaq 100/200 and Proxim are slightly
- * different and less well tested */
- /* D-Link MAC : 00:40:05:* */
- /* Addtron MAC : 00:90:D1:* */
- snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
- "Intersil %d.%d.%d", sta_id.major, sta_id.minor,
- sta_id.variant);
-
- firmver = ((unsigned long)sta_id.major << 16) |
- ((unsigned long)sta_id.minor << 8) | sta_id.variant;
-
- priv->has_ibss = (firmver >= 0x000700); /* FIXME */
- priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
- priv->has_pm = (firmver >= 0x000700);
- priv->has_hostscan = (firmver >= 0x010301);
-
- if (firmver >= 0x000800)
- priv->ibss_port = 0;
- else {
- printk(KERN_NOTICE "%s: Intersil firmware earlier "
- "than v0.8.x - several features not supported\n",
- dev->name);
- priv->ibss_port = 1;
- }
- break;
- }
- printk(KERN_DEBUG "%s: Firmware determined as %s\n", dev->name,
- priv->fw_name);
-
- return 0;
-}
-
-static int orinoco_init(struct net_device *dev)
+int orinoco_init(struct orinoco_private *priv)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct device *dev = priv->dev;
+ struct wiphy *wiphy = priv_to_wiphy(priv);
hermes_t *hw = &priv->hw;
int err = 0;
- struct hermes_idstring nickbuf;
- u16 reclen;
- int len;
/* No need to lock, the hw_unavailable flag is already set in
* alloc_orinocodev() */
@@ -2325,15 +1978,14 @@ static int orinoco_init(struct net_device *dev)
/* Initialize the firmware */
err = hermes_init(hw);
if (err != 0) {
- printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n",
- dev->name, err);
+ dev_err(dev, "Failed to initialize firmware (err = %d)\n",
+ err);
goto out;
}
- err = determine_firmware(dev);
+ err = determine_fw_capabilities(priv);
if (err != 0) {
- printk(KERN_ERR "%s: Incompatible firmware, aborting\n",
- dev->name);
+ dev_err(dev, "Incompatible firmware, aborting\n");
goto out;
}
@@ -2347,147 +1999,41 @@ static int orinoco_init(struct net_device *dev)
priv->do_fw_download = 0;
/* Check firmware version again */
- err = determine_firmware(dev);
+ err = determine_fw_capabilities(priv);
if (err != 0) {
- printk(KERN_ERR "%s: Incompatible firmware, aborting\n",
- dev->name);
+ dev_err(dev, "Incompatible firmware, aborting\n");
goto out;
}
}
if (priv->has_port3)
- printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n",
- dev->name);
+ dev_info(dev, "Ad-hoc demo mode supported\n");
if (priv->has_ibss)
- printk(KERN_DEBUG "%s: IEEE standard IBSS ad-hoc mode supported\n",
- dev->name);
- if (priv->has_wep) {
- printk(KERN_DEBUG "%s: WEP supported, %s-bit key\n", dev->name,
- priv->has_big_wep ? "104" : "40");
- }
+ dev_info(dev, "IEEE standard IBSS ad-hoc mode supported\n");
+ if (priv->has_wep)
+ dev_info(dev, "WEP supported, %s-bit key\n",
+ priv->has_big_wep ? "104" : "40");
if (priv->has_wpa) {
- printk(KERN_DEBUG "%s: WPA-PSK supported\n", dev->name);
+ dev_info(dev, "WPA-PSK supported\n");
if (orinoco_mic_init(priv)) {
- printk(KERN_ERR "%s: Failed to setup MIC crypto "
- "algorithm. Disabling WPA support\n", dev->name);
+ dev_err(dev, "Failed to setup MIC crypto algorithm. "
+ "Disabling WPA support\n");
priv->has_wpa = 0;
}
}
- /* Now we have the firmware capabilities, allocate appropiate
- * sized scan buffers */
- if (orinoco_bss_data_allocate(priv))
- goto out;
- orinoco_bss_data_init(priv);
-
- /* Get the MAC address */
- err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
- ETH_ALEN, NULL, dev->dev_addr);
- if (err) {
- printk(KERN_WARNING "%s: failed to read MAC address!\n",
- dev->name);
- goto out;
- }
-
- printk(KERN_DEBUG "%s: MAC address %pM\n",
- dev->name, dev->dev_addr);
-
- /* Get the station name */
- err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
- sizeof(nickbuf), &reclen, &nickbuf);
- if (err) {
- printk(KERN_ERR "%s: failed to read station name\n",
- dev->name);
- goto out;
- }
- if (nickbuf.len)
- len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len));
- else
- len = min(IW_ESSID_MAX_SIZE, 2 * reclen);
- memcpy(priv->nick, &nickbuf.val, len);
- priv->nick[len] = '\0';
-
- printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick);
-
- err = orinoco_allocate_fid(dev);
- if (err) {
- printk(KERN_ERR "%s: failed to allocate NIC buffer!\n",
- dev->name);
- goto out;
- }
-
- /* Get allowed channels */
- err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST,
- &priv->channel_mask);
- if (err) {
- printk(KERN_ERR "%s: failed to read channel list!\n",
- dev->name);
- goto out;
- }
-
- /* Get initial AP density */
- err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
- &priv->ap_density);
- if (err || priv->ap_density < 1 || priv->ap_density > 3)
- priv->has_sensitivity = 0;
-
- /* Get initial RTS threshold */
- err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
- &priv->rts_thresh);
- if (err) {
- printk(KERN_ERR "%s: failed to read RTS threshold!\n",
- dev->name);
+ err = orinoco_hw_read_card_settings(priv, wiphy->perm_addr);
+ if (err)
goto out;
- }
- /* Get initial fragmentation settings */
- if (priv->has_mwo)
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMWOROBUST_AGERE,
- &priv->mwo_robust);
- else
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
- &priv->frag_thresh);
+ err = orinoco_hw_allocate_fid(priv);
if (err) {
- printk(KERN_ERR "%s: failed to read fragmentation settings!\n",
- dev->name);
+ dev_err(dev, "Failed to allocate NIC buffer!\n");
goto out;
}
- /* Power management setup */
- if (priv->has_pm) {
- priv->pm_on = 0;
- priv->pm_mcast = 1;
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMAXSLEEPDURATION,
- &priv->pm_period);
- if (err) {
- printk(KERN_ERR "%s: failed to read power management period!\n",
- dev->name);
- goto out;
- }
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPMHOLDOVERDURATION,
- &priv->pm_timeout);
- if (err) {
- printk(KERN_ERR "%s: failed to read power management timeout!\n",
- dev->name);
- goto out;
- }
- }
-
- /* Preamble setup */
- if (priv->has_preamble) {
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPREAMBLE_SYMBOL,
- &priv->preamble);
- if (err)
- goto out;
- }
-
/* Set up the default configuration */
- priv->iw_mode = IW_MODE_INFRA;
+ priv->iw_mode = NL80211_IFTYPE_STATION;
/* By default use IEEE/IBSS ad-hoc mode if we have it */
priv->prefer_port3 = priv->has_port3 && (!priv->has_ibss);
set_port_type(priv);
@@ -2502,20 +2048,25 @@ static int orinoco_init(struct net_device *dev)
priv->wpa_ie_len = 0;
priv->wpa_ie = NULL;
+ if (orinoco_wiphy_register(wiphy)) {
+ err = -ENODEV;
+ goto out;
+ }
+
/* Make the hardware available, as long as it hasn't been
* removed elsewhere (e.g. by PCMCIA hot unplug) */
spin_lock_irq(&priv->lock);
priv->hw_unavailable--;
spin_unlock_irq(&priv->lock);
- printk(KERN_DEBUG "%s: ready\n", dev->name);
+ dev_dbg(dev, "Ready\n");
out:
return err;
}
+EXPORT_SYMBOL(orinoco_init);
static const struct net_device_ops orinoco_netdev_ops = {
- .ndo_init = orinoco_init,
.ndo_open = orinoco_open,
.ndo_stop = orinoco_stop,
.ndo_start_xmit = orinoco_xmit,
@@ -2527,40 +2078,64 @@ static const struct net_device_ops orinoco_netdev_ops = {
.ndo_get_stats = orinoco_get_stats,
};
-struct net_device
+/* Allocate private data.
+ *
+ * This driver has a number of structures associated with it
+ * netdev - Net device structure for each network interface
+ * wiphy - structure associated with wireless phy
+ * wireless_dev (wdev) - structure for each wireless interface
+ * hw - structure for hermes chip info
+ * card - card specific structure for use by the card driver
+ * (airport, orinoco_cs)
+ * priv - orinoco private data
+ * device - generic linux device structure
+ *
+ * +---------+ +---------+
+ * | wiphy | | netdev |
+ * | +-------+ | +-------+
+ * | | priv | | | wdev |
+ * | | +-----+ +-+-------+
+ * | | | hw |
+ * | +-+-----+
+ * | | card |
+ * +-+-------+
+ *
+ * priv has a link to netdev and device
+ * wdev has a link to wiphy
+ */
+struct orinoco_private
*alloc_orinocodev(int sizeof_card,
struct device *device,
int (*hard_reset)(struct orinoco_private *),
int (*stop_fw)(struct orinoco_private *, int))
{
- struct net_device *dev;
struct orinoco_private *priv;
+ struct wiphy *wiphy;
- dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card);
- if (!dev)
+ /* allocate wiphy
+ * NOTE: We only support a single virtual interface
+ * but this may change when monitor mode is added
+ */
+ wiphy = wiphy_new(&orinoco_cfg_ops,
+ sizeof(struct orinoco_private) + sizeof_card);
+ if (!wiphy)
return NULL;
- priv = netdev_priv(dev);
- priv->ndev = dev;
+
+ priv = wiphy_priv(wiphy);
+ priv->dev = device;
+
if (sizeof_card)
priv->card = (void *)((unsigned long)priv
+ sizeof(struct orinoco_private));
else
priv->card = NULL;
- priv->dev = device;
- /* Setup / override net_device fields */
- dev->netdev_ops = &orinoco_netdev_ops;
- dev->watchdog_timeo = HZ; /* 1 second timeout */
- dev->ethtool_ops = &orinoco_ethtool_ops;
- dev->wireless_handlers = &orinoco_handler_def;
+ orinoco_wiphy_init(wiphy);
+
#ifdef WIRELESS_SPY
priv->wireless_data.spy_data = &priv->spy_data;
- dev->wireless_data = &priv->wireless_data;
#endif
- /* Reserve space in skb for the SNAP header */
- dev->hard_header_len += ENCAPS_OVERHEAD;
-
/* Set up default callbacks */
priv->hard_reset = hard_reset;
priv->stop_fw = stop_fw;
@@ -2576,9 +2151,12 @@ struct net_device
INIT_LIST_HEAD(&priv->rx_list);
tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet,
- (unsigned long) dev);
+ (unsigned long) priv);
+
+ spin_lock_init(&priv->scan_lock);
+ INIT_LIST_HEAD(&priv->scan_list);
+ INIT_WORK(&priv->process_scan, orinoco_process_scan_results);
- netif_carrier_off(dev);
priv->last_linkstatus = 0xffff;
#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
@@ -2589,14 +2167,91 @@ struct net_device
/* Register PM notifiers */
orinoco_register_pm_notifier(priv);
- return dev;
+ return priv;
}
EXPORT_SYMBOL(alloc_orinocodev);
-void free_orinocodev(struct net_device *dev)
+/* We can only support a single interface. We provide a separate
+ * function to set it up to distinguish between hardware
+ * initialisation and interface setup.
+ *
+ * The base_addr and irq parameters are passed on to netdev for use
+ * with SIOCGIFMAP.
+ */
+int orinoco_if_add(struct orinoco_private *priv,
+ unsigned long base_addr,
+ unsigned int irq)
+{
+ struct wiphy *wiphy = priv_to_wiphy(priv);
+ struct wireless_dev *wdev;
+ struct net_device *dev;
+ int ret;
+
+ dev = alloc_etherdev(sizeof(struct wireless_dev));
+
+ if (!dev)
+ return -ENOMEM;
+
+ /* Initialise wireless_dev */
+ wdev = netdev_priv(dev);
+ wdev->wiphy = wiphy;
+ wdev->iftype = NL80211_IFTYPE_STATION;
+
+ /* Setup / override net_device fields */
+ dev->ieee80211_ptr = wdev;
+ dev->netdev_ops = &orinoco_netdev_ops;
+ dev->watchdog_timeo = HZ; /* 1 second timeout */
+ dev->ethtool_ops = &orinoco_ethtool_ops;
+ dev->wireless_handlers = &orinoco_handler_def;
+#ifdef WIRELESS_SPY
+ dev->wireless_data = &priv->wireless_data;
+#endif
+ /* 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;
+
+ netif_carrier_off(dev);
+
+ memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN);
+
+ dev->base_addr = base_addr;
+ dev->irq = irq;
+
+ SET_NETDEV_DEV(dev, priv->dev);
+ ret = register_netdev(dev);
+ if (ret)
+ goto fail;
+
+ priv->ndev = dev;
+
+ /* Report what we've done */
+ dev_dbg(priv->dev, "Registerred interface %s.\n", dev->name);
+
+ return 0;
+
+ fail:
+ free_netdev(dev);
+ return ret;
+}
+EXPORT_SYMBOL(orinoco_if_add);
+
+void orinoco_if_del(struct orinoco_private *priv)
+{
+ struct net_device *dev = priv->ndev;
+
+ unregister_netdev(dev);
+ free_netdev(dev);
+}
+EXPORT_SYMBOL(orinoco_if_del);
+
+void free_orinocodev(struct orinoco_private *priv)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct wiphy *wiphy = priv_to_wiphy(priv);
struct orinoco_rx_data *rx_data, *temp;
+ struct orinoco_scan_data *sd, *sdtemp;
+
+ wiphy_unregister(wiphy);
/* If the tasklet is scheduled when we call tasklet_kill it
* will run one final time. However the tasklet will only
@@ -2612,21 +2267,80 @@ void free_orinocodev(struct net_device *dev)
kfree(rx_data);
}
+ cancel_work_sync(&priv->process_scan);
+ /* Explicitly drain priv->scan_list */
+ list_for_each_entry_safe(sd, sdtemp, &priv->scan_list, list) {
+ list_del(&sd->list);
+
+ if ((sd->len > 0) && sd->buf)
+ kfree(sd->buf);
+ kfree(sd);
+ }
+
orinoco_unregister_pm_notifier(priv);
orinoco_uncache_fw(priv);
priv->wpa_ie_len = 0;
kfree(priv->wpa_ie);
orinoco_mic_free(priv);
- orinoco_bss_data_free(priv);
- free_netdev(dev);
+ wiphy_free(wiphy);
}
EXPORT_SYMBOL(free_orinocodev);
+int orinoco_up(struct orinoco_private *priv)
+{
+ struct net_device *dev = priv->ndev;
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ err = orinoco_reinit_firmware(priv);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
+ dev->name, err);
+ goto exit;
+ }
+
+ netif_device_attach(dev);
+ priv->hw_unavailable--;
+
+ if (priv->open && !priv->hw_unavailable) {
+ err = __orinoco_up(priv);
+ if (err)
+ printk(KERN_ERR "%s: Error %d restarting card\n",
+ dev->name, err);
+ }
+
+exit:
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(orinoco_up);
+
+void orinoco_down(struct orinoco_private *priv)
+{
+ struct net_device *dev = priv->ndev;
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ err = __orinoco_down(priv);
+ if (err)
+ printk(KERN_WARNING "%s: Error %d downing interface\n",
+ dev->name, err);
+
+ netif_device_detach(dev);
+ priv->hw_unavailable++;
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL(orinoco_down);
+
static void orinoco_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
diff --git a/drivers/net/wireless/orinoco/main.h b/drivers/net/wireless/orinoco/main.h
index af2bae4fe395..21ab36cd76c7 100644
--- a/drivers/net/wireless/orinoco/main.h
+++ b/drivers/net/wireless/orinoco/main.h
@@ -29,10 +29,9 @@ struct net_device;
struct work_struct;
void set_port_type(struct orinoco_private *priv);
-int __orinoco_program_rids(struct net_device *dev);
+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)
diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h
index 8e5a72cc297f..5f4f5c9eef79 100644
--- a/drivers/net/wireless/orinoco/orinoco.h
+++ b/drivers/net/wireless/orinoco/orinoco.h
@@ -14,6 +14,7 @@
#include <linux/netdevice.h>
#include <linux/wireless.h>
#include <net/iw_handler.h>
+#include <net/cfg80211.h>
#include "hermes.h"
@@ -47,18 +48,6 @@ typedef enum {
FIRMWARE_TYPE_SYMBOL
} fwtype_t;
-struct bss_element {
- union hermes_scan_info bss;
- unsigned long last_scanned;
- struct list_head list;
-};
-
-struct xbss_element {
- struct agere_ext_scan_info bss;
- unsigned long last_scanned;
- struct list_head list;
-};
-
struct firmware;
struct orinoco_private {
@@ -67,6 +56,10 @@ struct orinoco_private {
int (*hard_reset)(struct orinoco_private *);
int (*stop_fw)(struct orinoco_private *, int);
+ struct ieee80211_supported_band band;
+ struct ieee80211_channel channels[14];
+ u32 cipher_suites[3];
+
/* Synchronisation stuff */
spinlock_t lock;
int hw_unavailable;
@@ -116,7 +109,7 @@ struct orinoco_private {
unsigned int broken_monitor:1;
/* Configuration paramaters */
- u32 iw_mode;
+ enum nl80211_iftype iw_mode;
int prefer_port3;
u16 encode_alg, wep_restrict, tx_key;
struct orinoco_key keys[ORINOCO_MAX_KEYS];
@@ -140,12 +133,10 @@ struct orinoco_private {
int promiscuous, mc_count;
/* Scanning support */
- struct list_head bss_list;
- struct list_head bss_free_list;
- void *bss_xbss_data;
-
- int scan_inprogress; /* Scan pending... */
- u32 scan_mode; /* Type of scan done */
+ struct cfg80211_scan_request *scan_request;
+ struct work_struct process_scan;
+ struct list_head scan_list;
+ spinlock_t scan_lock; /* protects the scan list */
/* WPA support */
u8 *wpa_ie;
@@ -182,14 +173,18 @@ extern int orinoco_debug;
/* Exported prototypes */
/********************************************************************/
-extern struct net_device *alloc_orinocodev(
+extern struct orinoco_private *alloc_orinocodev(
int sizeof_card, struct device *device,
int (*hard_reset)(struct orinoco_private *),
int (*stop_fw)(struct orinoco_private *, int));
-extern void free_orinocodev(struct net_device *dev);
-extern int __orinoco_up(struct net_device *dev);
-extern int __orinoco_down(struct net_device *dev);
-extern int orinoco_reinit_firmware(struct net_device *dev);
+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);
+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);
/********************************************************************/
@@ -215,4 +210,10 @@ static inline void orinoco_unlock(struct orinoco_private *priv,
spin_unlock_irqrestore(&priv->lock, *flags);
}
+/*** Navigate from net_device to orinoco_private ***/
+static inline struct orinoco_private *ndev_priv(struct net_device *dev)
+{
+ struct wireless_dev *wdev = netdev_priv(dev);
+ return wdev_priv(wdev);
+}
#endif /* _ORINOCO_H */
diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c
index b381aed24d73..38c1c9d2abb8 100644
--- a/drivers/net/wireless/orinoco/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco/orinoco_cs.c
@@ -106,26 +106,24 @@ orinoco_cs_hard_reset(struct orinoco_private *priv)
static int
orinoco_cs_probe(struct pcmcia_device *link)
{
- struct net_device *dev;
struct orinoco_private *priv;
struct orinoco_pccard *card;
- dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
- orinoco_cs_hard_reset, NULL);
- if (!dev)
+ priv = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
+ orinoco_cs_hard_reset, NULL);
+ if (!priv)
return -ENOMEM;
- priv = netdev_priv(dev);
card = priv->card;
/* Link both structures together */
card->p_dev = link;
- link->priv = dev;
+ link->priv = priv;
/* Interrupt setup */
link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = orinoco_interrupt;
- link->irq.Instance = dev;
+ link->irq.Instance = priv;
/* General socket configuration defaults can go here. In this
* client, we assume very little, and rely on the CIS for
@@ -146,14 +144,14 @@ orinoco_cs_probe(struct pcmcia_device *link)
*/
static void orinoco_cs_detach(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
+ struct orinoco_private *priv = link->priv;
if (link->dev_node)
- unregister_netdev(dev);
+ orinoco_if_del(priv);
orinoco_cs_release(link);
- free_orinocodev(dev);
+ free_orinocodev(priv);
} /* orinoco_cs_detach */
/*
@@ -239,8 +237,7 @@ next_entry:
static int
orinoco_cs_config(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = link->priv;
struct orinoco_pccard *card = priv->card;
hermes_t *hw = &priv->hw;
int last_fn, last_ret;
@@ -295,29 +292,27 @@ orinoco_cs_config(struct pcmcia_device *link)
pcmcia_request_configuration(link, &link->conf));
/* Ok, we have the configuration, prepare to register the netdev */
- dev->base_addr = link->io.BasePort1;
- dev->irq = link->irq.AssignedIRQ;
card->node.major = card->node.minor = 0;
- SET_NETDEV_DEV(dev, &handle_to_dev(link));
- /* Tell the stack we exist */
- if (register_netdev(dev) != 0) {
- printk(KERN_ERR PFX "register_netdev() failed\n");
+ /* Initialise the main driver */
+ if (orinoco_init(priv) != 0) {
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
+ goto failed;
+ }
+
+ /* Register an interface with the stack */
+ if (orinoco_if_add(priv, link->io.BasePort1,
+ link->irq.AssignedIRQ) != 0) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
goto failed;
}
/* At this point, the dev_node_t structure(s) needs to be
* initialized and arranged in a linked list at link->dev_node. */
- strcpy(card->node.dev_name, dev->name);
+ strcpy(card->node.dev_name, priv->ndev->name);
link->dev_node = &card->node; /* link->dev_node being non-NULL is also
* used to indicate that the
* net_device has been registered */
-
- /* Finally, report what we've done */
- printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
- "0x%04x-0x%04x\n", dev->name, dev_name(dev->dev.parent),
- link->irq.AssignedIRQ, link->io.BasePort1,
- link->io.BasePort1 + link->io.NumPorts1 - 1);
return 0;
cs_failed:
@@ -336,8 +331,7 @@ orinoco_cs_config(struct pcmcia_device *link)
static void
orinoco_cs_release(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = link->priv;
unsigned long flags;
/* We're committed to taking the device away now, so mark the
@@ -353,62 +347,26 @@ orinoco_cs_release(struct pcmcia_device *link)
static int orinoco_cs_suspend(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = link->priv;
struct orinoco_pccard *card = priv->card;
- int err = 0;
- unsigned long flags;
/* This is probably racy, but I can't think of
a better way, short of rewriting the PCMCIA
layer to not suck :-( */
- if (!test_bit(0, &card->hard_reset_in_progress)) {
- spin_lock_irqsave(&priv->lock, flags);
-
- err = __orinoco_down(dev);
- if (err)
- printk(KERN_WARNING "%s: Error %d downing interface\n",
- dev->name, err);
-
- netif_device_detach(dev);
- priv->hw_unavailable++;
-
- spin_unlock_irqrestore(&priv->lock, flags);
- }
+ if (!test_bit(0, &card->hard_reset_in_progress))
+ orinoco_down(priv);
return 0;
}
static int orinoco_cs_resume(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = link->priv;
struct orinoco_pccard *card = priv->card;
int err = 0;
- unsigned long flags;
-
- if (!test_bit(0, &card->hard_reset_in_progress)) {
- err = orinoco_reinit_firmware(dev);
- if (err) {
- printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
- dev->name, err);
- return -EIO;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
- netif_device_attach(dev);
- priv->hw_unavailable--;
-
- if (priv->open && !priv->hw_unavailable) {
- err = __orinoco_up(dev);
- if (err)
- printk(KERN_ERR "%s: Error %d restarting card\n",
- dev->name, err);
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
- }
+ if (!test_bit(0, &card->hard_reset_in_progress))
+ err = orinoco_up(priv);
return err;
}
diff --git a/drivers/net/wireless/orinoco/orinoco_nortel.c b/drivers/net/wireless/orinoco/orinoco_nortel.c
index b01726255c6f..c13a4c383410 100644
--- a/drivers/net/wireless/orinoco/orinoco_nortel.c
+++ b/drivers/net/wireless/orinoco/orinoco_nortel.c
@@ -144,7 +144,6 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
int err;
struct orinoco_private *priv;
struct orinoco_pci_card *card;
- struct net_device *dev;
void __iomem *hermes_io, *bridge_io, *attr_io;
err = pci_enable_device(pdev);
@@ -181,24 +180,22 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
}
/* Allocate network device */
- dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
- orinoco_nortel_cor_reset, NULL);
- if (!dev) {
+ priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
+ orinoco_nortel_cor_reset, NULL);
+ if (!priv) {
printk(KERN_ERR PFX "Cannot allocate network device\n");
err = -ENOMEM;
goto fail_alloc;
}
- priv = netdev_priv(dev);
card = priv->card;
card->bridge_io = bridge_io;
card->attr_io = attr_io;
- SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- dev->name, dev);
+ DRIVER_NAME, priv);
if (err) {
printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
err = -EBUSY;
@@ -217,24 +214,28 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
goto fail;
}
- err = register_netdev(dev);
+ err = orinoco_init(priv);
if (err) {
- printk(KERN_ERR PFX "Cannot register network device\n");
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
goto fail;
}
- pci_set_drvdata(pdev, dev);
- printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
- pci_name(pdev));
+ err = orinoco_if_add(priv, 0, 0);
+ if (err) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
+ goto fail;
+ }
+
+ pci_set_drvdata(pdev, priv);
return 0;
fail:
- free_irq(pdev->irq, dev);
+ free_irq(pdev->irq, priv);
fail_irq:
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
fail_alloc:
pci_iounmap(pdev, hermes_io);
@@ -256,17 +257,16 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
static void __devexit orinoco_nortel_remove_one(struct pci_dev *pdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = pci_get_drvdata(pdev);
struct orinoco_pci_card *card = priv->card;
/* Clear LEDs */
iowrite16(0, card->bridge_io + 10);
- unregister_netdev(dev);
- free_irq(pdev->irq, dev);
+ orinoco_if_del(priv);
+ free_irq(pdev->irq, priv);
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
pci_iounmap(pdev, priv->hw.iobase);
pci_iounmap(pdev, card->attr_io);
pci_iounmap(pdev, card->bridge_io);
diff --git a/drivers/net/wireless/orinoco/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c
index 78cafff1fb2e..fea7781948e7 100644
--- a/drivers/net/wireless/orinoco/orinoco_pci.c
+++ b/drivers/net/wireless/orinoco/orinoco_pci.c
@@ -116,7 +116,6 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
int err;
struct orinoco_private *priv;
struct orinoco_pci_card *card;
- struct net_device *dev;
void __iomem *hermes_io;
err = pci_enable_device(pdev);
@@ -139,22 +138,20 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
}
/* Allocate network device */
- dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
- orinoco_pci_cor_reset, NULL);
- if (!dev) {
+ priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
+ orinoco_pci_cor_reset, NULL);
+ if (!priv) {
printk(KERN_ERR PFX "Cannot allocate network device\n");
err = -ENOMEM;
goto fail_alloc;
}
- priv = netdev_priv(dev);
card = priv->card;
- SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING);
err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- dev->name, dev);
+ DRIVER_NAME, priv);
if (err) {
printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
err = -EBUSY;
@@ -167,24 +164,28 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
goto fail;
}
- err = register_netdev(dev);
+ err = orinoco_init(priv);
if (err) {
- printk(KERN_ERR PFX "Cannot register network device\n");
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
goto fail;
}
- pci_set_drvdata(pdev, dev);
- printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
- pci_name(pdev));
+ err = orinoco_if_add(priv, 0, 0);
+ if (err) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
+ goto fail;
+ }
+
+ pci_set_drvdata(pdev, priv);
return 0;
fail:
- free_irq(pdev->irq, dev);
+ free_irq(pdev->irq, priv);
fail_irq:
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
fail_alloc:
pci_iounmap(pdev, hermes_io);
@@ -200,13 +201,12 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = pci_get_drvdata(pdev);
- unregister_netdev(dev);
- free_irq(pdev->irq, dev);
+ orinoco_if_del(priv);
+ free_irq(pdev->irq, priv);
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
pci_iounmap(pdev, priv->hw.iobase);
pci_release_regions(pdev);
pci_disable_device(pdev);
diff --git a/drivers/net/wireless/orinoco/orinoco_pci.h b/drivers/net/wireless/orinoco/orinoco_pci.h
index c655b4a3de16..ea7231af40a8 100644
--- a/drivers/net/wireless/orinoco/orinoco_pci.h
+++ b/drivers/net/wireless/orinoco/orinoco_pci.h
@@ -21,30 +21,10 @@ struct orinoco_pci_card {
#ifdef CONFIG_PM
static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
- int err;
-
- err = orinoco_lock(priv, &flags);
- if (err) {
- printk(KERN_ERR "%s: cannot lock hardware for suspend\n",
- dev->name);
- return err;
- }
-
- err = __orinoco_down(dev);
- if (err)
- printk(KERN_WARNING "%s: error %d bringing interface down "
- "for suspend\n", dev->name, err);
-
- netif_device_detach(dev);
-
- priv->hw_unavailable++;
-
- orinoco_unlock(priv, &flags);
+ struct orinoco_private *priv = pci_get_drvdata(pdev);
- free_irq(pdev->irq, dev);
+ orinoco_down(priv);
+ free_irq(pdev->irq, priv);
pci_save_state(pdev);
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
@@ -54,9 +34,8 @@ static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state)
static int orinoco_pci_resume(struct pci_dev *pdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
+ struct orinoco_private *priv = pci_get_drvdata(pdev);
+ struct net_device *dev = priv->ndev;
int err;
pci_set_power_state(pdev, 0);
@@ -69,7 +48,7 @@ static int orinoco_pci_resume(struct pci_dev *pdev)
pci_restore_state(pdev);
err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- dev->name, dev);
+ dev->name, priv);
if (err) {
printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n",
dev->name);
@@ -77,29 +56,9 @@ static int orinoco_pci_resume(struct pci_dev *pdev)
return -EBUSY;
}
- err = orinoco_reinit_firmware(dev);
- if (err) {
- printk(KERN_ERR "%s: error %d re-initializing firmware "
- "on resume\n", dev->name, err);
- return err;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
-
- netif_device_attach(dev);
+ err = orinoco_up(priv);
- priv->hw_unavailable--;
-
- if (priv->open && (!priv->hw_unavailable)) {
- err = __orinoco_up(dev);
- if (err)
- printk(KERN_ERR "%s: Error %d restarting card on resume\n",
- dev->name, err);
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
+ return err;
}
#else
#define orinoco_pci_suspend NULL
diff --git a/drivers/net/wireless/orinoco/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c
index a2a4471c0337..3f2942a1e4f5 100644
--- a/drivers/net/wireless/orinoco/orinoco_plx.c
+++ b/drivers/net/wireless/orinoco/orinoco_plx.c
@@ -183,7 +183,6 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
int err;
struct orinoco_private *priv;
struct orinoco_pci_card *card;
- struct net_device *dev;
void __iomem *hermes_io, *attr_io, *bridge_io;
err = pci_enable_device(pdev);
@@ -220,24 +219,22 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
}
/* Allocate network device */
- dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
- orinoco_plx_cor_reset, NULL);
- if (!dev) {
+ priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
+ orinoco_plx_cor_reset, NULL);
+ if (!priv) {
printk(KERN_ERR PFX "Cannot allocate network device\n");
err = -ENOMEM;
goto fail_alloc;
}
- priv = netdev_priv(dev);
card = priv->card;
card->bridge_io = bridge_io;
card->attr_io = attr_io;
- SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- dev->name, dev);
+ DRIVER_NAME, priv);
if (err) {
printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
err = -EBUSY;
@@ -256,24 +253,28 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
goto fail;
}
- err = register_netdev(dev);
+ err = orinoco_init(priv);
if (err) {
- printk(KERN_ERR PFX "Cannot register network device\n");
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
goto fail;
}
- pci_set_drvdata(pdev, dev);
- printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
- pci_name(pdev));
+ err = orinoco_if_add(priv, 0, 0);
+ if (err) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
+ goto fail;
+ }
+
+ pci_set_drvdata(pdev, priv);
return 0;
fail:
- free_irq(pdev->irq, dev);
+ free_irq(pdev->irq, priv);
fail_irq:
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
fail_alloc:
pci_iounmap(pdev, hermes_io);
@@ -295,14 +296,13 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = pci_get_drvdata(pdev);
struct orinoco_pci_card *card = priv->card;
- unregister_netdev(dev);
- free_irq(pdev->irq, dev);
+ orinoco_if_del(priv);
+ free_irq(pdev->irq, priv);
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
pci_iounmap(pdev, priv->hw.iobase);
pci_iounmap(pdev, card->attr_io);
pci_iounmap(pdev, card->bridge_io);
diff --git a/drivers/net/wireless/orinoco/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c
index cda0e6e4d7a1..d3452548cc71 100644
--- a/drivers/net/wireless/orinoco/orinoco_tmd.c
+++ b/drivers/net/wireless/orinoco/orinoco_tmd.c
@@ -94,7 +94,6 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
int err;
struct orinoco_private *priv;
struct orinoco_pci_card *card;
- struct net_device *dev;
void __iomem *hermes_io, *bridge_io;
err = pci_enable_device(pdev);
@@ -124,23 +123,21 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
}
/* Allocate network device */
- dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
- orinoco_tmd_cor_reset, NULL);
- if (!dev) {
+ priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
+ orinoco_tmd_cor_reset, NULL);
+ if (!priv) {
printk(KERN_ERR PFX "Cannot allocate network device\n");
err = -ENOMEM;
goto fail_alloc;
}
- priv = netdev_priv(dev);
card = priv->card;
card->bridge_io = bridge_io;
- SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- dev->name, dev);
+ DRIVER_NAME, priv);
if (err) {
printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
err = -EBUSY;
@@ -153,24 +150,28 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
goto fail;
}
- err = register_netdev(dev);
+ err = orinoco_init(priv);
if (err) {
- printk(KERN_ERR PFX "Cannot register network device\n");
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
goto fail;
}
- pci_set_drvdata(pdev, dev);
- printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
- pci_name(pdev));
+ err = orinoco_if_add(priv, 0, 0);
+ if (err) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
+ goto fail;
+ }
+
+ pci_set_drvdata(pdev, priv);
return 0;
fail:
- free_irq(pdev->irq, dev);
+ free_irq(pdev->irq, priv);
fail_irq:
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
fail_alloc:
pci_iounmap(pdev, hermes_io);
@@ -189,14 +190,13 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = pci_get_drvdata(pdev);
struct orinoco_pci_card *card = priv->card;
- unregister_netdev(dev);
- free_irq(pdev->irq, dev);
+ orinoco_if_del(priv);
+ free_irq(pdev->irq, priv);
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
pci_iounmap(pdev, priv->hw.iobase);
pci_iounmap(pdev, card->bridge_io);
pci_release_regions(pdev);
diff --git a/drivers/net/wireless/orinoco/scan.c b/drivers/net/wireless/orinoco/scan.c
index 89d699d4dfe6..d2f10e9c2162 100644
--- a/drivers/net/wireless/orinoco/scan.c
+++ b/drivers/net/wireless/orinoco/scan.c
@@ -5,147 +5,166 @@
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/etherdevice.h>
+#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
#include "hermes.h"
#include "orinoco.h"
+#include "main.h"
#include "scan.h"
-#define ORINOCO_MAX_BSS_COUNT 64
+#define ZERO_DBM_OFFSET 0x95
+#define MAX_SIGNAL_LEVEL 0x8A
+#define MIN_SIGNAL_LEVEL 0x2F
-#define PRIV_BSS ((struct bss_element *)priv->bss_xbss_data)
-#define PRIV_XBSS ((struct xbss_element *)priv->bss_xbss_data)
+#define SIGNAL_TO_DBM(x) \
+ (clamp_t(s32, (x), MIN_SIGNAL_LEVEL, MAX_SIGNAL_LEVEL) \
+ - ZERO_DBM_OFFSET)
+#define SIGNAL_TO_MBM(x) (SIGNAL_TO_DBM(x) * 100)
-int orinoco_bss_data_allocate(struct orinoco_private *priv)
+static int symbol_build_supp_rates(u8 *buf, const __le16 *rates)
{
- if (priv->bss_xbss_data)
- return 0;
-
- if (priv->has_ext_scan)
- priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
- sizeof(struct xbss_element),
- GFP_KERNEL);
- else
- priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
- sizeof(struct bss_element),
- GFP_KERNEL);
-
- if (!priv->bss_xbss_data) {
- printk(KERN_WARNING "Out of memory allocating beacons");
- return -ENOMEM;
+ int i;
+ u8 rate;
+
+ buf[0] = WLAN_EID_SUPP_RATES;
+ for (i = 0; i < 5; i++) {
+ rate = le16_to_cpu(rates[i]);
+ /* NULL terminated */
+ if (rate == 0x0)
+ break;
+ buf[i + 2] = rate;
}
- return 0;
-}
+ buf[1] = i;
-void orinoco_bss_data_free(struct orinoco_private *priv)
-{
- kfree(priv->bss_xbss_data);
- priv->bss_xbss_data = NULL;
+ return i + 2;
}
-void orinoco_bss_data_init(struct orinoco_private *priv)
+static int prism_build_supp_rates(u8 *buf, const u8 *rates)
{
int i;
- INIT_LIST_HEAD(&priv->bss_free_list);
- INIT_LIST_HEAD(&priv->bss_list);
- if (priv->has_ext_scan)
- for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
- list_add_tail(&(PRIV_XBSS[i].list),
- &priv->bss_free_list);
- else
- for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
- list_add_tail(&(PRIV_BSS[i].list),
- &priv->bss_free_list);
-
-}
-
-void orinoco_clear_scan_results(struct orinoco_private *priv,
- unsigned long scan_age)
-{
- if (priv->has_ext_scan) {
- struct xbss_element *bss;
- struct xbss_element *tmp_bss;
-
- /* Blow away current list of scan results */
- list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
- if (!scan_age ||
- time_after(jiffies, bss->last_scanned + scan_age)) {
- list_move_tail(&bss->list,
- &priv->bss_free_list);
- /* Don't blow away ->list, just BSS data */
- memset(&bss->bss, 0, sizeof(bss->bss));
- bss->last_scanned = 0;
- }
- }
- } else {
- struct bss_element *bss;
- struct bss_element *tmp_bss;
-
- /* Blow away current list of scan results */
- list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
- if (!scan_age ||
- time_after(jiffies, bss->last_scanned + scan_age)) {
- list_move_tail(&bss->list,
- &priv->bss_free_list);
- /* Don't blow away ->list, just BSS data */
- memset(&bss->bss, 0, sizeof(bss->bss));
- bss->last_scanned = 0;
- }
+ buf[0] = WLAN_EID_SUPP_RATES;
+ for (i = 0; i < 8; i++) {
+ /* NULL terminated */
+ if (rates[i] == 0x0)
+ break;
+ buf[i + 2] = rates[i];
+ }
+ buf[1] = i;
+
+ /* We might still have another 2 rates, which need to go in
+ * extended supported rates */
+ if (i == 8 && rates[i] > 0) {
+ buf[10] = WLAN_EID_EXT_SUPP_RATES;
+ for (; i < 10; i++) {
+ /* NULL terminated */
+ if (rates[i] == 0x0)
+ break;
+ buf[i + 2] = rates[i];
}
+ buf[11] = i - 8;
}
+
+ return (i < 8) ? i + 2 : i + 4;
}
-void orinoco_add_ext_scan_result(struct orinoco_private *priv,
- struct agere_ext_scan_info *atom)
+static void orinoco_add_hostscan_result(struct orinoco_private *priv,
+ const union hermes_scan_info *bss)
{
- struct xbss_element *bss = NULL;
- int found = 0;
-
- /* Try to update an existing bss first */
- list_for_each_entry(bss, &priv->bss_list, list) {
- if (compare_ether_addr(bss->bss.bssid, atom->bssid))
- continue;
- /* ESSID lengths */
- if (bss->bss.data[1] != atom->data[1])
- continue;
- if (memcmp(&bss->bss.data[2], &atom->data[2],
- atom->data[1]))
- continue;
- found = 1;
+ struct wiphy *wiphy = priv_to_wiphy(priv);
+ struct ieee80211_channel *channel;
+ u8 *ie;
+ u8 ie_buf[46];
+ u64 timestamp;
+ s32 signal;
+ u16 capability;
+ u16 beacon_interval;
+ int ie_len;
+ int freq;
+ int len;
+
+ len = le16_to_cpu(bss->a.essid_len);
+
+ /* Reconstruct SSID and bitrate IEs to pass up */
+ ie_buf[0] = WLAN_EID_SSID;
+ ie_buf[1] = len;
+ memcpy(&ie_buf[2], bss->a.essid, len);
+
+ ie = ie_buf + len + 2;
+ ie_len = ie_buf[1] + 2;
+ switch (priv->firmware_type) {
+ case FIRMWARE_TYPE_SYMBOL:
+ ie_len += symbol_build_supp_rates(ie, bss->s.rates);
break;
- }
- /* Grab a bss off the free list */
- if (!found && !list_empty(&priv->bss_free_list)) {
- bss = list_entry(priv->bss_free_list.next,
- struct xbss_element, list);
- list_del(priv->bss_free_list.next);
+ case FIRMWARE_TYPE_INTERSIL:
+ ie_len += prism_build_supp_rates(ie, bss->p.rates);
+ break;
- list_add_tail(&bss->list, &priv->bss_list);
+ case FIRMWARE_TYPE_AGERE:
+ default:
+ break;
}
- if (bss) {
- /* Always update the BSS to get latest beacon info */
- memcpy(&bss->bss, atom, sizeof(bss->bss));
- bss->last_scanned = jiffies;
- }
+ freq = ieee80211_dsss_chan_to_freq(le16_to_cpu(bss->a.channel));
+ channel = ieee80211_get_channel(wiphy, freq);
+ timestamp = 0;
+ capability = le16_to_cpu(bss->a.capabilities);
+ beacon_interval = le16_to_cpu(bss->a.beacon_interv);
+ signal = SIGNAL_TO_MBM(le16_to_cpu(bss->a.level));
+
+ cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp,
+ capability, beacon_interval, ie_buf, ie_len,
+ signal, GFP_KERNEL);
}
-int orinoco_process_scan_results(struct orinoco_private *priv,
- unsigned char *buf,
- int len)
+void orinoco_add_extscan_result(struct orinoco_private *priv,
+ struct agere_ext_scan_info *bss,
+ size_t len)
{
- int offset; /* In the scan data */
- union hermes_scan_info *atom;
- int atom_len;
+ struct wiphy *wiphy = priv_to_wiphy(priv);
+ struct ieee80211_channel *channel;
+ u8 *ie;
+ u64 timestamp;
+ s32 signal;
+ u16 capability;
+ u16 beacon_interval;
+ size_t ie_len;
+ int chan, freq;
+
+ ie_len = len - sizeof(*bss);
+ ie = orinoco_get_ie(bss->data, ie_len, WLAN_EID_DS_PARAMS);
+ chan = ie ? ie[2] : 0;
+ freq = ieee80211_dsss_chan_to_freq(chan);
+ channel = ieee80211_get_channel(wiphy, freq);
+
+ timestamp = le64_to_cpu(bss->timestamp);
+ capability = le16_to_cpu(bss->capabilities);
+ beacon_interval = le16_to_cpu(bss->beacon_interval);
+ ie = bss->data;
+ signal = SIGNAL_TO_MBM(bss->level);
+
+ cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp,
+ capability, beacon_interval, ie, ie_len,
+ signal, GFP_KERNEL);
+}
+
+void orinoco_add_hostscan_results(struct orinoco_private *priv,
+ unsigned char *buf,
+ size_t len)
+{
+ int offset; /* In the scan data */
+ size_t atom_len;
+ bool abort = false;
switch (priv->firmware_type) {
case FIRMWARE_TYPE_AGERE:
atom_len = sizeof(struct agere_scan_apinfo);
offset = 0;
break;
+
case FIRMWARE_TYPE_SYMBOL:
/* Lack of documentation necessitates this hack.
* Different firmwares have 68 or 76 byte long atoms.
@@ -163,6 +182,7 @@ int orinoco_process_scan_results(struct orinoco_private *priv,
atom_len = 68;
offset = 0;
break;
+
case FIRMWARE_TYPE_INTERSIL:
offset = 4;
if (priv->has_hostscan) {
@@ -170,64 +190,41 @@ int orinoco_process_scan_results(struct orinoco_private *priv,
/* Sanity check for atom_len */
if (atom_len < sizeof(struct prism2_scan_apinfo)) {
printk(KERN_ERR "%s: Invalid atom_len in scan "
- "data: %d\n", priv->ndev->name,
+ "data: %zu\n", priv->ndev->name,
atom_len);
- return -EIO;
+ abort = true;
+ goto scan_abort;
}
} else
atom_len = offsetof(struct prism2_scan_apinfo, atim);
break;
+
default:
- return -EOPNOTSUPP;
+ abort = true;
+ goto scan_abort;
}
/* Check that we got an whole number of atoms */
if ((len - offset) % atom_len) {
- printk(KERN_ERR "%s: Unexpected scan data length %d, "
- "atom_len %d, offset %d\n", priv->ndev->name, len,
+ printk(KERN_ERR "%s: Unexpected scan data length %zu, "
+ "atom_len %zu, offset %d\n", priv->ndev->name, len,
atom_len, offset);
- return -EIO;
+ abort = true;
+ goto scan_abort;
}
- orinoco_clear_scan_results(priv, msecs_to_jiffies(15000));
-
- /* Read the entries one by one */
+ /* Process the entries one by one */
for (; offset + atom_len <= len; offset += atom_len) {
- int found = 0;
- struct bss_element *bss = NULL;
+ union hermes_scan_info *atom;
- /* Get next atom */
atom = (union hermes_scan_info *) (buf + offset);
- /* Try to update an existing bss first */
- list_for_each_entry(bss, &priv->bss_list, list) {
- if (compare_ether_addr(bss->bss.a.bssid, atom->a.bssid))
- continue;
- if (le16_to_cpu(bss->bss.a.essid_len) !=
- le16_to_cpu(atom->a.essid_len))
- continue;
- if (memcmp(bss->bss.a.essid, atom->a.essid,
- le16_to_cpu(atom->a.essid_len)))
- continue;
- found = 1;
- break;
- }
-
- /* Grab a bss off the free list */
- if (!found && !list_empty(&priv->bss_free_list)) {
- bss = list_entry(priv->bss_free_list.next,
- struct bss_element, list);
- list_del(priv->bss_free_list.next);
-
- list_add_tail(&bss->list, &priv->bss_list);
- }
-
- if (bss) {
- /* Always update the BSS to get latest beacon info */
- memcpy(&bss->bss, atom, sizeof(bss->bss));
- bss->last_scanned = jiffies;
- }
+ orinoco_add_hostscan_result(priv, atom);
}
- return 0;
+ scan_abort:
+ if (priv->scan_request) {
+ cfg80211_scan_done(priv->scan_request, abort);
+ priv->scan_request = NULL;
+ }
}
diff --git a/drivers/net/wireless/orinoco/scan.h b/drivers/net/wireless/orinoco/scan.h
index f319f7466af1..2dc4e046dbdb 100644
--- a/drivers/net/wireless/orinoco/scan.h
+++ b/drivers/net/wireless/orinoco/scan.h
@@ -9,21 +9,12 @@
struct orinoco_private;
struct agere_ext_scan_info;
-/* Setup and free memory for scan results */
-int orinoco_bss_data_allocate(struct orinoco_private *priv);
-void orinoco_bss_data_free(struct orinoco_private *priv);
-void orinoco_bss_data_init(struct orinoco_private *priv);
-
/* Add scan results */
-void orinoco_add_ext_scan_result(struct orinoco_private *priv,
- struct agere_ext_scan_info *atom);
-int orinoco_process_scan_results(struct orinoco_private *dev,
- unsigned char *buf,
- int len);
-
-/* Clear scan results */
-void orinoco_clear_scan_results(struct orinoco_private *priv,
- unsigned long scan_age);
-
+void orinoco_add_extscan_result(struct orinoco_private *priv,
+ struct agere_ext_scan_info *atom,
+ size_t len);
+void orinoco_add_hostscan_results(struct orinoco_private *dev,
+ unsigned char *buf,
+ size_t len);
#endif /* _ORINOCO_SCAN_H_ */
diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c
index 38e5198e44c7..c361310b885d 100644
--- a/drivers/net/wireless/orinoco/spectrum_cs.c
+++ b/drivers/net/wireless/orinoco/spectrum_cs.c
@@ -178,27 +178,25 @@ spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle)
static int
spectrum_cs_probe(struct pcmcia_device *link)
{
- struct net_device *dev;
struct orinoco_private *priv;
struct orinoco_pccard *card;
- dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
- spectrum_cs_hard_reset,
- spectrum_cs_stop_firmware);
- if (!dev)
+ priv = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
+ spectrum_cs_hard_reset,
+ spectrum_cs_stop_firmware);
+ if (!priv)
return -ENOMEM;
- priv = netdev_priv(dev);
card = priv->card;
/* Link both structures together */
card->p_dev = link;
- link->priv = dev;
+ link->priv = priv;
/* Interrupt setup */
link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = orinoco_interrupt;
- link->irq.Instance = dev;
+ link->irq.Instance = priv;
/* General socket configuration defaults can go here. In this
* client, we assume very little, and rely on the CIS for
@@ -219,14 +217,14 @@ spectrum_cs_probe(struct pcmcia_device *link)
*/
static void spectrum_cs_detach(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
+ struct orinoco_private *priv = link->priv;
if (link->dev_node)
- unregister_netdev(dev);
+ orinoco_if_del(priv);
spectrum_cs_release(link);
- free_orinocodev(dev);
+ free_orinocodev(priv);
} /* spectrum_cs_detach */
/*
@@ -306,8 +304,7 @@ next_entry:
static int
spectrum_cs_config(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = link->priv;
struct orinoco_pccard *card = priv->card;
hermes_t *hw = &priv->hw;
int last_fn, last_ret;
@@ -362,34 +359,31 @@ spectrum_cs_config(struct pcmcia_device *link)
pcmcia_request_configuration(link, &link->conf));
/* Ok, we have the configuration, prepare to register the netdev */
- dev->base_addr = link->io.BasePort1;
- dev->irq = link->irq.AssignedIRQ;
card->node.major = card->node.minor = 0;
/* Reset card */
if (spectrum_cs_hard_reset(priv) != 0)
goto failed;
- SET_NETDEV_DEV(dev, &handle_to_dev(link));
- /* Tell the stack we exist */
- if (register_netdev(dev) != 0) {
- printk(KERN_ERR PFX "register_netdev() failed\n");
+ /* Initialise the main driver */
+ if (orinoco_init(priv) != 0) {
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
+ goto failed;
+ }
+
+ /* Register an interface with the stack */
+ if (orinoco_if_add(priv, link->io.BasePort1,
+ link->irq.AssignedIRQ) != 0) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
goto failed;
}
/* At this point, the dev_node_t structure(s) needs to be
* initialized and arranged in a linked list at link->dev_node. */
- strcpy(card->node.dev_name, dev->name);
+ strcpy(card->node.dev_name, priv->ndev->name);
link->dev_node = &card->node; /* link->dev_node being non-NULL is also
* used to indicate that the
* net_device has been registered */
-
- /* Finally, report what we've done */
- printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
- "0x%04x-0x%04x\n", dev->name, dev_name(dev->dev.parent),
- link->irq.AssignedIRQ, link->io.BasePort1,
- link->io.BasePort1 + link->io.NumPorts1 - 1);
-
return 0;
cs_failed:
@@ -408,8 +402,7 @@ spectrum_cs_config(struct pcmcia_device *link)
static void
spectrum_cs_release(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = link->priv;
unsigned long flags;
/* We're committed to taking the device away now, so mark the
@@ -427,23 +420,11 @@ spectrum_cs_release(struct pcmcia_device *link)
static int
spectrum_cs_suspend(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
+ struct orinoco_private *priv = link->priv;
int err = 0;
/* Mark the device as stopped, to block IO until later */
- spin_lock_irqsave(&priv->lock, flags);
-
- err = __orinoco_down(dev);
- if (err)
- printk(KERN_WARNING "%s: Error %d downing interface\n",
- dev->name, err);
-
- netif_device_detach(dev);
- priv->hw_unavailable++;
-
- spin_unlock_irqrestore(&priv->lock, flags);
+ orinoco_down(priv);
return err;
}
@@ -451,33 +432,10 @@ spectrum_cs_suspend(struct pcmcia_device *link)
static int
spectrum_cs_resume(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
- int err;
-
- err = orinoco_reinit_firmware(dev);
- if (err) {
- printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
- dev->name, err);
- return -EIO;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
-
- netif_device_attach(dev);
- priv->hw_unavailable--;
+ struct orinoco_private *priv = link->priv;
+ int err = orinoco_up(priv);
- if (priv->open && !priv->hw_unavailable) {
- err = __orinoco_up(dev);
- if (err)
- printk(KERN_ERR "%s: Error %d restarting card\n",
- dev->name, err);
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
+ return err;
}
diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c
index 3f0814234392..b6ff3dbb7dd6 100644
--- a/drivers/net/wireless/orinoco/wext.c
+++ b/drivers/net/wireless/orinoco/wext.c
@@ -7,6 +7,7 @@
#include <linux/wireless.h>
#include <linux/ieee80211.h>
#include <net/iw_handler.h>
+#include <net/cfg80211.h>
#include "hermes.h"
#include "hermes_rid.h"
@@ -23,7 +24,7 @@
static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
struct iw_statistics *wstats = &priv->wstats;
int err;
@@ -51,7 +52,7 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
* here so we're not safe to sleep here. */
hermes_inquire(hw, HERMES_INQ_TALLIES);
- if (priv->iw_mode == IW_MODE_ADHOC) {
+ if (priv->iw_mode == NL80211_IFTYPE_ADHOC) {
memset(&wstats->qual, 0, sizeof(wstats->qual));
/* If a spy address is defined, we report stats of the
* first spy address - Jean II */
@@ -87,31 +88,12 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
/* Wireless extensions */
/********************************************************************/
-static int orinoco_ioctl_getname(struct net_device *dev,
- struct iw_request_info *info,
- char *name,
- char *extra)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- int numrates;
- int err;
-
- err = orinoco_hw_get_bitratelist(priv, &numrates, NULL, 0);
-
- if (!err && (numrates > 2))
- strcpy(name, "IEEE 802.11b");
- else
- strcpy(name, "IEEE 802.11-DS");
-
- return 0;
-}
-
static int orinoco_ioctl_setwap(struct net_device *dev,
struct iw_request_info *info,
struct sockaddr *ap_addr,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags;
static const u8 off_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
@@ -142,7 +124,7 @@ static int orinoco_ioctl_setwap(struct net_device *dev,
goto out;
}
- if (priv->iw_mode != IW_MODE_INFRA) {
+ if (priv->iw_mode != NL80211_IFTYPE_STATION) {
printk(KERN_WARNING "%s: Manual roaming supported only in "
"managed mode\n", dev->name);
err = -EOPNOTSUPP;
@@ -172,7 +154,7 @@ static int orinoco_ioctl_getwap(struct net_device *dev,
struct sockaddr *ap_addr,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
int err = 0;
@@ -190,184 +172,12 @@ static int orinoco_ioctl_getwap(struct net_device *dev,
return err;
}
-static int orinoco_ioctl_setmode(struct net_device *dev,
- struct iw_request_info *info,
- u32 *mode,
- char *extra)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- int err = -EINPROGRESS; /* Call commit handler */
- unsigned long flags;
-
- if (priv->iw_mode == *mode)
- return 0;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- switch (*mode) {
- case IW_MODE_ADHOC:
- if (!priv->has_ibss && !priv->has_port3)
- err = -EOPNOTSUPP;
- break;
-
- case IW_MODE_INFRA:
- break;
-
- case IW_MODE_MONITOR:
- if (priv->broken_monitor && !force_monitor) {
- printk(KERN_WARNING "%s: Monitor mode support is "
- "buggy in this firmware, not enabling\n",
- dev->name);
- err = -EOPNOTSUPP;
- }
- break;
-
- default:
- err = -EOPNOTSUPP;
- break;
- }
-
- if (err == -EINPROGRESS) {
- priv->iw_mode = *mode;
- set_port_type(priv);
- }
-
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_ioctl_getmode(struct net_device *dev,
- struct iw_request_info *info,
- u32 *mode,
- char *extra)
-{
- struct orinoco_private *priv = netdev_priv(dev);
-
- *mode = priv->iw_mode;
- return 0;
-}
-
-static int orinoco_ioctl_getiwrange(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *rrq,
- char *extra)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- int err = 0;
- struct iw_range *range = (struct iw_range *) extra;
- int numrates;
- int i, k;
-
- rrq->length = sizeof(struct iw_range);
- memset(range, 0, sizeof(struct iw_range));
-
- range->we_version_compiled = WIRELESS_EXT;
- range->we_version_source = 22;
-
- /* Set available channels/frequencies */
- range->num_channels = NUM_CHANNELS;
- k = 0;
- for (i = 0; i < NUM_CHANNELS; i++) {
- if (priv->channel_mask & (1 << i)) {
- range->freq[k].i = i + 1;
- range->freq[k].m = (ieee80211_dsss_chan_to_freq(i + 1) *
- 100000);
- range->freq[k].e = 1;
- k++;
- }
-
- if (k >= IW_MAX_FREQUENCIES)
- break;
- }
- range->num_frequency = k;
- range->sensitivity = 3;
-
- if (priv->has_wep) {
- range->max_encoding_tokens = ORINOCO_MAX_KEYS;
- range->encoding_size[0] = SMALL_KEY_SIZE;
- range->num_encoding_sizes = 1;
-
- if (priv->has_big_wep) {
- range->encoding_size[1] = LARGE_KEY_SIZE;
- range->num_encoding_sizes = 2;
- }
- }
-
- if (priv->has_wpa)
- range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP;
-
- if ((priv->iw_mode == IW_MODE_ADHOC) && (!SPY_NUMBER(priv))) {
- /* Quality stats meaningless in ad-hoc mode */
- } else {
- range->max_qual.qual = 0x8b - 0x2f;
- range->max_qual.level = 0x2f - 0x95 - 1;
- range->max_qual.noise = 0x2f - 0x95 - 1;
- /* Need to get better values */
- range->avg_qual.qual = 0x24;
- range->avg_qual.level = 0xC2;
- range->avg_qual.noise = 0x9E;
- }
-
- err = orinoco_hw_get_bitratelist(priv, &numrates,
- range->bitrate, IW_MAX_BITRATES);
- if (err)
- return err;
- range->num_bitrates = numrates;
-
- /* Set an indication of the max TCP throughput in bit/s that we can
- * expect using this interface. May be use for QoS stuff...
- * Jean II */
- if (numrates > 2)
- range->throughput = 5 * 1000 * 1000; /* ~5 Mb/s */
- else
- range->throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */
-
- range->min_rts = 0;
- range->max_rts = 2347;
- range->min_frag = 256;
- range->max_frag = 2346;
-
- range->min_pmp = 0;
- range->max_pmp = 65535000;
- range->min_pmt = 0;
- range->max_pmt = 65535 * 1000; /* ??? */
- range->pmp_flags = IW_POWER_PERIOD;
- range->pmt_flags = IW_POWER_TIMEOUT;
- range->pm_capa = (IW_POWER_PERIOD | IW_POWER_TIMEOUT |
- IW_POWER_UNICAST_R);
-
- range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
- range->retry_flags = IW_RETRY_LIMIT;
- range->r_time_flags = IW_RETRY_LIFETIME;
- range->min_retry = 0;
- range->max_retry = 65535; /* ??? */
- range->min_r_time = 0;
- range->max_r_time = 65535 * 1000; /* ??? */
-
- if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
- range->scan_capa = IW_SCAN_CAPA_ESSID;
- else
- range->scan_capa = IW_SCAN_CAPA_NONE;
-
- /* Event capability (kernel) */
- IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
- /* Event capability (driver) */
- IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY);
- IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
- IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
- IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
-
- return 0;
-}
-
static int orinoco_ioctl_setiwencode(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *erq,
char *keybuf)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int index = (erq->flags & IW_ENCODE_INDEX) - 1;
int setindex = priv->tx_key;
int encode_alg = priv->encode_alg;
@@ -469,7 +279,7 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev,
struct iw_point *erq,
char *keybuf)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int index = (erq->flags & IW_ENCODE_INDEX) - 1;
u16 xlen = 0;
unsigned long flags;
@@ -508,7 +318,7 @@ static int orinoco_ioctl_setessid(struct net_device *dev,
struct iw_point *erq,
char *essidbuf)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
unsigned long flags;
/* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
@@ -539,7 +349,7 @@ static int orinoco_ioctl_getessid(struct net_device *dev,
struct iw_point *erq,
char *essidbuf)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int active;
int err = 0;
unsigned long flags;
@@ -562,59 +372,18 @@ static int orinoco_ioctl_getessid(struct net_device *dev,
return 0;
}
-static int orinoco_ioctl_setnick(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *nrq,
- char *nickbuf)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
-
- if (nrq->length > IW_ESSID_MAX_SIZE)
- return -E2BIG;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- memset(priv->nick, 0, sizeof(priv->nick));
- memcpy(priv->nick, nickbuf, nrq->length);
-
- orinoco_unlock(priv, &flags);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-static int orinoco_ioctl_getnick(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *nrq,
- char *nickbuf)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE);
- orinoco_unlock(priv, &flags);
-
- nrq->length = strlen(priv->nick);
-
- return 0;
-}
-
static int orinoco_ioctl_setfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *frq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int chan = -1;
unsigned long flags;
int err = -EINPROGRESS; /* Call commit handler */
/* In infrastructure mode the AP sets the channel */
- if (priv->iw_mode == IW_MODE_INFRA)
+ if (priv->iw_mode == NL80211_IFTYPE_STATION)
return -EBUSY;
if ((frq->e == 0) && (frq->m <= 1000)) {
@@ -640,7 +409,7 @@ static int orinoco_ioctl_setfreq(struct net_device *dev,
return -EBUSY;
priv->channel = chan;
- if (priv->iw_mode == IW_MODE_MONITOR) {
+ 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 |
@@ -657,7 +426,7 @@ static int orinoco_ioctl_getfreq(struct net_device *dev,
struct iw_freq *frq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int tmp;
/* Locking done in there */
@@ -676,7 +445,7 @@ static int orinoco_ioctl_getsens(struct net_device *dev,
struct iw_param *srq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
u16 val;
int err;
@@ -705,7 +474,7 @@ static int orinoco_ioctl_setsens(struct net_device *dev,
struct iw_param *srq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int val = srq->value;
unsigned long flags;
@@ -728,7 +497,7 @@ static int orinoco_ioctl_setrts(struct net_device *dev,
struct iw_param *rrq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int val = rrq->value;
unsigned long flags;
@@ -752,7 +521,7 @@ static int orinoco_ioctl_getrts(struct net_device *dev,
struct iw_param *rrq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
rrq->value = priv->rts_thresh;
rrq->disabled = (rrq->value == 2347);
@@ -766,7 +535,7 @@ static int orinoco_ioctl_setfrag(struct net_device *dev,
struct iw_param *frq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags;
@@ -806,7 +575,7 @@ static int orinoco_ioctl_getfrag(struct net_device *dev,
struct iw_param *frq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
int err;
u16 val;
@@ -847,7 +616,7 @@ static int orinoco_ioctl_setrate(struct net_device *dev,
struct iw_param *rrq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int ratemode;
int bitrate; /* 100s of kilobits */
unsigned long flags;
@@ -881,7 +650,7 @@ static int orinoco_ioctl_getrate(struct net_device *dev,
struct iw_param *rrq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int err = 0;
int bitrate, automatic;
unsigned long flags;
@@ -910,7 +679,7 @@ static int orinoco_ioctl_setpower(struct net_device *dev,
struct iw_param *prq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags;
@@ -964,7 +733,7 @@ static int orinoco_ioctl_getpower(struct net_device *dev,
struct iw_param *prq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
int err = 0;
u16 enable, period, timeout, mcast;
@@ -1018,7 +787,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev,
union iwreq_data *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct iw_point *encoding = &wrqu->encoding;
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
int idx, alg = ext->alg, set_key = 1;
@@ -1079,7 +848,6 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev,
case IW_ENCODE_ALG_TKIP:
{
- hermes_t *hw = &priv->hw;
u8 *tkip_iv = NULL;
if (!priv->has_wpa ||
@@ -1094,7 +862,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev,
if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
tkip_iv = &ext->rx_seq[0];
- err = __orinoco_hw_set_tkip_key(hw, idx,
+ err = __orinoco_hw_set_tkip_key(priv, idx,
ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
(u8 *) &priv->tkip_key[idx],
tkip_iv, NULL);
@@ -1120,7 +888,7 @@ static int orinoco_ioctl_get_encodeext(struct net_device *dev,
union iwreq_data *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct iw_point *encoding = &wrqu->encoding;
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
int idx, max_key_len;
@@ -1177,7 +945,7 @@ static int orinoco_ioctl_set_auth(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
struct iw_param *param = &wrqu->param;
unsigned long flags;
@@ -1255,7 +1023,7 @@ static int orinoco_ioctl_get_auth(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct iw_param *param = &wrqu->param;
unsigned long flags;
int ret = 0;
@@ -1295,7 +1063,7 @@ static int orinoco_ioctl_set_genie(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
u8 *buf;
unsigned long flags;
@@ -1338,7 +1106,7 @@ static int orinoco_ioctl_get_genie(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
unsigned long flags;
int err = 0;
@@ -1367,7 +1135,7 @@ static int orinoco_ioctl_set_mlme(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
struct iw_mlme *mlme = (struct iw_mlme *)extra;
unsigned long flags;
@@ -1408,7 +1176,7 @@ static int orinoco_ioctl_getretry(struct net_device *dev,
struct iw_param *rrq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
int err = 0;
u16 short_limit, long_limit, lifetime;
@@ -1462,7 +1230,7 @@ static int orinoco_ioctl_reset(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
if (!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -1487,7 +1255,7 @@ static int orinoco_ioctl_setibssport(struct net_device *dev,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int val = *((int *) extra);
unsigned long flags;
@@ -1508,7 +1276,7 @@ static int orinoco_ioctl_getibssport(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int *val = (int *) extra;
*val = priv->ibss_port;
@@ -1520,7 +1288,7 @@ static int orinoco_ioctl_setport3(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int val = *((int *) extra);
int err = 0;
unsigned long flags;
@@ -1566,7 +1334,7 @@ static int orinoco_ioctl_getport3(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int *val = (int *) extra;
*val = priv->prefer_port3;
@@ -1578,7 +1346,7 @@ static int orinoco_ioctl_setpreamble(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
unsigned long flags;
int val;
@@ -1610,7 +1378,7 @@ static int orinoco_ioctl_getpreamble(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int *val = (int *) extra;
if (!priv->has_preamble)
@@ -1630,7 +1398,7 @@ static int orinoco_ioctl_getrid(struct net_device *dev,
struct iw_point *data,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
int rid = data->flags;
u16 length;
@@ -1661,519 +1429,6 @@ static int orinoco_ioctl_getrid(struct net_device *dev,
return err;
}
-/* Trigger a scan (look for other cells in the vicinity) */
-static int orinoco_ioctl_setscan(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *srq,
- char *extra)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- hermes_t *hw = &priv->hw;
- struct iw_scan_req *si = (struct iw_scan_req *) extra;
- int err = 0;
- unsigned long flags;
-
- /* Note : you may have realised that, as this is a SET operation,
- * this is privileged and therefore a normal user can't
- * perform scanning.
- * This is not an error, while the device perform scanning,
- * traffic doesn't flow, so it's a perfect DoS...
- * Jean II */
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- /* Scanning with port 0 disabled would fail */
- if (!netif_running(dev)) {
- err = -ENETDOWN;
- goto out;
- }
-
- /* In monitor mode, the scan results are always empty.
- * Probe responses are passed to the driver as received
- * frames and could be processed in software. */
- if (priv->iw_mode == IW_MODE_MONITOR) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- /* Note : because we don't lock out the irq handler, the way
- * we access scan variables in priv is critical.
- * o scan_inprogress : not touched by irq handler
- * o scan_mode : not touched by irq handler
- * Before modifying anything on those variables, please think hard !
- * Jean II */
-
- /* Save flags */
- priv->scan_mode = srq->flags;
-
- /* Always trigger scanning, even if it's in progress.
- * This way, if the info frame get lost, we will recover somewhat
- * gracefully - Jean II */
-
- if (priv->has_hostscan) {
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_SYMBOL:
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFHOSTSCAN_SYMBOL,
- HERMES_HOSTSCAN_SYMBOL_ONCE |
- HERMES_HOSTSCAN_SYMBOL_BCAST);
- break;
- case FIRMWARE_TYPE_INTERSIL: {
- __le16 req[3];
-
- req[0] = cpu_to_le16(0x3fff); /* All channels */
- req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */
- req[2] = 0; /* Any ESSID */
- err = HERMES_WRITE_RECORD(hw, USER_BAP,
- HERMES_RID_CNFHOSTSCAN, &req);
- }
- break;
- case FIRMWARE_TYPE_AGERE:
- if (priv->scan_mode & IW_SCAN_THIS_ESSID) {
- struct hermes_idstring idbuf;
- size_t len = min(sizeof(idbuf.val),
- (size_t) si->essid_len);
- idbuf.len = cpu_to_le16(len);
- memcpy(idbuf.val, si->essid, len);
-
- err = hermes_write_ltv(hw, USER_BAP,
- HERMES_RID_CNFSCANSSID_AGERE,
- HERMES_BYTES_TO_RECLEN(len + 2),
- &idbuf);
- } else
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFSCANSSID_AGERE,
- 0); /* Any ESSID */
- if (err)
- break;
-
- if (priv->has_ext_scan) {
- /* Clear scan results at the start of
- * an extended scan */
- orinoco_clear_scan_results(priv,
- msecs_to_jiffies(15000));
-
- /* TODO: Is this available on older firmware?
- * Can we use it to scan specific channels
- * for IW_SCAN_THIS_FREQ? */
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFSCANCHANNELS2GHZ,
- 0x7FFF);
- if (err)
- goto out;
-
- err = hermes_inquire(hw,
- HERMES_INQ_CHANNELINFO);
- } else
- err = hermes_inquire(hw, HERMES_INQ_SCAN);
- break;
- }
- } else
- err = hermes_inquire(hw, HERMES_INQ_SCAN);
-
- /* One more client */
- if (!err)
- priv->scan_inprogress = 1;
-
- out:
- orinoco_unlock(priv, &flags);
- return err;
-}
-
-#define MAX_CUSTOM_LEN 64
-
-/* Translate scan data returned from the card to a card independant
- * format that the Wireless Tools will understand - Jean II */
-static inline char *orinoco_translate_scan(struct net_device *dev,
- struct iw_request_info *info,
- char *current_ev,
- char *end_buf,
- union hermes_scan_info *bss,
- unsigned long last_scanned)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- u16 capabilities;
- u16 channel;
- struct iw_event iwe; /* Temporary buffer */
- char custom[MAX_CUSTOM_LEN];
-
- memset(&iwe, 0, sizeof(iwe));
-
- /* First entry *MUST* be the AP MAC address */
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, bss->a.bssid, ETH_ALEN);
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_ADDR_LEN);
-
- /* Other entries will be displayed in the order we give them */
-
- /* Add the ESSID */
- iwe.u.data.length = le16_to_cpu(bss->a.essid_len);
- if (iwe.u.data.length > 32)
- iwe.u.data.length = 32;
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, bss->a.essid);
-
- /* Add mode */
- iwe.cmd = SIOCGIWMODE;
- capabilities = le16_to_cpu(bss->a.capabilities);
- if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
- if (capabilities & WLAN_CAPABILITY_ESS)
- iwe.u.mode = IW_MODE_MASTER;
- else
- iwe.u.mode = IW_MODE_ADHOC;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_UINT_LEN);
- }
-
- channel = bss->s.channel;
- if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
- /* Add channel and frequency */
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = channel;
- iwe.u.freq.e = 0;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_FREQ_LEN);
-
- iwe.u.freq.m = ieee80211_dsss_chan_to_freq(channel) * 100000;
- iwe.u.freq.e = 1;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_FREQ_LEN);
- }
-
- /* Add quality statistics. level and noise in dB. No link quality */
- iwe.cmd = IWEVQUAL;
- iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID;
- iwe.u.qual.level = (__u8) le16_to_cpu(bss->a.level) - 0x95;
- iwe.u.qual.noise = (__u8) le16_to_cpu(bss->a.noise) - 0x95;
- /* Wireless tools prior to 27.pre22 will show link quality
- * anyway, so we provide a reasonable value. */
- if (iwe.u.qual.level > iwe.u.qual.noise)
- iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
- else
- iwe.u.qual.qual = 0;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_QUAL_LEN);
-
- /* Add encryption capability */
- iwe.cmd = SIOCGIWENCODE;
- if (capabilities & WLAN_CAPABILITY_PRIVACY)
- iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- iwe.u.data.length = 0;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, NULL);
-
- /* Bit rate is not available in Lucent/Agere firmwares */
- if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
- char *current_val = current_ev + iwe_stream_lcp_len(info);
- int i;
- int step;
-
- if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
- step = 2;
- else
- step = 1;
-
- iwe.cmd = SIOCGIWRATE;
- /* Those two flags are ignored... */
- iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
- /* Max 10 values */
- for (i = 0; i < 10; i += step) {
- /* NULL terminated */
- if (bss->p.rates[i] == 0x0)
- break;
- /* Bit rate given in 500 kb/s units (+ 0x80) */
- iwe.u.bitrate.value =
- ((bss->p.rates[i] & 0x7f) * 500000);
- current_val = iwe_stream_add_value(info, current_ev,
- current_val,
- end_buf, &iwe,
- IW_EV_PARAM_LEN);
- }
- /* Check if we added any event */
- if ((current_val - current_ev) > iwe_stream_lcp_len(info))
- current_ev = current_val;
- }
-
- /* Beacon interval */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- "bcn_int=%d",
- le16_to_cpu(bss->a.beacon_interv));
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- /* Capabilites */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- "capab=0x%04x",
- capabilities);
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- /* Add EXTRA: Age to display seconds since last beacon/probe response
- * for given network. */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- " Last beacon: %dms ago",
- jiffies_to_msecs(jiffies - last_scanned));
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- return current_ev;
-}
-
-static inline char *orinoco_translate_ext_scan(struct net_device *dev,
- struct iw_request_info *info,
- char *current_ev,
- char *end_buf,
- struct agere_ext_scan_info *bss,
- unsigned long last_scanned)
-{
- u16 capabilities;
- u16 channel;
- struct iw_event iwe; /* Temporary buffer */
- char custom[MAX_CUSTOM_LEN];
- u8 *ie;
-
- memset(&iwe, 0, sizeof(iwe));
-
- /* First entry *MUST* be the AP MAC address */
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_ADDR_LEN);
-
- /* Other entries will be displayed in the order we give them */
-
- /* Add the ESSID */
- ie = bss->data;
- iwe.u.data.length = ie[1];
- if (iwe.u.data.length) {
- if (iwe.u.data.length > 32)
- iwe.u.data.length = 32;
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, &ie[2]);
- }
-
- /* Add mode */
- capabilities = le16_to_cpu(bss->capabilities);
- if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
- iwe.cmd = SIOCGIWMODE;
- if (capabilities & WLAN_CAPABILITY_ESS)
- iwe.u.mode = IW_MODE_MASTER;
- else
- iwe.u.mode = IW_MODE_ADHOC;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_UINT_LEN);
- }
-
- ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_DS_PARAMS);
- channel = ie ? ie[2] : 0;
- if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
- /* Add channel and frequency */
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = channel;
- iwe.u.freq.e = 0;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_FREQ_LEN);
-
- iwe.u.freq.m = ieee80211_dsss_chan_to_freq(channel) * 100000;
- iwe.u.freq.e = 1;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_FREQ_LEN);
- }
-
- /* Add quality statistics. level and noise in dB. No link quality */
- iwe.cmd = IWEVQUAL;
- iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID;
- iwe.u.qual.level = bss->level - 0x95;
- iwe.u.qual.noise = bss->noise - 0x95;
- /* Wireless tools prior to 27.pre22 will show link quality
- * anyway, so we provide a reasonable value. */
- if (iwe.u.qual.level > iwe.u.qual.noise)
- iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
- else
- iwe.u.qual.qual = 0;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_QUAL_LEN);
-
- /* Add encryption capability */
- iwe.cmd = SIOCGIWENCODE;
- if (capabilities & WLAN_CAPABILITY_PRIVACY)
- iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- iwe.u.data.length = 0;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, NULL);
-
- /* WPA IE */
- ie = orinoco_get_wpa_ie(bss->data, sizeof(bss->data));
- if (ie) {
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = ie[1] + 2;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, ie);
- }
-
- /* RSN IE */
- ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_RSN);
- if (ie) {
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = ie[1] + 2;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, ie);
- }
-
- ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_SUPP_RATES);
- if (ie) {
- char *p = current_ev + iwe_stream_lcp_len(info);
- int i;
-
- iwe.cmd = SIOCGIWRATE;
- /* Those two flags are ignored... */
- iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
-
- for (i = 2; i < (ie[1] + 2); i++) {
- iwe.u.bitrate.value = ((ie[i] & 0x7F) * 500000);
- p = iwe_stream_add_value(info, current_ev, p, end_buf,
- &iwe, IW_EV_PARAM_LEN);
- }
- /* Check if we added any event */
- if (p > (current_ev + iwe_stream_lcp_len(info)))
- current_ev = p;
- }
-
- /* Timestamp */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length =
- snprintf(custom, MAX_CUSTOM_LEN, "tsf=%016llx",
- (unsigned long long) le64_to_cpu(bss->timestamp));
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- /* Beacon interval */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- "bcn_int=%d",
- le16_to_cpu(bss->beacon_interval));
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- /* Capabilites */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- "capab=0x%04x",
- capabilities);
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- /* Add EXTRA: Age to display seconds since last beacon/probe response
- * for given network. */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- " Last beacon: %dms ago",
- jiffies_to_msecs(jiffies - last_scanned));
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- return current_ev;
-}
-
-/* Return results of a scan */
-static int orinoco_ioctl_getscan(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *srq,
- char *extra)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- int err = 0;
- unsigned long flags;
- char *current_ev = extra;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- if (priv->scan_inprogress) {
- /* Important note : we don't want to block the caller
- * until results are ready for various reasons.
- * First, managing wait queues is complex and racy.
- * Second, we grab some rtnetlink lock before comming
- * here (in dev_ioctl()).
- * Third, we generate an Wireless Event, so the
- * caller can wait itself on that - Jean II */
- err = -EAGAIN;
- goto out;
- }
-
- if (priv->has_ext_scan) {
- struct xbss_element *bss;
-
- list_for_each_entry(bss, &priv->bss_list, list) {
- /* Translate this entry to WE format */
- current_ev =
- orinoco_translate_ext_scan(dev, info,
- current_ev,
- extra + srq->length,
- &bss->bss,
- bss->last_scanned);
-
- /* Check if there is space for one more entry */
- if ((extra + srq->length - current_ev)
- <= IW_EV_ADDR_LEN) {
- /* Ask user space to try again with a
- * bigger buffer */
- err = -E2BIG;
- goto out;
- }
- }
-
- } else {
- struct bss_element *bss;
-
- list_for_each_entry(bss, &priv->bss_list, list) {
- /* Translate this entry to WE format */
- current_ev = orinoco_translate_scan(dev, info,
- current_ev,
- extra + srq->length,
- &bss->bss,
- bss->last_scanned);
-
- /* Check if there is space for one more entry */
- if ((extra + srq->length - current_ev)
- <= IW_EV_ADDR_LEN) {
- /* Ask user space to try again with a
- * bigger buffer */
- err = -E2BIG;
- goto out;
- }
- }
- }
-
- srq->length = (current_ev - extra);
- srq->flags = (__u16) priv->scan_mode;
-
-out:
- orinoco_unlock(priv, &flags);
- return err;
-}
/* Commit handler, called after set operations */
static int orinoco_ioctl_commit(struct net_device *dev,
@@ -2181,50 +1436,17 @@ static int orinoco_ioctl_commit(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
- struct hermes *hw = &priv->hw;
+ struct orinoco_private *priv = ndev_priv(dev);
unsigned long flags;
int err = 0;
if (!priv->open)
return 0;
- if (priv->broken_disableport) {
- orinoco_reset(&priv->reset_work);
- return 0;
- }
-
if (orinoco_lock(priv, &flags) != 0)
return err;
- err = hermes_disable_port(hw, 0);
- if (err) {
- printk(KERN_WARNING "%s: Unable to disable port "
- "while reconfiguring card\n", dev->name);
- priv->broken_disableport = 1;
- goto out;
- }
-
- err = __orinoco_program_rids(dev);
- if (err) {
- printk(KERN_WARNING "%s: Unable to reconfigure card\n",
- dev->name);
- goto out;
- }
-
- err = hermes_enable_port(hw, 0);
- if (err) {
- printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
- dev->name);
- goto out;
- }
-
- out:
- if (err) {
- printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
- schedule_work(&priv->reset_work);
- err = 0;
- }
+ err = orinoco_commit(priv);
orinoco_unlock(priv, &flags);
return err;
@@ -2258,26 +1480,24 @@ static const struct iw_priv_args orinoco_privtab[] = {
[IW_IOCTL_IDX(id)] = (iw_handler) func
static const iw_handler orinoco_handler[] = {
STD_IW_HANDLER(SIOCSIWCOMMIT, orinoco_ioctl_commit),
- STD_IW_HANDLER(SIOCGIWNAME, orinoco_ioctl_getname),
+ 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, orinoco_ioctl_setmode),
- STD_IW_HANDLER(SIOCGIWMODE, orinoco_ioctl_getmode),
+ 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, orinoco_ioctl_getiwrange),
+ 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, orinoco_ioctl_setscan),
- STD_IW_HANDLER(SIOCGIWSCAN, orinoco_ioctl_getscan),
+ 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(SIOCSIWNICKN, orinoco_ioctl_setnick),
- STD_IW_HANDLER(SIOCGIWNICKN, orinoco_ioctl_getnick),
STD_IW_HANDLER(SIOCSIWRATE, orinoco_ioctl_setrate),
STD_IW_HANDLER(SIOCGIWRATE, orinoco_ioctl_getrate),
STD_IW_HANDLER(SIOCSIWRTS, orinoco_ioctl_setrts),
diff --git a/drivers/net/wireless/p54/Makefile b/drivers/net/wireless/p54/Makefile
index c2050dee6293..b542e68f1781 100644
--- a/drivers/net/wireless/p54/Makefile
+++ b/drivers/net/wireless/p54/Makefile
@@ -1,3 +1,6 @@
+p54common-objs := eeprom.o fwio.o txrx.o main.o
+p54common-$(CONFIG_P54_LEDS) += led.o
+
obj-$(CONFIG_P54_COMMON) += p54common.o
obj-$(CONFIG_P54_USB) += p54usb.o
obj-$(CONFIG_P54_PCI) += p54pci.o
diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c
new file mode 100644
index 000000000000..0efe67deedee
--- /dev/null
+++ b/drivers/net/wireless/p54/eeprom.c
@@ -0,0 +1,753 @@
+/*
+ * EEPROM parser code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * 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/init.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+#include <linux/sort.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "eeprom.h"
+#include "lmac.h"
+
+static struct ieee80211_rate p54_bgrates[] = {
+ { .bitrate = 10, .hw_value = 0, },
+ { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 110, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 60, .hw_value = 4, },
+ { .bitrate = 90, .hw_value = 5, },
+ { .bitrate = 120, .hw_value = 6, },
+ { .bitrate = 180, .hw_value = 7, },
+ { .bitrate = 240, .hw_value = 8, },
+ { .bitrate = 360, .hw_value = 9, },
+ { .bitrate = 480, .hw_value = 10, },
+ { .bitrate = 540, .hw_value = 11, },
+};
+
+static struct ieee80211_rate p54_arates[] = {
+ { .bitrate = 60, .hw_value = 4, },
+ { .bitrate = 90, .hw_value = 5, },
+ { .bitrate = 120, .hw_value = 6, },
+ { .bitrate = 180, .hw_value = 7, },
+ { .bitrate = 240, .hw_value = 8, },
+ { .bitrate = 360, .hw_value = 9, },
+ { .bitrate = 480, .hw_value = 10, },
+ { .bitrate = 540, .hw_value = 11, },
+};
+
+#define CHAN_HAS_CAL BIT(0)
+#define CHAN_HAS_LIMIT BIT(1)
+#define CHAN_HAS_CURVE BIT(2)
+#define CHAN_HAS_ALL (CHAN_HAS_CAL | CHAN_HAS_LIMIT | CHAN_HAS_CURVE)
+
+struct p54_channel_entry {
+ u16 freq;
+ u16 data;
+ int index;
+ enum ieee80211_band band;
+};
+
+struct p54_channel_list {
+ struct p54_channel_entry *channels;
+ size_t entries;
+ size_t max_entries;
+ size_t band_channel_num[IEEE80211_NUM_BANDS];
+};
+
+static int p54_get_band_from_freq(u16 freq)
+{
+ /* FIXME: sync these values with the 802.11 spec */
+
+ if ((freq >= 2412) && (freq <= 2484))
+ return IEEE80211_BAND_2GHZ;
+
+ if ((freq >= 4920) && (freq <= 5825))
+ return IEEE80211_BAND_5GHZ;
+
+ return -1;
+}
+
+static int p54_compare_channels(const void *_a,
+ const void *_b)
+{
+ const struct p54_channel_entry *a = _a;
+ const struct p54_channel_entry *b = _b;
+
+ return a->index - b->index;
+}
+
+static int p54_fill_band_bitrates(struct ieee80211_hw *dev,
+ struct ieee80211_supported_band *band_entry,
+ enum ieee80211_band band)
+{
+ /* TODO: generate rate array dynamically */
+
+ switch (band) {
+ case IEEE80211_BAND_2GHZ:
+ band_entry->bitrates = p54_bgrates;
+ band_entry->n_bitrates = ARRAY_SIZE(p54_bgrates);
+ break;
+ case IEEE80211_BAND_5GHZ:
+ band_entry->bitrates = p54_arates;
+ band_entry->n_bitrates = ARRAY_SIZE(p54_arates);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int p54_generate_band(struct ieee80211_hw *dev,
+ struct p54_channel_list *list,
+ enum ieee80211_band band)
+{
+ struct p54_common *priv = dev->priv;
+ struct ieee80211_supported_band *tmp, *old;
+ unsigned int i, j;
+ int ret = -ENOMEM;
+
+ if ((!list->entries) || (!list->band_channel_num[band]))
+ return 0;
+
+ tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
+ if (!tmp)
+ goto err_out;
+
+ tmp->channels = kzalloc(sizeof(struct ieee80211_channel) *
+ list->band_channel_num[band], GFP_KERNEL);
+ if (!tmp->channels)
+ goto err_out;
+
+ ret = p54_fill_band_bitrates(dev, tmp, band);
+ if (ret)
+ goto err_out;
+
+ for (i = 0, j = 0; (j < list->band_channel_num[band]) &&
+ (i < list->entries); i++) {
+
+ if (list->channels[i].band != band)
+ continue;
+
+ if (list->channels[i].data != CHAN_HAS_ALL) {
+ printk(KERN_ERR "%s:%s%s%s is/are missing for "
+ "channel:%d [%d MHz].\n",
+ wiphy_name(dev->wiphy),
+ (list->channels[i].data & CHAN_HAS_CAL ? "" :
+ " [iqauto calibration data]"),
+ (list->channels[i].data & CHAN_HAS_LIMIT ? "" :
+ " [output power limits]"),
+ (list->channels[i].data & CHAN_HAS_CURVE ? "" :
+ " [curve data]"),
+ list->channels[i].index, list->channels[i].freq);
+ }
+
+ tmp->channels[j].band = list->channels[i].band;
+ tmp->channels[j].center_freq = list->channels[i].freq;
+ j++;
+ }
+
+ tmp->n_channels = list->band_channel_num[band];
+ old = priv->band_table[band];
+ priv->band_table[band] = tmp;
+ if (old) {
+ kfree(old->channels);
+ kfree(old);
+ }
+
+ return 0;
+
+err_out:
+ if (tmp) {
+ kfree(tmp->channels);
+ kfree(tmp);
+ }
+
+ return ret;
+}
+
+static void p54_update_channel_param(struct p54_channel_list *list,
+ u16 freq, u16 data)
+{
+ int band, i;
+
+ /*
+ * usually all lists in the eeprom are mostly sorted.
+ * so it's very likely that the entry we are looking for
+ * is right at the end of the list
+ */
+ for (i = list->entries; i >= 0; i--) {
+ if (freq == list->channels[i].freq) {
+ list->channels[i].data |= data;
+ break;
+ }
+ }
+
+ if ((i < 0) && (list->entries < list->max_entries)) {
+ /* entry does not exist yet. Initialize a new one. */
+ band = p54_get_band_from_freq(freq);
+
+ /*
+ * filter out frequencies which don't belong into
+ * any supported band.
+ */
+ if (band < 0)
+ return ;
+
+ i = list->entries++;
+ list->band_channel_num[band]++;
+
+ list->channels[i].freq = freq;
+ list->channels[i].data = data;
+ list->channels[i].band = band;
+ list->channels[i].index = ieee80211_frequency_to_channel(freq);
+ /* TODO: parse output_limit and fill max_power */
+ }
+}
+
+static int p54_generate_channel_lists(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_channel_list *list;
+ unsigned int i, j, max_channel_num;
+ int ret = -ENOMEM;
+ u16 freq;
+
+ if ((priv->iq_autocal_len != priv->curve_data->entries) ||
+ (priv->iq_autocal_len != priv->output_limit->entries))
+ printk(KERN_ERR "%s: EEPROM is damaged... you may not be able"
+ "to use all channels with this device.\n",
+ wiphy_name(dev->wiphy));
+
+ max_channel_num = max_t(unsigned int, priv->output_limit->entries,
+ priv->iq_autocal_len);
+ max_channel_num = max_t(unsigned int, max_channel_num,
+ priv->curve_data->entries);
+
+ list = kzalloc(sizeof(*list), GFP_KERNEL);
+ if (!list)
+ goto free;
+
+ list->max_entries = max_channel_num;
+ list->channels = kzalloc(sizeof(struct p54_channel_entry) *
+ max_channel_num, GFP_KERNEL);
+ if (!list->channels)
+ goto free;
+
+ for (i = 0; i < max_channel_num; i++) {
+ if (i < priv->iq_autocal_len) {
+ freq = le16_to_cpu(priv->iq_autocal[i].freq);
+ p54_update_channel_param(list, freq, CHAN_HAS_CAL);
+ }
+
+ if (i < priv->output_limit->entries) {
+ freq = le16_to_cpup((__le16 *) (i *
+ priv->output_limit->entry_size +
+ priv->output_limit->offset +
+ priv->output_limit->data));
+
+ p54_update_channel_param(list, freq, CHAN_HAS_LIMIT);
+ }
+
+ if (i < priv->curve_data->entries) {
+ freq = le16_to_cpup((__le16 *) (i *
+ priv->curve_data->entry_size +
+ priv->curve_data->offset +
+ priv->curve_data->data));
+
+ p54_update_channel_param(list, freq, CHAN_HAS_CURVE);
+ }
+ }
+
+ /* sort the list by the channel index */
+ sort(list->channels, list->entries, sizeof(struct p54_channel_entry),
+ p54_compare_channels, NULL);
+
+ for (i = 0, j = 0; i < IEEE80211_NUM_BANDS; i++) {
+ if (list->band_channel_num[i]) {
+ ret = p54_generate_band(dev, list, i);
+ if (ret)
+ goto free;
+
+ j++;
+ }
+ }
+ if (j == 0) {
+ /* no useable band available. */
+ ret = -EINVAL;
+ }
+
+free:
+ if (list) {
+ kfree(list->channels);
+ kfree(list);
+ }
+
+ return ret;
+}
+
+static int p54_convert_rev0(struct ieee80211_hw *dev,
+ struct pda_pa_curve_data *curve_data)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_pa_curve_data_sample *dst;
+ struct pda_pa_curve_data_sample_rev0 *src;
+ size_t cd_len = sizeof(*curve_data) +
+ (curve_data->points_per_channel*sizeof(*dst) + 2) *
+ curve_data->channels;
+ unsigned int i, j;
+ void *source, *target;
+
+ priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len,
+ GFP_KERNEL);
+ if (!priv->curve_data)
+ return -ENOMEM;
+
+ priv->curve_data->entries = curve_data->channels;
+ priv->curve_data->entry_size = sizeof(__le16) +
+ sizeof(*dst) * curve_data->points_per_channel;
+ priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
+ priv->curve_data->len = cd_len;
+ memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
+ source = curve_data->data;
+ target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
+ for (i = 0; i < curve_data->channels; i++) {
+ __le16 *freq = source;
+ source += sizeof(__le16);
+ *((__le16 *)target) = *freq;
+ target += sizeof(__le16);
+ for (j = 0; j < curve_data->points_per_channel; j++) {
+ dst = target;
+ src = source;
+
+ dst->rf_power = src->rf_power;
+ dst->pa_detector = src->pa_detector;
+ dst->data_64qam = src->pcv;
+ /* "invent" the points for the other modulations */
+#define SUB(x, y) (u8)(((x) - (y)) > (x) ? 0 : (x) - (y))
+ dst->data_16qam = SUB(src->pcv, 12);
+ dst->data_qpsk = SUB(dst->data_16qam, 12);
+ dst->data_bpsk = SUB(dst->data_qpsk, 12);
+ dst->data_barker = SUB(dst->data_bpsk, 14);
+#undef SUB
+ target += sizeof(*dst);
+ source += sizeof(*src);
+ }
+ }
+
+ return 0;
+}
+
+static int p54_convert_rev1(struct ieee80211_hw *dev,
+ struct pda_pa_curve_data *curve_data)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_pa_curve_data_sample *dst;
+ struct pda_pa_curve_data_sample_rev1 *src;
+ size_t cd_len = sizeof(*curve_data) +
+ (curve_data->points_per_channel*sizeof(*dst) + 2) *
+ curve_data->channels;
+ unsigned int i, j;
+ void *source, *target;
+
+ priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data),
+ GFP_KERNEL);
+ if (!priv->curve_data)
+ return -ENOMEM;
+
+ priv->curve_data->entries = curve_data->channels;
+ priv->curve_data->entry_size = sizeof(__le16) +
+ sizeof(*dst) * curve_data->points_per_channel;
+ priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
+ priv->curve_data->len = cd_len;
+ memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
+ source = curve_data->data;
+ target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
+ for (i = 0; i < curve_data->channels; i++) {
+ __le16 *freq = source;
+ source += sizeof(__le16);
+ *((__le16 *)target) = *freq;
+ target += sizeof(__le16);
+ for (j = 0; j < curve_data->points_per_channel; j++) {
+ memcpy(target, source, sizeof(*src));
+
+ target += sizeof(*dst);
+ source += sizeof(*src);
+ }
+ source++;
+ }
+
+ return 0;
+}
+
+static const char *p54_rf_chips[] = { "INVALID-0", "Duette3", "Duette2",
+ "Frisbee", "Xbow", "Longbow", "INVALID-6", "INVALID-7" };
+
+static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len,
+ u16 type)
+{
+ struct p54_common *priv = dev->priv;
+ int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0;
+ int entry_size = sizeof(struct pda_rssi_cal_entry) + offset;
+ int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2;
+ int i;
+
+ if (len != (entry_size * num_entries)) {
+ printk(KERN_ERR "%s: unknown rssi calibration data packing "
+ " type:(%x) len:%d.\n",
+ wiphy_name(dev->wiphy), type, len);
+
+ print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE,
+ data, len);
+
+ printk(KERN_ERR "%s: please report this issue.\n",
+ wiphy_name(dev->wiphy));
+ return;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ struct pda_rssi_cal_entry *cal = data +
+ (offset + i * entry_size);
+ priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul);
+ priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add);
+ }
+}
+
+static void p54_parse_default_country(struct ieee80211_hw *dev,
+ void *data, int len)
+{
+ struct pda_country *country;
+
+ if (len != sizeof(*country)) {
+ printk(KERN_ERR "%s: found possible invalid default country "
+ "eeprom entry. (entry size: %d)\n",
+ wiphy_name(dev->wiphy), len);
+
+ print_hex_dump_bytes("country:", DUMP_PREFIX_NONE,
+ data, len);
+
+ printk(KERN_ERR "%s: please report this issue.\n",
+ wiphy_name(dev->wiphy));
+ return;
+ }
+
+ country = (struct pda_country *) data;
+ if (country->flags == PDR_COUNTRY_CERT_CODE_PSEUDO)
+ regulatory_hint(dev->wiphy, country->alpha2);
+ else {
+ /* TODO:
+ * write a shared/common function that converts
+ * "Regulatory domain codes" (802.11-2007 14.8.2.2)
+ * into ISO/IEC 3166-1 alpha2 for regulatory_hint.
+ */
+ }
+}
+
+static int p54_convert_output_limits(struct ieee80211_hw *dev,
+ u8 *data, size_t len)
+{
+ struct p54_common *priv = dev->priv;
+
+ if (len < 2)
+ return -EINVAL;
+
+ if (data[0] != 0) {
+ printk(KERN_ERR "%s: unknown output power db revision:%x\n",
+ wiphy_name(dev->wiphy), data[0]);
+ return -EINVAL;
+ }
+
+ if (2 + data[1] * sizeof(struct pda_channel_output_limit) > len)
+ return -EINVAL;
+
+ priv->output_limit = kmalloc(data[1] *
+ sizeof(struct pda_channel_output_limit) +
+ sizeof(*priv->output_limit), GFP_KERNEL);
+
+ if (!priv->output_limit)
+ return -ENOMEM;
+
+ priv->output_limit->offset = 0;
+ priv->output_limit->entries = data[1];
+ priv->output_limit->entry_size =
+ sizeof(struct pda_channel_output_limit);
+ priv->output_limit->len = priv->output_limit->entry_size *
+ priv->output_limit->entries +
+ priv->output_limit->offset;
+
+ memcpy(priv->output_limit->data, &data[2],
+ data[1] * sizeof(struct pda_channel_output_limit));
+
+ return 0;
+}
+
+static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src,
+ size_t total_len)
+{
+ struct p54_cal_database *dst;
+ size_t payload_len, entries, entry_size, offset;
+
+ payload_len = le16_to_cpu(src->len);
+ entries = le16_to_cpu(src->entries);
+ entry_size = le16_to_cpu(src->entry_size);
+ offset = le16_to_cpu(src->offset);
+ if (((entries * entry_size + offset) != payload_len) ||
+ (payload_len + sizeof(*src) != total_len))
+ return NULL;
+
+ dst = kmalloc(sizeof(*dst) + payload_len, GFP_KERNEL);
+ if (!dst)
+ return NULL;
+
+ dst->entries = entries;
+ dst->entry_size = entry_size;
+ dst->offset = offset;
+ dst->len = payload_len;
+
+ memcpy(dst->data, src->data, payload_len);
+ return dst;
+}
+
+int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
+{
+ struct p54_common *priv = dev->priv;
+ struct eeprom_pda_wrap *wrap;
+ struct pda_entry *entry;
+ unsigned int data_len, entry_len;
+ void *tmp;
+ int err;
+ u8 *end = (u8 *)eeprom + len;
+ u16 synth = 0;
+
+ wrap = (struct eeprom_pda_wrap *) eeprom;
+ entry = (void *)wrap->data + le16_to_cpu(wrap->len);
+
+ /* verify that at least the entry length/code fits */
+ while ((u8 *)entry <= end - sizeof(*entry)) {
+ entry_len = le16_to_cpu(entry->len);
+ data_len = ((entry_len - 1) << 1);
+
+ /* abort if entry exceeds whole structure */
+ if ((u8 *)entry + sizeof(*entry) + data_len > end)
+ break;
+
+ switch (le16_to_cpu(entry->code)) {
+ case PDR_MAC_ADDRESS:
+ if (data_len != ETH_ALEN)
+ break;
+ SET_IEEE80211_PERM_ADDR(dev, entry->data);
+ break;
+ case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS:
+ if (priv->output_limit)
+ break;
+ err = p54_convert_output_limits(dev, entry->data,
+ data_len);
+ if (err)
+ goto err;
+ break;
+ case PDR_PRISM_PA_CAL_CURVE_DATA: {
+ struct pda_pa_curve_data *curve_data =
+ (struct pda_pa_curve_data *)entry->data;
+ if (data_len < sizeof(*curve_data)) {
+ err = -EINVAL;
+ goto err;
+ }
+
+ switch (curve_data->cal_method_rev) {
+ case 0:
+ err = p54_convert_rev0(dev, curve_data);
+ break;
+ case 1:
+ err = p54_convert_rev1(dev, curve_data);
+ break;
+ default:
+ printk(KERN_ERR "%s: unknown curve data "
+ "revision %d\n",
+ wiphy_name(dev->wiphy),
+ curve_data->cal_method_rev);
+ err = -ENODEV;
+ break;
+ }
+ if (err)
+ goto err;
+ }
+ break;
+ case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
+ priv->iq_autocal = kmalloc(data_len, GFP_KERNEL);
+ if (!priv->iq_autocal) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ memcpy(priv->iq_autocal, entry->data, data_len);
+ priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry);
+ break;
+ case PDR_DEFAULT_COUNTRY:
+ p54_parse_default_country(dev, entry->data, data_len);
+ break;
+ case PDR_INTERFACE_LIST:
+ tmp = entry->data;
+ while ((u8 *)tmp < entry->data + data_len) {
+ struct exp_if *exp_if = tmp;
+ if (exp_if->if_id == cpu_to_le16(IF_ID_ISL39000))
+ synth = le16_to_cpu(exp_if->variant);
+ tmp += sizeof(*exp_if);
+ }
+ break;
+ case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
+ if (data_len < 2)
+ break;
+ priv->version = *(u8 *)(entry->data + 1);
+ break;
+ case PDR_RSSI_LINEAR_APPROXIMATION:
+ case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
+ case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
+ p54_parse_rssical(dev, entry->data, data_len,
+ le16_to_cpu(entry->code));
+ break;
+ case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM: {
+ __le16 *src = (void *) entry->data;
+ s16 *dst = (void *) &priv->rssical_db;
+ int i;
+
+ if (data_len != sizeof(priv->rssical_db)) {
+ err = -EINVAL;
+ goto err;
+ }
+ for (i = 0; i < sizeof(priv->rssical_db) /
+ sizeof(*src); i++)
+ *(dst++) = (s16) le16_to_cpu(*(src++));
+ }
+ break;
+ case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: {
+ struct pda_custom_wrapper *pda = (void *) entry->data;
+ if (priv->output_limit || data_len < sizeof(*pda))
+ break;
+ priv->output_limit = p54_convert_db(pda, data_len);
+ }
+ break;
+ case PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM: {
+ struct pda_custom_wrapper *pda = (void *) entry->data;
+ if (priv->curve_data || data_len < sizeof(*pda))
+ break;
+ priv->curve_data = p54_convert_db(pda, data_len);
+ }
+ break;
+ case PDR_END:
+ /* make it overrun */
+ entry_len = len;
+ break;
+ default:
+ break;
+ }
+
+ entry = (void *)entry + (entry_len + 1)*2;
+ }
+
+ if (!synth || !priv->iq_autocal || !priv->output_limit ||
+ !priv->curve_data) {
+ printk(KERN_ERR "%s: not all required entries found in eeprom!\n",
+ wiphy_name(dev->wiphy));
+ err = -EINVAL;
+ goto err;
+ }
+
+ err = p54_generate_channel_lists(dev);
+ if (err)
+ goto err;
+
+ priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
+ if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
+ p54_init_xbow_synth(priv);
+ if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
+ dev->wiphy->bands[IEEE80211_BAND_2GHZ] =
+ priv->band_table[IEEE80211_BAND_2GHZ];
+ if (!(synth & PDR_SYNTH_5_GHZ_DISABLED))
+ dev->wiphy->bands[IEEE80211_BAND_5GHZ] =
+ priv->band_table[IEEE80211_BAND_5GHZ];
+ if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED)
+ priv->rx_diversity_mask = 3;
+ if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED)
+ priv->tx_diversity_mask = 3;
+
+ if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
+ u8 perm_addr[ETH_ALEN];
+
+ printk(KERN_WARNING "%s: Invalid hwaddr! Using randomly generated MAC addr\n",
+ wiphy_name(dev->wiphy));
+ random_ether_addr(perm_addr);
+ SET_IEEE80211_PERM_ADDR(dev, perm_addr);
+ }
+
+ printk(KERN_INFO "%s: hwaddr %pM, MAC:isl38%02x RF:%s\n",
+ wiphy_name(dev->wiphy), dev->wiphy->perm_addr, priv->version,
+ p54_rf_chips[priv->rxhw]);
+
+ return 0;
+
+err:
+ kfree(priv->iq_autocal);
+ kfree(priv->output_limit);
+ kfree(priv->curve_data);
+ priv->iq_autocal = NULL;
+ priv->output_limit = NULL;
+ priv->curve_data = NULL;
+
+ printk(KERN_ERR "%s: eeprom parse failed!\n",
+ wiphy_name(dev->wiphy));
+ return err;
+}
+EXPORT_SYMBOL_GPL(p54_parse_eeprom);
+
+int p54_read_eeprom(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize;
+ int ret = -ENOMEM;
+ void *eeprom;
+
+ maxblocksize = EEPROM_READBACK_LEN;
+ if (priv->fw_var >= 0x509)
+ maxblocksize -= 0xc;
+ else
+ maxblocksize -= 0x4;
+
+ eeprom = kzalloc(eeprom_size, GFP_KERNEL);
+ if (unlikely(!eeprom))
+ goto free;
+
+ while (eeprom_size) {
+ blocksize = min(eeprom_size, maxblocksize);
+ ret = p54_download_eeprom(priv, (void *) (eeprom + offset),
+ offset, blocksize);
+ if (unlikely(ret))
+ goto free;
+
+ offset += blocksize;
+ eeprom_size -= blocksize;
+ }
+
+ ret = p54_parse_eeprom(dev, eeprom, offset);
+free:
+ kfree(eeprom);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(p54_read_eeprom);
diff --git a/drivers/net/wireless/p54/eeprom.h b/drivers/net/wireless/p54/eeprom.h
new file mode 100644
index 000000000000..9051aef11249
--- /dev/null
+++ b/drivers/net/wireless/p54/eeprom.h
@@ -0,0 +1,226 @@
+/*
+ * eeprom specific definitions for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * - LMAC API interface header file for STLC4560 (lmac_longbow.h)
+ * Copyright (C) 2007 Conexant Systems, Inc.
+ *
+ * - islmvc driver
+ * Copyright (C) 2001 Intersil Americas 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.
+ */
+
+#ifndef EEPROM_H
+#define EEPROM_H
+
+/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */
+
+struct pda_entry {
+ __le16 len; /* includes both code and data */
+ __le16 code;
+ u8 data[0];
+} __packed;
+
+struct eeprom_pda_wrap {
+ __le32 magic;
+ __le16 pad;
+ __le16 len;
+ __le32 arm_opcode;
+ u8 data[0];
+} __packed;
+
+struct p54_iq_autocal_entry {
+ __le16 iq_param[4];
+} __packed;
+
+struct pda_iq_autocal_entry {
+ __le16 freq;
+ struct p54_iq_autocal_entry params;
+} __packed;
+
+struct pda_channel_output_limit {
+ __le16 freq;
+ u8 val_bpsk;
+ u8 val_qpsk;
+ u8 val_16qam;
+ u8 val_64qam;
+ u8 rate_set_mask;
+ u8 rate_set_size;
+} __packed;
+
+struct pda_pa_curve_data_sample_rev0 {
+ u8 rf_power;
+ u8 pa_detector;
+ u8 pcv;
+} __packed;
+
+struct pda_pa_curve_data_sample_rev1 {
+ u8 rf_power;
+ u8 pa_detector;
+ u8 data_barker;
+ u8 data_bpsk;
+ u8 data_qpsk;
+ u8 data_16qam;
+ u8 data_64qam;
+} __packed;
+
+struct pda_pa_curve_data {
+ u8 cal_method_rev;
+ u8 channels;
+ u8 points_per_channel;
+ u8 padding;
+ u8 data[0];
+} __packed;
+
+struct pda_rssi_cal_entry {
+ __le16 mul;
+ __le16 add;
+} __packed;
+
+struct pda_country {
+ u8 regdomain;
+ u8 alpha2[2];
+ u8 flags;
+} __packed;
+
+struct pda_antenna_gain {
+ struct {
+ u8 gain_5GHz; /* 0.25 dBi units */
+ u8 gain_2GHz; /* 0.25 dBi units */
+ } __packed antenna[0];
+} __packed;
+
+struct pda_custom_wrapper {
+ __le16 entries;
+ __le16 entry_size;
+ __le16 offset;
+ __le16 len;
+ u8 data[0];
+} __packed;
+
+/*
+ * this defines the PDR codes used to build PDAs as defined in document
+ * number 553155. The current implementation mirrors version 1.1 of the
+ * document and lists only PDRs supported by the ARM platform.
+ */
+
+/* common and choice range (0x0000 - 0x0fff) */
+#define PDR_END 0x0000
+#define PDR_MANUFACTURING_PART_NUMBER 0x0001
+#define PDR_PDA_VERSION 0x0002
+#define PDR_NIC_SERIAL_NUMBER 0x0003
+#define PDR_NIC_RAM_SIZE 0x0005
+#define PDR_RFMODEM_SUP_RANGE 0x0006
+#define PDR_PRISM_MAC_SUP_RANGE 0x0007
+#define PDR_NIC_ID 0x0008
+
+#define PDR_MAC_ADDRESS 0x0101
+#define PDR_REGULATORY_DOMAIN_LIST 0x0103 /* obsolete */
+#define PDR_ALLOWED_CHAN_SET 0x0104
+#define PDR_DEFAULT_CHAN 0x0105
+#define PDR_TEMPERATURE_TYPE 0x0107
+
+#define PDR_IFR_SETTING 0x0200
+#define PDR_RFR_SETTING 0x0201
+#define PDR_3861_BASELINE_REG_SETTINGS 0x0202
+#define PDR_3861_SHADOW_REG_SETTINGS 0x0203
+#define PDR_3861_IFRF_REG_SETTINGS 0x0204
+
+#define PDR_3861_CHAN_CALIB_SET_POINTS 0x0300
+#define PDR_3861_CHAN_CALIB_INTEGRATOR 0x0301
+
+#define PDR_3842_PRISM_II_NIC_CONFIG 0x0400
+#define PDR_PRISM_USB_ID 0x0401
+#define PDR_PRISM_PCI_ID 0x0402
+#define PDR_PRISM_PCI_IF_CONFIG 0x0403
+#define PDR_PRISM_PCI_PM_CONFIG 0x0404
+
+#define PDR_3861_MF_TEST_CHAN_SET_POINTS 0x0900
+#define PDR_3861_MF_TEST_CHAN_INTEGRATORS 0x0901
+
+/* ARM range (0x1000 - 0x1fff) */
+#define PDR_COUNTRY_INFORMATION 0x1000 /* obsolete */
+#define PDR_INTERFACE_LIST 0x1001
+#define PDR_HARDWARE_PLATFORM_COMPONENT_ID 0x1002
+#define PDR_OEM_NAME 0x1003
+#define PDR_PRODUCT_NAME 0x1004
+#define PDR_UTF8_OEM_NAME 0x1005
+#define PDR_UTF8_PRODUCT_NAME 0x1006
+#define PDR_COUNTRY_LIST 0x1007
+#define PDR_DEFAULT_COUNTRY 0x1008
+
+#define PDR_ANTENNA_GAIN 0x1100
+
+#define PDR_PRISM_INDIGO_PA_CALIBRATION_DATA 0x1901
+#define PDR_RSSI_LINEAR_APPROXIMATION 0x1902
+#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS 0x1903
+#define PDR_PRISM_PA_CAL_CURVE_DATA 0x1904
+#define PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND 0x1905
+#define PDR_PRISM_ZIF_TX_IQ_CALIBRATION 0x1906
+#define PDR_REGULATORY_POWER_LIMITS 0x1907
+#define PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED 0x1908
+#define PDR_RADIATED_TRANSMISSION_CORRECTION 0x1909
+#define PDR_PRISM_TX_IQ_CALIBRATION 0x190a
+
+/* reserved range (0x2000 - 0x7fff) */
+
+/* customer range (0x8000 - 0xffff) */
+#define PDR_BASEBAND_REGISTERS 0x8000
+#define PDR_PER_CHANNEL_BASEBAND_REGISTERS 0x8001
+
+/* used by our modificated eeprom image */
+#define PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM 0xDEAD
+#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM 0xBEEF
+#define PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM 0xB05D
+
+/* Interface Definitions */
+#define PDR_INTERFACE_ROLE_SERVER 0x0000
+#define PDR_INTERFACE_ROLE_CLIENT 0x0001
+
+/* PDR definitions for default country & country list */
+#define PDR_COUNTRY_CERT_CODE 0x80
+#define PDR_COUNTRY_CERT_CODE_REAL 0x00
+#define PDR_COUNTRY_CERT_CODE_PSEUDO 0x80
+#define PDR_COUNTRY_CERT_BAND 0x40
+#define PDR_COUNTRY_CERT_BAND_2GHZ 0x00
+#define PDR_COUNTRY_CERT_BAND_5GHZ 0x40
+#define PDR_COUNTRY_CERT_IODOOR 0x30
+#define PDR_COUNTRY_CERT_IODOOR_BOTH 0x00
+#define PDR_COUNTRY_CERT_IODOOR_INDOOR 0x20
+#define PDR_COUNTRY_CERT_IODOOR_OUTDOOR 0x30
+#define PDR_COUNTRY_CERT_INDEX 0x0f
+
+/* Specific LMAC FW/HW variant definitions */
+#define PDR_SYNTH_FRONTEND_MASK 0x0007
+#define PDR_SYNTH_FRONTEND_DUETTE3 0x0001
+#define PDR_SYNTH_FRONTEND_DUETTE2 0x0002
+#define PDR_SYNTH_FRONTEND_FRISBEE 0x0003
+#define PDR_SYNTH_FRONTEND_XBOW 0x0004
+#define PDR_SYNTH_FRONTEND_LONGBOW 0x0005
+#define PDR_SYNTH_IQ_CAL_MASK 0x0018
+#define PDR_SYNTH_IQ_CAL_PA_DETECTOR 0x0000
+#define PDR_SYNTH_IQ_CAL_DISABLED 0x0008
+#define PDR_SYNTH_IQ_CAL_ZIF 0x0010
+#define PDR_SYNTH_FAA_SWITCH_MASK 0x0020
+#define PDR_SYNTH_FAA_SWITCH_ENABLED 0x0020
+#define PDR_SYNTH_24_GHZ_MASK 0x0040
+#define PDR_SYNTH_24_GHZ_DISABLED 0x0040
+#define PDR_SYNTH_5_GHZ_MASK 0x0080
+#define PDR_SYNTH_5_GHZ_DISABLED 0x0080
+#define PDR_SYNTH_RX_DIV_MASK 0x0100
+#define PDR_SYNTH_RX_DIV_SUPPORTED 0x0100
+#define PDR_SYNTH_TX_DIV_MASK 0x0200
+#define PDR_SYNTH_TX_DIV_SUPPORTED 0x0200
+#define PDR_SYNTH_ASM_MASK 0x0400
+#define PDR_SYNTH_ASM_XSWON 0x0400
+
+#endif /* EEPROM_H */
diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c
new file mode 100644
index 000000000000..21f19018fab5
--- /dev/null
+++ b/drivers/net/wireless/p54/fwio.c
@@ -0,0 +1,715 @@
+/*
+ * Firmware I/O code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * 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/init.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "eeprom.h"
+#include "lmac.h"
+
+int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
+{
+ struct p54_common *priv = dev->priv;
+ struct exp_if *exp_if;
+ struct bootrec *bootrec;
+ u32 *data = (u32 *)fw->data;
+ u32 *end_data = (u32 *)fw->data + (fw->size >> 2);
+ u8 *fw_version = NULL;
+ size_t len;
+ int i;
+ int maxlen;
+
+ if (priv->rx_start)
+ return 0;
+
+ while (data < end_data && *data)
+ data++;
+
+ while (data < end_data && !*data)
+ data++;
+
+ bootrec = (struct bootrec *) data;
+
+ while (bootrec->data <= end_data && (bootrec->data +
+ (len = le32_to_cpu(bootrec->len))) <= end_data) {
+ u32 code = le32_to_cpu(bootrec->code);
+ switch (code) {
+ case BR_CODE_COMPONENT_ID:
+ priv->fw_interface = be32_to_cpup((__be32 *)
+ bootrec->data);
+ switch (priv->fw_interface) {
+ case FW_LM86:
+ case FW_LM20:
+ case FW_LM87: {
+ char *iftype = (char *)bootrec->data;
+ printk(KERN_INFO "%s: p54 detected a LM%c%c "
+ "firmware\n",
+ wiphy_name(priv->hw->wiphy),
+ iftype[2], iftype[3]);
+ break;
+ }
+ case FW_FMAC:
+ default:
+ printk(KERN_ERR "%s: unsupported firmware\n",
+ wiphy_name(priv->hw->wiphy));
+ return -ENODEV;
+ }
+ break;
+ case BR_CODE_COMPONENT_VERSION:
+ /* 24 bytes should be enough for all firmwares */
+ if (strnlen((unsigned char *) bootrec->data, 24) < 24)
+ fw_version = (unsigned char *) bootrec->data;
+ break;
+ case BR_CODE_DESCR: {
+ struct bootrec_desc *desc =
+ (struct bootrec_desc *)bootrec->data;
+ priv->rx_start = le32_to_cpu(desc->rx_start);
+ /* FIXME add sanity checking */
+ priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500;
+ priv->headroom = desc->headroom;
+ priv->tailroom = desc->tailroom;
+ priv->privacy_caps = desc->privacy_caps;
+ priv->rx_keycache_size = desc->rx_keycache_size;
+ if (le32_to_cpu(bootrec->len) == 11)
+ priv->rx_mtu = le16_to_cpu(desc->rx_mtu);
+ else
+ priv->rx_mtu = (size_t)
+ 0x620 - priv->tx_hdr_len;
+ maxlen = priv->tx_hdr_len + /* USB devices */
+ sizeof(struct p54_rx_data) +
+ 4 + /* rx alignment */
+ IEEE80211_MAX_FRAG_THRESHOLD;
+ if (priv->rx_mtu > maxlen && PAGE_SIZE == 4096) {
+ printk(KERN_INFO "p54: rx_mtu reduced from %d "
+ "to %d\n", priv->rx_mtu, maxlen);
+ priv->rx_mtu = maxlen;
+ }
+ break;
+ }
+ case BR_CODE_EXPOSED_IF:
+ exp_if = (struct exp_if *) bootrec->data;
+ for (i = 0; i < (len * sizeof(*exp_if) / 4); i++)
+ if (exp_if[i].if_id == cpu_to_le16(IF_ID_LMAC))
+ priv->fw_var = le16_to_cpu(exp_if[i].variant);
+ break;
+ case BR_CODE_DEPENDENT_IF:
+ break;
+ case BR_CODE_END_OF_BRA:
+ case LEGACY_BR_CODE_END_OF_BRA:
+ end_data = NULL;
+ break;
+ default:
+ break;
+ }
+ bootrec = (struct bootrec *)&bootrec->data[len];
+ }
+
+ if (fw_version)
+ printk(KERN_INFO "%s: FW rev %s - Softmac protocol %x.%x\n",
+ wiphy_name(priv->hw->wiphy), fw_version,
+ priv->fw_var >> 8, priv->fw_var & 0xff);
+
+ if (priv->fw_var < 0x500)
+ printk(KERN_INFO "%s: you are using an obsolete firmware. "
+ "visit http://wireless.kernel.org/en/users/Drivers/p54 "
+ "and grab one for \"kernel >= 2.6.28\"!\n",
+ wiphy_name(priv->hw->wiphy));
+
+ if (priv->fw_var >= 0x300) {
+ /* Firmware supports QoS, use it! */
+
+ if (priv->fw_var >= 0x500) {
+ priv->tx_stats[P54_QUEUE_AC_VO].limit = 16;
+ priv->tx_stats[P54_QUEUE_AC_VI].limit = 16;
+ priv->tx_stats[P54_QUEUE_AC_BE].limit = 16;
+ priv->tx_stats[P54_QUEUE_AC_BK].limit = 16;
+ } else {
+ priv->tx_stats[P54_QUEUE_AC_VO].limit = 3;
+ priv->tx_stats[P54_QUEUE_AC_VI].limit = 4;
+ priv->tx_stats[P54_QUEUE_AC_BE].limit = 3;
+ priv->tx_stats[P54_QUEUE_AC_BK].limit = 2;
+ }
+ priv->hw->queues = P54_QUEUE_AC_NUM;
+ }
+
+ printk(KERN_INFO "%s: cryptographic accelerator "
+ "WEP:%s, TKIP:%s, CCMP:%s\n", wiphy_name(priv->hw->wiphy),
+ (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" :
+ "no", (priv->privacy_caps & (BR_DESC_PRIV_CAP_TKIP |
+ BR_DESC_PRIV_CAP_MICHAEL)) ? "YES" : "no",
+ (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ?
+ "YES" : "no");
+
+ if (priv->rx_keycache_size) {
+ /*
+ * NOTE:
+ *
+ * The firmware provides at most 255 (0 - 254) slots
+ * for keys which are then used to offload decryption.
+ * As a result the 255 entry (aka 0xff) can be used
+ * safely by the driver to mark keys that didn't fit
+ * into the full cache. This trick saves us from
+ * keeping a extra list for uploaded keys.
+ */
+
+ priv->used_rxkeys = kzalloc(BITS_TO_LONGS(
+ priv->rx_keycache_size), GFP_KERNEL);
+
+ if (!priv->used_rxkeys)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(p54_parse_firmware);
+
+static struct sk_buff *p54_alloc_skb(struct p54_common *priv, u16 hdr_flags,
+ u16 payload_len, u16 type, gfp_t memflags)
+{
+ struct p54_hdr *hdr;
+ struct sk_buff *skb;
+ size_t frame_len = sizeof(*hdr) + payload_len;
+
+ if (frame_len > P54_MAX_CTRL_FRAME_LEN)
+ return NULL;
+
+ if (unlikely(skb_queue_len(&priv->tx_pending) > 64))
+ return NULL;
+
+ skb = __dev_alloc_skb(priv->tx_hdr_len + frame_len, memflags);
+ if (!skb)
+ return NULL;
+ skb_reserve(skb, priv->tx_hdr_len);
+
+ hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr));
+ hdr->flags = cpu_to_le16(hdr_flags);
+ hdr->len = cpu_to_le16(payload_len);
+ hdr->type = cpu_to_le16(type);
+ hdr->tries = hdr->rts_tries = 0;
+ return skb;
+}
+
+int p54_download_eeprom(struct p54_common *priv, void *buf,
+ u16 offset, u16 len)
+{
+ struct p54_eeprom_lm86 *eeprom_hdr;
+ struct sk_buff *skb;
+ size_t eeprom_hdr_size;
+ int ret = 0;
+
+ if (priv->fw_var >= 0x509)
+ eeprom_hdr_size = sizeof(*eeprom_hdr);
+ else
+ eeprom_hdr_size = 0x4;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL, eeprom_hdr_size +
+ len, P54_CONTROL_TYPE_EEPROM_READBACK,
+ GFP_KERNEL);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ mutex_lock(&priv->eeprom_mutex);
+ priv->eeprom = buf;
+ eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb,
+ eeprom_hdr_size + len);
+
+ if (priv->fw_var < 0x509) {
+ eeprom_hdr->v1.offset = cpu_to_le16(offset);
+ eeprom_hdr->v1.len = cpu_to_le16(len);
+ } else {
+ eeprom_hdr->v2.offset = cpu_to_le32(offset);
+ eeprom_hdr->v2.len = cpu_to_le16(len);
+ eeprom_hdr->v2.magic2 = 0xf;
+ memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4);
+ }
+
+ p54_tx(priv, skb);
+
+ if (!wait_for_completion_interruptible_timeout(
+ &priv->eeprom_comp, HZ)) {
+ printk(KERN_ERR "%s: device does not respond!\n",
+ wiphy_name(priv->hw->wiphy));
+ ret = -EBUSY;
+ }
+ priv->eeprom = NULL;
+ mutex_unlock(&priv->eeprom_mutex);
+ return ret;
+}
+
+int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set)
+{
+ struct sk_buff *skb;
+ struct p54_tim *tim;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*tim),
+ P54_CONTROL_TYPE_TIM, GFP_ATOMIC);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ tim = (struct p54_tim *) skb_put(skb, sizeof(*tim));
+ tim->count = 1;
+ tim->entry[0] = cpu_to_le16(set ? (aid | 0x8000) : aid);
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_sta_unlock(struct p54_common *priv, u8 *addr)
+{
+ struct sk_buff *skb;
+ struct p54_sta_unlock *sta;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*sta),
+ P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta));
+ memcpy(sta->addr, addr, ETH_ALEN);
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_tx_cancel(struct p54_common *priv, __le32 req_id)
+{
+ struct sk_buff *skb;
+ struct p54_txcancel *cancel;
+ u32 _req_id = le32_to_cpu(req_id);
+
+ if (unlikely(_req_id < priv->rx_start || _req_id > priv->rx_end))
+ return -EINVAL;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*cancel),
+ P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel));
+ cancel->req_id = req_id;
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_setup_mac(struct p54_common *priv)
+{
+ struct sk_buff *skb;
+ struct p54_setup_mac *setup;
+ u16 mode;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup),
+ P54_CONTROL_TYPE_SETUP, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup));
+ if (priv->hw->conf.radio_enabled) {
+ switch (priv->mode) {
+ case NL80211_IFTYPE_STATION:
+ mode = P54_FILTER_TYPE_STATION;
+ break;
+ case NL80211_IFTYPE_AP:
+ mode = P54_FILTER_TYPE_AP;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_MESH_POINT:
+ mode = P54_FILTER_TYPE_IBSS;
+ break;
+ case NL80211_IFTYPE_MONITOR:
+ mode = P54_FILTER_TYPE_PROMISCUOUS;
+ break;
+ default:
+ mode = P54_FILTER_TYPE_HIBERNATE;
+ break;
+ }
+
+ /*
+ * "TRANSPARENT and PROMISCUOUS are mutually exclusive"
+ * STSW45X0C LMAC API - page 12
+ */
+ if (((priv->filter_flags & FIF_PROMISC_IN_BSS) ||
+ (priv->filter_flags & FIF_OTHER_BSS)) &&
+ (mode != P54_FILTER_TYPE_PROMISCUOUS))
+ mode |= P54_FILTER_TYPE_TRANSPARENT;
+ } else
+ mode = P54_FILTER_TYPE_HIBERNATE;
+
+ setup->mac_mode = cpu_to_le16(mode);
+ memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN);
+ memcpy(setup->bssid, priv->bssid, ETH_ALEN);
+ setup->rx_antenna = 2 & priv->rx_diversity_mask; /* automatic */
+ setup->rx_align = 0;
+ if (priv->fw_var < 0x500) {
+ setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+ memset(setup->v1.rts_rates, 0, 8);
+ setup->v1.rx_addr = cpu_to_le32(priv->rx_end);
+ setup->v1.max_rx = cpu_to_le16(priv->rx_mtu);
+ setup->v1.rxhw = cpu_to_le16(priv->rxhw);
+ setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer);
+ setup->v1.unalloc0 = cpu_to_le16(0);
+ } else {
+ setup->v2.rx_addr = cpu_to_le32(priv->rx_end);
+ setup->v2.max_rx = cpu_to_le16(priv->rx_mtu);
+ setup->v2.rxhw = cpu_to_le16(priv->rxhw);
+ setup->v2.timer = cpu_to_le16(priv->wakeup_timer);
+ setup->v2.truncate = cpu_to_le16(48896);
+ setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+ setup->v2.sbss_offset = 0;
+ setup->v2.mcast_window = 0;
+ setup->v2.rx_rssi_threshold = 0;
+ setup->v2.rx_ed_threshold = 0;
+ setup->v2.ref_clock = cpu_to_le32(644245094);
+ setup->v2.lpf_bandwidth = cpu_to_le16(65535);
+ setup->v2.osc_start_delay = cpu_to_le16(65535);
+ }
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_scan(struct p54_common *priv, u16 mode, u16 dwell)
+{
+ struct sk_buff *skb;
+ struct p54_hdr *hdr;
+ struct p54_scan_head *head;
+ struct p54_iq_autocal_entry *iq_autocal;
+ union p54_scan_body_union *body;
+ struct p54_scan_tail_rate *rate;
+ struct pda_rssi_cal_entry *rssi;
+ unsigned int i;
+ void *entry;
+ int band = priv->hw->conf.channel->band;
+ __le16 freq = cpu_to_le16(priv->hw->conf.channel->center_freq);
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*head) +
+ 2 + sizeof(*iq_autocal) + sizeof(*body) +
+ sizeof(*rate) + 2 * sizeof(*rssi),
+ P54_CONTROL_TYPE_SCAN, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ head = (struct p54_scan_head *) skb_put(skb, sizeof(*head));
+ memset(head->scan_params, 0, sizeof(head->scan_params));
+ head->mode = cpu_to_le16(mode);
+ head->dwell = cpu_to_le16(dwell);
+ head->freq = freq;
+
+ if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
+ __le16 *pa_power_points = (__le16 *) skb_put(skb, 2);
+ *pa_power_points = cpu_to_le16(0x0c);
+ }
+
+ iq_autocal = (void *) skb_put(skb, sizeof(*iq_autocal));
+ for (i = 0; i < priv->iq_autocal_len; i++) {
+ if (priv->iq_autocal[i].freq != freq)
+ continue;
+
+ memcpy(iq_autocal, &priv->iq_autocal[i].params,
+ sizeof(struct p54_iq_autocal_entry));
+ break;
+ }
+ if (i == priv->iq_autocal_len)
+ goto err;
+
+ if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW)
+ body = (void *) skb_put(skb, sizeof(body->longbow));
+ else
+ body = (void *) skb_put(skb, sizeof(body->normal));
+
+ for (i = 0; i < priv->output_limit->entries; i++) {
+ __le16 *entry_freq = (void *) (priv->output_limit->data +
+ priv->output_limit->entry_size * i);
+
+ if (*entry_freq != freq)
+ continue;
+
+ if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
+ memcpy(&body->longbow.power_limits,
+ (void *) entry_freq + sizeof(__le16),
+ priv->output_limit->entry_size);
+ } else {
+ struct pda_channel_output_limit *limits =
+ (void *) entry_freq;
+
+ body->normal.val_barker = 0x38;
+ body->normal.val_bpsk = body->normal.dup_bpsk =
+ limits->val_bpsk;
+ body->normal.val_qpsk = body->normal.dup_qpsk =
+ limits->val_qpsk;
+ body->normal.val_16qam = body->normal.dup_16qam =
+ limits->val_16qam;
+ body->normal.val_64qam = body->normal.dup_64qam =
+ limits->val_64qam;
+ }
+ break;
+ }
+ if (i == priv->output_limit->entries)
+ goto err;
+
+ entry = (void *)(priv->curve_data->data + priv->curve_data->offset);
+ for (i = 0; i < priv->curve_data->entries; i++) {
+ if (*((__le16 *)entry) != freq) {
+ entry += priv->curve_data->entry_size;
+ continue;
+ }
+
+ if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
+ memcpy(&body->longbow.curve_data,
+ (void *) entry + sizeof(__le16),
+ priv->curve_data->entry_size);
+ } else {
+ struct p54_scan_body *chan = &body->normal;
+ struct pda_pa_curve_data *curve_data =
+ (void *) priv->curve_data->data;
+
+ entry += sizeof(__le16);
+ chan->pa_points_per_curve = 8;
+ memset(chan->curve_data, 0, sizeof(*chan->curve_data));
+ memcpy(chan->curve_data, entry,
+ sizeof(struct p54_pa_curve_data_sample) *
+ min((u8)8, curve_data->points_per_channel));
+ }
+ break;
+ }
+ if (i == priv->curve_data->entries)
+ goto err;
+
+ if ((priv->fw_var >= 0x500) && (priv->fw_var < 0x509)) {
+ rate = (void *) skb_put(skb, sizeof(*rate));
+ rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+ for (i = 0; i < sizeof(rate->rts_rates); i++)
+ rate->rts_rates[i] = i;
+ }
+
+ rssi = (struct pda_rssi_cal_entry *) skb_put(skb, sizeof(*rssi));
+ rssi->mul = cpu_to_le16(priv->rssical_db[band].mul);
+ rssi->add = cpu_to_le16(priv->rssical_db[band].add);
+ if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
+ /* Longbow frontend needs ever more */
+ rssi = (void *) skb_put(skb, sizeof(*rssi));
+ rssi->mul = cpu_to_le16(priv->rssical_db[band].longbow_unkn);
+ rssi->add = cpu_to_le16(priv->rssical_db[band].longbow_unk2);
+ }
+
+ if (priv->fw_var >= 0x509) {
+ rate = (void *) skb_put(skb, sizeof(*rate));
+ rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+ for (i = 0; i < sizeof(rate->rts_rates); i++)
+ rate->rts_rates[i] = i;
+ }
+
+ hdr = (struct p54_hdr *) skb->data;
+ hdr->len = cpu_to_le16(skb->len - sizeof(*hdr));
+
+ p54_tx(priv, skb);
+ return 0;
+
+err:
+ printk(KERN_ERR "%s: frequency change to channel %d failed.\n",
+ wiphy_name(priv->hw->wiphy), ieee80211_frequency_to_channel(
+ priv->hw->conf.channel->center_freq));
+
+ dev_kfree_skb_any(skb);
+ return -EINVAL;
+}
+
+int p54_set_leds(struct p54_common *priv)
+{
+ struct sk_buff *skb;
+ struct p54_led *led;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*led),
+ P54_CONTROL_TYPE_LED, GFP_ATOMIC);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ led = (struct p54_led *) skb_put(skb, sizeof(*led));
+ led->flags = cpu_to_le16(0x0003);
+ led->mask[0] = led->mask[1] = cpu_to_le16(priv->softled_state);
+ led->delay[0] = cpu_to_le16(1);
+ led->delay[1] = cpu_to_le16(0);
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_set_edcf(struct p54_common *priv)
+{
+ struct sk_buff *skb;
+ struct p54_edcf *edcf;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf),
+ P54_CONTROL_TYPE_DCFINIT, GFP_ATOMIC);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf));
+ if (priv->use_short_slot) {
+ edcf->slottime = 9;
+ edcf->sifs = 0x10;
+ edcf->eofpad = 0x00;
+ } else {
+ edcf->slottime = 20;
+ edcf->sifs = 0x0a;
+ edcf->eofpad = 0x06;
+ }
+ /* (see prism54/isl_oid.h for further details) */
+ edcf->frameburst = cpu_to_le16(0);
+ edcf->round_trip_delay = cpu_to_le16(0);
+ edcf->flags = 0;
+ memset(edcf->mapping, 0, sizeof(edcf->mapping));
+ memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue));
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_set_ps(struct p54_common *priv)
+{
+ struct sk_buff *skb;
+ struct p54_psm *psm;
+ unsigned int i;
+ u16 mode;
+
+ if (priv->hw->conf.flags & IEEE80211_CONF_PS &&
+ !priv->powersave_override)
+ mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM |
+ P54_PSM_CHECKSUM | P54_PSM_MCBC;
+ else
+ mode = P54_PSM_CAM;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*psm),
+ P54_CONTROL_TYPE_PSM, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ psm = (struct p54_psm *)skb_put(skb, sizeof(*psm));
+ psm->mode = cpu_to_le16(mode);
+ psm->aid = cpu_to_le16(priv->aid);
+ for (i = 0; i < ARRAY_SIZE(psm->intervals); i++) {
+ psm->intervals[i].interval =
+ cpu_to_le16(priv->hw->conf.listen_interval);
+ psm->intervals[i].periods = cpu_to_le16(1);
+ }
+
+ psm->beacon_rssi_skip_max = 200;
+ psm->rssi_delta_threshold = 0;
+ psm->nr = 1;
+ psm->exclude[0] = WLAN_EID_TIM;
+
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_init_xbow_synth(struct p54_common *priv)
+{
+ struct sk_buff *skb;
+ struct p54_xbow_synth *xbow;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*xbow),
+ P54_CONTROL_TYPE_XBOW_SYNTH_CFG, GFP_KERNEL);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow));
+ xbow->magic1 = cpu_to_le16(0x1);
+ xbow->magic2 = cpu_to_le16(0x2);
+ xbow->freq = cpu_to_le16(5390);
+ memset(xbow->padding, 0, sizeof(xbow->padding));
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_upload_key(struct p54_common *priv, u8 algo, int slot, u8 idx, u8 len,
+ u8 *addr, u8* key)
+{
+ struct sk_buff *skb;
+ struct p54_keycache *rxkey;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey),
+ P54_CONTROL_TYPE_RX_KEYCACHE, GFP_KERNEL);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey));
+ rxkey->entry = slot;
+ rxkey->key_id = idx;
+ rxkey->key_type = algo;
+ if (addr)
+ memcpy(rxkey->mac, addr, ETH_ALEN);
+ else
+ memset(rxkey->mac, ~0, ETH_ALEN);
+
+ switch (algo) {
+ case P54_CRYPTO_WEP:
+ case P54_CRYPTO_AESCCMP:
+ rxkey->key_len = min_t(u8, 16, len);
+ memcpy(rxkey->key, key, rxkey->key_len);
+ break;
+
+ case P54_CRYPTO_TKIPMICHAEL:
+ rxkey->key_len = 24;
+ memcpy(rxkey->key, key, 16);
+ memcpy(&(rxkey->key[16]), &(key
+ [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8);
+ break;
+
+ case P54_CRYPTO_NONE:
+ rxkey->key_len = 0;
+ memset(rxkey->key, 0, sizeof(rxkey->key));
+ break;
+
+ default:
+ printk(KERN_ERR "%s: invalid cryptographic algorithm: %d\n",
+ wiphy_name(priv->hw->wiphy), algo);
+ dev_kfree_skb(skb);
+ return -EINVAL;
+ }
+
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_fetch_statistics(struct p54_common *priv)
+{
+ struct ieee80211_tx_info *txinfo;
+ struct p54_tx_info *p54info;
+ struct sk_buff *skb;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL,
+ sizeof(struct p54_statistics),
+ P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+ /*
+ * The statistic feedback causes some extra headaches here, if it
+ * is not to crash/corrupt the firmware data structures.
+ *
+ * Unlike all other Control Get OIDs we can not use helpers like
+ * skb_put to reserve the space for the data we're requesting.
+ * Instead the extra frame length -which will hold the results later-
+ * will only be told to the p54_assign_address, so that following
+ * frames won't be placed into the allegedly empty area.
+ */
+ txinfo = IEEE80211_SKB_CB(skb);
+ p54info = (void *) txinfo->rate_driver_data;
+ p54info->extra_len = sizeof(struct p54_statistics);
+
+ p54_tx(priv, skb);
+ return 0;
+}
diff --git a/drivers/net/wireless/p54/led.c b/drivers/net/wireless/p54/led.c
new file mode 100644
index 000000000000..c00115b206d4
--- /dev/null
+++ b/drivers/net/wireless/p54/led.c
@@ -0,0 +1,163 @@
+/*
+ * Common code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * 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/init.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+#ifdef CONFIG_P54_LEDS
+#include <linux/leds.h>
+#endif /* CONFIG_P54_LEDS */
+
+#include "p54.h"
+#include "lmac.h"
+
+static void p54_update_leds(struct work_struct *work)
+{
+ struct p54_common *priv = container_of(work, struct p54_common,
+ led_work.work);
+ int err, i, tmp, blink_delay = 400;
+ bool rerun = false;
+
+ /* Don't toggle the LED, when the device is down. */
+ if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
+ return ;
+
+ for (i = 0; i < ARRAY_SIZE(priv->leds); i++)
+ if (priv->leds[i].toggled) {
+ priv->softled_state |= BIT(i);
+
+ tmp = 70 + 200 / (priv->leds[i].toggled);
+ if (tmp < blink_delay)
+ blink_delay = tmp;
+
+ if (priv->leds[i].led_dev.brightness == LED_OFF)
+ rerun = true;
+
+ priv->leds[i].toggled =
+ !!priv->leds[i].led_dev.brightness;
+ } else
+ priv->softled_state &= ~BIT(i);
+
+ err = p54_set_leds(priv);
+ if (err && net_ratelimit())
+ printk(KERN_ERR "%s: failed to update LEDs (%d).\n",
+ wiphy_name(priv->hw->wiphy), err);
+
+ if (rerun)
+ queue_delayed_work(priv->hw->workqueue, &priv->led_work,
+ msecs_to_jiffies(blink_delay));
+}
+
+static void p54_led_brightness_set(struct led_classdev *led_dev,
+ enum led_brightness brightness)
+{
+ struct p54_led_dev *led = container_of(led_dev, struct p54_led_dev,
+ led_dev);
+ struct ieee80211_hw *dev = led->hw_dev;
+ struct p54_common *priv = dev->priv;
+
+ if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
+ return ;
+
+ if ((brightness) && (led->registered)) {
+ led->toggled++;
+ queue_delayed_work(priv->hw->workqueue, &priv->led_work,
+ HZ/10);
+ }
+}
+
+static int p54_register_led(struct p54_common *priv,
+ unsigned int led_index,
+ char *name, char *trigger)
+{
+ struct p54_led_dev *led = &priv->leds[led_index];
+ int err;
+
+ if (led->registered)
+ return -EEXIST;
+
+ snprintf(led->name, sizeof(led->name), "p54-%s::%s",
+ wiphy_name(priv->hw->wiphy), name);
+ led->hw_dev = priv->hw;
+ led->index = led_index;
+ led->led_dev.name = led->name;
+ led->led_dev.default_trigger = trigger;
+ led->led_dev.brightness_set = p54_led_brightness_set;
+
+ err = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_dev);
+ if (err)
+ printk(KERN_ERR "%s: Failed to register %s LED.\n",
+ wiphy_name(priv->hw->wiphy), name);
+ else
+ led->registered = 1;
+
+ return err;
+}
+
+int p54_init_leds(struct p54_common *priv)
+{
+ int err;
+
+ /*
+ * TODO:
+ * Figure out if the EEPROM contains some hints about the number
+ * of available/programmable LEDs of the device.
+ */
+
+ INIT_DELAYED_WORK(&priv->led_work, p54_update_leds);
+
+ err = p54_register_led(priv, 0, "assoc",
+ ieee80211_get_assoc_led_name(priv->hw));
+ if (err)
+ return err;
+
+ err = p54_register_led(priv, 1, "tx",
+ ieee80211_get_tx_led_name(priv->hw));
+ if (err)
+ return err;
+
+ err = p54_register_led(priv, 2, "rx",
+ ieee80211_get_rx_led_name(priv->hw));
+ if (err)
+ return err;
+
+ err = p54_register_led(priv, 3, "radio",
+ ieee80211_get_radio_led_name(priv->hw));
+ if (err)
+ return err;
+
+ err = p54_set_leds(priv);
+ return err;
+}
+
+void p54_unregister_leds(struct p54_common *priv)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(priv->leds); i++) {
+ if (priv->leds[i].registered) {
+ priv->leds[i].registered = false;
+ priv->leds[i].toggled = 0;
+ led_classdev_unregister(&priv->leds[i].led_dev);
+ }
+ }
+
+ cancel_delayed_work_sync(&priv->led_work);
+}
diff --git a/drivers/net/wireless/p54/lmac.h b/drivers/net/wireless/p54/lmac.h
new file mode 100644
index 000000000000..04b63ec80fa4
--- /dev/null
+++ b/drivers/net/wireless/p54/lmac.h
@@ -0,0 +1,558 @@
+/*
+ * LMAC Interface specific definitions for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007 - 2009, Christian Lamparter <chunkeey@web.de>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * - LMAC API interface header file for STLC4560 (lmac_longbow.h)
+ * Copyright (C) 2007 Conexant Systems, 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.
+ */
+
+#ifndef LMAC_H
+#define LMAC_H
+
+enum p54_control_frame_types {
+ P54_CONTROL_TYPE_SETUP = 0,
+ P54_CONTROL_TYPE_SCAN,
+ P54_CONTROL_TYPE_TRAP,
+ P54_CONTROL_TYPE_DCFINIT,
+ P54_CONTROL_TYPE_RX_KEYCACHE,
+ P54_CONTROL_TYPE_TIM,
+ P54_CONTROL_TYPE_PSM,
+ P54_CONTROL_TYPE_TXCANCEL,
+ P54_CONTROL_TYPE_TXDONE,
+ P54_CONTROL_TYPE_BURST,
+ P54_CONTROL_TYPE_STAT_READBACK,
+ P54_CONTROL_TYPE_BBP,
+ P54_CONTROL_TYPE_EEPROM_READBACK,
+ P54_CONTROL_TYPE_LED,
+ P54_CONTROL_TYPE_GPIO,
+ P54_CONTROL_TYPE_TIMER,
+ P54_CONTROL_TYPE_MODULATION,
+ P54_CONTROL_TYPE_SYNTH_CONFIG,
+ P54_CONTROL_TYPE_DETECTOR_VALUE,
+ P54_CONTROL_TYPE_XBOW_SYNTH_CFG,
+ P54_CONTROL_TYPE_CCE_QUIET,
+ P54_CONTROL_TYPE_PSM_STA_UNLOCK,
+ P54_CONTROL_TYPE_PCS,
+ P54_CONTROL_TYPE_BT_BALANCER = 28,
+ P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE = 30,
+ P54_CONTROL_TYPE_ARPTABLE = 31,
+ P54_CONTROL_TYPE_BT_OPTIONS = 35,
+};
+
+#define P54_HDR_FLAG_CONTROL BIT(15)
+#define P54_HDR_FLAG_CONTROL_OPSET (BIT(15) + BIT(0))
+#define P54_HDR_FLAG_DATA_ALIGN BIT(14)
+
+#define P54_HDR_FLAG_DATA_OUT_PROMISC BIT(0)
+#define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1)
+#define P54_HDR_FLAG_DATA_OUT_SEQNR BIT(2)
+#define P54_HDR_FLAG_DATA_OUT_BIT3 BIT(3)
+#define P54_HDR_FLAG_DATA_OUT_BURST BIT(4)
+#define P54_HDR_FLAG_DATA_OUT_NOCANCEL BIT(5)
+#define P54_HDR_FLAG_DATA_OUT_CLEARTIM BIT(6)
+#define P54_HDR_FLAG_DATA_OUT_HITCHHIKE BIT(7)
+#define P54_HDR_FLAG_DATA_OUT_COMPRESS BIT(8)
+#define P54_HDR_FLAG_DATA_OUT_CONCAT BIT(9)
+#define P54_HDR_FLAG_DATA_OUT_PCS_ACCEPT BIT(10)
+#define P54_HDR_FLAG_DATA_OUT_WAITEOSP BIT(11)
+
+#define P54_HDR_FLAG_DATA_IN_FCS_GOOD BIT(0)
+#define P54_HDR_FLAG_DATA_IN_MATCH_MAC BIT(1)
+#define P54_HDR_FLAG_DATA_IN_MCBC BIT(2)
+#define P54_HDR_FLAG_DATA_IN_BEACON BIT(3)
+#define P54_HDR_FLAG_DATA_IN_MATCH_BSS BIT(4)
+#define P54_HDR_FLAG_DATA_IN_BCAST_BSS BIT(5)
+#define P54_HDR_FLAG_DATA_IN_DATA BIT(6)
+#define P54_HDR_FLAG_DATA_IN_TRUNCATED BIT(7)
+#define P54_HDR_FLAG_DATA_IN_BIT8 BIT(8)
+#define P54_HDR_FLAG_DATA_IN_TRANSPARENT BIT(9)
+
+struct p54_hdr {
+ __le16 flags;
+ __le16 len;
+ __le32 req_id;
+ __le16 type; /* enum p54_control_frame_types */
+ u8 rts_tries;
+ u8 tries;
+ u8 data[0];
+} __packed;
+
+#define GET_REQ_ID(skb) \
+ (((struct p54_hdr *) ((struct sk_buff *) skb)->data)->req_id) \
+
+#define FREE_AFTER_TX(skb) \
+ ((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \
+ flags) == cpu_to_le16(P54_HDR_FLAG_CONTROL_OPSET))
+
+#define IS_DATA_FRAME(skb) \
+ (!((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \
+ flags) & cpu_to_le16(P54_HDR_FLAG_CONTROL)))
+
+#define GET_HW_QUEUE(skb) \
+ (((struct p54_tx_data *)((struct p54_hdr *) \
+ skb->data)->data)->hw_queue)
+
+/*
+ * shared interface ID definitions
+ * The interface ID is a unique identification of a specific interface.
+ * The following values are reserved: 0x0000, 0x0002, 0x0012, 0x0014, 0x0015
+ */
+#define IF_ID_ISL36356A 0x0001 /* ISL36356A <-> Firmware */
+#define IF_ID_MVC 0x0003 /* MAC Virtual Coprocessor */
+#define IF_ID_DEBUG 0x0008 /* PolDebug Interface */
+#define IF_ID_PRODUCT 0x0009
+#define IF_ID_OEM 0x000a
+#define IF_ID_PCI3877 0x000b /* 3877 <-> Host PCI */
+#define IF_ID_ISL37704C 0x000c /* ISL37704C <-> Fw */
+#define IF_ID_ISL39000 0x000f /* ISL39000 <-> Fw */
+#define IF_ID_ISL39300A 0x0010 /* ISL39300A <-> Fw */
+#define IF_ID_ISL37700_UAP 0x0016 /* ISL37700 uAP Fw <-> Fw */
+#define IF_ID_ISL39000_UAP 0x0017 /* ISL39000 uAP Fw <-> Fw */
+#define IF_ID_LMAC 0x001a /* Interface exposed by LMAC */
+
+struct exp_if {
+ __le16 role;
+ __le16 if_id;
+ __le16 variant;
+ __le16 btm_compat;
+ __le16 top_compat;
+} __packed;
+
+struct dep_if {
+ __le16 role;
+ __le16 if_id;
+ __le16 variant;
+} __packed;
+
+/* driver <-> lmac definitions */
+struct p54_eeprom_lm86 {
+ union {
+ struct {
+ __le16 offset;
+ __le16 len;
+ u8 data[0];
+ } __packed v1;
+ struct {
+ __le32 offset;
+ __le16 len;
+ u8 magic2;
+ u8 pad;
+ u8 magic[4];
+ u8 data[0];
+ } __packed v2;
+ } __packed;
+} __packed;
+
+enum p54_rx_decrypt_status {
+ P54_DECRYPT_NONE = 0,
+ P54_DECRYPT_OK,
+ P54_DECRYPT_NOKEY,
+ P54_DECRYPT_NOMICHAEL,
+ P54_DECRYPT_NOCKIPMIC,
+ P54_DECRYPT_FAIL_WEP,
+ P54_DECRYPT_FAIL_TKIP,
+ P54_DECRYPT_FAIL_MICHAEL,
+ P54_DECRYPT_FAIL_CKIPKP,
+ P54_DECRYPT_FAIL_CKIPMIC,
+ P54_DECRYPT_FAIL_AESCCMP
+};
+
+struct p54_rx_data {
+ __le16 flags;
+ __le16 len;
+ __le16 freq;
+ u8 antenna;
+ u8 rate;
+ u8 rssi;
+ u8 quality;
+ u8 decrypt_status;
+ u8 rssi_raw;
+ __le32 tsf32;
+ __le32 unalloc0;
+ u8 align[0];
+} __packed;
+
+enum p54_trap_type {
+ P54_TRAP_SCAN = 0,
+ P54_TRAP_TIMER,
+ P54_TRAP_BEACON_TX,
+ P54_TRAP_FAA_RADIO_ON,
+ P54_TRAP_FAA_RADIO_OFF,
+ P54_TRAP_RADAR,
+ P54_TRAP_NO_BEACON,
+ P54_TRAP_TBTT,
+ P54_TRAP_SCO_ENTER,
+ P54_TRAP_SCO_EXIT
+};
+
+struct p54_trap {
+ __le16 event;
+ __le16 frequency;
+} __packed;
+
+enum p54_frame_sent_status {
+ P54_TX_OK = 0,
+ P54_TX_FAILED,
+ P54_TX_PSM,
+ P54_TX_PSM_CANCELLED = 4
+};
+
+struct p54_frame_sent {
+ u8 status;
+ u8 tries;
+ u8 ack_rssi;
+ u8 quality;
+ __le16 seq;
+ u8 antenna;
+ u8 padding;
+} __packed;
+
+enum p54_tx_data_crypt {
+ P54_CRYPTO_NONE = 0,
+ P54_CRYPTO_WEP,
+ P54_CRYPTO_TKIP,
+ P54_CRYPTO_TKIPMICHAEL,
+ P54_CRYPTO_CCX_WEPMIC,
+ P54_CRYPTO_CCX_KPMIC,
+ P54_CRYPTO_CCX_KP,
+ P54_CRYPTO_AESCCMP
+};
+
+enum p54_tx_data_queue {
+ P54_QUEUE_BEACON = 0,
+ P54_QUEUE_FWSCAN = 1,
+ P54_QUEUE_MGMT = 2,
+ P54_QUEUE_CAB = 3,
+ P54_QUEUE_DATA = 4,
+
+ P54_QUEUE_AC_NUM = 4,
+ P54_QUEUE_AC_VO = 4,
+ P54_QUEUE_AC_VI = 5,
+ P54_QUEUE_AC_BE = 6,
+ P54_QUEUE_AC_BK = 7,
+
+ /* keep last */
+ P54_QUEUE_NUM = 8,
+};
+
+#define IS_QOS_QUEUE(n) (n >= P54_QUEUE_DATA)
+
+struct p54_tx_data {
+ u8 rateset[8];
+ u8 rts_rate_idx;
+ u8 crypt_offset;
+ u8 key_type;
+ u8 key_len;
+ u8 key[16];
+ u8 hw_queue;
+ u8 backlog;
+ __le16 durations[4];
+ u8 tx_antenna;
+ union {
+ struct {
+ u8 cts_rate;
+ __le16 output_power;
+ } __packed longbow;
+ struct {
+ u8 output_power;
+ u8 cts_rate;
+ u8 unalloc;
+ } __packed normal;
+ } __packed;
+ u8 unalloc2[2];
+ u8 align[0];
+} __packed;
+
+/* unit is ms */
+#define P54_TX_FRAME_LIFETIME 2000
+#define P54_TX_TIMEOUT 4000
+#define P54_STATISTICS_UPDATE 5000
+
+#define P54_FILTER_TYPE_NONE 0
+#define P54_FILTER_TYPE_STATION BIT(0)
+#define P54_FILTER_TYPE_IBSS BIT(1)
+#define P54_FILTER_TYPE_AP BIT(2)
+#define P54_FILTER_TYPE_TRANSPARENT BIT(3)
+#define P54_FILTER_TYPE_PROMISCUOUS BIT(4)
+#define P54_FILTER_TYPE_HIBERNATE BIT(5)
+#define P54_FILTER_TYPE_NOACK BIT(6)
+#define P54_FILTER_TYPE_RX_DISABLED BIT(7)
+
+struct p54_setup_mac {
+ __le16 mac_mode;
+ u8 mac_addr[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+ u8 rx_antenna;
+ u8 rx_align;
+ union {
+ struct {
+ __le32 basic_rate_mask;
+ u8 rts_rates[8];
+ __le32 rx_addr;
+ __le16 max_rx;
+ __le16 rxhw;
+ __le16 wakeup_timer;
+ __le16 unalloc0;
+ } __packed v1;
+ struct {
+ __le32 rx_addr;
+ __le16 max_rx;
+ __le16 rxhw;
+ __le16 timer;
+ __le16 truncate;
+ __le32 basic_rate_mask;
+ u8 sbss_offset;
+ u8 mcast_window;
+ u8 rx_rssi_threshold;
+ u8 rx_ed_threshold;
+ __le32 ref_clock;
+ __le16 lpf_bandwidth;
+ __le16 osc_start_delay;
+ } __packed v2;
+ } __packed;
+} __packed;
+
+#define P54_SETUP_V1_LEN 40
+#define P54_SETUP_V2_LEN (sizeof(struct p54_setup_mac))
+
+#define P54_SCAN_EXIT BIT(0)
+#define P54_SCAN_TRAP BIT(1)
+#define P54_SCAN_ACTIVE BIT(2)
+#define P54_SCAN_FILTER BIT(3)
+
+struct p54_scan_head {
+ __le16 mode;
+ __le16 dwell;
+ u8 scan_params[20];
+ __le16 freq;
+} __packed;
+
+struct p54_pa_curve_data_sample {
+ u8 rf_power;
+ u8 pa_detector;
+ u8 data_barker;
+ u8 data_bpsk;
+ u8 data_qpsk;
+ u8 data_16qam;
+ u8 data_64qam;
+ u8 padding;
+} __packed;
+
+struct p54_scan_body {
+ u8 pa_points_per_curve;
+ u8 val_barker;
+ u8 val_bpsk;
+ u8 val_qpsk;
+ u8 val_16qam;
+ u8 val_64qam;
+ struct p54_pa_curve_data_sample curve_data[8];
+ u8 dup_bpsk;
+ u8 dup_qpsk;
+ u8 dup_16qam;
+ u8 dup_64qam;
+} __packed;
+
+/*
+ * Warning: Longbow's structures are bogus.
+ */
+struct p54_channel_output_limit_longbow {
+ __le16 rf_power_points[12];
+} __packed;
+
+struct p54_pa_curve_data_sample_longbow {
+ __le16 rf_power;
+ __le16 pa_detector;
+ struct {
+ __le16 data[4];
+ } points[3] __packed;
+} __packed;
+
+struct p54_scan_body_longbow {
+ struct p54_channel_output_limit_longbow power_limits;
+ struct p54_pa_curve_data_sample_longbow curve_data[8];
+ __le16 unkn[6]; /* maybe more power_limits or rate_mask */
+} __packed;
+
+union p54_scan_body_union {
+ struct p54_scan_body normal;
+ struct p54_scan_body_longbow longbow;
+} __packed;
+
+struct p54_scan_tail_rate {
+ __le32 basic_rate_mask;
+ u8 rts_rates[8];
+} __packed;
+
+struct p54_led {
+ __le16 flags;
+ __le16 mask[2];
+ __le16 delay[2];
+} __packed;
+
+struct p54_edcf {
+ u8 flags;
+ u8 slottime;
+ u8 sifs;
+ u8 eofpad;
+ struct p54_edcf_queue_param queue[8];
+ u8 mapping[4];
+ __le16 frameburst;
+ __le16 round_trip_delay;
+} __packed;
+
+struct p54_statistics {
+ __le32 rx_success;
+ __le32 rx_bad_fcs;
+ __le32 rx_abort;
+ __le32 rx_abort_phy;
+ __le32 rts_success;
+ __le32 rts_fail;
+ __le32 tsf32;
+ __le32 airtime;
+ __le32 noise;
+ __le32 sample_noise[8];
+ __le32 sample_cca;
+ __le32 sample_tx;
+} __packed;
+
+struct p54_xbow_synth {
+ __le16 magic1;
+ __le16 magic2;
+ __le16 freq;
+ u32 padding[5];
+} __packed;
+
+struct p54_timer {
+ __le32 interval;
+} __packed;
+
+struct p54_keycache {
+ u8 entry;
+ u8 key_id;
+ u8 mac[ETH_ALEN];
+ u8 padding[2];
+ u8 key_type;
+ u8 key_len;
+ u8 key[24];
+} __packed;
+
+struct p54_burst {
+ u8 flags;
+ u8 queue;
+ u8 backlog;
+ u8 pad;
+ __le16 durations[32];
+} __packed;
+
+struct p54_psm_interval {
+ __le16 interval;
+ __le16 periods;
+} __packed;
+
+#define P54_PSM_CAM 0
+#define P54_PSM BIT(0)
+#define P54_PSM_DTIM BIT(1)
+#define P54_PSM_MCBC BIT(2)
+#define P54_PSM_CHECKSUM BIT(3)
+#define P54_PSM_SKIP_MORE_DATA BIT(4)
+#define P54_PSM_BEACON_TIMEOUT BIT(5)
+#define P54_PSM_HFOSLEEP BIT(6)
+#define P54_PSM_AUTOSWITCH_SLEEP BIT(7)
+#define P54_PSM_LPIT BIT(8)
+#define P54_PSM_BF_UCAST_SKIP BIT(9)
+#define P54_PSM_BF_MCAST_SKIP BIT(10)
+
+struct p54_psm {
+ __le16 mode;
+ __le16 aid;
+ struct p54_psm_interval intervals[4];
+ u8 beacon_rssi_skip_max;
+ u8 rssi_delta_threshold;
+ u8 nr;
+ u8 exclude[1];
+} __packed;
+
+#define MC_FILTER_ADDRESS_NUM 4
+
+struct p54_group_address_table {
+ __le16 filter_enable;
+ __le16 num_address;
+ u8 mac_list[MC_FILTER_ADDRESS_NUM][ETH_ALEN];
+} __packed;
+
+struct p54_txcancel {
+ __le32 req_id;
+} __packed;
+
+struct p54_sta_unlock {
+ u8 addr[ETH_ALEN];
+ u16 padding;
+} __packed;
+
+#define P54_TIM_CLEAR BIT(15)
+struct p54_tim {
+ u8 count;
+ u8 padding[3];
+ __le16 entry[8];
+} __packed;
+
+struct p54_cce_quiet {
+ __le32 period;
+} __packed;
+
+struct p54_bt_balancer {
+ __le16 prio_thresh;
+ __le16 acl_thresh;
+} __packed;
+
+struct p54_arp_table {
+ __le16 filter_enable;
+ u8 ipv4_addr[4];
+} __packed;
+
+/* LED control */
+int p54_set_leds(struct p54_common *priv);
+int p54_init_leds(struct p54_common *priv);
+void p54_unregister_leds(struct p54_common *priv);
+
+/* xmit functions */
+int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb);
+int p54_tx_cancel(struct p54_common *priv, __le32 req_id);
+void p54_tx(struct p54_common *priv, struct sk_buff *skb);
+
+/* synth/phy configuration */
+int p54_init_xbow_synth(struct p54_common *priv);
+int p54_scan(struct p54_common *priv, u16 mode, u16 dwell);
+
+/* MAC */
+int p54_sta_unlock(struct p54_common *priv, u8 *addr);
+int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set);
+int p54_setup_mac(struct p54_common *priv);
+int p54_set_ps(struct p54_common *priv);
+int p54_fetch_statistics(struct p54_common *priv);
+
+/* e/v DCF setup */
+int p54_set_edcf(struct p54_common *priv);
+
+/* cryptographic engine */
+int p54_upload_key(struct p54_common *priv, u8 algo, int slot,
+ u8 idx, u8 len, u8 *addr, u8* key);
+
+/* eeprom */
+int p54_download_eeprom(struct p54_common *priv, void *buf,
+ u16 offset, u16 len);
+
+/* utility */
+u8 *p54_find_ie(struct sk_buff *skb, u8 ie);
+
+#endif /* LMAC_H */
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
new file mode 100644
index 000000000000..955f6d7ec16a
--- /dev/null
+++ b/drivers/net/wireless/p54/main.c
@@ -0,0 +1,637 @@
+/*
+ * mac80211 glue code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * 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/init.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "lmac.h"
+
+static int modparam_nohwcrypt;
+module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
+MODULE_DESCRIPTION("Softmac Prism54 common code");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("prism54common");
+
+static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
+ enum sta_notify_cmd notify_cmd,
+ struct ieee80211_sta *sta)
+{
+ struct p54_common *priv = dev->priv;
+ switch (notify_cmd) {
+ case STA_NOTIFY_ADD:
+ case STA_NOTIFY_REMOVE:
+ /*
+ * Notify the firmware that we don't want or we don't
+ * need to buffer frames for this station anymore.
+ */
+
+ p54_sta_unlock(priv, sta->addr);
+ break;
+ case STA_NOTIFY_AWAKE:
+ /* update the firmware's filter table */
+ p54_sta_unlock(priv, sta->addr);
+ break;
+ default:
+ break;
+ }
+}
+
+static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta,
+ bool set)
+{
+ struct p54_common *priv = dev->priv;
+
+ return p54_update_beacon_tim(priv, sta->aid, set);
+}
+
+u8 *p54_find_ie(struct sk_buff *skb, u8 ie)
+{
+ struct ieee80211_mgmt *mgmt = (void *)skb->data;
+ u8 *pos, *end;
+
+ if (skb->len <= sizeof(mgmt))
+ return NULL;
+
+ pos = (u8 *)mgmt->u.beacon.variable;
+ end = skb->data + skb->len;
+ while (pos < end) {
+ if (pos + 2 + pos[1] > end)
+ return NULL;
+
+ if (pos[0] == ie)
+ return pos;
+
+ pos += 2 + pos[1];
+ }
+ return NULL;
+}
+
+static int p54_beacon_format_ie_tim(struct sk_buff *skb)
+{
+ /*
+ * the good excuse for this mess is ... the firmware.
+ * The dummy TIM MUST be at the end of the beacon frame,
+ * because it'll be overwritten!
+ */
+ u8 *tim;
+ u8 dtim_len;
+ u8 dtim_period;
+ u8 *next;
+
+ tim = p54_find_ie(skb, WLAN_EID_TIM);
+ if (!tim)
+ return 0;
+
+ dtim_len = tim[1];
+ dtim_period = tim[3];
+ next = tim + 2 + dtim_len;
+
+ if (dtim_len < 3)
+ return -EINVAL;
+
+ memmove(tim, next, skb_tail_pointer(skb) - next);
+ tim = skb_tail_pointer(skb) - (dtim_len + 2);
+
+ /* add the dummy at the end */
+ tim[0] = WLAN_EID_TIM;
+ tim[1] = 3;
+ tim[2] = 0;
+ tim[3] = dtim_period;
+ tim[4] = 0;
+
+ if (dtim_len > 3)
+ skb_trim(skb, skb->len - (dtim_len - 3));
+
+ return 0;
+}
+
+static int p54_beacon_update(struct p54_common *priv,
+ struct ieee80211_vif *vif)
+{
+ struct sk_buff *beacon;
+ int ret;
+
+ beacon = ieee80211_beacon_get(priv->hw, vif);
+ if (!beacon)
+ return -ENOMEM;
+ ret = p54_beacon_format_ie_tim(beacon);
+ if (ret)
+ return ret;
+
+ /*
+ * During operation, the firmware takes care of beaconing.
+ * The driver only needs to upload a new beacon template, once
+ * the template was changed by the stack or userspace.
+ *
+ * LMAC API 3.2.2 also specifies that the driver does not need
+ * to cancel the old beacon template by hand, instead the firmware
+ * will release the previous one through the feedback mechanism.
+ */
+ WARN_ON(p54_tx_80211(priv->hw, beacon));
+ priv->tsf_high32 = 0;
+ priv->tsf_low32 = 0;
+
+ return 0;
+}
+
+static int p54_start(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ int err;
+
+ mutex_lock(&priv->conf_mutex);
+ err = priv->open(dev);
+ if (err)
+ goto out;
+ P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47);
+ P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94);
+ P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0);
+ P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0);
+ err = p54_set_edcf(priv);
+ if (err)
+ goto out;
+
+ memset(priv->bssid, ~0, ETH_ALEN);
+ priv->mode = NL80211_IFTYPE_MONITOR;
+ err = p54_setup_mac(priv);
+ if (err) {
+ priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+ goto out;
+ }
+
+ queue_delayed_work(dev->workqueue, &priv->work, 0);
+
+ priv->softled_state = 0;
+ err = p54_set_leds(priv);
+
+out:
+ mutex_unlock(&priv->conf_mutex);
+ return err;
+}
+
+static void p54_stop(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ int i;
+
+ mutex_lock(&priv->conf_mutex);
+ priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+ priv->softled_state = 0;
+ p54_set_leds(priv);
+
+ cancel_delayed_work_sync(&priv->work);
+
+ priv->stop(dev);
+ skb_queue_purge(&priv->tx_pending);
+ skb_queue_purge(&priv->tx_queue);
+ for (i = 0; i < P54_QUEUE_NUM; i++) {
+ priv->tx_stats[i].count = 0;
+ priv->tx_stats[i].len = 0;
+ }
+
+ priv->beacon_req_id = cpu_to_le32(0);
+ priv->tsf_high32 = priv->tsf_low32 = 0;
+ mutex_unlock(&priv->conf_mutex);
+}
+
+static int p54_add_interface(struct ieee80211_hw *dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct p54_common *priv = dev->priv;
+
+ mutex_lock(&priv->conf_mutex);
+ if (priv->mode != NL80211_IFTYPE_MONITOR) {
+ mutex_unlock(&priv->conf_mutex);
+ return -EOPNOTSUPP;
+ }
+
+ priv->vif = conf->vif;
+
+ switch (conf->type) {
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_MESH_POINT:
+ priv->mode = conf->type;
+ break;
+ default:
+ mutex_unlock(&priv->conf_mutex);
+ return -EOPNOTSUPP;
+ }
+
+ memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
+ p54_setup_mac(priv);
+ mutex_unlock(&priv->conf_mutex);
+ return 0;
+}
+
+static void p54_remove_interface(struct ieee80211_hw *dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct p54_common *priv = dev->priv;
+
+ mutex_lock(&priv->conf_mutex);
+ priv->vif = NULL;
+
+ /*
+ * LMAC API 3.2.2 states that any active beacon template must be
+ * canceled by the driver before attempting a mode transition.
+ */
+ if (le32_to_cpu(priv->beacon_req_id) != 0) {
+ p54_tx_cancel(priv, priv->beacon_req_id);
+ wait_for_completion_interruptible_timeout(&priv->beacon_comp, HZ);
+ }
+ priv->mode = NL80211_IFTYPE_MONITOR;
+ memset(priv->mac_addr, 0, ETH_ALEN);
+ memset(priv->bssid, 0, ETH_ALEN);
+ p54_setup_mac(priv);
+ mutex_unlock(&priv->conf_mutex);
+}
+
+static int p54_config(struct ieee80211_hw *dev, u32 changed)
+{
+ int ret = 0;
+ struct p54_common *priv = dev->priv;
+ struct ieee80211_conf *conf = &dev->conf;
+
+ mutex_lock(&priv->conf_mutex);
+ if (changed & IEEE80211_CONF_CHANGE_POWER)
+ priv->output_power = conf->power_level << 2;
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+ ret = p54_scan(priv, P54_SCAN_EXIT, 0);
+ if (ret)
+ goto out;
+ }
+ if (changed & IEEE80211_CONF_CHANGE_PS) {
+ ret = p54_set_ps(priv);
+ if (ret)
+ goto out;
+ }
+
+out:
+ mutex_unlock(&priv->conf_mutex);
+ return ret;
+}
+
+static void p54_configure_filter(struct ieee80211_hw *dev,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count, struct dev_mc_list *mclist)
+{
+ struct p54_common *priv = dev->priv;
+
+ *total_flags &= FIF_PROMISC_IN_BSS |
+ FIF_OTHER_BSS;
+
+ priv->filter_flags = *total_flags;
+
+ if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS))
+ p54_setup_mac(priv);
+}
+
+static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct p54_common *priv = dev->priv;
+ int ret;
+
+ mutex_lock(&priv->conf_mutex);
+ if ((params) && !(queue > 4)) {
+ P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
+ params->cw_min, params->cw_max, params->txop);
+ ret = p54_set_edcf(priv);
+ } else
+ ret = -EINVAL;
+ mutex_unlock(&priv->conf_mutex);
+ return ret;
+}
+
+static void p54_work(struct work_struct *work)
+{
+ struct p54_common *priv = container_of(work, struct p54_common,
+ work.work);
+
+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+ return ;
+
+ /*
+ * TODO: walk through tx_queue and do the following tasks
+ * 1. initiate bursts.
+ * 2. cancel stuck frames / reset the device if necessary.
+ */
+
+ p54_fetch_statistics(priv);
+}
+
+static int p54_get_stats(struct ieee80211_hw *dev,
+ struct ieee80211_low_level_stats *stats)
+{
+ struct p54_common *priv = dev->priv;
+
+ memcpy(stats, &priv->stats, sizeof(*stats));
+ return 0;
+}
+
+static int p54_get_tx_stats(struct ieee80211_hw *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ struct p54_common *priv = dev->priv;
+
+ memcpy(stats, &priv->tx_stats[P54_QUEUE_DATA],
+ sizeof(stats[0]) * dev->queues);
+ return 0;
+}
+
+static void p54_bss_info_changed(struct ieee80211_hw *dev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info,
+ u32 changed)
+{
+ struct p54_common *priv = dev->priv;
+
+ mutex_lock(&priv->conf_mutex);
+ if (changed & BSS_CHANGED_BSSID) {
+ memcpy(priv->bssid, info->bssid, ETH_ALEN);
+ p54_setup_mac(priv);
+ }
+
+ if (changed & BSS_CHANGED_BEACON) {
+ p54_scan(priv, P54_SCAN_EXIT, 0);
+ p54_setup_mac(priv);
+ p54_beacon_update(priv, vif);
+ p54_set_edcf(priv);
+ }
+
+ if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BEACON)) {
+ priv->use_short_slot = info->use_short_slot;
+ p54_set_edcf(priv);
+ }
+ if (changed & BSS_CHANGED_BASIC_RATES) {
+ if (dev->conf.channel->band == IEEE80211_BAND_5GHZ)
+ priv->basic_rate_mask = (info->basic_rates << 4);
+ else
+ priv->basic_rate_mask = info->basic_rates;
+ p54_setup_mac(priv);
+ if (priv->fw_var >= 0x500)
+ p54_scan(priv, P54_SCAN_EXIT, 0);
+ }
+ if (changed & BSS_CHANGED_ASSOC) {
+ if (info->assoc) {
+ priv->aid = info->aid;
+ priv->wakeup_timer = info->beacon_int *
+ info->dtim_period * 5;
+ p54_setup_mac(priv);
+ } else {
+ priv->wakeup_timer = 500;
+ priv->aid = 0;
+ }
+ }
+
+ mutex_unlock(&priv->conf_mutex);
+}
+
+static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
+ struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+{
+ struct p54_common *priv = dev->priv;
+ int slot, ret = 0;
+ u8 algo = 0;
+ u8 *addr = NULL;
+
+ if (modparam_nohwcrypt)
+ return -EOPNOTSUPP;
+
+ mutex_lock(&priv->conf_mutex);
+ if (cmd == SET_KEY) {
+ switch (key->alg) {
+ case ALG_TKIP:
+ if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL |
+ BR_DESC_PRIV_CAP_TKIP))) {
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ algo = P54_CRYPTO_TKIPMICHAEL;
+ break;
+ case ALG_WEP:
+ if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) {
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ algo = P54_CRYPTO_WEP;
+ break;
+ case ALG_CCMP:
+ if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) {
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ algo = P54_CRYPTO_AESCCMP;
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+ slot = bitmap_find_free_region(priv->used_rxkeys,
+ priv->rx_keycache_size, 0);
+
+ if (slot < 0) {
+ /*
+ * The device supports the choosen algorithm, but the
+ * firmware does not provide enough key slots to store
+ * all of them.
+ * But encryption offload for outgoing frames is always
+ * possible, so we just pretend that the upload was
+ * successful and do the decryption in software.
+ */
+
+ /* mark the key as invalid. */
+ key->hw_key_idx = 0xff;
+ goto out_unlock;
+ }
+ } else {
+ slot = key->hw_key_idx;
+
+ if (slot == 0xff) {
+ /* This key was not uploaded into the rx key cache. */
+
+ goto out_unlock;
+ }
+
+ bitmap_release_region(priv->used_rxkeys, slot, 0);
+ algo = 0;
+ }
+
+ if (sta)
+ addr = sta->addr;
+
+ ret = p54_upload_key(priv, algo, slot, key->keyidx,
+ key->keylen, addr, key->key);
+ if (ret) {
+ bitmap_release_region(priv->used_rxkeys, slot, 0);
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+
+ key->hw_key_idx = slot;
+
+out_unlock:
+ mutex_unlock(&priv->conf_mutex);
+ return ret;
+}
+
+static const struct ieee80211_ops p54_ops = {
+ .tx = p54_tx_80211,
+ .start = p54_start,
+ .stop = p54_stop,
+ .add_interface = p54_add_interface,
+ .remove_interface = p54_remove_interface,
+ .set_tim = p54_set_tim,
+ .sta_notify = p54_sta_notify,
+ .set_key = p54_set_key,
+ .config = p54_config,
+ .bss_info_changed = p54_bss_info_changed,
+ .configure_filter = p54_configure_filter,
+ .conf_tx = p54_conf_tx,
+ .get_stats = p54_get_stats,
+ .get_tx_stats = p54_get_tx_stats
+};
+
+struct ieee80211_hw *p54_init_common(size_t priv_data_len)
+{
+ struct ieee80211_hw *dev;
+ struct p54_common *priv;
+
+ dev = ieee80211_alloc_hw(priv_data_len, &p54_ops);
+ if (!dev)
+ return NULL;
+
+ priv = dev->priv;
+ priv->hw = dev;
+ priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+ priv->basic_rate_mask = 0x15f;
+ spin_lock_init(&priv->tx_stats_lock);
+ skb_queue_head_init(&priv->tx_queue);
+ skb_queue_head_init(&priv->tx_pending);
+ dev->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_PS_NULLFUNC_STACK |
+ IEEE80211_HW_BEACON_FILTER |
+ IEEE80211_HW_NOISE_DBM;
+
+ dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_MESH_POINT);
+
+ dev->channel_change_time = 1000; /* TODO: find actual value */
+ priv->beacon_req_id = cpu_to_le32(0);
+ priv->tx_stats[P54_QUEUE_BEACON].limit = 1;
+ priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1;
+ priv->tx_stats[P54_QUEUE_MGMT].limit = 3;
+ priv->tx_stats[P54_QUEUE_CAB].limit = 3;
+ priv->tx_stats[P54_QUEUE_DATA].limit = 5;
+ dev->queues = 1;
+ priv->noise = -94;
+ /*
+ * We support at most 8 tries no matter which rate they're at,
+ * we cannot support max_rates * max_rate_tries as we set it
+ * here, but setting it correctly to 4/2 or so would limit us
+ * artificially if the RC algorithm wants just two rates, so
+ * let's say 4/7, we'll redistribute it at TX time, see the
+ * comments there.
+ */
+ dev->max_rates = 4;
+ dev->max_rate_tries = 7;
+ dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 +
+ sizeof(struct p54_tx_data);
+
+ mutex_init(&priv->conf_mutex);
+ mutex_init(&priv->eeprom_mutex);
+ init_completion(&priv->eeprom_comp);
+ init_completion(&priv->beacon_comp);
+ INIT_DELAYED_WORK(&priv->work, p54_work);
+
+ return dev;
+}
+EXPORT_SYMBOL_GPL(p54_init_common);
+
+int p54_register_common(struct ieee80211_hw *dev, struct device *pdev)
+{
+ struct p54_common *priv = dev->priv;
+ int err;
+
+ err = ieee80211_register_hw(dev);
+ if (err) {
+ dev_err(pdev, "Cannot register device (%d).\n", err);
+ return err;
+ }
+
+#ifdef CONFIG_P54_LEDS
+ err = p54_init_leds(priv);
+ if (err)
+ return err;
+#endif /* CONFIG_P54_LEDS */
+
+ dev_info(pdev, "is registered as '%s'\n", wiphy_name(dev->wiphy));
+ return 0;
+}
+EXPORT_SYMBOL_GPL(p54_register_common);
+
+void p54_free_common(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ unsigned int i;
+
+ for (i = 0; i < IEEE80211_NUM_BANDS; i++)
+ kfree(priv->band_table[i]);
+
+ kfree(priv->iq_autocal);
+ kfree(priv->output_limit);
+ kfree(priv->curve_data);
+ kfree(priv->used_rxkeys);
+ priv->iq_autocal = NULL;
+ priv->output_limit = NULL;
+ priv->curve_data = NULL;
+ priv->used_rxkeys = NULL;
+ ieee80211_free_hw(dev);
+}
+EXPORT_SYMBOL_GPL(p54_free_common);
+
+void p54_unregister_common(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+
+#ifdef CONFIG_P54_LEDS
+ p54_unregister_leds(priv);
+#endif /* CONFIG_P54_LEDS */
+
+ ieee80211_unregister_hw(dev);
+ mutex_destroy(&priv->conf_mutex);
+ mutex_destroy(&priv->eeprom_mutex);
+}
+EXPORT_SYMBOL_GPL(p54_unregister_common);
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
index db3df947d8ed..1afc39410e85 100644
--- a/drivers/net/wireless/p54/p54.h
+++ b/drivers/net/wireless/p54/p54.h
@@ -1,6 +1,3 @@
-#ifndef P54_H
-#define P54_H
-
/*
* Shared defines for all mac80211 Prism54 code
*
@@ -14,39 +11,78 @@
* published by the Free Software Foundation.
*/
+#ifndef P54_H
+#define P54_H
+
#ifdef CONFIG_P54_LEDS
#include <linux/leds.h>
#endif /* CONFIG_P54_LEDS */
-enum p54_control_frame_types {
- P54_CONTROL_TYPE_SETUP = 0,
- P54_CONTROL_TYPE_SCAN,
- P54_CONTROL_TYPE_TRAP,
- P54_CONTROL_TYPE_DCFINIT,
- P54_CONTROL_TYPE_RX_KEYCACHE,
- P54_CONTROL_TYPE_TIM,
- P54_CONTROL_TYPE_PSM,
- P54_CONTROL_TYPE_TXCANCEL,
- P54_CONTROL_TYPE_TXDONE,
- P54_CONTROL_TYPE_BURST,
- P54_CONTROL_TYPE_STAT_READBACK,
- P54_CONTROL_TYPE_BBP,
- P54_CONTROL_TYPE_EEPROM_READBACK,
- P54_CONTROL_TYPE_LED,
- P54_CONTROL_TYPE_GPIO,
- P54_CONTROL_TYPE_TIMER,
- P54_CONTROL_TYPE_MODULATION,
- P54_CONTROL_TYPE_SYNTH_CONFIG,
- P54_CONTROL_TYPE_DETECTOR_VALUE,
- P54_CONTROL_TYPE_XBOW_SYNTH_CFG,
- P54_CONTROL_TYPE_CCE_QUIET,
- P54_CONTROL_TYPE_PSM_STA_UNLOCK,
- P54_CONTROL_TYPE_PCS,
- P54_CONTROL_TYPE_BT_BALANCER = 28,
- P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE = 30,
- P54_CONTROL_TYPE_ARPTABLE = 31,
- P54_CONTROL_TYPE_BT_OPTIONS = 35
-};
+#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
+
+#define BR_CODE_MIN 0x80000000
+#define BR_CODE_COMPONENT_ID 0x80000001
+#define BR_CODE_COMPONENT_VERSION 0x80000002
+#define BR_CODE_DEPENDENT_IF 0x80000003
+#define BR_CODE_EXPOSED_IF 0x80000004
+#define BR_CODE_DESCR 0x80000101
+#define BR_CODE_MAX 0x8FFFFFFF
+#define BR_CODE_END_OF_BRA 0xFF0000FF
+#define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF
+
+struct bootrec {
+ __le32 code;
+ __le32 len;
+ u32 data[10];
+} __packed;
+
+/* Interface role definitions */
+#define BR_INTERFACE_ROLE_SERVER 0x0000
+#define BR_INTERFACE_ROLE_CLIENT 0x8000
+
+#define BR_DESC_PRIV_CAP_WEP BIT(0)
+#define BR_DESC_PRIV_CAP_TKIP BIT(1)
+#define BR_DESC_PRIV_CAP_MICHAEL BIT(2)
+#define BR_DESC_PRIV_CAP_CCX_CP BIT(3)
+#define BR_DESC_PRIV_CAP_CCX_MIC BIT(4)
+#define BR_DESC_PRIV_CAP_AESCCMP BIT(5)
+
+struct bootrec_desc {
+ __le16 modes;
+ __le16 flags;
+ __le32 rx_start;
+ __le32 rx_end;
+ u8 headroom;
+ u8 tailroom;
+ u8 tx_queues;
+ u8 tx_depth;
+ u8 privacy_caps;
+ u8 rx_keycache_size;
+ u8 time_size;
+ u8 padding;
+ u8 rates[16];
+ u8 padding2[4];
+ __le16 rx_mtu;
+} __packed;
+
+#define FW_FMAC 0x464d4143
+#define FW_LM86 0x4c4d3836
+#define FW_LM87 0x4c4d3837
+#define FW_LM20 0x4c4d3230
+
+struct bootrec_comp_id {
+ __le32 fw_variant;
+} __packed;
+
+struct bootrec_comp_ver {
+ char fw_version[24];
+} __packed;
+
+struct bootrec_end {
+ __le16 crc;
+ u8 padding[2];
+ u8 md5[16];
+} __packed;
/* provide 16 bytes for the transport back-end */
#define P54_TX_INFO_DATA_SIZE 16
@@ -55,34 +91,30 @@ enum p54_control_frame_types {
struct p54_tx_info {
u32 start_addr;
u32 end_addr;
- void *data[P54_TX_INFO_DATA_SIZE / sizeof(void *)];
+ union {
+ void *data[P54_TX_INFO_DATA_SIZE / sizeof(void *)];
+ struct {
+ u32 extra_len;
+ };
+ };
};
#define P54_MAX_CTRL_FRAME_LEN 0x1000
-#define P54_HDR_FLAG_CONTROL BIT(15)
-#define P54_HDR_FLAG_CONTROL_OPSET (BIT(15) + BIT(0))
-
-struct p54_hdr {
- __le16 flags;
- __le16 len;
- __le32 req_id;
- __le16 type; /* enum p54_control_frame_types */
- u8 rts_tries;
- u8 tries;
- u8 data[0];
-} __attribute__ ((packed));
-
-#define FREE_AFTER_TX(skb) \
- ((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \
- flags) == cpu_to_le16(P54_HDR_FLAG_CONTROL_OPSET))
+#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, _txop) \
+do { \
+ queue.aifs = cpu_to_le16(ai_fs); \
+ queue.cwmin = cpu_to_le16(cw_min); \
+ queue.cwmax = cpu_to_le16(cw_max); \
+ queue.txop = cpu_to_le16(_txop); \
+} while (0)
struct p54_edcf_queue_param {
__le16 aifs;
__le16 cwmin;
__le16 cwmax;
__le16 txop;
-} __attribute__ ((packed));
+} __packed;
struct p54_rssi_linear_approximation {
s16 mul;
@@ -101,13 +133,6 @@ struct p54_cal_database {
#define EEPROM_READBACK_LEN 0x3fc
-#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
-
-#define FW_FMAC 0x464d4143
-#define FW_LM86 0x4c4d3836
-#define FW_LM87 0x4c4d3837
-#define FW_LM20 0x4c4d3230
-
enum fw_state {
FW_STATE_OFF,
FW_STATE_BOOTING,
@@ -138,6 +163,7 @@ struct p54_common {
void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb);
int (*open)(struct ieee80211_hw *dev);
void (*stop)(struct ieee80211_hw *dev);
+ struct sk_buff_head tx_pending;
struct sk_buff_head tx_queue;
struct mutex conf_mutex;
@@ -156,6 +182,7 @@ struct p54_common {
/* (e)DCF / QOS state */
bool use_short_slot;
+ spinlock_t tx_stats_lock;
struct ieee80211_tx_queue_stats tx_stats[8];
struct p54_edcf_queue_param qos_params[8];
@@ -171,6 +198,7 @@ struct p54_common {
struct p54_cal_database *curve_data;
struct p54_cal_database *output_limit;
struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS];
+ struct ieee80211_supported_band *band_table[IEEE80211_NUM_BANDS];
/* BBP/MAC state */
u8 mac_addr[ETH_ALEN];
@@ -181,7 +209,9 @@ struct p54_common {
u32 tsf_low32, tsf_high32;
u32 basic_rate_mask;
u16 aid;
- struct sk_buff *cached_beacon;
+ bool powersave_override;
+ __le32 beacon_req_id;
+ struct completion beacon_comp;
/* cryptographic engine information */
u8 privacy_caps;
@@ -202,15 +232,20 @@ struct p54_common {
/* eeprom handling */
void *eeprom;
struct completion eeprom_comp;
+ struct mutex eeprom_mutex;
};
+/* interfaces for the drivers */
int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb);
int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw);
int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len);
int p54_read_eeprom(struct ieee80211_hw *dev);
+
struct ieee80211_hw *p54_init_common(size_t priv_data_len);
int p54_register_common(struct ieee80211_hw *dev, struct device *pdev);
void p54_free_common(struct ieee80211_hw *dev);
+void p54_unregister_common(struct ieee80211_hw *dev);
+
#endif /* P54_H */
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
deleted file mode 100644
index 22ca122bd798..000000000000
--- a/drivers/net/wireless/p54/p54common.c
+++ /dev/null
@@ -1,2688 +0,0 @@
-/*
- * Common code for mac80211 Prism54 drivers
- *
- * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
- * Copyright (c) 2007, Christian Lamparter <chunkeey@web.de>
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * Based on:
- * - the islsm (softmac prism54) driver, which is:
- * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- * - stlc45xx driver
- * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
- *
- * 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/init.h>
-#include <linux/firmware.h>
-#include <linux/etherdevice.h>
-
-#include <net/mac80211.h>
-#ifdef CONFIG_P54_LEDS
-#include <linux/leds.h>
-#endif /* CONFIG_P54_LEDS */
-
-#include "p54.h"
-#include "p54common.h"
-
-static int modparam_nohwcrypt;
-module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
-MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
-MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
-MODULE_DESCRIPTION("Softmac Prism54 common code");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("prism54common");
-
-static struct ieee80211_rate p54_bgrates[] = {
- { .bitrate = 10, .hw_value = 0, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 110, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 60, .hw_value = 4, },
- { .bitrate = 90, .hw_value = 5, },
- { .bitrate = 120, .hw_value = 6, },
- { .bitrate = 180, .hw_value = 7, },
- { .bitrate = 240, .hw_value = 8, },
- { .bitrate = 360, .hw_value = 9, },
- { .bitrate = 480, .hw_value = 10, },
- { .bitrate = 540, .hw_value = 11, },
-};
-
-static struct ieee80211_channel p54_bgchannels[] = {
- { .center_freq = 2412, .hw_value = 1, },
- { .center_freq = 2417, .hw_value = 2, },
- { .center_freq = 2422, .hw_value = 3, },
- { .center_freq = 2427, .hw_value = 4, },
- { .center_freq = 2432, .hw_value = 5, },
- { .center_freq = 2437, .hw_value = 6, },
- { .center_freq = 2442, .hw_value = 7, },
- { .center_freq = 2447, .hw_value = 8, },
- { .center_freq = 2452, .hw_value = 9, },
- { .center_freq = 2457, .hw_value = 10, },
- { .center_freq = 2462, .hw_value = 11, },
- { .center_freq = 2467, .hw_value = 12, },
- { .center_freq = 2472, .hw_value = 13, },
- { .center_freq = 2484, .hw_value = 14, },
-};
-
-static struct ieee80211_supported_band band_2GHz = {
- .channels = p54_bgchannels,
- .n_channels = ARRAY_SIZE(p54_bgchannels),
- .bitrates = p54_bgrates,
- .n_bitrates = ARRAY_SIZE(p54_bgrates),
-};
-
-static struct ieee80211_rate p54_arates[] = {
- { .bitrate = 60, .hw_value = 4, },
- { .bitrate = 90, .hw_value = 5, },
- { .bitrate = 120, .hw_value = 6, },
- { .bitrate = 180, .hw_value = 7, },
- { .bitrate = 240, .hw_value = 8, },
- { .bitrate = 360, .hw_value = 9, },
- { .bitrate = 480, .hw_value = 10, },
- { .bitrate = 540, .hw_value = 11, },
-};
-
-static struct ieee80211_channel p54_achannels[] = {
- { .center_freq = 4920 },
- { .center_freq = 4940 },
- { .center_freq = 4960 },
- { .center_freq = 4980 },
- { .center_freq = 5040 },
- { .center_freq = 5060 },
- { .center_freq = 5080 },
- { .center_freq = 5170 },
- { .center_freq = 5180 },
- { .center_freq = 5190 },
- { .center_freq = 5200 },
- { .center_freq = 5210 },
- { .center_freq = 5220 },
- { .center_freq = 5230 },
- { .center_freq = 5240 },
- { .center_freq = 5260 },
- { .center_freq = 5280 },
- { .center_freq = 5300 },
- { .center_freq = 5320 },
- { .center_freq = 5500 },
- { .center_freq = 5520 },
- { .center_freq = 5540 },
- { .center_freq = 5560 },
- { .center_freq = 5580 },
- { .center_freq = 5600 },
- { .center_freq = 5620 },
- { .center_freq = 5640 },
- { .center_freq = 5660 },
- { .center_freq = 5680 },
- { .center_freq = 5700 },
- { .center_freq = 5745 },
- { .center_freq = 5765 },
- { .center_freq = 5785 },
- { .center_freq = 5805 },
- { .center_freq = 5825 },
-};
-
-static struct ieee80211_supported_band band_5GHz = {
- .channels = p54_achannels,
- .n_channels = ARRAY_SIZE(p54_achannels),
- .bitrates = p54_arates,
- .n_bitrates = ARRAY_SIZE(p54_arates),
-};
-
-int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
-{
- struct p54_common *priv = dev->priv;
- struct bootrec_exp_if *exp_if;
- struct bootrec *bootrec;
- u32 *data = (u32 *)fw->data;
- u32 *end_data = (u32 *)fw->data + (fw->size >> 2);
- u8 *fw_version = NULL;
- size_t len;
- int i;
- int maxlen;
-
- if (priv->rx_start)
- return 0;
-
- while (data < end_data && *data)
- data++;
-
- while (data < end_data && !*data)
- data++;
-
- bootrec = (struct bootrec *) data;
-
- while (bootrec->data <= end_data &&
- (bootrec->data + (len = le32_to_cpu(bootrec->len))) <= end_data) {
- u32 code = le32_to_cpu(bootrec->code);
- switch (code) {
- case BR_CODE_COMPONENT_ID:
- priv->fw_interface = be32_to_cpup((__be32 *)
- bootrec->data);
- switch (priv->fw_interface) {
- case FW_LM86:
- case FW_LM20:
- case FW_LM87: {
- char *iftype = (char *)bootrec->data;
- printk(KERN_INFO "%s: p54 detected a LM%c%c "
- "firmware\n",
- wiphy_name(dev->wiphy),
- iftype[2], iftype[3]);
- break;
- }
- case FW_FMAC:
- default:
- printk(KERN_ERR "%s: unsupported firmware\n",
- wiphy_name(dev->wiphy));
- return -ENODEV;
- }
- break;
- case BR_CODE_COMPONENT_VERSION:
- /* 24 bytes should be enough for all firmwares */
- if (strnlen((unsigned char*)bootrec->data, 24) < 24)
- fw_version = (unsigned char*)bootrec->data;
- break;
- case BR_CODE_DESCR: {
- struct bootrec_desc *desc =
- (struct bootrec_desc *)bootrec->data;
- priv->rx_start = le32_to_cpu(desc->rx_start);
- /* FIXME add sanity checking */
- priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500;
- priv->headroom = desc->headroom;
- priv->tailroom = desc->tailroom;
- priv->privacy_caps = desc->privacy_caps;
- priv->rx_keycache_size = desc->rx_keycache_size;
- if (le32_to_cpu(bootrec->len) == 11)
- priv->rx_mtu = le16_to_cpu(desc->rx_mtu);
- else
- priv->rx_mtu = (size_t)
- 0x620 - priv->tx_hdr_len;
- maxlen = priv->tx_hdr_len + /* USB devices */
- sizeof(struct p54_rx_data) +
- 4 + /* rx alignment */
- IEEE80211_MAX_FRAG_THRESHOLD;
- if (priv->rx_mtu > maxlen && PAGE_SIZE == 4096) {
- printk(KERN_INFO "p54: rx_mtu reduced from %d "
- "to %d\n", priv->rx_mtu,
- maxlen);
- priv->rx_mtu = maxlen;
- }
- break;
- }
- case BR_CODE_EXPOSED_IF:
- exp_if = (struct bootrec_exp_if *) bootrec->data;
- for (i = 0; i < (len * sizeof(*exp_if) / 4); i++)
- if (exp_if[i].if_id == cpu_to_le16(0x1a))
- priv->fw_var = le16_to_cpu(exp_if[i].variant);
- break;
- case BR_CODE_DEPENDENT_IF:
- break;
- case BR_CODE_END_OF_BRA:
- case LEGACY_BR_CODE_END_OF_BRA:
- end_data = NULL;
- break;
- default:
- break;
- }
- bootrec = (struct bootrec *)&bootrec->data[len];
- }
-
- if (fw_version)
- printk(KERN_INFO "%s: FW rev %s - Softmac protocol %x.%x\n",
- wiphy_name(dev->wiphy), fw_version,
- priv->fw_var >> 8, priv->fw_var & 0xff);
-
- if (priv->fw_var < 0x500)
- printk(KERN_INFO "%s: you are using an obsolete firmware. "
- "visit http://wireless.kernel.org/en/users/Drivers/p54 "
- "and grab one for \"kernel >= 2.6.28\"!\n",
- wiphy_name(dev->wiphy));
-
- if (priv->fw_var >= 0x300) {
- /* Firmware supports QoS, use it! */
- priv->tx_stats[P54_QUEUE_AC_VO].limit = 3;
- priv->tx_stats[P54_QUEUE_AC_VI].limit = 4;
- priv->tx_stats[P54_QUEUE_AC_BE].limit = 3;
- priv->tx_stats[P54_QUEUE_AC_BK].limit = 2;
- dev->queues = P54_QUEUE_AC_NUM;
- }
-
- if (!modparam_nohwcrypt) {
- printk(KERN_INFO "%s: cryptographic accelerator "
- "WEP:%s, TKIP:%s, CCMP:%s\n",
- wiphy_name(dev->wiphy),
- (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" :
- "no", (priv->privacy_caps & (BR_DESC_PRIV_CAP_TKIP |
- BR_DESC_PRIV_CAP_MICHAEL)) ? "YES" : "no",
- (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ?
- "YES" : "no");
-
- if (priv->rx_keycache_size) {
- /*
- * NOTE:
- *
- * The firmware provides at most 255 (0 - 254) slots
- * for keys which are then used to offload decryption.
- * As a result the 255 entry (aka 0xff) can be used
- * safely by the driver to mark keys that didn't fit
- * into the full cache. This trick saves us from
- * keeping a extra list for uploaded keys.
- */
-
- priv->used_rxkeys = kzalloc(BITS_TO_LONGS(
- priv->rx_keycache_size), GFP_KERNEL);
-
- if (!priv->used_rxkeys)
- return -ENOMEM;
- }
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(p54_parse_firmware);
-
-static int p54_convert_rev0(struct ieee80211_hw *dev,
- struct pda_pa_curve_data *curve_data)
-{
- struct p54_common *priv = dev->priv;
- struct p54_pa_curve_data_sample *dst;
- struct pda_pa_curve_data_sample_rev0 *src;
- size_t cd_len = sizeof(*curve_data) +
- (curve_data->points_per_channel*sizeof(*dst) + 2) *
- curve_data->channels;
- unsigned int i, j;
- void *source, *target;
-
- priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len,
- GFP_KERNEL);
- if (!priv->curve_data)
- return -ENOMEM;
-
- priv->curve_data->entries = curve_data->channels;
- priv->curve_data->entry_size = sizeof(__le16) +
- sizeof(*dst) * curve_data->points_per_channel;
- priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
- priv->curve_data->len = cd_len;
- memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
- source = curve_data->data;
- target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
- for (i = 0; i < curve_data->channels; i++) {
- __le16 *freq = source;
- source += sizeof(__le16);
- *((__le16 *)target) = *freq;
- target += sizeof(__le16);
- for (j = 0; j < curve_data->points_per_channel; j++) {
- dst = target;
- src = source;
-
- dst->rf_power = src->rf_power;
- dst->pa_detector = src->pa_detector;
- dst->data_64qam = src->pcv;
- /* "invent" the points for the other modulations */
-#define SUB(x,y) (u8)((x) - (y)) > (x) ? 0 : (x) - (y)
- dst->data_16qam = SUB(src->pcv, 12);
- dst->data_qpsk = SUB(dst->data_16qam, 12);
- dst->data_bpsk = SUB(dst->data_qpsk, 12);
- dst->data_barker = SUB(dst->data_bpsk, 14);
-#undef SUB
- target += sizeof(*dst);
- source += sizeof(*src);
- }
- }
-
- return 0;
-}
-
-static int p54_convert_rev1(struct ieee80211_hw *dev,
- struct pda_pa_curve_data *curve_data)
-{
- struct p54_common *priv = dev->priv;
- struct p54_pa_curve_data_sample *dst;
- struct pda_pa_curve_data_sample_rev1 *src;
- size_t cd_len = sizeof(*curve_data) +
- (curve_data->points_per_channel*sizeof(*dst) + 2) *
- curve_data->channels;
- unsigned int i, j;
- void *source, *target;
-
- priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data),
- GFP_KERNEL);
- if (!priv->curve_data)
- return -ENOMEM;
-
- priv->curve_data->entries = curve_data->channels;
- priv->curve_data->entry_size = sizeof(__le16) +
- sizeof(*dst) * curve_data->points_per_channel;
- priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
- priv->curve_data->len = cd_len;
- memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
- source = curve_data->data;
- target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
- for (i = 0; i < curve_data->channels; i++) {
- __le16 *freq = source;
- source += sizeof(__le16);
- *((__le16 *)target) = *freq;
- target += sizeof(__le16);
- for (j = 0; j < curve_data->points_per_channel; j++) {
- memcpy(target, source, sizeof(*src));
-
- target += sizeof(*dst);
- source += sizeof(*src);
- }
- source++;
- }
-
- return 0;
-}
-
-static const char *p54_rf_chips[] = { "NULL", "Duette3", "Duette2",
- "Frisbee", "Xbow", "Longbow", "NULL", "NULL" };
-static int p54_init_xbow_synth(struct ieee80211_hw *dev);
-
-static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len,
- u16 type)
-{
- struct p54_common *priv = dev->priv;
- int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0;
- int entry_size = sizeof(struct pda_rssi_cal_entry) + offset;
- int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2;
- int i;
-
- if (len != (entry_size * num_entries)) {
- printk(KERN_ERR "%s: unknown rssi calibration data packing "
- " type:(%x) len:%d.\n",
- wiphy_name(dev->wiphy), type, len);
-
- print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE,
- data, len);
-
- printk(KERN_ERR "%s: please report this issue.\n",
- wiphy_name(dev->wiphy));
- return;
- }
-
- for (i = 0; i < num_entries; i++) {
- struct pda_rssi_cal_entry *cal = data +
- (offset + i * entry_size);
- priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul);
- priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add);
- }
-}
-
-static void p54_parse_default_country(struct ieee80211_hw *dev,
- void *data, int len)
-{
- struct pda_country *country;
-
- if (len != sizeof(*country)) {
- printk(KERN_ERR "%s: found possible invalid default country "
- "eeprom entry. (entry size: %d)\n",
- wiphy_name(dev->wiphy), len);
-
- print_hex_dump_bytes("country:", DUMP_PREFIX_NONE,
- data, len);
-
- printk(KERN_ERR "%s: please report this issue.\n",
- wiphy_name(dev->wiphy));
- return;
- }
-
- country = (struct pda_country *) data;
- if (country->flags == PDR_COUNTRY_CERT_CODE_PSEUDO)
- regulatory_hint(dev->wiphy, country->alpha2);
- else {
- /* TODO:
- * write a shared/common function that converts
- * "Regulatory domain codes" (802.11-2007 14.8.2.2)
- * into ISO/IEC 3166-1 alpha2 for regulatory_hint.
- */
- }
-}
-
-static int p54_convert_output_limits(struct ieee80211_hw *dev,
- u8 *data, size_t len)
-{
- struct p54_common *priv = dev->priv;
-
- if (len < 2)
- return -EINVAL;
-
- if (data[0] != 0) {
- printk(KERN_ERR "%s: unknown output power db revision:%x\n",
- wiphy_name(dev->wiphy), data[0]);
- return -EINVAL;
- }
-
- if (2 + data[1] * sizeof(struct pda_channel_output_limit) > len)
- return -EINVAL;
-
- priv->output_limit = kmalloc(data[1] *
- sizeof(struct pda_channel_output_limit) +
- sizeof(*priv->output_limit), GFP_KERNEL);
-
- if (!priv->output_limit)
- return -ENOMEM;
-
- priv->output_limit->offset = 0;
- priv->output_limit->entries = data[1];
- priv->output_limit->entry_size =
- sizeof(struct pda_channel_output_limit);
- priv->output_limit->len = priv->output_limit->entry_size *
- priv->output_limit->entries +
- priv->output_limit->offset;
-
- memcpy(priv->output_limit->data, &data[2],
- data[1] * sizeof(struct pda_channel_output_limit));
-
- return 0;
-}
-
-static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src,
- size_t total_len)
-{
- struct p54_cal_database *dst;
- size_t payload_len, entries, entry_size, offset;
-
- payload_len = le16_to_cpu(src->len);
- entries = le16_to_cpu(src->entries);
- entry_size = le16_to_cpu(src->entry_size);
- offset = le16_to_cpu(src->offset);
- if (((entries * entry_size + offset) != payload_len) ||
- (payload_len + sizeof(*src) != total_len))
- return NULL;
-
- dst = kmalloc(sizeof(*dst) + payload_len, GFP_KERNEL);
- if (!dst)
- return NULL;
-
- dst->entries = entries;
- dst->entry_size = entry_size;
- dst->offset = offset;
- dst->len = payload_len;
-
- memcpy(dst->data, src->data, payload_len);
- return dst;
-}
-
-int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
-{
- struct p54_common *priv = dev->priv;
- struct eeprom_pda_wrap *wrap = NULL;
- struct pda_entry *entry;
- unsigned int data_len, entry_len;
- void *tmp;
- int err;
- u8 *end = (u8 *)eeprom + len;
- u16 synth = 0;
-
- wrap = (struct eeprom_pda_wrap *) eeprom;
- entry = (void *)wrap->data + le16_to_cpu(wrap->len);
-
- /* verify that at least the entry length/code fits */
- while ((u8 *)entry <= end - sizeof(*entry)) {
- entry_len = le16_to_cpu(entry->len);
- data_len = ((entry_len - 1) << 1);
-
- /* abort if entry exceeds whole structure */
- if ((u8 *)entry + sizeof(*entry) + data_len > end)
- break;
-
- switch (le16_to_cpu(entry->code)) {
- case PDR_MAC_ADDRESS:
- if (data_len != ETH_ALEN)
- break;
- SET_IEEE80211_PERM_ADDR(dev, entry->data);
- break;
- case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS:
- if (priv->output_limit)
- break;
- err = p54_convert_output_limits(dev, entry->data,
- data_len);
- if (err)
- goto err;
- break;
- case PDR_PRISM_PA_CAL_CURVE_DATA: {
- struct pda_pa_curve_data *curve_data =
- (struct pda_pa_curve_data *)entry->data;
- if (data_len < sizeof(*curve_data)) {
- err = -EINVAL;
- goto err;
- }
-
- switch (curve_data->cal_method_rev) {
- case 0:
- err = p54_convert_rev0(dev, curve_data);
- break;
- case 1:
- err = p54_convert_rev1(dev, curve_data);
- break;
- default:
- printk(KERN_ERR "%s: unknown curve data "
- "revision %d\n",
- wiphy_name(dev->wiphy),
- curve_data->cal_method_rev);
- err = -ENODEV;
- break;
- }
- if (err)
- goto err;
- }
- break;
- case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
- priv->iq_autocal = kmalloc(data_len, GFP_KERNEL);
- if (!priv->iq_autocal) {
- err = -ENOMEM;
- goto err;
- }
-
- memcpy(priv->iq_autocal, entry->data, data_len);
- priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry);
- break;
- case PDR_DEFAULT_COUNTRY:
- p54_parse_default_country(dev, entry->data, data_len);
- break;
- case PDR_INTERFACE_LIST:
- tmp = entry->data;
- while ((u8 *)tmp < entry->data + data_len) {
- struct bootrec_exp_if *exp_if = tmp;
- if (le16_to_cpu(exp_if->if_id) == 0xf)
- synth = le16_to_cpu(exp_if->variant);
- tmp += sizeof(struct bootrec_exp_if);
- }
- break;
- case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
- if (data_len < 2)
- break;
- priv->version = *(u8 *)(entry->data + 1);
- break;
- case PDR_RSSI_LINEAR_APPROXIMATION:
- case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
- case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
- p54_parse_rssical(dev, entry->data, data_len,
- le16_to_cpu(entry->code));
- break;
- case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM: {
- __le16 *src = (void *) entry->data;
- s16 *dst = (void *) &priv->rssical_db;
- int i;
-
- if (data_len != sizeof(priv->rssical_db)) {
- err = -EINVAL;
- goto err;
- }
- for (i = 0; i < sizeof(priv->rssical_db) /
- sizeof(*src); i++)
- *(dst++) = (s16) le16_to_cpu(*(src++));
- }
- break;
- case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: {
- struct pda_custom_wrapper *pda = (void *) entry->data;
- if (priv->output_limit || data_len < sizeof(*pda))
- break;
- priv->output_limit = p54_convert_db(pda, data_len);
- }
- break;
- case PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM: {
- struct pda_custom_wrapper *pda = (void *) entry->data;
- if (priv->curve_data || data_len < sizeof(*pda))
- break;
- priv->curve_data = p54_convert_db(pda, data_len);
- }
- break;
- case PDR_END:
- /* make it overrun */
- entry_len = len;
- break;
- case PDR_MANUFACTURING_PART_NUMBER:
- case PDR_PDA_VERSION:
- case PDR_NIC_SERIAL_NUMBER:
- case PDR_REGULATORY_DOMAIN_LIST:
- case PDR_TEMPERATURE_TYPE:
- case PDR_PRISM_PCI_IDENTIFIER:
- case PDR_COUNTRY_INFORMATION:
- case PDR_OEM_NAME:
- case PDR_PRODUCT_NAME:
- case PDR_UTF8_OEM_NAME:
- case PDR_UTF8_PRODUCT_NAME:
- case PDR_COUNTRY_LIST:
- case PDR_ANTENNA_GAIN:
- case PDR_PRISM_INDIGO_PA_CALIBRATION_DATA:
- case PDR_REGULATORY_POWER_LIMITS:
- case PDR_RADIATED_TRANSMISSION_CORRECTION:
- case PDR_PRISM_TX_IQ_CALIBRATION:
- case PDR_BASEBAND_REGISTERS:
- case PDR_PER_CHANNEL_BASEBAND_REGISTERS:
- break;
- default:
- printk(KERN_INFO "%s: unknown eeprom code : 0x%x\n",
- wiphy_name(dev->wiphy),
- le16_to_cpu(entry->code));
- break;
- }
-
- entry = (void *)entry + (entry_len + 1)*2;
- }
-
- if (!synth || !priv->iq_autocal || !priv->output_limit ||
- !priv->curve_data) {
- printk(KERN_ERR "%s: not all required entries found in eeprom!\n",
- wiphy_name(dev->wiphy));
- err = -EINVAL;
- goto err;
- }
-
- priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
- if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
- p54_init_xbow_synth(dev);
- if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
- dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz;
- if (!(synth & PDR_SYNTH_5_GHZ_DISABLED))
- dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz;
- if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED)
- priv->rx_diversity_mask = 3;
- if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED)
- priv->tx_diversity_mask = 3;
-
- if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
- u8 perm_addr[ETH_ALEN];
-
- printk(KERN_WARNING "%s: Invalid hwaddr! Using randomly generated MAC addr\n",
- wiphy_name(dev->wiphy));
- random_ether_addr(perm_addr);
- SET_IEEE80211_PERM_ADDR(dev, perm_addr);
- }
-
- printk(KERN_INFO "%s: hwaddr %pM, MAC:isl38%02x RF:%s\n",
- wiphy_name(dev->wiphy),
- dev->wiphy->perm_addr,
- priv->version, p54_rf_chips[priv->rxhw]);
-
- return 0;
-
- err:
- if (priv->iq_autocal) {
- kfree(priv->iq_autocal);
- priv->iq_autocal = NULL;
- }
-
- if (priv->output_limit) {
- kfree(priv->output_limit);
- priv->output_limit = NULL;
- }
-
- if (priv->curve_data) {
- kfree(priv->curve_data);
- priv->curve_data = NULL;
- }
-
- printk(KERN_ERR "%s: eeprom parse failed!\n",
- wiphy_name(dev->wiphy));
- return err;
-}
-EXPORT_SYMBOL_GPL(p54_parse_eeprom);
-
-static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi)
-{
- struct p54_common *priv = dev->priv;
- int band = dev->conf.channel->band;
-
- if (priv->rxhw != PDR_SYNTH_FRONTEND_LONGBOW)
- return ((rssi * priv->rssical_db[band].mul) / 64 +
- priv->rssical_db[band].add) / 4;
- else
- /*
- * TODO: find the correct formula
- */
- return ((rssi * priv->rssical_db[band].mul) / 64 +
- priv->rssical_db[band].add) / 4;
-}
-
-static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct p54_common *priv = dev->priv;
- struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data;
- struct ieee80211_rx_status rx_status = {0};
- u16 freq = le16_to_cpu(hdr->freq);
- size_t header_len = sizeof(*hdr);
- u32 tsf32;
- u8 rate = hdr->rate & 0xf;
-
- /*
- * If the device is in a unspecified state we have to
- * ignore all data frames. Else we could end up with a
- * nasty crash.
- */
- if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
- return 0;
-
- if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD))) {
- return 0;
- }
-
- if (hdr->decrypt_status == P54_DECRYPT_OK)
- rx_status.flag |= RX_FLAG_DECRYPTED;
- if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) ||
- (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP))
- rx_status.flag |= RX_FLAG_MMIC_ERROR;
-
- rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi);
- rx_status.noise = priv->noise;
- if (hdr->rate & 0x10)
- rx_status.flag |= RX_FLAG_SHORTPRE;
- if (dev->conf.channel->band == IEEE80211_BAND_5GHZ)
- rx_status.rate_idx = (rate < 4) ? 0 : rate - 4;
- else
- rx_status.rate_idx = rate;
-
- rx_status.freq = freq;
- rx_status.band = dev->conf.channel->band;
- rx_status.antenna = hdr->antenna;
-
- tsf32 = le32_to_cpu(hdr->tsf32);
- if (tsf32 < priv->tsf_low32)
- priv->tsf_high32++;
- rx_status.mactime = ((u64)priv->tsf_high32) << 32 | tsf32;
- priv->tsf_low32 = tsf32;
-
- rx_status.flag |= RX_FLAG_TSFT;
-
- if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
- header_len += hdr->align[0];
-
- skb_pull(skb, header_len);
- skb_trim(skb, le16_to_cpu(hdr->len));
-
- ieee80211_rx_irqsafe(dev, skb, &rx_status);
-
- queue_delayed_work(dev->workqueue, &priv->work,
- msecs_to_jiffies(P54_STATISTICS_UPDATE));
-
- return -1;
-}
-
-static void inline p54_wake_free_queues(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- int i;
-
- if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
- return ;
-
- for (i = 0; i < dev->queues; i++)
- if (priv->tx_stats[i + P54_QUEUE_DATA].len <
- priv->tx_stats[i + P54_QUEUE_DATA].limit)
- ieee80211_wake_queue(dev, i);
-}
-
-void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct p54_common *priv = dev->priv;
- struct ieee80211_tx_info *info;
- struct p54_tx_info *range;
- unsigned long flags;
-
- if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue)))
- return;
-
- /*
- * don't try to free an already unlinked skb
- */
- if (unlikely((!skb->next) || (!skb->prev)))
- return;
-
- spin_lock_irqsave(&priv->tx_queue.lock, flags);
- info = IEEE80211_SKB_CB(skb);
- range = (void *)info->rate_driver_data;
- if (skb->prev != (struct sk_buff *)&priv->tx_queue) {
- struct ieee80211_tx_info *ni;
- struct p54_tx_info *mr;
-
- ni = IEEE80211_SKB_CB(skb->prev);
- mr = (struct p54_tx_info *)ni->rate_driver_data;
- }
- if (skb->next != (struct sk_buff *)&priv->tx_queue) {
- struct ieee80211_tx_info *ni;
- struct p54_tx_info *mr;
-
- ni = IEEE80211_SKB_CB(skb->next);
- mr = (struct p54_tx_info *)ni->rate_driver_data;
- }
- __skb_unlink(skb, &priv->tx_queue);
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
- dev_kfree_skb_any(skb);
- p54_wake_free_queues(dev);
-}
-EXPORT_SYMBOL_GPL(p54_free_skb);
-
-static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev,
- __le32 req_id)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *entry;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->tx_queue.lock, flags);
- entry = priv->tx_queue.next;
- while (entry != (struct sk_buff *)&priv->tx_queue) {
- struct p54_hdr *hdr = (struct p54_hdr *) entry->data;
-
- if (hdr->req_id == req_id) {
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
- return entry;
- }
- entry = entry->next;
- }
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
- return NULL;
-}
-
-static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct p54_common *priv = dev->priv;
- struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
- struct p54_frame_sent *payload = (struct p54_frame_sent *) hdr->data;
- struct sk_buff *entry;
- u32 addr = le32_to_cpu(hdr->req_id) - priv->headroom;
- struct p54_tx_info *range = NULL;
- unsigned long flags;
- int count, idx;
-
- spin_lock_irqsave(&priv->tx_queue.lock, flags);
- entry = (struct sk_buff *) priv->tx_queue.next;
- while (entry != (struct sk_buff *)&priv->tx_queue) {
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
- struct p54_hdr *entry_hdr;
- struct p54_tx_data *entry_data;
- unsigned int pad = 0, frame_len;
-
- range = (void *)info->rate_driver_data;
- if (range->start_addr != addr) {
- entry = entry->next;
- continue;
- }
-
- if (entry->next != (struct sk_buff *)&priv->tx_queue) {
- struct ieee80211_tx_info *ni;
- struct p54_tx_info *mr;
-
- ni = IEEE80211_SKB_CB(entry->next);
- mr = (struct p54_tx_info *)ni->rate_driver_data;
- }
-
- __skb_unlink(entry, &priv->tx_queue);
-
- frame_len = entry->len;
- entry_hdr = (struct p54_hdr *) entry->data;
- entry_data = (struct p54_tx_data *) entry_hdr->data;
- if (priv->tx_stats[entry_data->hw_queue].len)
- priv->tx_stats[entry_data->hw_queue].len--;
- priv->stats.dot11ACKFailureCount += payload->tries - 1;
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-
- /*
- * Frames in P54_QUEUE_FWSCAN and P54_QUEUE_BEACON are
- * generated by the driver. Therefore tx_status is bogus
- * and we don't want to confuse the mac80211 stack.
- */
- if (unlikely(entry_data->hw_queue < P54_QUEUE_FWSCAN)) {
- if (entry_data->hw_queue == P54_QUEUE_BEACON)
- priv->cached_beacon = NULL;
-
- kfree_skb(entry);
- goto out;
- }
-
- /*
- * Clear manually, ieee80211_tx_info_clear_status would
- * clear the counts too and we need them.
- */
- memset(&info->status.ampdu_ack_len, 0,
- sizeof(struct ieee80211_tx_info) -
- offsetof(struct ieee80211_tx_info, status.ampdu_ack_len));
- BUILD_BUG_ON(offsetof(struct ieee80211_tx_info,
- status.ampdu_ack_len) != 23);
-
- if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
- pad = entry_data->align[0];
-
- /* walk through the rates array and adjust the counts */
- count = payload->tries;
- for (idx = 0; idx < 4; idx++) {
- if (count >= info->status.rates[idx].count) {
- count -= info->status.rates[idx].count;
- } else if (count > 0) {
- info->status.rates[idx].count = count;
- count = 0;
- } else {
- info->status.rates[idx].idx = -1;
- info->status.rates[idx].count = 0;
- }
- }
-
- if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
- (!payload->status))
- info->flags |= IEEE80211_TX_STAT_ACK;
- if (payload->status & P54_TX_PSM_CANCELLED)
- info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
- info->status.ack_signal = p54_rssi_to_dbm(dev,
- (int)payload->ack_rssi);
-
- /* Undo all changes to the frame. */
- switch (entry_data->key_type) {
- case P54_CRYPTO_TKIPMICHAEL: {
- u8 *iv = (u8 *)(entry_data->align + pad +
- entry_data->crypt_offset);
-
- /* Restore the original TKIP IV. */
- iv[2] = iv[0];
- iv[0] = iv[1];
- iv[1] = (iv[0] | 0x20) & 0x7f; /* WEPSeed - 8.3.2.2 */
-
- frame_len -= 12; /* remove TKIP_MMIC + TKIP_ICV */
- break;
- }
- case P54_CRYPTO_AESCCMP:
- frame_len -= 8; /* remove CCMP_MIC */
- break;
- case P54_CRYPTO_WEP:
- frame_len -= 4; /* remove WEP_ICV */
- break;
- }
- skb_trim(entry, frame_len);
- skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
- ieee80211_tx_status_irqsafe(dev, entry);
- goto out;
- }
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-
-out:
- p54_wake_free_queues(dev);
-}
-
-static void p54_rx_eeprom_readback(struct ieee80211_hw *dev,
- struct sk_buff *skb)
-{
- struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
- struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data;
- struct p54_common *priv = dev->priv;
-
- if (!priv->eeprom)
- return ;
-
- if (priv->fw_var >= 0x509) {
- memcpy(priv->eeprom, eeprom->v2.data,
- le16_to_cpu(eeprom->v2.len));
- } else {
- memcpy(priv->eeprom, eeprom->v1.data,
- le16_to_cpu(eeprom->v1.len));
- }
-
- complete(&priv->eeprom_comp);
-}
-
-static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct p54_common *priv = dev->priv;
- struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
- struct p54_statistics *stats = (struct p54_statistics *) hdr->data;
- u32 tsf32;
-
- if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
- return ;
-
- tsf32 = le32_to_cpu(stats->tsf32);
- if (tsf32 < priv->tsf_low32)
- priv->tsf_high32++;
- priv->tsf_low32 = tsf32;
-
- priv->stats.dot11RTSFailureCount = le32_to_cpu(stats->rts_fail);
- priv->stats.dot11RTSSuccessCount = le32_to_cpu(stats->rts_success);
- priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs);
-
- priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise));
-
- p54_free_skb(dev, p54_find_tx_entry(dev, hdr->req_id));
-}
-
-static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct p54_common *priv = dev->priv;
- struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
- struct p54_trap *trap = (struct p54_trap *) hdr->data;
- u16 event = le16_to_cpu(trap->event);
- u16 freq = le16_to_cpu(trap->frequency);
-
- switch (event) {
- case P54_TRAP_BEACON_TX:
- break;
- case P54_TRAP_RADAR:
- printk(KERN_INFO "%s: radar (freq:%d MHz)\n",
- wiphy_name(dev->wiphy), freq);
- break;
- case P54_TRAP_NO_BEACON:
- if (priv->vif)
- ieee80211_beacon_loss(priv->vif);
- break;
- case P54_TRAP_SCAN:
- break;
- case P54_TRAP_TBTT:
- break;
- case P54_TRAP_TIMER:
- break;
- default:
- printk(KERN_INFO "%s: received event:%x freq:%d\n",
- wiphy_name(dev->wiphy), event, freq);
- break;
- }
-}
-
-static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
-
- switch (le16_to_cpu(hdr->type)) {
- case P54_CONTROL_TYPE_TXDONE:
- p54_rx_frame_sent(dev, skb);
- break;
- case P54_CONTROL_TYPE_TRAP:
- p54_rx_trap(dev, skb);
- break;
- case P54_CONTROL_TYPE_BBP:
- break;
- case P54_CONTROL_TYPE_STAT_READBACK:
- p54_rx_stats(dev, skb);
- break;
- case P54_CONTROL_TYPE_EEPROM_READBACK:
- p54_rx_eeprom_readback(dev, skb);
- break;
- default:
- printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n",
- wiphy_name(dev->wiphy), le16_to_cpu(hdr->type));
- break;
- }
-
- return 0;
-}
-
-/* returns zero if skb can be reused */
-int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- u16 type = le16_to_cpu(*((__le16 *)skb->data));
-
- if (type & P54_HDR_FLAG_CONTROL)
- return p54_rx_control(dev, skb);
- else
- return p54_rx_data(dev, skb);
-}
-EXPORT_SYMBOL_GPL(p54_rx);
-
-/*
- * So, the firmware is somewhat stupid and doesn't know what places in its
- * memory incoming data should go to. By poking around in the firmware, we
- * can find some unused memory to upload our packets to. However, data that we
- * want the card to TX needs to stay intact until the card has told us that
- * it is done with it. This function finds empty places we can upload to and
- * marks allocated areas as reserved if necessary. p54_rx_frame_sent or
- * p54_free_skb frees allocated areas.
- */
-static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
- struct p54_hdr *data, u32 len)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *entry;
- struct sk_buff *target_skb = NULL;
- struct ieee80211_tx_info *info;
- struct p54_tx_info *range;
- u32 last_addr = priv->rx_start;
- u32 largest_hole = 0;
- u32 target_addr = priv->rx_start;
- unsigned long flags;
- unsigned int left;
- len = (len + priv->headroom + priv->tailroom + 3) & ~0x3;
-
- if (!skb)
- return -EINVAL;
-
- spin_lock_irqsave(&priv->tx_queue.lock, flags);
-
- left = skb_queue_len(&priv->tx_queue);
- if (unlikely(left >= 28)) {
- /*
- * The tx_queue is nearly full!
- * We have throttle normal data traffic, because we must
- * have a few spare slots for control frames left.
- */
- ieee80211_stop_queues(dev);
- queue_delayed_work(dev->workqueue, &priv->work,
- msecs_to_jiffies(P54_TX_TIMEOUT));
-
- if (unlikely(left == 32)) {
- /*
- * The tx_queue is now really full.
- *
- * TODO: check if the device has crashed and reset it.
- */
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
- return -ENOSPC;
- }
- }
-
- entry = priv->tx_queue.next;
- while (left--) {
- u32 hole_size;
- info = IEEE80211_SKB_CB(entry);
- range = (void *)info->rate_driver_data;
- hole_size = range->start_addr - last_addr;
- if (!target_skb && hole_size >= len) {
- target_skb = entry->prev;
- hole_size -= len;
- target_addr = last_addr;
- }
- largest_hole = max(largest_hole, hole_size);
- last_addr = range->end_addr;
- entry = entry->next;
- }
- if (!target_skb && priv->rx_end - last_addr >= len) {
- target_skb = priv->tx_queue.prev;
- largest_hole = max(largest_hole, priv->rx_end - last_addr - len);
- if (!skb_queue_empty(&priv->tx_queue)) {
- info = IEEE80211_SKB_CB(target_skb);
- range = (void *)info->rate_driver_data;
- target_addr = range->end_addr;
- }
- } else
- largest_hole = max(largest_hole, priv->rx_end - last_addr);
-
- if (!target_skb) {
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
- ieee80211_stop_queues(dev);
- return -ENOSPC;
- }
-
- info = IEEE80211_SKB_CB(skb);
- range = (void *)info->rate_driver_data;
- range->start_addr = target_addr;
- range->end_addr = target_addr + len;
- __skb_queue_after(&priv->tx_queue, target_skb, skb);
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-
- if (largest_hole < priv->headroom + sizeof(struct p54_hdr) +
- 48 + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom)
- ieee80211_stop_queues(dev);
-
- data->req_id = cpu_to_le32(target_addr + priv->headroom);
- return 0;
-}
-
-static struct sk_buff *p54_alloc_skb(struct ieee80211_hw *dev, u16 hdr_flags,
- u16 payload_len, u16 type, gfp_t memflags)
-{
- struct p54_common *priv = dev->priv;
- struct p54_hdr *hdr;
- struct sk_buff *skb;
- size_t frame_len = sizeof(*hdr) + payload_len;
-
- if (frame_len > P54_MAX_CTRL_FRAME_LEN)
- return NULL;
-
- skb = __dev_alloc_skb(priv->tx_hdr_len + frame_len, memflags);
- if (!skb)
- return NULL;
- skb_reserve(skb, priv->tx_hdr_len);
-
- hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr));
- hdr->flags = cpu_to_le16(hdr_flags);
- hdr->len = cpu_to_le16(payload_len);
- hdr->type = cpu_to_le16(type);
- hdr->tries = hdr->rts_tries = 0;
-
- if (p54_assign_address(dev, skb, hdr, frame_len)) {
- kfree_skb(skb);
- return NULL;
- }
- return skb;
-}
-
-int p54_read_eeprom(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct p54_eeprom_lm86 *eeprom_hdr;
- struct sk_buff *skb;
- size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize;
- int ret = -ENOMEM;
- void *eeprom = NULL;
-
- maxblocksize = EEPROM_READBACK_LEN;
- if (priv->fw_var >= 0x509)
- maxblocksize -= 0xc;
- else
- maxblocksize -= 0x4;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(*eeprom_hdr) +
- maxblocksize, P54_CONTROL_TYPE_EEPROM_READBACK,
- GFP_KERNEL);
- if (!skb)
- goto free;
- priv->eeprom = kzalloc(EEPROM_READBACK_LEN, GFP_KERNEL);
- if (!priv->eeprom)
- goto free;
- eeprom = kzalloc(eeprom_size, GFP_KERNEL);
- if (!eeprom)
- goto free;
-
- eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb,
- sizeof(*eeprom_hdr) + maxblocksize);
-
- while (eeprom_size) {
- blocksize = min(eeprom_size, maxblocksize);
- if (priv->fw_var < 0x509) {
- eeprom_hdr->v1.offset = cpu_to_le16(offset);
- eeprom_hdr->v1.len = cpu_to_le16(blocksize);
- } else {
- eeprom_hdr->v2.offset = cpu_to_le32(offset);
- eeprom_hdr->v2.len = cpu_to_le16(blocksize);
- eeprom_hdr->v2.magic2 = 0xf;
- memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4);
- }
- priv->tx(dev, skb);
-
- if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) {
- printk(KERN_ERR "%s: device does not respond!\n",
- wiphy_name(dev->wiphy));
- ret = -EBUSY;
- goto free;
- }
-
- memcpy(eeprom + offset, priv->eeprom, blocksize);
- offset += blocksize;
- eeprom_size -= blocksize;
- }
-
- ret = p54_parse_eeprom(dev, eeprom, offset);
-free:
- kfree(priv->eeprom);
- priv->eeprom = NULL;
- p54_free_skb(dev, skb);
- kfree(eeprom);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(p54_read_eeprom);
-
-static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta,
- bool set)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_tim *tim;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*tim),
- P54_CONTROL_TYPE_TIM, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- tim = (struct p54_tim *) skb_put(skb, sizeof(*tim));
- tim->count = 1;
- tim->entry[0] = cpu_to_le16(set ? (sta->aid | 0x8000) : sta->aid);
- priv->tx(dev, skb);
- return 0;
-}
-
-static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_sta_unlock *sta;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*sta),
- P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta));
- memcpy(sta->addr, addr, ETH_ALEN);
- priv->tx(dev, skb);
- return 0;
-}
-
-static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
- enum sta_notify_cmd notify_cmd,
- struct ieee80211_sta *sta)
-{
- switch (notify_cmd) {
- case STA_NOTIFY_ADD:
- case STA_NOTIFY_REMOVE:
- /*
- * Notify the firmware that we don't want or we don't
- * need to buffer frames for this station anymore.
- */
-
- p54_sta_unlock(dev, sta->addr);
- break;
- case STA_NOTIFY_AWAKE:
- /* update the firmware's filter table */
- p54_sta_unlock(dev, sta->addr);
- break;
- default:
- break;
- }
-}
-
-static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_hdr *hdr;
- struct p54_txcancel *cancel;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*cancel),
- P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- hdr = (void *)entry->data;
- cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel));
- cancel->req_id = hdr->req_id;
- priv->tx(dev, skb);
- return 0;
-}
-
-static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb,
- struct ieee80211_tx_info *info, u8 *queue, size_t *extra_len,
- u16 *flags, u16 *aid)
-{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- struct p54_common *priv = dev->priv;
- int ret = 1;
-
- switch (priv->mode) {
- case NL80211_IFTYPE_MONITOR:
- /*
- * We have to set P54_HDR_FLAG_DATA_OUT_PROMISC for
- * every frame in promiscuous/monitor mode.
- * see STSW45x0C LMAC API - page 12.
- */
- *aid = 0;
- *flags = P54_HDR_FLAG_DATA_OUT_PROMISC;
- *queue += P54_QUEUE_DATA;
- break;
- case NL80211_IFTYPE_STATION:
- *aid = 1;
- if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
- *queue = P54_QUEUE_MGMT;
- ret = 0;
- } else
- *queue += P54_QUEUE_DATA;
- break;
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_MESH_POINT:
- if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
- *aid = 0;
- *queue = P54_QUEUE_CAB;
- return 0;
- }
-
- if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
- if (ieee80211_is_probe_resp(hdr->frame_control)) {
- *aid = 0;
- *queue = P54_QUEUE_MGMT;
- *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP |
- P54_HDR_FLAG_DATA_OUT_NOCANCEL;
- return 0;
- } else if (ieee80211_is_beacon(hdr->frame_control)) {
- *aid = 0;
-
- if (info->flags & IEEE80211_TX_CTL_INJECTED) {
- /*
- * Injecting beacons on top of a AP is
- * not a good idea... nevertheless,
- * it should be doable.
- */
-
- *queue += P54_QUEUE_DATA;
- return 1;
- }
-
- *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP;
- *queue = P54_QUEUE_BEACON;
- *extra_len = IEEE80211_MAX_TIM_LEN;
- return 0;
- } else {
- *queue = P54_QUEUE_MGMT;
- ret = 0;
- }
- } else
- *queue += P54_QUEUE_DATA;
-
- if (info->control.sta)
- *aid = info->control.sta->aid;
-
- if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
- *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
- break;
- }
- return ret;
-}
-
-static u8 p54_convert_algo(enum ieee80211_key_alg alg)
-{
- switch (alg) {
- case ALG_WEP:
- return P54_CRYPTO_WEP;
- case ALG_TKIP:
- return P54_CRYPTO_TKIPMICHAEL;
- case ALG_CCMP:
- return P54_CRYPTO_AESCCMP;
- default:
- return 0;
- }
-}
-
-static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ieee80211_tx_queue_stats *current_queue;
- struct p54_common *priv = dev->priv;
- struct p54_hdr *hdr;
- struct p54_tx_data *txhdr;
- size_t padding, len, tim_len = 0;
- int i, j, ridx, ret;
- u16 hdr_flags = 0, aid = 0;
- u8 rate, queue, crypt_offset = 0;
- u8 cts_rate = 0x20;
- u8 rc_flags;
- u8 calculated_tries[4];
- u8 nrates = 0, nremaining = 8;
-
- queue = skb_get_queue_mapping(skb);
-
- ret = p54_tx_fill(dev, skb, info, &queue, &tim_len, &hdr_flags, &aid);
- current_queue = &priv->tx_stats[queue];
- if (unlikely((current_queue->len > current_queue->limit) && ret))
- return NETDEV_TX_BUSY;
- current_queue->len++;
- current_queue->count++;
- if ((current_queue->len == current_queue->limit) && ret)
- ieee80211_stop_queue(dev, skb_get_queue_mapping(skb));
-
- padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
- len = skb->len;
-
- if (info->control.hw_key) {
- crypt_offset = ieee80211_get_hdrlen_from_skb(skb);
- if (info->control.hw_key->alg == ALG_TKIP) {
- u8 *iv = (u8 *)(skb->data + crypt_offset);
- /*
- * The firmware excepts that the IV has to have
- * this special format
- */
- iv[1] = iv[0];
- iv[0] = iv[2];
- iv[2] = 0;
- }
- }
-
- txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding);
- hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr));
-
- if (padding)
- hdr_flags |= P54_HDR_FLAG_DATA_ALIGN;
- hdr->type = cpu_to_le16(aid);
- hdr->rts_tries = info->control.rates[0].count;
-
- /*
- * we register the rates in perfect order, and
- * RTS/CTS won't happen on 5 GHz
- */
- cts_rate = info->control.rts_cts_rate_idx;
-
- memset(&txhdr->rateset, 0, sizeof(txhdr->rateset));
-
- /* see how many rates got used */
- for (i = 0; i < 4; i++) {
- if (info->control.rates[i].idx < 0)
- break;
- nrates++;
- }
-
- /* limit tries to 8/nrates per rate */
- for (i = 0; i < nrates; i++) {
- /*
- * The magic expression here is equivalent to 8/nrates for
- * all values that matter, but avoids division and jumps.
- * Note that nrates can only take the values 1 through 4.
- */
- calculated_tries[i] = min_t(int, ((15 >> nrates) | 1) + 1,
- info->control.rates[i].count);
- nremaining -= calculated_tries[i];
- }
-
- /* if there are tries left, distribute from back to front */
- for (i = nrates - 1; nremaining > 0 && i >= 0; i--) {
- int tmp = info->control.rates[i].count - calculated_tries[i];
-
- if (tmp <= 0)
- continue;
- /* RC requested more tries at this rate */
-
- tmp = min_t(int, tmp, nremaining);
- calculated_tries[i] += tmp;
- nremaining -= tmp;
- }
-
- ridx = 0;
- for (i = 0; i < nrates && ridx < 8; i++) {
- /* we register the rates in perfect order */
- rate = info->control.rates[i].idx;
- if (info->band == IEEE80211_BAND_5GHZ)
- rate += 4;
-
- /* store the count we actually calculated for TX status */
- info->control.rates[i].count = calculated_tries[i];
-
- rc_flags = info->control.rates[i].flags;
- if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) {
- rate |= 0x10;
- cts_rate |= 0x10;
- }
- if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS)
- rate |= 0x40;
- else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
- rate |= 0x20;
- for (j = 0; j < calculated_tries[i] && ridx < 8; j++) {
- txhdr->rateset[ridx] = rate;
- ridx++;
- }
- }
-
- if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
- hdr_flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
-
- /* TODO: enable bursting */
- hdr->flags = cpu_to_le16(hdr_flags);
- hdr->tries = ridx;
- txhdr->rts_rate_idx = 0;
- if (info->control.hw_key) {
- txhdr->key_type = p54_convert_algo(info->control.hw_key->alg);
- txhdr->key_len = min((u8)16, info->control.hw_key->keylen);
- memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len);
- if (info->control.hw_key->alg == ALG_TKIP) {
- if (unlikely(skb_tailroom(skb) < 12))
- goto err;
- /* reserve space for the MIC key */
- len += 8;
- memcpy(skb_put(skb, 8), &(info->control.hw_key->key
- [NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8);
- }
- /* reserve some space for ICV */
- len += info->control.hw_key->icv_len;
- memset(skb_put(skb, info->control.hw_key->icv_len), 0,
- info->control.hw_key->icv_len);
- } else {
- txhdr->key_type = 0;
- txhdr->key_len = 0;
- }
- txhdr->crypt_offset = crypt_offset;
- txhdr->hw_queue = queue;
- txhdr->backlog = current_queue->len;
- memset(txhdr->durations, 0, sizeof(txhdr->durations));
- txhdr->tx_antenna = ((info->antenna_sel_tx == 0) ?
- 2 : info->antenna_sel_tx - 1) & priv->tx_diversity_mask;
- if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
- txhdr->longbow.cts_rate = cts_rate;
- txhdr->longbow.output_power = cpu_to_le16(priv->output_power);
- } else {
- txhdr->normal.output_power = priv->output_power;
- txhdr->normal.cts_rate = cts_rate;
- }
- if (padding)
- txhdr->align[0] = padding;
-
- hdr->len = cpu_to_le16(len);
- /* modifies skb->cb and with it info, so must be last! */
- if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len)))
- goto err;
- priv->tx(dev, skb);
-
- queue_delayed_work(dev->workqueue, &priv->work,
- msecs_to_jiffies(P54_TX_FRAME_LIFETIME));
-
- return NETDEV_TX_OK;
-
- err:
- skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding);
- current_queue->len--;
- current_queue->count--;
- return NETDEV_TX_BUSY;
-}
-
-static int p54_setup_mac(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_setup_mac *setup;
- u16 mode;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup),
- P54_CONTROL_TYPE_SETUP, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup));
- if (dev->conf.radio_enabled) {
- switch (priv->mode) {
- case NL80211_IFTYPE_STATION:
- mode = P54_FILTER_TYPE_STATION;
- break;
- case NL80211_IFTYPE_AP:
- mode = P54_FILTER_TYPE_AP;
- break;
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_MESH_POINT:
- mode = P54_FILTER_TYPE_IBSS;
- break;
- case NL80211_IFTYPE_MONITOR:
- mode = P54_FILTER_TYPE_PROMISCUOUS;
- break;
- default:
- mode = P54_FILTER_TYPE_HIBERNATE;
- break;
- }
-
- /*
- * "TRANSPARENT and PROMISCUOUS are mutually exclusive"
- * STSW45X0C LMAC API - page 12
- */
- if (((priv->filter_flags & FIF_PROMISC_IN_BSS) ||
- (priv->filter_flags & FIF_OTHER_BSS)) &&
- (mode != P54_FILTER_TYPE_PROMISCUOUS))
- mode |= P54_FILTER_TYPE_TRANSPARENT;
- } else
- mode = P54_FILTER_TYPE_HIBERNATE;
-
- setup->mac_mode = cpu_to_le16(mode);
- memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN);
- memcpy(setup->bssid, priv->bssid, ETH_ALEN);
- setup->rx_antenna = 2 & priv->rx_diversity_mask; /* automatic */
- setup->rx_align = 0;
- if (priv->fw_var < 0x500) {
- setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
- memset(setup->v1.rts_rates, 0, 8);
- setup->v1.rx_addr = cpu_to_le32(priv->rx_end);
- setup->v1.max_rx = cpu_to_le16(priv->rx_mtu);
- setup->v1.rxhw = cpu_to_le16(priv->rxhw);
- setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer);
- setup->v1.unalloc0 = cpu_to_le16(0);
- } else {
- setup->v2.rx_addr = cpu_to_le32(priv->rx_end);
- setup->v2.max_rx = cpu_to_le16(priv->rx_mtu);
- setup->v2.rxhw = cpu_to_le16(priv->rxhw);
- setup->v2.timer = cpu_to_le16(priv->wakeup_timer);
- setup->v2.truncate = cpu_to_le16(48896);
- setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
- setup->v2.sbss_offset = 0;
- setup->v2.mcast_window = 0;
- setup->v2.rx_rssi_threshold = 0;
- setup->v2.rx_ed_threshold = 0;
- setup->v2.ref_clock = cpu_to_le32(644245094);
- setup->v2.lpf_bandwidth = cpu_to_le16(65535);
- setup->v2.osc_start_delay = cpu_to_le16(65535);
- }
- priv->tx(dev, skb);
- return 0;
-}
-
-static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_hdr *hdr;
- struct p54_scan_head *head;
- struct p54_iq_autocal_entry *iq_autocal;
- union p54_scan_body_union *body;
- struct p54_scan_tail_rate *rate;
- struct pda_rssi_cal_entry *rssi;
- unsigned int i;
- void *entry;
- int band = dev->conf.channel->band;
- __le16 freq = cpu_to_le16(dev->conf.channel->center_freq);
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*head) +
- 2 + sizeof(*iq_autocal) + sizeof(*body) +
- sizeof(*rate) + 2 * sizeof(*rssi),
- P54_CONTROL_TYPE_SCAN, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- head = (struct p54_scan_head *) skb_put(skb, sizeof(*head));
- memset(head->scan_params, 0, sizeof(head->scan_params));
- head->mode = cpu_to_le16(mode);
- head->dwell = cpu_to_le16(dwell);
- head->freq = freq;
-
- if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
- __le16 *pa_power_points = (__le16 *) skb_put(skb, 2);
- *pa_power_points = cpu_to_le16(0x0c);
- }
-
- iq_autocal = (void *) skb_put(skb, sizeof(*iq_autocal));
- for (i = 0; i < priv->iq_autocal_len; i++) {
- if (priv->iq_autocal[i].freq != freq)
- continue;
-
- memcpy(iq_autocal, &priv->iq_autocal[i].params,
- sizeof(struct p54_iq_autocal_entry));
- break;
- }
- if (i == priv->iq_autocal_len)
- goto err;
-
- if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW)
- body = (void *) skb_put(skb, sizeof(body->longbow));
- else
- body = (void *) skb_put(skb, sizeof(body->normal));
-
- for (i = 0; i < priv->output_limit->entries; i++) {
- __le16 *entry_freq = (void *) (priv->output_limit->data +
- priv->output_limit->entry_size * i);
-
- if (*entry_freq != freq)
- continue;
-
- if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
- memcpy(&body->longbow.power_limits,
- (void *) entry_freq + sizeof(__le16),
- priv->output_limit->entry_size);
- } else {
- struct pda_channel_output_limit *limits =
- (void *) entry_freq;
-
- body->normal.val_barker = 0x38;
- body->normal.val_bpsk = body->normal.dup_bpsk =
- limits->val_bpsk;
- body->normal.val_qpsk = body->normal.dup_qpsk =
- limits->val_qpsk;
- body->normal.val_16qam = body->normal.dup_16qam =
- limits->val_16qam;
- body->normal.val_64qam = body->normal.dup_64qam =
- limits->val_64qam;
- }
- break;
- }
- if (i == priv->output_limit->entries)
- goto err;
-
- entry = (void *)(priv->curve_data->data + priv->curve_data->offset);
- for (i = 0; i < priv->curve_data->entries; i++) {
- if (*((__le16 *)entry) != freq) {
- entry += priv->curve_data->entry_size;
- continue;
- }
-
- if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
- memcpy(&body->longbow.curve_data,
- (void *) entry + sizeof(__le16),
- priv->curve_data->entry_size);
- } else {
- struct p54_scan_body *chan = &body->normal;
- struct pda_pa_curve_data *curve_data =
- (void *) priv->curve_data->data;
-
- entry += sizeof(__le16);
- chan->pa_points_per_curve = 8;
- memset(chan->curve_data, 0, sizeof(*chan->curve_data));
- memcpy(chan->curve_data, entry,
- sizeof(struct p54_pa_curve_data_sample) *
- min((u8)8, curve_data->points_per_channel));
- }
- break;
- }
- if (i == priv->curve_data->entries)
- goto err;
-
- if ((priv->fw_var >= 0x500) && (priv->fw_var < 0x509)) {
- rate = (void *) skb_put(skb, sizeof(*rate));
- rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
- for (i = 0; i < sizeof(rate->rts_rates); i++)
- rate->rts_rates[i] = i;
- }
-
- rssi = (struct pda_rssi_cal_entry *) skb_put(skb, sizeof(*rssi));
- rssi->mul = cpu_to_le16(priv->rssical_db[band].mul);
- rssi->add = cpu_to_le16(priv->rssical_db[band].add);
- if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
- /* Longbow frontend needs ever more */
- rssi = (void *) skb_put(skb, sizeof(*rssi));
- rssi->mul = cpu_to_le16(priv->rssical_db[band].longbow_unkn);
- rssi->add = cpu_to_le16(priv->rssical_db[band].longbow_unk2);
- }
-
- if (priv->fw_var >= 0x509) {
- rate = (void *) skb_put(skb, sizeof(*rate));
- rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
- for (i = 0; i < sizeof(rate->rts_rates); i++)
- rate->rts_rates[i] = i;
- }
-
- hdr = (struct p54_hdr *) skb->data;
- hdr->len = cpu_to_le16(skb->len - sizeof(*hdr));
-
- priv->tx(dev, skb);
- return 0;
-
- err:
- printk(KERN_ERR "%s: frequency change failed\n", wiphy_name(dev->wiphy));
- p54_free_skb(dev, skb);
- return -EINVAL;
-}
-
-static int p54_set_leds(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_led *led;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*led),
- P54_CONTROL_TYPE_LED, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- led = (struct p54_led *) skb_put(skb, sizeof(*led));
- led->flags = cpu_to_le16(0x0003);
- led->mask[0] = led->mask[1] = cpu_to_le16(priv->softled_state);
- led->delay[0] = cpu_to_le16(1);
- led->delay[1] = cpu_to_le16(0);
- priv->tx(dev, skb);
- return 0;
-}
-
-#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, _txop) \
-do { \
- queue.aifs = cpu_to_le16(ai_fs); \
- queue.cwmin = cpu_to_le16(cw_min); \
- queue.cwmax = cpu_to_le16(cw_max); \
- queue.txop = cpu_to_le16(_txop); \
-} while(0)
-
-static int p54_set_edcf(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_edcf *edcf;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf),
- P54_CONTROL_TYPE_DCFINIT, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf));
- if (priv->use_short_slot) {
- edcf->slottime = 9;
- edcf->sifs = 0x10;
- edcf->eofpad = 0x00;
- } else {
- edcf->slottime = 20;
- edcf->sifs = 0x0a;
- edcf->eofpad = 0x06;
- }
- /* (see prism54/isl_oid.h for further details) */
- edcf->frameburst = cpu_to_le16(0);
- edcf->round_trip_delay = cpu_to_le16(0);
- edcf->flags = 0;
- memset(edcf->mapping, 0, sizeof(edcf->mapping));
- memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue));
- priv->tx(dev, skb);
- return 0;
-}
-
-static int p54_set_ps(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_psm *psm;
- u16 mode;
- int i;
-
- if (dev->conf.flags & IEEE80211_CONF_PS)
- mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM |
- P54_PSM_CHECKSUM | P54_PSM_MCBC;
- else
- mode = P54_PSM_CAM;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*psm),
- P54_CONTROL_TYPE_PSM, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- psm = (struct p54_psm *)skb_put(skb, sizeof(*psm));
- psm->mode = cpu_to_le16(mode);
- psm->aid = cpu_to_le16(priv->aid);
- for (i = 0; i < ARRAY_SIZE(psm->intervals); i++) {
- psm->intervals[i].interval =
- cpu_to_le16(dev->conf.listen_interval);
- psm->intervals[i].periods = cpu_to_le16(1);
- }
-
- psm->beacon_rssi_skip_max = 200;
- psm->rssi_delta_threshold = 0;
- psm->nr = 10;
- psm->exclude[0] = 0;
-
- priv->tx(dev, skb);
-
- return 0;
-}
-
-static int p54_beacon_tim(struct sk_buff *skb)
-{
- /*
- * the good excuse for this mess is ... the firmware.
- * The dummy TIM MUST be at the end of the beacon frame,
- * because it'll be overwritten!
- */
-
- struct ieee80211_mgmt *mgmt = (void *)skb->data;
- u8 *pos, *end;
-
- if (skb->len <= sizeof(mgmt))
- return -EINVAL;
-
- pos = (u8 *)mgmt->u.beacon.variable;
- end = skb->data + skb->len;
- while (pos < end) {
- if (pos + 2 + pos[1] > end)
- return -EINVAL;
-
- if (pos[0] == WLAN_EID_TIM) {
- u8 dtim_len = pos[1];
- u8 dtim_period = pos[3];
- u8 *next = pos + 2 + dtim_len;
-
- if (dtim_len < 3)
- return -EINVAL;
-
- memmove(pos, next, end - next);
-
- if (dtim_len > 3)
- skb_trim(skb, skb->len - (dtim_len - 3));
-
- pos = end - (dtim_len + 2);
-
- /* add the dummy at the end */
- pos[0] = WLAN_EID_TIM;
- pos[1] = 3;
- pos[2] = 0;
- pos[3] = dtim_period;
- pos[4] = 0;
- return 0;
- }
- pos += 2 + pos[1];
- }
- return 0;
-}
-
-static int p54_beacon_update(struct ieee80211_hw *dev,
- struct ieee80211_vif *vif)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *beacon;
- int ret;
-
- if (priv->cached_beacon) {
- p54_tx_cancel(dev, priv->cached_beacon);
- /* wait for the last beacon the be freed */
- msleep(10);
- }
-
- beacon = ieee80211_beacon_get(dev, vif);
- if (!beacon)
- return -ENOMEM;
- ret = p54_beacon_tim(beacon);
- if (ret)
- return ret;
- ret = p54_tx(dev, beacon);
- if (ret)
- return ret;
- priv->cached_beacon = beacon;
- priv->tsf_high32 = 0;
- priv->tsf_low32 = 0;
-
- return 0;
-}
-
-static int p54_start(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- int err;
-
- mutex_lock(&priv->conf_mutex);
- err = priv->open(dev);
- if (err)
- goto out;
- P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47);
- P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94);
- P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0);
- P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0);
- err = p54_set_edcf(dev);
- if (err)
- goto out;
-
- memset(priv->bssid, ~0, ETH_ALEN);
- priv->mode = NL80211_IFTYPE_MONITOR;
- err = p54_setup_mac(dev);
- if (err) {
- priv->mode = NL80211_IFTYPE_UNSPECIFIED;
- goto out;
- }
-
- queue_delayed_work(dev->workqueue, &priv->work, 0);
-
- priv->softled_state = 0;
- err = p54_set_leds(dev);
-
-out:
- mutex_unlock(&priv->conf_mutex);
- return err;
-}
-
-static void p54_stop(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
-
- mutex_lock(&priv->conf_mutex);
- priv->mode = NL80211_IFTYPE_UNSPECIFIED;
- priv->softled_state = 0;
- p54_set_leds(dev);
-
-#ifdef CONFIG_P54_LEDS
- cancel_delayed_work_sync(&priv->led_work);
-#endif /* CONFIG_P54_LEDS */
- cancel_delayed_work_sync(&priv->work);
- if (priv->cached_beacon)
- p54_tx_cancel(dev, priv->cached_beacon);
-
- priv->stop(dev);
- while ((skb = skb_dequeue(&priv->tx_queue)))
- kfree_skb(skb);
- priv->cached_beacon = NULL;
- priv->tsf_high32 = priv->tsf_low32 = 0;
- mutex_unlock(&priv->conf_mutex);
-}
-
-static int p54_add_interface(struct ieee80211_hw *dev,
- struct ieee80211_if_init_conf *conf)
-{
- struct p54_common *priv = dev->priv;
-
- mutex_lock(&priv->conf_mutex);
- if (priv->mode != NL80211_IFTYPE_MONITOR) {
- mutex_unlock(&priv->conf_mutex);
- return -EOPNOTSUPP;
- }
-
- priv->vif = conf->vif;
-
- switch (conf->type) {
- case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_MESH_POINT:
- priv->mode = conf->type;
- break;
- default:
- mutex_unlock(&priv->conf_mutex);
- return -EOPNOTSUPP;
- }
-
- memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
- p54_setup_mac(dev);
- mutex_unlock(&priv->conf_mutex);
- return 0;
-}
-
-static void p54_remove_interface(struct ieee80211_hw *dev,
- struct ieee80211_if_init_conf *conf)
-{
- struct p54_common *priv = dev->priv;
-
- mutex_lock(&priv->conf_mutex);
- priv->vif = NULL;
- if (priv->cached_beacon)
- p54_tx_cancel(dev, priv->cached_beacon);
- priv->mode = NL80211_IFTYPE_MONITOR;
- memset(priv->mac_addr, 0, ETH_ALEN);
- memset(priv->bssid, 0, ETH_ALEN);
- p54_setup_mac(dev);
- mutex_unlock(&priv->conf_mutex);
-}
-
-static int p54_config(struct ieee80211_hw *dev, u32 changed)
-{
- int ret = 0;
- struct p54_common *priv = dev->priv;
- struct ieee80211_conf *conf = &dev->conf;
-
- mutex_lock(&priv->conf_mutex);
- if (changed & IEEE80211_CONF_CHANGE_POWER)
- priv->output_power = conf->power_level << 2;
- if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) {
- ret = p54_setup_mac(dev);
- if (ret)
- goto out;
- }
- if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
- ret = p54_scan(dev, P54_SCAN_EXIT, 0);
- if (ret)
- goto out;
- }
- if (changed & IEEE80211_CONF_CHANGE_PS) {
- ret = p54_set_ps(dev);
- if (ret)
- goto out;
- }
-
-out:
- mutex_unlock(&priv->conf_mutex);
- return ret;
-}
-
-static void p54_configure_filter(struct ieee80211_hw *dev,
- unsigned int changed_flags,
- unsigned int *total_flags,
- int mc_count, struct dev_mc_list *mclist)
-{
- struct p54_common *priv = dev->priv;
-
- *total_flags &= FIF_PROMISC_IN_BSS |
- FIF_OTHER_BSS;
-
- priv->filter_flags = *total_flags;
-
- if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS))
- p54_setup_mac(dev);
-}
-
-static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue,
- const struct ieee80211_tx_queue_params *params)
-{
- struct p54_common *priv = dev->priv;
- int ret;
-
- mutex_lock(&priv->conf_mutex);
- if ((params) && !(queue > 4)) {
- P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
- params->cw_min, params->cw_max, params->txop);
- ret = p54_set_edcf(dev);
- } else
- ret = -EINVAL;
- mutex_unlock(&priv->conf_mutex);
- return ret;
-}
-
-static int p54_init_xbow_synth(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_xbow_synth *xbow;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*xbow),
- P54_CONTROL_TYPE_XBOW_SYNTH_CFG, GFP_KERNEL);
- if (!skb)
- return -ENOMEM;
-
- xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow));
- xbow->magic1 = cpu_to_le16(0x1);
- xbow->magic2 = cpu_to_le16(0x2);
- xbow->freq = cpu_to_le16(5390);
- memset(xbow->padding, 0, sizeof(xbow->padding));
- priv->tx(dev, skb);
- return 0;
-}
-
-static void p54_work(struct work_struct *work)
-{
- struct p54_common *priv = container_of(work, struct p54_common,
- work.work);
- struct ieee80211_hw *dev = priv->hw;
- struct sk_buff *skb;
-
- if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
- return ;
-
- /*
- * TODO: walk through tx_queue and do the following tasks
- * 1. initiate bursts.
- * 2. cancel stuck frames / reset the device if necessary.
- */
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL,
- sizeof(struct p54_statistics),
- P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL);
- if (!skb)
- return ;
-
- priv->tx(dev, skb);
-}
-
-static int p54_get_stats(struct ieee80211_hw *dev,
- struct ieee80211_low_level_stats *stats)
-{
- struct p54_common *priv = dev->priv;
-
- memcpy(stats, &priv->stats, sizeof(*stats));
- return 0;
-}
-
-static int p54_get_tx_stats(struct ieee80211_hw *dev,
- struct ieee80211_tx_queue_stats *stats)
-{
- struct p54_common *priv = dev->priv;
-
- memcpy(stats, &priv->tx_stats[P54_QUEUE_DATA],
- sizeof(stats[0]) * dev->queues);
- return 0;
-}
-
-static void p54_bss_info_changed(struct ieee80211_hw *dev,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *info,
- u32 changed)
-{
- struct p54_common *priv = dev->priv;
- int ret;
-
- mutex_lock(&priv->conf_mutex);
- if (changed & BSS_CHANGED_BSSID) {
- memcpy(priv->bssid, info->bssid, ETH_ALEN);
- ret = p54_setup_mac(dev);
- if (ret)
- goto out;
- }
-
- if (changed & BSS_CHANGED_BEACON) {
- ret = p54_scan(dev, P54_SCAN_EXIT, 0);
- if (ret)
- goto out;
- ret = p54_setup_mac(dev);
- if (ret)
- goto out;
- ret = p54_beacon_update(dev, vif);
- if (ret)
- goto out;
- }
- /* XXX: this mimics having two callbacks... clean up */
- out:
- mutex_unlock(&priv->conf_mutex);
-
- if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BEACON)) {
- priv->use_short_slot = info->use_short_slot;
- p54_set_edcf(dev);
- }
- if (changed & BSS_CHANGED_BASIC_RATES) {
- if (dev->conf.channel->band == IEEE80211_BAND_5GHZ)
- priv->basic_rate_mask = (info->basic_rates << 4);
- else
- priv->basic_rate_mask = info->basic_rates;
- p54_setup_mac(dev);
- if (priv->fw_var >= 0x500)
- p54_scan(dev, P54_SCAN_EXIT, 0);
- }
- if (changed & BSS_CHANGED_ASSOC) {
- if (info->assoc) {
- priv->aid = info->aid;
- priv->wakeup_timer = info->beacon_int *
- info->dtim_period * 5;
- p54_setup_mac(dev);
- }
- }
-}
-
-static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
- struct ieee80211_vif *vif, struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_keycache *rxkey;
- int slot, ret = 0;
- u8 algo = 0;
-
- if (modparam_nohwcrypt)
- return -EOPNOTSUPP;
-
- mutex_lock(&priv->conf_mutex);
- if (cmd == SET_KEY) {
- switch (key->alg) {
- case ALG_TKIP:
- if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL |
- BR_DESC_PRIV_CAP_TKIP))) {
- ret = -EOPNOTSUPP;
- goto out_unlock;
- }
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- algo = P54_CRYPTO_TKIPMICHAEL;
- break;
- case ALG_WEP:
- if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) {
- ret = -EOPNOTSUPP;
- goto out_unlock;
- }
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- algo = P54_CRYPTO_WEP;
- break;
- case ALG_CCMP:
- if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) {
- ret = -EOPNOTSUPP;
- goto out_unlock;
- }
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- algo = P54_CRYPTO_AESCCMP;
- break;
- default:
- ret = -EOPNOTSUPP;
- goto out_unlock;
- }
- slot = bitmap_find_free_region(priv->used_rxkeys,
- priv->rx_keycache_size, 0);
-
- if (slot < 0) {
- /*
- * The device supports the choosen algorithm, but the
- * firmware does not provide enough key slots to store
- * all of them.
- * But encryption offload for outgoing frames is always
- * possible, so we just pretend that the upload was
- * successful and do the decryption in software.
- */
-
- /* mark the key as invalid. */
- key->hw_key_idx = 0xff;
- goto out_unlock;
- }
- } else {
- slot = key->hw_key_idx;
-
- if (slot == 0xff) {
- /* This key was not uploaded into the rx key cache. */
-
- goto out_unlock;
- }
-
- bitmap_release_region(priv->used_rxkeys, slot, 0);
- algo = 0;
- }
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey),
- P54_CONTROL_TYPE_RX_KEYCACHE, GFP_KERNEL);
- if (!skb) {
- bitmap_release_region(priv->used_rxkeys, slot, 0);
- ret = -ENOSPC;
- goto out_unlock;
- }
-
- rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey));
- rxkey->entry = slot;
- rxkey->key_id = key->keyidx;
- rxkey->key_type = algo;
- if (sta)
- memcpy(rxkey->mac, sta->addr, ETH_ALEN);
- else
- memset(rxkey->mac, ~0, ETH_ALEN);
- if (key->alg != ALG_TKIP) {
- rxkey->key_len = min((u8)16, key->keylen);
- memcpy(rxkey->key, key->key, rxkey->key_len);
- } else {
- rxkey->key_len = 24;
- memcpy(rxkey->key, key->key, 16);
- memcpy(&(rxkey->key[16]), &(key->key
- [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8);
- }
-
- priv->tx(dev, skb);
- key->hw_key_idx = slot;
-
-out_unlock:
- mutex_unlock(&priv->conf_mutex);
- return ret;
-}
-
-#ifdef CONFIG_P54_LEDS
-static void p54_update_leds(struct work_struct *work)
-{
- struct p54_common *priv = container_of(work, struct p54_common,
- led_work.work);
- int err, i, tmp, blink_delay = 400;
- bool rerun = false;
-
- /* Don't toggle the LED, when the device is down. */
- if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
- return ;
-
- for (i = 0; i < ARRAY_SIZE(priv->leds); i++)
- if (priv->leds[i].toggled) {
- priv->softled_state |= BIT(i);
-
- tmp = 70 + 200 / (priv->leds[i].toggled);
- if (tmp < blink_delay)
- blink_delay = tmp;
-
- if (priv->leds[i].led_dev.brightness == LED_OFF)
- rerun = true;
-
- priv->leds[i].toggled =
- !!priv->leds[i].led_dev.brightness;
- } else
- priv->softled_state &= ~BIT(i);
-
- err = p54_set_leds(priv->hw);
- if (err && net_ratelimit())
- printk(KERN_ERR "%s: failed to update LEDs.\n",
- wiphy_name(priv->hw->wiphy));
-
- if (rerun)
- queue_delayed_work(priv->hw->workqueue, &priv->led_work,
- msecs_to_jiffies(blink_delay));
-}
-
-static void p54_led_brightness_set(struct led_classdev *led_dev,
- enum led_brightness brightness)
-{
- struct p54_led_dev *led = container_of(led_dev, struct p54_led_dev,
- led_dev);
- struct ieee80211_hw *dev = led->hw_dev;
- struct p54_common *priv = dev->priv;
-
- if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
- return ;
-
- if (brightness) {
- led->toggled++;
- queue_delayed_work(priv->hw->workqueue, &priv->led_work,
- HZ/10);
- }
-}
-
-static int p54_register_led(struct ieee80211_hw *dev,
- unsigned int led_index,
- char *name, char *trigger)
-{
- struct p54_common *priv = dev->priv;
- struct p54_led_dev *led = &priv->leds[led_index];
- int err;
-
- if (led->registered)
- return -EEXIST;
-
- snprintf(led->name, sizeof(led->name), "p54-%s::%s",
- wiphy_name(dev->wiphy), name);
- led->hw_dev = dev;
- led->index = led_index;
- led->led_dev.name = led->name;
- led->led_dev.default_trigger = trigger;
- led->led_dev.brightness_set = p54_led_brightness_set;
-
- err = led_classdev_register(wiphy_dev(dev->wiphy), &led->led_dev);
- if (err)
- printk(KERN_ERR "%s: Failed to register %s LED.\n",
- wiphy_name(dev->wiphy), name);
- else
- led->registered = 1;
-
- return err;
-}
-
-static int p54_init_leds(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- int err;
-
- /*
- * TODO:
- * Figure out if the EEPROM contains some hints about the number
- * of available/programmable LEDs of the device.
- */
-
- INIT_DELAYED_WORK(&priv->led_work, p54_update_leds);
-
- err = p54_register_led(dev, 0, "assoc",
- ieee80211_get_assoc_led_name(dev));
- if (err)
- return err;
-
- err = p54_register_led(dev, 1, "tx",
- ieee80211_get_tx_led_name(dev));
- if (err)
- return err;
-
- err = p54_register_led(dev, 2, "rx",
- ieee80211_get_rx_led_name(dev));
- if (err)
- return err;
-
- err = p54_register_led(dev, 3, "radio",
- ieee80211_get_radio_led_name(dev));
- if (err)
- return err;
-
- err = p54_set_leds(dev);
- return err;
-}
-
-static void p54_unregister_leds(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(priv->leds); i++)
- if (priv->leds[i].registered)
- led_classdev_unregister(&priv->leds[i].led_dev);
-}
-#endif /* CONFIG_P54_LEDS */
-
-static const struct ieee80211_ops p54_ops = {
- .tx = p54_tx,
- .start = p54_start,
- .stop = p54_stop,
- .add_interface = p54_add_interface,
- .remove_interface = p54_remove_interface,
- .set_tim = p54_set_tim,
- .sta_notify = p54_sta_notify,
- .set_key = p54_set_key,
- .config = p54_config,
- .bss_info_changed = p54_bss_info_changed,
- .configure_filter = p54_configure_filter,
- .conf_tx = p54_conf_tx,
- .get_stats = p54_get_stats,
- .get_tx_stats = p54_get_tx_stats
-};
-
-struct ieee80211_hw *p54_init_common(size_t priv_data_len)
-{
- struct ieee80211_hw *dev;
- struct p54_common *priv;
-
- dev = ieee80211_alloc_hw(priv_data_len, &p54_ops);
- if (!dev)
- return NULL;
-
- priv = dev->priv;
- priv->hw = dev;
- priv->mode = NL80211_IFTYPE_UNSPECIFIED;
- priv->basic_rate_mask = 0x15f;
- skb_queue_head_init(&priv->tx_queue);
- dev->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_NOISE_DBM;
-
- dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC) |
- BIT(NL80211_IFTYPE_AP) |
- BIT(NL80211_IFTYPE_MESH_POINT);
-
- dev->channel_change_time = 1000; /* TODO: find actual value */
- priv->tx_stats[P54_QUEUE_BEACON].limit = 1;
- priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1;
- priv->tx_stats[P54_QUEUE_MGMT].limit = 3;
- priv->tx_stats[P54_QUEUE_CAB].limit = 3;
- priv->tx_stats[P54_QUEUE_DATA].limit = 5;
- dev->queues = 1;
- priv->noise = -94;
- /*
- * We support at most 8 tries no matter which rate they're at,
- * we cannot support max_rates * max_rate_tries as we set it
- * here, but setting it correctly to 4/2 or so would limit us
- * artificially if the RC algorithm wants just two rates, so
- * let's say 4/7, we'll redistribute it at TX time, see the
- * comments there.
- */
- dev->max_rates = 4;
- dev->max_rate_tries = 7;
- dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 +
- sizeof(struct p54_tx_data);
-
- mutex_init(&priv->conf_mutex);
- init_completion(&priv->eeprom_comp);
- INIT_DELAYED_WORK(&priv->work, p54_work);
-
- return dev;
-}
-EXPORT_SYMBOL_GPL(p54_init_common);
-
-int p54_register_common(struct ieee80211_hw *dev, struct device *pdev)
-{
- int err;
-
- err = ieee80211_register_hw(dev);
- if (err) {
- dev_err(pdev, "Cannot register device (%d).\n", err);
- return err;
- }
-
-#ifdef CONFIG_P54_LEDS
- err = p54_init_leds(dev);
- if (err)
- return err;
-#endif /* CONFIG_P54_LEDS */
-
- dev_info(pdev, "is registered as '%s'\n", wiphy_name(dev->wiphy));
- return 0;
-}
-EXPORT_SYMBOL_GPL(p54_register_common);
-
-void p54_free_common(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- kfree(priv->iq_autocal);
- kfree(priv->output_limit);
- kfree(priv->curve_data);
- kfree(priv->used_rxkeys);
-
-#ifdef CONFIG_P54_LEDS
- p54_unregister_leds(dev);
-#endif /* CONFIG_P54_LEDS */
-}
-EXPORT_SYMBOL_GPL(p54_free_common);
diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h
deleted file mode 100644
index 75ead7a150fc..000000000000
--- a/drivers/net/wireless/p54/p54common.h
+++ /dev/null
@@ -1,644 +0,0 @@
-#ifndef P54COMMON_H
-#define P54COMMON_H
-
-/*
- * Common code specific definitions for mac80211 Prism54 drivers
- *
- * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
- * Copyright (c) 2007, Christian Lamparter <chunkeey@web.de>
- *
- * Based on:
- * - the islsm (softmac prism54) driver, which is:
- * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- *
- * - LMAC API interface header file for STLC4560 (lmac_longbow.h)
- * Copyright (C) 2007 Conexant Systems, 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.
- */
-
-struct bootrec {
- __le32 code;
- __le32 len;
- u32 data[10];
-} __attribute__((packed));
-
-#define PDR_SYNTH_FRONTEND_MASK 0x0007
-#define PDR_SYNTH_FRONTEND_DUETTE3 0x0001
-#define PDR_SYNTH_FRONTEND_DUETTE2 0x0002
-#define PDR_SYNTH_FRONTEND_FRISBEE 0x0003
-#define PDR_SYNTH_FRONTEND_XBOW 0x0004
-#define PDR_SYNTH_FRONTEND_LONGBOW 0x0005
-#define PDR_SYNTH_IQ_CAL_MASK 0x0018
-#define PDR_SYNTH_IQ_CAL_PA_DETECTOR 0x0000
-#define PDR_SYNTH_IQ_CAL_DISABLED 0x0008
-#define PDR_SYNTH_IQ_CAL_ZIF 0x0010
-#define PDR_SYNTH_FAA_SWITCH_MASK 0x0020
-#define PDR_SYNTH_FAA_SWITCH_ENABLED 0x0020
-#define PDR_SYNTH_24_GHZ_MASK 0x0040
-#define PDR_SYNTH_24_GHZ_DISABLED 0x0040
-#define PDR_SYNTH_5_GHZ_MASK 0x0080
-#define PDR_SYNTH_5_GHZ_DISABLED 0x0080
-#define PDR_SYNTH_RX_DIV_MASK 0x0100
-#define PDR_SYNTH_RX_DIV_SUPPORTED 0x0100
-#define PDR_SYNTH_TX_DIV_MASK 0x0200
-#define PDR_SYNTH_TX_DIV_SUPPORTED 0x0200
-
-struct bootrec_exp_if {
- __le16 role;
- __le16 if_id;
- __le16 variant;
- __le16 btm_compat;
- __le16 top_compat;
-} __attribute__((packed));
-
-#define BR_DESC_PRIV_CAP_WEP BIT(0)
-#define BR_DESC_PRIV_CAP_TKIP BIT(1)
-#define BR_DESC_PRIV_CAP_MICHAEL BIT(2)
-#define BR_DESC_PRIV_CAP_CCX_CP BIT(3)
-#define BR_DESC_PRIV_CAP_CCX_MIC BIT(4)
-#define BR_DESC_PRIV_CAP_AESCCMP BIT(5)
-
-struct bootrec_desc {
- __le16 modes;
- __le16 flags;
- __le32 rx_start;
- __le32 rx_end;
- u8 headroom;
- u8 tailroom;
- u8 tx_queues;
- u8 tx_depth;
- u8 privacy_caps;
- u8 rx_keycache_size;
- u8 time_size;
- u8 padding;
- u8 rates[16];
- u8 padding2[4];
- __le16 rx_mtu;
-} __attribute__((packed));
-
-#define BR_CODE_MIN 0x80000000
-#define BR_CODE_COMPONENT_ID 0x80000001
-#define BR_CODE_COMPONENT_VERSION 0x80000002
-#define BR_CODE_DEPENDENT_IF 0x80000003
-#define BR_CODE_EXPOSED_IF 0x80000004
-#define BR_CODE_DESCR 0x80000101
-#define BR_CODE_MAX 0x8FFFFFFF
-#define BR_CODE_END_OF_BRA 0xFF0000FF
-#define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF
-
-#define P54_HDR_FLAG_DATA_ALIGN BIT(14)
-#define P54_HDR_FLAG_DATA_OUT_PROMISC BIT(0)
-#define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1)
-#define P54_HDR_FLAG_DATA_OUT_SEQNR BIT(2)
-#define P54_HDR_FLAG_DATA_OUT_BIT3 BIT(3)
-#define P54_HDR_FLAG_DATA_OUT_BURST BIT(4)
-#define P54_HDR_FLAG_DATA_OUT_NOCANCEL BIT(5)
-#define P54_HDR_FLAG_DATA_OUT_CLEARTIM BIT(6)
-#define P54_HDR_FLAG_DATA_OUT_HITCHHIKE BIT(7)
-#define P54_HDR_FLAG_DATA_OUT_COMPRESS BIT(8)
-#define P54_HDR_FLAG_DATA_OUT_CONCAT BIT(9)
-#define P54_HDR_FLAG_DATA_OUT_PCS_ACCEPT BIT(10)
-#define P54_HDR_FLAG_DATA_OUT_WAITEOSP BIT(11)
-
-#define P54_HDR_FLAG_DATA_IN_FCS_GOOD BIT(0)
-#define P54_HDR_FLAG_DATA_IN_MATCH_MAC BIT(1)
-#define P54_HDR_FLAG_DATA_IN_MCBC BIT(2)
-#define P54_HDR_FLAG_DATA_IN_BEACON BIT(3)
-#define P54_HDR_FLAG_DATA_IN_MATCH_BSS BIT(4)
-#define P54_HDR_FLAG_DATA_IN_BCAST_BSS BIT(5)
-#define P54_HDR_FLAG_DATA_IN_DATA BIT(6)
-#define P54_HDR_FLAG_DATA_IN_TRUNCATED BIT(7)
-#define P54_HDR_FLAG_DATA_IN_BIT8 BIT(8)
-#define P54_HDR_FLAG_DATA_IN_TRANSPARENT BIT(9)
-
-/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */
-
-struct pda_entry {
- __le16 len; /* includes both code and data */
- __le16 code;
- u8 data[0];
-} __attribute__ ((packed));
-
-struct eeprom_pda_wrap {
- __le32 magic;
- __le16 pad;
- __le16 len;
- __le32 arm_opcode;
- u8 data[0];
-} __attribute__ ((packed));
-
-struct p54_iq_autocal_entry {
- __le16 iq_param[4];
-} __attribute__ ((packed));
-
-struct pda_iq_autocal_entry {
- __le16 freq;
- struct p54_iq_autocal_entry params;
-} __attribute__ ((packed));
-
-struct pda_channel_output_limit {
- __le16 freq;
- u8 val_bpsk;
- u8 val_qpsk;
- u8 val_16qam;
- u8 val_64qam;
- u8 rate_set_mask;
- u8 rate_set_size;
-} __attribute__ ((packed));
-
-struct pda_pa_curve_data_sample_rev0 {
- u8 rf_power;
- u8 pa_detector;
- u8 pcv;
-} __attribute__ ((packed));
-
-struct pda_pa_curve_data_sample_rev1 {
- u8 rf_power;
- u8 pa_detector;
- u8 data_barker;
- u8 data_bpsk;
- u8 data_qpsk;
- u8 data_16qam;
- u8 data_64qam;
-} __attribute__ ((packed));
-
-struct p54_pa_curve_data_sample {
- u8 rf_power;
- u8 pa_detector;
- u8 data_barker;
- u8 data_bpsk;
- u8 data_qpsk;
- u8 data_16qam;
- u8 data_64qam;
- u8 padding;
-} __attribute__ ((packed));
-
-struct pda_pa_curve_data {
- u8 cal_method_rev;
- u8 channels;
- u8 points_per_channel;
- u8 padding;
- u8 data[0];
-} __attribute__ ((packed));
-
-struct pda_rssi_cal_entry {
- __le16 mul;
- __le16 add;
-} __attribute__ ((packed));
-
-struct pda_country {
- u8 regdomain;
- u8 alpha2[2];
- u8 flags;
-} __attribute__ ((packed));
-
-/*
- * Warning: Longbow's structures are bogus.
- */
-struct p54_channel_output_limit_longbow {
- __le16 rf_power_points[12];
-} __attribute__ ((packed));
-
-struct p54_pa_curve_data_sample_longbow {
- __le16 rf_power;
- __le16 pa_detector;
- struct {
- __le16 data[4];
- } points[3] __attribute__ ((packed));
-} __attribute__ ((packed));
-
-struct pda_custom_wrapper {
- __le16 entries;
- __le16 entry_size;
- __le16 offset;
- __le16 len;
- u8 data[0];
-} __attribute__ ((packed));
-
-/*
- * this defines the PDR codes used to build PDAs as defined in document
- * number 553155. The current implementation mirrors version 1.1 of the
- * document and lists only PDRs supported by the ARM platform.
- */
-
-/* common and choice range (0x0000 - 0x0fff) */
-#define PDR_END 0x0000
-#define PDR_MANUFACTURING_PART_NUMBER 0x0001
-#define PDR_PDA_VERSION 0x0002
-#define PDR_NIC_SERIAL_NUMBER 0x0003
-
-#define PDR_MAC_ADDRESS 0x0101
-#define PDR_REGULATORY_DOMAIN_LIST 0x0103
-#define PDR_TEMPERATURE_TYPE 0x0107
-
-#define PDR_PRISM_PCI_IDENTIFIER 0x0402
-
-/* ARM range (0x1000 - 0x1fff) */
-#define PDR_COUNTRY_INFORMATION 0x1000
-#define PDR_INTERFACE_LIST 0x1001
-#define PDR_HARDWARE_PLATFORM_COMPONENT_ID 0x1002
-#define PDR_OEM_NAME 0x1003
-#define PDR_PRODUCT_NAME 0x1004
-#define PDR_UTF8_OEM_NAME 0x1005
-#define PDR_UTF8_PRODUCT_NAME 0x1006
-#define PDR_COUNTRY_LIST 0x1007
-#define PDR_DEFAULT_COUNTRY 0x1008
-
-#define PDR_ANTENNA_GAIN 0x1100
-
-#define PDR_PRISM_INDIGO_PA_CALIBRATION_DATA 0x1901
-#define PDR_RSSI_LINEAR_APPROXIMATION 0x1902
-#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS 0x1903
-#define PDR_PRISM_PA_CAL_CURVE_DATA 0x1904
-#define PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND 0x1905
-#define PDR_PRISM_ZIF_TX_IQ_CALIBRATION 0x1906
-#define PDR_REGULATORY_POWER_LIMITS 0x1907
-#define PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED 0x1908
-#define PDR_RADIATED_TRANSMISSION_CORRECTION 0x1909
-#define PDR_PRISM_TX_IQ_CALIBRATION 0x190a
-
-/* reserved range (0x2000 - 0x7fff) */
-
-/* customer range (0x8000 - 0xffff) */
-#define PDR_BASEBAND_REGISTERS 0x8000
-#define PDR_PER_CHANNEL_BASEBAND_REGISTERS 0x8001
-
-/* used by our modificated eeprom image */
-#define PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM 0xDEAD
-#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM 0xBEEF
-#define PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM 0xB05D
-
-/* PDR definitions for default country & country list */
-#define PDR_COUNTRY_CERT_CODE 0x80
-#define PDR_COUNTRY_CERT_CODE_REAL 0x00
-#define PDR_COUNTRY_CERT_CODE_PSEUDO 0x80
-#define PDR_COUNTRY_CERT_BAND 0x40
-#define PDR_COUNTRY_CERT_BAND_2GHZ 0x00
-#define PDR_COUNTRY_CERT_BAND_5GHZ 0x40
-#define PDR_COUNTRY_CERT_IODOOR 0x30
-#define PDR_COUNTRY_CERT_IODOOR_BOTH 0x00
-#define PDR_COUNTRY_CERT_IODOOR_INDOOR 0x20
-#define PDR_COUNTRY_CERT_IODOOR_OUTDOOR 0x30
-#define PDR_COUNTRY_CERT_INDEX 0x0F
-
-struct p54_eeprom_lm86 {
- union {
- struct {
- __le16 offset;
- __le16 len;
- u8 data[0];
- } v1;
- struct {
- __le32 offset;
- __le16 len;
- u8 magic2;
- u8 pad;
- u8 magic[4];
- u8 data[0];
- } v2;
- } __attribute__ ((packed));
-} __attribute__ ((packed));
-
-enum p54_rx_decrypt_status {
- P54_DECRYPT_NONE = 0,
- P54_DECRYPT_OK,
- P54_DECRYPT_NOKEY,
- P54_DECRYPT_NOMICHAEL,
- P54_DECRYPT_NOCKIPMIC,
- P54_DECRYPT_FAIL_WEP,
- P54_DECRYPT_FAIL_TKIP,
- P54_DECRYPT_FAIL_MICHAEL,
- P54_DECRYPT_FAIL_CKIPKP,
- P54_DECRYPT_FAIL_CKIPMIC,
- P54_DECRYPT_FAIL_AESCCMP
-};
-
-struct p54_rx_data {
- __le16 flags;
- __le16 len;
- __le16 freq;
- u8 antenna;
- u8 rate;
- u8 rssi;
- u8 quality;
- u8 decrypt_status;
- u8 rssi_raw;
- __le32 tsf32;
- __le32 unalloc0;
- u8 align[0];
-} __attribute__ ((packed));
-
-enum p54_trap_type {
- P54_TRAP_SCAN = 0,
- P54_TRAP_TIMER,
- P54_TRAP_BEACON_TX,
- P54_TRAP_FAA_RADIO_ON,
- P54_TRAP_FAA_RADIO_OFF,
- P54_TRAP_RADAR,
- P54_TRAP_NO_BEACON,
- P54_TRAP_TBTT,
- P54_TRAP_SCO_ENTER,
- P54_TRAP_SCO_EXIT
-};
-
-struct p54_trap {
- __le16 event;
- __le16 frequency;
-} __attribute__ ((packed));
-
-enum p54_frame_sent_status {
- P54_TX_OK = 0,
- P54_TX_FAILED,
- P54_TX_PSM,
- P54_TX_PSM_CANCELLED = 4
-};
-
-struct p54_frame_sent {
- u8 status;
- u8 tries;
- u8 ack_rssi;
- u8 quality;
- __le16 seq;
- u8 antenna;
- u8 padding;
-} __attribute__ ((packed));
-
-enum p54_tx_data_crypt {
- P54_CRYPTO_NONE = 0,
- P54_CRYPTO_WEP,
- P54_CRYPTO_TKIP,
- P54_CRYPTO_TKIPMICHAEL,
- P54_CRYPTO_CCX_WEPMIC,
- P54_CRYPTO_CCX_KPMIC,
- P54_CRYPTO_CCX_KP,
- P54_CRYPTO_AESCCMP
-};
-
-enum p54_tx_data_queue {
- P54_QUEUE_BEACON = 0,
- P54_QUEUE_FWSCAN = 1,
- P54_QUEUE_MGMT = 2,
- P54_QUEUE_CAB = 3,
- P54_QUEUE_DATA = 4,
-
- P54_QUEUE_AC_NUM = 4,
- P54_QUEUE_AC_VO = 4,
- P54_QUEUE_AC_VI = 5,
- P54_QUEUE_AC_BE = 6,
- P54_QUEUE_AC_BK = 7,
-
- /* keep last */
- P54_QUEUE_NUM = 8,
-};
-
-struct p54_tx_data {
- u8 rateset[8];
- u8 rts_rate_idx;
- u8 crypt_offset;
- u8 key_type;
- u8 key_len;
- u8 key[16];
- u8 hw_queue;
- u8 backlog;
- __le16 durations[4];
- u8 tx_antenna;
- union {
- struct {
- u8 cts_rate;
- __le16 output_power;
- } __attribute__((packed)) longbow;
- struct {
- u8 output_power;
- u8 cts_rate;
- u8 unalloc;
- } __attribute__ ((packed)) normal;
- } __attribute__ ((packed));
- u8 unalloc2[2];
- u8 align[0];
-} __attribute__ ((packed));
-
-/* unit is ms */
-#define P54_TX_FRAME_LIFETIME 2000
-#define P54_TX_TIMEOUT 4000
-#define P54_STATISTICS_UPDATE 5000
-
-#define P54_FILTER_TYPE_NONE 0
-#define P54_FILTER_TYPE_STATION BIT(0)
-#define P54_FILTER_TYPE_IBSS BIT(1)
-#define P54_FILTER_TYPE_AP BIT(2)
-#define P54_FILTER_TYPE_TRANSPARENT BIT(3)
-#define P54_FILTER_TYPE_PROMISCUOUS BIT(4)
-#define P54_FILTER_TYPE_HIBERNATE BIT(5)
-#define P54_FILTER_TYPE_NOACK BIT(6)
-#define P54_FILTER_TYPE_RX_DISABLED BIT(7)
-
-struct p54_setup_mac {
- __le16 mac_mode;
- u8 mac_addr[ETH_ALEN];
- u8 bssid[ETH_ALEN];
- u8 rx_antenna;
- u8 rx_align;
- union {
- struct {
- __le32 basic_rate_mask;
- u8 rts_rates[8];
- __le32 rx_addr;
- __le16 max_rx;
- __le16 rxhw;
- __le16 wakeup_timer;
- __le16 unalloc0;
- } v1 __attribute__ ((packed));
- struct {
- __le32 rx_addr;
- __le16 max_rx;
- __le16 rxhw;
- __le16 timer;
- __le16 truncate;
- __le32 basic_rate_mask;
- u8 sbss_offset;
- u8 mcast_window;
- u8 rx_rssi_threshold;
- u8 rx_ed_threshold;
- __le32 ref_clock;
- __le16 lpf_bandwidth;
- __le16 osc_start_delay;
- } v2 __attribute__ ((packed));
- } __attribute__ ((packed));
-} __attribute__ ((packed));
-
-#define P54_SETUP_V1_LEN 40
-#define P54_SETUP_V2_LEN (sizeof(struct p54_setup_mac))
-
-#define P54_SCAN_EXIT BIT(0)
-#define P54_SCAN_TRAP BIT(1)
-#define P54_SCAN_ACTIVE BIT(2)
-#define P54_SCAN_FILTER BIT(3)
-
-struct p54_scan_head {
- __le16 mode;
- __le16 dwell;
- u8 scan_params[20];
- __le16 freq;
-} __attribute__ ((packed));
-
-struct p54_scan_body {
- u8 pa_points_per_curve;
- u8 val_barker;
- u8 val_bpsk;
- u8 val_qpsk;
- u8 val_16qam;
- u8 val_64qam;
- struct p54_pa_curve_data_sample curve_data[8];
- u8 dup_bpsk;
- u8 dup_qpsk;
- u8 dup_16qam;
- u8 dup_64qam;
-} __attribute__ ((packed));
-
-struct p54_scan_body_longbow {
- struct p54_channel_output_limit_longbow power_limits;
- struct p54_pa_curve_data_sample_longbow curve_data[8];
- __le16 unkn[6]; /* maybe more power_limits or rate_mask */
-} __attribute__ ((packed));
-
-union p54_scan_body_union {
- struct p54_scan_body normal;
- struct p54_scan_body_longbow longbow;
-} __attribute__ ((packed));
-
-struct p54_scan_tail_rate {
- __le32 basic_rate_mask;
- u8 rts_rates[8];
-} __attribute__ ((packed));
-
-struct p54_led {
- __le16 flags;
- __le16 mask[2];
- __le16 delay[2];
-} __attribute__ ((packed));
-
-struct p54_edcf {
- u8 flags;
- u8 slottime;
- u8 sifs;
- u8 eofpad;
- struct p54_edcf_queue_param queue[8];
- u8 mapping[4];
- __le16 frameburst;
- __le16 round_trip_delay;
-} __attribute__ ((packed));
-
-struct p54_statistics {
- __le32 rx_success;
- __le32 rx_bad_fcs;
- __le32 rx_abort;
- __le32 rx_abort_phy;
- __le32 rts_success;
- __le32 rts_fail;
- __le32 tsf32;
- __le32 airtime;
- __le32 noise;
- __le32 sample_noise[8];
- __le32 sample_cca;
- __le32 sample_tx;
-} __attribute__ ((packed));
-
-struct p54_xbow_synth {
- __le16 magic1;
- __le16 magic2;
- __le16 freq;
- u32 padding[5];
-} __attribute__ ((packed));
-
-struct p54_timer {
- __le32 interval;
-} __attribute__ ((packed));
-
-struct p54_keycache {
- u8 entry;
- u8 key_id;
- u8 mac[ETH_ALEN];
- u8 padding[2];
- u8 key_type;
- u8 key_len;
- u8 key[24];
-} __attribute__ ((packed));
-
-struct p54_burst {
- u8 flags;
- u8 queue;
- u8 backlog;
- u8 pad;
- __le16 durations[32];
-} __attribute__ ((packed));
-
-struct p54_psm_interval {
- __le16 interval;
- __le16 periods;
-} __attribute__ ((packed));
-
-#define P54_PSM_CAM 0
-#define P54_PSM BIT(0)
-#define P54_PSM_DTIM BIT(1)
-#define P54_PSM_MCBC BIT(2)
-#define P54_PSM_CHECKSUM BIT(3)
-#define P54_PSM_SKIP_MORE_DATA BIT(4)
-#define P54_PSM_BEACON_TIMEOUT BIT(5)
-#define P54_PSM_HFOSLEEP BIT(6)
-#define P54_PSM_AUTOSWITCH_SLEEP BIT(7)
-#define P54_PSM_LPIT BIT(8)
-#define P54_PSM_BF_UCAST_SKIP BIT(9)
-#define P54_PSM_BF_MCAST_SKIP BIT(10)
-
-struct p54_psm {
- __le16 mode;
- __le16 aid;
- struct p54_psm_interval intervals[4];
- u8 beacon_rssi_skip_max;
- u8 rssi_delta_threshold;
- u8 nr;
- u8 exclude[1];
-} __attribute__ ((packed));
-
-#define MC_FILTER_ADDRESS_NUM 4
-
-struct p54_group_address_table {
- __le16 filter_enable;
- __le16 num_address;
- u8 mac_list[MC_FILTER_ADDRESS_NUM][ETH_ALEN];
-} __attribute__ ((packed));
-
-struct p54_txcancel {
- __le32 req_id;
-} __attribute__ ((packed));
-
-struct p54_sta_unlock {
- u8 addr[ETH_ALEN];
- u16 padding;
-} __attribute__ ((packed));
-
-#define P54_TIM_CLEAR BIT(15)
-struct p54_tim {
- u8 count;
- u8 padding[3];
- __le16 entry[8];
-} __attribute__ ((packed));
-
-struct p54_cce_quiet {
- __le32 period;
-} __attribute__ ((packed));
-
-struct p54_bt_balancer {
- __le16 prio_thresh;
- __le16 acl_thresh;
-} __attribute__ ((packed));
-
-struct p54_arp_table {
- __le16 filter_enable;
- u8 ipv4_addr[4];
-} __attribute__ ((packed));
-
-#endif /* P54COMMON_H */
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index b1610ea4bb3d..d348c265e867 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -22,6 +22,7 @@
#include <net/mac80211.h>
#include "p54.h"
+#include "lmac.h"
#include "p54pci.h"
MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
@@ -564,7 +565,6 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
err_free_common:
release_firmware(priv->firmware);
- p54_free_common(dev);
pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma);
@@ -573,7 +573,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
err_free_dev:
pci_set_drvdata(pdev, NULL);
- ieee80211_free_hw(dev);
+ p54_free_common(dev);
err_free_reg:
pci_release_regions(pdev);
@@ -590,16 +590,15 @@ static void __devexit p54p_remove(struct pci_dev *pdev)
if (!dev)
return;
- ieee80211_unregister_hw(dev);
+ p54_unregister_common(dev);
priv = dev->priv;
release_firmware(priv->firmware);
pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma);
- p54_free_common(dev);
iounmap(priv->map);
pci_release_regions(pdev);
pci_disable_device(pdev);
- ieee80211_free_hw(dev);
+ p54_free_common(dev);
}
#ifdef CONFIG_PM
diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c
index 72c7dbd39d0a..eef532987d05 100644
--- a/drivers/net/wireless/p54/p54spi.c
+++ b/drivers/net/wireless/p54/p54spi.c
@@ -34,7 +34,7 @@
#include "p54spi_eeprom.h"
#include "p54.h"
-#include "p54common.h"
+#include "lmac.h"
MODULE_FIRMWARE("3826.arm");
MODULE_ALIAS("stlc45xx");
@@ -111,15 +111,6 @@ static void p54spi_spi_write(struct p54s_priv *priv, u8 address,
spi_sync(priv->spi, &m);
}
-static u16 p54spi_read16(struct p54s_priv *priv, u8 addr)
-{
- __le16 val;
-
- p54spi_spi_read(priv, addr, &val, sizeof(val));
-
- return le16_to_cpu(val);
-}
-
static u32 p54spi_read32(struct p54s_priv *priv, u8 addr)
{
__le32 val;
@@ -139,37 +130,12 @@ static inline void p54spi_write32(struct p54s_priv *priv, u8 addr, __le32 val)
p54spi_spi_write(priv, addr, &val, sizeof(val));
}
-struct p54spi_spi_reg {
- u16 address; /* __le16 ? */
- u16 length;
- char *name;
-};
-
-static const struct p54spi_spi_reg p54spi_registers_array[] =
-{
- { SPI_ADRS_ARM_INTERRUPTS, 32, "ARM_INT " },
- { SPI_ADRS_ARM_INT_EN, 32, "ARM_INT_ENA " },
- { SPI_ADRS_HOST_INTERRUPTS, 32, "HOST_INT " },
- { SPI_ADRS_HOST_INT_EN, 32, "HOST_INT_ENA" },
- { SPI_ADRS_HOST_INT_ACK, 32, "HOST_INT_ACK" },
- { SPI_ADRS_GEN_PURP_1, 32, "GP1_COMM " },
- { SPI_ADRS_GEN_PURP_2, 32, "GP2_COMM " },
- { SPI_ADRS_DEV_CTRL_STAT, 32, "DEV_CTRL_STA" },
- { SPI_ADRS_DMA_DATA, 16, "DMA_DATA " },
- { SPI_ADRS_DMA_WRITE_CTRL, 16, "DMA_WR_CTRL " },
- { SPI_ADRS_DMA_WRITE_LEN, 16, "DMA_WR_LEN " },
- { SPI_ADRS_DMA_WRITE_BASE, 32, "DMA_WR_BASE " },
- { SPI_ADRS_DMA_READ_CTRL, 16, "DMA_RD_CTRL " },
- { SPI_ADRS_DMA_READ_LEN, 16, "DMA_RD_LEN " },
- { SPI_ADRS_DMA_WRITE_BASE, 32, "DMA_RD_BASE " }
-};
-
-static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits)
+static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, u32 bits)
{
int i;
for (i = 0; i < 2000; i++) {
- __le32 buffer = p54spi_read32(priv, reg);
+ u32 buffer = p54spi_read32(priv, reg);
if ((buffer & bits) == bits)
return 1;
}
@@ -179,8 +145,7 @@ static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits)
static int p54spi_spi_write_dma(struct p54s_priv *priv, __le32 base,
const void *buf, size_t len)
{
- if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL,
- cpu_to_le32(HOST_ALLOWED))) {
+ if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, HOST_ALLOWED)) {
dev_err(&priv->spi->dev, "spi_write_dma not allowed "
"to DMA write.\n");
return -EAGAIN;
@@ -333,7 +298,7 @@ static int p54spi_wakeup(struct p54s_priv *priv)
/* And wait for the READY interrupt */
if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS,
- cpu_to_le32(SPI_HOST_INT_READY))) {
+ SPI_HOST_INT_READY)) {
dev_err(&priv->spi->dev, "INT_READY timeout\n");
return -EBUSY;
}
@@ -444,7 +409,7 @@ static int p54spi_tx_frame(struct p54s_priv *priv, struct sk_buff *skb)
goto out;
if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS,
- cpu_to_le32(SPI_HOST_INT_WR_READY))) {
+ SPI_HOST_INT_WR_READY)) {
dev_err(&priv->spi->dev, "WR_READY timeout\n");
ret = -EAGAIN;
goto out;
@@ -713,7 +678,7 @@ static int __devexit p54spi_remove(struct spi_device *spi)
{
struct p54s_priv *priv = dev_get_drvdata(&spi->dev);
- ieee80211_unregister_hw(priv->hw);
+ p54_unregister_common(priv->hw);
free_irq(gpio_to_irq(p54spi_gpio_irq), spi);
@@ -724,7 +689,6 @@ static int __devexit p54spi_remove(struct spi_device *spi)
mutex_destroy(&priv->mutex);
p54_free_common(priv->hw);
- ieee80211_free_hw(priv->hw);
return 0;
}
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index 0e877a104a89..e44460ff149c 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -22,6 +22,7 @@
#include <net/mac80211.h>
#include "p54.h"
+#include "lmac.h"
#include "p54usb.h"
MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
@@ -245,8 +246,10 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
data_urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!data_urb)
+ if (!data_urb) {
+ p54_free_skb(dev, skb);
return;
+ }
hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
@@ -268,27 +271,22 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
{
struct p54u_priv *priv = dev->priv;
- struct urb *int_urb, *data_urb;
+ struct urb *int_urb = NULL, *data_urb = NULL;
struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
- struct net2280_reg_write *reg;
- int err = 0;
+ struct net2280_reg_write *reg = NULL;
+ int err = -ENOMEM;
reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
if (!reg)
- return;
+ goto out;
int_urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!int_urb) {
- kfree(reg);
- return;
- }
+ if (!int_urb)
+ goto out;
data_urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!data_urb) {
- kfree(reg);
- usb_free_urb(int_urb);
- return;
- }
+ if (!data_urb)
+ goto out;
reg->port = cpu_to_le16(NET2280_DEV_U32);
reg->addr = cpu_to_le32(P54U_DEV_BASE);
@@ -303,11 +301,12 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
p54u_tx_dummy_cb, dev);
/*
- * This flag triggers a code path in the USB subsystem that will
- * free what's inside the transfer_buffer after the callback routine
- * has completed.
+ * URB_FREE_BUFFER triggers a code path in the USB subsystem that will
+ * free what is inside the transfer_buffer after the last reference to
+ * the int_urb is dropped.
*/
int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
+ reg = NULL;
usb_fill_bulk_urb(data_urb, priv->udev,
usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
@@ -328,12 +327,12 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
usb_unanchor_urb(data_urb);
goto out;
}
- out:
+out:
usb_free_urb(int_urb);
usb_free_urb(data_urb);
if (err) {
- skb_pull(skb, sizeof(*hdr));
+ kfree(reg);
p54_free_skb(dev, skb);
}
}
@@ -961,7 +960,7 @@ err_free_fw:
release_firmware(priv->fw);
err_free_dev:
- ieee80211_free_hw(dev);
+ p54_free_common(dev);
usb_set_intfdata(intf, NULL);
usb_put_dev(udev);
return err;
@@ -975,13 +974,12 @@ static void __devexit p54u_disconnect(struct usb_interface *intf)
if (!dev)
return;
- ieee80211_unregister_hw(dev);
+ p54_unregister_common(dev);
priv = dev->priv;
usb_put_dev(interface_to_usbdev(intf));
release_firmware(priv->fw);
p54_free_common(dev);
- ieee80211_free_hw(dev);
}
static int p54u_pre_reset(struct usb_interface *intf)
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
new file mode 100644
index 000000000000..0d589d68e547
--- /dev/null
+++ b/drivers/net/wireless/p54/txrx.c
@@ -0,0 +1,860 @@
+/*
+ * Common code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * 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/init.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "lmac.h"
+
+#ifdef P54_MM_DEBUG
+static void p54_dump_tx_queue(struct p54_common *priv)
+{
+ unsigned long flags;
+ struct ieee80211_tx_info *info;
+ struct p54_tx_info *range;
+ struct sk_buff *skb;
+ struct p54_hdr *hdr;
+ unsigned int i = 0;
+ u32 prev_addr;
+ u32 largest_hole = 0, free;
+
+ spin_lock_irqsave(&priv->tx_queue.lock, flags);
+ 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;
+ skb_queue_walk(&priv->tx_queue, skb) {
+ info = IEEE80211_SKB_CB(skb);
+ range = (void *) info->rate_driver_data;
+ hdr = (void *) skb->data;
+
+ free = range->start_addr - prev_addr;
+ printk(KERN_DEBUG "%s: | [%02d] => [skb:%p skb_len:0x%04x "
+ "hdr:{flags:%02x len:%04x req_id:%04x type:%02x} "
+ "mem:{start:%04x end:%04x, free:%d}]\n",
+ wiphy_name(priv->hw->wiphy), i++, skb, skb->len,
+ le16_to_cpu(hdr->flags), le16_to_cpu(hdr->len),
+ le32_to_cpu(hdr->req_id), le16_to_cpu(hdr->type),
+ range->start_addr, range->end_addr, free);
+
+ prev_addr = range->end_addr;
+ largest_hole = max(largest_hole, free);
+ }
+ free = priv->rx_end - prev_addr;
+ largest_hole = max(largest_hole, free);
+ printk(KERN_DEBUG "%s: \\ --- [free: %d], largest free block: %d ---\n",
+ wiphy_name(priv->hw->wiphy), free, largest_hole);
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+}
+#endif /* P54_MM_DEBUG */
+
+/*
+ * So, the firmware is somewhat stupid and doesn't know what places in its
+ * memory incoming data should go to. By poking around in the firmware, we
+ * can find some unused memory to upload our packets to. However, data that we
+ * want the card to TX needs to stay intact until the card has told us that
+ * it is done with it. This function finds empty places we can upload to and
+ * marks allocated areas as reserved if necessary. p54_find_and_unlink_skb or
+ * p54_free_skb frees allocated areas.
+ */
+static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct sk_buff *entry, *target_skb = NULL;
+ struct ieee80211_tx_info *info;
+ struct p54_tx_info *range;
+ struct p54_hdr *data = (void *) skb->data;
+ unsigned long flags;
+ u32 last_addr = priv->rx_start;
+ u32 target_addr = priv->rx_start;
+ u16 len = priv->headroom + skb->len + priv->tailroom + 3;
+
+ info = IEEE80211_SKB_CB(skb);
+ range = (void *) info->rate_driver_data;
+ len = (range->extra_len + len) & ~0x3;
+
+ spin_lock_irqsave(&priv->tx_queue.lock, flags);
+ if (unlikely(skb_queue_len(&priv->tx_queue) == 32)) {
+ /*
+ * The tx_queue is now really full.
+ *
+ * TODO: check if the device has crashed and reset it.
+ */
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ return -EBUSY;
+ }
+
+ skb_queue_walk(&priv->tx_queue, entry) {
+ u32 hole_size;
+ info = IEEE80211_SKB_CB(entry);
+ range = (void *) info->rate_driver_data;
+ hole_size = range->start_addr - last_addr;
+
+ if (!target_skb && hole_size >= len) {
+ target_skb = entry->prev;
+ hole_size -= len;
+ target_addr = last_addr;
+ break;
+ }
+ last_addr = range->end_addr;
+ }
+ if (unlikely(!target_skb)) {
+ if (priv->rx_end - last_addr >= len) {
+ target_skb = priv->tx_queue.prev;
+ if (!skb_queue_empty(&priv->tx_queue)) {
+ info = IEEE80211_SKB_CB(target_skb);
+ range = (void *)info->rate_driver_data;
+ target_addr = range->end_addr;
+ }
+ } else {
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ return -ENOSPC;
+ }
+ }
+
+ info = IEEE80211_SKB_CB(skb);
+ range = (void *) info->rate_driver_data;
+ range->start_addr = target_addr;
+ range->end_addr = target_addr + len;
+ data->req_id = cpu_to_le32(target_addr + priv->headroom);
+ if (IS_DATA_FRAME(skb) &&
+ unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON))
+ priv->beacon_req_id = data->req_id;
+
+ __skb_queue_after(&priv->tx_queue, target_skb, skb);
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ return 0;
+}
+
+static void p54_tx_pending(struct p54_common *priv)
+{
+ struct sk_buff *skb;
+ int ret;
+
+ skb = skb_dequeue(&priv->tx_pending);
+ if (unlikely(!skb))
+ return ;
+
+ ret = p54_assign_address(priv, skb);
+ if (unlikely(ret))
+ skb_queue_head(&priv->tx_pending, skb);
+ else
+ priv->tx(priv->hw, skb);
+}
+
+static void p54_wake_queues(struct p54_common *priv)
+{
+ unsigned long flags;
+ unsigned int i;
+
+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+ return ;
+
+ p54_tx_pending(priv);
+
+ spin_lock_irqsave(&priv->tx_stats_lock, flags);
+ for (i = 0; i < priv->hw->queues; i++) {
+ if (priv->tx_stats[i + P54_QUEUE_DATA].len <
+ priv->tx_stats[i + P54_QUEUE_DATA].limit)
+ ieee80211_wake_queue(priv->hw, i);
+ }
+ spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+}
+
+static int p54_tx_qos_accounting_alloc(struct p54_common *priv,
+ struct sk_buff *skb,
+ const u16 p54_queue)
+{
+ struct ieee80211_tx_queue_stats *queue;
+ unsigned long flags;
+
+ if (WARN_ON(p54_queue > P54_QUEUE_NUM))
+ return -EINVAL;
+
+ queue = &priv->tx_stats[p54_queue];
+
+ spin_lock_irqsave(&priv->tx_stats_lock, flags);
+ if (unlikely(queue->len >= queue->limit && IS_QOS_QUEUE(p54_queue))) {
+ spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+ return -ENOSPC;
+ }
+
+ queue->len++;
+ queue->count++;
+
+ if (unlikely(queue->len == queue->limit && IS_QOS_QUEUE(p54_queue))) {
+ u16 ac_queue = p54_queue - P54_QUEUE_DATA;
+ ieee80211_stop_queue(priv->hw, ac_queue);
+ }
+
+ spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+ return 0;
+}
+
+static void p54_tx_qos_accounting_free(struct p54_common *priv,
+ struct sk_buff *skb)
+{
+ if (IS_DATA_FRAME(skb)) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->tx_stats_lock, flags);
+ priv->tx_stats[GET_HW_QUEUE(skb)].len--;
+ spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+
+ if (unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON)) {
+ if (priv->beacon_req_id == GET_REQ_ID(skb)) {
+ /* this is the active beacon set anymore */
+ priv->beacon_req_id = 0;
+ }
+ complete(&priv->beacon_comp);
+ }
+ }
+ p54_wake_queues(priv);
+}
+
+void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+ struct p54_common *priv = dev->priv;
+ if (unlikely(!skb))
+ return ;
+
+ skb_unlink(skb, &priv->tx_queue);
+ p54_tx_qos_accounting_free(priv, skb);
+ dev_kfree_skb_any(skb);
+}
+EXPORT_SYMBOL_GPL(p54_free_skb);
+
+static struct sk_buff *p54_find_and_unlink_skb(struct p54_common *priv,
+ const __le32 req_id)
+{
+ struct sk_buff *entry;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->tx_queue.lock, flags);
+ skb_queue_walk(&priv->tx_queue, entry) {
+ struct p54_hdr *hdr = (struct p54_hdr *) entry->data;
+
+ if (hdr->req_id == req_id) {
+ __skb_unlink(entry, &priv->tx_queue);
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ p54_tx_qos_accounting_free(priv, entry);
+ return entry;
+ }
+ }
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ return NULL;
+}
+
+void p54_tx(struct p54_common *priv, struct sk_buff *skb)
+{
+ skb_queue_tail(&priv->tx_pending, skb);
+ p54_tx_pending(priv);
+}
+
+static int p54_rssi_to_dbm(struct p54_common *priv, int rssi)
+{
+ int band = priv->hw->conf.channel->band;
+
+ if (priv->rxhw != 5)
+ return ((rssi * priv->rssical_db[band].mul) / 64 +
+ priv->rssical_db[band].add) / 4;
+ else
+ /*
+ * TODO: find the correct formula
+ */
+ return ((rssi * priv->rssical_db[band].mul) / 64 +
+ priv->rssical_db[band].add) / 4;
+}
+
+/*
+ * Even if the firmware is capable of dealing with incoming traffic,
+ * while dozing, we have to prepared in case mac80211 uses PS-POLL
+ * to retrieve outstanding frames from our AP.
+ * (see comment in net/mac80211/mlme.c @ line 1993)
+ */
+static void p54_pspoll_workaround(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr = (void *) skb->data;
+ struct ieee80211_tim_ie *tim_ie;
+ u8 *tim;
+ u8 tim_len;
+ bool new_psm;
+
+ /* only beacons have a TIM IE */
+ if (!ieee80211_is_beacon(hdr->frame_control))
+ return;
+
+ if (!priv->aid)
+ return;
+
+ /* only consider beacons from the associated BSSID */
+ if (compare_ether_addr(hdr->addr3, priv->bssid))
+ return;
+
+ tim = p54_find_ie(skb, WLAN_EID_TIM);
+ if (!tim)
+ return;
+
+ tim_len = tim[1];
+ tim_ie = (struct ieee80211_tim_ie *) &tim[2];
+
+ new_psm = ieee80211_check_tim(tim_ie, tim_len, priv->aid);
+ if (new_psm != priv->powersave_override) {
+ priv->powersave_override = new_psm;
+ p54_set_ps(priv);
+ }
+}
+
+static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data;
+ struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
+ u16 freq = le16_to_cpu(hdr->freq);
+ size_t header_len = sizeof(*hdr);
+ u32 tsf32;
+ u8 rate = hdr->rate & 0xf;
+
+ /*
+ * If the device is in a unspecified state we have to
+ * ignore all data frames. Else we could end up with a
+ * nasty crash.
+ */
+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+ return 0;
+
+ if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD)))
+ return 0;
+
+ if (hdr->decrypt_status == P54_DECRYPT_OK)
+ rx_status->flag |= RX_FLAG_DECRYPTED;
+ if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) ||
+ (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP))
+ 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)
+ rx_status->rate_idx = (rate < 4) ? 0 : rate - 4;
+ else
+ rx_status->rate_idx = rate;
+
+ rx_status->freq = freq;
+ rx_status->band = priv->hw->conf.channel->band;
+ rx_status->antenna = hdr->antenna;
+
+ tsf32 = le32_to_cpu(hdr->tsf32);
+ if (tsf32 < priv->tsf_low32)
+ priv->tsf_high32++;
+ rx_status->mactime = ((u64)priv->tsf_high32) << 32 | tsf32;
+ priv->tsf_low32 = tsf32;
+
+ rx_status->flag |= RX_FLAG_TSFT;
+
+ if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
+ header_len += hdr->align[0];
+
+ skb_pull(skb, header_len);
+ skb_trim(skb, le16_to_cpu(hdr->len));
+ if (unlikely(priv->hw->conf.flags & IEEE80211_CONF_PS))
+ p54_pspoll_workaround(priv, skb);
+
+ ieee80211_rx_irqsafe(priv->hw, skb);
+
+ queue_delayed_work(priv->hw->workqueue, &priv->work,
+ msecs_to_jiffies(P54_STATISTICS_UPDATE));
+
+ return -1;
+}
+
+static void p54_rx_frame_sent(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+ struct p54_frame_sent *payload = (struct p54_frame_sent *) hdr->data;
+ struct ieee80211_tx_info *info;
+ struct p54_hdr *entry_hdr;
+ struct p54_tx_data *entry_data;
+ struct sk_buff *entry;
+ unsigned int pad = 0, frame_len;
+ int count, idx;
+
+ entry = p54_find_and_unlink_skb(priv, hdr->req_id);
+ if (unlikely(!entry))
+ return ;
+
+ frame_len = entry->len;
+ info = IEEE80211_SKB_CB(entry);
+ entry_hdr = (struct p54_hdr *) entry->data;
+ entry_data = (struct p54_tx_data *) entry_hdr->data;
+ priv->stats.dot11ACKFailureCount += payload->tries - 1;
+
+ /*
+ * Frames in P54_QUEUE_FWSCAN and P54_QUEUE_BEACON are
+ * generated by the driver. Therefore tx_status is bogus
+ * and we don't want to confuse the mac80211 stack.
+ */
+ if (unlikely(entry_data->hw_queue < P54_QUEUE_FWSCAN)) {
+ dev_kfree_skb_any(entry);
+ return ;
+ }
+
+ /*
+ * Clear manually, ieee80211_tx_info_clear_status would
+ * clear the counts too and we need them.
+ */
+ memset(&info->status.ampdu_ack_len, 0,
+ sizeof(struct ieee80211_tx_info) -
+ offsetof(struct ieee80211_tx_info, status.ampdu_ack_len));
+ BUILD_BUG_ON(offsetof(struct ieee80211_tx_info,
+ status.ampdu_ack_len) != 23);
+
+ if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
+ pad = entry_data->align[0];
+
+ /* walk through the rates array and adjust the counts */
+ count = payload->tries;
+ for (idx = 0; idx < 4; idx++) {
+ if (count >= info->status.rates[idx].count) {
+ count -= info->status.rates[idx].count;
+ } else if (count > 0) {
+ info->status.rates[idx].count = count;
+ count = 0;
+ } else {
+ info->status.rates[idx].idx = -1;
+ info->status.rates[idx].count = 0;
+ }
+ }
+
+ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+ (!payload->status))
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ if (payload->status & P54_TX_PSM_CANCELLED)
+ info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+ info->status.ack_signal = p54_rssi_to_dbm(priv,
+ (int)payload->ack_rssi);
+
+ /* Undo all changes to the frame. */
+ switch (entry_data->key_type) {
+ case P54_CRYPTO_TKIPMICHAEL: {
+ u8 *iv = (u8 *)(entry_data->align + pad +
+ entry_data->crypt_offset);
+
+ /* Restore the original TKIP IV. */
+ iv[2] = iv[0];
+ iv[0] = iv[1];
+ iv[1] = (iv[0] | 0x20) & 0x7f; /* WEPSeed - 8.3.2.2 */
+
+ frame_len -= 12; /* remove TKIP_MMIC + TKIP_ICV */
+ break;
+ }
+ case P54_CRYPTO_AESCCMP:
+ frame_len -= 8; /* remove CCMP_MIC */
+ break;
+ case P54_CRYPTO_WEP:
+ frame_len -= 4; /* remove WEP_ICV */
+ break;
+ }
+
+ skb_trim(entry, frame_len);
+ skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
+ ieee80211_tx_status_irqsafe(priv->hw, entry);
+}
+
+static void p54_rx_eeprom_readback(struct p54_common *priv,
+ struct sk_buff *skb)
+{
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+ struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data;
+ struct sk_buff *tmp;
+
+ if (!priv->eeprom)
+ return ;
+
+ if (priv->fw_var >= 0x509) {
+ memcpy(priv->eeprom, eeprom->v2.data,
+ le16_to_cpu(eeprom->v2.len));
+ } else {
+ memcpy(priv->eeprom, eeprom->v1.data,
+ le16_to_cpu(eeprom->v1.len));
+ }
+
+ priv->eeprom = NULL;
+ tmp = p54_find_and_unlink_skb(priv, hdr->req_id);
+ dev_kfree_skb_any(tmp);
+ complete(&priv->eeprom_comp);
+}
+
+static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+ struct p54_statistics *stats = (struct p54_statistics *) hdr->data;
+ struct sk_buff *tmp;
+ u32 tsf32;
+
+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+ return ;
+
+ tsf32 = le32_to_cpu(stats->tsf32);
+ if (tsf32 < priv->tsf_low32)
+ priv->tsf_high32++;
+ priv->tsf_low32 = tsf32;
+
+ priv->stats.dot11RTSFailureCount = le32_to_cpu(stats->rts_fail);
+ priv->stats.dot11RTSSuccessCount = le32_to_cpu(stats->rts_success);
+ priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs);
+
+ priv->noise = p54_rssi_to_dbm(priv, le32_to_cpu(stats->noise));
+
+ tmp = p54_find_and_unlink_skb(priv, hdr->req_id);
+ dev_kfree_skb_any(tmp);
+}
+
+static void p54_rx_trap(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+ struct p54_trap *trap = (struct p54_trap *) hdr->data;
+ u16 event = le16_to_cpu(trap->event);
+ u16 freq = le16_to_cpu(trap->frequency);
+
+ switch (event) {
+ case P54_TRAP_BEACON_TX:
+ break;
+ case P54_TRAP_RADAR:
+ printk(KERN_INFO "%s: radar (freq:%d MHz)\n",
+ wiphy_name(priv->hw->wiphy), freq);
+ break;
+ case P54_TRAP_NO_BEACON:
+ if (priv->vif)
+ ieee80211_beacon_loss(priv->vif);
+ break;
+ case P54_TRAP_SCAN:
+ break;
+ case P54_TRAP_TBTT:
+ break;
+ case P54_TRAP_TIMER:
+ break;
+ default:
+ printk(KERN_INFO "%s: received event:%x freq:%d\n",
+ wiphy_name(priv->hw->wiphy), event, freq);
+ break;
+ }
+}
+
+static int p54_rx_control(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+
+ switch (le16_to_cpu(hdr->type)) {
+ case P54_CONTROL_TYPE_TXDONE:
+ p54_rx_frame_sent(priv, skb);
+ break;
+ case P54_CONTROL_TYPE_TRAP:
+ p54_rx_trap(priv, skb);
+ break;
+ case P54_CONTROL_TYPE_BBP:
+ break;
+ case P54_CONTROL_TYPE_STAT_READBACK:
+ p54_rx_stats(priv, skb);
+ break;
+ case P54_CONTROL_TYPE_EEPROM_READBACK:
+ p54_rx_eeprom_readback(priv, skb);
+ break;
+ default:
+ printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n",
+ wiphy_name(priv->hw->wiphy), le16_to_cpu(hdr->type));
+ break;
+ }
+ return 0;
+}
+
+/* returns zero if skb can be reused */
+int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+ struct p54_common *priv = dev->priv;
+ u16 type = le16_to_cpu(*((__le16 *)skb->data));
+
+ if (type & P54_HDR_FLAG_CONTROL)
+ return p54_rx_control(priv, skb);
+ else
+ return p54_rx_data(priv, skb);
+}
+EXPORT_SYMBOL_GPL(p54_rx);
+
+static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb,
+ struct ieee80211_tx_info *info, u8 *queue,
+ u32 *extra_len, u16 *flags, u16 *aid,
+ bool *burst_possible)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+
+ if (ieee80211_is_data_qos(hdr->frame_control))
+ *burst_possible = true;
+ else
+ *burst_possible = false;
+
+ if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
+ *flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
+
+ if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
+ *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
+
+ *queue = skb_get_queue_mapping(skb) + P54_QUEUE_DATA;
+
+ switch (priv->mode) {
+ case NL80211_IFTYPE_MONITOR:
+ /*
+ * We have to set P54_HDR_FLAG_DATA_OUT_PROMISC for
+ * every frame in promiscuous/monitor mode.
+ * see STSW45x0C LMAC API - page 12.
+ */
+ *aid = 0;
+ *flags |= P54_HDR_FLAG_DATA_OUT_PROMISC;
+ break;
+ case NL80211_IFTYPE_STATION:
+ *aid = 1;
+ break;
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_MESH_POINT:
+ if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
+ *aid = 0;
+ *queue = P54_QUEUE_CAB;
+ return;
+ }
+
+ if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
+ if (ieee80211_is_probe_resp(hdr->frame_control)) {
+ *aid = 0;
+ *flags |= P54_HDR_FLAG_DATA_OUT_TIMESTAMP |
+ P54_HDR_FLAG_DATA_OUT_NOCANCEL;
+ return;
+ } else if (ieee80211_is_beacon(hdr->frame_control)) {
+ *aid = 0;
+
+ if (info->flags & IEEE80211_TX_CTL_INJECTED) {
+ /*
+ * Injecting beacons on top of a AP is
+ * not a good idea... nevertheless,
+ * it should be doable.
+ */
+
+ return;
+ }
+
+ *flags |= P54_HDR_FLAG_DATA_OUT_TIMESTAMP;
+ *queue = P54_QUEUE_BEACON;
+ *extra_len = IEEE80211_MAX_TIM_LEN;
+ return;
+ }
+ }
+
+ if (info->control.sta)
+ *aid = info->control.sta->aid;
+ break;
+ }
+}
+
+static u8 p54_convert_algo(enum ieee80211_key_alg alg)
+{
+ switch (alg) {
+ case ALG_WEP:
+ return P54_CRYPTO_WEP;
+ case ALG_TKIP:
+ return P54_CRYPTO_TKIPMICHAEL;
+ case ALG_CCMP:
+ return P54_CRYPTO_AESCCMP;
+ default:
+ return 0;
+ }
+}
+
+int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+ struct p54_common *priv = dev->priv;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct p54_tx_info *p54info;
+ struct p54_hdr *hdr;
+ struct p54_tx_data *txhdr;
+ unsigned int padding, len, extra_len;
+ int i, j, ridx;
+ u16 hdr_flags = 0, aid = 0;
+ u8 rate, queue = 0, crypt_offset = 0;
+ u8 cts_rate = 0x20;
+ u8 rc_flags;
+ u8 calculated_tries[4];
+ u8 nrates = 0, nremaining = 8;
+ bool burst_allowed = false;
+
+ p54_tx_80211_header(priv, skb, info, &queue, &extra_len,
+ &hdr_flags, &aid, &burst_allowed);
+
+ if (p54_tx_qos_accounting_alloc(priv, skb, queue)) {
+ if (!IS_QOS_QUEUE(queue)) {
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ } else {
+ return NETDEV_TX_BUSY;
+ }
+ }
+
+ padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
+ len = skb->len;
+
+ if (info->control.hw_key) {
+ crypt_offset = ieee80211_get_hdrlen_from_skb(skb);
+ if (info->control.hw_key->alg == ALG_TKIP) {
+ u8 *iv = (u8 *)(skb->data + crypt_offset);
+ /*
+ * The firmware excepts that the IV has to have
+ * this special format
+ */
+ iv[1] = iv[0];
+ iv[0] = iv[2];
+ iv[2] = 0;
+ }
+ }
+
+ txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding);
+ hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr));
+
+ if (padding)
+ hdr_flags |= P54_HDR_FLAG_DATA_ALIGN;
+ hdr->type = cpu_to_le16(aid);
+ hdr->rts_tries = info->control.rates[0].count;
+
+ /*
+ * we register the rates in perfect order, and
+ * RTS/CTS won't happen on 5 GHz
+ */
+ cts_rate = info->control.rts_cts_rate_idx;
+
+ memset(&txhdr->rateset, 0, sizeof(txhdr->rateset));
+
+ /* see how many rates got used */
+ for (i = 0; i < dev->max_rates; i++) {
+ if (info->control.rates[i].idx < 0)
+ break;
+ nrates++;
+ }
+
+ /* limit tries to 8/nrates per rate */
+ for (i = 0; i < nrates; i++) {
+ /*
+ * The magic expression here is equivalent to 8/nrates for
+ * all values that matter, but avoids division and jumps.
+ * Note that nrates can only take the values 1 through 4.
+ */
+ calculated_tries[i] = min_t(int, ((15 >> nrates) | 1) + 1,
+ info->control.rates[i].count);
+ nremaining -= calculated_tries[i];
+ }
+
+ /* if there are tries left, distribute from back to front */
+ for (i = nrates - 1; nremaining > 0 && i >= 0; i--) {
+ int tmp = info->control.rates[i].count - calculated_tries[i];
+
+ if (tmp <= 0)
+ continue;
+ /* RC requested more tries at this rate */
+
+ tmp = min_t(int, tmp, nremaining);
+ calculated_tries[i] += tmp;
+ nremaining -= tmp;
+ }
+
+ ridx = 0;
+ for (i = 0; i < nrates && ridx < 8; i++) {
+ /* we register the rates in perfect order */
+ rate = info->control.rates[i].idx;
+ if (info->band == IEEE80211_BAND_5GHZ)
+ rate += 4;
+
+ /* store the count we actually calculated for TX status */
+ info->control.rates[i].count = calculated_tries[i];
+
+ rc_flags = info->control.rates[i].flags;
+ if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) {
+ rate |= 0x10;
+ cts_rate |= 0x10;
+ }
+ if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
+ burst_allowed = false;
+ rate |= 0x40;
+ } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+ rate |= 0x20;
+ burst_allowed = false;
+ }
+ for (j = 0; j < calculated_tries[i] && ridx < 8; j++) {
+ txhdr->rateset[ridx] = rate;
+ ridx++;
+ }
+ }
+
+ if (burst_allowed)
+ hdr_flags |= P54_HDR_FLAG_DATA_OUT_BURST;
+
+ /* TODO: enable bursting */
+ hdr->flags = cpu_to_le16(hdr_flags);
+ hdr->tries = ridx;
+ txhdr->rts_rate_idx = 0;
+ if (info->control.hw_key) {
+ txhdr->key_type = p54_convert_algo(info->control.hw_key->alg);
+ txhdr->key_len = min((u8)16, info->control.hw_key->keylen);
+ memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len);
+ if (info->control.hw_key->alg == ALG_TKIP) {
+ /* reserve space for the MIC key */
+ len += 8;
+ memcpy(skb_put(skb, 8), &(info->control.hw_key->key
+ [NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8);
+ }
+ /* reserve some space for ICV */
+ len += info->control.hw_key->icv_len;
+ memset(skb_put(skb, info->control.hw_key->icv_len), 0,
+ info->control.hw_key->icv_len);
+ } else {
+ txhdr->key_type = 0;
+ txhdr->key_len = 0;
+ }
+ txhdr->crypt_offset = crypt_offset;
+ txhdr->hw_queue = queue;
+ txhdr->backlog = priv->tx_stats[queue].len - 1;
+ memset(txhdr->durations, 0, sizeof(txhdr->durations));
+ txhdr->tx_antenna = ((info->antenna_sel_tx == 0) ?
+ 2 : info->antenna_sel_tx - 1) & priv->tx_diversity_mask;
+ if (priv->rxhw == 5) {
+ txhdr->longbow.cts_rate = cts_rate;
+ txhdr->longbow.output_power = cpu_to_le16(priv->output_power);
+ } else {
+ txhdr->normal.output_power = priv->output_power;
+ txhdr->normal.cts_rate = cts_rate;
+ }
+ if (padding)
+ txhdr->align[0] = padding;
+
+ hdr->len = cpu_to_le16(len);
+ /* modifies skb->cb and with it info, so must be last! */
+ p54info = (void *) info->rate_driver_data;
+ p54info->extra_len = extra_len;
+
+ p54_tx(priv, skb);
+ return NETDEV_TX_OK;
+}
diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c
index 8f6210993448..c255d9c6a5f1 100644
--- a/drivers/net/wireless/prism54/islpci_eth.c
+++ b/drivers/net/wireless/prism54/islpci_eth.c
@@ -234,7 +234,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev)
/* unlock the driver code */
spin_unlock_irqrestore(&priv->slock, flags);
- return 0;
+ return NETDEV_TX_OK;
drop_free:
ndev->stats.tx_dropped++;
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
index 30876728d7e6..83d366258c81 100644
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -49,9 +49,7 @@ static const struct pci_device_id prism54_id_tbl[] = {
/* 3COM 3CRWE154G72 Wireless LAN adapter */
{
- 0x10b7, 0x6001,
- PCI_ANY_ID, PCI_ANY_ID,
- 0, 0, 0
+ PCI_VDEVICE(3COM, 0x6001), 0
},
/* Intersil PRISM Indigo Wireless LAN adapter */
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index b10b0383dfa5..64e574c3655c 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -937,7 +937,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
switch (ray_hw_xmit(skb->data, length, dev, DATA_TYPE)) {
@@ -951,9 +951,9 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
default:
dev->trans_start = jiffies;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
- return 0;
+ return NETDEV_TX_OK;
} /* ray_dev_start_xmit */
/*===========================================================================*/
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 3bec3dbd3450..09c0702ae645 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -139,9 +139,15 @@ MODULE_PARM_DESC(workaround_interval,
/* Assume that Broadcom 4320 (only chipset at time of writing known to be
* based on wireless rndis) has default txpower of 13dBm.
* This value is from Linksys WUSB54GSC User Guide, Appendix F: Specifications.
- * 13dBm == 19.9mW
+ * 100% : 20 mW ~ 13dBm
+ * 75% : 15 mW ~ 12dBm
+ * 50% : 10 mW ~ 10dBm
+ * 25% : 5 mW ~ 7dBm
*/
-#define BCM4320_DEFAULT_TXPOWER 20
+#define BCM4320_DEFAULT_TXPOWER_DBM_100 13
+#define BCM4320_DEFAULT_TXPOWER_DBM_75 12
+#define BCM4320_DEFAULT_TXPOWER_DBM_50 10
+#define BCM4320_DEFAULT_TXPOWER_DBM_25 7
/* codes for "status" field of completion messages */
@@ -420,21 +426,30 @@ struct rndis_wlan_private {
/*
* cfg80211 ops
*/
-static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex,
+static int rndis_change_virtual_intf(struct wiphy *wiphy,
+ struct net_device *dev,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params);
static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_scan_request *request);
+static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed);
+
+static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type,
+ int dbm);
+static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm);
+
static struct cfg80211_ops rndis_config_ops = {
.change_virtual_intf = rndis_change_virtual_intf,
.scan = rndis_scan,
+ .set_wiphy_params = rndis_set_wiphy_params,
+ .set_tx_power = rndis_set_tx_power,
+ .get_tx_power = rndis_get_tx_power,
};
static void *rndis_wiphy_privid = &rndis_wiphy_privid;
-static const int bcm4320_power_output[4] = { 25, 50, 75, 100 };
static const unsigned char zero_bssid[ETH_ALEN] = {0,};
static const unsigned char ffff_bssid[ETH_ALEN] = { 0xff, 0xff, 0xff,
@@ -447,10 +462,19 @@ static struct rndis_wlan_private *get_rndis_wlan_priv(struct usbnet *dev)
}
-static u32 get_bcm4320_power(struct rndis_wlan_private *priv)
+static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv)
{
- return BCM4320_DEFAULT_TXPOWER *
- bcm4320_power_output[priv->param_power_output] / 100;
+ switch (priv->param_power_output) {
+ default:
+ case 3:
+ return BCM4320_DEFAULT_TXPOWER_DBM_100;
+ case 2:
+ return BCM4320_DEFAULT_TXPOWER_DBM_75;
+ case 1:
+ return BCM4320_DEFAULT_TXPOWER_DBM_50;
+ case 0:
+ return BCM4320_DEFAULT_TXPOWER_DBM_25;
+ }
}
@@ -968,6 +992,36 @@ static int set_infra_mode(struct usbnet *usbdev, int mode)
}
+static int set_rts_threshold(struct usbnet *usbdev, u32 rts_threshold)
+{
+ __le32 tmp;
+
+ devdbg(usbdev, "set_rts_threshold %i", rts_threshold);
+
+ if (rts_threshold < 0 || rts_threshold > 2347)
+ rts_threshold = 2347;
+
+ tmp = cpu_to_le32(rts_threshold);
+ return rndis_set_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp,
+ sizeof(tmp));
+}
+
+
+static int set_frag_threshold(struct usbnet *usbdev, u32 frag_threshold)
+{
+ __le32 tmp;
+
+ devdbg(usbdev, "set_frag_threshold %i", frag_threshold);
+
+ if (frag_threshold < 256 || frag_threshold > 2346)
+ frag_threshold = 2346;
+
+ tmp = cpu_to_le32(frag_threshold);
+ return rndis_set_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp,
+ sizeof(tmp));
+}
+
+
static void set_default_iw_params(struct usbnet *usbdev)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
@@ -1222,20 +1276,14 @@ static void set_multicast_list(struct usbnet *usbdev)
/*
* cfg80211 ops
*/
-static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex,
+static int rndis_change_virtual_intf(struct wiphy *wiphy,
+ struct net_device *dev,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params)
{
- struct net_device *dev;
- struct usbnet *usbdev;
+ struct usbnet *usbdev = netdev_priv(dev);
int mode;
- /* we're under RTNL */
- dev = __dev_get_by_index(&init_net, ifindex);
- if (!dev)
- return -ENODEV;
- usbdev = netdev_priv(dev);
-
switch (type) {
case NL80211_IFTYPE_ADHOC:
mode = NDIS_80211_INFRA_ADHOC;
@@ -1251,6 +1299,64 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex,
}
+static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+ struct usbnet *usbdev = priv->usbdev;
+ int err;
+
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
+ err = set_frag_threshold(usbdev, wiphy->frag_threshold);
+ if (err < 0)
+ return err;
+ }
+
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
+ err = set_rts_threshold(usbdev, wiphy->rts_threshold);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+
+static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type,
+ int dbm)
+{
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+ struct usbnet *usbdev = priv->usbdev;
+
+ devdbg(usbdev, "rndis_set_tx_power type:0x%x dbm:%i", type, dbm);
+
+ /* Device doesn't support changing txpower after initialization, only
+ * turn off/on radio. Support 'auto' mode and setting same dBm that is
+ * currently used.
+ */
+ if (type == TX_POWER_AUTOMATIC || dbm == get_bcm4320_power_dbm(priv)) {
+ if (!priv->radio_on)
+ disassociate(usbdev, 1); /* turn on radio */
+
+ return 0;
+ }
+
+ return -ENOTSUPP;
+}
+
+
+static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm)
+{
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+ struct usbnet *usbdev = priv->usbdev;
+
+ *dbm = get_bcm4320_power_dbm(priv);
+
+ devdbg(usbdev, "rndis_get_tx_power dbm:%i", *dbm);
+
+ return 0;
+}
+
+
#define SCAN_DELAY_JIFFIES (HZ)
static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_scan_request *request)
@@ -1766,74 +1872,6 @@ static int rndis_iw_get_genie(struct net_device *dev,
}
-static int rndis_iw_set_rts(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- __le32 tmp;
- devdbg(usbdev, "SIOCSIWRTS");
-
- tmp = cpu_to_le32(wrqu->rts.value);
- return rndis_set_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp,
- sizeof(tmp));
-}
-
-
-static int rndis_iw_get_rts(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- __le32 tmp;
- int len, ret;
-
- len = sizeof(tmp);
- ret = rndis_query_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp, &len);
- if (ret == 0) {
- wrqu->rts.value = le32_to_cpu(tmp);
- wrqu->rts.flags = 1;
- wrqu->rts.disabled = 0;
- }
-
- devdbg(usbdev, "SIOCGIWRTS: %d", wrqu->rts.value);
-
- return ret;
-}
-
-
-static int rndis_iw_set_frag(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- __le32 tmp;
-
- devdbg(usbdev, "SIOCSIWFRAG");
-
- tmp = cpu_to_le32(wrqu->frag.value);
- return rndis_set_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp,
- sizeof(tmp));
-}
-
-
-static int rndis_iw_get_frag(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- __le32 tmp;
- int len, ret;
-
- len = sizeof(tmp);
- ret = rndis_query_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp,
- &len);
- if (ret == 0) {
- wrqu->frag.value = le32_to_cpu(tmp);
- wrqu->frag.flags = 1;
- wrqu->frag.disabled = 0;
- }
- devdbg(usbdev, "SIOCGIWFRAG: %d", wrqu->frag.value);
- return ret;
-}
-
-
static int rndis_iw_set_freq(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
@@ -1882,71 +1920,6 @@ static int rndis_iw_get_freq(struct net_device *dev,
}
-static int rndis_iw_get_txpower(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- __le32 tx_power;
-
- if (priv->radio_on) {
- /* fake since changing tx_power (by userlevel) not supported */
- tx_power = cpu_to_le32(get_bcm4320_power(priv));
-
- wrqu->txpower.flags = IW_TXPOW_MWATT;
- wrqu->txpower.value = le32_to_cpu(tx_power);
- wrqu->txpower.disabled = 0;
- } else {
- wrqu->txpower.flags = IW_TXPOW_MWATT;
- wrqu->txpower.value = 0;
- wrqu->txpower.disabled = 1;
- }
-
- devdbg(usbdev, "SIOCGIWTXPOW: %d", wrqu->txpower.value);
-
- return 0;
-}
-
-
-static int rndis_iw_set_txpower(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- __le32 tx_power = 0;
-
- if (!wrqu->txpower.disabled) {
- if (wrqu->txpower.flags == IW_TXPOW_MWATT)
- tx_power = cpu_to_le32(wrqu->txpower.value);
- else { /* wrqu->txpower.flags == IW_TXPOW_DBM */
- if (wrqu->txpower.value > 20)
- tx_power = cpu_to_le32(128);
- else if (wrqu->txpower.value < -43)
- tx_power = cpu_to_le32(127);
- else {
- signed char tmp;
- tmp = wrqu->txpower.value;
- tmp = -12 - tmp;
- tmp <<= 2;
- tx_power = cpu_to_le32((unsigned char)tmp);
- }
- }
- }
-
- devdbg(usbdev, "SIOCSIWTXPOW: %d", le32_to_cpu(tx_power));
-
- if (le32_to_cpu(tx_power) != 0) {
- /* txpower unsupported, just turn radio on */
- if (!priv->radio_on)
- return disassociate(usbdev, 1);
- return 0; /* all ready on */
- }
-
- /* tx_power == 0, turn off radio */
- return disassociate(usbdev, 0);
-}
-
-
static int rndis_iw_get_rate(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
@@ -2022,12 +1995,12 @@ static const iw_handler rndis_iw_handler[] =
IW_IOCTL(SIOCSIWESSID) = rndis_iw_set_essid,
IW_IOCTL(SIOCGIWESSID) = rndis_iw_get_essid,
IW_IOCTL(SIOCGIWRATE) = rndis_iw_get_rate,
- IW_IOCTL(SIOCSIWRTS) = rndis_iw_set_rts,
- IW_IOCTL(SIOCGIWRTS) = rndis_iw_get_rts,
- IW_IOCTL(SIOCSIWFRAG) = rndis_iw_set_frag,
- IW_IOCTL(SIOCGIWFRAG) = rndis_iw_get_frag,
- IW_IOCTL(SIOCSIWTXPOW) = rndis_iw_set_txpower,
- IW_IOCTL(SIOCGIWTXPOW) = rndis_iw_get_txpower,
+ IW_IOCTL(SIOCSIWRTS) = (iw_handler) cfg80211_wext_siwrts,
+ IW_IOCTL(SIOCGIWRTS) = (iw_handler) cfg80211_wext_giwrts,
+ IW_IOCTL(SIOCSIWFRAG) = (iw_handler) cfg80211_wext_siwfrag,
+ IW_IOCTL(SIOCGIWFRAG) = (iw_handler) cfg80211_wext_giwfrag,
+ IW_IOCTL(SIOCSIWTXPOW) = (iw_handler) cfg80211_wext_siwtxpower,
+ IW_IOCTL(SIOCGIWTXPOW) = (iw_handler) cfg80211_wext_giwtxpower,
IW_IOCTL(SIOCSIWENCODE) = rndis_iw_set_encode,
IW_IOCTL(SIOCSIWENCODEEXT) = rndis_iw_set_encode_ext,
IW_IOCTL(SIOCSIWAUTH) = rndis_iw_set_auth,
@@ -2475,6 +2448,10 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf)
set_default_iw_params(usbdev);
+ /* set default rts/frag */
+ rndis_set_wiphy_params(wiphy,
+ WIPHY_PARAM_FRAG_THRESHOLD | WIPHY_PARAM_RTS_THRESHOLD);
+
/* turn radio on */
priv->radio_on = 1;
disassociate(usbdev, 1);
@@ -2522,10 +2499,18 @@ static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf)
static int rndis_wlan_reset(struct usbnet *usbdev)
{
+ devdbg(usbdev, "rndis_wlan_reset");
return deauthenticate(usbdev);
}
+static int rndis_wlan_stop(struct usbnet *usbdev)
+{
+ devdbg(usbdev, "rndis_wlan_stop");
+ return disassociate(usbdev, 0);
+}
+
+
static const struct driver_info bcm4320b_info = {
.description = "Wireless RNDIS device, BCM4320b based",
.flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
@@ -2535,6 +2520,7 @@ static const struct driver_info bcm4320b_info = {
.rx_fixup = rndis_rx_fixup,
.tx_fixup = rndis_tx_fixup,
.reset = rndis_wlan_reset,
+ .stop = rndis_wlan_stop,
.early_init = bcm4320b_early_init,
.link_change = rndis_wlan_link_change,
};
@@ -2548,6 +2534,7 @@ static const struct driver_info bcm4320a_info = {
.rx_fixup = rndis_rx_fixup,
.tx_fixup = rndis_tx_fixup,
.reset = rndis_wlan_reset,
+ .stop = rndis_wlan_stop,
.early_init = bcm4320a_early_init,
.link_change = rndis_wlan_link_change,
};
@@ -2561,6 +2548,7 @@ static const struct driver_info rndis_wlan_info = {
.rx_fixup = rndis_rx_fixup,
.tx_fixup = rndis_tx_fixup,
.reset = rndis_wlan_reset,
+ .stop = rndis_wlan_stop,
.early_init = bcm4320a_early_init,
.link_change = rndis_wlan_link_change,
};
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index 8aab3e6754bd..f970aa25326a 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -112,14 +112,6 @@ config RT2X00_LIB_FIRMWARE
config RT2X00_LIB_CRYPTO
boolean
-config RT2X00_LIB_RFKILL
- boolean
- default y if (RT2X00_LIB=y && INPUT=y) || (RT2X00_LIB=m && INPUT!=n)
- select INPUT_POLLDEV
-
-comment "rt2x00 rfkill support disabled due to modularized INPUT and built-in rt2x00"
- depends on RT2X00_LIB=y && INPUT=m
-
config RT2X00_LIB_LEDS
boolean
default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n)
diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile
index bfc7226f0afe..13043ea97667 100644
--- a/drivers/net/wireless/rt2x00/Makefile
+++ b/drivers/net/wireless/rt2x00/Makefile
@@ -5,7 +5,6 @@ rt2x00lib-y += rt2x00queue.o
rt2x00lib-y += rt2x00link.o
rt2x00lib-$(CONFIG_RT2X00_LIB_DEBUGFS) += rt2x00debug.o
rt2x00lib-$(CONFIG_RT2X00_LIB_CRYPTO) += rt2x00crypto.o
-rt2x00lib-$(CONFIG_RT2X00_LIB_RFKILL) += rt2x00rfkill.o
rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o
rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o
rt2x00lib-$(CONFIG_RT2X00_LIB_HT) += rt2x00ht.o
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 435f945fe64d..30185ad28d93 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -199,7 +199,6 @@ static const struct rt2x00debug rt2400pci_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -207,9 +206,6 @@ static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
rt2x00pci_register_read(rt2x00dev, GPIOCSR, &reg);
return rt2x00_get_field32(reg, GPIOCSR_BIT0);
}
-#else
-#define rt2400pci_rfkill_poll NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt2400pci_brightness_set(struct led_classdev *led_cdev,
@@ -1391,10 +1387,8 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Detect if this device has an hardware controlled radio.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* Check if the BBP tuning should be enabled.
@@ -1567,12 +1561,14 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2400pci_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt2400pci_get_tsf,
.tx_last_beacon = rt2400pci_tx_last_beacon,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
};
static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h
index ec3b004ddc3c..ccd644104ad1 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.h
+++ b/drivers/net/wireless/rt2x00/rt2400pci.h
@@ -928,7 +928,7 @@
#define RXD_W7_RESERVED FIELD32(0xffffffff)
/*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
* NOTE: Logics in rt2400pci for txpower are reversed
* compared to the other rt2x00 drivers. A higher txpower
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 08b30d01e67d..3b3171578b14 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -199,7 +199,6 @@ static const struct rt2x00debug rt2500pci_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -207,9 +206,6 @@ static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
rt2x00pci_register_read(rt2x00dev, GPIOCSR, &reg);
return rt2x00_get_field32(reg, GPIOCSR_BIT0);
}
-#else
-#define rt2500pci_rfkill_poll NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt2500pci_brightness_set(struct led_classdev *led_cdev,
@@ -1548,10 +1544,8 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Detect if this device has an hardware controlled radio.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* Check if the BBP tuning should be enabled.
@@ -1866,12 +1860,14 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2x00mac_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt2500pci_get_tsf,
.tx_last_beacon = rt2500pci_tx_last_beacon,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
};
static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h
index ce2f065c7486..54d37957883c 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.h
+++ b/drivers/net/wireless/rt2x00/rt2500pci.h
@@ -1218,7 +1218,7 @@
#define RXD_W10_DROP FIELD32(0x00000001)
/*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
*/
#define MIN_TXPOWER 0
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index ce75426764a1..de48c5c68eff 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -277,7 +277,6 @@ static const struct rt2x00debug rt2500usb_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
static int rt2500usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u16 reg;
@@ -285,9 +284,6 @@ static int rt2500usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
rt2500usb_register_read(rt2x00dev, MAC_CSR19, &reg);
return rt2x00_get_field32(reg, MAC_CSR19_BIT7);
}
-#else
-#define rt2500usb_rfkill_poll NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt2500usb_brightness_set(struct led_classdev *led_cdev,
@@ -1603,10 +1599,8 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Detect if this device has an hardware controlled radio.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* Check if the BBP tuning should be disabled.
@@ -1902,11 +1896,13 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2x00mac_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
};
static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h
index 5bc46fe72179..b01edca42583 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.h
+++ b/drivers/net/wireless/rt2x00/rt2500usb.h
@@ -831,7 +831,7 @@
#define RXD_W3_EIV FIELD32(0xffffffff)
/*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
*/
#define MIN_TXPOWER 0
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 37561667925b..9efb41710508 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -264,7 +264,6 @@ static const struct rt2x00debug rt2800usb_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
static int rt2800usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -272,9 +271,6 @@ static int rt2800usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
rt2x00usb_register_read(rt2x00dev, GPIO_CTRL_CFG, &reg);
return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2);
}
-#else
-#define rt2800usb_rfkill_poll NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt2800usb_brightness_set(struct led_classdev *led_cdev,
@@ -1914,7 +1910,7 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
/*
* Before the radio can be enabled, the device first has
* to be woken up. After that it needs a bit of time
- * to be fully awake and the radio can be enabled.
+ * to be fully awake and then the radio can be enabled.
*/
rt2800usb_set_state(rt2x00dev, STATE_AWAKE);
msleep(1);
@@ -1922,7 +1918,7 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
break;
case STATE_RADIO_OFF:
/*
- * After the radio has been disablee, the device should
+ * After the radio has been disabled, the device should
* be put to sleep for powersaving.
*/
rt2800usb_disable_radio(rt2x00dev);
@@ -2224,10 +2220,8 @@ static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
*/
mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
if (!is_valid_ether_addr(mac)) {
- DECLARE_MAC_BUF(macbuf);
-
random_ether_addr(mac);
- EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+ EEPROM(rt2x00dev, "MAC: %pM\n", mac);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
@@ -2385,10 +2379,8 @@ static int rt2800usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Detect if this device has an hardware controlled radio.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
if (rt2x00_get_field16(eeprom, EEPROM_NIC_HW_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* Store led settings, for correct led behaviour.
@@ -2792,6 +2784,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats,
.get_tkip_seq = rt2800usb_get_tkip_seq,
@@ -2800,6 +2793,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
.conf_tx = rt2800usb_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt2800usb_get_tsf,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
};
static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h
index 61a8be61d3f5..2d9dc3783361 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.h
+++ b/drivers/net/wireless/rt2x00/rt2800usb.h
@@ -1921,7 +1921,7 @@ struct mac_iveiv_entry {
#define RXWI_W3_SNR1 FIELD32(0x0000ff00)
/*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
*/
#define MIN_G_TXPOWER 0
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index a498dde024e1..cbec91ef6f76 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -245,7 +245,7 @@ struct link_ant {
struct antenna_setup active;
/*
- * RSSI information for the different antenna's.
+ * RSSI information for the different antennas.
* These statistics are used to determine when
* to switch antenna when using software diversity.
*
@@ -594,7 +594,6 @@ enum rt2x00_flags {
DEVICE_STATE_INITIALIZED,
DEVICE_STATE_STARTED,
DEVICE_STATE_ENABLED_RADIO,
- DEVICE_STATE_DISABLED_RADIO_HW,
/*
* Driver requirements
@@ -634,7 +633,7 @@ struct rt2x00_dev {
* The structure stored in here depends on the
* system bus (PCI or USB).
* When accessing this variable, the rt2x00dev_{pci,usb}
- * macro's should be used for correct typecasting.
+ * macros should be used for correct typecasting.
*/
struct device *dev;
@@ -651,18 +650,6 @@ struct rt2x00_dev {
enum ieee80211_band curr_band;
/*
- * rfkill structure for RF state switching support.
- * This will only be compiled in when required.
- */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
- unsigned long rfkill_state;
-#define RFKILL_STATE_ALLOCATED 1
-#define RFKILL_STATE_REGISTERED 2
-#define RFKILL_STATE_BLOCKED 3
- struct input_polled_dev *rfkill_poll_dev;
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
-
- /*
* If enabled, the debugfs interface structures
* required for deregistration of debugfs.
*/
@@ -975,6 +962,8 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
int mc_count, struct dev_addr_list *mc_list);
+int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+ bool set);
#ifdef CONFIG_RT2X00_LIB_CRYPTO
int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
@@ -992,6 +981,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
u32 changes);
int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params);
+void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw);
/*
* Driver allocation handlers.
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 3e019a12df2e..c6e0bcf78e9e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -132,7 +132,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
/*
* Failsafe: Make sure we are not sending the
* ANTENNA_SW_DIVERSITY state to the driver.
- * If that happes fallback to hardware default,
+ * If that happens, fallback to hardware defaults,
* or our own default.
* The calls to rt2x00lib_config_antenna_check()
* might have caused that we restore back to the already
diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c
index bc4e81e21841..30fbd3bbe08b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00crypto.c
+++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c
@@ -53,8 +53,7 @@ void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry,
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
- if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) ||
- !hw_key || entry->skb->do_not_encrypt)
+ if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !hw_key)
return;
__set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags);
@@ -82,8 +81,7 @@ unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev,
struct ieee80211_key_conf *key = tx_info->control.hw_key;
unsigned int overhead = 0;
- if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) ||
- !key || skb->do_not_encrypt)
+ if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !key)
return overhead;
/*
@@ -131,7 +129,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);
- /* IV/EIV data has officially be stripped */
+ /* IV/EIV data has officially been stripped */
skbdesc->flags |= SKBDESC_IV_STRIPPED;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 57813e72c808..658a63bfb761 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -40,8 +40,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
* Don't enable the radio twice.
* And check if the hardware button has been disabled.
*/
- if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
- test_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags))
+ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return 0;
/*
@@ -449,7 +448,8 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
* mac80211 will clean up the skb structure.
*/
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
- ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb, rx_status);
+ memcpy(IEEE80211_SKB_RXCB(entry->skb), rx_status, sizeof(*rx_status));
+ ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb);
/*
* Replace the skb with the freshly allocated one.
@@ -870,7 +870,6 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
*/
rt2x00link_register(rt2x00dev);
rt2x00leds_register(rt2x00dev);
- rt2x00rfkill_allocate(rt2x00dev);
rt2x00debug_register(rt2x00dev);
set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
@@ -902,7 +901,6 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
* Free extra components
*/
rt2x00debug_deregister(rt2x00dev);
- rt2x00rfkill_free(rt2x00dev);
rt2x00leds_unregister(rt2x00dev);
/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index 0bf2715fa93a..512fa2bc3a10 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -30,10 +30,8 @@
/*
* Interval defines
- * Both the link tuner as the rfkill will be called once per second.
*/
#define LINK_TUNE_INTERVAL round_jiffies_relative(HZ)
-#define RFKILL_POLL_INTERVAL 1000
/*
* rt2x00_rate: Per rate device information
@@ -386,29 +384,18 @@ static inline void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
/*
* RFkill handlers.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
-void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev);
-void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev);
-void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev);
-void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev);
-#else
static inline void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
{
+ if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+ wiphy_rfkill_start_polling(rt2x00dev->hw->wiphy);
}
static inline void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
{
+ if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+ wiphy_rfkill_stop_polling(rt2x00dev->hw->wiphy);
}
-static inline void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev)
-{
-}
-
-static inline void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
-{
-}
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
-
/*
* LED handlers
*/
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c
index eb9b981b9139..32570758e67c 100644
--- a/drivers/net/wireless/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/rt2x00/rt2x00link.c
@@ -158,7 +158,7 @@ static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev)
/*
* During the last period we have sampled the RSSI
- * from both antenna's. It now is time to determine
+ * from both antennas. It now is time to determine
* which antenna demonstrated the best performance.
* When we are already on the antenna with the best
* performance, then there really is nothing for us
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index c4c06b4e1f08..9d31c23b92fa 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -73,7 +73,8 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
else
rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
- skb->do_not_encrypt = 1;
+ /* Disable hardware encryption */
+ rts_info->control.hw_key = NULL;
/*
* RTS/CTS frame should use the length of the frame plus any
@@ -340,7 +341,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
int status;
/*
- * Mac80211 might be calling this function while we are trying
+ * mac80211 might be calling this function while we are trying
* to remove the device or perhaps suspending it.
*/
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
@@ -453,6 +454,16 @@ static void memcpy_tkip(struct rt2x00lib_crypto *crypto, u8 *key, u8 key_len)
sizeof(crypto->rx_mic));
}
+int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+ bool set)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ rt2x00lib_beacondone(rt2x00dev);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_set_tim);
+
int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
@@ -576,7 +587,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
int update_bssid = 0;
/*
- * Mac80211 might be calling this function while we are trying
+ * mac80211 might be calling this function while we are trying
* to remove the device or perhaps suspending it.
*/
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
@@ -687,3 +698,12 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00mac_conf_tx);
+
+void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ bool blocked = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
+
+ wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll);
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index b5e06347c8a7..47d175a13790 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -29,7 +29,7 @@
#include <linux/prefetch.h>
/**
- * DOC: Entrie frame size
+ * DOC: Entry frame size
*
* Ralink PCI devices demand the Frame size to be a multiple of 128 bytes,
* for USB devices this restriction does not apply, but the value of
@@ -45,13 +45,13 @@
/**
* DOC: Number of entries per queue
*
- * Under normal load without fragmentation 12 entries are sufficient
+ * Under normal load without fragmentation, 12 entries are sufficient
* without the queue being filled up to the maximum. When using fragmentation
- * and the queue threshold code we need to add some additional margins to
+ * and the queue threshold code, we need to add some additional margins to
* make sure the queue will never (or only under extreme load) fill up
* completely.
- * Since we don't use preallocated DMA having a large number of queue entries
- * will have only minimal impact on the memory requirements for the queue.
+ * Since we don't use preallocated DMA, having a large number of queue entries
+ * will have minimal impact on the memory requirements for the queue.
*/
#define RX_ENTRIES 24
#define TX_ENTRIES 24
diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h
index 861322d97fce..983e52e127a7 100644
--- a/drivers/net/wireless/rt2x00/rt2x00reg.h
+++ b/drivers/net/wireless/rt2x00/rt2x00reg.h
@@ -176,8 +176,8 @@ struct rt2x00_field32 {
#define is_valid_mask(x) is_power_of_two(1LU + (x) + low_bit_mask(x))
/*
- * Macro's to find first set bit in a variable.
- * These macro's behaves the same as the __ffs() function with
+ * Macros to find first set bit in a variable.
+ * These macros behave the same as the __ffs() functions but
* the most important difference that this is done during
* compile-time rather then run-time.
*/
diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c
deleted file mode 100644
index b6d4c6700bf3..000000000000
--- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
- <http://rt2x00.serialmonkey.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the
- Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*
- Module: rt2x00rfkill
- Abstract: rt2x00 rfkill routines.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-#include "rt2x00.h"
-#include "rt2x00lib.h"
-
-static void rt2x00rfkill_poll(struct input_polled_dev *poll_dev)
-{
- struct rt2x00_dev *rt2x00dev = poll_dev->private;
- int state, old_state;
-
- if (!test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state) ||
- !test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
- return;
-
- /*
- * Poll latest state, if the state is different then the previous state,
- * we should generate an input event.
- */
- state = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
- old_state = !!test_bit(RFKILL_STATE_BLOCKED, &rt2x00dev->rfkill_state);
-
- if (old_state != state) {
- input_report_switch(poll_dev->input, SW_RFKILL_ALL, state);
- change_bit(RFKILL_STATE_BLOCKED, &rt2x00dev->rfkill_state);
- }
-}
-
-void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
-{
- if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) ||
- test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state))
- return;
-
- if (input_register_polled_device(rt2x00dev->rfkill_poll_dev)) {
- ERROR(rt2x00dev, "Failed to register polled device.\n");
- return;
- }
-
- __set_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state);
-
- /*
- * Force initial poll which will detect the initial device state,
- * and correctly sends the signal to the input layer about this
- * state.
- */
- rt2x00rfkill_poll(rt2x00dev->rfkill_poll_dev);
-}
-
-void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
-{
- if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) ||
- !test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state))
- return;
-
- input_unregister_polled_device(rt2x00dev->rfkill_poll_dev);
-
- __clear_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state);
-}
-
-void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev)
-{
- struct input_polled_dev *poll_dev;
-
- if (test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) ||
- !test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
- return;
-
- poll_dev = input_allocate_polled_device();
- if (!poll_dev) {
- ERROR(rt2x00dev, "Failed to allocate polled device.\n");
- return;
- }
-
- poll_dev->private = rt2x00dev;
- poll_dev->poll = rt2x00rfkill_poll;
- poll_dev->poll_interval = RFKILL_POLL_INTERVAL;
-
- poll_dev->input->name = rt2x00dev->ops->name;
- poll_dev->input->phys = wiphy_name(rt2x00dev->hw->wiphy);
- poll_dev->input->id.bustype = BUS_HOST;
- poll_dev->input->id.vendor = 0x1814;
- poll_dev->input->id.product = rt2x00dev->chip.rt;
- poll_dev->input->id.version = rt2x00dev->chip.rev;
- poll_dev->input->dev.parent = wiphy_dev(rt2x00dev->hw->wiphy);
- poll_dev->input->evbit[0] = BIT(EV_SW);
- poll_dev->input->swbit[0] = BIT(SW_RFKILL_ALL);
-
- rt2x00dev->rfkill_poll_dev = poll_dev;
-
- __set_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state);
-}
-
-void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
-{
- if (!__test_and_clear_bit(RFKILL_STATE_ALLOCATED,
- &rt2x00dev->rfkill_state))
- return;
-
- input_free_polled_device(rt2x00dev->rfkill_poll_dev);
- rt2x00dev->rfkill_poll_dev = NULL;
-}
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 49b29ff90c47..fb95b8cc4fe9 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -237,7 +237,6 @@ static const struct rt2x00debug rt61pci_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -245,9 +244,6 @@ static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
rt2x00pci_register_read(rt2x00dev, MAC_CSR13, &reg);
return rt2x00_get_field32(reg, MAC_CSR13_BIT5);
}
-#else
-#define rt61pci_rfkill_poll NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt61pci_brightness_set(struct led_classdev *led_cdev,
@@ -2316,7 +2312,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
}
/*
- * Determine number of antenna's.
+ * Determine number of antennas.
*/
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2)
__set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags);
@@ -2338,10 +2334,8 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Detect if this device has an hardware controlled radio.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* Read frequency offset and RF programming sequence.
@@ -2722,12 +2716,14 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt61pci_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt61pci_get_tsf,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
};
static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
index 6c71f77c8165..93eb699165cc 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -1476,7 +1476,7 @@ struct hw_pairwise_ta_entry {
#define RXD_W15_RESERVED FIELD32(0xffffffff)
/*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
*/
#define MIN_TXPOWER 0
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index c18848836f2d..4f9b1772e1a1 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -183,7 +183,6 @@ static const struct rt2x00debug rt73usb_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
static int rt73usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -191,9 +190,6 @@ static int rt73usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
rt2x00usb_register_read(rt2x00dev, MAC_CSR13, &reg);
return rt2x00_get_field32(reg, MAC_CSR13_BIT7);
}
-#else
-#define rt73usb_rfkill_poll NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt73usb_brightness_set(struct led_classdev *led_cdev,
@@ -1863,10 +1859,8 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Detect if this device has an hardware controlled radio.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* Read frequency offset.
@@ -2247,12 +2241,14 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt73usb_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt73usb_get_tsf,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
};
static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
index c8016f65b4bd..81fe0be51c42 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.h
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -809,7 +809,7 @@ struct hw_pairwise_ta_entry {
/*
* EEPROM antenna.
- * ANTENNA_NUM: Number of antenna's.
+ * ANTENNA_NUM: Number of antennas.
* TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
* RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
* FRAME_TYPE: 0: DPDT , 1: SPDT , noted this bit is valid for g only.
@@ -1058,7 +1058,7 @@ struct hw_pairwise_ta_entry {
#define RXD_W5_RESERVED FIELD32(0xffffffff)
/*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
*/
#define MIN_TXPOWER 0
diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c
index 7e65d7c31802..09f46abc730a 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c
@@ -143,7 +143,8 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR)
rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
- ieee80211_rx_irqsafe(dev, skb, &rx_status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+ ieee80211_rx_irqsafe(dev, skb);
skb = new_skb;
priv->rx_buf[priv->rx_idx] = skb;
@@ -280,7 +281,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
(ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10);
remainder = (16 * (skb->len + 4)) %
((ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10);
- if (remainder > 0 && remainder <= 6)
+ if (remainder <= 6)
plcp_len |= 1 << 15;
}
diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c
index 294250e294dd..c9b9dbe584c6 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
@@ -380,7 +380,8 @@ static void rtl8187_rx_cb(struct urb *urb)
rx_status.flag |= RX_FLAG_TSFT;
if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR)
rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
- ieee80211_rx_irqsafe(dev, skb, &rx_status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+ ieee80211_rx_irqsafe(dev, skb);
skb = dev_alloc_skb(RTL8187_MAX_RX);
if (unlikely(!skb)) {
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index 38366a56b71f..73300c226f67 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -1582,7 +1582,7 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index ab7fc5c0c8b4..5cb5329a20d1 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -2891,7 +2891,7 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev)
#ifdef DEBUG_TX_TRACE
printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
#endif
- return 0;
+ return NETDEV_TX_OK;
}
/*********************** HARDWARE CONFIGURATION ***********************/
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index 6af706408ac0..9dd241adc379 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -3113,7 +3113,7 @@ wavelan_packet_xmit(struct sk_buff * skb,
* able to detect collisions, therefore in theory we don't really
* need to pad. Jean II */
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
wv_packet_write(dev, skb->data, skb->len);
@@ -3122,7 +3122,7 @@ wavelan_packet_xmit(struct sk_buff * skb,
#ifdef DEBUG_TX_TRACE
printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
#endif
- return(0);
+ return NETDEV_TX_OK;
}
/********************** HARDWARE CONFIGURATION **********************/
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig
index a82c4cd436d8..82a0f97975de 100644
--- a/drivers/net/wireless/wl12xx/Kconfig
+++ b/drivers/net/wireless/wl12xx/Kconfig
@@ -1,11 +1,18 @@
-config WL12XX
- tristate "TI wl1251/wl1271 support"
- depends on MAC80211 && WLAN_80211 && SPI_MASTER && GENERIC_HARDIRQS && EXPERIMENTAL
+menuconfig WL12XX
+ boolean "TI wl12xx driver support"
+ depends on MAC80211 && WLAN_80211 && EXPERIMENTAL
+ ---help---
+ This will enable TI wl12xx driver support. The drivers make
+ use of the mac80211 stack.
+
+config WL1251
+ tristate "TI wl1251 support"
+ depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS
select FW_LOADER
select CRC7
---help---
This module adds support for wireless adapters based on
- TI wl1251/wl1271 chipsets.
+ TI wl1251 chipset.
- If you choose to build a module, it'll be called wl12xx. Say N if
+ If you choose to build a module, it'll be called wl1251. Say N if
unsure.
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile
index d43de27dc54c..d5595a841f5f 100644
--- a/drivers/net/wireless/wl12xx/Makefile
+++ b/drivers/net/wireless/wl12xx/Makefile
@@ -1,4 +1,5 @@
-wl12xx-objs = main.o spi.o event.o tx.o rx.o \
- ps.o cmd.o acx.o boot.o init.o wl1251.o \
- debugfs.o
-obj-$(CONFIG_WL12XX) += wl12xx.o
+wl1251-objs = wl1251_main.o wl1251_spi.o wl1251_event.o \
+ wl1251_tx.o wl1251_rx.o wl1251_ps.o wl1251_cmd.o \
+ wl1251_acx.o wl1251_boot.o wl1251_init.o \
+ wl1251_ops.o wl1251_debugfs.o
+obj-$(CONFIG_WL1251) += wl1251.o
diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
deleted file mode 100644
index 1cfd458ad5ab..000000000000
--- a/drivers/net/wireless/wl12xx/acx.c
+++ /dev/null
@@ -1,689 +0,0 @@
-#include "acx.h"
-
-#include <linux/module.h>
-#include <linux/crc7.h>
-#include <linux/spi/spi.h>
-
-#include "wl12xx.h"
-#include "wl12xx_80211.h"
-#include "reg.h"
-#include "spi.h"
-#include "ps.h"
-
-int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod,
- u8 mgt_rate, u8 mgt_mod)
-{
- int ret;
- struct acx_fw_gen_frame_rates rates;
-
- wl12xx_debug(DEBUG_ACX, "acx frame rates");
-
- rates.header.id = ACX_FW_GEN_FRAME_RATES;
- rates.header.len = sizeof(struct acx_fw_gen_frame_rates) -
- sizeof(struct acx_header);
-
- rates.tx_ctrl_frame_rate = ctrl_rate;
- rates.tx_ctrl_frame_mod = ctrl_mod;
- rates.tx_mgt_frame_rate = mgt_rate;
- rates.tx_mgt_frame_mod = mgt_mod;
-
- ret = wl12xx_cmd_configure(wl, &rates, sizeof(rates));
- if (ret < 0) {
- wl12xx_error("Failed to set FW rates and modulation");
- return ret;
- }
-
- return 0;
-}
-
-
-int wl12xx_acx_station_id(struct wl12xx *wl)
-{
- int ret, i;
- struct dot11_station_id mac;
-
- wl12xx_debug(DEBUG_ACX, "acx dot11_station_id");
-
- mac.header.id = DOT11_STATION_ID;
- mac.header.len = sizeof(mac) - sizeof(struct acx_header);
-
- for (i = 0; i < ETH_ALEN; i++)
- mac.mac[i] = wl->mac_addr[ETH_ALEN - 1 - i];
-
- ret = wl12xx_cmd_configure(wl, &mac, sizeof(mac));
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id)
-{
- struct acx_dot11_default_key default_key;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id);
-
- default_key.header.id = DOT11_DEFAULT_KEY;
- default_key.header.len = sizeof(default_key) -
- sizeof(struct acx_header);
-
- default_key.id = key_id;
-
- ret = wl12xx_cmd_configure(wl, &default_key, sizeof(default_key));
- if (ret < 0) {
- wl12xx_error("Couldnt set default key");
- return ret;
- }
-
- wl->default_key = key_id;
-
- return 0;
-}
-
-int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval)
-{
- struct acx_wake_up_condition wake_up;
-
- wl12xx_debug(DEBUG_ACX, "acx wake up conditions");
-
- wake_up.header.id = ACX_WAKE_UP_CONDITIONS;
- wake_up.header.len = sizeof(wake_up) - sizeof(struct acx_header);
-
- wake_up.wake_up_event = WAKE_UP_EVENT_DTIM_BITMAP;
- wake_up.listen_interval = listen_interval;
-
- return wl12xx_cmd_configure(wl, &wake_up, sizeof(wake_up));
-}
-
-int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth)
-{
- int ret;
- struct acx_sleep_auth auth;
-
- wl12xx_debug(DEBUG_ACX, "acx sleep auth");
-
- auth.header.id = ACX_SLEEP_AUTH;
- auth.header.len = sizeof(auth) - sizeof(struct acx_header);
-
- auth.sleep_auth = sleep_auth;
-
- ret = wl12xx_cmd_configure(wl, &auth, sizeof(auth));
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len)
-{
- struct wl12xx_command cmd;
- struct acx_revision *rev;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx fw rev");
-
- memset(&cmd, 0, sizeof(cmd));
-
- ret = wl12xx_cmd_interrogate(wl, ACX_FW_REV, sizeof(*rev), &cmd);
- if (ret < 0) {
- wl12xx_warning("ACX_FW_REV interrogate failed");
- return ret;
- }
-
- rev = (struct acx_revision *) &cmd.parameters;
-
- /* be careful with the buffer sizes */
- strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version)));
-
- /*
- * if the firmware version string is exactly
- * sizeof(rev->fw_version) long or fw_len is less than
- * sizeof(rev->fw_version) it won't be null terminated
- */
- buf[min(len, sizeof(rev->fw_version)) - 1] = '\0';
-
- return 0;
-}
-
-int wl12xx_acx_tx_power(struct wl12xx *wl, int power)
-{
- struct acx_current_tx_power ie;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr");
-
- if (power < 0 || power > 25)
- return -EINVAL;
-
- memset(&ie, 0, sizeof(ie));
-
- ie.header.id = DOT11_CUR_TX_PWR;
- ie.header.len = sizeof(ie) - sizeof(struct acx_header);
- ie.current_tx_power = power * 10;
-
- ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie));
- if (ret < 0) {
- wl12xx_warning("configure of tx power failed: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_feature_cfg(struct wl12xx *wl)
-{
- struct acx_feature_config feature;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx feature cfg");
-
- memset(&feature, 0, sizeof(feature));
-
- feature.header.id = ACX_FEATURE_CFG;
- feature.header.len = sizeof(feature) - sizeof(struct acx_header);
-
- /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */
- feature.data_flow_options = 0;
- feature.options = 0;
-
- ret = wl12xx_cmd_configure(wl, &feature, sizeof(feature));
- if (ret < 0)
- wl12xx_error("Couldnt set HW encryption");
-
- return ret;
-}
-
-int wl12xx_acx_mem_map(struct wl12xx *wl, void *mem_map, size_t len)
-{
- struct wl12xx_command cmd;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx mem map");
-
- ret = wl12xx_cmd_interrogate(wl, ACX_MEM_MAP, len, &cmd);
- if (ret < 0)
- return ret;
- else if (cmd.status != CMD_STATUS_SUCCESS)
- return -EIO;
-
- memcpy(mem_map, &cmd.parameters, len);
-
- return 0;
-}
-
-int wl12xx_acx_data_path_params(struct wl12xx *wl,
- struct acx_data_path_params_resp *data_path)
-{
- struct acx_data_path_params params;
- struct wl12xx_command cmd;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx data path params");
-
- params.rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE;
- params.tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE;
-
- params.rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM;
- params.tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM;
-
- params.tx_complete_threshold = 1;
-
- params.tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE;
-
- params.tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT;
-
- params.header.id = ACX_DATA_PATH_PARAMS;
- params.header.len = sizeof(params) - sizeof(struct acx_header);
-
- ret = wl12xx_cmd_configure(wl, &params, sizeof(params));
- if (ret < 0)
- return ret;
-
-
- ret = wl12xx_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS,
- sizeof(struct acx_data_path_params_resp),
- &cmd);
-
- if (ret < 0) {
- wl12xx_warning("failed to read data path parameters: %d", ret);
- return ret;
- } else if (cmd.status != CMD_STATUS_SUCCESS) {
- wl12xx_warning("data path parameter acx status failed");
- return -EIO;
- }
-
- memcpy(data_path, &cmd.parameters, sizeof(*data_path));
-
- return 0;
-}
-
-int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time)
-{
- struct rx_msdu_lifetime msdu_lifetime;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx rx msdu life time");
-
- msdu_lifetime.header.id = DOT11_RX_MSDU_LIFE_TIME;
- msdu_lifetime.header.len = sizeof(msdu_lifetime) -
- sizeof(struct acx_header);
- msdu_lifetime.lifetime = life_time;
-
- ret = wl12xx_cmd_configure(wl, &msdu_lifetime, sizeof(msdu_lifetime));
- if (ret < 0) {
- wl12xx_warning("failed to set rx msdu life time: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter)
-{
- struct acx_rx_config rx_config;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx rx config");
-
- rx_config.header.id = ACX_RX_CFG;
- rx_config.header.len = sizeof(rx_config) - sizeof(struct acx_header);
- rx_config.config_options = config;
- rx_config.filter_options = filter;
-
- ret = wl12xx_cmd_configure(wl, &rx_config, sizeof(rx_config));
- if (ret < 0) {
- wl12xx_warning("failed to set rx config: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_pd_threshold(struct wl12xx *wl)
-{
- struct acx_packet_detection packet_detection;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx data pd threshold");
-
- /* FIXME: threshold value not set */
- packet_detection.header.id = ACX_PD_THRESHOLD;
- packet_detection.header.len = sizeof(packet_detection) -
- sizeof(struct acx_header);
-
- ret = wl12xx_cmd_configure(wl, &packet_detection,
- sizeof(packet_detection));
- if (ret < 0) {
- wl12xx_warning("failed to set pd threshold: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time)
-{
- struct acx_slot slot;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx slot");
-
- slot.header.id = ACX_SLOT;
- slot.header.len = sizeof(slot) - sizeof(struct acx_header);
-
- slot.wone_index = STATION_WONE_INDEX;
- slot.slot_time = slot_time;
-
- ret = wl12xx_cmd_configure(wl, &slot, sizeof(slot));
- if (ret < 0) {
- wl12xx_warning("failed to set slot time: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_group_address_tbl(struct wl12xx *wl)
-{
- struct multicast_grp_addr_start multicast;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx group address tbl");
-
- /* MAC filtering */
- multicast.header.id = DOT11_GROUP_ADDRESS_TBL;
- multicast.header.len = sizeof(multicast) - sizeof(struct acx_header);
-
- multicast.enabled = 0;
- multicast.num_groups = 0;
- memset(multicast.mac_table, 0, ADDRESS_GROUP_MAX_LEN);
-
- ret = wl12xx_cmd_configure(wl, &multicast, sizeof(multicast));
- if (ret < 0) {
- wl12xx_warning("failed to set group addr table: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_service_period_timeout(struct wl12xx *wl)
-{
- struct acx_rx_timeout rx_timeout;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx service period timeout");
-
- /* RX timeout */
- rx_timeout.header.id = ACX_SERVICE_PERIOD_TIMEOUT;
- rx_timeout.header.len = sizeof(rx_timeout) - sizeof(struct acx_header);
-
- rx_timeout.ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF;
- rx_timeout.upsd_timeout = RX_TIMEOUT_UPSD_DEF;
-
- ret = wl12xx_cmd_configure(wl, &rx_timeout, sizeof(rx_timeout));
- if (ret < 0) {
- wl12xx_warning("failed to set service period timeout: %d",
- ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold)
-{
- struct acx_rts_threshold rts;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx rts threshold");
-
- rts.header.id = DOT11_RTS_THRESHOLD;
- rts.header.len = sizeof(rts) - sizeof(struct acx_header);
-
- rts.threshold = rts_threshold;
-
- ret = wl12xx_cmd_configure(wl, &rts, sizeof(rts));
- if (ret < 0) {
- wl12xx_warning("failed to set rts threshold: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl)
-{
- struct acx_beacon_filter_option beacon_filter;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx beacon filter opt");
-
- beacon_filter.header.id = ACX_BEACON_FILTER_OPT;
- beacon_filter.header.len = sizeof(beacon_filter) -
- sizeof(struct acx_header);
-
- beacon_filter.enable = 0;
- beacon_filter.max_num_beacons = 0;
-
- ret = wl12xx_cmd_configure(wl, &beacon_filter, sizeof(beacon_filter));
- if (ret < 0) {
- wl12xx_warning("failed to set beacon filter opt: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_beacon_filter_table(struct wl12xx *wl)
-{
- struct acx_beacon_filter_ie_table ie_table;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx beacon filter table");
-
- ie_table.header.id = ACX_BEACON_FILTER_TABLE;
- ie_table.header.len = sizeof(ie_table) - sizeof(struct acx_header);
-
- ie_table.num_ie = 0;
- memset(ie_table.table, 0, BEACON_FILTER_TABLE_MAX_SIZE);
-
- ret = wl12xx_cmd_configure(wl, &ie_table, sizeof(ie_table));
- if (ret < 0) {
- wl12xx_warning("failed to set beacon filter table: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_sg_enable(struct wl12xx *wl)
-{
- struct acx_bt_wlan_coex pta;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx sg enable");
-
- pta.header.id = ACX_SG_ENABLE;
- pta.header.len = sizeof(pta) - sizeof(struct acx_header);
-
- pta.enable = SG_ENABLE;
-
- ret = wl12xx_cmd_configure(wl, &pta, sizeof(pta));
- if (ret < 0) {
- wl12xx_warning("failed to set softgemini enable: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_sg_cfg(struct wl12xx *wl)
-{
- struct acx_bt_wlan_coex_param param;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx sg cfg");
-
- /* BT-WLAN coext parameters */
- param.header.id = ACX_SG_CFG;
- param.header.len = sizeof(param) - sizeof(struct acx_header);
-
- param.min_rate = RATE_INDEX_24MBPS;
- param.bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF;
- param.wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF;
- param.sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF;
- param.rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF;
- param.tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF;
- param.rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF;
- param.tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF;
- param.wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF;
- param.bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF;
- param.next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF;
- param.wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF;
- param.hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF;
- param.next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF;
- param.antenna_type = PTA_ANTENNA_TYPE_DEF;
- param.signal_type = PTA_SIGNALING_TYPE_DEF;
- param.afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF;
- param.quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF;
- param.max_cts = PTA_MAX_NUM_CTS_DEF;
- param.wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF;
- param.bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF;
- param.missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF;
- param.wlan_elp_hp = PTA_ELP_HP_DEF;
- param.bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF;
- param.ack_mode_dual_ant = PTA_ACK_MODE_DEF;
- param.pa_sd_enable = PTA_ALLOW_PA_SD_DEF;
- param.pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF;
- param.bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF;
-
- ret = wl12xx_cmd_configure(wl, &param, sizeof(param));
- if (ret < 0) {
- wl12xx_warning("failed to set sg config: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_cca_threshold(struct wl12xx *wl)
-{
- struct acx_energy_detection detection;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx cca threshold");
-
- detection.header.id = ACX_CCA_THRESHOLD;
- detection.header.len = sizeof(detection) - sizeof(struct acx_header);
-
- detection.rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D;
- detection.tx_energy_detection = 0;
-
- ret = wl12xx_cmd_configure(wl, &detection, sizeof(detection));
- if (ret < 0) {
- wl12xx_warning("failed to set cca threshold: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl)
-{
- struct acx_beacon_broadcast bb;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx bcn dtim options");
-
- bb.header.id = ACX_BCN_DTIM_OPTIONS;
- bb.header.len = sizeof(bb) - sizeof(struct acx_header);
-
- bb.beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE;
- bb.broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE;
- bb.rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE;
- bb.ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF;
-
- ret = wl12xx_cmd_configure(wl, &bb, sizeof(bb));
- if (ret < 0) {
- wl12xx_warning("failed to set rx config: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_aid(struct wl12xx *wl, u16 aid)
-{
- struct acx_aid acx_aid;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx aid");
-
- acx_aid.header.id = ACX_AID;
- acx_aid.header.len = sizeof(acx_aid) - sizeof(struct acx_header);
-
- acx_aid.aid = aid;
-
- ret = wl12xx_cmd_configure(wl, &acx_aid, sizeof(acx_aid));
- if (ret < 0) {
- wl12xx_warning("failed to set aid: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask)
-{
- struct acx_event_mask mask;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx event mbox mask");
-
- mask.header.id = ACX_EVENT_MBOX_MASK;
- mask.header.len = sizeof(mask) - sizeof(struct acx_header);
-
- /* high event mask is unused */
- mask.high_event_mask = 0xffffffff;
-
- mask.event_mask = event_mask;
-
- ret = wl12xx_cmd_configure(wl, &mask, sizeof(mask));
- if (ret < 0) {
- wl12xx_warning("failed to set aid: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble)
-{
- struct acx_preamble ie;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx_set_preamble");
-
- memset(&ie, 0, sizeof(ie));
-
- ie.header.id = ACX_PREAMBLE_TYPE;
- ie.header.len = sizeof(ie) - sizeof(struct acx_header);
- ie.preamble = preamble;
- ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie));
- if (ret < 0) {
- wl12xx_warning("Setting of preamble failed: %d", ret);
- return ret;
- }
- return 0;
-}
-
-int wl12xx_acx_cts_protect(struct wl12xx *wl,
- enum acx_ctsprotect_type ctsprotect)
-{
- struct acx_ctsprotect ie;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx_set_ctsprotect");
-
- memset(&ie, 0, sizeof(ie));
-
- ie.header.id = ACX_CTS_PROTECTION;
- ie.header.len = sizeof(ie) - sizeof(struct acx_header);
- ie.ctsprotect = ctsprotect;
- ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie));
- if (ret < 0) {
- wl12xx_warning("Setting of ctsprotect failed: %d", ret);
- return ret;
- }
- return 0;
-}
-
-int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats)
-{
- struct wl12xx_command *answer;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx statistics");
-
- answer = kmalloc(sizeof(*answer), GFP_KERNEL);
- if (!answer) {
- wl12xx_warning("could not allocate memory for acx statistics");
- ret = -ENOMEM;
- goto out;
- }
-
- ret = wl12xx_cmd_interrogate(wl, ACX_STATISTICS, sizeof(*answer),
- answer);
- if (ret < 0) {
- wl12xx_warning("acx statistics failed: %d", ret);
- goto out;
- }
-
- memcpy(stats, answer->parameters, sizeof(*stats));
-
-out:
- kfree(answer);
- return ret;
-}
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
deleted file mode 100644
index f73ab602b7ae..000000000000
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ /dev/null
@@ -1,353 +0,0 @@
-#include "cmd.h"
-
-#include <linux/module.h>
-#include <linux/crc7.h>
-#include <linux/spi/spi.h>
-
-#include "wl12xx.h"
-#include "wl12xx_80211.h"
-#include "reg.h"
-#include "spi.h"
-#include "ps.h"
-
-int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len)
-{
- struct wl12xx_command cmd;
- unsigned long timeout;
- size_t cmd_len;
- u32 intr;
- int ret = 0;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.id = type;
- cmd.status = 0;
- memcpy(cmd.parameters, buf, buf_len);
- cmd_len = ALIGN(buf_len, 4) + CMDMBOX_HEADER_LEN;
-
- wl12xx_ps_elp_wakeup(wl);
-
- wl12xx_spi_mem_write(wl, wl->cmd_box_addr, &cmd, cmd_len);
-
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
-
- timeout = jiffies + msecs_to_jiffies(WL12XX_COMMAND_TIMEOUT);
-
- intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
- while (!(intr & wl->chip.intr_cmd_complete)) {
- if (time_after(jiffies, timeout)) {
- wl12xx_error("command complete timeout");
- ret = -ETIMEDOUT;
- goto out;
- }
-
- msleep(1);
-
- intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
- }
-
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
- wl->chip.intr_cmd_complete);
-
-out:
- wl12xx_ps_elp_sleep(wl);
-
- return ret;
-}
-
-int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer)
-{
- int ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd test");
-
- ret = wl12xx_cmd_send(wl, CMD_TEST, buf, buf_len);
- if (ret < 0) {
- wl12xx_warning("TEST command failed");
- return ret;
- }
-
- if (answer) {
- struct wl12xx_command *cmd_answer;
-
- /*
- * The test command got in, we can read the answer.
- * The answer would be a wl12xx_command, where the
- * parameter array contains the actual answer.
- */
-
- wl12xx_ps_elp_wakeup(wl);
-
- wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len);
-
- wl12xx_ps_elp_sleep(wl);
-
- cmd_answer = buf;
- if (cmd_answer->status != CMD_STATUS_SUCCESS)
- wl12xx_error("TEST command answer error: %d",
- cmd_answer->status);
- }
-
- return 0;
-}
-
-
-int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 ie_id, u16 ie_len,
- void *answer)
-{
- struct wl12xx_command *cmd;
- struct acx_header header;
- int ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd interrogate");
-
- header.id = ie_id;
- header.len = ie_len - sizeof(header);
-
- ret = wl12xx_cmd_send(wl, CMD_INTERROGATE, &header, sizeof(header));
- if (ret < 0) {
- wl12xx_error("INTERROGATE command failed");
- return ret;
- }
-
- wl12xx_ps_elp_wakeup(wl);
-
- /* the interrogate command got in, we can read the answer */
- wl12xx_spi_mem_read(wl, wl->cmd_box_addr, answer,
- CMDMBOX_HEADER_LEN + ie_len);
-
- wl12xx_ps_elp_sleep(wl);
-
- cmd = answer;
- if (cmd->status != CMD_STATUS_SUCCESS)
- wl12xx_error("INTERROGATE command error: %d",
- cmd->status);
-
- return 0;
-
-}
-
-int wl12xx_cmd_configure(struct wl12xx *wl, void *ie, int ie_len)
-{
- int ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd configure");
-
- ret = wl12xx_cmd_send(wl, CMD_CONFIGURE, ie,
- ie_len);
- if (ret < 0) {
- wl12xx_warning("CONFIGURE command NOK");
- return ret;
- }
-
- return 0;
-
-}
-
-int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity,
- void *bitmap, u16 bitmap_len, u8 bitmap_control)
-{
- struct vbm_update_request vbm;
- int ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd vbm");
-
- /* Count and period will be filled by the target */
- vbm.tim.bitmap_ctrl = bitmap_control;
- if (bitmap_len > PARTIAL_VBM_MAX) {
- wl12xx_warning("cmd vbm len is %d B, truncating to %d",
- bitmap_len, PARTIAL_VBM_MAX);
- bitmap_len = PARTIAL_VBM_MAX;
- }
- memcpy(vbm.tim.pvb_field, bitmap, bitmap_len);
- vbm.tim.identity = identity;
- vbm.tim.length = bitmap_len + 3;
-
- vbm.len = cpu_to_le16(bitmap_len + 5);
-
- ret = wl12xx_cmd_send(wl, CMD_VBM, &vbm, sizeof(vbm));
- if (ret < 0) {
- wl12xx_error("VBM command failed");
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, u8 enable)
-{
- int ret;
- u16 cmd_rx, cmd_tx;
-
- wl12xx_debug(DEBUG_CMD, "cmd data path");
-
- if (enable) {
- cmd_rx = CMD_ENABLE_RX;
- cmd_tx = CMD_ENABLE_TX;
- } else {
- cmd_rx = CMD_DISABLE_RX;
- cmd_tx = CMD_DISABLE_TX;
- }
-
- ret = wl12xx_cmd_send(wl, cmd_rx, &channel, sizeof(channel));
- if (ret < 0) {
- wl12xx_error("rx %s cmd for channel %d failed",
- enable ? "start" : "stop", channel);
- return ret;
- }
-
- wl12xx_debug(DEBUG_BOOT, "rx %s cmd channel %d",
- enable ? "start" : "stop", channel);
-
- ret = wl12xx_cmd_send(wl, cmd_tx, &channel, sizeof(channel));
- if (ret < 0) {
- wl12xx_error("tx %s cmd for channel %d failed",
- enable ? "start" : "stop", channel);
- return ret;
- }
-
- wl12xx_debug(DEBUG_BOOT, "tx %s cmd channel %d",
- enable ? "start" : "stop", channel);
-
- return 0;
-}
-
-int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval,
- u16 beacon_interval, u8 wait)
-{
- unsigned long timeout;
- struct cmd_join join = {};
- int ret, i;
- u8 *bssid;
-
- /* FIXME: this should be in main.c */
- ret = wl12xx_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE,
- DEFAULT_HW_GEN_MODULATION_TYPE,
- wl->tx_mgmt_frm_rate,
- wl->tx_mgmt_frm_mod);
- if (ret < 0)
- return ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd join");
-
- /* Reverse order BSSID */
- bssid = (u8 *)&join.bssid_lsb;
- for (i = 0; i < ETH_ALEN; i++)
- bssid[i] = wl->bssid[ETH_ALEN - i - 1];
-
- join.rx_config_options = wl->rx_config;
- join.rx_filter_options = wl->rx_filter;
-
- join.basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS |
- RATE_MASK_5_5MBPS | RATE_MASK_11MBPS;
-
- join.beacon_interval = beacon_interval;
- join.dtim_interval = dtim_interval;
- join.bss_type = bss_type;
- join.channel = wl->channel;
- join.ctrl = JOIN_CMD_CTRL_TX_FLUSH;
-
- ret = wl12xx_cmd_send(wl, CMD_START_JOIN, &join, sizeof(join));
- if (ret < 0) {
- wl12xx_error("failed to initiate cmd join");
- return ret;
- }
-
- timeout = msecs_to_jiffies(JOIN_TIMEOUT);
-
- /*
- * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
- * simplify locking we just sleep instead, for now
- */
- if (wait)
- msleep(10);
-
- return 0;
-}
-
-int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode)
-{
- int ret;
- struct acx_ps_params ps_params;
-
- /* FIXME: this should be in ps.c */
- ret = wl12xx_acx_wake_up_conditions(wl, wl->listen_int);
- if (ret < 0) {
- wl12xx_error("Couldnt set wake up conditions");
- return ret;
- }
-
- wl12xx_debug(DEBUG_CMD, "cmd set ps mode");
-
- ps_params.ps_mode = ps_mode;
- ps_params.send_null_data = 1;
- ps_params.retries = 5;
- ps_params.hang_over_period = 128;
- ps_params.null_data_rate = 1; /* 1 Mbps */
-
- ret = wl12xx_cmd_send(wl, CMD_SET_PS_MODE, &ps_params,
- sizeof(ps_params));
- if (ret < 0) {
- wl12xx_error("cmd set_ps_mode failed");
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, u32 len, void *answer)
-{
- struct cmd_read_write_memory mem_cmd, *mem_answer;
- struct wl12xx_command cmd;
- int ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd read memory");
-
- memset(&mem_cmd, 0, sizeof(mem_cmd));
- mem_cmd.addr = addr;
- mem_cmd.size = len;
-
- ret = wl12xx_cmd_send(wl, CMD_READ_MEMORY, &mem_cmd, sizeof(mem_cmd));
- if (ret < 0) {
- wl12xx_error("read memory command failed: %d", ret);
- return ret;
- }
-
- /* the read command got in, we can now read the answer */
- wl12xx_spi_mem_read(wl, wl->cmd_box_addr, &cmd,
- CMDMBOX_HEADER_LEN + sizeof(mem_cmd));
-
- if (cmd.status != CMD_STATUS_SUCCESS)
- wl12xx_error("error in read command result: %d", cmd.status);
-
- mem_answer = (struct cmd_read_write_memory *) cmd.parameters;
- memcpy(answer, mem_answer->value, len);
-
- return 0;
-}
-
-int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id,
- void *buf, size_t buf_len)
-{
- struct wl12xx_cmd_packet_template template;
- int ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd template %d", cmd_id);
-
- memset(&template, 0, sizeof(template));
-
- WARN_ON(buf_len > WL12XX_MAX_TEMPLATE_SIZE);
- buf_len = min_t(size_t, buf_len, WL12XX_MAX_TEMPLATE_SIZE);
- template.size = cpu_to_le16(buf_len);
-
- if (buf)
- memcpy(template.template, buf, buf_len);
-
- ret = wl12xx_cmd_send(wl, cmd_id, &template,
- sizeof(template.size) + buf_len);
- if (ret < 0) {
- wl12xx_warning("cmd set_template failed: %d", ret);
- return ret;
- }
-
- return 0;
-}
diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/reg.h
index e421643215cd..2de47cc32b8b 100644
--- a/drivers/net/wireless/wl12xx/reg.h
+++ b/drivers/net/wireless/wl12xx/reg.h
@@ -26,7 +26,6 @@
#define __REG_H__
#include <linux/bitops.h>
-#include "wl12xx.h"
#define REGISTERS_BASE 0x00300000
#define DRPW_BASE 0x00310000
diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h
index 1f4a44330394..665aca02bea9 100644
--- a/drivers/net/wireless/wl12xx/wl1251.h
+++ b/drivers/net/wireless/wl12xx/wl1251.h
@@ -1,7 +1,8 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
- * Copyright (C) 2008 Nokia Corporation
+ * Copyright (c) 1998-2007 Texas Instruments Incorporated
+ * Copyright (C) 2008-2009 Nokia Corporation
*
* Contact: Kalle Valo <kalle.valo@nokia.com>
*
@@ -24,142 +25,396 @@
#ifndef __WL1251_H__
#define __WL1251_H__
+#include <linux/mutex.h>
+#include <linux/list.h>
#include <linux/bitops.h>
-
-#include "wl12xx.h"
-#include "acx.h"
-
-#define WL1251_FW_NAME "wl1251-fw.bin"
-#define WL1251_NVS_NAME "wl1251-nvs.bin"
-
-#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */
-
-void wl1251_setup(struct wl12xx *wl);
-
-
-struct wl1251_acx_memory {
- __le16 num_stations; /* number of STAs to be supported. */
- u16 reserved_1;
+#include <net/mac80211.h>
+
+#define DRIVER_NAME "wl1251"
+#define DRIVER_PREFIX DRIVER_NAME ": "
+
+enum {
+ DEBUG_NONE = 0,
+ DEBUG_IRQ = BIT(0),
+ DEBUG_SPI = BIT(1),
+ DEBUG_BOOT = BIT(2),
+ DEBUG_MAILBOX = BIT(3),
+ DEBUG_NETLINK = BIT(4),
+ DEBUG_EVENT = BIT(5),
+ DEBUG_TX = BIT(6),
+ DEBUG_RX = BIT(7),
+ DEBUG_SCAN = BIT(8),
+ DEBUG_CRYPT = BIT(9),
+ DEBUG_PSM = BIT(10),
+ DEBUG_MAC80211 = BIT(11),
+ DEBUG_CMD = BIT(12),
+ DEBUG_ACX = BIT(13),
+ DEBUG_ALL = ~0,
+};
+
+#define DEBUG_LEVEL (DEBUG_NONE)
+
+#define DEBUG_DUMP_LIMIT 1024
+
+#define wl1251_error(fmt, arg...) \
+ printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg)
+
+#define wl1251_warning(fmt, arg...) \
+ printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg)
+
+#define wl1251_notice(fmt, arg...) \
+ printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg)
+
+#define wl1251_info(fmt, arg...) \
+ printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg)
+
+#define wl1251_debug(level, fmt, arg...) \
+ do { \
+ if (level & DEBUG_LEVEL) \
+ printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \
+ } while (0)
+
+#define wl1251_dump(level, prefix, buf, len) \
+ do { \
+ if (level & DEBUG_LEVEL) \
+ print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
+ DUMP_PREFIX_OFFSET, 16, 1, \
+ buf, \
+ min_t(size_t, len, DEBUG_DUMP_LIMIT), \
+ 0); \
+ } while (0)
+
+#define wl1251_dump_ascii(level, prefix, buf, len) \
+ do { \
+ if (level & DEBUG_LEVEL) \
+ print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
+ DUMP_PREFIX_OFFSET, 16, 1, \
+ buf, \
+ min_t(size_t, len, DEBUG_DUMP_LIMIT), \
+ true); \
+ } while (0)
+
+#define WL1251_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \
+ CFG_BSSID_FILTER_EN)
+
+#define WL1251_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \
+ CFG_RX_MGMT_EN | \
+ CFG_RX_DATA_EN | \
+ CFG_RX_CTL_EN | \
+ CFG_RX_BCN_EN | \
+ CFG_RX_AUTH_EN | \
+ CFG_RX_ASSOC_EN)
+
+#define WL1251_BUSY_WORD_LEN 8
+
+struct boot_attr {
+ u32 radio_type;
+ u8 mac_clock;
+ u8 arm_clock;
+ int firmware_debug;
+ u32 minor;
+ u32 major;
+ u32 bugfix;
+};
+
+enum wl1251_state {
+ WL1251_STATE_OFF,
+ WL1251_STATE_ON,
+ WL1251_STATE_PLT,
+};
+
+enum wl1251_partition_type {
+ PART_DOWN,
+ PART_WORK,
+ PART_DRPW,
+
+ PART_TABLE_LEN
+};
+
+struct wl1251_partition {
+ u32 size;
+ u32 start;
+};
+
+struct wl1251_partition_set {
+ struct wl1251_partition mem;
+ struct wl1251_partition reg;
+};
+
+struct wl1251;
+
+/* FIXME: I'm not sure about this structure name */
+struct wl1251_chip {
+ u32 id;
+
+ const char *fw_filename;
+ const char *nvs_filename;
+
+ char fw_ver[21];
+
+ unsigned int power_on_sleep;
+ int intr_cmd_complete;
+ int intr_init_complete;
+
+ int (*op_upload_fw)(struct wl1251 *wl);
+ int (*op_upload_nvs)(struct wl1251 *wl);
+ int (*op_boot)(struct wl1251 *wl);
+ void (*op_set_ecpu_ctrl)(struct wl1251 *wl, u32 flag);
+ void (*op_target_enable_interrupts)(struct wl1251 *wl);
+ int (*op_hw_init)(struct wl1251 *wl);
+ int (*op_plt_init)(struct wl1251 *wl);
+ void (*op_tx_flush)(struct wl1251 *wl);
+ void (*op_fw_version)(struct wl1251 *wl);
+ int (*op_cmd_join)(struct wl1251 *wl, u8 bss_type, u8 dtim_interval,
+ u16 beacon_interval, u8 wait);
+
+ struct wl1251_partition_set *p_table;
+ enum wl12xx_acx_int_reg *acx_reg_table;
+};
+
+struct wl1251_stats {
+ struct acx_statistics *fw_stats;
+ unsigned long fw_stats_update;
+
+ unsigned int retry_count;
+ unsigned int excessive_retries;
+};
+
+struct wl1251_debugfs {
+ struct dentry *rootdir;
+ struct dentry *fw_statistics;
+
+ struct dentry *tx_internal_desc_overflow;
+
+ struct dentry *rx_out_of_mem;
+ struct dentry *rx_hdr_overflow;
+ struct dentry *rx_hw_stuck;
+ struct dentry *rx_dropped;
+ struct dentry *rx_fcs_err;
+ struct dentry *rx_xfr_hint_trig;
+ struct dentry *rx_path_reset;
+ struct dentry *rx_reset_counter;
+
+ struct dentry *dma_rx_requested;
+ struct dentry *dma_rx_errors;
+ struct dentry *dma_tx_requested;
+ struct dentry *dma_tx_errors;
+
+ struct dentry *isr_cmd_cmplt;
+ struct dentry *isr_fiqs;
+ struct dentry *isr_rx_headers;
+ struct dentry *isr_rx_mem_overflow;
+ struct dentry *isr_rx_rdys;
+ struct dentry *isr_irqs;
+ struct dentry *isr_tx_procs;
+ struct dentry *isr_decrypt_done;
+ struct dentry *isr_dma0_done;
+ struct dentry *isr_dma1_done;
+ struct dentry *isr_tx_exch_complete;
+ struct dentry *isr_commands;
+ struct dentry *isr_rx_procs;
+ struct dentry *isr_hw_pm_mode_changes;
+ struct dentry *isr_host_acknowledges;
+ struct dentry *isr_pci_pm;
+ struct dentry *isr_wakeups;
+ struct dentry *isr_low_rssi;
+
+ struct dentry *wep_addr_key_count;
+ struct dentry *wep_default_key_count;
+ /* skipping wep.reserved */
+ struct dentry *wep_key_not_found;
+ struct dentry *wep_decrypt_fail;
+ struct dentry *wep_packets;
+ struct dentry *wep_interrupt;
+
+ struct dentry *pwr_ps_enter;
+ struct dentry *pwr_elp_enter;
+ struct dentry *pwr_missing_bcns;
+ struct dentry *pwr_wake_on_host;
+ struct dentry *pwr_wake_on_timer_exp;
+ struct dentry *pwr_tx_with_ps;
+ struct dentry *pwr_tx_without_ps;
+ struct dentry *pwr_rcvd_beacons;
+ struct dentry *pwr_power_save_off;
+ struct dentry *pwr_enable_ps;
+ struct dentry *pwr_disable_ps;
+ struct dentry *pwr_fix_tsf_ps;
+ /* skipping cont_miss_bcns_spread for now */
+ struct dentry *pwr_rcvd_awake_beacons;
+
+ struct dentry *mic_rx_pkts;
+ struct dentry *mic_calc_failure;
+
+ struct dentry *aes_encrypt_fail;
+ struct dentry *aes_decrypt_fail;
+ struct dentry *aes_encrypt_packets;
+ struct dentry *aes_decrypt_packets;
+ struct dentry *aes_encrypt_interrupt;
+ struct dentry *aes_decrypt_interrupt;
+
+ struct dentry *event_heart_beat;
+ struct dentry *event_calibration;
+ struct dentry *event_rx_mismatch;
+ struct dentry *event_rx_mem_empty;
+ struct dentry *event_rx_pool;
+ struct dentry *event_oom_late;
+ struct dentry *event_phy_transmit_error;
+ struct dentry *event_tx_stuck;
+
+ struct dentry *ps_pspoll_timeouts;
+ struct dentry *ps_upsd_timeouts;
+ struct dentry *ps_upsd_max_sptime;
+ struct dentry *ps_upsd_max_apturn;
+ struct dentry *ps_pspoll_max_apturn;
+ struct dentry *ps_pspoll_utilization;
+ struct dentry *ps_upsd_utilization;
+
+ struct dentry *rxpipe_rx_prep_beacon_drop;
+ struct dentry *rxpipe_descr_host_int_trig_rx_data;
+ struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data;
+ struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data;
+ struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data;
+
+ struct dentry *tx_queue_len;
+
+ struct dentry *retry_count;
+ struct dentry *excessive_retries;
+};
+
+struct wl1251 {
+ struct ieee80211_hw *hw;
+ bool mac80211_registered;
+
+ struct spi_device *spi;
+
+ void (*set_power)(bool enable);
+ int irq;
+
+ enum wl1251_state state;
+ struct mutex mutex;
+
+ int physical_mem_addr;
+ int physical_reg_addr;
+ int virtual_mem_addr;
+ int virtual_reg_addr;
+
+ struct wl1251_chip chip;
+
+ int cmd_box_addr;
+ int event_box_addr;
+ struct boot_attr boot_attr;
+
+ u8 *fw;
+ size_t fw_len;
+ u8 *nvs;
+ size_t nvs_len;
+
+ u8 bssid[ETH_ALEN];
+ u8 mac_addr[ETH_ALEN];
+ u8 bss_type;
+ u8 listen_int;
+ int channel;
+
+ void *target_mem_map;
+ struct acx_data_path_params_resp *data_path;
+
+ /* Number of TX packets transferred to the FW, modulo 16 */
+ u32 data_in_count;
+
+ /* Frames scheduled for transmission, not handled yet */
+ struct sk_buff_head tx_queue;
+ bool tx_queue_stopped;
+
+ struct work_struct tx_work;
+ struct work_struct filter_work;
+
+ /* Pending TX frames */
+ struct sk_buff *tx_frames[16];
/*
- * Nmber of memory buffers for the RX mem pool.
- * The actual number may be less if there are
- * not enough blocks left for the minimum num
- * of TX ones.
+ * Index pointing to the next TX complete entry
+ * in the cyclic XT complete array we get from
+ * the FW.
*/
- u8 rx_mem_block_num;
- u8 reserved_2;
- u8 num_tx_queues; /* From 1 to 16 */
- u8 host_if_options; /* HOST_IF* */
- u8 tx_min_mem_block_num;
- u8 num_ssid_profiles;
- __le16 debug_buffer_size;
-} __attribute__ ((packed));
-
-
-#define ACX_RX_DESC_MIN 1
-#define ACX_RX_DESC_MAX 127
-#define ACX_RX_DESC_DEF 32
-struct wl1251_acx_rx_queue_config {
- u8 num_descs;
- u8 pad;
- u8 type;
- u8 priority;
- __le32 dma_address;
-} __attribute__ ((packed));
-
-#define ACX_TX_DESC_MIN 1
-#define ACX_TX_DESC_MAX 127
-#define ACX_TX_DESC_DEF 16
-struct wl1251_acx_tx_queue_config {
- u8 num_descs;
- u8 pad[2];
- u8 attributes;
-} __attribute__ ((packed));
-
-#define MAX_TX_QUEUE_CONFIGS 5
-#define MAX_TX_QUEUES 4
-struct wl1251_acx_config_memory {
- struct acx_header header;
-
- struct wl1251_acx_memory mem_config;
- struct wl1251_acx_rx_queue_config rx_queue_config;
- struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS];
-} __attribute__ ((packed));
-
-struct wl1251_acx_mem_map {
- struct acx_header header;
-
- void *code_start;
- void *code_end;
-
- void *wep_defkey_start;
- void *wep_defkey_end;
+ u32 next_tx_complete;
- void *sta_table_start;
- void *sta_table_end;
+ /* FW Rx counter */
+ u32 rx_counter;
- void *packet_template_start;
- void *packet_template_end;
+ /* Rx frames handled */
+ u32 rx_handled;
- void *queue_memory_start;
- void *queue_memory_end;
+ /* Current double buffer */
+ u32 rx_current_buffer;
+ u32 rx_last_id;
- void *packet_memory_pool_start;
- void *packet_memory_pool_end;
+ /* The target interrupt mask */
+ u32 intr_mask;
+ struct work_struct irq_work;
- void *debug_buffer1_start;
- void *debug_buffer1_end;
+ /* The mbox event mask */
+ u32 event_mask;
- void *debug_buffer2_start;
- void *debug_buffer2_end;
+ /* Mailbox pointers */
+ u32 mbox_ptr[2];
- /* Number of blocks FW allocated for TX packets */
- u32 num_tx_mem_blocks;
+ /* Are we currently scanning */
+ bool scanning;
- /* Number of blocks FW allocated for RX packets */
- u32 num_rx_mem_blocks;
-} __attribute__ ((packed));
+ /* Our association ID */
+ u16 aid;
-/*************************************************************************
+ /* Default key (for WEP) */
+ u32 default_key;
- Host Interrupt Register (WiLink -> Host)
+ unsigned int tx_mgmt_frm_rate;
+ unsigned int tx_mgmt_frm_mod;
-**************************************************************************/
+ unsigned int rx_config;
+ unsigned int rx_filter;
-/* RX packet is ready in Xfer buffer #0 */
-#define WL1251_ACX_INTR_RX0_DATA BIT(0)
+ /* is firmware in elp mode */
+ bool elp;
-/* TX result(s) are in the TX complete buffer */
-#define WL1251_ACX_INTR_TX_RESULT BIT(1)
+ /* we can be in psm, but not in elp, we have to differentiate */
+ bool psm;
-/* OBSOLETE */
-#define WL1251_ACX_INTR_TX_XFR BIT(2)
+ /* PSM mode requested */
+ bool psm_requested;
-/* RX packet is ready in Xfer buffer #1 */
-#define WL1251_ACX_INTR_RX1_DATA BIT(3)
+ /* in dBm */
+ int power_level;
-/* Event was entered to Event MBOX #A */
-#define WL1251_ACX_INTR_EVENT_A BIT(4)
+ struct wl1251_stats stats;
+ struct wl1251_debugfs debugfs;
-/* Event was entered to Event MBOX #B */
-#define WL1251_ACX_INTR_EVENT_B BIT(5)
+ u32 buffer_32;
+ u32 buffer_cmd;
+ u8 buffer_busyword[WL1251_BUSY_WORD_LEN];
+ struct wl1251_rx_descriptor *rx_descriptor;
+};
-/* OBSOLETE */
-#define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6)
+int wl1251_plt_start(struct wl1251 *wl);
+int wl1251_plt_stop(struct wl1251 *wl);
-/* Trace meassge on MBOX #A */
-#define WL1251_ACX_INTR_TRACE_A BIT(7)
+#define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */
+#define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS
+#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */
-/* Trace meassge on MBOX #B */
-#define WL1251_ACX_INTR_TRACE_B BIT(8)
+#define WL1251_DEFAULT_POWER_LEVEL 20
-/* Command processing completion */
-#define WL1251_ACX_INTR_CMD_COMPLETE BIT(9)
+#define WL1251_TX_QUEUE_MAX_LENGTH 20
-/* Init sequence is done */
-#define WL1251_ACX_INTR_INIT_COMPLETE BIT(14)
+/* Different chips need different sleep times after power on. WL1271 needs
+ * 200ms, WL1251 needs only 10ms. By default we use 200ms, but as soon as we
+ * know the chip ID, we change the sleep value in the wl1251 chip structure,
+ * so in subsequent power ons, we don't waste more time then needed. */
+#define WL1251_DEFAULT_POWER_ON_SLEEP 200
-#define WL1251_ACX_INTR_ALL 0xFFFFFFFF
+#define CHIP_ID_1251_PG10 (0x7010101)
+#define CHIP_ID_1251_PG11 (0x7020101)
+#define CHIP_ID_1251_PG12 (0x7030101)
+#define CHIP_ID_1271_PG10 (0x4030101)
+#define CHIP_ID_1271_PG20 (0x4030111)
#endif
diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c
new file mode 100644
index 000000000000..a46c92a29526
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1251_acx.c
@@ -0,0 +1,840 @@
+#include "wl1251_acx.h"
+
+#include <linux/module.h>
+#include <linux/crc7.h>
+#include <linux/spi/spi.h>
+
+#include "wl1251.h"
+#include "reg.h"
+#include "wl1251_spi.h"
+#include "wl1251_ps.h"
+
+int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod,
+ u8 mgt_rate, u8 mgt_mod)
+{
+ struct acx_fw_gen_frame_rates *rates;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx frame rates");
+
+ rates = kzalloc(sizeof(*rates), GFP_KERNEL);
+ if (!rates) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ rates->tx_ctrl_frame_rate = ctrl_rate;
+ rates->tx_ctrl_frame_mod = ctrl_mod;
+ rates->tx_mgt_frame_rate = mgt_rate;
+ rates->tx_mgt_frame_mod = mgt_mod;
+
+ ret = wl1251_cmd_configure(wl, ACX_FW_GEN_FRAME_RATES,
+ rates, sizeof(*rates));
+ if (ret < 0) {
+ wl1251_error("Failed to set FW rates and modulation");
+ goto out;
+ }
+
+out:
+ kfree(rates);
+ return ret;
+}
+
+
+int wl1251_acx_station_id(struct wl1251 *wl)
+{
+ struct acx_dot11_station_id *mac;
+ int ret, i;
+
+ wl1251_debug(DEBUG_ACX, "acx dot11_station_id");
+
+ mac = kzalloc(sizeof(*mac), GFP_KERNEL);
+ if (!mac) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < ETH_ALEN; i++)
+ mac->mac[i] = wl->mac_addr[ETH_ALEN - 1 - i];
+
+ ret = wl1251_cmd_configure(wl, DOT11_STATION_ID, mac, sizeof(*mac));
+ if (ret < 0)
+ goto out;
+
+out:
+ kfree(mac);
+ return ret;
+}
+
+int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id)
+{
+ struct acx_dot11_default_key *default_key;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id);
+
+ default_key = kzalloc(sizeof(*default_key), GFP_KERNEL);
+ if (!default_key) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ default_key->id = key_id;
+
+ ret = wl1251_cmd_configure(wl, DOT11_DEFAULT_KEY,
+ default_key, sizeof(*default_key));
+ if (ret < 0) {
+ wl1251_error("Couldn't set default key");
+ goto out;
+ }
+
+ wl->default_key = key_id;
+
+out:
+ kfree(default_key);
+ return ret;
+}
+
+int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event,
+ u8 listen_interval)
+{
+ struct acx_wake_up_condition *wake_up;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx wake up conditions");
+
+ wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL);
+ if (!wake_up) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wake_up->wake_up_event = wake_up_event;
+ wake_up->listen_interval = listen_interval;
+
+ ret = wl1251_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS,
+ wake_up, sizeof(*wake_up));
+ if (ret < 0) {
+ wl1251_warning("could not set wake up conditions: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(wake_up);
+ return ret;
+}
+
+int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth)
+{
+ struct acx_sleep_auth *auth;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx sleep auth");
+
+ auth = kzalloc(sizeof(*auth), GFP_KERNEL);
+ if (!auth) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ auth->sleep_auth = sleep_auth;
+
+ ret = wl1251_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth));
+ if (ret < 0)
+ return ret;
+
+out:
+ kfree(auth);
+ return ret;
+}
+
+int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len)
+{
+ struct acx_revision *rev;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx fw rev");
+
+ rev = kzalloc(sizeof(*rev), GFP_KERNEL);
+ if (!rev) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = wl1251_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev));
+ if (ret < 0) {
+ wl1251_warning("ACX_FW_REV interrogate failed");
+ goto out;
+ }
+
+ /* be careful with the buffer sizes */
+ strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version)));
+
+ /*
+ * if the firmware version string is exactly
+ * sizeof(rev->fw_version) long or fw_len is less than
+ * sizeof(rev->fw_version) it won't be null terminated
+ */
+ buf[min(len, sizeof(rev->fw_version)) - 1] = '\0';
+
+out:
+ kfree(rev);
+ return ret;
+}
+
+int wl1251_acx_tx_power(struct wl1251 *wl, int power)
+{
+ struct acx_current_tx_power *acx;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr");
+
+ if (power < 0 || power > 25)
+ return -EINVAL;
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->current_tx_power = power * 10;
+
+ ret = wl1251_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_warning("configure of tx power failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1251_acx_feature_cfg(struct wl1251 *wl)
+{
+ struct acx_feature_config *feature;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx feature cfg");
+
+ feature = kzalloc(sizeof(*feature), GFP_KERNEL);
+ if (!feature) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */
+ feature->data_flow_options = 0;
+ feature->options = 0;
+
+ ret = wl1251_cmd_configure(wl, ACX_FEATURE_CFG,
+ feature, sizeof(*feature));
+ if (ret < 0) {
+ wl1251_error("Couldn't set HW encryption");
+ goto out;
+ }
+
+out:
+ kfree(feature);
+ return ret;
+}
+
+int wl1251_acx_mem_map(struct wl1251 *wl, struct acx_header *mem_map,
+ size_t len)
+{
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx mem map");
+
+ ret = wl1251_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int wl1251_acx_data_path_params(struct wl1251 *wl,
+ struct acx_data_path_params_resp *resp)
+{
+ struct acx_data_path_params *params;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx data path params");
+
+ params = kzalloc(sizeof(*params), GFP_KERNEL);
+ if (!params) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ params->rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE;
+ params->tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE;
+
+ params->rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM;
+ params->tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM;
+
+ params->tx_complete_threshold = 1;
+
+ params->tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE;
+
+ params->tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT;
+
+ ret = wl1251_cmd_configure(wl, ACX_DATA_PATH_PARAMS,
+ params, sizeof(*params));
+ if (ret < 0)
+ goto out;
+
+ /* FIXME: shouldn't this be ACX_DATA_PATH_RESP_PARAMS? */
+ ret = wl1251_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS,
+ resp, sizeof(*resp));
+
+ if (ret < 0) {
+ wl1251_warning("failed to read data path parameters: %d", ret);
+ goto out;
+ } else if (resp->header.cmd.status != CMD_STATUS_SUCCESS) {
+ wl1251_warning("data path parameter acx status failed");
+ ret = -EIO;
+ goto out;
+ }
+
+out:
+ kfree(params);
+ return ret;
+}
+
+int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time)
+{
+ struct acx_rx_msdu_lifetime *acx;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx rx msdu life time");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->lifetime = life_time;
+ ret = wl1251_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME,
+ acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_warning("failed to set rx msdu life time: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter)
+{
+ struct acx_rx_config *rx_config;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx rx config");
+
+ rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL);
+ if (!rx_config) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ rx_config->config_options = config;
+ rx_config->filter_options = filter;
+
+ ret = wl1251_cmd_configure(wl, ACX_RX_CFG,
+ rx_config, sizeof(*rx_config));
+ if (ret < 0) {
+ wl1251_warning("failed to set rx config: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(rx_config);
+ return ret;
+}
+
+int wl1251_acx_pd_threshold(struct wl1251 *wl)
+{
+ struct acx_packet_detection *pd;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx data pd threshold");
+
+ pd = kzalloc(sizeof(*pd), GFP_KERNEL);
+ if (!pd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* FIXME: threshold value not set */
+
+ ret = wl1251_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd));
+ if (ret < 0) {
+ wl1251_warning("failed to set pd threshold: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(pd);
+ return 0;
+}
+
+int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time)
+{
+ struct acx_slot *slot;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx slot");
+
+ slot = kzalloc(sizeof(*slot), GFP_KERNEL);
+ if (!slot) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ slot->wone_index = STATION_WONE_INDEX;
+ slot->slot_time = slot_time;
+
+ ret = wl1251_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot));
+ if (ret < 0) {
+ wl1251_warning("failed to set slot time: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(slot);
+ return ret;
+}
+
+int wl1251_acx_group_address_tbl(struct wl1251 *wl)
+{
+ struct acx_dot11_grp_addr_tbl *acx;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx group address tbl");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* MAC filtering */
+ acx->enabled = 0;
+ acx->num_groups = 0;
+ memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN);
+
+ ret = wl1251_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL,
+ acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_warning("failed to set group addr table: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1251_acx_service_period_timeout(struct wl1251 *wl)
+{
+ struct acx_rx_timeout *rx_timeout;
+ int ret;
+
+ rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL);
+ if (!rx_timeout) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wl1251_debug(DEBUG_ACX, "acx service period timeout");
+
+ rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF;
+ rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF;
+
+ ret = wl1251_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT,
+ rx_timeout, sizeof(*rx_timeout));
+ if (ret < 0) {
+ wl1251_warning("failed to set service period timeout: %d",
+ ret);
+ goto out;
+ }
+
+out:
+ kfree(rx_timeout);
+ return ret;
+}
+
+int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold)
+{
+ struct acx_rts_threshold *rts;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx rts threshold");
+
+ rts = kzalloc(sizeof(*rts), GFP_KERNEL);
+ if (!rts) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ rts->threshold = rts_threshold;
+
+ ret = wl1251_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts));
+ if (ret < 0) {
+ wl1251_warning("failed to set rts threshold: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(rts);
+ return ret;
+}
+
+int wl1251_acx_beacon_filter_opt(struct wl1251 *wl)
+{
+ struct acx_beacon_filter_option *beacon_filter;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx beacon filter opt");
+
+ beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL);
+ if (!beacon_filter) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ beacon_filter->enable = 0;
+ beacon_filter->max_num_beacons = 0;
+
+ ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_OPT,
+ beacon_filter, sizeof(*beacon_filter));
+ if (ret < 0) {
+ wl1251_warning("failed to set beacon filter opt: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(beacon_filter);
+ return ret;
+}
+
+int wl1251_acx_beacon_filter_table(struct wl1251 *wl)
+{
+ struct acx_beacon_filter_ie_table *ie_table;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx beacon filter table");
+
+ ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL);
+ if (!ie_table) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ie_table->num_ie = 0;
+ memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE);
+
+ ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_TABLE,
+ ie_table, sizeof(*ie_table));
+ if (ret < 0) {
+ wl1251_warning("failed to set beacon filter table: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(ie_table);
+ return ret;
+}
+
+int wl1251_acx_sg_enable(struct wl1251 *wl)
+{
+ struct acx_bt_wlan_coex *pta;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx sg enable");
+
+ pta = kzalloc(sizeof(*pta), GFP_KERNEL);
+ if (!pta) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ pta->enable = SG_ENABLE;
+
+ ret = wl1251_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta));
+ if (ret < 0) {
+ wl1251_warning("failed to set softgemini enable: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(pta);
+ return ret;
+}
+
+int wl1251_acx_sg_cfg(struct wl1251 *wl)
+{
+ struct acx_bt_wlan_coex_param *param;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx sg cfg");
+
+ param = kzalloc(sizeof(*param), GFP_KERNEL);
+ if (!param) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* BT-WLAN coext parameters */
+ param->min_rate = RATE_INDEX_24MBPS;
+ param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF;
+ param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF;
+ param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF;
+ param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF;
+ param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF;
+ param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF;
+ param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF;
+ param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF;
+ param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF;
+ param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF;
+ param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF;
+ param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF;
+ param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF;
+ param->antenna_type = PTA_ANTENNA_TYPE_DEF;
+ param->signal_type = PTA_SIGNALING_TYPE_DEF;
+ param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF;
+ param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF;
+ param->max_cts = PTA_MAX_NUM_CTS_DEF;
+ param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF;
+ param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF;
+ param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF;
+ param->wlan_elp_hp = PTA_ELP_HP_DEF;
+ param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF;
+ param->ack_mode_dual_ant = PTA_ACK_MODE_DEF;
+ param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF;
+ param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF;
+ param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF;
+
+ ret = wl1251_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
+ if (ret < 0) {
+ wl1251_warning("failed to set sg config: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(param);
+ return ret;
+}
+
+int wl1251_acx_cca_threshold(struct wl1251 *wl)
+{
+ struct acx_energy_detection *detection;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx cca threshold");
+
+ detection = kzalloc(sizeof(*detection), GFP_KERNEL);
+ if (!detection) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D;
+ detection->tx_energy_detection = 0;
+
+ ret = wl1251_cmd_configure(wl, ACX_CCA_THRESHOLD,
+ detection, sizeof(*detection));
+ if (ret < 0) {
+ wl1251_warning("failed to set cca threshold: %d", ret);
+ return ret;
+ }
+
+out:
+ kfree(detection);
+ return ret;
+}
+
+int wl1251_acx_bcn_dtim_options(struct wl1251 *wl)
+{
+ struct acx_beacon_broadcast *bb;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx bcn dtim options");
+
+ bb = kzalloc(sizeof(*bb), GFP_KERNEL);
+ if (!bb) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE;
+ bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE;
+ bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE;
+ bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF;
+
+ ret = wl1251_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb));
+ if (ret < 0) {
+ wl1251_warning("failed to set rx config: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(bb);
+ return ret;
+}
+
+int wl1251_acx_aid(struct wl1251 *wl, u16 aid)
+{
+ struct acx_aid *acx_aid;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx aid");
+
+ acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL);
+ if (!acx_aid) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx_aid->aid = aid;
+
+ ret = wl1251_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid));
+ if (ret < 0) {
+ wl1251_warning("failed to set aid: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx_aid);
+ return ret;
+}
+
+int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask)
+{
+ struct acx_event_mask *mask;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx event mbox mask");
+
+ mask = kzalloc(sizeof(*mask), GFP_KERNEL);
+ if (!mask) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* high event mask is unused */
+ mask->high_event_mask = 0xffffffff;
+
+ mask->event_mask = event_mask;
+
+ ret = wl1251_cmd_configure(wl, ACX_EVENT_MBOX_MASK,
+ mask, sizeof(*mask));
+ if (ret < 0) {
+ wl1251_warning("failed to set acx_event_mbox_mask: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(mask);
+ return ret;
+}
+
+int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble)
+{
+ struct acx_preamble *acx;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx_set_preamble");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->preamble = preamble;
+
+ ret = wl1251_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_warning("Setting of preamble failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1251_acx_cts_protect(struct wl1251 *wl,
+ enum acx_ctsprotect_type ctsprotect)
+{
+ struct acx_ctsprotect *acx;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx_set_ctsprotect");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->ctsprotect = ctsprotect;
+
+ ret = wl1251_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_warning("Setting of ctsprotect failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime)
+{
+ struct acx_tsf_info *tsf_info;
+ int ret;
+
+ tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL);
+ if (!tsf_info) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = wl1251_cmd_interrogate(wl, ACX_TSF_INFO,
+ tsf_info, sizeof(*tsf_info));
+ if (ret < 0) {
+ wl1251_warning("ACX_FW_REV interrogate failed");
+ goto out;
+ }
+
+ *mactime = tsf_info->current_tsf_lsb |
+ (tsf_info->current_tsf_msb << 31);
+
+out:
+ kfree(tsf_info);
+ return ret;
+}
+
+int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats)
+{
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx statistics");
+
+ ret = wl1251_cmd_interrogate(wl, ACX_STATISTICS, stats,
+ sizeof(*stats));
+ if (ret < 0) {
+ wl1251_warning("acx statistics failed: %d", ret);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h
index fb2d2340993c..2e7b1933a8f9 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_acx.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,14 +22,20 @@
*
*/
-#ifndef __WL12XX_ACX_H__
-#define __WL12XX_ACX_H__
+#ifndef __WL1251_ACX_H__
+#define __WL1251_ACX_H__
-#include "wl12xx.h"
+#include "wl1251.h"
+#include "wl1251_cmd.h"
/* Target's information element */
struct acx_header {
+ struct wl1251_cmd_header cmd;
+
+ /* acx (or information element) header */
u16 id;
+
+ /* payload length (not including headers */
u16 len;
};
@@ -85,15 +91,15 @@ struct acx_revision {
u32 hw_version;
} __attribute__ ((packed));
-enum wl12xx_psm_mode {
+enum wl1251_psm_mode {
/* Active mode */
- WL12XX_PSM_CAM = 0,
+ WL1251_PSM_CAM = 0,
/* Power save mode */
- WL12XX_PSM_PS = 1,
+ WL1251_PSM_PS = 1,
/* Extreme low power */
- WL12XX_PSM_ELP = 2,
+ WL1251_PSM_ELP = 2,
};
struct acx_sleep_auth {
@@ -107,25 +113,6 @@ struct acx_sleep_auth {
u8 padding[3];
} __attribute__ ((packed));
-#define TIM_ELE_ID 5
-#define PARTIAL_VBM_MAX 251
-
-struct tim {
- u8 identity;
- u8 length;
- u8 dtim_count;
- u8 dtim_period;
- u8 bitmap_ctrl;
- u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */
-} __attribute__ ((packed));
-
-/* Virtual Bit Map update */
-struct vbm_update_request {
- __le16 len;
- u8 padding[2];
- struct tim tim;
-} __attribute__ ((packed));
-
enum {
HOSTIF_PCI_MASTER_HOST_INDIRECT,
HOSTIF_PCI_MASTER_HOST_DIRECT,
@@ -202,7 +189,7 @@ struct acx_data_path_params_resp {
#define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF
#define RX_MSDU_LIFETIME_DEF 512000
-struct rx_msdu_lifetime {
+struct acx_rx_msdu_lifetime {
struct acx_header header;
/*
@@ -368,7 +355,7 @@ struct acx_slot {
#define ADDRESS_GROUP_MAX (8)
#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX)
-struct multicast_grp_addr_start {
+struct acx_dot11_grp_addr_tbl {
struct acx_header header;
u8 enabled;
@@ -730,22 +717,13 @@ struct acx_fw_gen_frame_rates {
} __attribute__ ((packed));
/* STA MAC */
-struct dot11_station_id {
+struct acx_dot11_station_id {
struct acx_header header;
u8 mac[ETH_ALEN];
u8 pad[2];
} __attribute__ ((packed));
-/* HW encryption keys */
-#define NUM_ACCESS_CATEGORIES_COPY 4
-#define MAX_KEY_SIZE 32
-
-/* When set, disable HW encryption */
-#define DF_ENCRYPTION_DISABLE 0x01
-/* When set, disable HW decryption */
-#define DF_SNIFF_MODE_ENABLE 0x80
-
struct acx_feature_config {
struct acx_header header;
@@ -753,67 +731,6 @@ struct acx_feature_config {
u32 data_flow_options;
} __attribute__ ((packed));
-enum acx_key_action {
- KEY_ADD_OR_REPLACE = 1,
- KEY_REMOVE = 2,
- KEY_SET_ID = 3,
- MAX_KEY_ACTION = 0xffff,
-};
-
-enum acx_key_type {
- KEY_WEP_DEFAULT = 0,
- KEY_WEP_ADDR = 1,
- KEY_AES_GROUP = 4,
- KEY_AES_PAIRWISE = 5,
- KEY_WEP_GROUP = 6,
- KEY_TKIP_MIC_GROUP = 10,
- KEY_TKIP_MIC_PAIRWISE = 11,
-};
-
-/*
- *
- * key_type_e key size key format
- * ---------- --------- ----------
- * 0x00 5, 13, 29 Key data
- * 0x01 5, 13, 29 Key data
- * 0x04 16 16 bytes of key data
- * 0x05 16 16 bytes of key data
- * 0x0a 32 16 bytes of TKIP key data
- * 8 bytes of RX MIC key data
- * 8 bytes of TX MIC key data
- * 0x0b 32 16 bytes of TKIP key data
- * 8 bytes of RX MIC key data
- * 8 bytes of TX MIC key data
- *
- */
-
-struct acx_set_key {
- /* Ignored for default WEP key */
- u8 addr[ETH_ALEN];
-
- /* key_action_e */
- u16 key_action;
-
- u16 reserved_1;
-
- /* key size in bytes */
- u8 key_size;
-
- /* key_type_e */
- u8 key_type;
- u8 ssid_profile;
-
- /*
- * TKIP, AES: frame's key id field.
- * For WEP default key: key id;
- */
- u8 id;
- u8 reserved_2[6];
- u8 key[MAX_KEY_SIZE];
- u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
- u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
-} __attribute__ ((packed));
-
struct acx_current_tx_power {
struct acx_header header;
@@ -839,26 +756,6 @@ struct acx_tsf_info {
u8 pad[3];
} __attribute__ ((packed));
-/* 802.11 PS */
-enum acx_ps_mode {
- STATION_ACTIVE_MODE,
- STATION_POWER_SAVE_MODE
-};
-
-struct acx_ps_params {
- u8 ps_mode; /* STATION_* */
- u8 send_null_data; /* Do we have to send NULL data packet ? */
- u8 retries; /* Number of retires for the initial NULL data packet */
-
- /*
- * TUs during which the target stays awake after switching
- * to power save mode.
- */
- u8 hang_over_period;
- u16 null_data_rate;
- u8 pad[2];
-} __attribute__ ((packed));
-
enum acx_wake_up_event {
WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/
WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/
@@ -892,6 +789,7 @@ enum acx_preamble_type {
struct acx_preamble {
struct acx_header header;
+
/*
* When set, the WiLink transmits the frames with a short preamble and
* when cleared, the WiLink transmits the frames with a long preamble.
@@ -1210,36 +1108,39 @@ enum {
};
-int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod,
+int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod,
u8 mgt_rate, u8 mgt_mod);
-int wl12xx_acx_station_id(struct wl12xx *wl);
-int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id);
-int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval);
-int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth);
-int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len);
-int wl12xx_acx_tx_power(struct wl12xx *wl, int power);
-int wl12xx_acx_feature_cfg(struct wl12xx *wl);
-int wl12xx_acx_mem_map(struct wl12xx *wl, void *mem_map, size_t len);
-int wl12xx_acx_data_path_params(struct wl12xx *wl,
+int wl1251_acx_station_id(struct wl1251 *wl);
+int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id);
+int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event,
+ u8 listen_interval);
+int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth);
+int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len);
+int wl1251_acx_tx_power(struct wl1251 *wl, int power);
+int wl1251_acx_feature_cfg(struct wl1251 *wl);
+int wl1251_acx_mem_map(struct wl1251 *wl,
+ struct acx_header *mem_map, size_t len);
+int wl1251_acx_data_path_params(struct wl1251 *wl,
struct acx_data_path_params_resp *data_path);
-int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time);
-int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter);
-int wl12xx_acx_pd_threshold(struct wl12xx *wl);
-int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time);
-int wl12xx_acx_group_address_tbl(struct wl12xx *wl);
-int wl12xx_acx_service_period_timeout(struct wl12xx *wl);
-int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold);
-int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl);
-int wl12xx_acx_beacon_filter_table(struct wl12xx *wl);
-int wl12xx_acx_sg_enable(struct wl12xx *wl);
-int wl12xx_acx_sg_cfg(struct wl12xx *wl);
-int wl12xx_acx_cca_threshold(struct wl12xx *wl);
-int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl);
-int wl12xx_acx_aid(struct wl12xx *wl, u16 aid);
-int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask);
-int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble);
-int wl12xx_acx_cts_protect(struct wl12xx *wl,
+int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time);
+int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter);
+int wl1251_acx_pd_threshold(struct wl1251 *wl);
+int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time);
+int wl1251_acx_group_address_tbl(struct wl1251 *wl);
+int wl1251_acx_service_period_timeout(struct wl1251 *wl);
+int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold);
+int wl1251_acx_beacon_filter_opt(struct wl1251 *wl);
+int wl1251_acx_beacon_filter_table(struct wl1251 *wl);
+int wl1251_acx_sg_enable(struct wl1251 *wl);
+int wl1251_acx_sg_cfg(struct wl1251 *wl);
+int wl1251_acx_cca_threshold(struct wl1251 *wl);
+int wl1251_acx_bcn_dtim_options(struct wl1251 *wl);
+int wl1251_acx_aid(struct wl1251 *wl, u16 aid);
+int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask);
+int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble);
+int wl1251_acx_cts_protect(struct wl1251 *wl,
enum acx_ctsprotect_type ctsprotect);
-int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats);
+int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats);
+int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime);
-#endif /* __WL12XX_ACX_H__ */
+#endif /* __WL1251_ACX_H__ */
diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c
index 48ac08c429bd..d8a155dc2fa1 100644
--- a/drivers/net/wireless/wl12xx/boot.c
+++ b/drivers/net/wireless/wl12xx/wl1251_boot.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2008 Nokia Corporation
*
@@ -24,41 +24,41 @@
#include <linux/gpio.h>
#include "reg.h"
-#include "boot.h"
-#include "spi.h"
-#include "event.h"
+#include "wl1251_boot.h"
+#include "wl1251_spi.h"
+#include "wl1251_event.h"
-static void wl12xx_boot_enable_interrupts(struct wl12xx *wl)
+static void wl1251_boot_enable_interrupts(struct wl1251 *wl)
{
enable_irq(wl->irq);
}
-void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl)
+void wl1251_boot_target_enable_interrupts(struct wl1251 *wl)
{
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
- wl12xx_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
+ wl1251_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
}
-int wl12xx_boot_soft_reset(struct wl12xx *wl)
+int wl1251_boot_soft_reset(struct wl1251 *wl)
{
unsigned long timeout;
u32 boot_data;
/* perform soft reset */
- wl12xx_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
+ wl1251_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
/* SOFT_RESET is self clearing */
timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
while (1) {
- boot_data = wl12xx_reg_read32(wl, ACX_REG_SLV_SOFT_RESET);
- wl12xx_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
+ boot_data = wl1251_reg_read32(wl, ACX_REG_SLV_SOFT_RESET);
+ wl1251_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
break;
if (time_after(jiffies, timeout)) {
/* 1.2 check pWhalBus->uSelfClearTime if the
* timeout was reached */
- wl12xx_error("soft reset timeout");
+ wl1251_error("soft reset timeout");
return -1;
}
@@ -66,15 +66,15 @@ int wl12xx_boot_soft_reset(struct wl12xx *wl)
}
/* disable Rx/Tx */
- wl12xx_reg_write32(wl, ENABLE, 0x0);
+ wl1251_reg_write32(wl, ENABLE, 0x0);
/* disable auto calibration on start*/
- wl12xx_reg_write32(wl, SPARE_A2, 0xffff);
+ wl1251_reg_write32(wl, SPARE_A2, 0xffff);
return 0;
}
-int wl12xx_boot_init_seq(struct wl12xx *wl)
+int wl1251_boot_init_seq(struct wl1251 *wl)
{
u32 scr_pad6, init_data, tmp, elp_cmd, ref_freq;
@@ -96,23 +96,23 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
};
/* read NVS params */
- scr_pad6 = wl12xx_reg_read32(wl, SCR_PAD6);
- wl12xx_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6);
+ scr_pad6 = wl1251_reg_read32(wl, SCR_PAD6);
+ wl1251_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6);
/* read ELP_CMD */
- elp_cmd = wl12xx_reg_read32(wl, ELP_CMD);
- wl12xx_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd);
+ elp_cmd = wl1251_reg_read32(wl, ELP_CMD);
+ wl1251_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd);
/* set the BB calibration time to be 300 usec (PLL_CAL_TIME) */
ref_freq = scr_pad6 & 0x000000FF;
- wl12xx_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq);
+ wl1251_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq);
- wl12xx_reg_write32(wl, PLL_CAL_TIME, 0x9);
+ wl1251_reg_write32(wl, PLL_CAL_TIME, 0x9);
/*
* PG 1.2: set the clock buffer time to be 210 usec (CLK_BUF_TIME)
*/
- wl12xx_reg_write32(wl, CLK_BUF_TIME, 0x6);
+ wl1251_reg_write32(wl, CLK_BUF_TIME, 0x6);
/*
* set the clock detect feature to work in the restart wu procedure
@@ -120,18 +120,18 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
* (ELP_CFG_MODE[13:12])
*/
tmp = ((scr_pad6 & 0x0000FF00) << 4) | 0x00004000;
- wl12xx_reg_write32(wl, ELP_CFG_MODE, tmp);
+ wl1251_reg_write32(wl, ELP_CFG_MODE, tmp);
/* PG 1.2: enable the BB PLL fix. Enable the PLL_LIMP_CLK_EN_CMD */
elp_cmd |= 0x00000040;
- wl12xx_reg_write32(wl, ELP_CMD, elp_cmd);
+ wl1251_reg_write32(wl, ELP_CMD, elp_cmd);
/* PG 1.2: Set the BB PLL stable time to be 1000usec
* (PLL_STABLE_TIME) */
- wl12xx_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20);
+ wl1251_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20);
/* PG 1.2: read clock request time */
- init_data = wl12xx_reg_read32(wl, CLK_REQ_TIME);
+ init_data = wl1251_reg_read32(wl, CLK_REQ_TIME);
/*
* PG 1.2: set the clock request time to be ref_clk_settling_time -
@@ -141,35 +141,35 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
tmp = init_data - 0x21;
else
tmp = 0;
- wl12xx_reg_write32(wl, CLK_REQ_TIME, tmp);
+ wl1251_reg_write32(wl, CLK_REQ_TIME, tmp);
/* set BB PLL configurations in RF AFE */
- wl12xx_reg_write32(wl, 0x003058cc, 0x4B5);
+ wl1251_reg_write32(wl, 0x003058cc, 0x4B5);
/* set RF_AFE_REG_5 */
- wl12xx_reg_write32(wl, 0x003058d4, 0x50);
+ wl1251_reg_write32(wl, 0x003058d4, 0x50);
/* set RF_AFE_CTRL_REG_2 */
- wl12xx_reg_write32(wl, 0x00305948, 0x11c001);
+ wl1251_reg_write32(wl, 0x00305948, 0x11c001);
/*
* change RF PLL and BB PLL divider for VCO clock and adjust VCO
* bais current(RF_AFE_REG_13)
*/
- wl12xx_reg_write32(wl, 0x003058f4, 0x1e);
+ wl1251_reg_write32(wl, 0x003058f4, 0x1e);
/* set BB PLL configurations */
tmp = LUT[ref_freq][LUT_PARAM_INTEGER_DIVIDER] | 0x00017000;
- wl12xx_reg_write32(wl, 0x00305840, tmp);
+ wl1251_reg_write32(wl, 0x00305840, tmp);
/* set fractional divider according to Appendix C-BB PLL
* Calculations
*/
tmp = LUT[ref_freq][LUT_PARAM_FRACTIONAL_DIVIDER];
- wl12xx_reg_write32(wl, 0x00305844, tmp);
+ wl1251_reg_write32(wl, 0x00305844, tmp);
/* set the initial data for the sigma delta */
- wl12xx_reg_write32(wl, 0x00305848, 0x3039);
+ wl1251_reg_write32(wl, 0x00305848, 0x3039);
/*
* set the accumulator attenuation value, calibration loop1
@@ -178,14 +178,14 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
*/
tmp = (LUT[ref_freq][LUT_PARAM_ATTN_BB] << 16) |
(LUT[ref_freq][LUT_PARAM_ALPHA_BB] << 12) | 0x1;
- wl12xx_reg_write32(wl, 0x00305854, tmp);
+ wl1251_reg_write32(wl, 0x00305854, tmp);
/*
* set the calibration stop time after holdoff time expires and set
* settling time HOLD_OFF_TIME_BB
*/
tmp = LUT[ref_freq][LUT_PARAM_STOP_TIME_BB] | 0x000A0000;
- wl12xx_reg_write32(wl, 0x00305858, tmp);
+ wl1251_reg_write32(wl, 0x00305858, tmp);
/*
* set BB PLL Loop filter capacitor3- BB_C3[2:0] and set BB PLL
@@ -193,7 +193,7 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
* BB_ILOOPF[7:3]
*/
tmp = LUT[ref_freq][LUT_PARAM_BB_PLL_LOOP_FILTER] | 0x00000030;
- wl12xx_reg_write32(wl, 0x003058f8, tmp);
+ wl1251_reg_write32(wl, 0x003058f8, tmp);
/*
* set regulator output voltage for n divider to
@@ -201,10 +201,10 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
* set BB PLL Loop filter capacitor2- BB_C2[7:5], set gain of BB
* PLL auto-call to normal mode- BB_CALGAIN_3DB[8]
*/
- wl12xx_reg_write32(wl, 0x003058f0, 0x29);
+ wl1251_reg_write32(wl, 0x003058f0, 0x29);
/* enable restart wakeup sequence (ELP_CMD[0]) */
- wl12xx_reg_write32(wl, ELP_CMD, elp_cmd | 0x1);
+ wl1251_reg_write32(wl, ELP_CMD, elp_cmd | 0x1);
/* restart sequence completed */
udelay(2000);
@@ -212,19 +212,19 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
return 0;
}
-int wl12xx_boot_run_firmware(struct wl12xx *wl)
+int wl1251_boot_run_firmware(struct wl1251 *wl)
{
int loop, ret;
u32 chip_id, interrupt;
wl->chip.op_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
- chip_id = wl12xx_reg_read32(wl, CHIP_ID_B);
+ chip_id = wl1251_reg_read32(wl, CHIP_ID_B);
- wl12xx_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
+ wl1251_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
if (chip_id != wl->chip.id) {
- wl12xx_error("chip id doesn't match after firmware boot");
+ wl1251_error("chip id doesn't match after firmware boot");
return -EIO;
}
@@ -232,63 +232,65 @@ int wl12xx_boot_run_firmware(struct wl12xx *wl)
loop = 0;
while (loop++ < INIT_LOOP) {
udelay(INIT_LOOP_DELAY);
- interrupt = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+ interrupt = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
if (interrupt == 0xffffffff) {
- wl12xx_error("error reading hardware complete "
+ wl1251_error("error reading hardware complete "
"init indication");
return -EIO;
}
/* check that ACX_INTR_INIT_COMPLETE is enabled */
else if (interrupt & wl->chip.intr_init_complete) {
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
wl->chip.intr_init_complete);
break;
}
}
if (loop >= INIT_LOOP) {
- wl12xx_error("timeout waiting for the hardware to "
+ wl1251_error("timeout waiting for the hardware to "
"complete initialization");
return -EIO;
}
/* get hardware config command mail box */
- wl->cmd_box_addr = wl12xx_reg_read32(wl, REG_COMMAND_MAILBOX_PTR);
+ wl->cmd_box_addr = wl1251_reg_read32(wl, REG_COMMAND_MAILBOX_PTR);
/* get hardware config event mail box */
- wl->event_box_addr = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
+ wl->event_box_addr = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
/* set the working partition to its "running" mode offset */
- wl12xx_set_partition(wl,
+ wl1251_set_partition(wl,
wl->chip.p_table[PART_WORK].mem.start,
wl->chip.p_table[PART_WORK].mem.size,
wl->chip.p_table[PART_WORK].reg.start,
wl->chip.p_table[PART_WORK].reg.size);
- wl12xx_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
+ wl1251_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
wl->cmd_box_addr, wl->event_box_addr);
+ wl->chip.op_fw_version(wl);
+
/*
* in case of full asynchronous mode the firmware event must be
* ready to receive event from the command mailbox
*/
/* enable gpio interrupts */
- wl12xx_boot_enable_interrupts(wl);
+ wl1251_boot_enable_interrupts(wl);
wl->chip.op_target_enable_interrupts(wl);
/* unmask all mbox events */
wl->event_mask = 0xffffffff;
- ret = wl12xx_event_unmask(wl);
+ ret = wl1251_event_unmask(wl);
if (ret < 0) {
- wl12xx_error("EVENT mask setting failed");
+ wl1251_error("EVENT mask setting failed");
return ret;
}
- wl12xx_event_mbox_config(wl);
+ wl1251_event_mbox_config(wl);
/* firmware startup completed */
return 0;
diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/wl1251_boot.h
index 4fa73132baae..798362d71e3f 100644
--- a/drivers/net/wireless/wl12xx/boot.h
+++ b/drivers/net/wireless/wl12xx/wl1251_boot.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2008 Nokia Corporation
*
@@ -24,12 +24,12 @@
#ifndef __BOOT_H__
#define __BOOT_H__
-#include "wl12xx.h"
+#include "wl1251.h"
-int wl12xx_boot_soft_reset(struct wl12xx *wl);
-int wl12xx_boot_init_seq(struct wl12xx *wl);
-int wl12xx_boot_run_firmware(struct wl12xx *wl);
-void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl);
+int wl1251_boot_soft_reset(struct wl1251 *wl);
+int wl1251_boot_init_seq(struct wl1251 *wl);
+int wl1251_boot_run_firmware(struct wl1251 *wl);
+void wl1251_boot_target_enable_interrupts(struct wl1251 *wl);
/* number of times we try to read the INIT interrupt */
#define INIT_LOOP 20000
diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c
new file mode 100644
index 000000000000..dc04d1fc2ee4
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c
@@ -0,0 +1,428 @@
+#include "wl1251_cmd.h"
+
+#include <linux/module.h>
+#include <linux/crc7.h>
+#include <linux/spi/spi.h>
+
+#include "wl1251.h"
+#include "reg.h"
+#include "wl1251_spi.h"
+#include "wl1251_ps.h"
+#include "wl1251_acx.h"
+
+/**
+ * send command to firmware
+ *
+ * @wl: wl struct
+ * @id: command id
+ * @buf: buffer containing the command, must work with dma
+ * @len: length of the buffer
+ */
+int wl1251_cmd_send(struct wl1251 *wl, u16 id, void *buf, size_t len)
+{
+ struct wl1251_cmd_header *cmd;
+ unsigned long timeout;
+ u32 intr;
+ int ret = 0;
+
+ cmd = buf;
+ cmd->id = id;
+ cmd->status = 0;
+
+ WARN_ON(len % 4 != 0);
+
+ wl1251_spi_mem_write(wl, wl->cmd_box_addr, buf, len);
+
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
+
+ timeout = jiffies + msecs_to_jiffies(WL1251_COMMAND_TIMEOUT);
+
+ intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+ while (!(intr & wl->chip.intr_cmd_complete)) {
+ if (time_after(jiffies, timeout)) {
+ wl1251_error("command complete timeout");
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ msleep(1);
+
+ intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+ }
+
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
+ wl->chip.intr_cmd_complete);
+
+out:
+ return ret;
+}
+
+/**
+ * send test command to firmware
+ *
+ * @wl: wl struct
+ * @buf: buffer containing the command, with all headers, must work with dma
+ * @len: length of the buffer
+ * @answer: is answer needed
+ */
+int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer)
+{
+ int ret;
+
+ wl1251_debug(DEBUG_CMD, "cmd test");
+
+ ret = wl1251_cmd_send(wl, CMD_TEST, buf, buf_len);
+
+ if (ret < 0) {
+ wl1251_warning("TEST command failed");
+ return ret;
+ }
+
+ if (answer) {
+ struct wl1251_command *cmd_answer;
+
+ /*
+ * The test command got in, we can read the answer.
+ * The answer would be a wl1251_command, where the
+ * parameter array contains the actual answer.
+ */
+ wl1251_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len);
+
+ cmd_answer = buf;
+
+ if (cmd_answer->header.status != CMD_STATUS_SUCCESS)
+ wl1251_error("TEST command answer error: %d",
+ cmd_answer->header.status);
+ }
+
+ return 0;
+}
+
+/**
+ * read acx from firmware
+ *
+ * @wl: wl struct
+ * @id: acx id
+ * @buf: buffer for the response, including all headers, must work with dma
+ * @len: lenght of buf
+ */
+int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len)
+{
+ struct acx_header *acx = buf;
+ int ret;
+
+ wl1251_debug(DEBUG_CMD, "cmd interrogate");
+
+ acx->id = id;
+
+ /* payload length, does not include any headers */
+ acx->len = len - sizeof(*acx);
+
+ ret = wl1251_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_error("INTERROGATE command failed");
+ goto out;
+ }
+
+ /* the interrogate command got in, we can read the answer */
+ wl1251_spi_mem_read(wl, wl->cmd_box_addr, buf, len);
+
+ acx = buf;
+ if (acx->cmd.status != CMD_STATUS_SUCCESS)
+ wl1251_error("INTERROGATE command error: %d",
+ acx->cmd.status);
+
+out:
+ return ret;
+}
+
+/**
+ * write acx value to firmware
+ *
+ * @wl: wl struct
+ * @id: acx id
+ * @buf: buffer containing acx, including all headers, must work with dma
+ * @len: length of buf
+ */
+int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len)
+{
+ struct acx_header *acx = buf;
+ int ret;
+
+ wl1251_debug(DEBUG_CMD, "cmd configure");
+
+ acx->id = id;
+
+ /* payload length, does not include any headers */
+ acx->len = len - sizeof(*acx);
+
+ ret = wl1251_cmd_send(wl, CMD_CONFIGURE, acx, len);
+ if (ret < 0) {
+ wl1251_warning("CONFIGURE command NOK");
+ return ret;
+ }
+
+ return 0;
+}
+
+int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity,
+ void *bitmap, u16 bitmap_len, u8 bitmap_control)
+{
+ struct wl1251_cmd_vbm_update *vbm;
+ int ret;
+
+ wl1251_debug(DEBUG_CMD, "cmd vbm");
+
+ vbm = kzalloc(sizeof(*vbm), GFP_KERNEL);
+ if (!vbm) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* Count and period will be filled by the target */
+ vbm->tim.bitmap_ctrl = bitmap_control;
+ if (bitmap_len > PARTIAL_VBM_MAX) {
+ wl1251_warning("cmd vbm len is %d B, truncating to %d",
+ bitmap_len, PARTIAL_VBM_MAX);
+ bitmap_len = PARTIAL_VBM_MAX;
+ }
+ memcpy(vbm->tim.pvb_field, bitmap, bitmap_len);
+ vbm->tim.identity = identity;
+ vbm->tim.length = bitmap_len + 3;
+
+ vbm->len = cpu_to_le16(bitmap_len + 5);
+
+ ret = wl1251_cmd_send(wl, CMD_VBM, vbm, sizeof(*vbm));
+ if (ret < 0) {
+ wl1251_error("VBM command failed");
+ goto out;
+ }
+
+out:
+ kfree(vbm);
+ return 0;
+}
+
+int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable)
+{
+ struct cmd_enabledisable_path *cmd;
+ int ret;
+ u16 cmd_rx, cmd_tx;
+
+ wl1251_debug(DEBUG_CMD, "cmd data path");
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->channel = channel;
+
+ if (enable) {
+ cmd_rx = CMD_ENABLE_RX;
+ cmd_tx = CMD_ENABLE_TX;
+ } else {
+ cmd_rx = CMD_DISABLE_RX;
+ cmd_tx = CMD_DISABLE_TX;
+ }
+
+ ret = wl1251_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd));
+ if (ret < 0) {
+ wl1251_error("rx %s cmd for channel %d failed",
+ enable ? "start" : "stop", channel);
+ goto out;
+ }
+
+ wl1251_debug(DEBUG_BOOT, "rx %s cmd channel %d",
+ enable ? "start" : "stop", channel);
+
+ ret = wl1251_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd));
+ if (ret < 0) {
+ wl1251_error("tx %s cmd for channel %d failed",
+ enable ? "start" : "stop", channel);
+ return ret;
+ }
+
+ wl1251_debug(DEBUG_BOOT, "tx %s cmd channel %d",
+ enable ? "start" : "stop", channel);
+
+out:
+ kfree(cmd);
+ return ret;
+}
+
+int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval,
+ u16 beacon_interval, u8 wait)
+{
+ unsigned long timeout;
+ struct cmd_join *join;
+ int ret, i;
+ u8 *bssid;
+
+ join = kzalloc(sizeof(*join), GFP_KERNEL);
+ if (!join) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* FIXME: this should be in main.c */
+ ret = wl1251_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE,
+ DEFAULT_HW_GEN_MODULATION_TYPE,
+ wl->tx_mgmt_frm_rate,
+ wl->tx_mgmt_frm_mod);
+ if (ret < 0)
+ goto out;
+
+ wl1251_debug(DEBUG_CMD, "cmd join");
+
+ /* Reverse order BSSID */
+ bssid = (u8 *) &join->bssid_lsb;
+ for (i = 0; i < ETH_ALEN; i++)
+ bssid[i] = wl->bssid[ETH_ALEN - i - 1];
+
+ join->rx_config_options = wl->rx_config;
+ join->rx_filter_options = wl->rx_filter;
+
+ join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS |
+ RATE_MASK_5_5MBPS | RATE_MASK_11MBPS;
+
+ join->beacon_interval = beacon_interval;
+ join->dtim_interval = dtim_interval;
+ join->bss_type = bss_type;
+ join->channel = wl->channel;
+ join->ctrl = JOIN_CMD_CTRL_TX_FLUSH;
+
+ ret = wl1251_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join));
+ if (ret < 0) {
+ wl1251_error("failed to initiate cmd join");
+ goto out;
+ }
+
+ timeout = msecs_to_jiffies(JOIN_TIMEOUT);
+
+ /*
+ * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
+ * simplify locking we just sleep instead, for now
+ */
+ if (wait)
+ msleep(10);
+
+out:
+ kfree(join);
+ return ret;
+}
+
+int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode)
+{
+ struct wl1251_cmd_ps_params *ps_params = NULL;
+ int ret = 0;
+
+ /* FIXME: this should be in ps.c */
+ ret = wl1251_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP,
+ wl->listen_int);
+ if (ret < 0) {
+ wl1251_error("couldn't set wake up conditions");
+ goto out;
+ }
+
+ wl1251_debug(DEBUG_CMD, "cmd set ps mode");
+
+ ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL);
+ if (!ps_params) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ps_params->ps_mode = ps_mode;
+ ps_params->send_null_data = 1;
+ ps_params->retries = 5;
+ ps_params->hang_over_period = 128;
+ ps_params->null_data_rate = 1; /* 1 Mbps */
+
+ ret = wl1251_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
+ sizeof(*ps_params));
+ if (ret < 0) {
+ wl1251_error("cmd set_ps_mode failed");
+ goto out;
+ }
+
+out:
+ kfree(ps_params);
+ return ret;
+}
+
+int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer,
+ size_t len)
+{
+ struct cmd_read_write_memory *cmd;
+ int ret = 0;
+
+ wl1251_debug(DEBUG_CMD, "cmd read memory");
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ WARN_ON(len > MAX_READ_SIZE);
+ len = min_t(size_t, len, MAX_READ_SIZE);
+
+ cmd->addr = addr;
+ cmd->size = len;
+
+ ret = wl1251_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd));
+ if (ret < 0) {
+ wl1251_error("read memory command failed: %d", ret);
+ goto out;
+ }
+
+ /* the read command got in, we can now read the answer */
+ wl1251_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd));
+
+ if (cmd->header.status != CMD_STATUS_SUCCESS)
+ wl1251_error("error in read command result: %d",
+ cmd->header.status);
+
+ memcpy(answer, cmd->value, len);
+
+out:
+ kfree(cmd);
+ return ret;
+}
+
+int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id,
+ void *buf, size_t buf_len)
+{
+ struct wl1251_cmd_packet_template *cmd;
+ size_t cmd_len;
+ int ret = 0;
+
+ wl1251_debug(DEBUG_CMD, "cmd template %d", cmd_id);
+
+ WARN_ON(buf_len > WL1251_MAX_TEMPLATE_SIZE);
+ buf_len = min_t(size_t, buf_len, WL1251_MAX_TEMPLATE_SIZE);
+ cmd_len = ALIGN(sizeof(*cmd) + buf_len, 4);
+
+ cmd = kzalloc(cmd_len, GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->size = cpu_to_le16(buf_len);
+
+ if (buf)
+ memcpy(cmd->data, buf, buf_len);
+
+ ret = wl1251_cmd_send(wl, cmd_id, cmd, cmd_len);
+ if (ret < 0) {
+ wl1251_warning("cmd set_template failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(cmd);
+ return ret;
+}
diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h
index aa307dcd081f..64f228dd9a9b 100644
--- a/drivers/net/wireless/wl12xx/cmd.h
+++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,37 +22,32 @@
*
*/
-#ifndef __WL12XX_CMD_H__
-#define __WL12XX_CMD_H__
+#ifndef __WL1251_CMD_H__
+#define __WL1251_CMD_H__
-#include "wl12xx.h"
+#include "wl1251.h"
-int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len);
-int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer);
-int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 ie_id, u16 ie_len,
- void *answer);
-int wl12xx_cmd_configure(struct wl12xx *wl, void *ie, int ie_len);
-int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity,
+struct acx_header;
+
+int wl1251_cmd_send(struct wl1251 *wl, u16 type, void *buf, size_t buf_len);
+int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer);
+int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len);
+int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len);
+int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity,
void *bitmap, u16 bitmap_len, u8 bitmap_control);
-int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, u8 enable);
-int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval,
+int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable);
+int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval,
u16 beacon_interval, u8 wait);
-int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode);
-int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, u32 len, void *answer);
-int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id,
+int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode);
+int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer,
+ size_t len);
+int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id,
void *buf, size_t buf_len);
/* unit ms */
-#define WL12XX_COMMAND_TIMEOUT 2000
-
-#define WL12XX_MAX_TEMPLATE_SIZE 300
+#define WL1251_COMMAND_TIMEOUT 2000
-struct wl12xx_cmd_packet_template {
- __le16 size;
- u8 template[WL12XX_MAX_TEMPLATE_SIZE];
-} __attribute__ ((packed));
-
-enum wl12xx_commands {
+enum wl1251_commands {
CMD_RESET = 0,
CMD_INTERROGATE = 1, /*use this to read information elements*/
CMD_CONFIGURE = 2, /*use this to write information elements*/
@@ -100,9 +95,15 @@ enum wl12xx_commands {
#define MAX_CMD_PARAMS 572
-struct wl12xx_command {
+struct wl1251_cmd_header {
u16 id;
u16 status;
+ /* payload */
+ u8 data[0];
+} __attribute__ ((packed));
+
+struct wl1251_command {
+ struct wl1251_cmd_header header;
u8 parameters[MAX_CMD_PARAMS];
};
@@ -144,6 +145,8 @@ enum {
#define MAX_READ_SIZE 256
struct cmd_read_write_memory {
+ struct wl1251_cmd_header header;
+
/* The address of the memory to read from or write to.*/
u32 addr;
@@ -211,6 +214,8 @@ struct basic_scan_channel_parameters {
#define SCAN_MAX_NUM_OF_CHANNELS 16
struct cmd_scan {
+ struct wl1251_cmd_header header;
+
struct basic_scan_parameters params;
struct basic_scan_channel_parameters channels[SCAN_MAX_NUM_OF_CHANNELS];
} __attribute__ ((packed));
@@ -227,6 +232,8 @@ enum {
struct cmd_join {
+ struct wl1251_cmd_header header;
+
u32 bssid_lsb;
u16 bssid_msb;
u16 beacon_interval; /* in TBTTs */
@@ -261,5 +268,140 @@ struct cmd_join {
u8 reserved;
} __attribute__ ((packed));
+struct cmd_enabledisable_path {
+ struct wl1251_cmd_header header;
+
+ u8 channel;
+ u8 padding[3];
+} __attribute__ ((packed));
+
+#define WL1251_MAX_TEMPLATE_SIZE 300
+
+struct wl1251_cmd_packet_template {
+ struct wl1251_cmd_header header;
+
+ __le16 size;
+ u8 data[0];
+} __attribute__ ((packed));
+
+#define TIM_ELE_ID 5
+#define PARTIAL_VBM_MAX 251
+
+struct wl1251_tim {
+ u8 identity;
+ u8 length;
+ u8 dtim_count;
+ u8 dtim_period;
+ u8 bitmap_ctrl;
+ u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */
+} __attribute__ ((packed));
+
+/* Virtual Bit Map update */
+struct wl1251_cmd_vbm_update {
+ struct wl1251_cmd_header header;
+ __le16 len;
+ u8 padding[2];
+ struct wl1251_tim tim;
+} __attribute__ ((packed));
+
+enum wl1251_cmd_ps_mode {
+ STATION_ACTIVE_MODE,
+ STATION_POWER_SAVE_MODE
+};
+
+struct wl1251_cmd_ps_params {
+ struct wl1251_cmd_header header;
+
+ u8 ps_mode; /* STATION_* */
+ u8 send_null_data; /* Do we have to send NULL data packet ? */
+ u8 retries; /* Number of retires for the initial NULL data packet */
+
+ /*
+ * TUs during which the target stays awake after switching
+ * to power save mode.
+ */
+ u8 hang_over_period;
+ u16 null_data_rate;
+ u8 pad[2];
+} __attribute__ ((packed));
+
+struct wl1251_cmd_trigger_scan_to {
+ struct wl1251_cmd_header header;
+
+ u32 timeout;
+};
+
+/* HW encryption keys */
+#define NUM_ACCESS_CATEGORIES_COPY 4
+#define MAX_KEY_SIZE 32
+
+/* When set, disable HW encryption */
+#define DF_ENCRYPTION_DISABLE 0x01
+/* When set, disable HW decryption */
+#define DF_SNIFF_MODE_ENABLE 0x80
+
+enum wl1251_cmd_key_action {
+ KEY_ADD_OR_REPLACE = 1,
+ KEY_REMOVE = 2,
+ KEY_SET_ID = 3,
+ MAX_KEY_ACTION = 0xffff,
+};
+
+enum wl1251_cmd_key_type {
+ KEY_WEP_DEFAULT = 0,
+ KEY_WEP_ADDR = 1,
+ KEY_AES_GROUP = 4,
+ KEY_AES_PAIRWISE = 5,
+ KEY_WEP_GROUP = 6,
+ KEY_TKIP_MIC_GROUP = 10,
+ KEY_TKIP_MIC_PAIRWISE = 11,
+};
+
+/*
+ *
+ * key_type_e key size key format
+ * ---------- --------- ----------
+ * 0x00 5, 13, 29 Key data
+ * 0x01 5, 13, 29 Key data
+ * 0x04 16 16 bytes of key data
+ * 0x05 16 16 bytes of key data
+ * 0x0a 32 16 bytes of TKIP key data
+ * 8 bytes of RX MIC key data
+ * 8 bytes of TX MIC key data
+ * 0x0b 32 16 bytes of TKIP key data
+ * 8 bytes of RX MIC key data
+ * 8 bytes of TX MIC key data
+ *
+ */
+
+struct wl1251_cmd_set_keys {
+ struct wl1251_cmd_header header;
+
+ /* Ignored for default WEP key */
+ u8 addr[ETH_ALEN];
+
+ /* key_action_e */
+ u16 key_action;
+
+ u16 reserved_1;
+
+ /* key size in bytes */
+ u8 key_size;
+
+ /* key_type_e */
+ u8 key_type;
+ u8 ssid_profile;
+
+ /*
+ * TKIP, AES: frame's key id field.
+ * For WEP default key: key id;
+ */
+ u8 id;
+ u8 reserved_2[6];
+ u8 key[MAX_KEY_SIZE];
+ u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
+ u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
+} __attribute__ ((packed));
+
-#endif /* __WL12XX_CMD_H__ */
+#endif /* __WL1251_CMD_H__ */
diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/wl1251_debugfs.c
index cdb368ce4dae..a00723059f83 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2009 Nokia Corporation
*
@@ -21,15 +21,16 @@
*
*/
-#include "debugfs.h"
+#include "wl1251_debugfs.h"
#include <linux/skbuff.h>
-#include "wl12xx.h"
-#include "acx.h"
+#include "wl1251.h"
+#include "wl1251_acx.h"
+#include "wl1251_ps.h"
/* ms */
-#define WL12XX_DEBUGFS_STATS_LIFETIME 1000
+#define WL1251_DEBUGFS_STATS_LIFETIME 1000
/* debugfs macros idea from mac80211 */
@@ -37,7 +38,7 @@
static ssize_t name## _read(struct file *file, char __user *userbuf, \
size_t count, loff_t *ppos) \
{ \
- struct wl12xx *wl = file->private_data; \
+ struct wl1251 *wl = file->private_data; \
char buf[buflen]; \
int res; \
\
@@ -47,7 +48,7 @@ static ssize_t name## _read(struct file *file, char __user *userbuf, \
\
static const struct file_operations name## _ops = { \
.read = name## _read, \
- .open = wl12xx_open_file_generic, \
+ .open = wl1251_open_file_generic, \
};
#define DEBUGFS_ADD(name, parent) \
@@ -70,11 +71,11 @@ static ssize_t sub## _ ##name## _read(struct file *file, \
char __user *userbuf, \
size_t count, loff_t *ppos) \
{ \
- struct wl12xx *wl = file->private_data; \
+ struct wl1251 *wl = file->private_data; \
char buf[buflen]; \
int res; \
\
- wl12xx_debugfs_update_stats(wl); \
+ wl1251_debugfs_update_stats(wl); \
\
res = scnprintf(buf, buflen, fmt "\n", \
wl->stats.fw_stats->sub.name); \
@@ -83,7 +84,7 @@ static ssize_t sub## _ ##name## _read(struct file *file, \
\
static const struct file_operations sub## _ ##name## _ops = { \
.read = sub## _ ##name## _read, \
- .open = wl12xx_open_file_generic, \
+ .open = wl1251_open_file_generic, \
};
#define DEBUGFS_FWSTATS_ADD(sub, name) \
@@ -92,21 +93,30 @@ static const struct file_operations sub## _ ##name## _ops = { \
#define DEBUGFS_FWSTATS_DEL(sub, name) \
DEBUGFS_DEL(sub## _ ##name)
-static void wl12xx_debugfs_update_stats(struct wl12xx *wl)
+static void wl1251_debugfs_update_stats(struct wl1251 *wl)
{
+ int ret;
+
mutex_lock(&wl->mutex);
- if (wl->state == WL12XX_STATE_ON &&
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ if (wl->state == WL1251_STATE_ON &&
time_after(jiffies, wl->stats.fw_stats_update +
- msecs_to_jiffies(WL12XX_DEBUGFS_STATS_LIFETIME))) {
- wl12xx_acx_statistics(wl, wl->stats.fw_stats);
+ msecs_to_jiffies(WL1251_DEBUGFS_STATS_LIFETIME))) {
+ wl1251_acx_statistics(wl, wl->stats.fw_stats);
wl->stats.fw_stats_update = jiffies;
}
+ wl1251_ps_elp_sleep(wl);
+
+out:
mutex_unlock(&wl->mutex);
}
-static int wl12xx_open_file_generic(struct inode *inode, struct file *file)
+static int wl1251_open_file_generic(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
@@ -211,7 +221,7 @@ DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u",
static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
- struct wl12xx *wl = file->private_data;
+ struct wl1251 *wl = file->private_data;
u32 queue_len;
char buf[20];
int res;
@@ -224,10 +234,10 @@ static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf,
static const struct file_operations tx_queue_len_ops = {
.read = tx_queue_len_read,
- .open = wl12xx_open_file_generic,
+ .open = wl1251_open_file_generic,
};
-static void wl12xx_debugfs_delete_files(struct wl12xx *wl)
+static void wl1251_debugfs_delete_files(struct wl1251 *wl)
{
DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow);
@@ -325,7 +335,7 @@ static void wl12xx_debugfs_delete_files(struct wl12xx *wl)
DEBUGFS_DEL(excessive_retries);
}
-static int wl12xx_debugfs_add_files(struct wl12xx *wl)
+static int wl1251_debugfs_add_files(struct wl1251 *wl)
{
int ret = 0;
@@ -426,19 +436,19 @@ static int wl12xx_debugfs_add_files(struct wl12xx *wl)
out:
if (ret < 0)
- wl12xx_debugfs_delete_files(wl);
+ wl1251_debugfs_delete_files(wl);
return ret;
}
-void wl12xx_debugfs_reset(struct wl12xx *wl)
+void wl1251_debugfs_reset(struct wl1251 *wl)
{
memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats));
wl->stats.retry_count = 0;
wl->stats.excessive_retries = 0;
}
-int wl12xx_debugfs_init(struct wl12xx *wl)
+int wl1251_debugfs_init(struct wl1251 *wl)
{
int ret;
@@ -469,7 +479,7 @@ int wl12xx_debugfs_init(struct wl12xx *wl)
wl->stats.fw_stats_update = jiffies;
- ret = wl12xx_debugfs_add_files(wl);
+ ret = wl1251_debugfs_add_files(wl);
if (ret < 0)
goto err_file;
@@ -492,9 +502,9 @@ err:
return ret;
}
-void wl12xx_debugfs_exit(struct wl12xx *wl)
+void wl1251_debugfs_exit(struct wl1251 *wl)
{
- wl12xx_debugfs_delete_files(wl);
+ wl1251_debugfs_delete_files(wl);
kfree(wl->stats.fw_stats);
wl->stats.fw_stats = NULL;
diff --git a/drivers/net/wireless/wl12xx/debugfs.h b/drivers/net/wireless/wl12xx/wl1251_debugfs.h
index 562cdcbcc874..6dc3d080853c 100644
--- a/drivers/net/wireless/wl12xx/debugfs.h
+++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2009 Nokia Corporation
*
@@ -21,13 +21,13 @@
*
*/
-#ifndef WL12XX_DEBUGFS_H
-#define WL12XX_DEBUGFS_H
+#ifndef WL1251_DEBUGFS_H
+#define WL1251_DEBUGFS_H
-#include "wl12xx.h"
+#include "wl1251.h"
-int wl12xx_debugfs_init(struct wl12xx *wl);
-void wl12xx_debugfs_exit(struct wl12xx *wl);
-void wl12xx_debugfs_reset(struct wl12xx *wl);
+int wl1251_debugfs_init(struct wl1251 *wl);
+void wl1251_debugfs_exit(struct wl1251 *wl);
+void wl1251_debugfs_reset(struct wl1251 *wl);
-#endif /* WL12XX_DEBUGFS_H */
+#endif /* WL1251_DEBUGFS_H */
diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/wl1251_event.c
index 99529ca89a7e..1a0a0bc1a31f 100644
--- a/drivers/net/wireless/wl12xx/event.c
+++ b/drivers/net/wireless/wl12xx/wl1251_event.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,16 +22,16 @@
*
*/
-#include "wl12xx.h"
+#include "wl1251.h"
#include "reg.h"
-#include "spi.h"
-#include "event.h"
-#include "ps.h"
+#include "wl1251_spi.h"
+#include "wl1251_event.h"
+#include "wl1251_ps.h"
-static int wl12xx_event_scan_complete(struct wl12xx *wl,
+static int wl1251_event_scan_complete(struct wl1251 *wl,
struct event_mailbox *mbox)
{
- wl12xx_debug(DEBUG_EVENT, "status: 0x%x, channels: %d",
+ wl1251_debug(DEBUG_EVENT, "status: 0x%x, channels: %d",
mbox->scheduled_scan_status,
mbox->scheduled_scan_channels);
@@ -45,34 +45,34 @@ static int wl12xx_event_scan_complete(struct wl12xx *wl,
return 0;
}
-static void wl12xx_event_mbox_dump(struct event_mailbox *mbox)
+static void wl1251_event_mbox_dump(struct event_mailbox *mbox)
{
- wl12xx_debug(DEBUG_EVENT, "MBOX DUMP:");
- wl12xx_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector);
- wl12xx_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask);
+ wl1251_debug(DEBUG_EVENT, "MBOX DUMP:");
+ wl1251_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector);
+ wl1251_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask);
}
-static int wl12xx_event_process(struct wl12xx *wl, struct event_mailbox *mbox)
+static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox)
{
int ret;
u32 vector;
- wl12xx_event_mbox_dump(mbox);
+ wl1251_event_mbox_dump(mbox);
vector = mbox->events_vector & ~(mbox->events_mask);
- wl12xx_debug(DEBUG_EVENT, "vector: 0x%x", vector);
+ wl1251_debug(DEBUG_EVENT, "vector: 0x%x", vector);
if (vector & SCAN_COMPLETE_EVENT_ID) {
- ret = wl12xx_event_scan_complete(wl, mbox);
+ ret = wl1251_event_scan_complete(wl, mbox);
if (ret < 0)
return ret;
}
if (vector & BSS_LOSE_EVENT_ID) {
- wl12xx_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
+ wl1251_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
if (wl->psm_requested && wl->psm) {
- ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE);
+ ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
if (ret < 0)
return ret;
}
@@ -81,47 +81,47 @@ static int wl12xx_event_process(struct wl12xx *wl, struct event_mailbox *mbox)
return 0;
}
-int wl12xx_event_unmask(struct wl12xx *wl)
+int wl1251_event_unmask(struct wl1251 *wl)
{
int ret;
- ret = wl12xx_acx_event_mbox_mask(wl, ~(wl->event_mask));
+ ret = wl1251_acx_event_mbox_mask(wl, ~(wl->event_mask));
if (ret < 0)
return ret;
return 0;
}
-void wl12xx_event_mbox_config(struct wl12xx *wl)
+void wl1251_event_mbox_config(struct wl1251 *wl)
{
- wl->mbox_ptr[0] = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
+ wl->mbox_ptr[0] = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
- wl12xx_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
+ wl1251_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
wl->mbox_ptr[0], wl->mbox_ptr[1]);
}
-int wl12xx_event_handle(struct wl12xx *wl, u8 mbox_num)
+int wl1251_event_handle(struct wl1251 *wl, u8 mbox_num)
{
struct event_mailbox mbox;
int ret;
- wl12xx_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num);
+ wl1251_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num);
if (mbox_num > 1)
return -EINVAL;
/* first we read the mbox descriptor */
- wl12xx_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox,
+ wl1251_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox,
sizeof(struct event_mailbox));
/* process the descriptor */
- ret = wl12xx_event_process(wl, &mbox);
+ ret = wl1251_event_process(wl, &mbox);
if (ret < 0)
return ret;
/* then we let the firmware know it can go on...*/
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
return 0;
}
diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/wl1251_event.h
index 1f4c2f7438a7..be0ac54d6246 100644
--- a/drivers/net/wireless/wl12xx/event.h
+++ b/drivers/net/wireless/wl12xx/wl1251_event.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,8 +22,8 @@
*
*/
-#ifndef __WL12XX_EVENT_H__
-#define __WL12XX_EVENT_H__
+#ifndef __WL1251_EVENT_H__
+#define __WL1251_EVENT_H__
/*
* Mbox events
@@ -114,8 +114,8 @@ struct event_mailbox {
u8 padding[19];
} __attribute__ ((packed));
-int wl12xx_event_unmask(struct wl12xx *wl);
-void wl12xx_event_mbox_config(struct wl12xx *wl);
-int wl12xx_event_handle(struct wl12xx *wl, u8 mbox);
+int wl1251_event_unmask(struct wl1251 *wl);
+void wl1251_event_mbox_config(struct wl1251 *wl);
+int wl1251_event_handle(struct wl1251 *wl, u8 mbox);
#endif
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/wl1251_init.c
index 2a573a6010bd..df6c60f0fd66 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/wl1251_init.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2009 Nokia Corporation
*
@@ -24,64 +24,64 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include "init.h"
+#include "wl1251_init.h"
#include "wl12xx_80211.h"
-#include "acx.h"
-#include "cmd.h"
+#include "wl1251_acx.h"
+#include "wl1251_cmd.h"
-int wl12xx_hw_init_hwenc_config(struct wl12xx *wl)
+int wl1251_hw_init_hwenc_config(struct wl1251 *wl)
{
int ret;
- ret = wl12xx_acx_feature_cfg(wl);
+ ret = wl1251_acx_feature_cfg(wl);
if (ret < 0) {
- wl12xx_warning("couldn't set feature config");
+ wl1251_warning("couldn't set feature config");
return ret;
}
- ret = wl12xx_acx_default_key(wl, wl->default_key);
+ ret = wl1251_acx_default_key(wl, wl->default_key);
if (ret < 0) {
- wl12xx_warning("couldn't set default key");
+ wl1251_warning("couldn't set default key");
return ret;
}
return 0;
}
-int wl12xx_hw_init_templates_config(struct wl12xx *wl)
+int wl1251_hw_init_templates_config(struct wl1251 *wl)
{
int ret;
u8 partial_vbm[PARTIAL_VBM_MAX];
/* send empty templates for fw memory reservation */
- ret = wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, NULL,
+ ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, NULL,
sizeof(struct wl12xx_probe_req_template));
if (ret < 0)
return ret;
- ret = wl12xx_cmd_template_set(wl, CMD_NULL_DATA, NULL,
+ ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA, NULL,
sizeof(struct wl12xx_null_data_template));
if (ret < 0)
return ret;
- ret = wl12xx_cmd_template_set(wl, CMD_PS_POLL, NULL,
+ ret = wl1251_cmd_template_set(wl, CMD_PS_POLL, NULL,
sizeof(struct wl12xx_ps_poll_template));
if (ret < 0)
return ret;
- ret = wl12xx_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL,
+ ret = wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL,
sizeof
(struct wl12xx_qos_null_data_template));
if (ret < 0)
return ret;
- ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, NULL,
+ ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, NULL,
sizeof
(struct wl12xx_probe_resp_template));
if (ret < 0)
return ret;
- ret = wl12xx_cmd_template_set(wl, CMD_BEACON, NULL,
+ ret = wl1251_cmd_template_set(wl, CMD_BEACON, NULL,
sizeof
(struct wl12xx_beacon_template));
if (ret < 0)
@@ -89,112 +89,112 @@ int wl12xx_hw_init_templates_config(struct wl12xx *wl)
/* tim templates, first reserve space then allocate an empty one */
memset(partial_vbm, 0, PARTIAL_VBM_MAX);
- ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0);
+ ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0);
if (ret < 0)
return ret;
- ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0);
+ ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0);
if (ret < 0)
return ret;
return 0;
}
-int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter)
+int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter)
{
int ret;
- ret = wl12xx_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF);
+ ret = wl1251_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF);
if (ret < 0)
return ret;
- ret = wl12xx_acx_rx_config(wl, config, filter);
+ ret = wl1251_acx_rx_config(wl, config, filter);
if (ret < 0)
return ret;
return 0;
}
-int wl12xx_hw_init_phy_config(struct wl12xx *wl)
+int wl1251_hw_init_phy_config(struct wl1251 *wl)
{
int ret;
- ret = wl12xx_acx_pd_threshold(wl);
+ ret = wl1251_acx_pd_threshold(wl);
if (ret < 0)
return ret;
- ret = wl12xx_acx_slot(wl, DEFAULT_SLOT_TIME);
+ ret = wl1251_acx_slot(wl, DEFAULT_SLOT_TIME);
if (ret < 0)
return ret;
- ret = wl12xx_acx_group_address_tbl(wl);
+ ret = wl1251_acx_group_address_tbl(wl);
if (ret < 0)
return ret;
- ret = wl12xx_acx_service_period_timeout(wl);
+ ret = wl1251_acx_service_period_timeout(wl);
if (ret < 0)
return ret;
- ret = wl12xx_acx_rts_threshold(wl, RTS_THRESHOLD_DEF);
+ ret = wl1251_acx_rts_threshold(wl, RTS_THRESHOLD_DEF);
if (ret < 0)
return ret;
return 0;
}
-int wl12xx_hw_init_beacon_filter(struct wl12xx *wl)
+int wl1251_hw_init_beacon_filter(struct wl1251 *wl)
{
int ret;
- ret = wl12xx_acx_beacon_filter_opt(wl);
+ ret = wl1251_acx_beacon_filter_opt(wl);
if (ret < 0)
return ret;
- ret = wl12xx_acx_beacon_filter_table(wl);
+ ret = wl1251_acx_beacon_filter_table(wl);
if (ret < 0)
return ret;
return 0;
}
-int wl12xx_hw_init_pta(struct wl12xx *wl)
+int wl1251_hw_init_pta(struct wl1251 *wl)
{
int ret;
- ret = wl12xx_acx_sg_enable(wl);
+ ret = wl1251_acx_sg_enable(wl);
if (ret < 0)
return ret;
- ret = wl12xx_acx_sg_cfg(wl);
+ ret = wl1251_acx_sg_cfg(wl);
if (ret < 0)
return ret;
return 0;
}
-int wl12xx_hw_init_energy_detection(struct wl12xx *wl)
+int wl1251_hw_init_energy_detection(struct wl1251 *wl)
{
int ret;
- ret = wl12xx_acx_cca_threshold(wl);
+ ret = wl1251_acx_cca_threshold(wl);
if (ret < 0)
return ret;
return 0;
}
-int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl)
+int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl)
{
int ret;
- ret = wl12xx_acx_bcn_dtim_options(wl);
+ ret = wl1251_acx_bcn_dtim_options(wl);
if (ret < 0)
return ret;
return 0;
}
-int wl12xx_hw_init_power_auth(struct wl12xx *wl)
+int wl1251_hw_init_power_auth(struct wl1251 *wl)
{
- return wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM);
+ return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM);
}
diff --git a/drivers/net/wireless/wl12xx/init.h b/drivers/net/wireless/wl12xx/wl1251_init.h
index c8b6cd0b7c3e..8596188e834e 100644
--- a/drivers/net/wireless/wl12xx/init.h
+++ b/drivers/net/wireless/wl12xx/wl1251_init.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2009 Nokia Corporation
*
@@ -21,20 +21,19 @@
*
*/
-#ifndef __WL12XX_INIT_H__
-#define __WL12XX_INIT_H__
+#ifndef __WL1251_INIT_H__
+#define __WL1251_INIT_H__
-#include "wl12xx.h"
+#include "wl1251.h"
-int wl12xx_hw_init_hwenc_config(struct wl12xx *wl);
-int wl12xx_hw_init_templates_config(struct wl12xx *wl);
-int wl12xx_hw_init_mem_config(struct wl12xx *wl);
-int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter);
-int wl12xx_hw_init_phy_config(struct wl12xx *wl);
-int wl12xx_hw_init_beacon_filter(struct wl12xx *wl);
-int wl12xx_hw_init_pta(struct wl12xx *wl);
-int wl12xx_hw_init_energy_detection(struct wl12xx *wl);
-int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl);
-int wl12xx_hw_init_power_auth(struct wl12xx *wl);
+int wl1251_hw_init_hwenc_config(struct wl1251 *wl);
+int wl1251_hw_init_templates_config(struct wl1251 *wl);
+int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter);
+int wl1251_hw_init_phy_config(struct wl1251 *wl);
+int wl1251_hw_init_beacon_filter(struct wl1251 *wl);
+int wl1251_hw_init_pta(struct wl1251 *wl);
+int wl1251_hw_init_energy_detection(struct wl1251 *wl);
+int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl);
+int wl1251_hw_init_power_auth(struct wl1251 *wl);
#endif
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/wl1251_main.c
index 603d6114882e..da4c688c46af 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/wl1251_main.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2008-2009 Nokia Corporation
*
@@ -31,38 +31,38 @@
#include <linux/etherdevice.h>
#include <linux/spi/wl12xx.h>
-#include "wl12xx.h"
+#include "wl1251.h"
#include "wl12xx_80211.h"
#include "reg.h"
-#include "wl1251.h"
-#include "spi.h"
-#include "event.h"
-#include "tx.h"
-#include "rx.h"
-#include "ps.h"
-#include "init.h"
-#include "debugfs.h"
-
-static void wl12xx_disable_interrupts(struct wl12xx *wl)
+#include "wl1251_ops.h"
+#include "wl1251_spi.h"
+#include "wl1251_event.h"
+#include "wl1251_tx.h"
+#include "wl1251_rx.h"
+#include "wl1251_ps.h"
+#include "wl1251_init.h"
+#include "wl1251_debugfs.h"
+
+static void wl1251_disable_interrupts(struct wl1251 *wl)
{
disable_irq(wl->irq);
}
-static void wl12xx_power_off(struct wl12xx *wl)
+static void wl1251_power_off(struct wl1251 *wl)
{
wl->set_power(false);
}
-static void wl12xx_power_on(struct wl12xx *wl)
+static void wl1251_power_on(struct wl1251 *wl)
{
wl->set_power(true);
}
-static irqreturn_t wl12xx_irq(int irq, void *cookie)
+static irqreturn_t wl1251_irq(int irq, void *cookie)
{
- struct wl12xx *wl;
+ struct wl1251 *wl;
- wl12xx_debug(DEBUG_IRQ, "IRQ");
+ wl1251_debug(DEBUG_IRQ, "IRQ");
wl = cookie;
@@ -71,7 +71,7 @@ static irqreturn_t wl12xx_irq(int irq, void *cookie)
return IRQ_HANDLED;
}
-static int wl12xx_fetch_firmware(struct wl12xx *wl)
+static int wl1251_fetch_firmware(struct wl1251 *wl)
{
const struct firmware *fw;
int ret;
@@ -79,12 +79,12 @@ static int wl12xx_fetch_firmware(struct wl12xx *wl)
ret = request_firmware(&fw, wl->chip.fw_filename, &wl->spi->dev);
if (ret < 0) {
- wl12xx_error("could not get firmware: %d", ret);
+ wl1251_error("could not get firmware: %d", ret);
return ret;
}
if (fw->size % 4) {
- wl12xx_error("firmware size is not multiple of 32 bits: %zu",
+ wl1251_error("firmware size is not multiple of 32 bits: %zu",
fw->size);
ret = -EILSEQ;
goto out;
@@ -94,7 +94,7 @@ static int wl12xx_fetch_firmware(struct wl12xx *wl)
wl->fw = kmalloc(wl->fw_len, GFP_KERNEL);
if (!wl->fw) {
- wl12xx_error("could not allocate memory for the firmware");
+ wl1251_error("could not allocate memory for the firmware");
ret = -ENOMEM;
goto out;
}
@@ -109,7 +109,7 @@ out:
return ret;
}
-static int wl12xx_fetch_nvs(struct wl12xx *wl)
+static int wl1251_fetch_nvs(struct wl1251 *wl)
{
const struct firmware *fw;
int ret;
@@ -117,12 +117,12 @@ static int wl12xx_fetch_nvs(struct wl12xx *wl)
ret = request_firmware(&fw, wl->chip.nvs_filename, &wl->spi->dev);
if (ret < 0) {
- wl12xx_error("could not get nvs file: %d", ret);
+ wl1251_error("could not get nvs file: %d", ret);
return ret;
}
if (fw->size % 4) {
- wl12xx_error("nvs size is not multiple of 32 bits: %zu",
+ wl1251_error("nvs size is not multiple of 32 bits: %zu",
fw->size);
ret = -EILSEQ;
goto out;
@@ -132,7 +132,7 @@ static int wl12xx_fetch_nvs(struct wl12xx *wl)
wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL);
if (!wl->nvs) {
- wl12xx_error("could not allocate memory for the nvs file");
+ wl1251_error("could not allocate memory for the nvs file");
ret = -ENOMEM;
goto out;
}
@@ -147,74 +147,70 @@ out:
return ret;
}
-static void wl12xx_fw_wakeup(struct wl12xx *wl)
+static void wl1251_fw_wakeup(struct wl1251 *wl)
{
u32 elp_reg;
elp_reg = ELPCTRL_WAKE_UP;
- wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
- elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
+ wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
+ elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
- if (!(elp_reg & ELPCTRL_WLAN_READY)) {
- wl12xx_warning("WLAN not ready");
- elp_reg = ELPCTRL_WAKE_UP_WLAN_READY;
- wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
- }
+ if (!(elp_reg & ELPCTRL_WLAN_READY))
+ wl1251_warning("WLAN not ready");
}
-static int wl12xx_chip_wakeup(struct wl12xx *wl)
+static int wl1251_chip_wakeup(struct wl1251 *wl)
{
int ret = 0;
- wl12xx_power_on(wl);
+ wl1251_power_on(wl);
msleep(wl->chip.power_on_sleep);
- wl12xx_spi_reset(wl);
- wl12xx_spi_init(wl);
+ wl1251_spi_reset(wl);
+ wl1251_spi_init(wl);
/* We don't need a real memory partition here, because we only want
* to use the registers at this point. */
- wl12xx_set_partition(wl,
+ wl1251_set_partition(wl,
0x00000000,
0x00000000,
REGISTERS_BASE,
REGISTERS_DOWN_SIZE);
/* ELP module wake up */
- wl12xx_fw_wakeup(wl);
+ wl1251_fw_wakeup(wl);
/* whal_FwCtrl_BootSm() */
/* 0. read chip id from CHIP_ID */
- wl->chip.id = wl12xx_reg_read32(wl, CHIP_ID_B);
+ wl->chip.id = wl1251_reg_read32(wl, CHIP_ID_B);
/* 1. check if chip id is valid */
switch (wl->chip.id) {
case CHIP_ID_1251_PG12:
- wl12xx_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)",
+ wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)",
wl->chip.id);
wl1251_setup(wl);
break;
- case CHIP_ID_1271_PG10:
case CHIP_ID_1251_PG10:
case CHIP_ID_1251_PG11:
default:
- wl12xx_error("unsupported chip id: 0x%x", wl->chip.id);
+ wl1251_error("unsupported chip id: 0x%x", wl->chip.id);
ret = -ENODEV;
goto out;
}
if (wl->fw == NULL) {
- ret = wl12xx_fetch_firmware(wl);
+ ret = wl1251_fetch_firmware(wl);
if (ret < 0)
goto out;
}
/* No NVS from netlink, try to get it from the filesystem */
if (wl->nvs == NULL) {
- ret = wl12xx_fetch_nvs(wl);
+ ret = wl1251_fetch_nvs(wl);
if (ret < 0)
goto out;
}
@@ -223,88 +219,51 @@ out:
return ret;
}
-static void wl12xx_filter_work(struct work_struct *work)
+static void wl1251_filter_work(struct work_struct *work)
{
- struct wl12xx *wl =
- container_of(work, struct wl12xx, filter_work);
+ struct wl1251 *wl =
+ container_of(work, struct wl1251, filter_work);
int ret;
mutex_lock(&wl->mutex);
- if (wl->state == WL12XX_STATE_OFF)
+ if (wl->state == WL1251_STATE_OFF)
goto out;
- ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0);
+ ret = wl1251_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
-out:
- mutex_unlock(&wl->mutex);
-}
-
-int wl12xx_plt_start(struct wl12xx *wl)
-{
- int ret;
-
- wl12xx_notice("power up");
-
- if (wl->state != WL12XX_STATE_OFF) {
- wl12xx_error("cannot go into PLT state because not "
- "in off state: %d", wl->state);
- return -EBUSY;
- }
-
- wl->state = WL12XX_STATE_PLT;
-
- ret = wl12xx_chip_wakeup(wl);
+ /* FIXME: replace the magic numbers with proper definitions */
+ ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0);
if (ret < 0)
- return ret;
+ goto out_sleep;
- ret = wl->chip.op_boot(wl);
- if (ret < 0)
- return ret;
-
- wl12xx_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
+out_sleep:
+ wl1251_ps_elp_sleep(wl);
- ret = wl->chip.op_plt_init(wl);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-int wl12xx_plt_stop(struct wl12xx *wl)
-{
- wl12xx_notice("power down");
-
- if (wl->state != WL12XX_STATE_PLT) {
- wl12xx_error("cannot power down because not in PLT "
- "state: %d", wl->state);
- return -EBUSY;
- }
-
- wl12xx_disable_interrupts(wl);
- wl12xx_power_off(wl);
-
- wl->state = WL12XX_STATE_OFF;
-
- return 0;
+out:
+ mutex_unlock(&wl->mutex);
}
-
-static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
skb_queue_tail(&wl->tx_queue, skb);
+ /*
+ * The chip specific setup must run before the first TX packet -
+ * before that, the tx_work will not be initialized!
+ */
+
schedule_work(&wl->tx_work);
/*
* 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) >= WL12XX_TX_QUEUE_MAX_LENGTH) {
+ if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_MAX_LENGTH) {
ieee80211_stop_queues(wl->hw);
/*
@@ -318,25 +277,25 @@ static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
return NETDEV_TX_OK;
}
-static int wl12xx_op_start(struct ieee80211_hw *hw)
+static int wl1251_op_start(struct ieee80211_hw *hw)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
int ret = 0;
- wl12xx_debug(DEBUG_MAC80211, "mac80211 start");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 start");
mutex_lock(&wl->mutex);
- if (wl->state != WL12XX_STATE_OFF) {
- wl12xx_error("cannot start because not in off state: %d",
+ if (wl->state != WL1251_STATE_OFF) {
+ wl1251_error("cannot start because not in off state: %d",
wl->state);
ret = -EBUSY;
goto out;
}
- ret = wl12xx_chip_wakeup(wl);
+ ret = wl1251_chip_wakeup(wl);
if (ret < 0)
- return ret;
+ goto out;
ret = wl->chip.op_boot(wl);
if (ret < 0)
@@ -346,34 +305,34 @@ static int wl12xx_op_start(struct ieee80211_hw *hw)
if (ret < 0)
goto out;
- ret = wl12xx_acx_station_id(wl);
+ ret = wl1251_acx_station_id(wl);
if (ret < 0)
goto out;
- wl->state = WL12XX_STATE_ON;
+ wl->state = WL1251_STATE_ON;
- wl12xx_info("firmware booted (%s)", wl->chip.fw_ver);
+ wl1251_info("firmware booted (%s)", wl->chip.fw_ver);
out:
if (ret < 0)
- wl12xx_power_off(wl);
+ wl1251_power_off(wl);
mutex_unlock(&wl->mutex);
return ret;
}
-static void wl12xx_op_stop(struct ieee80211_hw *hw)
+static void wl1251_op_stop(struct ieee80211_hw *hw)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
- wl12xx_info("down");
+ wl1251_info("down");
- wl12xx_debug(DEBUG_MAC80211, "mac80211 stop");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 stop");
mutex_lock(&wl->mutex);
- WARN_ON(wl->state != WL12XX_STATE_ON);
+ WARN_ON(wl->state != WL1251_STATE_ON);
if (wl->scanning) {
mutex_unlock(&wl->mutex);
@@ -382,9 +341,9 @@ static void wl12xx_op_stop(struct ieee80211_hw *hw)
wl->scanning = false;
}
- wl->state = WL12XX_STATE_OFF;
+ wl->state = WL1251_STATE_OFF;
- wl12xx_disable_interrupts(wl);
+ wl1251_disable_interrupts(wl);
mutex_unlock(&wl->mutex);
@@ -395,9 +354,8 @@ static void wl12xx_op_stop(struct ieee80211_hw *hw)
mutex_lock(&wl->mutex);
/* let's notify MAC80211 about the remaining pending TX frames */
- wl12xx_tx_flush(wl);
-
- wl12xx_power_off(wl);
+ wl->chip.op_tx_flush(wl);
+ wl1251_power_off(wl);
memset(wl->bssid, 0, ETH_ALEN);
wl->listen_int = 1;
@@ -412,22 +370,21 @@ static void wl12xx_op_stop(struct ieee80211_hw *hw)
wl->elp = false;
wl->psm = 0;
wl->tx_queue_stopped = false;
- wl->power_level = WL12XX_DEFAULT_POWER_LEVEL;
+ wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
- wl12xx_debugfs_reset(wl);
+ wl1251_debugfs_reset(wl);
mutex_unlock(&wl->mutex);
}
-static int wl12xx_op_add_interface(struct ieee80211_hw *hw,
+static int wl1251_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
- struct wl12xx *wl = hw->priv;
- DECLARE_MAC_BUF(mac);
+ struct wl1251 *wl = hw->priv;
int ret = 0;
- wl12xx_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s",
- conf->type, print_mac(mac, conf->mac_addr));
+ wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
+ conf->type, conf->mac_addr);
mutex_lock(&wl->mutex);
@@ -446,7 +403,7 @@ static int wl12xx_op_add_interface(struct ieee80211_hw *hw,
if (memcmp(wl->mac_addr, conf->mac_addr, ETH_ALEN)) {
memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
- ret = wl12xx_acx_station_id(wl);
+ ret = wl1251_acx_station_id(wl);
if (ret < 0)
goto out;
}
@@ -456,13 +413,13 @@ out:
return ret;
}
-static void wl12xx_op_remove_interface(struct ieee80211_hw *hw,
+static void wl1251_op_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
- wl12xx_debug(DEBUG_MAC80211, "mac80211 remove interface");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 remove interface");
}
-static int wl12xx_build_null_data(struct wl12xx *wl)
+static int wl1251_build_null_data(struct wl1251 *wl)
{
struct wl12xx_null_data_template template;
@@ -478,12 +435,12 @@ static int wl12xx_build_null_data(struct wl12xx *wl)
template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA |
IEEE80211_STYPE_NULLFUNC);
- return wl12xx_cmd_template_set(wl, CMD_NULL_DATA, &template,
+ return wl1251_cmd_template_set(wl, CMD_NULL_DATA, &template,
sizeof(template));
}
-static int wl12xx_build_ps_poll(struct wl12xx *wl, u16 aid)
+static int wl1251_build_ps_poll(struct wl1251 *wl, u16 aid)
{
struct wl12xx_ps_poll_template template;
@@ -492,41 +449,45 @@ static int wl12xx_build_ps_poll(struct wl12xx *wl, u16 aid)
template.aid = aid;
template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
- return wl12xx_cmd_template_set(wl, CMD_PS_POLL, &template,
+ return wl1251_cmd_template_set(wl, CMD_PS_POLL, &template,
sizeof(template));
}
-static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed)
+static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
struct ieee80211_conf *conf = &hw->conf;
int channel, ret = 0;
channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
- wl12xx_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
+ wl1251_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
channel,
conf->flags & IEEE80211_CONF_PS ? "on" : "off",
conf->power_level);
mutex_lock(&wl->mutex);
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
if (channel != wl->channel) {
/* FIXME: use beacon interval provided by mac80211 */
- ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0);
+ ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0);
if (ret < 0)
- goto out;
+ goto out_sleep;
wl->channel = channel;
}
- ret = wl12xx_build_null_data(wl);
+ ret = wl1251_build_null_data(wl);
if (ret < 0)
- goto out;
+ goto out_sleep;
if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
- wl12xx_info("psm enabled");
+ wl1251_debug(DEBUG_PSM, "psm enabled");
wl->psm_requested = true;
@@ -535,49 +496,53 @@ static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed)
* If we're not, we'll enter it when joining an SSID,
* through the bss_info_changed() hook.
*/
- ret = wl12xx_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
+ ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
} else if (!(conf->flags & IEEE80211_CONF_PS) &&
wl->psm_requested) {
- wl12xx_info("psm disabled");
+ wl1251_debug(DEBUG_PSM, "psm disabled");
wl->psm_requested = false;
if (wl->psm)
- ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE);
+ ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
}
if (conf->power_level != wl->power_level) {
- ret = wl12xx_acx_tx_power(wl, conf->power_level);
+ ret = wl1251_acx_tx_power(wl, conf->power_level);
if (ret < 0)
goto out;
wl->power_level = conf->power_level;
}
+out_sleep:
+ wl1251_ps_elp_sleep(wl);
+
out:
mutex_unlock(&wl->mutex);
+
return ret;
}
-#define WL12XX_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
+#define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
FIF_ALLMULTI | \
FIF_FCSFAIL | \
FIF_BCN_PRBRESP_PROMISC | \
FIF_CONTROL | \
FIF_OTHER_BSS)
-static void wl12xx_op_configure_filter(struct ieee80211_hw *hw,
+static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
unsigned int changed,
unsigned int *total,
int mc_count,
struct dev_addr_list *mc_list)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
- wl12xx_debug(DEBUG_MAC80211, "mac80211 configure filter");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 configure filter");
- *total &= WL12XX_SUPPORTED_FILTERS;
- changed &= WL12XX_SUPPORTED_FILTERS;
+ *total &= WL1251_SUPPORTED_FILTERS;
+ changed &= WL1251_SUPPORTED_FILTERS;
if (changed == 0)
/* no filters which we support changed */
@@ -585,8 +550,8 @@ static void wl12xx_op_configure_filter(struct ieee80211_hw *hw,
/* FIXME: wl->rx_config and wl->rx_filter are not protected */
- wl->rx_config = WL12XX_DEFAULT_RX_CONFIG;
- wl->rx_filter = WL12XX_DEFAULT_RX_FILTER;
+ wl->rx_config = WL1251_DEFAULT_RX_CONFIG;
+ wl->rx_filter = WL1251_DEFAULT_RX_FILTER;
if (*total & FIF_PROMISC_IN_BSS) {
wl->rx_config |= CFG_BSSID_FILTER_EN;
@@ -618,7 +583,8 @@ static void wl12xx_op_configure_filter(struct ieee80211_hw *hw,
}
/* HW encryption */
-static int wl12xx_set_key_type(struct wl12xx *wl, struct acx_set_key *key,
+static int wl1251_set_key_type(struct wl1251 *wl,
+ struct wl1251_cmd_set_keys *key,
enum set_key_cmd cmd,
struct ieee80211_key_conf *mac80211_key,
const u8 *addr)
@@ -648,95 +614,116 @@ static int wl12xx_set_key_type(struct wl12xx *wl, struct acx_set_key *key,
mac80211_key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
break;
default:
- wl12xx_error("Unknown key algo 0x%x", mac80211_key->alg);
+ wl1251_error("Unknown key algo 0x%x", mac80211_key->alg);
return -EOPNOTSUPP;
}
return 0;
}
-static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+static int wl1251_op_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 wl12xx *wl = hw->priv;
- struct acx_set_key wl_key;
+ struct wl1251 *wl = hw->priv;
+ struct wl1251_cmd_set_keys *wl_cmd;
const u8 *addr;
int ret;
static const u8 bcast_addr[ETH_ALEN] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- wl12xx_debug(DEBUG_MAC80211, "mac80211 set key");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 set key");
- memset(&wl_key, 0, sizeof(wl_key));
+ wl_cmd = kzalloc(sizeof(*wl_cmd), GFP_KERNEL);
+ if (!wl_cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
addr = sta ? sta->addr : bcast_addr;
- wl12xx_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
- wl12xx_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
- wl12xx_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
+ wl1251_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
+ wl1251_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
+ wl1251_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
key->alg, key->keyidx, key->keylen, key->flags);
- wl12xx_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen);
+ wl1251_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen);
+
+ if (is_zero_ether_addr(addr)) {
+ /* We dont support TX only encryption */
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
mutex_lock(&wl->mutex);
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out_unlock;
+
switch (cmd) {
case SET_KEY:
- wl_key.key_action = KEY_ADD_OR_REPLACE;
+ wl_cmd->key_action = KEY_ADD_OR_REPLACE;
break;
case DISABLE_KEY:
- wl_key.key_action = KEY_REMOVE;
+ wl_cmd->key_action = KEY_REMOVE;
break;
default:
- wl12xx_error("Unsupported key cmd 0x%x", cmd);
+ wl1251_error("Unsupported key cmd 0x%x", cmd);
break;
}
- ret = wl12xx_set_key_type(wl, &wl_key, cmd, key, addr);
+ ret = wl1251_set_key_type(wl, wl_cmd, cmd, key, addr);
if (ret < 0) {
- wl12xx_error("Set KEY type failed");
- goto out;
+ wl1251_error("Set KEY type failed");
+ goto out_sleep;
}
- if (wl_key.key_type != KEY_WEP_DEFAULT)
- memcpy(wl_key.addr, addr, ETH_ALEN);
+ if (wl_cmd->key_type != KEY_WEP_DEFAULT)
+ memcpy(wl_cmd->addr, addr, ETH_ALEN);
- if ((wl_key.key_type == KEY_TKIP_MIC_GROUP) ||
- (wl_key.key_type == KEY_TKIP_MIC_PAIRWISE)) {
+ if ((wl_cmd->key_type == KEY_TKIP_MIC_GROUP) ||
+ (wl_cmd->key_type == KEY_TKIP_MIC_PAIRWISE)) {
/*
* We get the key in the following form:
* TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes)
* but the target is expecting:
* TKIP - RX MIC - TX MIC
*/
- memcpy(wl_key.key, key->key, 16);
- memcpy(wl_key.key + 16, key->key + 24, 8);
- memcpy(wl_key.key + 24, key->key + 16, 8);
+ memcpy(wl_cmd->key, key->key, 16);
+ memcpy(wl_cmd->key + 16, key->key + 24, 8);
+ memcpy(wl_cmd->key + 24, key->key + 16, 8);
} else {
- memcpy(wl_key.key, key->key, key->keylen);
+ memcpy(wl_cmd->key, key->key, key->keylen);
}
- wl_key.key_size = key->keylen;
+ wl_cmd->key_size = key->keylen;
- wl_key.id = key->keyidx;
- wl_key.ssid_profile = 0;
+ wl_cmd->id = key->keyidx;
+ wl_cmd->ssid_profile = 0;
- wl12xx_dump(DEBUG_CRYPT, "TARGET KEY: ", &wl_key, sizeof(wl_key));
+ wl1251_dump(DEBUG_CRYPT, "TARGET KEY: ", wl_cmd, sizeof(*wl_cmd));
- if (wl12xx_cmd_send(wl, CMD_SET_KEYS, &wl_key, sizeof(wl_key)) < 0) {
- wl12xx_error("Set KEY failed");
- ret = -EOPNOTSUPP;
- goto out;
+ ret = wl1251_cmd_send(wl, CMD_SET_KEYS, wl_cmd, sizeof(*wl_cmd));
+ if (ret < 0) {
+ wl1251_warning("could not set keys");
+ goto out_sleep;
}
-out:
+out_sleep:
+ wl1251_ps_elp_sleep(wl);
+
+out_unlock:
mutex_unlock(&wl->mutex);
+
+out:
+ kfree(wl_cmd);
+
return ret;
}
-static int wl12xx_build_basic_rates(char *rates)
+static int wl1251_build_basic_rates(char *rates)
{
u8 index = 0;
@@ -748,7 +735,7 @@ static int wl12xx_build_basic_rates(char *rates)
return index;
}
-static int wl12xx_build_extended_rates(char *rates)
+static int wl1251_build_extended_rates(char *rates)
{
u8 index = 0;
@@ -765,7 +752,7 @@ static int wl12xx_build_extended_rates(char *rates)
}
-static int wl12xx_build_probe_req(struct wl12xx *wl, u8 *ssid, size_t ssid_len)
+static int wl1251_build_probe_req(struct wl1251 *wl, u8 *ssid, size_t ssid_len)
{
struct wl12xx_probe_req_template template;
struct wl12xx_ie_rates *rates;
@@ -792,31 +779,30 @@ static int wl12xx_build_probe_req(struct wl12xx *wl, u8 *ssid, size_t ssid_len)
/* Basic Rates */
rates = (struct wl12xx_ie_rates *)ptr;
rates->header.id = WLAN_EID_SUPP_RATES;
- rates->header.len = wl12xx_build_basic_rates(rates->rates);
+ rates->header.len = wl1251_build_basic_rates(rates->rates);
size += sizeof(struct wl12xx_ie_header) + rates->header.len;
ptr += sizeof(struct wl12xx_ie_header) + rates->header.len;
/* Extended rates */
rates = (struct wl12xx_ie_rates *)ptr;
rates->header.id = WLAN_EID_EXT_SUPP_RATES;
- rates->header.len = wl12xx_build_extended_rates(rates->rates);
+ rates->header.len = wl1251_build_extended_rates(rates->rates);
size += sizeof(struct wl12xx_ie_header) + rates->header.len;
- wl12xx_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size);
+ wl1251_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size);
- return wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, &template,
+ return wl1251_cmd_template_set(wl, CMD_PROBE_REQ, &template,
size);
}
-static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len,
+static int wl1251_hw_scan(struct wl1251 *wl, u8 *ssid, size_t len,
u8 active_scan, u8 high_prio, u8 num_channels,
u8 probe_requests)
{
+ struct wl1251_cmd_trigger_scan_to *trigger = NULL;
+ struct cmd_scan *params = NULL;
int i, ret;
- u32 split_scan = 0;
u16 scan_options = 0;
- struct cmd_scan *params;
- struct wl12xx_command *cmd_answer;
if (wl->scanning)
return -EINVAL;
@@ -864,33 +850,38 @@ static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len,
memset(params->params.ssid, 0, 32);
}
- ret = wl12xx_build_probe_req(wl, ssid, len);
+ ret = wl1251_build_probe_req(wl, ssid, len);
if (ret < 0) {
- wl12xx_error("PROBE request template failed");
+ wl1251_error("PROBE request template failed");
goto out;
}
- ret = wl12xx_cmd_send(wl, CMD_TRIGGER_SCAN_TO, &split_scan,
- sizeof(u32));
+ trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
+ if (!trigger)
+ goto out;
+
+ trigger->timeout = 0;
+
+ ret = wl1251_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
+ sizeof(*trigger));
if (ret < 0) {
- wl12xx_error("Split SCAN failed");
+ wl1251_error("trigger scan to failed for hw scan");
goto out;
}
- wl12xx_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
+ wl1251_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
wl->scanning = true;
- ret = wl12xx_cmd_send(wl, CMD_SCAN, params, sizeof(*params));
+ ret = wl1251_cmd_send(wl, CMD_SCAN, params, sizeof(*params));
if (ret < 0)
- wl12xx_error("SCAN failed");
+ wl1251_error("SCAN failed");
- wl12xx_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params));
+ wl1251_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params));
- cmd_answer = (struct wl12xx_command *) params;
- if (cmd_answer->status != CMD_STATUS_SUCCESS) {
- wl12xx_error("TEST command answer error: %d",
- cmd_answer->status);
+ if (params->header.status != CMD_STATUS_SUCCESS) {
+ wl1251_error("TEST command answer error: %d",
+ params->header.status);
wl->scanning = false;
ret = -EIO;
goto out;
@@ -902,15 +893,15 @@ out:
}
-static int wl12xx_op_hw_scan(struct ieee80211_hw *hw,
+static int wl1251_op_hw_scan(struct ieee80211_hw *hw,
struct cfg80211_scan_request *req)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
int ret;
u8 *ssid = NULL;
size_t ssid_len = 0;
- wl12xx_debug(DEBUG_MAC80211, "mac80211 hw scan");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan");
if (req->n_ssids) {
ssid = req->ssids[0].ssid;
@@ -918,85 +909,108 @@ static int wl12xx_op_hw_scan(struct ieee80211_hw *hw,
}
mutex_lock(&wl->mutex);
- ret = wl12xx_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3);
+
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wl1251_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3);
+
+ wl1251_ps_elp_sleep(wl);
+
+out:
mutex_unlock(&wl->mutex);
return ret;
}
-static int wl12xx_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
+static int wl1251_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
int ret;
- ret = wl12xx_acx_rts_threshold(wl, (u16) value);
+ mutex_lock(&wl->mutex);
+ ret = wl1251_ps_elp_wakeup(wl);
if (ret < 0)
- wl12xx_warning("wl12xx_op_set_rts_threshold failed: %d", ret);
+ goto out;
+
+ ret = wl1251_acx_rts_threshold(wl, (u16) value);
+ if (ret < 0)
+ wl1251_warning("wl1251_op_set_rts_threshold failed: %d", ret);
+
+ wl1251_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
return ret;
}
-static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw,
+static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
u32 changed)
{
- enum acx_ps_mode mode;
- struct wl12xx *wl = hw->priv;
+ enum wl1251_cmd_ps_mode mode;
+ struct wl1251 *wl = hw->priv;
struct sk_buff *beacon;
int ret;
- wl12xx_debug(DEBUG_MAC80211, "mac80211 bss info changed");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed");
mutex_lock(&wl->mutex);
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
if (changed & BSS_CHANGED_ASSOC) {
if (bss_conf->assoc) {
wl->aid = bss_conf->aid;
- ret = wl12xx_build_ps_poll(wl, wl->aid);
+ ret = wl1251_build_ps_poll(wl, wl->aid);
if (ret < 0)
- goto out;
+ goto out_sleep;
- ret = wl12xx_acx_aid(wl, wl->aid);
+ ret = wl1251_acx_aid(wl, wl->aid);
if (ret < 0)
- goto out;
+ goto out_sleep;
/* If we want to go in PSM but we're not there yet */
if (wl->psm_requested && !wl->psm) {
mode = STATION_POWER_SAVE_MODE;
- ret = wl12xx_ps_set_mode(wl, mode);
+ ret = wl1251_ps_set_mode(wl, mode);
if (ret < 0)
- goto out;
+ goto out_sleep;
}
}
}
if (changed & BSS_CHANGED_ERP_SLOT) {
if (bss_conf->use_short_slot)
- ret = wl12xx_acx_slot(wl, SLOT_TIME_SHORT);
+ ret = wl1251_acx_slot(wl, SLOT_TIME_SHORT);
else
- ret = wl12xx_acx_slot(wl, SLOT_TIME_LONG);
+ ret = wl1251_acx_slot(wl, SLOT_TIME_LONG);
if (ret < 0) {
- wl12xx_warning("Set slot time failed %d", ret);
- goto out;
+ wl1251_warning("Set slot time failed %d", ret);
+ goto out_sleep;
}
}
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
if (bss_conf->use_short_preamble)
- wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
+ wl1251_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
else
- wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
+ wl1251_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
}
if (changed & BSS_CHANGED_ERP_CTS_PROT) {
if (bss_conf->use_cts_prot)
- ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_ENABLE);
+ ret = wl1251_acx_cts_protect(wl, CTSPROTECT_ENABLE);
else
- ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_DISABLE);
+ ret = wl1251_acx_cts_protect(wl, CTSPROTECT_DISABLE);
if (ret < 0) {
- wl12xx_warning("Set ctsprotect failed %d", ret);
+ wl1251_warning("Set ctsprotect failed %d", ret);
goto out;
}
}
@@ -1004,20 +1018,22 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_BSSID) {
memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
- ret = wl12xx_build_null_data(wl);
+ ret = wl1251_build_null_data(wl);
if (ret < 0)
goto out;
if (wl->bss_type != BSS_TYPE_IBSS) {
- ret = wl12xx_cmd_join(wl, wl->bss_type, 5, 100, 1);
+ ret = wl1251_cmd_join(wl, wl->bss_type, 5, 100, 1);
if (ret < 0)
- goto out;
+ goto out_sleep;
+ wl1251_warning("Set ctsprotect failed %d", ret);
+ goto out_sleep;
}
}
if (changed & BSS_CHANGED_BEACON) {
beacon = ieee80211_beacon_get(hw, vif);
- ret = wl12xx_cmd_template_set(wl, CMD_BEACON, beacon->data,
+ ret = wl1251_cmd_template_set(wl, CMD_BEACON, beacon->data,
beacon->len);
if (ret < 0) {
@@ -1025,7 +1041,7 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw,
goto out;
}
- ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data,
+ ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data,
beacon->len);
dev_kfree_skb(beacon);
@@ -1033,19 +1049,22 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
- ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0);
+ ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0);
if (ret < 0)
goto out;
}
+out_sleep:
+ wl1251_ps_elp_sleep(wl);
+
out:
mutex_unlock(&wl->mutex);
}
/* can't be const, mac80211 writes to this */
-static struct ieee80211_rate wl12xx_rates[] = {
+static struct ieee80211_rate wl1251_rates[] = {
{ .bitrate = 10,
.hw_value = 0x1,
.hw_value_short = 0x1, },
@@ -1088,7 +1107,7 @@ static struct ieee80211_rate wl12xx_rates[] = {
};
/* can't be const, mac80211 writes to this */
-static struct ieee80211_channel wl12xx_channels[] = {
+static struct ieee80211_channel wl1251_channels[] = {
{ .hw_value = 1, .center_freq = 2412},
{ .hw_value = 2, .center_freq = 2417},
{ .hw_value = 3, .center_freq = 2422},
@@ -1105,28 +1124,28 @@ static struct ieee80211_channel wl12xx_channels[] = {
};
/* can't be const, mac80211 writes to this */
-static struct ieee80211_supported_band wl12xx_band_2ghz = {
- .channels = wl12xx_channels,
- .n_channels = ARRAY_SIZE(wl12xx_channels),
- .bitrates = wl12xx_rates,
- .n_bitrates = ARRAY_SIZE(wl12xx_rates),
+static struct ieee80211_supported_band wl1251_band_2ghz = {
+ .channels = wl1251_channels,
+ .n_channels = ARRAY_SIZE(wl1251_channels),
+ .bitrates = wl1251_rates,
+ .n_bitrates = ARRAY_SIZE(wl1251_rates),
};
-static const struct ieee80211_ops wl12xx_ops = {
- .start = wl12xx_op_start,
- .stop = wl12xx_op_stop,
- .add_interface = wl12xx_op_add_interface,
- .remove_interface = wl12xx_op_remove_interface,
- .config = wl12xx_op_config,
- .configure_filter = wl12xx_op_configure_filter,
- .tx = wl12xx_op_tx,
- .set_key = wl12xx_op_set_key,
- .hw_scan = wl12xx_op_hw_scan,
- .bss_info_changed = wl12xx_op_bss_info_changed,
- .set_rts_threshold = wl12xx_op_set_rts_threshold,
+static const struct ieee80211_ops wl1251_ops = {
+ .start = wl1251_op_start,
+ .stop = wl1251_op_stop,
+ .add_interface = wl1251_op_add_interface,
+ .remove_interface = wl1251_op_remove_interface,
+ .config = wl1251_op_config,
+ .configure_filter = wl1251_op_configure_filter,
+ .tx = wl1251_op_tx,
+ .set_key = wl1251_op_set_key,
+ .hw_scan = wl1251_op_hw_scan,
+ .bss_info_changed = wl1251_op_bss_info_changed,
+ .set_rts_threshold = wl1251_op_set_rts_threshold,
};
-static int wl12xx_register_hw(struct wl12xx *wl)
+static int wl1251_register_hw(struct wl1251 *wl)
{
int ret;
@@ -1137,22 +1156,22 @@ static int wl12xx_register_hw(struct wl12xx *wl)
ret = ieee80211_register_hw(wl->hw);
if (ret < 0) {
- wl12xx_error("unable to register mac80211 hw: %d", ret);
+ wl1251_error("unable to register mac80211 hw: %d", ret);
return ret;
}
wl->mac80211_registered = true;
- wl12xx_notice("loaded");
+ wl1251_notice("loaded");
return 0;
}
-static int wl12xx_init_ieee80211(struct wl12xx *wl)
+static int wl1251_init_ieee80211(struct wl1251 *wl)
{
/* The tx descriptor buffer and the TKIP space */
wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc)
- + WL12XX_TKIP_IV_SPACE;
+ + WL1251_TKIP_IV_SPACE;
/* unit us */
/* FIXME: find a proper value */
@@ -1163,31 +1182,31 @@ static int wl12xx_init_ieee80211(struct wl12xx *wl)
wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
wl->hw->wiphy->max_scan_ssids = 1;
- wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl12xx_band_2ghz;
+ wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz;
SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
return 0;
}
-#define WL12XX_DEFAULT_CHANNEL 1
-static int __devinit wl12xx_probe(struct spi_device *spi)
+#define WL1251_DEFAULT_CHANNEL 1
+static int __devinit wl1251_probe(struct spi_device *spi)
{
struct wl12xx_platform_data *pdata;
struct ieee80211_hw *hw;
- struct wl12xx *wl;
+ struct wl1251 *wl;
int ret, i;
static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
pdata = spi->dev.platform_data;
if (!pdata) {
- wl12xx_error("no platform data");
+ wl1251_error("no platform data");
return -ENODEV;
}
- hw = ieee80211_alloc_hw(sizeof(*wl), &wl12xx_ops);
+ hw = ieee80211_alloc_hw(sizeof(*wl), &wl1251_ops);
if (!hw) {
- wl12xx_error("could not alloc ieee80211_hw");
+ wl1251_error("could not alloc ieee80211_hw");
return -ENOMEM;
}
@@ -1202,9 +1221,8 @@ static int __devinit wl12xx_probe(struct spi_device *spi)
skb_queue_head_init(&wl->tx_queue);
- INIT_WORK(&wl->tx_work, wl12xx_tx_work);
- INIT_WORK(&wl->filter_work, wl12xx_filter_work);
- wl->channel = WL12XX_DEFAULT_CHANNEL;
+ INIT_WORK(&wl->filter_work, wl1251_filter_work);
+ wl->channel = WL1251_DEFAULT_CHANNEL;
wl->scanning = false;
wl->default_key = 0;
wl->listen_int = 1;
@@ -1212,17 +1230,17 @@ static int __devinit wl12xx_probe(struct spi_device *spi)
wl->rx_handled = 0;
wl->rx_current_buffer = 0;
wl->rx_last_id = 0;
- wl->rx_config = WL12XX_DEFAULT_RX_CONFIG;
- wl->rx_filter = WL12XX_DEFAULT_RX_FILTER;
+ wl->rx_config = WL1251_DEFAULT_RX_CONFIG;
+ wl->rx_filter = WL1251_DEFAULT_RX_FILTER;
wl->elp = false;
wl->psm = 0;
wl->psm_requested = false;
wl->tx_queue_stopped = false;
- wl->power_level = WL12XX_DEFAULT_POWER_LEVEL;
+ wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
/* We use the default power on sleep time until we know which chip
* we're using */
- wl->chip.power_on_sleep = WL12XX_DEFAULT_POWER_ON_SLEEP;
+ wl->chip.power_on_sleep = WL1251_DEFAULT_POWER_ON_SLEEP;
for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++)
wl->tx_frames[i] = NULL;
@@ -1236,37 +1254,46 @@ static int __devinit wl12xx_probe(struct spi_device *spi)
memcpy(wl->mac_addr, nokia_oui, 3);
get_random_bytes(wl->mac_addr + 3, 3);
- wl->state = WL12XX_STATE_OFF;
+ wl->state = WL1251_STATE_OFF;
mutex_init(&wl->mutex);
wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE;
wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE;
+ wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL);
+ if (!wl->rx_descriptor) {
+ wl1251_error("could not allocate memory for rx descriptor");
+ ret = -ENOMEM;
+ goto out_free;
+ }
+
/* 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) {
- wl12xx_error("spi_setup failed");
+ wl1251_error("spi_setup failed");
goto out_free;
}
wl->set_power = pdata->set_power;
if (!wl->set_power) {
- wl12xx_error("set power function missing in platform data");
- return -ENODEV;
+ wl1251_error("set power function missing in platform data");
+ ret = -ENODEV;
+ goto out_free;
}
wl->irq = spi->irq;
if (wl->irq < 0) {
- wl12xx_error("irq missing in platform data");
- return -ENODEV;
+ wl1251_error("irq missing in platform data");
+ ret = -ENODEV;
+ goto out_free;
}
- ret = request_irq(wl->irq, wl12xx_irq, 0, DRIVER_NAME, wl);
+ ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl);
if (ret < 0) {
- wl12xx_error("request_irq() failed: %d", ret);
+ wl1251_error("request_irq() failed: %d", ret);
goto out_free;
}
@@ -1274,17 +1301,17 @@ static int __devinit wl12xx_probe(struct spi_device *spi)
disable_irq(wl->irq);
- ret = wl12xx_init_ieee80211(wl);
+ ret = wl1251_init_ieee80211(wl);
if (ret)
goto out_irq;
- ret = wl12xx_register_hw(wl);
+ ret = wl1251_register_hw(wl);
if (ret)
goto out_irq;
- wl12xx_debugfs_init(wl);
+ wl1251_debugfs_init(wl);
- wl12xx_notice("initialized");
+ wl1251_notice("initialized");
return 0;
@@ -1292,18 +1319,21 @@ static int __devinit wl12xx_probe(struct spi_device *spi)
free_irq(wl->irq, wl);
out_free:
+ kfree(wl->rx_descriptor);
+ wl->rx_descriptor = NULL;
+
ieee80211_free_hw(hw);
return ret;
}
-static int __devexit wl12xx_remove(struct spi_device *spi)
+static int __devexit wl1251_remove(struct spi_device *spi)
{
- struct wl12xx *wl = dev_get_drvdata(&spi->dev);
+ struct wl1251 *wl = dev_get_drvdata(&spi->dev);
ieee80211_unregister_hw(wl->hw);
- wl12xx_debugfs_exit(wl);
+ wl1251_debugfs_exit(wl);
free_irq(wl->irq, wl);
kfree(wl->target_mem_map);
@@ -1312,30 +1342,35 @@ static int __devexit wl12xx_remove(struct spi_device *spi)
wl->fw = NULL;
kfree(wl->nvs);
wl->nvs = NULL;
+
+ kfree(wl->rx_descriptor);
+ wl->rx_descriptor = NULL;
+
ieee80211_free_hw(wl->hw);
return 0;
}
-static struct spi_driver wl12xx_spi_driver = {
+static struct spi_driver wl1251_spi_driver = {
.driver = {
+ /* FIXME: use wl12xx name to not break the user space */
.name = "wl12xx",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
- .probe = wl12xx_probe,
- .remove = __devexit_p(wl12xx_remove),
+ .probe = wl1251_probe,
+ .remove = __devexit_p(wl1251_remove),
};
-static int __init wl12xx_init(void)
+static int __init wl1251_init(void)
{
int ret;
- ret = spi_register_driver(&wl12xx_spi_driver);
+ ret = spi_register_driver(&wl1251_spi_driver);
if (ret < 0) {
- wl12xx_error("failed to register spi driver: %d", ret);
+ wl1251_error("failed to register spi driver: %d", ret);
goto out;
}
@@ -1343,15 +1378,15 @@ out:
return ret;
}
-static void __exit wl12xx_exit(void)
+static void __exit wl1251_exit(void)
{
- spi_unregister_driver(&wl12xx_spi_driver);
+ spi_unregister_driver(&wl1251_spi_driver);
- wl12xx_notice("unloaded");
+ wl1251_notice("unloaded");
}
-module_init(wl12xx_init);
-module_exit(wl12xx_exit);
+module_init(wl1251_init);
+module_exit(wl1251_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kalle Valo <Kalle.Valo@nokia.com>, "
diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.h b/drivers/net/wireless/wl12xx/wl1251_netlink.h
new file mode 100644
index 000000000000..ee36695e134e
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1251_netlink.h
@@ -0,0 +1,30 @@
+/*
+ * This file is part of wl1251
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Contact: Kalle Valo <kalle.valo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 __WL1251_NETLINK_H__
+#define __WL1251_NETLINK_H__
+
+int wl1251_nl_register(void);
+void wl1251_nl_unregister(void);
+
+#endif /* __WL1251_NETLINK_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1251.c b/drivers/net/wireless/wl12xx/wl1251_ops.c
index ce1561a41fa4..e7b9aab3682f 100644
--- a/drivers/net/wireless/wl12xx/wl1251.c
+++ b/drivers/net/wireless/wl12xx/wl1251_ops.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2008-2009 Nokia Corporation
*
@@ -24,18 +24,18 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include "wl1251.h"
+#include "wl1251_ops.h"
#include "reg.h"
-#include "spi.h"
-#include "boot.h"
-#include "event.h"
-#include "acx.h"
-#include "tx.h"
-#include "rx.h"
-#include "ps.h"
-#include "init.h"
-
-static struct wl12xx_partition_set wl1251_part_table[PART_TABLE_LEN] = {
+#include "wl1251_spi.h"
+#include "wl1251_boot.h"
+#include "wl1251_event.h"
+#include "wl1251_acx.h"
+#include "wl1251_tx.h"
+#include "wl1251_rx.h"
+#include "wl1251_ps.h"
+#include "wl1251_init.h"
+
+static struct wl1251_partition_set wl1251_part_table[PART_TABLE_LEN] = {
[PART_DOWN] = {
.mem = {
.start = 0x00000000,
@@ -75,31 +75,31 @@ static enum wl12xx_acx_int_reg wl1251_acx_reg_table[ACX_REG_TABLE_LEN] = {
[ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804)
};
-static int wl1251_upload_firmware(struct wl12xx *wl)
+static int wl1251_upload_firmware(struct wl1251 *wl)
{
- struct wl12xx_partition_set *p_table = wl->chip.p_table;
+ struct wl1251_partition_set *p_table = wl->chip.p_table;
int addr, chunk_num, partition_limit;
size_t fw_data_len;
u8 *p;
/* whal_FwCtrl_LoadFwImageSm() */
- wl12xx_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x",
- wl12xx_reg_read32(wl, CHIP_ID_B));
+ wl1251_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x",
+ wl1251_reg_read32(wl, CHIP_ID_B));
/* 10.0 check firmware length and set partition */
fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) |
(wl->fw[6] << 8) | (wl->fw[7]);
- wl12xx_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len,
+ wl1251_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len,
CHUNK_SIZE);
if ((fw_data_len % 4) != 0) {
- wl12xx_error("firmware length not multiple of four");
+ wl1251_error("firmware length not multiple of four");
return -EIO;
}
- wl12xx_set_partition(wl,
+ wl1251_set_partition(wl,
p_table[PART_DOWN].mem.start,
p_table[PART_DOWN].mem.size,
p_table[PART_DOWN].reg.start,
@@ -118,7 +118,7 @@ static int wl1251_upload_firmware(struct wl12xx *wl)
chunk_num * CHUNK_SIZE;
partition_limit = chunk_num * CHUNK_SIZE +
p_table[PART_DOWN].mem.size;
- wl12xx_set_partition(wl,
+ wl1251_set_partition(wl,
addr,
p_table[PART_DOWN].mem.size,
p_table[PART_DOWN].reg.start,
@@ -128,9 +128,9 @@ static int wl1251_upload_firmware(struct wl12xx *wl)
/* 10.3 upload the chunk */
addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE;
p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
- wl12xx_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
+ wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
p, addr);
- wl12xx_spi_mem_write(wl, addr, p, CHUNK_SIZE);
+ wl1251_spi_mem_write(wl, addr, p, CHUNK_SIZE);
chunk_num++;
}
@@ -138,14 +138,14 @@ static int wl1251_upload_firmware(struct wl12xx *wl)
/* 10.4 upload the last chunk */
addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE;
p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
- wl12xx_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x",
+ wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x",
fw_data_len % CHUNK_SIZE, p, addr);
- wl12xx_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE);
+ wl1251_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE);
return 0;
}
-static int wl1251_upload_nvs(struct wl12xx *wl)
+static int wl1251_upload_nvs(struct wl1251 *wl)
{
size_t nvs_len, nvs_bytes_written, burst_len;
int nvs_start, i;
@@ -181,10 +181,10 @@ static int wl1251_upload_nvs(struct wl12xx *wl)
val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
| (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
- wl12xx_debug(DEBUG_BOOT,
+ wl1251_debug(DEBUG_BOOT,
"nvs burst write 0x%x: 0x%x",
dest_addr, val);
- wl12xx_mem_write32(wl, dest_addr, val);
+ wl1251_mem_write32(wl, dest_addr, val);
nvs_ptr += 4;
dest_addr += 4;
@@ -200,7 +200,7 @@ static int wl1251_upload_nvs(struct wl12xx *wl)
nvs_len = ALIGN(nvs_len, 4);
/* Now we must set the partition correctly */
- wl12xx_set_partition(wl, nvs_start,
+ wl1251_set_partition(wl, nvs_start,
wl->chip.p_table[PART_DOWN].mem.size,
wl->chip.p_table[PART_DOWN].reg.start,
wl->chip.p_table[PART_DOWN].reg.size);
@@ -213,10 +213,10 @@ static int wl1251_upload_nvs(struct wl12xx *wl)
val = cpu_to_le32(val);
- wl12xx_debug(DEBUG_BOOT,
+ wl1251_debug(DEBUG_BOOT,
"nvs write table 0x%x: 0x%x",
nvs_start, val);
- wl12xx_mem_write32(wl, nvs_start, val);
+ wl1251_mem_write32(wl, nvs_start, val);
nvs_ptr += 4;
nvs_bytes_written += 4;
@@ -226,12 +226,12 @@ static int wl1251_upload_nvs(struct wl12xx *wl)
return 0;
}
-static int wl1251_boot(struct wl12xx *wl)
+static int wl1251_boot(struct wl1251 *wl)
{
int ret = 0, minor_minor_e2_ver;
u32 tmp, boot_data;
- ret = wl12xx_boot_soft_reset(wl);
+ ret = wl1251_boot_soft_reset(wl);
if (ret < 0)
goto out;
@@ -242,39 +242,39 @@ static int wl1251_boot(struct wl12xx *wl)
/* write firmware's last address (ie. it's length) to
* ACX_EEPROMLESS_IND_REG */
- wl12xx_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len);
+ wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len);
/* 6. read the EEPROM parameters */
- tmp = wl12xx_reg_read32(wl, SCR_PAD2);
+ tmp = wl1251_reg_read32(wl, SCR_PAD2);
/* 7. read bootdata */
wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8;
wl->boot_attr.major = (tmp & 0x00FF0000) >> 16;
- tmp = wl12xx_reg_read32(wl, SCR_PAD3);
+ tmp = wl1251_reg_read32(wl, SCR_PAD3);
/* 8. check bootdata and call restart sequence */
wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16;
minor_minor_e2_ver = (tmp & 0xFF000000) >> 24;
- wl12xx_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x "
+ wl1251_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x "
"minorE2Ver 0x%x minor_minor_e2_ver 0x%x",
wl->boot_attr.radio_type, wl->boot_attr.major,
wl->boot_attr.minor, minor_minor_e2_ver);
- ret = wl12xx_boot_init_seq(wl);
+ ret = wl1251_boot_init_seq(wl);
if (ret < 0)
goto out;
/* 9. NVS processing done */
- boot_data = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL);
+ boot_data = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL);
- wl12xx_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data);
+ wl1251_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data);
/* 10. check that ECPU_CONTROL_HALT bits are set in
* pWhalBus->uBootData and start uploading firmware
*/
if ((boot_data & ECPU_CONTROL_HALT) == 0) {
- wl12xx_error("boot failed, ECPU_CONTROL_HALT not set");
+ wl1251_error("boot failed, ECPU_CONTROL_HALT not set");
ret = -EIO;
goto out;
}
@@ -284,62 +284,62 @@ static int wl1251_boot(struct wl12xx *wl)
goto out;
/* 10.5 start firmware */
- ret = wl12xx_boot_run_firmware(wl);
+ ret = wl1251_boot_run_firmware(wl);
if (ret < 0)
goto out;
- /* Get and save the firmware version */
- wl12xx_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver));
-
out:
return ret;
}
-static int wl1251_mem_cfg(struct wl12xx *wl)
+static int wl1251_mem_cfg(struct wl1251 *wl)
{
- struct wl1251_acx_config_memory mem_conf;
+ struct wl1251_acx_config_memory *mem_conf;
int ret, i;
- wl12xx_debug(DEBUG_ACX, "wl1251 mem cfg");
+ wl1251_debug(DEBUG_ACX, "wl1251 mem cfg");
+
+ mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL);
+ if (!mem_conf) {
+ ret = -ENOMEM;
+ goto out;
+ }
/* memory config */
- mem_conf.mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS);
- mem_conf.mem_config.rx_mem_block_num = 35;
- mem_conf.mem_config.tx_min_mem_block_num = 64;
- mem_conf.mem_config.num_tx_queues = MAX_TX_QUEUES;
- mem_conf.mem_config.host_if_options = HOSTIF_PKT_RING;
- mem_conf.mem_config.num_ssid_profiles = 1;
- mem_conf.mem_config.debug_buffer_size =
+ mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS);
+ mem_conf->mem_config.rx_mem_block_num = 35;
+ mem_conf->mem_config.tx_min_mem_block_num = 64;
+ mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES;
+ mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING;
+ mem_conf->mem_config.num_ssid_profiles = 1;
+ mem_conf->mem_config.debug_buffer_size =
cpu_to_le16(TRACE_BUFFER_MAX_SIZE);
/* RX queue config */
- mem_conf.rx_queue_config.dma_address = 0;
- mem_conf.rx_queue_config.num_descs = ACX_RX_DESC_DEF;
- mem_conf.rx_queue_config.priority = DEFAULT_RXQ_PRIORITY;
- mem_conf.rx_queue_config.type = DEFAULT_RXQ_TYPE;
+ mem_conf->rx_queue_config.dma_address = 0;
+ mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF;
+ mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY;
+ mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE;
/* TX queue config */
for (i = 0; i < MAX_TX_QUEUES; i++) {
- mem_conf.tx_queue_config[i].num_descs = ACX_TX_DESC_DEF;
- mem_conf.tx_queue_config[i].attributes = i;
+ mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF;
+ mem_conf->tx_queue_config[i].attributes = i;
}
- mem_conf.header.id = ACX_MEM_CFG;
- mem_conf.header.len = sizeof(struct wl1251_acx_config_memory) -
- sizeof(struct acx_header);
- mem_conf.header.len -=
- (MAX_TX_QUEUE_CONFIGS - mem_conf.mem_config.num_tx_queues) *
- sizeof(struct wl1251_acx_tx_queue_config);
-
- ret = wl12xx_cmd_configure(wl, &mem_conf,
- sizeof(struct wl1251_acx_config_memory));
- if (ret < 0)
- wl12xx_warning("wl1251 mem config failed: %d", ret);
+ ret = wl1251_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
+ sizeof(*mem_conf));
+ if (ret < 0) {
+ wl1251_warning("wl1251 mem config failed: %d", ret);
+ goto out;
+ }
+out:
+ kfree(mem_conf);
return ret;
}
-static int wl1251_hw_init_mem_config(struct wl12xx *wl)
+static int wl1251_hw_init_mem_config(struct wl1251 *wl)
{
int ret;
@@ -350,15 +350,15 @@ static int wl1251_hw_init_mem_config(struct wl12xx *wl)
wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map),
GFP_KERNEL);
if (!wl->target_mem_map) {
- wl12xx_error("couldn't allocate target memory map");
+ wl1251_error("couldn't allocate target memory map");
return -ENOMEM;
}
/* we now ask for the firmware built memory map */
- ret = wl12xx_acx_mem_map(wl, wl->target_mem_map,
+ ret = wl1251_acx_mem_map(wl, wl->target_mem_map,
sizeof(struct wl1251_acx_mem_map));
if (ret < 0) {
- wl12xx_error("couldn't retrieve firmware memory map");
+ wl1251_error("couldn't retrieve firmware memory map");
kfree(wl->target_mem_map);
wl->target_mem_map = NULL;
return ret;
@@ -367,19 +367,19 @@ static int wl1251_hw_init_mem_config(struct wl12xx *wl)
return 0;
}
-static void wl1251_set_ecpu_ctrl(struct wl12xx *wl, u32 flag)
+static void wl1251_set_ecpu_ctrl(struct wl1251 *wl, u32 flag)
{
u32 cpu_ctrl;
/* 10.5.0 run the firmware (I) */
- cpu_ctrl = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL);
+ cpu_ctrl = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL);
/* 10.5.1 run the firmware (II) */
cpu_ctrl &= ~flag;
- wl12xx_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
+ wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
}
-static void wl1251_target_enable_interrupts(struct wl12xx *wl)
+static void wl1251_target_enable_interrupts(struct wl1251 *wl)
{
/* Enable target's interrupts */
wl->intr_mask = WL1251_ACX_INTR_RX0_DATA |
@@ -388,52 +388,60 @@ static void wl1251_target_enable_interrupts(struct wl12xx *wl)
WL1251_ACX_INTR_EVENT_A |
WL1251_ACX_INTR_EVENT_B |
WL1251_ACX_INTR_INIT_COMPLETE;
- wl12xx_boot_target_enable_interrupts(wl);
+ wl1251_boot_target_enable_interrupts(wl);
+}
+
+static void wl1251_fw_version(struct wl1251 *wl)
+{
+ wl1251_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver));
}
static void wl1251_irq_work(struct work_struct *work)
{
u32 intr;
- struct wl12xx *wl =
- container_of(work, struct wl12xx, irq_work);
+ struct wl1251 *wl =
+ container_of(work, struct wl1251, irq_work);
+ int ret;
mutex_lock(&wl->mutex);
- wl12xx_debug(DEBUG_IRQ, "IRQ work");
+ wl1251_debug(DEBUG_IRQ, "IRQ work");
- if (wl->state == WL12XX_STATE_OFF)
+ if (wl->state == WL1251_STATE_OFF)
goto out;
- wl12xx_ps_elp_wakeup(wl);
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL);
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL);
- intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
- wl12xx_debug(DEBUG_IRQ, "intr: 0x%x", intr);
+ intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
+ wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr);
if (wl->data_path) {
- wl12xx_spi_mem_read(wl, wl->data_path->rx_control_addr,
- &wl->rx_counter, sizeof(u32));
+ wl->rx_counter =
+ wl1251_mem_read32(wl, wl->data_path->rx_control_addr);
- /* We handle a frmware bug here */
+ /* We handle a firmware bug here */
switch ((wl->rx_counter - wl->rx_handled) & 0xf) {
case 0:
- wl12xx_debug(DEBUG_IRQ, "RX: FW and host in sync");
+ wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync");
intr &= ~WL1251_ACX_INTR_RX0_DATA;
intr &= ~WL1251_ACX_INTR_RX1_DATA;
break;
case 1:
- wl12xx_debug(DEBUG_IRQ, "RX: FW +1");
+ wl1251_debug(DEBUG_IRQ, "RX: FW +1");
intr |= WL1251_ACX_INTR_RX0_DATA;
intr &= ~WL1251_ACX_INTR_RX1_DATA;
break;
case 2:
- wl12xx_debug(DEBUG_IRQ, "RX: FW +2");
+ wl1251_debug(DEBUG_IRQ, "RX: FW +2");
intr |= WL1251_ACX_INTR_RX0_DATA;
intr |= WL1251_ACX_INTR_RX1_DATA;
break;
default:
- wl12xx_warning("RX: FW and host out of sync: %d",
+ wl1251_warning("RX: FW and host out of sync: %d",
wl->rx_counter - wl->rx_handled);
break;
}
@@ -441,49 +449,50 @@ static void wl1251_irq_work(struct work_struct *work)
wl->rx_handled = wl->rx_counter;
- wl12xx_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter);
+ wl1251_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter);
}
intr &= wl->intr_mask;
if (intr == 0) {
- wl12xx_debug(DEBUG_IRQ, "INTR is 0");
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
+ wl1251_debug(DEBUG_IRQ, "INTR is 0");
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
~(wl->intr_mask));
goto out_sleep;
}
if (intr & WL1251_ACX_INTR_RX0_DATA) {
- wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA");
- wl12xx_rx(wl);
+ wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA");
+ wl1251_rx(wl);
}
if (intr & WL1251_ACX_INTR_RX1_DATA) {
- wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA");
- wl12xx_rx(wl);
+ wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA");
+ wl1251_rx(wl);
}
if (intr & WL1251_ACX_INTR_TX_RESULT) {
- wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT");
- wl12xx_tx_complete(wl);
+ wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT");
+ wl1251_tx_complete(wl);
}
if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) {
- wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr);
+ wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr);
if (intr & WL1251_ACX_INTR_EVENT_A)
- wl12xx_event_handle(wl, 0);
+ wl1251_event_handle(wl, 0);
else
- wl12xx_event_handle(wl, 1);
+ wl1251_event_handle(wl, 1);
}
if (intr & WL1251_ACX_INTR_INIT_COMPLETE)
- wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE");
+ wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE");
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
out_sleep:
- wl12xx_ps_elp_sleep(wl);
+ wl1251_ps_elp_sleep(wl);
+
out:
mutex_unlock(&wl->mutex);
}
@@ -520,40 +529,45 @@ static int wl1251_hw_init_txq_fill(u8 qid,
(QOS_TX_LOW_VO_DEF * num_blocks) / 100;
break;
default:
- wl12xx_error("Invalid TX queue id: %d", qid);
+ wl1251_error("Invalid TX queue id: %d", qid);
return -EINVAL;
}
return 0;
}
-static int wl1251_hw_init_tx_queue_config(struct wl12xx *wl)
+static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl)
{
- struct acx_tx_queue_qos_config config;
+ struct acx_tx_queue_qos_config *config;
struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map;
int ret, i;
- wl12xx_debug(DEBUG_ACX, "acx tx queue config");
+ wl1251_debug(DEBUG_ACX, "acx tx queue config");
- config.header.id = ACX_TX_QUEUE_CFG;
- config.header.len = sizeof(struct acx_tx_queue_qos_config) -
- sizeof(struct acx_header);
+ config = kzalloc(sizeof(*config), GFP_KERNEL);
+ if (!config) {
+ ret = -ENOMEM;
+ goto out;
+ }
for (i = 0; i < MAX_NUM_OF_AC; i++) {
- ret = wl1251_hw_init_txq_fill(i, &config,
+ ret = wl1251_hw_init_txq_fill(i, config,
wl_mem_map->num_tx_mem_blocks);
if (ret < 0)
- return ret;
+ goto out;
- ret = wl12xx_cmd_configure(wl, &config, sizeof(config));
+ ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG,
+ config, sizeof(*config));
if (ret < 0)
- return ret;
+ goto out;
}
- return 0;
+out:
+ kfree(config);
+ return ret;
}
-static int wl1251_hw_init_data_path_config(struct wl12xx *wl)
+static int wl1251_hw_init_data_path_config(struct wl1251 *wl)
{
int ret;
@@ -561,11 +575,11 @@ static int wl1251_hw_init_data_path_config(struct wl12xx *wl)
wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp),
GFP_KERNEL);
if (!wl->data_path) {
- wl12xx_error("Couldnt allocate data path parameters");
+ wl1251_error("Couldn't allocate data path parameters");
return -ENOMEM;
}
- ret = wl12xx_acx_data_path_params(wl, wl->data_path);
+ ret = wl1251_acx_data_path_params(wl, wl->data_path);
if (ret < 0) {
kfree(wl->data_path);
wl->data_path = NULL;
@@ -575,17 +589,17 @@ static int wl1251_hw_init_data_path_config(struct wl12xx *wl)
return 0;
}
-static int wl1251_hw_init(struct wl12xx *wl)
+static int wl1251_hw_init(struct wl1251 *wl)
{
struct wl1251_acx_mem_map *wl_mem_map;
int ret;
- ret = wl12xx_hw_init_hwenc_config(wl);
+ ret = wl1251_hw_init_hwenc_config(wl);
if (ret < 0)
return ret;
/* Template settings */
- ret = wl12xx_hw_init_templates_config(wl);
+ ret = wl1251_hw_init_templates_config(wl);
if (ret < 0)
return ret;
@@ -600,7 +614,7 @@ static int wl1251_hw_init(struct wl12xx *wl)
goto out_free_memmap;
/* RX config */
- ret = wl12xx_hw_init_rx_config(wl,
+ ret = wl1251_hw_init_rx_config(wl,
RX_CFG_PROMISCUOUS | RX_CFG_TSF,
RX_FILTER_OPTION_DEF);
/* RX_CONFIG_OPTION_ANY_DST_ANY_BSS,
@@ -614,42 +628,42 @@ static int wl1251_hw_init(struct wl12xx *wl)
goto out_free_data_path;
/* PHY layer config */
- ret = wl12xx_hw_init_phy_config(wl);
+ ret = wl1251_hw_init_phy_config(wl);
if (ret < 0)
goto out_free_data_path;
/* Beacon filtering */
- ret = wl12xx_hw_init_beacon_filter(wl);
+ ret = wl1251_hw_init_beacon_filter(wl);
if (ret < 0)
goto out_free_data_path;
/* Bluetooth WLAN coexistence */
- ret = wl12xx_hw_init_pta(wl);
+ ret = wl1251_hw_init_pta(wl);
if (ret < 0)
goto out_free_data_path;
/* Energy detection */
- ret = wl12xx_hw_init_energy_detection(wl);
+ ret = wl1251_hw_init_energy_detection(wl);
if (ret < 0)
goto out_free_data_path;
/* Beacons and boradcast settings */
- ret = wl12xx_hw_init_beacon_broadcast(wl);
+ ret = wl1251_hw_init_beacon_broadcast(wl);
if (ret < 0)
goto out_free_data_path;
/* Enable data path */
- ret = wl12xx_cmd_data_path(wl, wl->channel, 1);
+ ret = wl1251_cmd_data_path(wl, wl->channel, 1);
if (ret < 0)
goto out_free_data_path;
/* Default power state */
- ret = wl12xx_hw_init_power_auth(wl);
+ ret = wl1251_hw_init_power_auth(wl);
if (ret < 0)
goto out_free_data_path;
wl_mem_map = wl->target_mem_map;
- wl12xx_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x",
+ wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x",
wl_mem_map->num_tx_mem_blocks,
wl->data_path->tx_control_addr,
wl_mem_map->num_rx_mem_blocks,
@@ -666,7 +680,7 @@ static int wl1251_hw_init(struct wl12xx *wl)
return ret;
}
-static int wl1251_plt_init(struct wl12xx *wl)
+static int wl1251_plt_init(struct wl1251 *wl)
{
int ret;
@@ -674,14 +688,14 @@ static int wl1251_plt_init(struct wl12xx *wl)
if (ret < 0)
return ret;
- ret = wl12xx_cmd_data_path(wl, wl->channel, 1);
+ ret = wl1251_cmd_data_path(wl, wl->channel, 1);
if (ret < 0)
return ret;
return 0;
}
-void wl1251_setup(struct wl12xx *wl)
+void wl1251_setup(struct wl1251 *wl)
{
/* FIXME: Is it better to use strncpy here or is this ok? */
wl->chip.fw_filename = WL1251_FW_NAME;
@@ -701,9 +715,14 @@ void wl1251_setup(struct wl12xx *wl)
wl->chip.op_target_enable_interrupts = wl1251_target_enable_interrupts;
wl->chip.op_hw_init = wl1251_hw_init;
wl->chip.op_plt_init = wl1251_plt_init;
+ wl->chip.op_fw_version = wl1251_fw_version;
+ wl->chip.op_tx_flush = wl1251_tx_flush;
+ wl->chip.op_cmd_join = wl1251_cmd_join;
wl->chip.p_table = wl1251_part_table;
wl->chip.acx_reg_table = wl1251_acx_reg_table;
INIT_WORK(&wl->irq_work, wl1251_irq_work);
+ INIT_WORK(&wl->tx_work, wl1251_tx_work);
+
}
diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.h b/drivers/net/wireless/wl12xx/wl1251_ops.h
new file mode 100644
index 000000000000..68183c472e43
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1251_ops.h
@@ -0,0 +1,165 @@
+/*
+ * This file is part of wl1251
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Kalle Valo <kalle.valo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 __WL1251_OPS_H__
+#define __WL1251_OPS_H__
+
+#include <linux/bitops.h>
+
+#include "wl1251.h"
+#include "wl1251_acx.h"
+
+#define WL1251_FW_NAME "wl1251-fw.bin"
+#define WL1251_NVS_NAME "wl1251-nvs.bin"
+
+#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */
+
+void wl1251_setup(struct wl1251 *wl);
+
+
+struct wl1251_acx_memory {
+ __le16 num_stations; /* number of STAs to be supported. */
+ u16 reserved_1;
+
+ /*
+ * Nmber of memory buffers for the RX mem pool.
+ * The actual number may be less if there are
+ * not enough blocks left for the minimum num
+ * of TX ones.
+ */
+ u8 rx_mem_block_num;
+ u8 reserved_2;
+ u8 num_tx_queues; /* From 1 to 16 */
+ u8 host_if_options; /* HOST_IF* */
+ u8 tx_min_mem_block_num;
+ u8 num_ssid_profiles;
+ __le16 debug_buffer_size;
+} __attribute__ ((packed));
+
+
+#define ACX_RX_DESC_MIN 1
+#define ACX_RX_DESC_MAX 127
+#define ACX_RX_DESC_DEF 32
+struct wl1251_acx_rx_queue_config {
+ u8 num_descs;
+ u8 pad;
+ u8 type;
+ u8 priority;
+ __le32 dma_address;
+} __attribute__ ((packed));
+
+#define ACX_TX_DESC_MIN 1
+#define ACX_TX_DESC_MAX 127
+#define ACX_TX_DESC_DEF 16
+struct wl1251_acx_tx_queue_config {
+ u8 num_descs;
+ u8 pad[2];
+ u8 attributes;
+} __attribute__ ((packed));
+
+#define MAX_TX_QUEUE_CONFIGS 5
+#define MAX_TX_QUEUES 4
+struct wl1251_acx_config_memory {
+ struct acx_header header;
+
+ struct wl1251_acx_memory mem_config;
+ struct wl1251_acx_rx_queue_config rx_queue_config;
+ struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS];
+} __attribute__ ((packed));
+
+struct wl1251_acx_mem_map {
+ struct acx_header header;
+
+ void *code_start;
+ void *code_end;
+
+ void *wep_defkey_start;
+ void *wep_defkey_end;
+
+ void *sta_table_start;
+ void *sta_table_end;
+
+ void *packet_template_start;
+ void *packet_template_end;
+
+ void *queue_memory_start;
+ void *queue_memory_end;
+
+ void *packet_memory_pool_start;
+ void *packet_memory_pool_end;
+
+ void *debug_buffer1_start;
+ void *debug_buffer1_end;
+
+ void *debug_buffer2_start;
+ void *debug_buffer2_end;
+
+ /* Number of blocks FW allocated for TX packets */
+ u32 num_tx_mem_blocks;
+
+ /* Number of blocks FW allocated for RX packets */
+ u32 num_rx_mem_blocks;
+} __attribute__ ((packed));
+
+/*************************************************************************
+
+ Host Interrupt Register (WiLink -> Host)
+
+**************************************************************************/
+
+/* RX packet is ready in Xfer buffer #0 */
+#define WL1251_ACX_INTR_RX0_DATA BIT(0)
+
+/* TX result(s) are in the TX complete buffer */
+#define WL1251_ACX_INTR_TX_RESULT BIT(1)
+
+/* OBSOLETE */
+#define WL1251_ACX_INTR_TX_XFR BIT(2)
+
+/* RX packet is ready in Xfer buffer #1 */
+#define WL1251_ACX_INTR_RX1_DATA BIT(3)
+
+/* Event was entered to Event MBOX #A */
+#define WL1251_ACX_INTR_EVENT_A BIT(4)
+
+/* Event was entered to Event MBOX #B */
+#define WL1251_ACX_INTR_EVENT_B BIT(5)
+
+/* OBSOLETE */
+#define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6)
+
+/* Trace meassge on MBOX #A */
+#define WL1251_ACX_INTR_TRACE_A BIT(7)
+
+/* Trace meassge on MBOX #B */
+#define WL1251_ACX_INTR_TRACE_B BIT(8)
+
+/* Command processing completion */
+#define WL1251_ACX_INTR_CMD_COMPLETE BIT(9)
+
+/* Init sequence is done */
+#define WL1251_ACX_INTR_INIT_COMPLETE BIT(14)
+
+#define WL1251_ACX_INTR_ALL 0xFFFFFFFF
+
+#endif
diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c
index 83a10117330b..68ff7f1900ed 100644
--- a/drivers/net/wireless/wl12xx/ps.c
+++ b/drivers/net/wireless/wl12xx/wl1251_ps.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2008 Nokia Corporation
*
@@ -22,25 +22,25 @@
*/
#include "reg.h"
-#include "ps.h"
-#include "spi.h"
+#include "wl1251_ps.h"
+#include "wl1251_spi.h"
-#define WL12XX_WAKEUP_TIMEOUT 2000
+#define WL1251_WAKEUP_TIMEOUT 2000
/* Routines to toggle sleep mode while in ELP */
-void wl12xx_ps_elp_sleep(struct wl12xx *wl)
+void wl1251_ps_elp_sleep(struct wl1251 *wl)
{
if (wl->elp || !wl->psm)
return;
- wl12xx_debug(DEBUG_PSM, "chip to elp");
+ wl1251_debug(DEBUG_PSM, "chip to elp");
- wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
+ wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
wl->elp = true;
}
-int wl12xx_ps_elp_wakeup(struct wl12xx *wl)
+int wl1251_ps_elp_wakeup(struct wl1251 *wl)
{
unsigned long timeout;
u32 elp_reg;
@@ -48,13 +48,13 @@ int wl12xx_ps_elp_wakeup(struct wl12xx *wl)
if (!wl->elp)
return 0;
- wl12xx_debug(DEBUG_PSM, "waking up chip from elp");
+ wl1251_debug(DEBUG_PSM, "waking up chip from elp");
- timeout = jiffies + msecs_to_jiffies(WL12XX_WAKEUP_TIMEOUT);
+ timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT);
- wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
+ wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
- elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
+ elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
/*
* FIXME: we should wait for irq from chip but, as a temporary
@@ -62,40 +62,36 @@ int wl12xx_ps_elp_wakeup(struct wl12xx *wl)
*/
while (!(elp_reg & ELPCTRL_WLAN_READY)) {
if (time_after(jiffies, timeout)) {
- wl12xx_error("elp wakeup timeout");
+ wl1251_error("elp wakeup timeout");
return -ETIMEDOUT;
}
msleep(1);
- elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
+ elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
}
- wl12xx_debug(DEBUG_PSM, "wakeup time: %u ms",
+ wl1251_debug(DEBUG_PSM, "wakeup time: %u ms",
jiffies_to_msecs(jiffies) -
- (jiffies_to_msecs(timeout) - WL12XX_WAKEUP_TIMEOUT));
+ (jiffies_to_msecs(timeout) - WL1251_WAKEUP_TIMEOUT));
wl->elp = false;
return 0;
}
-static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable)
+static int wl1251_ps_set_elp(struct wl1251 *wl, bool enable)
{
int ret;
if (enable) {
- wl12xx_debug(DEBUG_PSM, "sleep auth psm/elp");
+ wl1251_debug(DEBUG_PSM, "sleep auth psm/elp");
- /*
- * FIXME: we should PSM_ELP, but because of firmware wakeup
- * problems let's use only PSM_PS
- */
- ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_PS);
+ ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP);
if (ret < 0)
return ret;
- wl12xx_ps_elp_sleep(wl);
+ wl1251_ps_elp_sleep(wl);
} else {
- wl12xx_debug(DEBUG_PSM, "sleep auth cam");
+ wl1251_debug(DEBUG_PSM, "sleep auth cam");
/*
* When the target is in ELP, we can only
@@ -104,9 +100,9 @@ static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable)
* changing the power authorization.
*/
- wl12xx_ps_elp_wakeup(wl);
+ wl1251_ps_elp_wakeup(wl);
- ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM);
+ ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM);
if (ret < 0)
return ret;
}
@@ -114,18 +110,18 @@ static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable)
return 0;
}
-int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode)
+int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode)
{
int ret;
switch (mode) {
case STATION_POWER_SAVE_MODE:
- wl12xx_debug(DEBUG_PSM, "entering psm");
- ret = wl12xx_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
+ wl1251_debug(DEBUG_PSM, "entering psm");
+ ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
if (ret < 0)
return ret;
- ret = wl12xx_ps_set_elp(wl, true);
+ ret = wl1251_ps_set_elp(wl, true);
if (ret < 0)
return ret;
@@ -133,12 +129,12 @@ int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode)
break;
case STATION_ACTIVE_MODE:
default:
- wl12xx_debug(DEBUG_PSM, "leaving psm");
- ret = wl12xx_ps_set_elp(wl, false);
+ wl1251_debug(DEBUG_PSM, "leaving psm");
+ ret = wl1251_ps_set_elp(wl, false);
if (ret < 0)
return ret;
- ret = wl12xx_cmd_ps_mode(wl, STATION_ACTIVE_MODE);
+ ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE);
if (ret < 0)
return ret;
diff --git a/drivers/net/wireless/wl12xx/ps.h b/drivers/net/wireless/wl12xx/wl1251_ps.h
index 5d7c52553830..db036fe12f25 100644
--- a/drivers/net/wireless/wl12xx/ps.h
+++ b/drivers/net/wireless/wl12xx/wl1251_ps.h
@@ -1,8 +1,8 @@
-#ifndef __WL12XX_PS_H__
-#define __WL12XX_PS_H__
+#ifndef __WL1251_PS_H__
+#define __WL1251_PS_H__
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -25,12 +25,12 @@
*
*/
-#include "wl12xx.h"
-#include "acx.h"
+#include "wl1251.h"
+#include "wl1251_acx.h"
-int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode);
-void wl12xx_ps_elp_sleep(struct wl12xx *wl);
-int wl12xx_ps_elp_wakeup(struct wl12xx *wl);
+int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode);
+void wl1251_ps_elp_sleep(struct wl1251 *wl);
+int wl1251_ps_elp_wakeup(struct wl1251 *wl);
-#endif /* __WL12XX_PS_H__ */
+#endif /* __WL1251_PS_H__ */
diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c
index 981ea259eb89..0dbb483a0973 100644
--- a/drivers/net/wireless/wl12xx/rx.c
+++ b/drivers/net/wireless/wl12xx/wl1251_rx.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -25,13 +25,14 @@
#include <linux/skbuff.h>
#include <net/mac80211.h>
-#include "wl12xx.h"
+#include "wl1251.h"
#include "reg.h"
-#include "spi.h"
-#include "rx.h"
+#include "wl1251_spi.h"
+#include "wl1251_rx.h"
+#include "wl1251_acx.h"
-static void wl12xx_rx_header(struct wl12xx *wl,
- struct wl12xx_rx_descriptor *desc)
+static void wl1251_rx_header(struct wl1251 *wl,
+ struct wl1251_rx_descriptor *desc)
{
u32 rx_packet_ring_addr;
@@ -39,15 +40,17 @@ static void wl12xx_rx_header(struct wl12xx *wl,
if (wl->rx_current_buffer)
rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size;
- wl12xx_spi_mem_read(wl, rx_packet_ring_addr, desc,
- sizeof(struct wl12xx_rx_descriptor));
+ wl1251_spi_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc));
}
-static void wl12xx_rx_status(struct wl12xx *wl,
- struct wl12xx_rx_descriptor *desc,
+static void wl1251_rx_status(struct wl1251 *wl,
+ struct wl1251_rx_descriptor *desc,
struct ieee80211_rx_status *status,
u8 beacon)
{
+ u64 mactime;
+ int ret;
+
memset(status, 0, sizeof(struct ieee80211_rx_status));
status->band = IEEE80211_BAND_2GHZ;
@@ -62,32 +65,14 @@ static void wl12xx_rx_status(struct wl12xx *wl,
* this one must be atomic, while our SPI routines can sleep.
*/
if ((wl->bss_type == BSS_TYPE_IBSS) && beacon) {
- u64 mactime;
- int ret;
- struct wl12xx_command cmd;
- struct acx_tsf_info *tsf_info;
-
- memset(&cmd, 0, sizeof(cmd));
-
- ret = wl12xx_cmd_interrogate(wl, ACX_TSF_INFO,
- sizeof(struct acx_tsf_info),
- &cmd);
- if (ret < 0) {
- wl12xx_warning("ACX_FW_REV interrogate failed");
- return;
- }
-
- tsf_info = (struct acx_tsf_info *)&(cmd.parameters);
-
- mactime = tsf_info->current_tsf_lsb |
- (tsf_info->current_tsf_msb << 31);
-
- status->mactime = mactime;
+ ret = wl1251_acx_tsf_info(wl, &mactime);
+ if (ret == 0)
+ status->mactime = mactime;
}
status->signal = desc->rssi;
- status->qual = (desc->rssi - WL12XX_RX_MIN_RSSI) * 100 /
- (WL12XX_RX_MAX_RSSI - WL12XX_RX_MIN_RSSI);
+ status->qual = (desc->rssi - WL1251_RX_MIN_RSSI) * 100 /
+ (WL1251_RX_MAX_RSSI - WL1251_RX_MIN_RSSI);
status->qual = min(status->qual, 100);
status->qual = max(status->qual, 0);
@@ -118,8 +103,8 @@ static void wl12xx_rx_status(struct wl12xx *wl,
/* FIXME: set status->rate_idx */
}
-static void wl12xx_rx_body(struct wl12xx *wl,
- struct wl12xx_rx_descriptor *desc)
+static void wl1251_rx_body(struct wl1251 *wl,
+ struct wl1251_rx_descriptor *desc)
{
struct sk_buff *skb;
struct ieee80211_rx_status status;
@@ -127,12 +112,12 @@ static void wl12xx_rx_body(struct wl12xx *wl,
u16 length, *fc;
u32 curr_id, last_id_inc, rx_packet_ring_addr;
- length = WL12XX_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH);
+ length = WL1251_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH);
curr_id = (desc->flags & RX_DESC_SEQNUM_MASK) >> RX_DESC_PACKETID_SHIFT;
last_id_inc = (wl->rx_last_id + 1) % (RX_MAX_PACKET_ID + 1);
if (last_id_inc != curr_id) {
- wl12xx_warning("curr ID:%d, last ID inc:%d",
+ wl1251_warning("curr ID:%d, last ID inc:%d",
curr_id, last_id_inc);
wl->rx_last_id = curr_id;
} else {
@@ -140,18 +125,18 @@ static void wl12xx_rx_body(struct wl12xx *wl,
}
rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr +
- sizeof(struct wl12xx_rx_descriptor) + 20;
+ sizeof(struct wl1251_rx_descriptor) + 20;
if (wl->rx_current_buffer)
rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size;
skb = dev_alloc_skb(length);
if (!skb) {
- wl12xx_error("Couldn't allocate RX frame");
+ wl1251_error("Couldn't allocate RX frame");
return;
}
rx_buffer = skb_put(skb, length);
- wl12xx_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length);
+ wl1251_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length);
/* The actual lenght doesn't include the target's alignment */
skb->len = desc->length - PLCP_HEADER_LENGTH;
@@ -161,15 +146,16 @@ static void wl12xx_rx_body(struct wl12xx *wl,
if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON)
beacon = 1;
- wl12xx_rx_status(wl, desc, &status, beacon);
+ wl1251_rx_status(wl, desc, &status, beacon);
- wl12xx_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len,
+ wl1251_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len,
beacon ? "beacon" : "");
- ieee80211_rx(wl->hw, skb, &status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx(wl->hw, skb);
}
-static void wl12xx_rx_ack(struct wl12xx *wl)
+static void wl1251_rx_ack(struct wl1251 *wl)
{
u32 data, addr;
@@ -181,28 +167,30 @@ static void wl12xx_rx_ack(struct wl12xx *wl)
data = INTR_TRIG_RX_PROC0;
}
- wl12xx_reg_write32(wl, addr, data);
+ wl1251_reg_write32(wl, addr, data);
/* Toggle buffer ring */
wl->rx_current_buffer = !wl->rx_current_buffer;
}
-void wl12xx_rx(struct wl12xx *wl)
+void wl1251_rx(struct wl1251 *wl)
{
- struct wl12xx_rx_descriptor rx_desc;
+ struct wl1251_rx_descriptor *rx_desc;
- if (wl->state != WL12XX_STATE_ON)
+ if (wl->state != WL1251_STATE_ON)
return;
+ rx_desc = wl->rx_descriptor;
+
/* We first read the frame's header */
- wl12xx_rx_header(wl, &rx_desc);
+ wl1251_rx_header(wl, rx_desc);
/* Now we can read the body */
- wl12xx_rx_body(wl, &rx_desc);
+ wl1251_rx_body(wl, rx_desc);
/* Finally, we need to ACK the RX */
- wl12xx_rx_ack(wl);
+ wl1251_rx_ack(wl);
return;
}
diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/wl1251_rx.h
index 8a23fdea5016..563a3fde40fb 100644
--- a/drivers/net/wireless/wl12xx/rx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_rx.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,11 +22,13 @@
*
*/
-#ifndef __WL12XX_RX_H__
-#define __WL12XX_RX_H__
+#ifndef __WL1251_RX_H__
+#define __WL1251_RX_H__
#include <linux/bitops.h>
+#include "wl1251.h"
+
/*
* RX PATH
*
@@ -43,12 +45,12 @@
* 4) The target prepares the next RX packet.
*/
-#define WL12XX_RX_MAX_RSSI -30
-#define WL12XX_RX_MIN_RSSI -95
+#define WL1251_RX_MAX_RSSI -30
+#define WL1251_RX_MIN_RSSI -95
-#define WL12XX_RX_ALIGN_TO 4
-#define WL12XX_RX_ALIGN(len) (((len) + WL12XX_RX_ALIGN_TO - 1) & \
- ~(WL12XX_RX_ALIGN_TO - 1))
+#define WL1251_RX_ALIGN_TO 4
+#define WL1251_RX_ALIGN(len) (((len) + WL1251_RX_ALIGN_TO - 1) & \
+ ~(WL1251_RX_ALIGN_TO - 1))
#define SHORT_PREAMBLE_BIT BIT(0)
#define OFDM_RATE_BIT BIT(6)
@@ -72,7 +74,7 @@
#define RX_DESC_MIC_FAIL 0x2000
#define RX_DESC_DECRYPT_FAIL 0x4000
-struct wl12xx_rx_descriptor {
+struct wl1251_rx_descriptor {
u32 timestamp; /* In microseconds */
u16 length; /* Paylod length, including headers */
u16 flags;
@@ -86,7 +88,7 @@ struct wl12xx_rx_descriptor {
u8 type;
/*
- * Recevied Rate:
+ * Received Rate:
* 0x0A - 1MBPS
* 0x14 - 2MBPS
* 0x37 - 5_5MBPS
@@ -117,6 +119,6 @@ struct wl12xx_rx_descriptor {
u8 snr; /* in dB */
} __attribute__ ((packed));
-void wl12xx_rx(struct wl12xx *wl);
+void wl1251_rx(struct wl1251 *wl);
#endif
diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c
index abdf171a47e7..c5da79dbc49c 100644
--- a/drivers/net/wireless/wl12xx/spi.c
+++ b/drivers/net/wireless/wl12xx/wl1251_spi.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2008 Nokia Corporation
*
@@ -25,13 +25,11 @@
#include <linux/crc7.h>
#include <linux/spi/spi.h>
-#include "wl12xx.h"
-#include "wl12xx_80211.h"
+#include "wl1251.h"
#include "reg.h"
-#include "spi.h"
-#include "ps.h"
+#include "wl1251_spi.h"
-static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr)
+static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr)
{
/* If the address is lower than REGISTERS_BASE, it means that this is
* a chip-specific register address, so look it up in the registers
@@ -39,7 +37,7 @@ static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr)
if (addr < REGISTERS_BASE) {
/* Make sure we don't go over the table */
if (addr >= ACX_REG_TABLE_LEN) {
- wl12xx_error("address out of range (%d)", addr);
+ wl1251_error("address out of range (%d)", addr);
return -EINVAL;
}
addr = wl->chip.acx_reg_table[addr];
@@ -48,13 +46,13 @@ static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr)
return addr - wl->physical_reg_addr + wl->virtual_reg_addr;
}
-static int wl12xx_translate_mem_addr(struct wl12xx *wl, int addr)
+static int wl1251_translate_mem_addr(struct wl1251 *wl, int addr)
{
return addr - wl->physical_mem_addr + wl->virtual_mem_addr;
}
-void wl12xx_spi_reset(struct wl12xx *wl)
+void wl1251_spi_reset(struct wl1251 *wl)
{
u8 *cmd;
struct spi_transfer t;
@@ -62,7 +60,7 @@ void wl12xx_spi_reset(struct wl12xx *wl)
cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);
if (!cmd) {
- wl12xx_error("could not allocate cmd for spi reset");
+ wl1251_error("could not allocate cmd for spi reset");
return;
}
@@ -77,10 +75,10 @@ void wl12xx_spi_reset(struct wl12xx *wl)
spi_sync(wl->spi, &m);
- wl12xx_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
+ wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
}
-void wl12xx_spi_init(struct wl12xx *wl)
+void wl1251_spi_init(struct wl1251 *wl)
{
u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd;
struct spi_transfer t;
@@ -88,7 +86,7 @@ void wl12xx_spi_init(struct wl12xx *wl)
cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);
if (!cmd) {
- wl12xx_error("could not allocate cmd for spi init");
+ wl1251_error("could not allocate cmd for spi init");
return;
}
@@ -131,7 +129,7 @@ void wl12xx_spi_init(struct wl12xx *wl)
spi_sync(wl->spi, &m);
- wl12xx_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
+ wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
}
/* Set the SPI partitions to access the chip addresses
@@ -167,45 +165,47 @@ void wl12xx_spi_init(struct wl12xx *wl)
* | |
*
*/
-void wl12xx_set_partition(struct wl12xx *wl,
+int wl1251_set_partition(struct wl1251 *wl,
u32 mem_start, u32 mem_size,
u32 reg_start, u32 reg_size)
{
- u8 tx_buf[sizeof(u32) + 2 * sizeof(struct wl12xx_partition)];
- struct wl12xx_partition *partition;
+ struct wl1251_partition *partition;
struct spi_transfer t;
struct spi_message m;
+ size_t len, cmd_len;
u32 *cmd;
- size_t len;
int addr;
+ cmd_len = sizeof(u32) + 2 * sizeof(struct wl1251_partition);
+ cmd = kzalloc(cmd_len, GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
spi_message_init(&m);
memset(&t, 0, sizeof(t));
- memset(tx_buf, 0, sizeof(tx_buf));
- cmd = (u32 *) tx_buf;
- partition = (struct wl12xx_partition *) (tx_buf + sizeof(u32));
+ partition = (struct wl1251_partition *) (cmd + 1);
addr = HW_ACCESS_PART0_SIZE_ADDR;
- len = 2 * sizeof(struct wl12xx_partition);
+ len = 2 * sizeof(struct wl1251_partition);
*cmd |= WSPI_CMD_WRITE;
*cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
*cmd |= addr & WSPI_CMD_BYTE_ADDR;
- wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
mem_start, mem_size);
- wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
reg_start, reg_size);
/* Make sure that the two partitions together don't exceed the
* address range */
if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) {
- wl12xx_debug(DEBUG_SPI, "Total size exceeds maximum virtual"
+ wl1251_debug(DEBUG_SPI, "Total size exceeds maximum virtual"
" address range. Truncating partition[0].");
mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size;
- wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
mem_start, mem_size);
- wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
reg_start, reg_size);
}
@@ -213,23 +213,23 @@ void wl12xx_set_partition(struct wl12xx *wl,
((mem_start + mem_size) > reg_start)) {
/* Guarantee that the memory partition doesn't overlap the
* registers partition */
- wl12xx_debug(DEBUG_SPI, "End of partition[0] is "
+ wl1251_debug(DEBUG_SPI, "End of partition[0] is "
"overlapping partition[1]. Adjusted.");
mem_size = reg_start - mem_start;
- wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
mem_start, mem_size);
- wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
reg_start, reg_size);
} else if ((reg_start < mem_start) &&
((reg_start + reg_size) > mem_start)) {
/* Guarantee that the register partition doesn't overlap the
* memory partition */
- wl12xx_debug(DEBUG_SPI, "End of partition[1] is"
+ wl1251_debug(DEBUG_SPI, "End of partition[1] is"
" overlapping partition[0]. Adjusted.");
reg_size = mem_start - reg_start;
- wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
mem_start, mem_size);
- wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
reg_start, reg_size);
}
@@ -244,36 +244,46 @@ void wl12xx_set_partition(struct wl12xx *wl,
wl->virtual_mem_addr = 0;
wl->virtual_reg_addr = mem_size;
- t.tx_buf = tx_buf;
- t.len = sizeof(tx_buf);
+ t.tx_buf = cmd;
+ t.len = cmd_len;
spi_message_add_tail(&t, &m);
spi_sync(wl->spi, &m);
+
+ kfree(cmd);
+
+ return 0;
}
-void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf,
- size_t len)
+void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf,
+ size_t len, bool fixed)
{
struct spi_transfer t[3];
struct spi_message m;
- char busy_buf[TNETWIF_READ_OFFSET_BYTES];
- u32 cmd;
+ u8 *busy_buf;
+ u32 *cmd;
+
+ cmd = &wl->buffer_cmd;
+ busy_buf = wl->buffer_busyword;
+
+ *cmd = 0;
+ *cmd |= WSPI_CMD_READ;
+ *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
+ *cmd |= addr & WSPI_CMD_BYTE_ADDR;
- cmd = 0;
- cmd |= WSPI_CMD_READ;
- cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
- cmd |= addr & WSPI_CMD_BYTE_ADDR;
+ if (fixed)
+ *cmd |= WSPI_CMD_FIXED;
spi_message_init(&m);
memset(t, 0, sizeof(t));
- t[0].tx_buf = &cmd;
+ t[0].tx_buf = cmd;
t[0].len = 4;
spi_message_add_tail(&t[0], &m);
/* Busy and non busy words read */
t[1].rx_buf = busy_buf;
- t[1].len = TNETWIF_READ_OFFSET_BYTES;
+ t[1].len = WL1251_BUSY_WORD_LEN;
spi_message_add_tail(&t[1], &m);
t[2].rx_buf = buf;
@@ -284,27 +294,32 @@ void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf,
/* FIXME: check busy words */
- wl12xx_dump(DEBUG_SPI, "spi_read cmd -> ", &cmd, sizeof(cmd));
- wl12xx_dump(DEBUG_SPI, "spi_read buf <- ", buf, len);
+ wl1251_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd));
+ wl1251_dump(DEBUG_SPI, "spi_read buf <- ", buf, len);
}
-void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf,
- size_t len)
+void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf,
+ size_t len, bool fixed)
{
struct spi_transfer t[2];
struct spi_message m;
- u32 cmd;
+ u32 *cmd;
+
+ cmd = &wl->buffer_cmd;
- cmd = 0;
- cmd |= WSPI_CMD_WRITE;
- cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
- cmd |= addr & WSPI_CMD_BYTE_ADDR;
+ *cmd = 0;
+ *cmd |= WSPI_CMD_WRITE;
+ *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
+ *cmd |= addr & WSPI_CMD_BYTE_ADDR;
+
+ if (fixed)
+ *cmd |= WSPI_CMD_FIXED;
spi_message_init(&m);
memset(t, 0, sizeof(t));
- t[0].tx_buf = &cmd;
- t[0].len = sizeof(cmd);
+ t[0].tx_buf = cmd;
+ t[0].len = sizeof(*cmd);
spi_message_add_tail(&t[0], &m);
t[1].tx_buf = buf;
@@ -313,46 +328,66 @@ void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf,
spi_sync(wl->spi, &m);
- wl12xx_dump(DEBUG_SPI, "spi_write cmd -> ", &cmd, sizeof(cmd));
- wl12xx_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
+ wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd));
+ wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
}
-void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf,
+void wl1251_spi_mem_read(struct wl1251 *wl, int addr, void *buf,
size_t len)
{
int physical;
- physical = wl12xx_translate_mem_addr(wl, addr);
+ physical = wl1251_translate_mem_addr(wl, addr);
- wl12xx_spi_read(wl, physical, buf, len);
+ wl1251_spi_read(wl, physical, buf, len, false);
}
-void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf,
+void wl1251_spi_mem_write(struct wl1251 *wl, int addr, void *buf,
size_t len)
{
int physical;
- physical = wl12xx_translate_mem_addr(wl, addr);
+ physical = wl1251_translate_mem_addr(wl, addr);
+
+ wl1251_spi_write(wl, physical, buf, len, false);
+}
+
+void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len,
+ bool fixed)
+{
+ int physical;
+
+ physical = wl1251_translate_reg_addr(wl, addr);
+
+ wl1251_spi_read(wl, physical, buf, len, fixed);
+}
+
+void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len,
+ bool fixed)
+{
+ int physical;
+
+ physical = wl1251_translate_reg_addr(wl, addr);
- wl12xx_spi_write(wl, physical, buf, len);
+ wl1251_spi_write(wl, physical, buf, len, fixed);
}
-u32 wl12xx_mem_read32(struct wl12xx *wl, int addr)
+u32 wl1251_mem_read32(struct wl1251 *wl, int addr)
{
- return wl12xx_read32(wl, wl12xx_translate_mem_addr(wl, addr));
+ return wl1251_read32(wl, wl1251_translate_mem_addr(wl, addr));
}
-void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val)
+void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val)
{
- wl12xx_write32(wl, wl12xx_translate_mem_addr(wl, addr), val);
+ wl1251_write32(wl, wl1251_translate_mem_addr(wl, addr), val);
}
-u32 wl12xx_reg_read32(struct wl12xx *wl, int addr)
+u32 wl1251_reg_read32(struct wl1251 *wl, int addr)
{
- return wl12xx_read32(wl, wl12xx_translate_reg_addr(wl, addr));
+ return wl1251_read32(wl, wl1251_translate_reg_addr(wl, addr));
}
-void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val)
+void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val)
{
- wl12xx_write32(wl, wl12xx_translate_reg_addr(wl, addr), val);
+ wl1251_write32(wl, wl1251_translate_reg_addr(wl, addr), val);
}
diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/wl1251_spi.h
index fd3227e904a8..6e8daf4e1085 100644
--- a/drivers/net/wireless/wl12xx/spi.h
+++ b/drivers/net/wireless/wl12xx/wl1251_spi.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,11 +22,11 @@
*
*/
-#ifndef __WL12XX_SPI_H__
-#define __WL12XX_SPI_H__
+#ifndef __WL1251_SPI_H__
+#define __WL1251_SPI_H__
-#include "cmd.h"
-#include "acx.h"
+#include "wl1251_cmd.h"
+#include "wl1251_acx.h"
#include "reg.h"
#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0
@@ -65,45 +65,51 @@
#define WSPI_INIT_CMD_LEN 8
-#define TNETWIF_READ_OFFSET_BYTES 8
#define HW_ACCESS_WSPI_FIXED_BUSY_LEN \
- ((TNETWIF_READ_OFFSET_BYTES - 4) / sizeof(u32))
+ ((WL1251_BUSY_WORD_LEN - 4) / sizeof(u32))
#define HW_ACCESS_WSPI_INIT_CMD_MASK 0
/* Raw target IO, address is not translated */
-void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, size_t len);
-void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, size_t len);
+void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf,
+ size_t len, bool fixed);
+void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf,
+ size_t len, bool fixed);
/* Memory target IO, address is tranlated to partition 0 */
-void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, size_t len);
-void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, size_t len);
-u32 wl12xx_mem_read32(struct wl12xx *wl, int addr);
-void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val);
+void wl1251_spi_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len);
+void wl1251_spi_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len);
+u32 wl1251_mem_read32(struct wl1251 *wl, int addr);
+void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val);
/* Registers IO */
-u32 wl12xx_reg_read32(struct wl12xx *wl, int addr);
-void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val);
+void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len,
+ bool fixed);
+void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len,
+ bool fixed);
+u32 wl1251_reg_read32(struct wl1251 *wl, int addr);
+void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val);
/* INIT and RESET words */
-void wl12xx_spi_reset(struct wl12xx *wl);
-void wl12xx_spi_init(struct wl12xx *wl);
-void wl12xx_set_partition(struct wl12xx *wl,
- u32 part_start, u32 part_size,
- u32 reg_start, u32 reg_size);
+void wl1251_spi_reset(struct wl1251 *wl);
+void wl1251_spi_init(struct wl1251 *wl);
+int wl1251_set_partition(struct wl1251 *wl,
+ u32 part_start, u32 part_size,
+ u32 reg_start, u32 reg_size);
-static inline u32 wl12xx_read32(struct wl12xx *wl, int addr)
+static inline u32 wl1251_read32(struct wl1251 *wl, int addr)
{
- u32 response;
+ wl1251_spi_read(wl, addr, &wl->buffer_32,
+ sizeof(wl->buffer_32), false);
- wl12xx_spi_read(wl, addr, &response, sizeof(u32));
-
- return response;
+ return wl->buffer_32;
}
-static inline void wl12xx_write32(struct wl12xx *wl, int addr, u32 val)
+static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val)
{
- wl12xx_spi_write(wl, addr, &val, sizeof(u32));
+ wl->buffer_32 = val;
+ wl1251_spi_write(wl, addr, &wl->buffer_32,
+ sizeof(wl->buffer_32), false);
}
-#endif /* __WL12XX_SPI_H__ */
+#endif /* __WL1251_SPI_H__ */
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c
index 62145e205a8c..2652a222383a 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/wl1251_tx.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -25,13 +25,13 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include "wl12xx.h"
+#include "wl1251.h"
#include "reg.h"
-#include "spi.h"
-#include "tx.h"
-#include "ps.h"
+#include "wl1251_spi.h"
+#include "wl1251_tx.h"
+#include "wl1251_ps.h"
-static bool wl12xx_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count)
+static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count)
{
int used, data_in_count;
@@ -52,15 +52,15 @@ static bool wl12xx_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count)
return false;
}
-static int wl12xx_tx_path_status(struct wl12xx *wl)
+static int wl1251_tx_path_status(struct wl1251 *wl)
{
u32 status, addr, data_out_count;
bool busy;
addr = wl->data_path->tx_control_addr;
- status = wl12xx_mem_read32(wl, addr);
+ status = wl1251_mem_read32(wl, addr);
data_out_count = status & TX_STATUS_DATA_OUT_COUNT_MASK;
- busy = wl12xx_tx_double_buffer_busy(wl, data_out_count);
+ busy = wl1251_tx_double_buffer_busy(wl, data_out_count);
if (busy)
return -EBUSY;
@@ -68,7 +68,7 @@ static int wl12xx_tx_path_status(struct wl12xx *wl)
return 0;
}
-static int wl12xx_tx_id(struct wl12xx *wl, struct sk_buff *skb)
+static int wl1251_tx_id(struct wl1251 *wl, struct sk_buff *skb)
{
int i;
@@ -81,7 +81,7 @@ static int wl12xx_tx_id(struct wl12xx *wl, struct sk_buff *skb)
return -EBUSY;
}
-static void wl12xx_tx_control(struct tx_double_buffer_desc *tx_hdr,
+static void wl1251_tx_control(struct tx_double_buffer_desc *tx_hdr,
struct ieee80211_tx_info *control, u16 fc)
{
*(u16 *)&tx_hdr->control = 0;
@@ -109,7 +109,7 @@ static void wl12xx_tx_control(struct tx_double_buffer_desc *tx_hdr,
#define MAX_MPDU_HEADER_AND_SECURITY (MAX_MPDU_SECURITY_LENGTH + \
WLAN_QOS_HDR_LEN)
#define HW_BLOCK_SIZE 252
-static void wl12xx_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr)
+static void wl1251_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr)
{
u16 payload_len, frag_threshold, mem_blocks;
u16 num_mpdus, mem_blocks_per_frag;
@@ -142,7 +142,7 @@ static void wl12xx_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr)
tx_hdr->num_mem_blocks = mem_blocks;
}
-static int wl12xx_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb,
+static int wl1251_tx_fill_hdr(struct wl1251 *wl, struct sk_buff *skb,
struct ieee80211_tx_info *control)
{
struct tx_double_buffer_desc *tx_hdr;
@@ -153,7 +153,7 @@ static int wl12xx_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb,
if (!skb)
return -EINVAL;
- id = wl12xx_tx_id(wl, skb);
+ id = wl1251_tx_id(wl, skb);
if (id < 0)
return id;
@@ -170,14 +170,14 @@ static int wl12xx_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb,
/* FIXME: how to get the correct queue id? */
tx_hdr->xmit_queue = 0;
- wl12xx_tx_control(tx_hdr, control, fc);
- wl12xx_tx_frag_block_num(tx_hdr);
+ wl1251_tx_control(tx_hdr, control, fc);
+ wl1251_tx_frag_block_num(tx_hdr);
return 0;
}
/* We copy the packet to the target */
-static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
+static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb,
struct ieee80211_tx_info *control)
{
struct tx_double_buffer_desc *tx_hdr;
@@ -196,12 +196,12 @@ static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
u8 *pos;
fc = *(u16 *)(skb->data + sizeof(*tx_hdr));
- tx_hdr->length += WL12XX_TKIP_IV_SPACE;
+ tx_hdr->length += WL1251_TKIP_IV_SPACE;
hdrlen = ieee80211_hdrlen(fc);
- pos = skb_push(skb, WL12XX_TKIP_IV_SPACE);
- memmove(pos, pos + WL12XX_TKIP_IV_SPACE,
+ pos = skb_push(skb, WL1251_TKIP_IV_SPACE);
+ memmove(pos, pos + WL1251_TKIP_IV_SPACE,
sizeof(*tx_hdr) + hdrlen);
}
@@ -211,7 +211,7 @@ static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
*/
if (unlikely((long)skb->data & 0x03)) {
int offset = (4 - (long)skb->data) & 0x03;
- wl12xx_debug(DEBUG_TX, "skb offset %d", offset);
+ wl1251_debug(DEBUG_TX, "skb offset %d", offset);
/* check whether the current skb can be used */
if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) {
@@ -221,13 +221,13 @@ static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
skb_reserve(skb, offset);
memmove(skb->data, src, skb->len);
} else {
- wl12xx_info("No handler, fixme!");
+ wl1251_info("No handler, fixme!");
return -EINVAL;
}
}
/* Our skb->data at this point includes the HW header */
- len = WL12XX_TX_ALIGN(skb->len);
+ len = WL1251_TX_ALIGN(skb->len);
if (wl->data_in_count & 0x1)
addr = wl->data_path->tx_packet_ring_addr +
@@ -235,15 +235,15 @@ static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
else
addr = wl->data_path->tx_packet_ring_addr;
- wl12xx_spi_mem_write(wl, addr, skb->data, len);
+ wl1251_spi_mem_write(wl, addr, skb->data, len);
- wl12xx_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x",
+ wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x",
tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate);
return 0;
}
-static void wl12xx_tx_trigger(struct wl12xx *wl)
+static void wl1251_tx_trigger(struct wl1251 *wl)
{
u32 data, addr;
@@ -255,7 +255,7 @@ static void wl12xx_tx_trigger(struct wl12xx *wl)
data = INTR_TRIG_TX_PROC0;
}
- wl12xx_reg_write32(wl, addr, data);
+ wl1251_reg_write32(wl, addr, data);
/* Bumping data in */
wl->data_in_count = (wl->data_in_count + 1) &
@@ -263,7 +263,7 @@ static void wl12xx_tx_trigger(struct wl12xx *wl)
}
/* caller must hold wl->mutex */
-static int wl12xx_tx_frame(struct wl12xx *wl, struct sk_buff *skb)
+static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb)
{
struct ieee80211_tx_info *info;
int ret = 0;
@@ -274,51 +274,53 @@ static int wl12xx_tx_frame(struct wl12xx *wl, struct sk_buff *skb)
if (info->control.hw_key) {
idx = info->control.hw_key->hw_key_idx;
if (unlikely(wl->default_key != idx)) {
- ret = wl12xx_acx_default_key(wl, idx);
+ ret = wl1251_acx_default_key(wl, idx);
if (ret < 0)
return ret;
}
}
- ret = wl12xx_tx_path_status(wl);
+ ret = wl1251_tx_path_status(wl);
if (ret < 0)
return ret;
- ret = wl12xx_tx_fill_hdr(wl, skb, info);
+ ret = wl1251_tx_fill_hdr(wl, skb, info);
if (ret < 0)
return ret;
- ret = wl12xx_tx_send_packet(wl, skb, info);
+ ret = wl1251_tx_send_packet(wl, skb, info);
if (ret < 0)
return ret;
- wl12xx_tx_trigger(wl);
+ wl1251_tx_trigger(wl);
return ret;
}
-void wl12xx_tx_work(struct work_struct *work)
+void wl1251_tx_work(struct work_struct *work)
{
- struct wl12xx *wl = container_of(work, struct wl12xx, tx_work);
+ struct wl1251 *wl = container_of(work, struct wl1251, tx_work);
struct sk_buff *skb;
bool woken_up = false;
int ret;
mutex_lock(&wl->mutex);
- if (unlikely(wl->state == WL12XX_STATE_OFF))
+ if (unlikely(wl->state == WL1251_STATE_OFF))
goto out;
while ((skb = skb_dequeue(&wl->tx_queue))) {
if (!woken_up) {
- wl12xx_ps_elp_wakeup(wl);
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
woken_up = true;
}
- ret = wl12xx_tx_frame(wl, skb);
+ ret = wl1251_tx_frame(wl, skb);
if (ret == -EBUSY) {
/* firmware buffer is full, stop queues */
- wl12xx_debug(DEBUG_TX, "tx_work: fw buffer full, "
+ wl1251_debug(DEBUG_TX, "tx_work: fw buffer full, "
"stop queues");
ieee80211_stop_queues(wl->hw);
wl->tx_queue_stopped = true;
@@ -332,12 +334,12 @@ void wl12xx_tx_work(struct work_struct *work)
out:
if (woken_up)
- wl12xx_ps_elp_sleep(wl);
+ wl1251_ps_elp_sleep(wl);
mutex_unlock(&wl->mutex);
}
-static const char *wl12xx_tx_parse_status(u8 status)
+static const char *wl1251_tx_parse_status(u8 status)
{
/* 8 bit status field, one character per bit plus null */
static char buf[9];
@@ -365,7 +367,7 @@ static const char *wl12xx_tx_parse_status(u8 status)
return buf;
}
-static void wl12xx_tx_packet_cb(struct wl12xx *wl,
+static void wl1251_tx_packet_cb(struct wl1251 *wl,
struct tx_result *result)
{
struct ieee80211_tx_info *info;
@@ -375,7 +377,7 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
skb = wl->tx_frames[result->id];
if (skb == NULL) {
- wl12xx_error("SKB for packet %d is NULL", result->id);
+ wl1251_error("SKB for packet %d is NULL", result->id);
return;
}
@@ -396,14 +398,14 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
if (info->control.hw_key &&
info->control.hw_key->alg == ALG_TKIP) {
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
- memmove(frame + WL12XX_TKIP_IV_SPACE, frame, hdrlen);
- skb_pull(skb, WL12XX_TKIP_IV_SPACE);
+ memmove(frame + WL1251_TKIP_IV_SPACE, frame, hdrlen);
+ skb_pull(skb, WL1251_TKIP_IV_SPACE);
}
- wl12xx_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x"
+ wl1251_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x"
" status 0x%x (%s)",
result->id, skb, result->ack_failures, result->rate,
- result->status, wl12xx_tx_parse_status(result->status));
+ result->status, wl1251_tx_parse_status(result->status));
ieee80211_tx_status(wl->hw, skb);
@@ -411,7 +413,7 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
wl->tx_frames[result->id] = NULL;
if (wl->tx_queue_stopped) {
- wl12xx_debug(DEBUG_TX, "cb: queue was stopped");
+ wl1251_debug(DEBUG_TX, "cb: queue was stopped");
skb = skb_dequeue(&wl->tx_queue);
@@ -420,10 +422,10 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
queue empty */
if (skb) {
- ret = wl12xx_tx_frame(wl, skb);
+ ret = wl1251_tx_frame(wl, skb);
if (ret == -EBUSY) {
/* firmware buffer is still full */
- wl12xx_debug(DEBUG_TX, "cb: fw buffer "
+ wl1251_debug(DEBUG_TX, "cb: fw buffer "
"still full");
skb_queue_head(&wl->tx_queue, skb);
return;
@@ -433,23 +435,23 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
}
}
- wl12xx_debug(DEBUG_TX, "cb: waking queues");
+ wl1251_debug(DEBUG_TX, "cb: waking queues");
ieee80211_wake_queues(wl->hw);
wl->tx_queue_stopped = false;
}
}
/* Called upon reception of a TX complete interrupt */
-void wl12xx_tx_complete(struct wl12xx *wl)
+void wl1251_tx_complete(struct wl1251 *wl)
{
int i, result_index, num_complete = 0;
struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr;
- if (unlikely(wl->state != WL12XX_STATE_ON))
+ if (unlikely(wl->state != WL1251_STATE_ON))
return;
/* First we read the result */
- wl12xx_spi_mem_read(wl, wl->data_path->tx_complete_addr,
+ wl1251_spi_mem_read(wl, wl->data_path->tx_complete_addr,
result, sizeof(result));
result_index = wl->next_tx_complete;
@@ -459,7 +461,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
if (result_ptr->done_1 == 1 &&
result_ptr->done_2 == 1) {
- wl12xx_tx_packet_cb(wl, result_ptr);
+ wl1251_tx_packet_cb(wl, result_ptr);
result_ptr->done_1 = 0;
result_ptr->done_2 = 0;
@@ -480,7 +482,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
*/
if (result_index > wl->next_tx_complete) {
/* Only 1 write is needed */
- wl12xx_spi_mem_write(wl,
+ wl1251_spi_mem_write(wl,
wl->data_path->tx_complete_addr +
(wl->next_tx_complete *
sizeof(struct tx_result)),
@@ -491,7 +493,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
} else if (result_index < wl->next_tx_complete) {
/* 2 writes are needed */
- wl12xx_spi_mem_write(wl,
+ wl1251_spi_mem_write(wl,
wl->data_path->tx_complete_addr +
(wl->next_tx_complete *
sizeof(struct tx_result)),
@@ -500,7 +502,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
wl->next_tx_complete) *
sizeof(struct tx_result));
- wl12xx_spi_mem_write(wl,
+ wl1251_spi_mem_write(wl,
wl->data_path->tx_complete_addr,
result,
(num_complete -
@@ -510,7 +512,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
} else {
/* We have to write the whole array */
- wl12xx_spi_mem_write(wl,
+ wl1251_spi_mem_write(wl,
wl->data_path->tx_complete_addr,
result,
FW_TX_CMPLT_BLOCK_SIZE *
@@ -523,7 +525,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
}
/* caller must hold wl->mutex */
-void wl12xx_tx_flush(struct wl12xx *wl)
+void wl1251_tx_flush(struct wl1251 *wl)
{
int i;
struct sk_buff *skb;
@@ -535,7 +537,7 @@ void wl12xx_tx_flush(struct wl12xx *wl)
while ((skb = skb_dequeue(&wl->tx_queue))) {
info = IEEE80211_SKB_CB(skb);
- wl12xx_debug(DEBUG_TX, "flushing skb 0x%p", skb);
+ wl1251_debug(DEBUG_TX, "flushing skb 0x%p", skb);
if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS))
continue;
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/wl1251_tx.h
index dc82691f4c14..7c1c1665c810 100644
--- a/drivers/net/wireless/wl12xx/tx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_tx.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,8 +22,8 @@
*
*/
-#ifndef __WL12XX_TX_H__
-#define __WL12XX_TX_H__
+#ifndef __WL1251_TX_H__
+#define __WL1251_TX_H__
#include <linux/bitops.h>
@@ -73,10 +73,11 @@
#define TX_COMPLETE_REQUIRED_BIT 0x80
#define TX_STATUS_DATA_OUT_COUNT_MASK 0xf
-#define WL12XX_TX_ALIGN_TO 4
-#define WL12XX_TX_ALIGN(len) (((len) + WL12XX_TX_ALIGN_TO - 1) & \
- ~(WL12XX_TX_ALIGN_TO - 1))
-#define WL12XX_TKIP_IV_SPACE 4
+
+#define WL1251_TX_ALIGN_TO 4
+#define WL1251_TX_ALIGN(len) (((len) + WL1251_TX_ALIGN_TO - 1) & \
+ ~(WL1251_TX_ALIGN_TO - 1))
+#define WL1251_TKIP_IV_SPACE 4
struct tx_control {
/* Rate Policy (class) index */
@@ -208,8 +209,8 @@ struct tx_result {
u8 done_2;
} __attribute__ ((packed));
-void wl12xx_tx_work(struct work_struct *work);
-void wl12xx_tx_complete(struct wl12xx *wl);
-void wl12xx_tx_flush(struct wl12xx *wl);
+void wl1251_tx_work(struct work_struct *work);
+void wl1251_tx_complete(struct wl1251 *wl);
+void wl1251_tx_flush(struct wl1251 *wl);
#endif
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
deleted file mode 100644
index 48641437414b..000000000000
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- * This file is part of wl12xx
- *
- * Copyright (c) 1998-2007 Texas Instruments Incorporated
- * Copyright (C) 2008-2009 Nokia Corporation
- *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * 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 __WL12XX_H__
-#define __WL12XX_H__
-
-#include <linux/mutex.h>
-#include <linux/list.h>
-#include <linux/bitops.h>
-#include <net/mac80211.h>
-
-#define DRIVER_NAME "wl12xx"
-#define DRIVER_PREFIX DRIVER_NAME ": "
-
-enum {
- DEBUG_NONE = 0,
- DEBUG_IRQ = BIT(0),
- DEBUG_SPI = BIT(1),
- DEBUG_BOOT = BIT(2),
- DEBUG_MAILBOX = BIT(3),
- DEBUG_NETLINK = BIT(4),
- DEBUG_EVENT = BIT(5),
- DEBUG_TX = BIT(6),
- DEBUG_RX = BIT(7),
- DEBUG_SCAN = BIT(8),
- DEBUG_CRYPT = BIT(9),
- DEBUG_PSM = BIT(10),
- DEBUG_MAC80211 = BIT(11),
- DEBUG_CMD = BIT(12),
- DEBUG_ACX = BIT(13),
- DEBUG_ALL = ~0,
-};
-
-#define DEBUG_LEVEL (DEBUG_NONE)
-
-#define DEBUG_DUMP_LIMIT 1024
-
-#define wl12xx_error(fmt, arg...) \
- printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg)
-
-#define wl12xx_warning(fmt, arg...) \
- printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg)
-
-#define wl12xx_notice(fmt, arg...) \
- printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg)
-
-#define wl12xx_info(fmt, arg...) \
- printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg)
-
-#define wl12xx_debug(level, fmt, arg...) \
- do { \
- if (level & DEBUG_LEVEL) \
- printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \
- } while (0)
-
-#define wl12xx_dump(level, prefix, buf, len) \
- do { \
- if (level & DEBUG_LEVEL) \
- print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
- DUMP_PREFIX_OFFSET, 16, 1, \
- buf, \
- min_t(size_t, len, DEBUG_DUMP_LIMIT), \
- 0); \
- } while (0)
-
-#define wl12xx_dump_ascii(level, prefix, buf, len) \
- do { \
- if (level & DEBUG_LEVEL) \
- print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
- DUMP_PREFIX_OFFSET, 16, 1, \
- buf, \
- min_t(size_t, len, DEBUG_DUMP_LIMIT), \
- true); \
- } while (0)
-
-#define WL12XX_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \
- CFG_BSSID_FILTER_EN)
-
-#define WL12XX_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \
- CFG_RX_MGMT_EN | \
- CFG_RX_DATA_EN | \
- CFG_RX_CTL_EN | \
- CFG_RX_BCN_EN | \
- CFG_RX_AUTH_EN | \
- CFG_RX_ASSOC_EN)
-
-
-struct boot_attr {
- u32 radio_type;
- u8 mac_clock;
- u8 arm_clock;
- int firmware_debug;
- u32 minor;
- u32 major;
- u32 bugfix;
-};
-
-enum wl12xx_state {
- WL12XX_STATE_OFF,
- WL12XX_STATE_ON,
- WL12XX_STATE_PLT,
-};
-
-enum wl12xx_partition_type {
- PART_DOWN,
- PART_WORK,
- PART_DRPW,
-
- PART_TABLE_LEN
-};
-
-struct wl12xx_partition {
- u32 size;
- u32 start;
-};
-
-struct wl12xx_partition_set {
- struct wl12xx_partition mem;
- struct wl12xx_partition reg;
-};
-
-struct wl12xx;
-
-/* FIXME: I'm not sure about this structure name */
-struct wl12xx_chip {
- u32 id;
-
- const char *fw_filename;
- const char *nvs_filename;
-
- char fw_ver[21];
-
- unsigned int power_on_sleep;
- int intr_cmd_complete;
- int intr_init_complete;
-
- int (*op_upload_fw)(struct wl12xx *wl);
- int (*op_upload_nvs)(struct wl12xx *wl);
- int (*op_boot)(struct wl12xx *wl);
- void (*op_set_ecpu_ctrl)(struct wl12xx *wl, u32 flag);
- void (*op_target_enable_interrupts)(struct wl12xx *wl);
- int (*op_hw_init)(struct wl12xx *wl);
- int (*op_plt_init)(struct wl12xx *wl);
-
- struct wl12xx_partition_set *p_table;
- enum wl12xx_acx_int_reg *acx_reg_table;
-};
-
-struct wl12xx_stats {
- struct acx_statistics *fw_stats;
- unsigned long fw_stats_update;
-
- unsigned int retry_count;
- unsigned int excessive_retries;
-};
-
-struct wl12xx_debugfs {
- struct dentry *rootdir;
- struct dentry *fw_statistics;
-
- struct dentry *tx_internal_desc_overflow;
-
- struct dentry *rx_out_of_mem;
- struct dentry *rx_hdr_overflow;
- struct dentry *rx_hw_stuck;
- struct dentry *rx_dropped;
- struct dentry *rx_fcs_err;
- struct dentry *rx_xfr_hint_trig;
- struct dentry *rx_path_reset;
- struct dentry *rx_reset_counter;
-
- struct dentry *dma_rx_requested;
- struct dentry *dma_rx_errors;
- struct dentry *dma_tx_requested;
- struct dentry *dma_tx_errors;
-
- struct dentry *isr_cmd_cmplt;
- struct dentry *isr_fiqs;
- struct dentry *isr_rx_headers;
- struct dentry *isr_rx_mem_overflow;
- struct dentry *isr_rx_rdys;
- struct dentry *isr_irqs;
- struct dentry *isr_tx_procs;
- struct dentry *isr_decrypt_done;
- struct dentry *isr_dma0_done;
- struct dentry *isr_dma1_done;
- struct dentry *isr_tx_exch_complete;
- struct dentry *isr_commands;
- struct dentry *isr_rx_procs;
- struct dentry *isr_hw_pm_mode_changes;
- struct dentry *isr_host_acknowledges;
- struct dentry *isr_pci_pm;
- struct dentry *isr_wakeups;
- struct dentry *isr_low_rssi;
-
- struct dentry *wep_addr_key_count;
- struct dentry *wep_default_key_count;
- /* skipping wep.reserved */
- struct dentry *wep_key_not_found;
- struct dentry *wep_decrypt_fail;
- struct dentry *wep_packets;
- struct dentry *wep_interrupt;
-
- struct dentry *pwr_ps_enter;
- struct dentry *pwr_elp_enter;
- struct dentry *pwr_missing_bcns;
- struct dentry *pwr_wake_on_host;
- struct dentry *pwr_wake_on_timer_exp;
- struct dentry *pwr_tx_with_ps;
- struct dentry *pwr_tx_without_ps;
- struct dentry *pwr_rcvd_beacons;
- struct dentry *pwr_power_save_off;
- struct dentry *pwr_enable_ps;
- struct dentry *pwr_disable_ps;
- struct dentry *pwr_fix_tsf_ps;
- /* skipping cont_miss_bcns_spread for now */
- struct dentry *pwr_rcvd_awake_beacons;
-
- struct dentry *mic_rx_pkts;
- struct dentry *mic_calc_failure;
-
- struct dentry *aes_encrypt_fail;
- struct dentry *aes_decrypt_fail;
- struct dentry *aes_encrypt_packets;
- struct dentry *aes_decrypt_packets;
- struct dentry *aes_encrypt_interrupt;
- struct dentry *aes_decrypt_interrupt;
-
- struct dentry *event_heart_beat;
- struct dentry *event_calibration;
- struct dentry *event_rx_mismatch;
- struct dentry *event_rx_mem_empty;
- struct dentry *event_rx_pool;
- struct dentry *event_oom_late;
- struct dentry *event_phy_transmit_error;
- struct dentry *event_tx_stuck;
-
- struct dentry *ps_pspoll_timeouts;
- struct dentry *ps_upsd_timeouts;
- struct dentry *ps_upsd_max_sptime;
- struct dentry *ps_upsd_max_apturn;
- struct dentry *ps_pspoll_max_apturn;
- struct dentry *ps_pspoll_utilization;
- struct dentry *ps_upsd_utilization;
-
- struct dentry *rxpipe_rx_prep_beacon_drop;
- struct dentry *rxpipe_descr_host_int_trig_rx_data;
- struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data;
- struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data;
- struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data;
-
- struct dentry *tx_queue_len;
-
- struct dentry *retry_count;
- struct dentry *excessive_retries;
-};
-
-struct wl12xx {
- struct ieee80211_hw *hw;
- bool mac80211_registered;
-
- struct spi_device *spi;
-
- void (*set_power)(bool enable);
- int irq;
-
- enum wl12xx_state state;
- struct mutex mutex;
-
- int physical_mem_addr;
- int physical_reg_addr;
- int virtual_mem_addr;
- int virtual_reg_addr;
-
- struct wl12xx_chip chip;
-
- int cmd_box_addr;
- int event_box_addr;
- struct boot_attr boot_attr;
-
- u8 *fw;
- size_t fw_len;
- u8 *nvs;
- size_t nvs_len;
-
- u8 bssid[ETH_ALEN];
- u8 mac_addr[ETH_ALEN];
- u8 bss_type;
- u8 listen_int;
- int channel;
-
- void *target_mem_map;
- struct acx_data_path_params_resp *data_path;
-
- /* Number of TX packets transferred to the FW, modulo 16 */
- u32 data_in_count;
-
- /* Frames scheduled for transmission, not handled yet */
- struct sk_buff_head tx_queue;
- bool tx_queue_stopped;
-
- struct work_struct tx_work;
- struct work_struct filter_work;
-
- /* Pending TX frames */
- struct sk_buff *tx_frames[16];
-
- /*
- * Index pointing to the next TX complete entry
- * in the cyclic XT complete array we get from
- * the FW.
- */
- u32 next_tx_complete;
-
- /* FW Rx counter */
- u32 rx_counter;
-
- /* Rx frames handled */
- u32 rx_handled;
-
- /* Current double buffer */
- u32 rx_current_buffer;
- u32 rx_last_id;
-
- /* The target interrupt mask */
- u32 intr_mask;
- struct work_struct irq_work;
-
- /* The mbox event mask */
- u32 event_mask;
-
- /* Mailbox pointers */
- u32 mbox_ptr[2];
-
- /* Are we currently scanning */
- bool scanning;
-
- /* Our association ID */
- u16 aid;
-
- /* Default key (for WEP) */
- u32 default_key;
-
- unsigned int tx_mgmt_frm_rate;
- unsigned int tx_mgmt_frm_mod;
-
- unsigned int rx_config;
- unsigned int rx_filter;
-
- /* is firmware in elp mode */
- bool elp;
-
- /* we can be in psm, but not in elp, we have to differentiate */
- bool psm;
-
- /* PSM mode requested */
- bool psm_requested;
-
- /* in dBm */
- int power_level;
-
- struct wl12xx_stats stats;
- struct wl12xx_debugfs debugfs;
-};
-
-int wl12xx_plt_start(struct wl12xx *wl);
-int wl12xx_plt_stop(struct wl12xx *wl);
-
-#define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */
-#define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS
-#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */
-
-#define WL12XX_DEFAULT_POWER_LEVEL 20
-
-#define WL12XX_TX_QUEUE_MAX_LENGTH 20
-
-/* Different chips need different sleep times after power on. WL1271 needs
- * 200ms, WL1251 needs only 10ms. By default we use 200ms, but as soon as we
- * know the chip ID, we change the sleep value in the wl12xx chip structure,
- * so in subsequent power ons, we don't waste more time then needed. */
-#define WL12XX_DEFAULT_POWER_ON_SLEEP 200
-
-#define CHIP_ID_1251_PG10 (0x7010101)
-#define CHIP_ID_1251_PG11 (0x7020101)
-#define CHIP_ID_1251_PG12 (0x7030101)
-#define CHIP_ID_1271_PG10 (0x4030101)
-
-#endif
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index e3e96bb2c246..a83a5621ec44 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -1348,7 +1348,6 @@ static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (rc) {
++dev->stats.tx_dropped;
netif_stop_queue(dev);
- rc = NETDEV_TX_OK;
} else {
++dev->stats.tx_packets;
dev->stats.tx_bytes += skb->len;
@@ -1358,7 +1357,7 @@ static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
}
spin_unlock_irqrestore(&this->lock, flags);
- return rc;
+ return NETDEV_TX_OK;
}
static int wl3501_open(struct net_device *dev)
diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
index 4430b8d92e21..dae1bfb7655e 100644
--- a/drivers/net/wireless/zd1201.c
+++ b/drivers/net/wireless/zd1201.c
@@ -789,7 +789,7 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (!zd->mac_enabled || zd->monitor) {
dev->stats.tx_dropped++;
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
netif_stop_queue(dev);
@@ -826,7 +826,7 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void zd1201_tx_timeout(struct net_device *dev)
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 40b07b988224..9600b72495da 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -711,7 +711,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
memcpy(skb_put(skb, length), buffer, length);
- ieee80211_rx_irqsafe(hw, skb, &stats);
+ memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats));
+ ieee80211_rx_irqsafe(hw, skb);
return 0;
}
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 0e6e44689cc6..38688847d568 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -36,58 +36,60 @@
static struct usb_device_id usb_ids[] = {
/* ZD1211 */
+ { USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0586, 0x3409), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x0ace, 0x1211), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x0ace, 0xa211), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0b05, 0x170c), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0b3b, 0x5630), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x0df6, 0x9075), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0b3b, 0x5630), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0b05, 0x170c), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x1435, 0x0711), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0586, 0x3409), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
/* ZD1211B */
+ { USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x054c, 0x0257), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0ace, 0xb215), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x340a), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x083a, 0xe501), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x083a, 0xe503), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x083a, 0xe506), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0ace, 0xb215), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0b05, 0x171b), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0cde, 0x001a), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0586, 0x340a), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0df6, 0x0036), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B },
/* "Driverless" devices that need ejecting */
{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
{ USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER },
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 8d88daeed0c6..3700c49d76ca 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -558,12 +558,12 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irq(&np->tx_lock);
- return 0;
+ return NETDEV_TX_OK;
drop:
dev->stats.tx_dropped++;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static int xennet_close(struct net_device *dev)
diff --git a/drivers/net/xtsonic.c b/drivers/net/xtsonic.c
index 5a4ad156f63e..0c44135c0b1f 100644
--- a/drivers/net/xtsonic.c
+++ b/drivers/net/xtsonic.c
@@ -239,7 +239,7 @@ out:
* Actually probing is superfluous but we're paranoid.
*/
-int __init xtsonic_probe(struct platform_device *pdev)
+int __devinit xtsonic_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct sonic_local *lp;
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index 3c7a5053f1da..c3722b40a651 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -827,7 +827,7 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb_padto(skb, len)) {
yp->tx_skbuff[entry] = NULL;
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
}
}
@@ -881,7 +881,7 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: Yellowfin transmit frame #%d queued in slot %d.\n",
dev->name, yp->cur_tx, entry);
}
- return 0;
+ return NETDEV_TX_OK;
}
/* The interrupt handler does all of the Rx thread work and cleans up
diff --git a/drivers/net/znet.c b/drivers/net/znet.c
index 0a6992d8611b..7f9e14131a5c 100644
--- a/drivers/net/znet.c
+++ b/drivers/net/znet.c
@@ -546,7 +546,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
@@ -600,7 +600,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length);
}
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* The ZNET interrupt handler. */