Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/davem/net...
authorPatrick McHardy <kaber@trash.net>
Thu, 11 Jun 2009 14:00:49 +0000 (16:00 +0200)
committerPatrick McHardy <kaber@trash.net>
Thu, 11 Jun 2009 14:00:49 +0000 (16:00 +0200)
518 files changed:
Documentation/feature-removal-schedule.txt
Documentation/isdn/INTERFACE.CAPI
Documentation/networking/ieee802154.txt [new file with mode: 0644]
Documentation/networking/ip-sysctl.txt
Documentation/networking/ipv6.txt
Documentation/powerpc/dts-bindings/can/sja1000.txt [new file with mode: 0644]
Documentation/rfkill.txt
MAINTAINERS
arch/alpha/include/asm/errno.h
arch/arm/mach-pxa/tosa-bt.c
arch/arm/mach-pxa/tosa.c
arch/mips/include/asm/errno.h
arch/parisc/include/asm/errno.h
arch/powerpc/include/asm/qe.h
arch/sparc/include/asm/errno.h
drivers/Makefile
drivers/block/aoe/aoecmd.c
drivers/bluetooth/hci_vhci.c
drivers/ieee802154/Kconfig [new file with mode: 0644]
drivers/ieee802154/Makefile [new file with mode: 0644]
drivers/ieee802154/fakehard.c [new file with mode: 0644]
drivers/infiniband/ulp/ipoib/ipoib_cm.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/ipoib/ipoib_multicast.c
drivers/isdn/capi/capiutil.c
drivers/isdn/capi/kcapi.c
drivers/isdn/hardware/avm/b1.c
drivers/isdn/hardware/avm/b1dma.c
drivers/isdn/hardware/avm/c4.c
drivers/isdn/hardware/avm/t1isa.c
drivers/isdn/hysdn/hycapi.c
drivers/net/3c509.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/acenic.c
drivers/net/appletalk/ipddp.c
drivers/net/arm/ep93xx_eth.c
drivers/net/arm/ixp4xx_eth.c
drivers/net/atl1c/atl1c_ethtool.c
drivers/net/atl1c/atl1c_main.c
drivers/net/atl1e/atl1e_main.c
drivers/net/atlx/atl1.c
drivers/net/atlx/atlx.h
drivers/net/b44.c
drivers/net/b44.h
drivers/net/benet/be_main.c
drivers/net/bfin_mac.c
drivers/net/bnx2.c
drivers/net/bnx2x_main.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_sysfs.c
drivers/net/bonding/bonding.h
drivers/net/can/Kconfig
drivers/net/can/dev.c
drivers/net/can/sja1000/Makefile
drivers/net/can/sja1000/ems_pci.c
drivers/net/can/sja1000/kvaser_pci.c
drivers/net/can/sja1000/sja1000.c
drivers/net/can/sja1000/sja1000.h
drivers/net/can/sja1000/sja1000_of_platform.c [new file with mode: 0644]
drivers/net/can/sja1000/sja1000_platform.c
drivers/net/chelsio/sge.c
drivers/net/cpmac.c
drivers/net/cxgb3/Makefile
drivers/net/cxgb3/adapter.h
drivers/net/cxgb3/ael1002.c
drivers/net/cxgb3/aq100x.c [new file with mode: 0644]
drivers/net/cxgb3/common.h
drivers/net/cxgb3/cxgb3_main.c
drivers/net/cxgb3/cxgb3_offload.c
drivers/net/cxgb3/cxgb3_offload.h
drivers/net/cxgb3/sge.c
drivers/net/cxgb3/t3_hw.c
drivers/net/cxgb3/version.h
drivers/net/davinci_emac.c
drivers/net/declance.c
drivers/net/dl2k.c
drivers/net/e100.c
drivers/net/e1000/e1000_main.c
drivers/net/e1000e/82571.c
drivers/net/e1000e/defines.h
drivers/net/e1000e/e1000.h
drivers/net/e1000e/es2lan.c
drivers/net/e1000e/ethtool.c
drivers/net/e1000e/hw.h
drivers/net/e1000e/ich8lan.c
drivers/net/e1000e/lib.c
drivers/net/e1000e/netdev.c
drivers/net/e1000e/param.c
drivers/net/e1000e/phy.c
drivers/net/enic/enic_main.c
drivers/net/forcedeth.c
drivers/net/fsl_pq_mdio.c
drivers/net/gianfar.h
drivers/net/hamachi.c
drivers/net/igb/igb_main.c
drivers/net/igbvf/netdev.c
drivers/net/irda/irda-usb.c
drivers/net/ixgb/ixgb_main.c
drivers/net/ixgbe/ixgbe.h
drivers/net/ixgbe/ixgbe_82598.c
drivers/net/ixgbe/ixgbe_82599.c
drivers/net/ixgbe/ixgbe_common.c
drivers/net/ixgbe/ixgbe_common.h
drivers/net/ixgbe/ixgbe_dcb_82599.c
drivers/net/ixgbe/ixgbe_ethtool.c
drivers/net/ixgbe/ixgbe_fcoe.c
drivers/net/ixgbe/ixgbe_fcoe.h
drivers/net/ixgbe/ixgbe_main.c
drivers/net/ixgbe/ixgbe_phy.c
drivers/net/ixgbe/ixgbe_type.h
drivers/net/jme.c
drivers/net/korina.c
drivers/net/ks8842.c [new file with mode: 0644]
drivers/net/mac8390.c
drivers/net/macvlan.c
drivers/net/mdio.c
drivers/net/mlx4/Makefile
drivers/net/mlx4/en_ethtool.c [moved from drivers/net/mlx4/en_params.c with 86% similarity]
drivers/net/mlx4/en_main.c
drivers/net/mlx4/en_netdev.c
drivers/net/mlx4/en_rx.c
drivers/net/mlx4/en_tx.c
drivers/net/mlx4/eq.c
drivers/net/mlx4/mlx4_en.h
drivers/net/mlx4/mr.c
drivers/net/mv643xx_eth.c
drivers/net/myri10ge/myri10ge.c
drivers/net/netxen/netxen_nic_init.c
drivers/net/netxen/netxen_nic_main.c
drivers/net/niu.c
drivers/net/ns83820.c
drivers/net/phy/marvell.c
drivers/net/pppol2tp.c
drivers/net/qla3xxx.c
drivers/net/qlge/qlge.h
drivers/net/qlge/qlge_ethtool.c
drivers/net/qlge/qlge_main.c
drivers/net/qlge/qlge_mpi.c
drivers/net/r6040.c
drivers/net/r8169.c
drivers/net/s2io.c
drivers/net/s2io.h
drivers/net/sfc/selftest.c
drivers/net/sfc/tenxpress.c
drivers/net/sfc/tx.c
drivers/net/sis190.c
drivers/net/skge.c
drivers/net/sky2.c
drivers/net/smsc911x.c
drivers/net/sundance.c
drivers/net/tehuti.c
drivers/net/tg3.c
drivers/net/tulip/Kconfig
drivers/net/tulip/de2104x.c
drivers/net/tun.c
drivers/net/ucc_geth.c
drivers/net/ucc_geth.h
drivers/net/usb/hso.c
drivers/net/usb/rtl8150.c
drivers/net/veth.c
drivers/net/via-rhine.c
drivers/net/via-velocity.c
drivers/net/via-velocity.h
drivers/net/virtio_net.c
drivers/net/vxge/vxge-config.c
drivers/net/vxge/vxge-main.c
drivers/net/wan/ixp4xx_hss.c
drivers/net/wimax/i2400m/control.c
drivers/net/wimax/i2400m/driver.c
drivers/net/wimax/i2400m/i2400m.h
drivers/net/wimax/i2400m/netdev.c
drivers/net/wimax/i2400m/rx.c
drivers/net/wimax/i2400m/sdio.c
drivers/net/wimax/i2400m/usb.c
drivers/net/wireless/Kconfig
drivers/net/wireless/at76c50x-usb.c
drivers/net/wireless/ath/ar9170/ar9170.h
drivers/net/wireless/ath/ar9170/hw.h
drivers/net/wireless/ath/ar9170/led.c
drivers/net/wireless/ath/ar9170/mac.c
drivers/net/wireless/ath/ar9170/main.c
drivers/net/wireless/ath/ar9170/phy.c
drivers/net/wireless/ath/ar9170/usb.c
drivers/net/wireless/ath/ar9170/usb.h
drivers/net/wireless/ath/ath5k/Makefile
drivers/net/wireless/ath/ath5k/ath5k.h
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath5k/base.h
drivers/net/wireless/ath/ath5k/reset.c
drivers/net/wireless/ath/ath5k/rfkill.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/pci.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/regd.c
drivers/net/wireless/b43/Kconfig
drivers/net/wireless/b43/Makefile
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/dma.c
drivers/net/wireless/b43/leds.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/main.h
drivers/net/wireless/b43/phy_a.c
drivers/net/wireless/b43/phy_common.c
drivers/net/wireless/b43/phy_common.h
drivers/net/wireless/b43/phy_g.c
drivers/net/wireless/b43/phy_lp.c
drivers/net/wireless/b43/phy_n.c
drivers/net/wireless/b43/pio.c
drivers/net/wireless/b43/rfkill.c
drivers/net/wireless/b43/rfkill.h
drivers/net/wireless/b43/xmit.c
drivers/net/wireless/b43legacy/Kconfig
drivers/net/wireless/b43legacy/Makefile
drivers/net/wireless/b43legacy/b43legacy.h
drivers/net/wireless/b43legacy/leds.c
drivers/net/wireless/b43legacy/main.c
drivers/net/wireless/b43legacy/rfkill.c
drivers/net/wireless/b43legacy/rfkill.h
drivers/net/wireless/iwlwifi/Kconfig
drivers/net/wireless/iwlwifi/Makefile
drivers/net/wireless/iwlwifi/iwl-3945-led.c
drivers/net/wireless/iwlwifi/iwl-3945-rs.c
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/iwlwifi/iwl-3945.h
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-commands.h
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-debugfs.c
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-eeprom.c
drivers/net/wireless/iwlwifi/iwl-led.c
drivers/net/wireless/iwlwifi/iwl-rfkill.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-rfkill.h [deleted file]
drivers/net/wireless/iwlwifi/iwl-sta.c
drivers/net/wireless/iwlwifi/iwl-sta.h
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/iwmc3200wifi/Kconfig
drivers/net/wireless/iwmc3200wifi/Makefile
drivers/net/wireless/iwmc3200wifi/cfg80211.c
drivers/net/wireless/iwmc3200wifi/fw.c
drivers/net/wireless/iwmc3200wifi/iwm.h
drivers/net/wireless/iwmc3200wifi/netdev.c
drivers/net/wireless/iwmc3200wifi/rfkill.c [deleted file]
drivers/net/wireless/iwmc3200wifi/sdio.c
drivers/net/wireless/libertas/11d.c
drivers/net/wireless/libertas/11d.h
drivers/net/wireless/libertas/assoc.c
drivers/net/wireless/libertas/assoc.h
drivers/net/wireless/libertas/cmd.c
drivers/net/wireless/libertas/cmdresp.c
drivers/net/wireless/libertas/debugfs.c
drivers/net/wireless/libertas/dev.h
drivers/net/wireless/libertas/hostcmd.h
drivers/net/wireless/libertas/if_sdio.c
drivers/net/wireless/libertas/if_spi.c
drivers/net/wireless/libertas/main.c
drivers/net/wireless/libertas/scan.c
drivers/net/wireless/libertas/types.h
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/p54/p54common.c
drivers/net/wireless/p54/p54usb.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00config.c
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rtl818x/rtl8187_dev.c
drivers/net/wireless/wavelan.c
drivers/net/wireless/wavelan_cs.c
drivers/net/yellowfin.c
drivers/platform/x86/Kconfig
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/eeepc-laptop.c
drivers/platform/x86/hp-wmi.c
drivers/platform/x86/sony-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/toshiba_acpi.c
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3_main.c
drivers/scsi/fcoe/fcoe.c
drivers/usb/gadget/f_phonet.c
firmware/Makefile
firmware/WHENCE
firmware/cis/.gitignore [new file with mode: 0644]
firmware/cxgb3/t3fw-7.1.0.bin.ihex [deleted file]
firmware/cxgb3/t3fw-7.4.0.bin.ihex [new file with mode: 0644]
include/asm-generic/errno.h
include/linux/Kbuild
include/linux/can/platform/sja1000.h
include/linux/ethtool.h
include/linux/ieee80211.h
include/linux/if_arp.h
include/linux/if_ether.h
include/linux/in.h
include/linux/ipv6.h
include/linux/isdn/capilli.h
include/linux/mdio.h
include/linux/netdevice.h
include/linux/netfilter/nf_conntrack_tcp.h
include/linux/nl802154.h [new file with mode: 0644]
include/linux/notifier.h
include/linux/pci_ids.h
include/linux/rfkill.h
include/linux/sctp.h
include/linux/skbuff.h
include/linux/socket.h
include/linux/spi/libertas_spi.h
include/linux/wimax.h
include/net/bluetooth/bluetooth.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
include/net/cfg80211.h
include/net/dst.h
include/net/ieee802154/af_ieee802154.h [new file with mode: 0644]
include/net/ieee802154/mac_def.h [new file with mode: 0644]
include/net/ieee802154/netdevice.h [new file with mode: 0644]
include/net/ieee802154/nl802154.h [new file with mode: 0644]
include/net/inet6_hashtables.h
include/net/inet_hashtables.h
include/net/inet_sock.h
include/net/ip6_route.h
include/net/mac80211.h
include/net/pkt_sched.h
include/net/route.h
include/net/sctp/structs.h
include/net/sctp/user.h
include/net/sock.h
include/net/wimax.h
include/net/xfrm.h
net/8021q/vlan.c
net/8021q/vlan_dev.c
net/Kconfig
net/Makefile
net/appletalk/ddp.c
net/atm/br2684.c
net/atm/clip.c
net/bluetooth/cmtp/capi.c
net/bluetooth/hci_core.c
net/bluetooth/hci_sysfs.c
net/bluetooth/l2cap.c
net/bluetooth/rfcomm/core.c
net/bridge/br_fdb.c
net/bridge/br_netfilter.c
net/can/af_can.c
net/core/datagram.c
net/core/dev.c
net/core/iovec.c
net/core/neighbour.c
net/core/pktgen.c
net/core/skb_dma_map.c
net/core/skbuff.c
net/core/sock.c
net/core/user_dma.c
net/dccp/ipv4.c
net/dccp/ipv6.c
net/dccp/output.c
net/decnet/af_decnet.c
net/decnet/dn_neigh.c
net/decnet/dn_nsp_out.c
net/decnet/dn_route.c
net/dsa/slave.c
net/econet/af_econet.c
net/ieee802154/Kconfig [new file with mode: 0644]
net/ieee802154/Makefile [new file with mode: 0644]
net/ieee802154/af802154.h [new file with mode: 0644]
net/ieee802154/af_ieee802154.c [new file with mode: 0644]
net/ieee802154/dgram.c [new file with mode: 0644]
net/ieee802154/netlink.c [new file with mode: 0644]
net/ieee802154/nl_policy.c [new file with mode: 0644]
net/ieee802154/raw.c [new file with mode: 0644]
net/ipv4/af_inet.c
net/ipv4/arp.c
net/ipv4/icmp.c
net/ipv4/igmp.c
net/ipv4/ip_forward.c
net/ipv4/ip_fragment.c
net/ipv4/ip_gre.c
net/ipv4/ip_input.c
net/ipv4/ip_options.c
net/ipv4/ip_output.c
net/ipv4/ip_sockglue.c
net/ipv4/ipip.c
net/ipv4/ipmr.c
net/ipv4/netfilter.c
net/ipv4/netfilter/ipt_MASQUERADE.c
net/ipv4/netfilter/ipt_REJECT.c
net/ipv4/netfilter/nf_nat_helper.c
net/ipv4/netfilter/nf_nat_proto_sctp.c
net/ipv4/netfilter/nf_nat_standalone.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/tcp_vegas.c
net/ipv4/udp.c
net/ipv4/xfrm4_input.c
net/ipv4/xfrm4_mode_tunnel.c
net/ipv4/xfrm4_output.c
net/ipv6/addrconf.c
net/ipv6/af_inet6.c
net/ipv6/exthdrs.c
net/ipv6/inet6_connection_sock.c
net/ipv6/ip6_input.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6mr.c
net/ipv6/mcast.c
net/ipv6/ndisc.c
net/ipv6/netfilter.c
net/ipv6/netfilter/ip6t_REJECT.c
net/ipv6/netfilter/nf_conntrack_reasm.c
net/ipv6/raw.c
net/ipv6/reassembly.c
net/ipv6/route.c
net/ipv6/sit.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/ipv6/xfrm6_mode_tunnel.c
net/ipv6/xfrm6_output.c
net/irda/irlap_frame.c
net/llc/llc_conn.c
net/mac80211/Kconfig
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/driver-ops.h
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/main.c
net/mac80211/mlme.c
net/mac80211/rc80211_minstrel.c
net/mac80211/rx.c
net/mac80211/sta_info.c
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wext.c
net/mac80211/wme.c
net/netfilter/ipvs/ip_vs_xmit.c
net/netfilter/nf_conntrack_netbios_ns.c
net/netfilter/nf_conntrack_proto_dccp.c
net/netfilter/nf_conntrack_proto_gre.c
net/netfilter/nf_conntrack_proto_tcp.c
net/netfilter/nfnetlink_log.c
net/netfilter/nfnetlink_queue.c
net/netfilter/xt_TCPMSS.c
net/netfilter/xt_hashlimit.c
net/netfilter/xt_policy.c
net/netfilter/xt_realm.c
net/packet/af_packet.c
net/phonet/pep-gprs.c
net/phonet/pep.c
net/rfkill/Kconfig
net/rfkill/Makefile
net/rfkill/core.c [new file with mode: 0644]
net/rfkill/input.c [new file with mode: 0644]
net/rfkill/rfkill-input.c [deleted file]
net/rfkill/rfkill.c [deleted file]
net/rfkill/rfkill.h [moved from net/rfkill/rfkill-input.h with 60% similarity]
net/sched/cls_api.c
net/sched/cls_cgroup.c
net/sched/cls_flow.c
net/sched/cls_route.c
net/sched/em_meta.c
net/sched/sch_hfsc.c
net/sched/sch_sfq.c
net/sched/sch_teql.c
net/sctp/associola.c
net/sctp/input.c
net/sctp/output.c
net/sctp/protocol.c
net/sctp/sm_make_chunk.c
net/sctp/sm_sideeffect.c
net/sctp/sm_statefuns.c
net/sctp/sm_statetable.c
net/sctp/socket.c
net/sctp/sysctl.c
net/sctp/ulpevent.c
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/xprtsock.c
net/wimax/Kconfig
net/wimax/Makefile
net/wimax/debug-levels.h
net/wimax/debugfs.c
net/wimax/op-msg.c
net/wimax/op-rfkill.c
net/wimax/op-state-get.c [new file with mode: 0644]
net/wimax/stack.c
net/wireless/Kconfig
net/wireless/core.c
net/wireless/core.h
net/wireless/nl80211.c
net/wireless/reg.c
net/wireless/scan.c
net/wireless/util.c
net/wireless/wext-compat.c
net/xfrm/xfrm_algo.c
net/xfrm/xfrm_input.c
net/xfrm/xfrm_output.c
net/xfrm/xfrm_policy.c
security/selinux/hooks.c
security/selinux/xfrm.c

index de491a3..edb2f0b 100644 (file)
@@ -437,3 +437,10 @@ Why:       Superseded by tdfxfb. I2C/DDC support used to live in a separate
        driver but this caused driver conflicts.
 Who:   Jean Delvare <khali@linux-fr.org>
        Krzysztof Helt <krzysztof.h1@wp.pl>
+
+---------------------------
+
+What:  CONFIG_RFKILL_INPUT
+When:  2.6.33
+Why:   Should be implemented in userspace, policy daemon.
+Who:   Johannes Berg <johannes@sipsolutions.net>
index 786d619..686e107 100644 (file)
@@ -45,7 +45,7 @@ From then on, Kernel CAPI may call the registered callback functions for the
 device.
 
 If the device becomes unusable for any reason (shutdown, disconnect ...), the
-driver has to call capi_ctr_reseted(). This will prevent further calls to the
+driver has to call capi_ctr_down(). This will prevent further calls to the
 callback functions by Kernel CAPI.
 
 
@@ -114,20 +114,36 @@ char *driver_name
 int (*load_firmware)(struct capi_ctr *ctrlr, capiloaddata *ldata)
        (optional) pointer to a callback function for sending firmware and
        configuration data to the device
+       Return value: 0 on success, error code on error
+       Called in process context.
 
 void (*reset_ctr)(struct capi_ctr *ctrlr)
-       pointer to a callback function for performing a reset on the device,
-       releasing all registered applications
+       (optional) pointer to a callback function for performing a reset on
+       the device, releasing all registered applications
+       Called in process context.
 
 void (*register_appl)(struct capi_ctr *ctrlr, u16 applid,
                        capi_register_params *rparam)
 void (*release_appl)(struct capi_ctr *ctrlr, u16 applid)
        pointers to callback functions for registration and deregistration of
        applications with the device
+       Calls to these functions are serialized by Kernel CAPI so that only
+       one call to any of them is active at any time.
 
 u16  (*send_message)(struct capi_ctr *ctrlr, struct sk_buff *skb)
        pointer to a callback function for sending a CAPI message to the
        device
+       Return value: CAPI error code
+       If the method returns 0 (CAPI_NOERROR) the driver has taken ownership
+       of the skb and the caller may no longer access it. If it returns a
+       non-zero (error) value then ownership of the skb returns to the caller
+       who may reuse or free it.
+       The return value should only be used to signal problems with respect
+       to accepting or queueing the message. Errors occurring during the
+       actual processing of the message should be signaled with an
+       appropriate reply message.
+       Calls to this function are not serialized by Kernel CAPI, ie. it must
+       be prepared to be re-entered.
 
 char *(*procinfo)(struct capi_ctr *ctrlr)
        pointer to a callback function returning the entry for the device in
@@ -138,6 +154,8 @@ read_proc_t *ctr_read_proc
        system entry, /proc/capi/controllers/<n>; will be called with a
        pointer to the device's capi_ctr structure as the last (data) argument
 
+Note: Callback functions are never called in interrupt context.
+
 - to be filled in before calling capi_ctr_ready():
 
 u8 manu[CAPI_MANUFACTURER_LEN]
@@ -153,6 +171,45 @@ u8 serial[CAPI_SERIAL_LEN]
        value to return for CAPI_GET_SERIAL
 
 
+4.3 The _cmsg Structure
+
+(declared in <linux/isdn/capiutil.h>)
+
+The _cmsg structure stores the contents of a CAPI 2.0 message in an easily
+accessible form. It contains members for all possible CAPI 2.0 parameters, of
+which only those appearing in the message type currently being processed are
+actually used. Unused members should be set to zero.
+
+Members are named after the CAPI 2.0 standard names of the parameters they
+represent. See <linux/isdn/capiutil.h> for the exact spelling. Member data
+types are:
+
+u8          for CAPI parameters of type 'byte'
+
+u16         for CAPI parameters of type 'word'
+
+u32         for CAPI parameters of type 'dword'
+
+_cstruct    for CAPI parameters of type 'struct' not containing any
+           variably-sized (struct) subparameters (eg. 'Called Party Number')
+           The member is a pointer to a buffer containing the parameter in
+           CAPI encoding (length + content). It may also be NULL, which will
+           be taken to represent an empty (zero length) parameter.
+
+_cmstruct   for CAPI parameters of type 'struct' containing 'struct'
+           subparameters ('Additional Info' and 'B Protocol')
+           The representation is a single byte containing one of the values:
+           CAPI_DEFAULT: the parameter is empty
+           CAPI_COMPOSE: the values of the subparameters are stored
+           individually in the corresponding _cmsg structure members
+
+Functions capi_cmsg2message() and capi_message2cmsg() are provided to convert
+messages between their transport encoding described in the CAPI 2.0 standard
+and their _cmsg structure representation. Note that capi_cmsg2message() does
+not know or check the size of its destination buffer. The caller must make
+sure it is big enough to accomodate the resulting CAPI message.
+
+
 5. Lower Layer Interface Functions
 
 (declared in <linux/isdn/capilli.h>)
@@ -166,7 +223,7 @@ int detach_capi_ctr(struct capi_ctr *ctrlr)
        register/unregister a device (controller) with Kernel CAPI
 
 void capi_ctr_ready(struct capi_ctr *ctrlr)
-void capi_ctr_reseted(struct capi_ctr *ctrlr)
+void capi_ctr_down(struct capi_ctr *ctrlr)
        signal controller ready/not ready
 
 void capi_ctr_suspend_output(struct capi_ctr *ctrlr)
@@ -211,3 +268,32 @@ CAPIMSG_CONTROL(m) CAPIMSG_SETCONTROL(m, contr)    Controller/PLCI/NCCI
                                                        (u32)
 CAPIMSG_DATALEN(m)     CAPIMSG_SETDATALEN(m, len)      Data Length (u16)
 
+
+Library functions for working with _cmsg structures
+(from <linux/isdn/capiutil.h>):
+
+unsigned capi_cmsg2message(_cmsg *cmsg, u8 *msg)
+       Assembles a CAPI 2.0 message from the parameters in *cmsg, storing the
+       result in *msg.
+
+unsigned capi_message2cmsg(_cmsg *cmsg, u8 *msg)
+       Disassembles the CAPI 2.0 message in *msg, storing the parameters in
+       *cmsg.
+
+unsigned capi_cmsg_header(_cmsg *cmsg, u16 ApplId, u8 Command, u8 Subcommand,
+                         u16 Messagenumber, u32 Controller)
+       Fills the header part and address field of the _cmsg structure *cmsg
+       with the given values, zeroing the remainder of the structure so only
+       parameters with non-default values need to be changed before sending
+       the message.
+
+void capi_cmsg_answer(_cmsg *cmsg)
+       Sets the low bit of the Subcommand field in *cmsg, thereby converting
+       _REQ to _CONF and _IND to _RESP.
+
+char *capi_cmd2str(u8 Command, u8 Subcommand)
+       Returns the CAPI 2.0 message name corresponding to the given command
+       and subcommand values, as a static ASCII string. The return value may
+       be NULL if the command/subcommand is not one of those defined in the
+       CAPI 2.0 standard.
+
diff --git a/Documentation/networking/ieee802154.txt b/Documentation/networking/ieee802154.txt
new file mode 100644 (file)
index 0000000..a0280ad
--- /dev/null
@@ -0,0 +1,76 @@
+
+               Linux IEEE 802.15.4 implementation
+
+
+Introduction
+============
+
+The Linux-ZigBee project goal is to provide complete implementation
+of IEEE 802.15.4 / ZigBee / 6LoWPAN protocols. IEEE 802.15.4 is a stack
+of protocols for organizing Low-Rate Wireless Personal Area Networks.
+
+Currently only IEEE 802.15.4 layer is implemented. We have choosen
+to use plain Berkeley socket API, the generic Linux networking stack
+to transfer IEEE 802.15.4 messages and a special protocol over genetlink
+for configuration/management
+
+
+Socket API
+==========
+
+int sd = socket(PF_IEEE802154, SOCK_DGRAM, 0);
+.....
+
+The address family, socket addresses etc. are defined in the
+include/net/ieee802154/af_ieee802154.h header or in the special header
+in our userspace package (see either linux-zigbee sourceforge download page
+or git tree at git://linux-zigbee.git.sourceforge.net/gitroot/linux-zigbee).
+
+One can use SOCK_RAW for passing raw data towards device xmit function. YMMV.
+
+
+MLME - MAC Level Management
+============================
+
+Most of IEEE 802.15.4 MLME interfaces are directly mapped on netlink commands.
+See the include/net/ieee802154/nl802154.h header. Our userspace tools package
+(see above) provides CLI configuration utility for radio interfaces and simple
+coordinator for IEEE 802.15.4 networks as an example users of MLME protocol.
+
+
+Kernel side
+=============
+
+Like with WiFi, there are several types of devices implementing IEEE 802.15.4.
+1) 'HardMAC'. The MAC layer is implemented in the device itself, the device
+   exports MLME and data API.
+2) 'SoftMAC' or just radio. These types of devices are just radio transceivers
+   possibly with some kinds of acceleration like automatic CRC computation and
+   comparation, automagic ACK handling, address matching, etc.
+
+Those types of devices require different approach to be hooked into Linux kernel.
+
+
+HardMAC
+=======
+
+See the header include/net/ieee802154/netdevice.h. You have to implement Linux
+net_device, with .type = ARPHRD_IEEE802154. Data is exchanged with socket family
+code via plain sk_buffs. The control block of sk_buffs will contain additional
+info as described in the struct ieee802154_mac_cb.
+
+To hook the MLME interface you have to populate the ml_priv field of your
+net_device with a pointer to struct ieee802154_mlme_ops instance. All fields are
+required.
+
+We provide an example of simple HardMAC driver at drivers/ieee802154/fakehard.c
+
+
+SoftMAC
+=======
+
+We are going to provide intermediate layer impelementing IEEE 802.15.4 MAC
+in software. This is currently WIP.
+
+See header include/net/ieee802154/mac802154.h and several drivers in
+drivers/ieee802154/
index 3ffd233..8be7623 100644 (file)
@@ -1057,6 +1057,13 @@ disable_ipv6 - BOOLEAN
        address.
        Default: FALSE (enable IPv6 operation)
 
+       When this value is changed from 1 to 0 (IPv6 is being enabled),
+       it will dynamically create a link-local address on the given
+       interface and start Duplicate Address Detection, if necessary.
+
+       When this value is changed from 0 to 1 (IPv6 is being disabled),
+       it will dynamically delete all address on the given interface.
+
 accept_dad - INTEGER
        Whether to accept DAD (Duplicate Address Detection).
        0: Disable DAD
index 268e5c1..9fd7e21 100644 (file)
@@ -33,3 +33,40 @@ disable
 
                A reboot is required to enable IPv6.
 
+autoconf
+
+       Specifies whether to enable IPv6 address autoconfiguration
+       on all interfaces.  This might be used when one does not wish
+       for addresses to be automatically generated from prefixes
+       received in Router Advertisements.
+
+       The possible values and their effects are:
+
+       0
+               IPv6 address autoconfiguration is disabled on all interfaces.
+
+               Only the IPv6 loopback address (::1) and link-local addresses
+               will be added to interfaces.
+
+       1
+               IPv6 address autoconfiguration is enabled on all interfaces.
+
+               This is the default value.
+
+disable_ipv6
+
+       Specifies whether to disable IPv6 on all interfaces.
+       This might be used when no IPv6 addresses are desired.
+
+       The possible values and their effects are:
+
+       0
+               IPv6 is enabled on all interfaces.
+
+               This is the default value.
+
+       1
+               IPv6 is disabled on all interfaces.
+
+               No IPv6 addresses will be added to interfaces.
+
diff --git a/Documentation/powerpc/dts-bindings/can/sja1000.txt b/Documentation/powerpc/dts-bindings/can/sja1000.txt
new file mode 100644 (file)
index 0000000..d6d209d
--- /dev/null
@@ -0,0 +1,53 @@
+Memory mapped SJA1000 CAN controller from NXP (formerly Philips)
+
+Required properties:
+
+- compatible : should be "nxp,sja1000".
+
+- reg : should specify the chip select, address offset and size required
+       to map the registers of the SJA1000. The size is usually 0x80.
+
+- interrupts: property with a value describing the interrupt source
+       (number and sensitivity) required for the SJA1000.
+
+Optional properties:
+
+- nxp,external-clock-frequency : Frequency of the external oscillator
+       clock in Hz. Note that the internal clock frequency used by the
+       SJA1000 is half of that value. If not specified, a default value
+       of 16000000 (16 MHz) is used.
+
+- nxp,tx-output-mode : operation mode of the TX output control logic:
+       <0x0> : bi-phase output mode
+       <0x1> : normal output mode (default)
+       <0x2> : test output mode
+       <0x3> : clock output mode
+
+- nxp,tx-output-config : TX output pin configuration:
+       <0x01> : TX0 invert
+       <0x02> : TX0 pull-down (default)
+       <0x04> : TX0 pull-up
+       <0x06> : TX0 push-pull
+       <0x08> : TX1 invert
+       <0x10> : TX1 pull-down
+       <0x20> : TX1 pull-up
+       <0x30> : TX1 push-pull
+
+- nxp,clock-out-frequency : clock frequency in Hz on the CLKOUT pin.
+       If not specified or if the specified value is 0, the CLKOUT pin
+       will be disabled.
+
+- nxp,no-comparator-bypass : Allows to disable the CAN input comperator.
+
+For futher information, please have a look to the SJA1000 data sheet.
+
+Examples:
+
+can@3,100 {
+       compatible = "nxp,sja1000";
+       reg = <3 0x100 0x80>;
+       interrupts = <2 0>;
+       interrupt-parent = <&mpic>;
+       nxp,external-clock-frequency = <16000000>;
+};
+
index 40c3a3f..1b74b5f 100644 (file)
-rfkill - RF switch subsystem support
-====================================
+rfkill - RF kill switch support
+===============================
 
-1 Introduction
-2 Implementation details
-3 Kernel driver guidelines
-3.1 wireless device drivers
-3.2 platform/switch drivers
-3.3 input device drivers
-4 Kernel API
-5 Userspace support
+1. Introduction
+2. Implementation details
+3. Kernel driver guidelines
+4. Kernel API
+5. Userspace support
 
 
-1. Introduction:
+1. Introduction
 
-The rfkill switch subsystem exists to add a generic interface to circuitry that
-can enable or disable the signal output of a wireless *transmitter* of any
-type.  By far, the most common use is to disable radio-frequency transmitters.
+The rfkill subsystem provides a generic interface to disabling any radio
+transmitter in the system. When a transmitter is blocked, it shall not
+radiate any power.
 
-Note that disabling the signal output means that the the transmitter is to be
-made to not emit any energy when "blocked".  rfkill is not about blocking data
-transmissions, it is about blocking energy emission.
+The subsystem also provides the ability to react on button presses and
+disable all transmitters of a certain type (or all). This is intended for
+situations where transmitters need to be turned off, for example on
+aircraft.
 
-The rfkill subsystem offers support for keys and switches often found on
-laptops to enable wireless devices like WiFi and Bluetooth, so that these keys
-and switches actually perform an action in all wireless devices of a given type
-attached to the system.
 
-The buttons to enable and disable the wireless transmitters are important in
-situations where the user is for example using his laptop on a location where
-radio-frequency transmitters _must_ be disabled (e.g. airplanes).
 
-Because of this requirement, userspace support for the keys should not be made
-mandatory.  Because userspace might want to perform some additional smarter
-tasks when the key is pressed, rfkill provides userspace the possibility to
-take over the task to handle the key events.
-
-===============================================================================
-2: Implementation details
+2. Implementation details
 
 The rfkill subsystem is composed of various components: the rfkill class, the
 rfkill-input module (an input layer handler), and some specific input layer
 events.
 
-The rfkill class provides kernel drivers with an interface that allows them to
-know when they should enable or disable a wireless network device transmitter.
-This is enabled by the CONFIG_RFKILL Kconfig option.
-
-The rfkill class support makes sure userspace will be notified of all state
-changes on rfkill devices through uevents.  It provides a notification chain
-for interested parties in the kernel to also get notified of rfkill state
-changes in other drivers.  It creates several sysfs entries which can be used
-by userspace.  See section "Userspace support".
-
-The rfkill-input module provides the kernel with the ability to implement a
-basic response when the user presses a key or button (or toggles a switch)
-related to rfkill functionality.  It is an in-kernel implementation of default
-policy of reacting to rfkill-related input events and neither mandatory nor
-required for wireless drivers to operate.  It is enabled by the
-CONFIG_RFKILL_INPUT Kconfig option.
-
-rfkill-input is a rfkill-related events input layer handler.  This handler will
-listen to all rfkill key events and will change the rfkill state of the
-wireless devices accordingly.  With this option enabled userspace could either
-do nothing or simply perform monitoring tasks.
-
-The rfkill-input module also provides EPO (emergency power-off) functionality
-for all wireless transmitters.  This function cannot be overridden, and it is
-always active.  rfkill EPO is related to *_RFKILL_ALL input layer events.
-
-
-Important terms for the rfkill subsystem:
-
-In order to avoid confusion, we avoid the term "switch" in rfkill when it is
-referring to an electronic control circuit that enables or disables a
-transmitter.  We reserve it for the physical device a human manipulates
-(which is an input device, by the way):
-
-rfkill switch:
-
-       A physical device a human manipulates.  Its state can be perceived by
-       the kernel either directly (through a GPIO pin, ACPI GPE) or by its
-       effect on a rfkill line of a wireless device.
-
-rfkill controller:
-
-       A hardware circuit that controls the state of a rfkill line, which a
-       kernel driver can interact with *to modify* that state (i.e. it has
-       either write-only or read/write access).
-
-rfkill line:
-
-       An input channel (hardware or software) of a wireless device, which
-       causes a wireless transmitter to stop emitting energy (BLOCK) when it
-       is active.  Point of view is extremely important here: rfkill lines are
-       always seen from the PoV of a wireless device (and its driver).
-
-soft rfkill line/software rfkill line:
-
-       A rfkill line the wireless device driver can directly change the state
-       of.  Related to rfkill_state RFKILL_STATE_SOFT_BLOCKED.
-
-hard rfkill line/hardware rfkill line:
-
-       A rfkill line that works fully in hardware or firmware, and that cannot
-       be overridden by the kernel driver.  The hardware device or the
-       firmware just exports its status to the driver, but it is read-only.
-       Related to rfkill_state RFKILL_STATE_HARD_BLOCKED.
-
-The enum rfkill_state describes the rfkill state of a transmitter:
-
-When a rfkill line or rfkill controller is in the RFKILL_STATE_UNBLOCKED state,
-the wireless transmitter (radio TX circuit for example) is *enabled*.  When the
-it is in the RFKILL_STATE_SOFT_BLOCKED or RFKILL_STATE_HARD_BLOCKED, the
-wireless transmitter is to be *blocked* from operating.
-
-RFKILL_STATE_SOFT_BLOCKED indicates that a call to toggle_radio() can change
-that state.  RFKILL_STATE_HARD_BLOCKED indicates that a call to toggle_radio()
-will not be able to change the state and will return with a suitable error if
-attempts are made to set the state to RFKILL_STATE_UNBLOCKED.
-
-RFKILL_STATE_HARD_BLOCKED is used by drivers to signal that the device is
-locked in the BLOCKED state by a hardwire rfkill line (typically an input pin
-that, when active, forces the transmitter to be disabled) which the driver
-CANNOT override.
-
-Full rfkill functionality requires two different subsystems to cooperate: the
-input layer and the rfkill class.  The input layer issues *commands* to the
-entire system requesting that devices registered to the rfkill class change
-state.  The way this interaction happens is not complex, but it is not obvious
-either:
-
-Kernel Input layer:
-
-       * Generates KEY_WWAN, KEY_WLAN, KEY_BLUETOOTH, SW_RFKILL_ALL, and
-         other such events when the user presses certain keys, buttons, or
-         toggles certain physical switches.
-
-       THE INPUT LAYER IS NEVER USED TO PROPAGATE STATUS, NOTIFICATIONS OR THE
-       KIND OF STUFF AN ON-SCREEN-DISPLAY APPLICATION WOULD REPORT.  It is
-       used to issue *commands* for the system to change behaviour, and these
-       commands may or may not be carried out by some kernel driver or
-       userspace application.  It follows that doing user feedback based only
-       on input events is broken, as there is no guarantee that an input event
-       will be acted upon.
-
-       Most wireless communication device drivers implementing rfkill
-       functionality MUST NOT generate these events, and have no reason to
-       register themselves with the input layer.  Doing otherwise is a common
-       misconception.  There is an API to propagate rfkill status change
-       information, and it is NOT the input layer.
-
-rfkill class:
-
-       * Calls a hook in a driver to effectively change the wireless
-         transmitter state;
-       * Keeps track of the wireless transmitter state (with help from
-         the driver);
-       * Generates userspace notifications (uevents) and a call to a
-         notification chain (kernel) when there is a wireless transmitter
-         state change;
-       * Connects a wireless communications driver with the common rfkill
-         control system, which, for example, allows actions such as
-         "switch all bluetooth devices offline" to be carried out by
-         userspace or by rfkill-input.
-
-       THE RFKILL CLASS NEVER ISSUES INPUT EVENTS.  THE RFKILL CLASS DOES
-       NOT LISTEN TO INPUT EVENTS.  NO DRIVER USING THE RFKILL CLASS SHALL
-       EVER LISTEN TO, OR ACT ON RFKILL INPUT EVENTS.  Doing otherwise is
-       a layering violation.
-
-       Most wireless data communication drivers in the kernel have just to
-       implement the rfkill class API to work properly.  Interfacing to the
-       input layer is not often required (and is very often a *bug*) on
-       wireless drivers.
-
-       Platform drivers often have to attach to the input layer to *issue*
-       (but never to listen to) rfkill events for rfkill switches, and also to
-       the rfkill class to export a control interface for the platform rfkill
-       controllers to the rfkill subsystem.  This does NOT mean the rfkill
-       switch is attached to a rfkill class (doing so is almost always wrong).
-       It just means the same kernel module is the driver for different
-       devices (rfkill switches and rfkill controllers).
-
-
-Userspace input handlers (uevents) or kernel input handlers (rfkill-input):
-
-       * Implements the policy of what should happen when one of the input
-         layer events related to rfkill operation is received.
-       * Uses the sysfs interface (userspace) or private rfkill API calls
-         to tell the devices registered with the rfkill class to change
-         their state (i.e. translates the input layer event into real
-         action).
-
-       * rfkill-input implements EPO by handling EV_SW SW_RFKILL_ALL 0
-         (power off all transmitters) in a special way: it ignores any
-         overrides and local state cache and forces all transmitters to the
-         RFKILL_STATE_SOFT_BLOCKED state (including those which are already
-         supposed to be BLOCKED).
-       * rfkill EPO will remain active until rfkill-input receives an
-         EV_SW SW_RFKILL_ALL 1 event.  While the EPO is active, transmitters
-         are locked in the blocked state (rfkill will refuse to unblock them).
-       * rfkill-input implements different policies that the user can
-         select for handling EV_SW SW_RFKILL_ALL 1.  It will unlock rfkill,
-         and either do nothing (leave transmitters blocked, but now unlocked),
-         restore the transmitters to their state before the EPO, or unblock
-         them all.
-
-Userspace uevent handler or kernel platform-specific drivers hooked to the
-rfkill notifier chain:
-
-       * Taps into the rfkill notifier chain or to KOBJ_CHANGE uevents,
-         in order to know when a device that is registered with the rfkill
-         class changes state;
-       * Issues feedback notifications to the user;
-       * In the rare platforms where this is required, synthesizes an input
-         event to command all *OTHER* rfkill devices to also change their
-         statues when a specific rfkill device changes state.
-
-
-===============================================================================
-3: Kernel driver guidelines
-
-Remember: point-of-view is everything for a driver that connects to the rfkill
-subsystem.  All the details below must be measured/perceived from the point of
-view of the specific driver being modified.
-
-The first thing one needs to know is whether his driver should be talking to
-the rfkill class or to the input layer.  In rare cases (platform drivers), it
-could happen that you need to do both, as platform drivers often handle a
-variety of devices in the same driver.
-
-Do not mistake input devices for rfkill controllers.  The only type of "rfkill
-switch" device that is to be registered with the rfkill class are those
-directly controlling the circuits that cause a wireless transmitter to stop
-working (or the software equivalent of them), i.e. what we call a rfkill
-controller.  Every other kind of "rfkill switch" is just an input device and
-MUST NOT be registered with the rfkill class.
-
-A driver should register a device with the rfkill class when ALL of the
-following conditions are met (they define a rfkill controller):
-
-1. The device is/controls a data communications wireless transmitter;
-
-2. The kernel can interact with the hardware/firmware to CHANGE the wireless
-   transmitter state (block/unblock TX operation);
-
-3. The transmitter can be made to not emit any energy when "blocked":
-   rfkill is not about blocking data transmissions, it is about blocking
-   energy emission;
-
-A driver should register a device with the input subsystem to issue
-rfkill-related events (KEY_WLAN, KEY_BLUETOOTH, KEY_WWAN, KEY_WIMAX,
-SW_RFKILL_ALL, etc) when ALL of the folowing conditions are met:
-
-1. It is directly related to some physical device the user interacts with, to
-   command the O.S./firmware/hardware to enable/disable a data communications
-   wireless transmitter.
-
-   Examples of the physical device are: buttons, keys and switches the user
-   will press/touch/slide/switch to enable or disable the wireless
-   communication device.
-
-2. It is NOT slaved to another device, i.e. there is no other device that
-   issues rfkill-related input events in preference to this one.
-
-   Please refer to the corner cases and examples section for more details.
-
-When in doubt, do not issue input events.  For drivers that should generate
-input events in some platforms, but not in others (e.g. b43), the best solution
-is to NEVER generate input events in the first place.  That work should be
-deferred to a platform-specific kernel module (which will know when to generate
-events through the rfkill notifier chain) or to userspace.  This avoids the
-usual maintenance problems with DMI whitelisting.
-
-
-Corner cases and examples:
-====================================
-
-1. If the device is an input device that, because of hardware or firmware,
-causes wireless transmitters to be blocked regardless of the kernel's will, it
-is still just an input device, and NOT to be registered with the rfkill class.
-
-2. If the wireless transmitter switch control is read-only, it is an input
-device and not to be registered with the rfkill class (and maybe not to be made
-an input layer event source either, see below).
-
-3. If there is some other device driver *closer* to the actual hardware the
-user interacted with (the button/switch/key) to issue an input event, THAT is
-the device driver that should be issuing input events.
-
-E.g:
-  [RFKILL slider switch] -- [GPIO hardware] -- [WLAN card rf-kill input]
-                           (platform driver)    (wireless card driver)
-
-The user is closer to the RFKILL slide switch plaform driver, so the driver
-which must issue input events is the platform driver looking at the GPIO
-hardware, and NEVER the wireless card driver (which is just a slave).  It is
-very likely that there are other leaves than just the WLAN card rf-kill input
-(e.g. a bluetooth card, etc)...
-
-On the other hand, some embedded devices do this:
-
-  [RFKILL slider switch] -- [WLAN card rf-kill input]
-                             (wireless card driver)
-
-In this situation, the wireless card driver *could* register itself as an input
-device and issue rf-kill related input events... but in order to AVOID the need
-for DMI whitelisting, the wireless card driver does NOT do it.  Userspace (HAL)
-or a platform driver (that exists only on these embedded devices) will do the
-dirty job of issuing the input events.
-
-
-COMMON MISTAKES in kernel drivers, related to rfkill:
-====================================
-
-1. NEVER confuse input device keys and buttons with input device switches.
-
-  1a. Switches are always set or reset.  They report the current state
-      (on position or off position).
-
-  1b. Keys and buttons are either in the pressed or not-pressed state, and
-      that's it.  A "button" that latches down when you press it, and
-      unlatches when you press it again is in fact a switch as far as input
-      devices go.
-
-Add the SW_* events you need for switches, do NOT try to emulate a button using
-KEY_* events just because there is no such SW_* event yet.  Do NOT try to use,
-for example, KEY_BLUETOOTH when you should be using SW_BLUETOOTH instead.
-
-2. Input device switches (sources of EV_SW events) DO store their current state
-(so you *must* initialize it by issuing a gratuitous input layer event on
-driver start-up and also when resuming from sleep), and that state CAN be
-queried from userspace through IOCTLs.  There is no sysfs interface for this,
-but that doesn't mean you should break things trying to hook it to the rfkill
-class to get a sysfs interface :-)
-
-3. Do not issue *_RFKILL_ALL events by default, unless you are sure it is the
-correct event for your switch/button.  These events are emergency power-off
-events when they are trying to turn the transmitters off.  An example of an
-input device which SHOULD generate *_RFKILL_ALL events is the wireless-kill
-switch in a laptop which is NOT a hotkey, but a real sliding/rocker switch.
-An example of an input device which SHOULD NOT generate *_RFKILL_ALL events by
-default, is any sort of hot key that is type-specific (e.g. the one for WLAN).
-
-
-3.1 Guidelines for wireless device drivers
-------------------------------------------
-
-(in this text, rfkill->foo means the foo field of struct rfkill).
-
-1. Each independent transmitter in a wireless device (usually there is only one
-transmitter per device) should have a SINGLE rfkill class attached to it.
-
-2. If the device does not have any sort of hardware assistance to allow the
-driver to rfkill the device, the driver should emulate it by taking all actions
-required to silence the transmitter.
-
-3. If it is impossible to silence the transmitter (i.e. it still emits energy,
-even if it is just in brief pulses, when there is no data to transmit and there
-is no hardware support to turn it off) do NOT lie to the users.  Do not attach
-it to a rfkill class.  The rfkill subsystem does not deal with data
-transmission, it deals with energy emission.  If the transmitter is emitting
-energy, it is not blocked in rfkill terms.
-
-4. It doesn't matter if the device has multiple rfkill input lines affecting
-the same transmitter, their combined state is to be exported as a single state
-per transmitter (see rule 1).
-
-This rule exists because users of the rfkill subsystem expect to get (and set,
-when possible) the overall transmitter rfkill state, not of a particular rfkill
-line.
-
-5. The wireless device driver MUST NOT leave the transmitter enabled during
-suspend and hibernation unless:
+The rfkill class is provided for kernel drivers to register their radio
+transmitter with the kernel, provide methods for turning it on and off and,
+optionally, letting the system know about hardware-disabled states that may
+be implemented on the device. This code is enabled with the CONFIG_RFKILL
+Kconfig option, which drivers can "select".
 
-       5.1. The transmitter has to be enabled for some sort of functionality
-       like wake-on-wireless-packet or autonomous packed forwarding in a mesh
-       network, and that functionality is enabled for this suspend/hibernation
-       cycle.
+The rfkill class code also notifies userspace of state changes, this is
+achieved via uevents. It also provides some sysfs files for userspace to
+check the status of radio transmitters. See the "Userspace support" section
+below.
 
-AND
 
-       5.2. The device was not on a user-requested BLOCKED state before
-       the suspend (i.e. the driver must NOT unblock a device, not even
-       to support wake-on-wireless-packet or remain in the mesh).
+The rfkill-input code implements a basic response to rfkill buttons -- it
+implements turning on/off all devices of a certain class (or all).
 
-In other words, there is absolutely no allowed scenario where a driver can
-automatically take action to unblock a rfkill controller (obviously, this deals
-with scenarios where soft-blocking or both soft and hard blocking is happening.
-Scenarios where hardware rfkill lines are the only ones blocking the
-transmitter are outside of this rule, since the wireless device driver does not
-control its input hardware rfkill lines in the first place).
+When the device is hard-blocked (either by a call to rfkill_set_hw_state()
+or from query_hw_block) set_block() will be invoked but drivers can well
+ignore the method call since they can use the return value of the function
+rfkill_set_hw_state() to sync the software state instead of keeping track
+of calls to set_block().
 
-6. During resume, rfkill will try to restore its previous state.
 
-7. After a rfkill class is suspended, it will *not* call rfkill->toggle_radio
-until it is resumed.
+The entire functionality is spread over more than one subsystem:
 
+ * The kernel input layer generates KEY_WWAN, KEY_WLAN etc. and
+   SW_RFKILL_ALL -- when the user presses a button. Drivers for radio
+   transmitters generally do not register to the input layer, unless the
+   device really provides an input device (i.e. a button that has no
+   effect other than generating a button press event)
 
-Example of a WLAN wireless driver connected to the rfkill subsystem:
---------------------------------------------------------------------
+ * The rfkill-input code hooks up to these events and switches the soft-block
+   of the various radio transmitters, depending on the button type.
 
-A certain WLAN card has one input pin that causes it to block the transmitter
-and makes the status of that input pin available (only for reading!) to the
-kernel driver.  This is a hard rfkill input line (it cannot be overridden by
-the kernel driver).
+ * The rfkill drivers turn off/on their transmitters as requested.
 
-The card also has one PCI register that, if manipulated by the driver, causes
-it to block the transmitter.  This is a soft rfkill input line.
+ * The rfkill class will generate userspace notifications (uevents) to tell
+   userspace what the current state is.
 
-It has also a thermal protection circuitry that shuts down its transmitter if
-the card overheats, and makes the status of that protection available (only for
-reading!) to the kernel driver.  This is also a hard rfkill input line.
 
-If either one of these rfkill lines are active, the transmitter is blocked by
-the hardware and forced offline.
 
-The driver should allocate and attach to its struct device *ONE* instance of
-the rfkill class (there is only one transmitter).
+3. Kernel driver guidelines
 
-It can implement the get_state() hook, and return RFKILL_STATE_HARD_BLOCKED if
-either one of its two hard rfkill input lines are active.  If the two hard
-rfkill lines are inactive, it must return RFKILL_STATE_SOFT_BLOCKED if its soft
-rfkill input line is active.  Only if none of the rfkill input lines are
-active, will it return RFKILL_STATE_UNBLOCKED.
 
-Since the device has a hardware rfkill line, it IS subject to state changes
-external to rfkill.  Therefore, the driver must make sure that it calls
-rfkill_force_state() to keep the status always up-to-date, and it must do a
-rfkill_force_state() on resume from sleep.
+Drivers for radio transmitters normally implement only the rfkill class.
+These drivers may not unblock the transmitter based on own decisions, they
+should act on information provided by the rfkill class only.
 
-Every time the driver gets a notification from the card that one of its rfkill
-lines changed state (polling might be needed on badly designed cards that don't
-generate interrupts for such events), it recomputes the rfkill state as per
-above, and calls rfkill_force_state() to update it.
+Platform drivers might implement input devices if the rfkill button is just
+that, a button. If that button influences the hardware then you need to
+implement an rfkill class instead. This also applies if the platform provides
+a way to turn on/off the transmitter(s).
 
-The driver should implement the toggle_radio() hook, that:
+During suspend/hibernation, transmitters should only be left enabled when
+wake-on wlan or similar functionality requires it and the device wasn't
+blocked before suspend/hibernate. Note that it may be necessary to update
+the rfkill subsystem's idea of what the current state is at resume time if
+the state may have changed over suspend.
 
-1. Returns an error if one of the hardware rfkill lines are active, and the
-caller asked for RFKILL_STATE_UNBLOCKED.
 
-2. Activates the soft rfkill line if the caller asked for state
-RFKILL_STATE_SOFT_BLOCKED.  It should do this even if one of the hard rfkill
-lines are active, effectively double-blocking the transmitter.
 
-3. Deactivates the soft rfkill line if none of the hardware rfkill lines are
-active and the caller asked for RFKILL_STATE_UNBLOCKED.
-
-===============================================================================
-4: Kernel API
+4. Kernel API
 
 To build a driver with rfkill subsystem support, the driver should depend on
-(or select) the Kconfig symbol RFKILL; it should _not_ depend on RKFILL_INPUT.
+(or select) the Kconfig symbol RFKILL.
 
 The hardware the driver talks to may be write-only (where the current state
 of the hardware is unknown), or read-write (where the hardware can be queried
 about its current state).
 
-The rfkill class will call the get_state hook of a device every time it needs
-to know the *real* current state of the hardware.  This can happen often, but
-it does not do any polling, so it is not enough on hardware that is subject
-to state changes outside of the rfkill subsystem.
-
-Therefore, calling rfkill_force_state() when a state change happens is
-mandatory when the device has a hardware rfkill line, or when something else
-like the firmware could cause its state to be changed without going through the
-rfkill class.
-
-Some hardware provides events when its status changes.  In these cases, it is
-best for the driver to not provide a get_state hook, and instead register the
-rfkill class *already* with the correct status, and keep it updated using
-rfkill_force_state() when it gets an event from the hardware.
-
-rfkill_force_state() must be used on the device resume handlers to update the
-rfkill status, should there be any chance of the device status changing during
-the sleep.
-
-There is no provision for a statically-allocated rfkill struct.  You must
-use rfkill_allocate() to allocate one.
-
-You should:
-       - rfkill_allocate()
-       - modify rfkill fields (flags, name)
-       - modify state to the current hardware state (THIS IS THE ONLY TIME
-         YOU CAN ACCESS state DIRECTLY)
-       - rfkill_register()
-
-The only way to set a device to the RFKILL_STATE_HARD_BLOCKED state is through
-a suitable return of get_state() or through rfkill_force_state().
+Calling rfkill_set_hw_state() when a state change happens is required from
+rfkill drivers that control devices that can be hard-blocked unless they also
+assign the poll_hw_block() callback (then the rfkill core will poll the
+device). Don't do this unless you cannot get the event in any other way.
 
-When a device is in the RFKILL_STATE_HARD_BLOCKED state, the only way to switch
-it to a different state is through a suitable return of get_state() or through
-rfkill_force_state().
 
-If toggle_radio() is called to set a device to state RFKILL_STATE_SOFT_BLOCKED
-when that device is already at the RFKILL_STATE_HARD_BLOCKED state, it should
-not return an error.  Instead, it should try to double-block the transmitter,
-so that its state will change from RFKILL_STATE_HARD_BLOCKED to
-RFKILL_STATE_SOFT_BLOCKED should the hardware blocking cease.
-
-Please refer to the source for more documentation.
-
-===============================================================================
-5: Userspace support
-
-rfkill devices issue uevents (with an action of "change"), with the following
-environment variables set:
-
-RFKILL_NAME
-RFKILL_STATE
-RFKILL_TYPE
 
-The ABI for these variables is defined by the sysfs attributes.  It is best
-to take a quick look at the source to make sure of the possible values.
+5. Userspace support
 
-It is expected that HAL will trap those, and bridge them to DBUS, etc.  These
-events CAN and SHOULD be used to give feedback to the user about the rfkill
-status of the system.
-
-Input devices may issue events that are related to rfkill.  These are the
-various KEY_* events and SW_* events supported by rfkill-input.c.
-
-Userspace may not change the state of an rfkill switch in response to an
-input event, it should refrain from changing states entirely.
-
-Userspace cannot assume it is the only source of control for rfkill switches.
-Their state can change due to firmware actions, direct user actions, and the
-rfkill-input EPO override for *_RFKILL_ALL.
-
-When rfkill-input is not active, userspace must initiate a rfkill status
-change by writing to the "state" attribute in order for anything to happen.
-
-Take particular care to implement EV_SW SW_RFKILL_ALL properly.  When that
-switch is set to OFF, *every* rfkill device *MUST* be immediately put into the
-RFKILL_STATE_SOFT_BLOCKED state, no questions asked.
-
-The following sysfs entries will be created:
+The following sysfs entries exist for every rfkill device:
 
        name: Name assigned by driver to this key (interface or driver name).
        type: Name of the key type ("wlan", "bluetooth", etc).
        state: Current state of the transmitter
                0: RFKILL_STATE_SOFT_BLOCKED
-                       transmitter is forced off, but one can override it
-                       by a write to the state attribute;
+                       transmitter is turned off by software
                1: RFKILL_STATE_UNBLOCKED
-                       transmiter is NOT forced off, and may operate if
-                       all other conditions for such operation are met
-                       (such as interface is up and configured, etc);
+                       transmitter is (potentially) active
                2: RFKILL_STATE_HARD_BLOCKED
                        transmitter is forced off by something outside of
-                       the driver's control.  One cannot set a device to
-                       this state through writes to the state attribute;
-       claim: 1: Userspace handles events, 0: Kernel handles events
-
-Both the "state" and "claim" entries are also writable. For the "state" entry
-this means that when 1 or 0 is written, the device rfkill state (if not yet in
-the requested state), will be will be toggled accordingly.
-
-For the "claim" entry writing 1 to it means that the kernel no longer handles
-key events even though RFKILL_INPUT input was enabled. When "claim" has been
-set to 0, userspace should make sure that it listens for the input events or
-check the sysfs "state" entry regularly to correctly perform the required tasks
-when the rkfill key is pressed.
-
-A note about input devices and EV_SW events:
-
-In order to know the current state of an input device switch (like
-SW_RFKILL_ALL), you will need to use an IOCTL.  That information is not
-available through sysfs in a generic way at this time, and it is not available
-through the rfkill class AT ALL.
+                       the driver's control.
+       claim: 0: Kernel handles events (currently always reads that value)
+
+rfkill devices also issue uevents (with an action of "change"), with the
+following environment variables set:
+
+RFKILL_NAME
+RFKILL_STATE
+RFKILL_TYPE
+
+The contents of these variables corresponds to the "name", "state" and
+"type" sysfs files explained above.
+
+An alternative userspace interface exists as a misc device /dev/rfkill,
+which allows userspace to obtain and set the state of rfkill devices and
+sets of devices. It also notifies userspace about device addition and
+removal. The API is a simple read/write API that is defined in
+linux/rfkill.h.
index 77f277e..a6df68f 100644 (file)
@@ -1545,6 +1545,13 @@ W:       http://www.fi.muni.cz/~kas/cosa/
 S:     Maintained
 F:     drivers/net/wan/cosa*
 
+CPMAC ETHERNET DRIVER
+P:     Florian Fainelli
+M:     florian@openwrt.org
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     drivers/net/cpmac.c
+
 CPU FREQUENCY DRIVERS
 P:     Dave Jones
 M:     davej@redhat.com
@@ -2812,6 +2819,18 @@ L:       linux1394-devel@lists.sourceforge.net
 S:     Maintained
 F:     drivers/ieee1394/raw1394*
 
+IEEE 802.15.4 SUBSYSTEM
+P:     Dmitry Eremin-Solenikov
+M:     dbaryshkov@gmail.com
+P:     Sergey Lapin
+M:     slapin@ossfans.org
+L:     linux-zigbee-devel@lists.sourceforge.net
+W:     http://apps.sourceforge.net/trac/linux-zigbee
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lumag/lowpan.git
+S:     Maintained
+F:     net/ieee802154/
+F:     drivers/ieee801254/
+
 INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
 P:     Mimi Zohar
 M:     zohar@us.ibm.com
@@ -4746,9 +4765,9 @@ S:        Supported
 F:     fs/reiserfs/
 
 RFKILL
-P:     Ivo van Doorn
-M:     IvDoorn@gmail.com
-L:     netdev@vger.kernel.org
+P:     Johannes Berg
+M:     johannes@sipsolutions.net
+L:     linux-wireless@vger.kernel.org
 S:     Maintained
 F      Documentation/rfkill.txt
 F:     net/rfkill/
index 69e2655..98099bd 100644 (file)
 #define        EOWNERDEAD      136     /* Owner died */
 #define        ENOTRECOVERABLE 137     /* State not recoverable */
 
+#define        ERFKILL         138     /* Operation not possible due to RF-kill */
+
 #endif
index bde42aa..c31e601 100644 (file)
@@ -35,21 +35,25 @@ static void tosa_bt_off(struct tosa_bt_data *data)
        gpio_set_value(data->gpio_reset, 0);
 }
 
-static int tosa_bt_toggle_radio(void *data, enum rfkill_state state)
+static int tosa_bt_set_block(void *data, bool blocked)
 {
-       pr_info("BT_RADIO going: %s\n",
-                       state == RFKILL_STATE_UNBLOCKED ? "on" : "off");
+       pr_info("BT_RADIO going: %s\n", blocked ? "off" : "on");
 
-       if (state == RFKILL_STATE_UNBLOCKED) {
+       if (!blocked) {
                pr_info("TOSA_BT: going ON\n");
                tosa_bt_on(data);
        } else {
                pr_info("TOSA_BT: going OFF\n");
                tosa_bt_off(data);
        }
+
        return 0;
 }
 
+static const struct rfkill_ops tosa_bt_rfkill_ops = {
+       .set_block = tosa_bt_set_block,
+};
+
 static int tosa_bt_probe(struct platform_device *dev)
 {
        int rc;
@@ -70,18 +74,14 @@ static int tosa_bt_probe(struct platform_device *dev)
        if (rc)
                goto err_pwr_dir;
 
-       rfk = rfkill_allocate(&dev->dev, RFKILL_TYPE_BLUETOOTH);
+       rfk = rfkill_alloc("tosa-bt", &dev->dev, RFKILL_TYPE_BLUETOOTH,
+                          &tosa_bt_rfkill_ops, data);
        if (!rfk) {
                rc = -ENOMEM;
                goto err_rfk_alloc;
        }
 
-       rfk->name = "tosa-bt";
-       rfk->toggle_radio = tosa_bt_toggle_radio;
-       rfk->data = data;
-#ifdef CONFIG_RFKILL_LEDS
-       rfk->led_trigger.name = "tosa-bt";
-#endif
+       rfkill_set_led_trigger_name(rfk, "tosa-bt");
 
        rc = rfkill_register(rfk);
        if (rc)
@@ -92,9 +92,7 @@ static int tosa_bt_probe(struct platform_device *dev)
        return 0;
 
 err_rfkill:
-       if (rfk)
-               rfkill_free(rfk);
-       rfk = NULL;
+       rfkill_destroy(rfk);
 err_rfk_alloc:
        tosa_bt_off(data);
 err_pwr_dir:
@@ -113,8 +111,10 @@ static int __devexit tosa_bt_remove(struct platform_device *dev)
 
        platform_set_drvdata(dev, NULL);
 
-       if (rfk)
+       if (rfk) {
                rfkill_unregister(rfk);
+               rfkill_destroy(rfk);
+       }
        rfk = NULL;
 
        tosa_bt_off(data);
index afac5b6..58ce807 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/input.h>
 #include <linux/gpio.h>
 #include <linux/pda_power.h>
-#include <linux/rfkill.h>
 #include <linux/spi/spi.h>
 
 #include <asm/setup.h>
index 3c0d840..a0efc73 100644 (file)
 #define        EOWNERDEAD      165     /* Owner died */
 #define        ENOTRECOVERABLE 166     /* State not recoverable */
 
+#define        ERFKILL         167     /* Operation not possible due to RF-kill */
+
 #define EDQUOT         1133    /* Quota exceeded */
 
 #ifdef __KERNEL__
index e2f3ddc..9992abd 100644 (file)
 #define EOWNERDEAD     254     /* Owner died */
 #define ENOTRECOVERABLE        255     /* State not recoverable */
 
+#define        ERFKILL         256     /* Operation not possible due to RF-kill */
 
 #endif
index 2701753..4459d20 100644 (file)
@@ -668,6 +668,8 @@ struct ucc_slow_pram {
 #define UCC_GETH_UPSMR_RMM      0x00001000
 #define UCC_GETH_UPSMR_CAM      0x00000400
 #define UCC_GETH_UPSMR_BRO      0x00000200
+#define UCC_GETH_UPSMR_SMM     0x00000080
+#define UCC_GETH_UPSMR_SGMM    0x00000020
 
 /* UCC Transmit On Demand Register (UTODR) */
 #define UCC_SLOW_TOD   0x8000
index a9ef172..4e2bc49 100644 (file)
 #define        EOWNERDEAD      132     /* Owner died */
 #define        ENOTRECOVERABLE 133     /* State not recoverable */
 
+#define        ERFKILL         134     /* Operation not possible due to RF-kill */
+
 #endif
index 1266ead..9e7d4e5 100644 (file)
@@ -107,3 +107,4 @@ obj-$(CONFIG_SSB)           += ssb/
 obj-$(CONFIG_VIRTIO)           += virtio/
 obj-$(CONFIG_STAGING)          += staging/
 obj-y                          += platform/
+obj-y                          += ieee802154/
index 31693bc..965ece2 100644 (file)
@@ -34,13 +34,6 @@ new_skb(ulong len)
                skb_reset_mac_header(skb);
                skb_reset_network_header(skb);
                skb->protocol = __constant_htons(ETH_P_AOE);
-               skb->priority = 0;
-               skb->next = skb->prev = NULL;
-
-               /* tell the network layer not to perform IP checksums
-                * or to get the NIC to do it
-                */
-               skb->ip_summed = CHECKSUM_NONE;
        }
        return skb;
 }
index 0bbefba..1df9dda 100644 (file)
@@ -40,7 +40,7 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
-#define VERSION "1.2"
+#define VERSION "1.3"
 
 static int minor = MISC_DYNAMIC_MINOR;
 
@@ -51,14 +51,8 @@ struct vhci_data {
 
        wait_queue_head_t read_wait;
        struct sk_buff_head readq;
-
-       struct fasync_struct *fasync;
 };
 
-#define VHCI_FASYNC    0x0010
-
-static struct miscdevice vhci_miscdev;
-
 static int vhci_open_dev(struct hci_dev *hdev)
 {
        set_bit(HCI_RUNNING, &hdev->flags);
@@ -105,9 +99,6 @@ static int vhci_send_frame(struct sk_buff *skb)
        memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
        skb_queue_tail(&data->readq, skb);
 
-       if (data->flags & VHCI_FASYNC)
-               kill_fasync(&data->fasync, SIGIO, POLL_IN);
-
        wake_up_interruptible(&data->read_wait);
 
        return 0;
@@ -179,41 +170,31 @@ static inline ssize_t vhci_put_user(struct vhci_data *data,
 static ssize_t vhci_read(struct file *file,
                                char __user *buf, size_t count, loff_t *pos)
 {
-       DECLARE_WAITQUEUE(wait, current);
        struct vhci_data *data = file->private_data;
        struct sk_buff *skb;
        ssize_t ret = 0;
 
-       add_wait_queue(&data->read_wait, &wait);
        while (count) {
-               set_current_state(TASK_INTERRUPTIBLE);
-
                skb = skb_dequeue(&data->readq);
-               if (!skb) {
-                       if (file->f_flags & O_NONBLOCK) {
-                               ret = -EAGAIN;
-                               break;
-                       }
-
-                       if (signal_pending(current)) {
-                               ret = -ERESTARTSYS;
-                               break;
-                       }
-
-                       schedule();
-                       continue;
+               if (skb) {
+                       ret = vhci_put_user(data, skb, buf, count);
+                       if (ret < 0)
+                               skb_queue_head(&data->readq, skb);
+                       else
+                               kfree_skb(skb);
+                       break;
                }
 
-               if (access_ok(VERIFY_WRITE, buf, count))
-                       ret = vhci_put_user(data, skb, buf, count);
-               else
-                       ret = -EFAULT;
+               if (file->f_flags & O_NONBLOCK) {
+                       ret = -EAGAIN;
+                       break;
+               }
 
-               kfree_skb(skb);
-               break;
+               ret = wait_event_interruptible(data->read_wait,
+                                       !skb_queue_empty(&data->readq));
+               if (ret < 0)
+                       break;
        }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&data->read_wait, &wait);
 
        return ret;
 }
@@ -223,9 +204,6 @@ static ssize_t vhci_write(struct file *file,
 {
        struct vhci_data *data = file->private_data;
 
-       if (!access_ok(VERIFY_READ, buf, count))
-               return -EFAULT;
-
        return vhci_get_user(data, buf, count);
 }
 
@@ -259,11 +237,9 @@ static int vhci_open(struct inode *inode, struct file *file)
        skb_queue_head_init(&data->readq);
        init_waitqueue_head(&data->read_wait);
 
-       lock_kernel();
        hdev = hci_alloc_dev();
        if (!hdev) {
                kfree(data);
-               unlock_kernel();
                return -ENOMEM;
        }
 
@@ -284,12 +260,10 @@ static int vhci_open(struct inode *inode, struct file *file)
                BT_ERR("Can't register HCI device");
                kfree(data);
                hci_free_dev(hdev);
-               unlock_kernel();
                return -EBUSY;
        }
 
        file->private_data = data;
-       unlock_kernel();
 
        return nonseekable_open(inode, file);
 }
@@ -310,48 +284,25 @@ static int vhci_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-static int vhci_fasync(int fd, struct file *file, int on)
-{
-       struct vhci_data *data = file->private_data;
-       int err = 0;
-
-       lock_kernel();
-       err = fasync_helper(fd, file, on, &data->fasync);
-       if (err < 0)
-               goto out;
-
-       if (on)
-               data->flags |= VHCI_FASYNC;
-       else
-               data->flags &= ~VHCI_FASYNC;
-
-out:
-       unlock_kernel();
-       return err;
-}
-
 static const struct file_operations vhci_fops = {
-       .owner          = THIS_MODULE,
        .read           = vhci_read,
        .write          = vhci_write,
        .poll           = vhci_poll,
        .ioctl          = vhci_ioctl,
        .open           = vhci_open,
        .release        = vhci_release,
-       .fasync         = vhci_fasync,
 };
 
 static struct miscdevice vhci_miscdev= {
-       .name           = "vhci",
-       .fops           = &vhci_fops,
+       .name   = "vhci",
+       .fops   = &vhci_fops,
+       .minor  = MISC_DYNAMIC_MINOR,
 };
 
 static int __init vhci_init(void)
 {
        BT_INFO("Virtual HCI driver ver %s", VERSION);
 
-       vhci_miscdev.minor = minor;
-
        if (misc_register(&vhci_miscdev) < 0) {
                BT_ERR("Can't register misc device with minor %d", minor);
                return -EIO;
@@ -369,9 +320,6 @@ static void __exit vhci_exit(void)
 module_init(vhci_init);
 module_exit(vhci_exit);
 
-module_param(minor, int, 0444);
-MODULE_PARM_DESC(minor, "Miscellaneous minor device number");
-
 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION);
 MODULE_VERSION(VERSION);
diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig
new file mode 100644 (file)
index 0000000..25740bd
--- /dev/null
@@ -0,0 +1,22 @@
+menuconfig IEEE802154_DRIVERS
+       bool "IEEE 802.15.4 drivers"
+       depends on NETDEVICES && IEEE802154
+       default y
+       ---help---
+         Say Y here to get to see options for IEEE 802.15.4 Low-Rate
+         Wireless Personal Area Network device drivers. This option alone
+         does not add any kernel code.
+
+         If you say N, all options in this submenu will be skipped and
+         disabled.
+
+config IEEE802154_FAKEHARD
+       tristate "Fake LR-WPAN driver with several interconnected devices"
+       depends on  IEEE802154_DRIVERS
+       ---help---
+         Say Y here to enable the fake driver that serves as an example
+          of HardMAC device driver.
+
+          This driver can also be built as a module. To do so say M here.
+         The module will be called 'fakehard'.
+
diff --git a/drivers/ieee802154/Makefile b/drivers/ieee802154/Makefile
new file mode 100644 (file)
index 0000000..e0e8e1a
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o
+
+EXTRA_CFLAGS += -DDEBUG -DCONFIG_FFD
diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c
new file mode 100644 (file)
index 0000000..0384144
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * Sample driver for HardMAC IEEE 802.15.4 devices
+ *
+ * Copyright (C) 2009 Siemens AG
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by:
+ * Dmitry Eremin-Solenikov <dmitry.baryshkov@siemens.com>
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+
+#include <net/ieee802154/af_ieee802154.h>
+#include <net/ieee802154/netdevice.h>
+#include <net/ieee802154/mac_def.h>
+#include <net/ieee802154/nl802154.h>
+
+static u16 fake_get_pan_id(struct net_device *dev)
+{
+       BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+       return 0xeba1;
+}
+
+static u16 fake_get_short_addr(struct net_device *dev)
+{
+       BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+       return 0x1;
+}
+
+static u8 fake_get_dsn(struct net_device *dev)
+{
+       BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+       return 0x00; /* DSN are implemented in HW, so return just 0 */
+}
+
+static u8 fake_get_bsn(struct net_device *dev)
+{
+       BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+       return 0x00; /* BSN are implemented in HW, so return just 0 */
+}
+
+static int fake_assoc_req(struct net_device *dev,
+               struct ieee802154_addr *addr, u8 channel, u8 cap)
+{
+       /* We simply emulate it here */
+       return ieee802154_nl_assoc_confirm(dev, fake_get_short_addr(dev),
+                       IEEE802154_SUCCESS);
+}
+
+static int fake_assoc_resp(struct net_device *dev,
+               struct ieee802154_addr *addr, u16 short_addr, u8 status)
+{
+       return 0;
+}
+
+static int fake_disassoc_req(struct net_device *dev,
+               struct ieee802154_addr *addr, u8 reason)
+{
+       return ieee802154_nl_disassoc_confirm(dev, IEEE802154_SUCCESS);
+}
+
+static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr,
+                               u8 channel,
+                               u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
+                               u8 coord_realign)
+{
+       return 0;
+}
+
+static int fake_scan_req(struct net_device *dev, u8 type, u32 channels,
+               u8 duration)
+{
+       u8 edl[27] = {};
+       return ieee802154_nl_scan_confirm(dev, IEEE802154_SUCCESS, type,
+                       channels,
+                       type == IEEE802154_MAC_SCAN_ED ? edl : NULL);
+}
+
+static struct ieee802154_mlme_ops fake_mlme = {
+       .assoc_req = fake_assoc_req,
+       .assoc_resp = fake_assoc_resp,
+       .disassoc_req = fake_disassoc_req,
+       .start_req = fake_start_req,
+       .scan_req = fake_scan_req,
+
+       .get_pan_id = fake_get_pan_id,
+       .get_short_addr = fake_get_short_addr,
+       .get_dsn = fake_get_dsn,
+       .get_bsn = fake_get_bsn,
+};
+
+static int ieee802154_fake_open(struct net_device *dev)
+{
+       netif_start_queue(dev);
+       return 0;
+}
+
+static int ieee802154_fake_close(struct net_device *dev)
+{
+       netif_stop_queue(dev);
+       return 0;
+}
+
+static int ieee802154_fake_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       skb->iif = dev->ifindex;
+       skb->dev = dev;
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += skb->len;
+
+       dev->trans_start = jiffies;
+
+       /* FIXME: do hardware work here ... */
+
+       return 0;
+}
+
+
+static int ieee802154_fake_ioctl(struct net_device *dev, struct ifreq *ifr,
+               int cmd)
+{
+       struct sockaddr_ieee802154 *sa =
+               (struct sockaddr_ieee802154 *)&ifr->ifr_addr;
+       u16 pan_id, short_addr;
+
+       switch (cmd) {
+       case SIOCGIFADDR:
+               /* FIXME: fixed here, get from device IRL */
+               pan_id = fake_get_pan_id(dev);
+               short_addr = fake_get_short_addr(dev);
+               if (pan_id == IEEE802154_PANID_BROADCAST ||
+                   short_addr == IEEE802154_ADDR_BROADCAST)
+                       return -EADDRNOTAVAIL;
+
+               sa->family = AF_IEEE802154;
+               sa->addr.addr_type = IEEE802154_ADDR_SHORT;
+               sa->addr.pan_id = pan_id;
+               sa->addr.short_addr = short_addr;
+               return 0;
+       }
+       return -ENOIOCTLCMD;
+}
+
+static int ieee802154_fake_mac_addr(struct net_device *dev, void *p)
+{
+       return -EBUSY; /* HW address is built into the device */
+}
+
+static const struct net_device_ops fake_ops = {
+       .ndo_open               = ieee802154_fake_open,
+       .ndo_stop               = ieee802154_fake_close,
+       .ndo_start_xmit         = ieee802154_fake_xmit,
+       .ndo_do_ioctl           = ieee802154_fake_ioctl,
+       .ndo_set_mac_address    = ieee802154_fake_mac_addr,
+};
+
+
+static void ieee802154_fake_setup(struct net_device *dev)
+{
+       dev->addr_len           = IEEE802154_ADDR_LEN;
+       memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
+       dev->features           = NETIF_F_NO_CSUM;
+       dev->needed_tailroom    = 2; /* FCS */
+       dev->mtu                = 127;
+       dev->tx_queue_len       = 10;
+       dev->type               = ARPHRD_IEEE802154;
+       dev->flags              = IFF_NOARP | IFF_BROADCAST;
+       dev->watchdog_timeo     = 0;
+}
+
+
+static int __devinit ieee802154fake_probe(struct platform_device *pdev)
+{
+       struct net_device *dev =
+               alloc_netdev(0, "hardwpan%d", ieee802154_fake_setup);
+       int err;
+
+       if (!dev)
+               return -ENOMEM;
+
+       memcpy(dev->dev_addr, "\xba\xbe\xca\xfe\xde\xad\xbe\xef",
+                       dev->addr_len);
+       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
+       dev->netdev_ops = &fake_ops;
+       dev->ml_priv = &fake_mlme;
+
+       /*
+        * If the name is a format string the caller wants us to do a
+        * name allocation.
+        */
+       if (strchr(dev->name, '%')) {
+               err = dev_alloc_name(dev, dev->name);
+               if (err < 0)
+                       goto out;
+       }
+
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
+       platform_set_drvdata(pdev, dev);
+
+       err = register_netdev(dev);
+       if (err < 0)
+               goto out;
+
+
+       dev_info(&pdev->dev, "Added ieee802154 HardMAC hardware\n");
+       return 0;
+
+out:
+       unregister_netdev(dev);
+       return err;
+}
+
+static int __devexit ieee802154fake_remove(struct platform_device *pdev)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+       unregister_netdev(dev);
+       free_netdev(dev);
+       return 0;
+}
+
+static struct platform_device *ieee802154fake_dev;
+
+static struct platform_driver ieee802154fake_driver = {
+       .probe = ieee802154fake_probe,
+       .remove = __devexit_p(ieee802154fake_remove),
+       .driver = {
+                       .name = "ieee802154hardmac",
+                       .owner = THIS_MODULE,
+       },
+};
+
+static __init int fake_init(void)
+{
+       ieee802154fake_dev = platform_device_register_simple(
+                       "ieee802154hardmac", -1, NULL, 0);
+       return platform_driver_register(&ieee802154fake_driver);
+}
+
+static __exit void fake_exit(void)
+{
+       platform_driver_unregister(&ieee802154fake_driver);
+       platform_device_unregister(ieee802154fake_dev);
+}
+
+module_init(fake_init);
+module_exit(fake_exit);
+MODULE_LICENSE("GPL");
+
index 4248c31..181b1f3 100644 (file)
@@ -1394,8 +1394,8 @@ void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb,
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        int e = skb_queue_empty(&priv->cm.skb_queue);
 
-       if (skb->dst)
-               skb->dst->ops->update_pmtu(skb->dst, mtu);
+       if (skb_dst(skb))
+               skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
 
        skb_queue_tail(&priv->cm.skb_queue, skb);
        if (e)
index ab2c192..e319d91 100644 (file)
@@ -561,7 +561,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
        struct ipoib_neigh *neigh;
        unsigned long flags;
 
-       neigh = ipoib_neigh_alloc(skb->dst->neighbour, skb->dev);
+       neigh = ipoib_neigh_alloc(skb_dst(skb)->neighbour, skb->dev);
        if (!neigh) {
                ++dev->stats.tx_dropped;
                dev_kfree_skb_any(skb);
@@ -570,9 +570,9 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
 
        spin_lock_irqsave(&priv->lock, flags);
 
-       path = __path_find(dev, skb->dst->neighbour->ha + 4);
+       path = __path_find(dev, skb_dst(skb)->neighbour->ha + 4);
        if (!path) {
-               path = path_rec_create(dev, skb->dst->neighbour->ha + 4);
+               path = path_rec_create(dev, skb_dst(skb)->neighbour->ha + 4);
                if (!path)
                        goto err_path;
 
@@ -605,7 +605,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
                                goto err_drop;
                        }
                } else
-                       ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb->dst->neighbour->ha));
+                       ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb_dst(skb)->neighbour->ha));
        } else {
                neigh->ah  = NULL;
 
@@ -635,15 +635,15 @@ static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev)
        struct ipoib_dev_priv *priv = netdev_priv(skb->dev);
 
        /* Look up path record for unicasts */
-       if (skb->dst->neighbour->ha[4] != 0xff) {
+       if (skb_dst(skb)->neighbour->ha[4] != 0xff) {
                neigh_add_path(skb, dev);
                return;
        }
 
        /* Add in the P_Key for multicasts */
-       skb->dst->neighbour->ha[8] = (priv->pkey >> 8) & 0xff;
-       skb->dst->neighbour->ha[9] = priv->pkey & 0xff;
-       ipoib_mcast_send(dev, skb->dst->neighbour->ha + 4, skb);
+       skb_dst(skb)->neighbour->ha[8] = (priv->pkey >> 8) & 0xff;
+       skb_dst(skb)->neighbour->ha[9] = priv->pkey & 0xff;
+       ipoib_mcast_send(dev, skb_dst(skb)->neighbour->ha + 4, skb);
 }
 
 static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
@@ -708,16 +708,16 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
        struct ipoib_neigh *neigh;
        unsigned long flags;
 
-       if (likely(skb->dst && skb->dst->neighbour)) {
-               if (unlikely(!*to_ipoib_neigh(skb->dst->neighbour))) {
+       if (likely(skb_dst(skb) && skb_dst(skb)->neighbour)) {
+               if (unlikely(!*to_ipoib_neigh(skb_dst(skb)->neighbour))) {
                        ipoib_path_lookup(skb, dev);
                        return NETDEV_TX_OK;
                }
 
-               neigh = *to_ipoib_neigh(skb->dst->neighbour);
+               neigh = *to_ipoib_neigh(skb_dst(skb)->neighbour);
 
                if (unlikely((memcmp(&neigh->dgid.raw,
-                                    skb->dst->neighbour->ha + 4,
+                                    skb_dst(skb)->neighbour->ha + 4,
                                     sizeof(union ib_gid))) ||
                             (neigh->dev != dev))) {
                        spin_lock_irqsave(&priv->lock, flags);
@@ -743,7 +743,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                return NETDEV_TX_OK;
                        }
                } else if (neigh->ah) {
-                       ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(skb->dst->neighbour->ha));
+                       ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(skb_dst(skb)->neighbour->ha));
                        return NETDEV_TX_OK;
                }
 
@@ -772,7 +772,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        if ((be16_to_cpup((__be16 *) skb->data) != ETH_P_ARP) &&
                            (be16_to_cpup((__be16 *) skb->data) != ETH_P_RARP)) {
                                ipoib_warn(priv, "Unicast, no %s: type %04x, QPN %06x %pI6\n",
-                                          skb->dst ? "neigh" : "dst",
+                                          skb_dst(skb) ? "neigh" : "dst",
                                           be16_to_cpup((__be16 *) skb->data),
                                           IPOIB_QPN(phdr->hwaddr),
                                           phdr->hwaddr + 4);
@@ -817,7 +817,7 @@ static int ipoib_hard_header(struct sk_buff *skb,
         * destination address onto the front of the skb so we can
         * figure out where to send the packet later.
         */
-       if ((!skb->dst || !skb->dst->neighbour) && daddr) {
+       if ((!skb_dst(skb) || !skb_dst(skb)->neighbour) && daddr) {
                struct ipoib_pseudoheader *phdr =
                        (struct ipoib_pseudoheader *) skb_push(skb, sizeof *phdr);
                memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN);
@@ -1053,6 +1053,7 @@ static void ipoib_setup(struct net_device *dev)
        dev->tx_queue_len        = ipoib_sendq_size * 2;
        dev->features            = (NETIF_F_VLAN_CHALLENGED     |
                                    NETIF_F_HIGHDMA);
+       dev->priv_flags         &= ~IFF_XMIT_DST_RELEASE;
 
        memcpy(dev->broadcast, ipv4_bcast_addr, INFINIBAND_ALEN);
 
index 425e311..a0e9753 100644 (file)
@@ -261,7 +261,7 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
 
                skb->dev = dev;
 
-               if (!skb->dst || !skb->dst->neighbour) {
+               if (!skb_dst(skb) || !skb_dst(skb)->neighbour) {
                        /* put pseudoheader back on for next time */
                        skb_push(skb, sizeof (struct ipoib_pseudoheader));
                }
@@ -707,10 +707,10 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)
 
 out:
        if (mcast && mcast->ah) {
-               if (skb->dst            &&
-                   skb->dst->neighbour &&
-                   !*to_ipoib_neigh(skb->dst->neighbour)) {
-                       struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb->dst->neighbour,
+               if (skb_dst(skb)                &&
+                   skb_dst(skb)->neighbour &&
+                   !*to_ipoib_neigh(skb_dst(skb)->neighbour)) {
+                       struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb_dst(skb)->neighbour,
                                                                        skb->dev);
 
                        if (neigh) {
index 29419a8..16f2e46 100644 (file)
@@ -490,7 +490,14 @@ static void pars_2_message(_cmsg * cmsg)
        }
 }
 
-/*-------------------------------------------------------*/
+/**
+ * capi_cmsg2message() - assemble CAPI 2.0 message from _cmsg structure
+ * @cmsg:      _cmsg structure
+ * @msg:       buffer for assembled message
+ *
+ * Return value: 0 for success
+ */
+
 unsigned capi_cmsg2message(_cmsg * cmsg, u8 * msg)
 {
        cmsg->m = msg;
@@ -553,7 +560,14 @@ static void message_2_pars(_cmsg * cmsg)
        }
 }
 
-/*-------------------------------------------------------*/
+/**
+ * capi_message2cmsg() - disassemble CAPI 2.0 message into _cmsg structure
+ * @cmsg:      _cmsg structure
+ * @msg:       buffer for assembled message
+ *
+ * Return value: 0 for success
+ */
+
 unsigned capi_message2cmsg(_cmsg * cmsg, u8 * msg)
 {
        memset(cmsg, 0, sizeof(_cmsg));
@@ -573,7 +587,18 @@ unsigned capi_message2cmsg(_cmsg * cmsg, u8 * msg)
        return 0;
 }
 
-/*-------------------------------------------------------*/
+/**
+ * capi_cmsg_header() - initialize header part of _cmsg structure
+ * @cmsg:      _cmsg structure
+ * @_ApplId:   ApplID field value
+ * @_Command:  Command field value
+ * @_Subcommand:       Subcommand field value
+ * @_Messagenumber:    Message Number field value
+ * @_Controller:       Controller/PLCI/NCCI field value
+ *
+ * Return value: 0 for success
+ */
+
 unsigned capi_cmsg_header(_cmsg * cmsg, u16 _ApplId,
                          u8 _Command, u8 _Subcommand,
                          u16 _Messagenumber, u32 _Controller)
@@ -641,6 +666,14 @@ static char *mnames[] =
        [0x4e] = "MANUFACTURER_RESP"
 };
 
+/**
+ * capi_cmd2str() - convert CAPI 2.0 command/subcommand number to name
+ * @cmd:       command number
+ * @subcmd:    subcommand number
+ *
+ * Return value: static string, NULL if command/subcommand unknown
+ */
+
 char *capi_cmd2str(u8 cmd, u8 subcmd)
 {
        return mnames[command_2_index(cmd, subcmd)];
@@ -879,6 +912,11 @@ init:
        return cdb;
 }
 
+/**
+ * cdebbuf_free() - free CAPI debug buffer
+ * @cdb:       buffer to free
+ */
+
 void cdebbuf_free(_cdebbuf *cdb)
 {
        if (likely(cdb == g_debbuf)) {
@@ -891,6 +929,16 @@ void cdebbuf_free(_cdebbuf *cdb)
 }
 
 
+/**
+ * capi_message2str() - format CAPI 2.0 message for printing
+ * @msg:       CAPI 2.0 message
+ *
+ * Allocates a CAPI debug buffer and fills it with a printable representation
+ * of the CAPI 2.0 message in @msg.
+ * Return value: allocated debug buffer, NULL on error
+ * The returned buffer should be freed by a call to cdebbuf_free() after use.
+ */
+
 _cdebbuf *capi_message2str(u8 * msg)
 {
        _cdebbuf *cdb;
@@ -926,10 +974,23 @@ _cdebbuf *capi_message2str(u8 * msg)
        return cdb;
 }
 
+/**
+ * capi_cmsg2str() - format _cmsg structure for printing
+ * @cmsg:      _cmsg structure
+ *
+ * Allocates a CAPI debug buffer and fills it with a printable representation
+ * of the CAPI 2.0 message stored in @cmsg by a previous call to
+ * capi_cmsg2message() or capi_message2cmsg().
+ * Return value: allocated debug buffer, NULL on error
+ * The returned buffer should be freed by a call to cdebbuf_free() after use.
+ */
+
 _cdebbuf *capi_cmsg2str(_cmsg * cmsg)
 {
        _cdebbuf *cdb;
 
+       if (!cmsg->m)
+               return NULL;    /* no message */
        cdb = cdebbuf_alloc();
        if (!cdb)
                return NULL;
index f331703..57d2636 100644 (file)
@@ -377,14 +377,14 @@ void capi_ctr_ready(struct capi_ctr * card)
 EXPORT_SYMBOL(capi_ctr_ready);
 
 /**
- * capi_ctr_reseted() - signal CAPI controller reset
+ * capi_ctr_down() - signal CAPI controller not ready
  * @card:      controller descriptor structure.
  *
  * Called by hardware driver to signal that the controller is down and
  * unavailable for use.
  */
 
-void capi_ctr_reseted(struct capi_ctr * card)
+void capi_ctr_down(struct capi_ctr * card)
 {
        u16 appl;
 
@@ -413,7 +413,7 @@ void capi_ctr_reseted(struct capi_ctr * card)
        notify_push(KCI_CONTRDOWN, card->cnr, 0, 0);
 }
 
-EXPORT_SYMBOL(capi_ctr_reseted);
+EXPORT_SYMBOL(capi_ctr_down);
 
 /**
  * capi_ctr_suspend_output() - suspend controller
@@ -517,7 +517,7 @@ EXPORT_SYMBOL(attach_capi_ctr);
 int detach_capi_ctr(struct capi_ctr *card)
 {
         if (card->cardstate != CARD_DETECTED)
-               capi_ctr_reseted(card);
+               capi_ctr_down(card);
 
        ncards--;
 
index abf05ec..a7c0083 100644 (file)
@@ -330,7 +330,7 @@ void b1_reset_ctr(struct capi_ctr *ctrl)
        spin_lock_irqsave(&card->lock, flags);
        capilib_release(&cinfo->ncci_head);
        spin_unlock_irqrestore(&card->lock, flags);
-       capi_ctr_reseted(ctrl);
+       capi_ctr_down(ctrl);
 }
 
 void b1_register_appl(struct capi_ctr *ctrl,
index da34b98..0e84aaa 100644 (file)
@@ -759,7 +759,7 @@ void b1dma_reset_ctr(struct capi_ctr *ctrl)
        memset(cinfo->version, 0, sizeof(cinfo->version));
        capilib_release(&cinfo->ncci_head);
        spin_unlock_irqrestore(&card->lock, flags);
-       capi_ctr_reseted(ctrl);
+       capi_ctr_down(ctrl);
 }
 
 /* ------------------------------------------------------------- */
index 9df1d3f..6833301 100644 (file)
@@ -681,7 +681,7 @@ static irqreturn_t c4_handle_interrupt(avmcard *card)
                        spin_lock_irqsave(&card->lock, flags);
                        capilib_release(&cinfo->ncci_head);
                        spin_unlock_irqrestore(&card->lock, flags);
-                       capi_ctr_reseted(&cinfo->capi_ctrl);
+                       capi_ctr_down(&cinfo->capi_ctrl);
                }
                card->nlogcontr = 0;
                return IRQ_HANDLED;
@@ -909,7 +909,7 @@ static void c4_reset_ctr(struct capi_ctr *ctrl)
         for (i=0; i < card->nr_controllers; i++) {
                cinfo = &card->ctrlinfo[i];
                memset(cinfo->version, 0, sizeof(cinfo->version));
-               capi_ctr_reseted(&cinfo->capi_ctrl);
+               capi_ctr_down(&cinfo->capi_ctrl);
        }
        card->nlogcontr = 0;
 }
index e772449..1c53fd4 100644 (file)
@@ -339,7 +339,7 @@ static void t1isa_reset_ctr(struct capi_ctr *ctrl)
        spin_lock_irqsave(&card->lock, flags);
        capilib_release(&cinfo->ncci_head);
        spin_unlock_irqrestore(&card->lock, flags);
-       capi_ctr_reseted(ctrl);
+       capi_ctr_down(ctrl);
 }
 
 static void t1isa_remove(struct pci_dev *pdev)
index 53f6ad1..4ffaa14 100644 (file)
@@ -67,7 +67,7 @@ hycapi_reset_ctr(struct capi_ctr *ctrl)
        printk(KERN_NOTICE "HYCAPI hycapi_reset_ctr\n");
 #endif
        capilib_release(&cinfo->ncci_head);
-       capi_ctr_reseted(ctrl);
+       capi_ctr_down(ctrl);
 }
 
 /******************************
@@ -347,7 +347,7 @@ int hycapi_capi_stop(hysdn_card *card)
        if(cinfo) {
                ctrl = &cinfo->capi_ctrl;
 /*             ctrl->suspend_output(ctrl); */
-               capi_ctr_reseted(ctrl);
+               capi_ctr_down(ctrl);
        }
        return 0;
 }
index 8d9aa49..d2137ef 100644 (file)
@@ -480,9 +480,13 @@ static int pnp_registered;
 
 #ifdef CONFIG_EISA
 static struct eisa_device_id el3_eisa_ids[] = {
+               { "TCM5090" },
+               { "TCM5091" },
                { "TCM5092" },
                { "TCM5093" },
+               { "TCM5094" },
                { "TCM5095" },
+               { "TCM5098" },
                { "" }
 };
 MODULE_DEVICE_TABLE(eisa, el3_eisa_ids);
index 43a5254..3f739cf 100644 (file)
@@ -1001,7 +1001,7 @@ config SMC911X
 
 config SMSC911X
        tristate "SMSC LAN911x/LAN921x families embedded ethernet support"
-       depends on ARM || SUPERH
+       depends on ARM || SUPERH || BLACKFIN
        select CRC32
        select MII
        select PHYLIB
@@ -1723,6 +1723,11 @@ config TLAN
 
          Please email feedback to <torben.mathiasen@compaq.com>.
 
+config KS8842
+       tristate "Micrel KSZ8842"
+       help
+         This platform driver is for Micrel KSZ8842 chip.
+
 config VIA_RHINE
        tristate "VIA Rhine support"
        depends on NET_PCI && PCI
@@ -1859,8 +1864,8 @@ config 68360_ENET
          the Motorola 68360 processor.
 
 config FEC
-       bool "FEC ethernet controller (of ColdFire CPUs)"
-       depends on M523x || M527x || M5272 || M528x || M520x || M532x || MACH_MX27
+       bool "FEC ethernet controller (of ColdFire and some i.MX CPUs)"
+       depends on M523x || M527x || M5272 || M528x || M520x || M532x || MACH_MX27 || ARCH_MX35
        help
          Say Y here if you want to use the built-in 10/100 Fast ethernet
          controller on some Motorola ColdFire and Freescale i.MX processors.
@@ -2720,6 +2725,8 @@ source "drivers/net/wan/Kconfig"
 
 source "drivers/atm/Kconfig"
 
+source "drivers/ieee802154/Kconfig"
+
 source "drivers/s390/net/Kconfig"
 
 config XEN_NETDEV_FRONTEND
index f07a1e9..1c378dd 100644 (file)
@@ -86,6 +86,7 @@ obj-$(CONFIG_TC35815) += tc35815.o
 obj-$(CONFIG_SKGE) += skge.o
 obj-$(CONFIG_SKY2) += sky2.o
 obj-$(CONFIG_SKFP) += skfp/
+obj-$(CONFIG_KS8842)   += ks8842.o
 obj-$(CONFIG_VIA_RHINE) += via-rhine.o
 obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o
 obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
@@ -105,7 +106,7 @@ obj-$(CONFIG_HAMACHI) += hamachi.o
 obj-$(CONFIG_NET) += Space.o loopback.o
 obj-$(CONFIG_SEEQ8005) += seeq8005.o
 obj-$(CONFIG_NET_SB1000) += sb1000.o
-obj-$(CONFIG_MAC8390) += mac8390.o 8390.o
+obj-$(CONFIG_MAC8390) += mac8390.o
 obj-$(CONFIG_APNE) += apne.o 8390.o
 obj-$(CONFIG_PCMCIA_PCNET) += 8390.o
 obj-$(CONFIG_HP100) += hp100.o
index 57bc715..08419ee 100644 (file)
@@ -2573,7 +2573,6 @@ restart:
                        netif_wake_queue(dev);
        }
 
-       dev->trans_start = jiffies;
        return NETDEV_TX_OK;
 
 overflow:
index f939e92..78cea5e 100644 (file)
@@ -39,6 +39,7 @@
 static const char version[] = KERN_INFO "ipddp.c:v0.01 8/28/97 Bradford W. Johnson <johns393@maroon.tc.umn.edu>\n";
 
 static struct ipddp_route *ipddp_route_list;
+static DEFINE_SPINLOCK(ipddp_route_lock);
 
 #ifdef CONFIG_IPDDP_ENCAP
 static int ipddp_mode = IPDDP_ENCAP;
@@ -50,7 +51,7 @@ static int ipddp_mode = IPDDP_DECAP;
 static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev);
 static int ipddp_create(struct ipddp_route *new_rt);
 static int ipddp_delete(struct ipddp_route *rt);
-static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt);
+static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt);
 static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
 
 static const struct net_device_ops ipddp_netdev_ops = {
@@ -114,11 +115,13 @@ static struct net_device * __init ipddp_init(void)
  */
 static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-       __be32 paddr = ((struct rtable*)skb->dst)->rt_gateway;
+       __be32 paddr = skb_rtable(skb)->rt_gateway;
         struct ddpehdr *ddp;
         struct ipddp_route *rt;
         struct atalk_addr *our_addr;
 
+       spin_lock(&ipddp_route_lock);
+
        /*
          * Find appropriate route to use, based only on IP number.
          */
@@ -127,8 +130,10 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
                 if(rt->ip == paddr)
                         break;
         }
-        if(rt == NULL)
+        if(rt == NULL) {
+               spin_unlock(&ipddp_route_lock);
                 return 0;
+       }
 
         our_addr = atalk_find_dev_addr(rt->dev);
 
@@ -174,6 +179,8 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
         if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0)
                 dev_kfree_skb(skb);
 
+       spin_unlock(&ipddp_route_lock);
+
         return 0;
 }
 
@@ -196,7 +203,9 @@ static int ipddp_create(struct ipddp_route *new_rt)
                 return -ENETUNREACH;
         }
 
-       if (ipddp_find_route(rt)) {
+       spin_lock_bh(&ipddp_route_lock);
+       if (__ipddp_find_route(rt)) {
+               spin_unlock_bh(&ipddp_route_lock);
                kfree(rt);
                return -EEXIST;
        }
@@ -204,6 +213,8 @@ static int ipddp_create(struct ipddp_route *new_rt)
         rt->next = ipddp_route_list;
         ipddp_route_list = rt;
 
+       spin_unlock_bh(&ipddp_route_lock);
+
         return 0;
 }
 
@@ -216,6 +227,7 @@ static int ipddp_delete(struct ipddp_route *rt)
         struct ipddp_route **r = &ipddp_route_list;
         struct ipddp_route *tmp;
 
+       spin_lock_bh(&ipddp_route_lock);
         while((tmp = *r) != NULL)
         {
                 if(tmp->ip == rt->ip
@@ -223,19 +235,21 @@ static int ipddp_delete(struct ipddp_route *rt)
                         && tmp->at.s_node == rt->at.s_node)
                 {
                         *r = tmp->next;
+                       spin_unlock_bh(&ipddp_route_lock);
                         kfree(tmp);
                         return 0;
                 }
                 r = &tmp->next;
         }
 
+       spin_unlock_bh(&ipddp_route_lock);
         return (-ENOENT);
 }
 
 /*
  * Find a routing entry, we only return a FULL match
  */
-static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt)
+static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt)
 {
         struct ipddp_route *f;
 
@@ -253,7 +267,7 @@ static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt)
 static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
         struct ipddp_route __user *rt = ifr->ifr_data;
-        struct ipddp_route rcp;
+        struct ipddp_route rcp, rcp2, *rp;
 
         if(!capable(CAP_NET_ADMIN))
                 return -EPERM;
@@ -267,9 +281,19 @@ static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                         return (ipddp_create(&rcp));
 
                 case SIOCFINDIPDDPRT:
-                        if(copy_to_user(rt, ipddp_find_route(&rcp), sizeof(struct ipddp_route)))
-                                return -EFAULT;
-                        return 0;
+                       spin_lock_bh(&ipddp_route_lock);
+                       rp = __ipddp_find_route(&rcp);
+                       if (rp)
+                               memcpy(&rcp2, rp, sizeof(rcp2));
+                       spin_unlock_bh(&ipddp_route_lock);
+
+                       if (rp) {
+                               if (copy_to_user(rt, &rcp2,
+                                                sizeof(struct ipddp_route)))
+                                       return -EFAULT;
+                               return 0;
+                       } else
+                               return -ENOENT;
 
                 case SIOCDELIPDDPRT:
                         return (ipddp_delete(&rcp));
index b72b3d6..fbf4645 100644 (file)
@@ -253,7 +253,7 @@ static int ep93xx_rx(struct net_device *dev, int processed, int budget)
                skb = dev_alloc_skb(length + 2);
                if (likely(skb != NULL)) {
                        skb_reserve(skb, 2);
-                       dma_sync_single(NULL, ep->descs->rdesc[entry].buf_addr,
+                       dma_sync_single_for_cpu(NULL, ep->descs->rdesc[entry].buf_addr,
                                                length, DMA_FROM_DEVICE);
                        skb_copy_to_linear_data(skb, ep->rx_buf[entry], length);
                        skb_put(skb, length);
@@ -331,7 +331,7 @@ static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev)
        ep->descs->tdesc[entry].tdesc1 =
                TDESC1_EOF | (entry << 16) | (skb->len & 0xfff);
        skb_copy_and_csum_dev(skb, ep->tx_buf[entry]);
-       dma_sync_single(NULL, ep->descs->tdesc[entry].buf_addr,
+       dma_sync_single_for_cpu(NULL, ep->descs->tdesc[entry].buf_addr,
                                skb->len, DMA_TO_DEVICE);
        dev_kfree_skb(skb);
 
index 322c49b..1fcf838 100644 (file)
@@ -561,8 +561,8 @@ static int eth_poll(struct napi_struct *napi, int budget)
                dma_unmap_single(&dev->dev, desc->data - NET_IP_ALIGN,
                                 RX_BUFF_SIZE, DMA_FROM_DEVICE);
 #else
-               dma_sync_single(&dev->dev, desc->data - NET_IP_ALIGN,
-                               RX_BUFF_SIZE, DMA_FROM_DEVICE);
+               dma_sync_single_for_cpu(&dev->dev, desc->data - NET_IP_ALIGN,
+                                       RX_BUFF_SIZE, DMA_FROM_DEVICE);
                memcpy_swab32((u32 *)skb->data, (u32 *)port->rx_buff_tab[n],
                              ALIGN(NET_IP_ALIGN + desc->pkt_len, 4) / 4);
 #endif
index 45c5b73..e4afbd6 100644 (file)
@@ -271,7 +271,7 @@ static int atl1c_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
        struct atl1c_adapter *adapter = netdev_priv(netdev);
 
        if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE |
-                           WAKE_MCAST | WAKE_BCAST | WAKE_MCAST))
+                           WAKE_UCAST | WAKE_BCAST | WAKE_MCAST))
                return -EOPNOTSUPP;
        /* these settings will always override what we currently have */
        adapter->wol = 0;
index fc1092b..cd547a2 100644 (file)
@@ -164,6 +164,24 @@ static inline void atl1c_irq_reset(struct atl1c_adapter *adapter)
 }
 
 /*
+ * atl1c_wait_until_idle - wait up to AT_HW_MAX_IDLE_DELAY reads
+ * of the idle status register until the device is actually idle
+ */
+static u32 atl1c_wait_until_idle(struct atl1c_hw *hw)
+{
+       int timeout;
+       u32 data;
+
+       for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) {
+               AT_READ_REG(hw, REG_IDLE_STATUS, &data);
+               if ((data & IDLE_STATUS_MASK) == 0)
+                       return 0;
+               msleep(1);
+       }
+       return data;
+}
+
+/*
  * atl1c_phy_config - Timer Call-back
  * @data: pointer to netdev cast into an unsigned long
  */
@@ -1106,7 +1124,6 @@ static void atl1c_configure_dma(struct atl1c_adapter *adapter)
 static int atl1c_stop_mac(struct atl1c_hw *hw)
 {
        u32 data;
-       int timeout;
 
        AT_READ_REG(hw, REG_RXQ_CTRL, &data);
        data &= ~(RXQ1_CTRL_EN | RXQ2_CTRL_EN |
@@ -1117,25 +1134,13 @@ static int atl1c_stop_mac(struct atl1c_hw *hw)
        data &= ~TXQ_CTRL_EN;
        AT_WRITE_REG(hw, REG_TWSI_CTRL, data);
 
-       for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) {
-               AT_READ_REG(hw, REG_IDLE_STATUS, &data);
-               if ((data & (IDLE_STATUS_RXQ_NO_IDLE |
-                       IDLE_STATUS_TXQ_NO_IDLE)) == 0)
-                       break;
-               msleep(1);
-       }
+       atl1c_wait_until_idle(hw);
 
        AT_READ_REG(hw, REG_MAC_CTRL, &data);
        data &= ~(MAC_CTRL_TX_EN | MAC_CTRL_RX_EN);
        AT_WRITE_REG(hw, REG_MAC_CTRL, data);
 
-       for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) {
-               AT_READ_REG(hw, REG_IDLE_STATUS, &data);
-               if ((data & IDLE_STATUS_MASK) == 0)
-                       return 0;
-               msleep(1);
-       }
-       return data;
+       return (int)atl1c_wait_until_idle(hw);
 }
 
 static void atl1c_enable_rx_ctrl(struct atl1c_hw *hw)
@@ -1178,8 +1183,6 @@ static int atl1c_reset_mac(struct atl1c_hw *hw)
 {
        struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter;
        struct pci_dev *pdev = adapter->pdev;
-       u32 idle_status_data = 0;
-       int timeout = 0;
        int ret;
 
        AT_WRITE_REG(hw, REG_IMR, 0);
@@ -1198,15 +1201,10 @@ static int atl1c_reset_mac(struct atl1c_hw *hw)
        AT_WRITE_FLUSH(hw);
        msleep(10);
        /* Wait at least 10ms for All module to be Idle */
-       for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) {
-               AT_READ_REG(hw, REG_IDLE_STATUS, &idle_status_data);
-               if ((idle_status_data & IDLE_STATUS_MASK) == 0)
-                       break;
-               msleep(1);
-       }
-       if (timeout >= AT_HW_MAX_IDLE_DELAY) {
+
+       if (atl1c_wait_until_idle(hw)) {
                dev_err(&pdev->dev,
-                       "MAC state machine cann't be idle since"
+                       "MAC state machine can't be idle since"
                        " disabled for 10ms second\n");
                return -1;
        }
@@ -2113,7 +2111,6 @@ static int atl1c_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        atl1c_tx_map(adapter, skb, tpd, type);
        atl1c_tx_queue(adapter, skb, tpd, type);
 
-       netdev->trans_start = jiffies;
        spin_unlock_irqrestore(&adapter->tx_lock, flags);
        return NETDEV_TX_OK;
 }
index c271b75..e1ae10c 100644 (file)
@@ -37,6 +37,7 @@ char atl1e_driver_version[] = DRV_VERSION;
  */
 static struct pci_device_id atl1e_pci_tbl[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1E)},
+       {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, 0x1066)},
        /* required last entry */
        { 0 }
 };
@@ -1893,7 +1894,7 @@ static int atl1e_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        atl1e_tx_map(adapter, skb, tpd);
        atl1e_tx_queue(adapter, tpd_req, tpd);
 
-       netdev->trans_start = jiffies;
+       netdev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */
        spin_unlock_irqrestore(&adapter->tx_lock, flags);
        return NETDEV_TX_OK;
 }
index 13f0bdc..560f387 100644 (file)
 
 #include "atl1.h"
 
+#define ATLX_DRIVER_VERSION "2.1.3"
+MODULE_AUTHOR("Xiong Huang <xiong.huang@atheros.com>, \
+       Chris Snook <csnook@redhat.com>, Jay Cliburn <jcliburn@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(ATLX_DRIVER_VERSION);
+
 /* Temporary hack for merging atl1 and atl2 */
 #include "atlx.c"
 
@@ -2431,7 +2437,6 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        atl1_tx_queue(adapter, count, ptpd);
        atl1_update_mailbox(adapter);
        mmiowb();
-       netdev->trans_start = jiffies;
        return NETDEV_TX_OK;
 }
 
index 297a03d..14054b7 100644 (file)
 #include <linux/module.h>
 #include <linux/types.h>
 
-#define ATLX_DRIVER_VERSION "2.1.3"
-MODULE_AUTHOR("Xiong Huang <xiong.huang@atheros.com>, \
-       Chris Snook <csnook@redhat.com>, Jay Cliburn <jcliburn@gmail.com>");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(ATLX_DRIVER_VERSION);
-
 #define ATLX_ERR_PHY                   2
 #define ATLX_ERR_PHY_SPEED             7
 #define ATLX_ERR_PHY_RES               8
index b70b81e..36d4d37 100644 (file)
@@ -782,7 +782,7 @@ static int b44_rx(struct b44 *bp, int budget)
                drop_it:
                        b44_recycle_rx(bp, cons, bp->rx_prod);
                drop_it_no_recycle:
-                       bp->stats.rx_dropped++;
+                       bp->dev->stats.rx_dropped++;
                        goto next_pkt;
                }
 
@@ -1647,7 +1647,7 @@ static int b44_close(struct net_device *dev)
 static struct net_device_stats *b44_get_stats(struct net_device *dev)
 {
        struct b44 *bp = netdev_priv(dev);
-       struct net_device_stats *nstat = &bp->stats;
+       struct net_device_stats *nstat = &dev->stats;
        struct b44_hw_stats *hwstat = &bp->hw_stats;
 
        /* Convert HW stats into netdevice stats. */
index e678498..0443f68 100644 (file)
@@ -384,7 +384,6 @@ struct b44 {
 
        struct timer_list       timer;
 
-       struct net_device_stats stats;
        struct b44_hw_stats     hw_stats;
 
        struct ssb_device       *sdev;
index ae2f6b5..66bb568 100644 (file)
@@ -168,6 +168,7 @@ static void netdev_stats_update(struct be_adapter *adapter)
        struct be_port_rxf_stats *port_stats =
                        &rxf_stats->port[adapter->port_num];
        struct net_device_stats *dev_stats = &adapter->stats.net_stats;
+       struct be_erx_stats *erx_stats = &hw_stats->erx;
 
        dev_stats->rx_packets = port_stats->rx_total_frames;
        dev_stats->tx_packets = port_stats->tx_unicastframes +
@@ -181,29 +182,33 @@ static void netdev_stats_update(struct be_adapter *adapter)
        dev_stats->rx_errors = port_stats->rx_crc_errors +
                port_stats->rx_alignment_symbol_errors +
                port_stats->rx_in_range_errors +
-               port_stats->rx_out_range_errors + port_stats->rx_frame_too_long;
-
-       /*  packet transmit problems */
-       dev_stats->tx_errors = 0;
-
-       /*  no space in linux buffers */
-       dev_stats->rx_dropped = 0;
-
-       /* no space available in linux */
-       dev_stats->tx_dropped = 0;
-
-       dev_stats->multicast = port_stats->tx_multicastframes;
-       dev_stats->collisions = 0;
+               port_stats->rx_out_range_errors +
+               port_stats->rx_frame_too_long +
+               port_stats->rx_dropped_too_small +
+               port_stats->rx_dropped_too_short +
+               port_stats->rx_dropped_header_too_small +
+               port_stats->rx_dropped_tcp_length +
+               port_stats->rx_dropped_runt +
+               port_stats->rx_tcp_checksum_errs +
+               port_stats->rx_ip_checksum_errs +
+               port_stats->rx_udp_checksum_errs;
+
+       /*  no space in linux buffers: best possible approximation */
+       dev_stats->rx_dropped = erx_stats->rx_drops_no_fragments[0];
 
        /* detailed rx errors */
        dev_stats->rx_length_errors = port_stats->rx_in_range_errors +
-               port_stats->rx_out_range_errors + port_stats->rx_frame_too_long;
+               port_stats->rx_out_range_errors +
+               port_stats->rx_frame_too_long;
+
        /* receive ring buffer overflow */
        dev_stats->rx_over_errors = 0;
+
        dev_stats->rx_crc_errors = port_stats->rx_crc_errors;
 
        /* frame alignment errors */
        dev_stats->rx_frame_errors = port_stats->rx_alignment_symbol_errors;
+
        /* receiver fifo overrun */
        /* drops_no_pbuf is no per i/f, it's per BE card */
        dev_stats->rx_fifo_errors = port_stats->rx_fifo_overflow +
@@ -211,6 +216,16 @@ static void netdev_stats_update(struct be_adapter *adapter)
                                        rxf_stats->rx_drops_no_pbuf;
        /* receiver missed packetd */
        dev_stats->rx_missed_errors = 0;
+
+       /*  packet transmit problems */
+       dev_stats->tx_errors = 0;
+
+       /* no space available in linux */
+       dev_stats->tx_dropped = 0;
+
+       dev_stats->multicast = port_stats->tx_multicastframes;
+       dev_stats->collisions = 0;
+
        /* detailed tx_errors */
        dev_stats->tx_aborted_errors = 0;
        dev_stats->tx_carrier_errors = 0;
@@ -337,13 +352,10 @@ static void be_tx_stats_update(struct be_adapter *adapter,
 /* Determine number of WRB entries needed to xmit data in an skb */
 static u32 wrb_cnt_for_skb(struct sk_buff *skb, bool *dummy)
 {
-       int cnt = 0;
-       while (skb) {
-               if (skb->len > skb->data_len)
-                       cnt++;
-               cnt += skb_shinfo(skb)->nr_frags;
-               skb = skb_shinfo(skb)->frag_list;
-       }
+       int cnt = (skb->len > skb->data_len);
+
+       cnt += skb_shinfo(skb)->nr_frags;
+
        /* to account for hdr wrb */
        cnt++;
        if (cnt & 1) {
@@ -409,31 +421,28 @@ static int make_tx_wrbs(struct be_adapter *adapter,
        hdr = queue_head_node(txq);
        queue_head_inc(txq);
 
-       while (skb) {
-               if (skb->len > skb->data_len) {
-                       int len = skb->len - skb->data_len;
-                       busaddr = pci_map_single(pdev, skb->data, len,
-                                       PCI_DMA_TODEVICE);
-                       wrb = queue_head_node(txq);
-                       wrb_fill(wrb, busaddr, len);
-                       be_dws_cpu_to_le(wrb, sizeof(*wrb));
-                       queue_head_inc(txq);
-                       copied += len;
-               }
+       if (skb->len > skb->data_len) {
+               int len = skb->len - skb->data_len;
+               busaddr = pci_map_single(pdev, skb->data, len,
+                                        PCI_DMA_TODEVICE);
+               wrb = queue_head_node(txq);
+               wrb_fill(wrb, busaddr, len);
+               be_dws_cpu_to_le(wrb, sizeof(*wrb));
+               queue_head_inc(txq);
+               copied += len;
+       }
 
-               for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-                       struct skb_frag_struct *frag =
-                               &skb_shinfo(skb)->frags[i];
-                       busaddr = pci_map_page(pdev, frag->page,
-                                       frag->page_offset,
-                                       frag->size, PCI_DMA_TODEVICE);
-                       wrb = queue_head_node(txq);
-                       wrb_fill(wrb, busaddr, frag->size);
-                       be_dws_cpu_to_le(wrb, sizeof(*wrb));
-                       queue_head_inc(txq);
-                       copied += frag->size;
-               }
-               skb = skb_shinfo(skb)->frag_list;
+       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+               struct skb_frag_struct *frag =
+                       &skb_shinfo(skb)->frags[i];
+               busaddr = pci_map_page(pdev, frag->page,
+                                      frag->page_offset,
+                                      frag->size, PCI_DMA_TODEVICE);
+               wrb = queue_head_node(txq);
+               wrb_fill(wrb, busaddr, frag->size);
+               be_dws_cpu_to_le(wrb, sizeof(*wrb));
+               queue_head_inc(txq);
+               copied += frag->size;
        }
 
        if (dummy_wrb) {
@@ -478,8 +487,6 @@ static int be_xmit(struct sk_buff *skb, struct net_device *netdev)
 
        be_txq_notify(&adapter->ctrl, txq->id, wrb_cnt);
 
-       netdev->trans_start = jiffies;
-
        be_tx_stats_update(adapter, wrb_cnt, copied, stopped);
        return NETDEV_TX_OK;
 }
@@ -736,7 +743,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
 
        if (pktsize <= rx_frag_size) {
                BUG_ON(num_rcvd != 1);
-               return;
+               goto done;
        }
 
        /* More frags present for this completion */
@@ -758,6 +765,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
                memset(page_info, 0, sizeof(*page_info));
        }
 
+done:
        be_rx_stats_update(adapter, pktsize, num_rcvd);
        return;
 }
@@ -868,12 +876,19 @@ static struct be_eth_rx_compl *be_rx_compl_get(struct be_adapter *adapter)
 
        be_dws_le_to_cpu(rxcp, sizeof(*rxcp));
 
-       rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] = 0;
-
        queue_tail_inc(&adapter->rx_obj.cq);
        return rxcp;
 }
 
+/* To reset the valid bit, we need to reset the whole word as
+ * when walking the queue the valid entries are little-endian
+ * and invalid entries are host endian
+ */
+static inline void be_rx_compl_reset(struct be_eth_rx_compl *rxcp)
+{
+       rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] = 0;
+}
+
 static inline struct page *be_alloc_pages(u32 size)
 {
        gfp_t alloc_flags = GFP_ATOMIC;
@@ -1005,6 +1020,7 @@ static void be_rx_q_clean(struct be_adapter *adapter)
        /* First cleanup pending rx completions */
        while ((rxcp = be_rx_compl_get(adapter)) != NULL) {
                be_rx_compl_discard(adapter, rxcp);
+               be_rx_compl_reset(rxcp);
                be_cq_notify(&adapter->ctrl, rx_cq->id, true, 1);
        }
 
@@ -1040,8 +1056,13 @@ static void be_tx_queues_destroy(struct be_adapter *adapter)
        struct be_queue_info *q;
 
        q = &adapter->tx_obj.q;
-       if (q->created)
+       if (q->created) {
                be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_TXQ);
+
+               /* No more tx completions can be rcvd now; clean up if there
+                * are any pending completions or pending tx requests */
+               be_tx_q_clean(adapter);
+       }
        be_queue_free(adapter, q);
 
        q = &adapter->tx_obj.cq;
@@ -1049,10 +1070,6 @@ static void be_tx_queues_destroy(struct be_adapter *adapter)
                be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_CQ);
        be_queue_free(adapter, q);
 
-       /* No more tx completions can be rcvd now; clean up if there are
-        * any pending completions or pending tx requests */
-       be_tx_q_clean(adapter);
-
        q = &adapter->tx_eq.q;
        if (q->created)
                be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_EQ);
@@ -1286,6 +1303,8 @@ int be_poll_rx(struct napi_struct *napi, int budget)
                        be_rx_compl_process_lro(adapter, rxcp);
                else
                        be_rx_compl_process(adapter, rxcp);
+
+               be_rx_compl_reset(rxcp);
        }
 
        lro_flush_all(&adapter->rx_obj.lro_mgr);
@@ -1541,7 +1560,7 @@ static int be_close(struct net_device *netdev)
        struct be_eq_obj *tx_eq = &adapter->tx_eq;
        int vec;
 
-       cancel_delayed_work(&adapter->work);
+       cancel_delayed_work_sync(&adapter->work);
 
        netif_stop_queue(netdev);
        netif_carrier_off(netdev);
index 9f971ed..c15fc28 100644 (file)
@@ -194,13 +194,13 @@ static int desc_list_init(void)
                struct dma_descriptor *b = &(r->desc_b);
 
                /* allocate a new skb for next time receive */
-               new_skb = dev_alloc_skb(PKT_BUF_SZ + 2);
+               new_skb = dev_alloc_skb(PKT_BUF_SZ + NET_IP_ALIGN);
                if (!new_skb) {
                        printk(KERN_NOTICE DRV_NAME
                               ": init: low on mem - packet dropped\n");
                        goto init_error;
                }
-               skb_reserve(new_skb, 2);
+               skb_reserve(new_skb, NET_IP_ALIGN);
                r->skb = new_skb;
 
                /*
@@ -566,9 +566,9 @@ static void adjust_tx_list(void)
         */
        if (current_tx_ptr->next->next == tx_list_head) {
                while (tx_list_head->status.status_word == 0) {
-                       mdelay(1);
+                       udelay(10);
                        if (tx_list_head->status.status_word != 0
-                           || !(bfin_read_DMA2_IRQ_STATUS() & 0x08)) {
+                           || !(bfin_read_DMA2_IRQ_STATUS() & DMA_RUN)) {
                                goto adjust_head;
                        }
                        if (timeout_cnt-- < 0) {
@@ -606,93 +606,41 @@ static int bfin_mac_hard_start_xmit(struct sk_buff *skb,
                                struct net_device *dev)
 {
        u16 *data;
-
+       u32 data_align = (unsigned long)(skb->data) & 0x3;
        current_tx_ptr->skb = skb;
 
-       if (ANOMALY_05000285) {
-               /*
-                * TXDWA feature is not avaible to older revision < 0.3 silicon
-                * of BF537
-                *
-                * Only if data buffer is ODD WORD alignment, we do not
-                * need to memcpy
-                */
-               u32 data_align = (u32)(skb->data) & 0x3;
-               if (data_align == 0x2) {
-                       /* move skb->data to current_tx_ptr payload */
-                       data = (u16 *)(skb->data) - 1;
-                       *data = (u16)(skb->len);
-                       current_tx_ptr->desc_a.start_addr = (u32)data;
-                       /* this is important! */
-                       blackfin_dcache_flush_range((u32)data,
-                                       (u32)((u8 *)data + skb->len + 4));
-               } else {
-                       *((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len);
-                       memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data,
-                               skb->len);
-                       current_tx_ptr->desc_a.start_addr =
-                               (u32)current_tx_ptr->packet;
-                       if (current_tx_ptr->status.status_word != 0)
-                               current_tx_ptr->status.status_word = 0;
-                       blackfin_dcache_flush_range(
-                               (u32)current_tx_ptr->packet,
-                               (u32)(current_tx_ptr->packet + skb->len + 2));
-               }
+       if (data_align == 0x2) {
+               /* move skb->data to current_tx_ptr payload */
+               data = (u16 *)(skb->data) - 1;
+                               *data = (u16)(skb->len);
+               current_tx_ptr->desc_a.start_addr = (u32)data;
+               /* this is important! */
+               blackfin_dcache_flush_range((u32)data,
+                               (u32)((u8 *)data + skb->len + 4));
        } else {
-               /*
-                * TXDWA feature is avaible to revision < 0.3 silicon of
-                * BF537 and always avaible to BF52x
-                */
-               u32 data_align = (u32)(skb->data) & 0x3;
-               if (data_align == 0x0) {
-                       u16 sysctl = bfin_read_EMAC_SYSCTL();
-                       sysctl |= TXDWA;
-                       bfin_write_EMAC_SYSCTL(sysctl);
-
-                       /* move skb->data to current_tx_ptr payload */
-                       data = (u16 *)(skb->data) - 2;
-                       *data = (u16)(skb->len);
-                       current_tx_ptr->desc_a.start_addr = (u32)data;
-                       /* this is important! */
-                       blackfin_dcache_flush_range(
-                                       (u32)data,
-                                       (u32)((u8 *)data + skb->len + 4));
-               } else if (data_align == 0x2) {
-                       u16 sysctl = bfin_read_EMAC_SYSCTL();
-                       sysctl &= ~TXDWA;
-                       bfin_write_EMAC_SYSCTL(sysctl);
-
-                       /* move skb->data to current_tx_ptr payload */
-                       data = (u16 *)(skb->data) - 1;
-                       *data = (u16)(skb->len);
-                       current_tx_ptr->desc_a.start_addr = (u32)data;
-                       /* this is important! */
-                       blackfin_dcache_flush_range(
-                                       (u32)data,
-                                       (u32)((u8 *)data + skb->len + 4));
-               } else {
-                       u16 sysctl = bfin_read_EMAC_SYSCTL();
-                       sysctl &= ~TXDWA;
-                       bfin_write_EMAC_SYSCTL(sysctl);
-
-                       *((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len);
-                       memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data,
-                               skb->len);
-                       current_tx_ptr->desc_a.start_addr =
-                               (u32)current_tx_ptr->packet;
-                       if (current_tx_ptr->status.status_word != 0)
-                               current_tx_ptr->status.status_word = 0;
-                       blackfin_dcache_flush_range(
-                               (u32)current_tx_ptr->packet,
-                               (u32)(current_tx_ptr->packet + skb->len + 2));
-               }
+               *((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len);
+               memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data,
+                       skb->len);
+               current_tx_ptr->desc_a.start_addr =
+                       (u32)current_tx_ptr->packet;
+               if (current_tx_ptr->status.status_word != 0)
+                       current_tx_ptr->status.status_word = 0;
+               blackfin_dcache_flush_range(
+                       (u32)current_tx_ptr->packet,
+                       (u32)(current_tx_ptr->packet + skb->len + 2));
        }
 
+       /* make sure the internal data buffers in the core are drained
+        * so that the DMA descriptors are completely written when the
+        * DMA engine goes to fetch them below
+        */
+       SSYNC();
+
        /* enable this packet's dma */
        current_tx_ptr->desc_a.config |= DMAEN;
 
        /* tx dma is running, just return */
-       if (bfin_read_DMA2_IRQ_STATUS() & 0x08)
+       if (bfin_read_DMA2_IRQ_STATUS() & DMA_RUN)
                goto out;
 
        /* tx dma is not running */
@@ -718,7 +666,7 @@ static void bfin_mac_rx(struct net_device *dev)
 
        /* allocate a new skb for next time receive */
        skb = current_rx_ptr->skb;
-       new_skb = dev_alloc_skb(PKT_BUF_SZ + 2);
+       new_skb = dev_alloc_skb(PKT_BUF_SZ + NET_IP_ALIGN);
        if (!new_skb) {
                printk(KERN_NOTICE DRV_NAME
                       ": rx: low on mem - packet dropped\n");
@@ -726,7 +674,7 @@ static void bfin_mac_rx(struct net_device *dev)
                goto out;
        }
        /* reserve 2 bytes for RXDWA padding */
-       skb_reserve(new_skb, 2);
+       skb_reserve(new_skb, NET_IP_ALIGN);
        current_rx_ptr->skb = new_skb;
        current_rx_ptr->desc_a.start_addr = (unsigned long)new_skb->data - 2;
 
@@ -979,22 +927,7 @@ static int bfin_mac_open(struct net_device *dev)
        return 0;
 }
 
-static const struct net_device_ops bfin_mac_netdev_ops = {
-       .ndo_open               = bfin_mac_open,
-       .ndo_stop               = bfin_mac_close,
-       .ndo_start_xmit         = bfin_mac_hard_start_xmit,
-       .ndo_set_mac_address    = bfin_mac_set_mac_address,
-       .ndo_tx_timeout         = bfin_mac_timeout,
-       .ndo_set_multicast_list = bfin_mac_set_multicast_list,
-       .ndo_validate_addr      = eth_validate_addr,
-       .ndo_change_mtu         = eth_change_mtu,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       .ndo_poll_controller    = bfin_mac_poll,
-#endif
-};
-
 /*
- *
  * this makes the board clean up everything that it can
  * and not talk to the outside world.   Caused by
  * an 'ifconfig ethX down'
@@ -1019,11 +952,26 @@ static int bfin_mac_close(struct net_device *dev)
        return 0;
 }
 
+static const struct net_device_ops bfin_mac_netdev_ops = {
+       .ndo_open               = bfin_mac_open,
+       .ndo_stop               = bfin_mac_close,
+       .ndo_start_xmit         = bfin_mac_hard_start_xmit,
+       .ndo_set_mac_address    = bfin_mac_set_mac_address,
+       .ndo_tx_timeout         = bfin_mac_timeout,
+       .ndo_set_multicast_list = bfin_mac_set_multicast_list,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_change_mtu         = eth_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = bfin_mac_poll,
+#endif
+};
+
 static int __devinit bfin_mac_probe(struct platform_device *pdev)
 {
        struct net_device *ndev;
        struct bfin_mac_local *lp;
-       int rc, i;
+       struct platform_device *pd;
+       int rc;
 
        ndev = alloc_etherdev(sizeof(struct bfin_mac_local));
        if (!ndev) {
@@ -1048,13 +996,6 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev)
                goto out_err_probe_mac;
        }
 
-       /* set the GPIO pins to Ethernet mode */
-       rc = peripheral_request_list(pin_req, DRV_NAME);
-       if (rc) {
-               dev_err(&pdev->dev, "Requesting peripherals failed!\n");
-               rc = -EFAULT;
-               goto out_err_setup_pin_mux;
-       }
 
        /*
         * Is it valid? (Did bootloader initialize it?)
@@ -1070,26 +1011,14 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev)
 
        setup_mac_addr(ndev->dev_addr);
 
-       /* MDIO bus initial */
-       lp->mii_bus = mdiobus_alloc();
-       if (lp->mii_bus == NULL)
-               goto out_err_mdiobus_alloc;
-
-       lp->mii_bus->priv = ndev;
-       lp->mii_bus->read = bfin_mdiobus_read;
-       lp->mii_bus->write = bfin_mdiobus_write;
-       lp->mii_bus->reset = bfin_mdiobus_reset;
-       lp->mii_bus->name = "bfin_mac_mdio";
-       snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "0");
-       lp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
-       for (i = 0; i < PHY_MAX_ADDR; ++i)
-               lp->mii_bus->irq[i] = PHY_POLL;
-
-       rc = mdiobus_register(lp->mii_bus);
-       if (rc) {
-               dev_err(&pdev->dev, "Cannot register MDIO bus!\n");
-               goto out_err_mdiobus_register;
+       if (!pdev->dev.platform_data) {
+               dev_err(&pdev->dev, "Cannot get platform device bfin_mii_bus!\n");
+               rc = -ENODEV;
+               goto out_err_probe_mac;
        }
+       pd = pdev->dev.platform_data;
+       lp->mii_bus = platform_get_drvdata(pd);
+       lp->mii_bus->priv = ndev;
 
        rc = mii_probe(ndev);
        if (rc) {
@@ -1108,7 +1037,7 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev)
        /* now, enable interrupts */
        /* register irq handler */
        rc = request_irq(IRQ_MAC_RX, bfin_mac_interrupt,
-                       IRQF_DISABLED | IRQF_SHARED, "EMAC_RX", ndev);
+                       IRQF_DISABLED, "EMAC_RX", ndev);
        if (rc) {
                dev_err(&pdev->dev, "Cannot request Blackfin MAC RX IRQ!\n");
                rc = -EBUSY;
@@ -1131,11 +1060,8 @@ out_err_reg_ndev:
 out_err_request_irq:
 out_err_mii_probe:
        mdiobus_unregister(lp->mii_bus);
-out_err_mdiobus_register:
        mdiobus_free(lp->mii_bus);
-out_err_mdiobus_alloc:
        peripheral_free_list(pin_req);
-out_err_setup_pin_mux:
 out_err_probe_mac:
        platform_set_drvdata(pdev, NULL);
        free_netdev(ndev);
@@ -1150,8 +1076,7 @@ static int __devexit bfin_mac_remove(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, NULL);
 
-       mdiobus_unregister(lp->mii_bus);
-       mdiobus_free(lp->mii_bus);
+       lp->mii_bus->priv = NULL;
 
        unregister_netdev(ndev);
 
@@ -1189,6 +1114,74 @@ static int bfin_mac_resume(struct platform_device *pdev)
 #define bfin_mac_resume NULL
 #endif /* CONFIG_PM */
 
+static int __devinit bfin_mii_bus_probe(struct platform_device *pdev)
+{
+       struct mii_bus *miibus;
+       int rc, i;
+
+       /*
+        * We are setting up a network card,
+        * so set the GPIO pins to Ethernet mode
+        */
+       rc = peripheral_request_list(pin_req, DRV_NAME);
+       if (rc) {
+               dev_err(&pdev->dev, "Requesting peripherals failed!\n");
+               return rc;
+       }
+
+       rc = -ENOMEM;
+       miibus = mdiobus_alloc();
+       if (miibus == NULL)
+               goto out_err_alloc;
+       miibus->read = bfin_mdiobus_read;
+       miibus->write = bfin_mdiobus_write;
+       miibus->reset = bfin_mdiobus_reset;
+
+       miibus->parent = &pdev->dev;
+       miibus->name = "bfin_mii_bus";
+       snprintf(miibus->id, MII_BUS_ID_SIZE, "0");
+       miibus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+       if (miibus->irq == NULL)
+               goto out_err_alloc;
+       for (i = 0; i < PHY_MAX_ADDR; ++i)
+               miibus->irq[i] = PHY_POLL;
+
+       rc = mdiobus_register(miibus);
+       if (rc) {
+               dev_err(&pdev->dev, "Cannot register MDIO bus!\n");
+               goto out_err_mdiobus_register;
+       }
+
+       platform_set_drvdata(pdev, miibus);
+       return 0;
+
+out_err_mdiobus_register:
+       mdiobus_free(miibus);
+out_err_alloc:
+       peripheral_free_list(pin_req);
+
+       return rc;
+}
+
+static int __devexit bfin_mii_bus_remove(struct platform_device *pdev)
+{
+       struct mii_bus *miibus = platform_get_drvdata(pdev);
+       platform_set_drvdata(pdev, NULL);
+       mdiobus_unregister(miibus);
+       mdiobus_free(miibus);
+       peripheral_free_list(pin_req);
+       return 0;
+}
+
+static struct platform_driver bfin_mii_bus_driver = {
+       .probe = bfin_mii_bus_probe,
+       .remove = __devexit_p(bfin_mii_bus_remove),
+       .driver = {
+               .name = "bfin_mii_bus",
+               .owner  = THIS_MODULE,
+       },
+};
+
 static struct platform_driver bfin_mac_driver = {
        .probe = bfin_mac_probe,
        .remove = __devexit_p(bfin_mac_remove),
@@ -1202,7 +1195,11 @@ static struct platform_driver bfin_mac_driver = {
 
 static int __init bfin_mac_init(void)
 {
-       return platform_driver_register(&bfin_mac_driver);
+       int ret;
+       ret = platform_driver_register(&bfin_mii_bus_driver);
+       if (!ret)
+               return platform_driver_register(&bfin_mac_driver);
+       return -ENODEV;
 }
 
 module_init(bfin_mac_init);
@@ -1210,6 +1207,7 @@ module_init(bfin_mac_init);
 static void __exit bfin_mac_cleanup(void)
 {
        platform_driver_unregister(&bfin_mac_driver);
+       platform_driver_unregister(&bfin_mii_bus_driver);
 }
 
 module_exit(bfin_mac_cleanup);
index c37acc1..f99e17e 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/cache.h>
 #include <linux/firmware.h>
 #include <linux/log2.h>
+#include <linux/list.h>
 
 #include "bnx2.h"
 #include "bnx2_fw.h"
@@ -545,8 +546,7 @@ bnx2_free_rx_mem(struct bnx2 *bp)
                                                    rxr->rx_desc_mapping[j]);
                        rxr->rx_desc_ring[j] = NULL;
                }
-               if (rxr->rx_buf_ring)
-                       vfree(rxr->rx_buf_ring);
+               vfree(rxr->rx_buf_ring);
                rxr->rx_buf_ring = NULL;
 
                for (j = 0; j < bp->rx_max_pg_ring; j++) {
@@ -556,8 +556,7 @@ bnx2_free_rx_mem(struct bnx2 *bp)
                                                    rxr->rx_pg_desc_mapping[j]);
                        rxr->rx_pg_desc_ring[j] = NULL;
                }
-               if (rxr->rx_pg_ring)
-                       vfree(rxr->rx_pg_ring);
+               vfree(rxr->rx_pg_ring);
                rxr->rx_pg_ring = NULL;
        }
 }
@@ -3310,7 +3309,7 @@ bnx2_set_rx_mode(struct net_device *dev)
 {
        struct bnx2 *bp = netdev_priv(dev);
        u32 rx_mode, sort_mode;
-       struct dev_addr_list *uc_ptr;
+       struct netdev_hw_addr *ha;
        int i;
 
        if (!netif_running(dev))
@@ -3369,21 +3368,19 @@ bnx2_set_rx_mode(struct net_device *dev)
                sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN;
        }
 
-       uc_ptr = NULL;
        if (dev->uc_count > BNX2_MAX_UNICAST_ADDRESSES) {
                rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
                sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
                             BNX2_RPM_SORT_USER0_PROM_VLAN;
        } else if (!(dev->flags & IFF_PROMISC)) {
-               uc_ptr = dev->uc_list;
-
                /* Add all entries into to the match filter list */
-               for (i = 0; i < dev->uc_count; i++) {
-                       bnx2_set_mac_addr(bp, uc_ptr->da_addr,
+               i = 0;
+               list_for_each_entry(ha, &dev->uc_list, list) {
+                       bnx2_set_mac_addr(bp, ha->addr,
                                          i + BNX2_START_UNICAST_ADDRESS_INDEX);
                        sort_mode |= (1 <<
                                      (i + BNX2_START_UNICAST_ADDRESS_INDEX));
-                       uc_ptr = uc_ptr->next;
+                       i++;
                }
 
        }
@@ -5488,7 +5485,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
                dev_kfree_skb(skb);
                return -EIO;
        }
-       map = skb_shinfo(skb)->dma_maps[0];
+       map = skb_shinfo(skb)->dma_head;
 
        REG_WR(bp, BNX2_HC_COMMAND,
               bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
@@ -6168,7 +6165,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        sp = skb_shinfo(skb);
-       mapping = sp->dma_maps[0];
+       mapping = sp->dma_head;
 
        tx_buf = &txr->tx_buf_ring[ring_prod];
        tx_buf->skb = skb;
@@ -6192,7 +6189,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
                txbd = &txr->tx_desc_ring[ring_prod];
 
                len = frag->size;
-               mapping = sp->dma_maps[i + 1];
+               mapping = sp->dma_maps[i];
 
                txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
                txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
@@ -6211,7 +6208,6 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
        mmiowb();
 
        txr->tx_prod = prod;
-       dev->trans_start = jiffies;
 
        if (unlikely(bnx2_tx_avail(bp, txr) <= MAX_SKB_FRAGS)) {
                netif_tx_stop_queue(txq);
index e01539c..fbf1352 100644 (file)
@@ -10617,7 +10617,6 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
        mmiowb();
 
        fp->tx_bd_prod += nbd;
-       dev->trans_start = jiffies;
 
        if (unlikely(bnx2x_tx_avail(fp) < MAX_SKB_FRAGS + 3)) {
                /* We want bnx2x_tx_int to "see" the updated tx_bd_prod
index 92a9d69..2f4329e 100644 (file)
@@ -2405,8 +2405,7 @@ static void bond_miimon_commit(struct bonding *bond)
                                bond_3ad_handle_link_change(slave,
                                                            BOND_LINK_DOWN);
 
-                       if (bond->params.mode == BOND_MODE_TLB ||
-                           bond->params.mode == BOND_MODE_ALB)
+                       if (bond_is_lb(bond))
                                bond_alb_handle_link_change(bond, slave,
                                                            BOND_LINK_DOWN);
 
index 3a1b7b0..5fb861a 100644 (file)
@@ -1541,6 +1541,7 @@ int bond_create_sysfs(void)
                        printk(KERN_ERR
                               "network device named %s already exists in sysfs",
                               class_attr_bonding_masters.attr.name);
+               ret = 0;
        }
 
        return ret;
index ca849d2..41ceca1 100644 (file)
@@ -286,8 +286,7 @@ static inline unsigned long slave_last_rx(struct bonding *bond,
 static inline void bond_set_slave_inactive_flags(struct slave *slave)
 {
        struct bonding *bond = netdev_priv(slave->dev->master);
-       if (bond->params.mode != BOND_MODE_TLB &&
-           bond->params.mode != BOND_MODE_ALB)
+       if (!bond_is_lb(bond))
                slave->state = BOND_STATE_BACKUP;
        slave->dev->priv_flags |= IFF_SLAVE_INACTIVE;
        if (slave_do_arp_validate(bond, slave))
index cfd6c5a..d5e1881 100644 (file)
@@ -51,6 +51,15 @@ config CAN_SJA1000_PLATFORM
          boards from Phytec (http://www.phytec.de) like the PCM027,
          PCM038.
 
+config CAN_SJA1000_OF_PLATFORM
+       depends on CAN_SJA1000 && PPC_OF
+       tristate "Generic OF Platform Bus based SJA1000 driver"
+       ---help---
+         This driver adds support for the SJA1000 chips connected to
+         the OpenFirmware "platform bus" found on embedded systems with
+         OpenFirmware bindings, e.g. if you have a PowerPC based system
+         you may want to enable this option.
+
 config CAN_EMS_PCI
        tristate "EMS CPC-PCI and CPC-PCIe Card"
        depends on PCI && CAN_SJA1000
index 52b0e7d..574dadd 100644 (file)
@@ -477,7 +477,7 @@ int open_candev(struct net_device *dev)
 
        return 0;
 }
-EXPORT_SYMBOL(open_candev);
+EXPORT_SYMBOL_GPL(open_candev);
 
 /*
  * Common close function for cleanup before the device gets closed.
index d6c631f..9d0c08d 100644 (file)
@@ -4,6 +4,7 @@
 
 obj-$(CONFIG_CAN_SJA1000) += sja1000.o
 obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o
+obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o
 obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o
 obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o
 
index 3cd2ff9..121b641 100644 (file)
@@ -99,25 +99,21 @@ MODULE_DEVICE_TABLE(pci, ems_pci_tbl);
  */
 static u8 ems_pci_readb(struct ems_pci_card *card, unsigned int port)
 {
-       return readb((void __iomem *)card->base_addr
-                       + (port * EMS_PCI_PORT_BYTES));
+       return readb(card->base_addr + (port * EMS_PCI_PORT_BYTES));
 }
 
-static u8 ems_pci_read_reg(const struct net_device *dev, int port)
+static u8 ems_pci_read_reg(const struct sja1000_priv *priv, int port)
 {
-       return readb((void __iomem *)dev->base_addr
-                       + (port * EMS_PCI_PORT_BYTES));
+       return readb(priv->reg_base + (port * EMS_PCI_PORT_BYTES));
 }
 
-static void ems_pci_write_reg(const struct net_device *dev, int port, u8 val)
+static void ems_pci_write_reg(const struct sja1000_priv *priv, int port, u8 val)
 {
-       writeb(val, (void __iomem *)dev->base_addr
-               + (port * EMS_PCI_PORT_BYTES));
+       writeb(val, priv->reg_base + (port * EMS_PCI_PORT_BYTES));
 }
 
-static void ems_pci_post_irq(const struct net_device *dev)
+static void ems_pci_post_irq(const struct sja1000_priv *priv)
 {
-       struct sja1000_priv *priv = netdev_priv(dev);
        struct ems_pci_card *card = (struct ems_pci_card *)priv->priv;
 
        /* reset int flag of pita */
@@ -129,17 +125,17 @@ static void ems_pci_post_irq(const struct net_device *dev)
  * Check if a CAN controller is present at the specified location
  * by trying to set 'em into the PeliCAN mode
  */
-static inline int ems_pci_check_chan(struct net_device *dev)
+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(dev, REG_MOD, 1);
+       ems_pci_write_reg(priv, REG_MOD, 1);
 
-       ems_pci_write_reg(dev, REG_CDR, CDR_PELICAN);
+       ems_pci_write_reg(priv, REG_CDR, CDR_PELICAN);
 
        /* read reset-values */
-       res = ems_pci_read_reg(dev, REG_CDR);
+       res = ems_pci_read_reg(priv, REG_CDR);
 
        if (res == CDR_PELICAN)
                return 1;
@@ -218,14 +214,12 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
        card->conf_addr = pci_iomap(pdev, 0, EMS_PCI_MEM_SIZE);
        if (card->conf_addr == NULL) {
                err = -ENOMEM;
-
                goto failure_cleanup;
        }
 
        card->base_addr = pci_iomap(pdev, 1, EMS_PCI_MEM_SIZE);
        if (card->base_addr == NULL) {
                err = -ENOMEM;
-
                goto failure_cleanup;
        }
 
@@ -239,7 +233,6 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
            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;
        }
@@ -260,12 +253,11 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
                priv->irq_flags = IRQF_SHARED;
 
                dev->irq = pdev->irq;
-               dev->base_addr = (unsigned long)(card->base_addr
-                                               + EMS_PCI_CAN_BASE_OFFSET
-                                               + (i * EMS_PCI_CAN_CTRL_SIZE));
+               priv->reg_base = card->base_addr + EMS_PCI_CAN_BASE_OFFSET
+                                       + (i * EMS_PCI_CAN_CTRL_SIZE);
 
                /* Check if channel is present */
-               if (ems_pci_check_chan(dev)) {
+               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;
@@ -289,9 +281,8 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
 
                        card->channels++;
 
-                       dev_info(&pdev->dev, "Channel #%d at %#lX, irq %d\n",
-                                               i + 1, dev->base_addr,
-                                               dev->irq);
+                       dev_info(&pdev->dev, "Channel #%d at 0x%p, irq %d\n",
+                                       i + 1, priv->reg_base, dev->irq);
                } else {
                        free_sja1000dev(dev);
                }
index 00830b3..7dd7769 100644 (file)
@@ -117,14 +117,15 @@ static struct pci_device_id kvaser_pci_tbl[] = {
 
 MODULE_DEVICE_TABLE(pci, kvaser_pci_tbl);
 
-static u8 kvaser_pci_read_reg(const struct net_device *dev, int port)
+static u8 kvaser_pci_read_reg(const struct sja1000_priv *priv, int port)
 {
-       return ioread8((void __iomem *)(dev->base_addr + port));
+       return ioread8(priv->reg_base + port);
 }
 
-static void kvaser_pci_write_reg(const struct net_device *dev, int port, u8 val)
+static void kvaser_pci_write_reg(const struct sja1000_priv *priv,
+                                int port, u8 val)
 {
-       iowrite8(val, (void __iomem *)(dev->base_addr + port));
+       iowrite8(val, priv->reg_base + port);
 }
 
 static void kvaser_pci_disable_irq(struct net_device *dev)
@@ -199,7 +200,7 @@ static void kvaser_pci_del_chan(struct net_device *dev)
        }
        unregister_sja1000dev(dev);
 
-       pci_iounmap(board->pci_dev, (void __iomem *)dev->base_addr);
+       pci_iounmap(board->pci_dev, priv->reg_base);
        pci_iounmap(board->pci_dev, board->conf_addr);
        pci_iounmap(board->pci_dev, board->res_addr);
 
@@ -210,7 +211,7 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel,
                               struct net_device **master_dev,
                               void __iomem *conf_addr,
                               void __iomem *res_addr,
-                              unsigned long base_addr)
+                              void __iomem *base_addr)
 {
        struct net_device *dev;
        struct sja1000_priv *priv;
@@ -252,7 +253,7 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel,
                board->xilinx_ver = master_board->xilinx_ver;
        }
 
-       dev->base_addr = base_addr + channel * KVASER_PCI_PORT_BYTES;
+       priv->reg_base = base_addr + channel * KVASER_PCI_PORT_BYTES;
 
        priv->read_reg = kvaser_pci_read_reg;
        priv->write_reg = kvaser_pci_write_reg;
@@ -267,8 +268,8 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel,
 
        init_step = 4;
 
-       dev_info(&pdev->dev, "base_addr=%#lx conf_addr=%p irq=%d\n",
-                dev->base_addr, board->conf_addr, dev->irq);
+       dev_info(&pdev->dev, "reg_base=%p conf_addr=%p irq=%d\n",
+                priv->reg_base, board->conf_addr, dev->irq);
 
        SET_NETDEV_DEV(dev, &pdev->dev);
 
@@ -343,7 +344,7 @@ static int __devinit kvaser_pci_init_one(struct pci_dev *pdev,
        for (i = 0; i < no_channels; i++) {
                err = kvaser_pci_add_chan(pdev, i, &master_dev,
                                          conf_addr, res_addr,
-                                         (unsigned long)base_addr);
+                                         base_addr);
                if (err)
                        goto failure_cleanup;
        }
index 05b38dd..571f133 100644 (file)
@@ -89,7 +89,7 @@ static int sja1000_probe_chip(struct net_device *dev)
 {
        struct sja1000_priv *priv = netdev_priv(dev);
 
-       if (dev->base_addr && (priv->read_reg(dev, 0) == 0xFF)) {
+       if (priv->reg_base && (priv->read_reg(priv, 0) == 0xFF)) {
                printk(KERN_INFO "%s: probing @0x%lX failed\n",
                       DRV_NAME, dev->base_addr);
                return 0;
@@ -100,11 +100,11 @@ static int sja1000_probe_chip(struct net_device *dev)
 static void set_reset_mode(struct net_device *dev)
 {
        struct sja1000_priv *priv = netdev_priv(dev);
-       unsigned char status = priv->read_reg(dev, REG_MOD);
+       unsigned char status = priv->read_reg(priv, REG_MOD);
        int i;
 
        /* disable interrupts */
-       priv->write_reg(dev, REG_IER, IRQ_OFF);
+       priv->write_reg(priv, REG_IER, IRQ_OFF);
 
        for (i = 0; i < 100; i++) {
                /* check reset bit */
@@ -113,9 +113,9 @@ static void set_reset_mode(struct net_device *dev)
                        return;
                }
 
-               priv->write_reg(dev, REG_MOD, MOD_RM);  /* reset chip */
+               priv->write_reg(priv, REG_MOD, MOD_RM); /* reset chip */
                udelay(10);
-               status = priv->read_reg(dev, REG_MOD);
+               status = priv->read_reg(priv, REG_MOD);
        }
 
        dev_err(dev->dev.parent, "setting SJA1000 into reset mode failed!\n");
@@ -124,7 +124,7 @@ static void set_reset_mode(struct net_device *dev)
 static void set_normal_mode(struct net_device *dev)
 {
        struct sja1000_priv *priv = netdev_priv(dev);
-       unsigned char status = priv->read_reg(dev, REG_MOD);
+       unsigned char status = priv->read_reg(priv, REG_MOD);
        int i;
 
        for (i = 0; i < 100; i++) {
@@ -132,14 +132,14 @@ static void set_normal_mode(struct net_device *dev)
                if ((status & MOD_RM) == 0) {
                        priv->can.state = CAN_STATE_ERROR_ACTIVE;
                        /* enable all interrupts */
-                       priv->write_reg(dev, REG_IER, IRQ_ALL);
+                       priv->write_reg(priv, REG_IER, IRQ_ALL);
                        return;
                }
 
                /* set chip to normal mode */
-               priv->write_reg(dev, REG_MOD, 0x00);
+               priv->write_reg(priv, REG_MOD, 0x00);
                udelay(10);
-               status = priv->read_reg(dev, REG_MOD);
+               status = priv->read_reg(priv, REG_MOD);
        }
 
        dev_err(dev->dev.parent, "setting SJA1000 into normal mode failed!\n");
@@ -154,9 +154,9 @@ static void sja1000_start(struct net_device *dev)
                set_reset_mode(dev);
 
        /* Clear error counters and error code capture */
-       priv->write_reg(dev, REG_TXERR, 0x0);
-       priv->write_reg(dev, REG_RXERR, 0x0);
-       priv->read_reg(dev, REG_ECC);
+       priv->write_reg(priv, REG_TXERR, 0x0);
+       priv->write_reg(priv, REG_RXERR, 0x0);
+       priv->read_reg(priv, REG_ECC);
 
        /* leave reset mode */
        set_normal_mode(dev);
@@ -198,8 +198,8 @@ static int sja1000_set_bittiming(struct net_device *dev)
        dev_info(dev->dev.parent,
                 "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1);
 
-       priv->write_reg(dev, REG_BTR0, btr0);
-       priv->write_reg(dev, REG_BTR1, btr1);
+       priv->write_reg(priv, REG_BTR0, btr0);
+       priv->write_reg(priv, REG_BTR1, btr1);
 
        return 0;
 }
@@ -217,20 +217,20 @@ static void chipset_init(struct net_device *dev)
        struct sja1000_priv *priv = netdev_priv(dev);
 
        /* set clock divider and output control register */
-       priv->write_reg(dev, REG_CDR, priv->cdr | CDR_PELICAN);
+       priv->write_reg(priv, REG_CDR, priv->cdr | CDR_PELICAN);
 
        /* set acceptance filter (accept all) */
-       priv->write_reg(dev, REG_ACCC0, 0x00);
-       priv->write_reg(dev, REG_ACCC1, 0x00);
-       priv->write_reg(dev, REG_ACCC2, 0x00);
-       priv->write_reg(dev, REG_ACCC3, 0x00);
+       priv->write_reg(priv, REG_ACCC0, 0x00);
+       priv->write_reg(priv, REG_ACCC1, 0x00);
+       priv->write_reg(priv, REG_ACCC2, 0x00);
+       priv->write_reg(priv, REG_ACCC3, 0x00);
 
-       priv->write_reg(dev, REG_ACCM0, 0xFF);
-       priv->write_reg(dev, REG_ACCM1, 0xFF);
-       priv->write_reg(dev, REG_ACCM2, 0xFF);
-       priv->write_reg(dev, REG_ACCM3, 0xFF);
+       priv->write_reg(priv, REG_ACCM0, 0xFF);
+       priv->write_reg(priv, REG_ACCM1, 0xFF);
+       priv->write_reg(priv, REG_ACCM2, 0xFF);
+       priv->write_reg(priv, REG_ACCM3, 0xFF);
 
-       priv->write_reg(dev, REG_OCR, priv->ocr | OCR_MODE_NORMAL);
+       priv->write_reg(priv, REG_OCR, priv->ocr | OCR_MODE_NORMAL);
 }
 
 /*
@@ -261,27 +261,27 @@ static int sja1000_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (id & CAN_EFF_FLAG) {
                fi |= FI_FF;
                dreg = EFF_BUF;
-               priv->write_reg(dev, REG_FI, fi);
-               priv->write_reg(dev, REG_ID1, (id & 0x1fe00000) >> (5 + 16));
-               priv->write_reg(dev, REG_ID2, (id & 0x001fe000) >> (5 + 8));
-               priv->write_reg(dev, REG_ID3, (id & 0x00001fe0) >> 5);
-               priv->write_reg(dev, REG_ID4, (id & 0x0000001f) << 3);
+               priv->write_reg(priv, REG_FI, fi);
+               priv->write_reg(priv, REG_ID1, (id & 0x1fe00000) >> (5 + 16));
+               priv->write_reg(priv, REG_ID2, (id & 0x001fe000) >> (5 + 8));
+               priv->write_reg(priv, REG_ID3, (id & 0x00001fe0) >> 5);
+               priv->write_reg(priv, REG_ID4, (id & 0x0000001f) << 3);
        } else {
                dreg = SFF_BUF;
-               priv->write_reg(dev, REG_FI, fi);
-               priv->write_reg(dev, REG_ID1, (id & 0x000007f8) >> 3);
-               priv->write_reg(dev, REG_ID2, (id & 0x00000007) << 5);
+               priv->write_reg(priv, REG_FI, fi);
+               priv->write_reg(priv, REG_ID1, (id & 0x000007f8) >> 3);
+               priv->write_reg(priv, REG_ID2, (id & 0x00000007) << 5);
        }
 
        for (i = 0; i < dlc; i++)
-               priv->write_reg(dev, dreg++, cf->data[i]);
+               priv->write_reg(priv, dreg++, cf->data[i]);
 
        stats->tx_bytes += dlc;
        dev->trans_start = jiffies;
 
        can_put_echo_skb(skb, dev, 0);
 
-       priv->write_reg(dev, REG_CMR, CMD_TR);
+       priv->write_reg(priv, REG_CMR, CMD_TR);
 
        return 0;
 }
@@ -304,22 +304,22 @@ static void sja1000_rx(struct net_device *dev)
        skb->dev = dev;
        skb->protocol = htons(ETH_P_CAN);
 
-       fi = priv->read_reg(dev, REG_FI);
+       fi = priv->read_reg(priv, REG_FI);
        dlc = fi & 0x0F;
 
        if (fi & FI_FF) {
                /* extended frame format (EFF) */
                dreg = EFF_BUF;
-               id = (priv->read_reg(dev, REG_ID1) << (5 + 16))
-                   | (priv->read_reg(dev, REG_ID2) << (5 + 8))
-                   | (priv->read_reg(dev, REG_ID3) << 5)
-                   | (priv->read_reg(dev, REG_ID4) >> 3);
+               id = (priv->read_reg(priv, REG_ID1) << (5 + 16))
+                   | (priv->read_reg(priv, REG_ID2) << (5 + 8))
+                   | (priv->read_reg(priv, REG_ID3) << 5)
+                   | (priv->read_reg(priv, REG_ID4) >> 3);
                id |= CAN_EFF_FLAG;
        } else {
                /* standard frame format (SFF) */
                dreg = SFF_BUF;
-               id = (priv->read_reg(dev, REG_ID1) << 3)
-                   | (priv->read_reg(dev, REG_ID2) >> 5);
+               id = (priv->read_reg(priv, REG_ID1) << 3)
+                   | (priv->read_reg(priv, REG_ID2) >> 5);
        }
 
        if (fi & FI_RTR)
@@ -330,13 +330,13 @@ static void sja1000_rx(struct net_device *dev)
        cf->can_id = id;
        cf->can_dlc = dlc;
        for (i = 0; i < dlc; i++)
-               cf->data[i] = priv->read_reg(dev, dreg++);
+               cf->data[i] = priv->read_reg(priv, dreg++);
 
        while (i < 8)
                cf->data[i++] = 0;
 
        /* release receive buffer */
-       priv->write_reg(dev, REG_CMR, CMD_RRB);
+       priv->write_reg(priv, REG_CMR, CMD_RRB);
 
        netif_rx(skb);
 
@@ -371,7 +371,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
                cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
                stats->rx_over_errors++;
                stats->rx_errors++;
-               priv->write_reg(dev, REG_CMR, CMD_CDO); /* clear bit */
+               priv->write_reg(priv, REG_CMR, CMD_CDO);        /* clear bit */
        }
 
        if (isrc & IRQ_EI) {
@@ -392,7 +392,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
                priv->can.can_stats.bus_error++;
                stats->rx_errors++;
 
-               ecc = priv->read_reg(dev, REG_ECC);
+               ecc = priv->read_reg(priv, REG_ECC);
 
                cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
 
@@ -426,7 +426,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
        if (isrc & IRQ_ALI) {
                /* arbitration lost interrupt */
                dev_dbg(dev->dev.parent, "arbitration lost interrupt\n");
-               alc = priv->read_reg(dev, REG_ALC);
+               alc = priv->read_reg(priv, REG_ALC);
                priv->can.can_stats.arbitration_lost++;
                stats->rx_errors++;
                cf->can_id |= CAN_ERR_LOSTARB;
@@ -435,8 +435,8 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
 
        if (state != priv->can.state && (state == CAN_STATE_ERROR_WARNING ||
                                         state == CAN_STATE_ERROR_PASSIVE)) {
-               uint8_t rxerr = priv->read_reg(dev, REG_RXERR);
-               uint8_t txerr = priv->read_reg(dev, REG_TXERR);
+               uint8_t rxerr = priv->read_reg(priv, REG_RXERR);
+               uint8_t txerr = priv->read_reg(priv, REG_TXERR);
                cf->can_id |= CAN_ERR_CRTL;
                if (state == CAN_STATE_ERROR_WARNING) {
                        priv->can.can_stats.error_warning++;
@@ -471,15 +471,15 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
        int n = 0;
 
        /* Shared interrupts and IRQ off? */
-       if (priv->read_reg(dev, REG_IER) == IRQ_OFF)
+       if (priv->read_reg(priv, REG_IER) == IRQ_OFF)
                return IRQ_NONE;
 
        if (priv->pre_irq)
-               priv->pre_irq(dev);
+               priv->pre_irq(priv);
 
-       while ((isrc = priv->read_reg(dev, REG_IR)) && (n < SJA1000_MAX_IRQ)) {
+       while ((isrc = priv->read_reg(priv, REG_IR)) && (n < SJA1000_MAX_IRQ)) {
                n++;
-               status = priv->read_reg(dev, REG_SR);
+               status = priv->read_reg(priv, REG_SR);
 
                if (isrc & IRQ_WUI)
                        dev_warn(dev->dev.parent, "wakeup interrupt\n");
@@ -494,7 +494,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
                        /* receive interrupt */
                        while (status & SR_RBS) {
                                sja1000_rx(dev);
-                               status = priv->read_reg(dev, REG_SR);
+                               status = priv->read_reg(priv, REG_SR);
                        }
                }
                if (isrc & (IRQ_DOI | IRQ_EI | IRQ_BEI | IRQ_EPI | IRQ_ALI)) {
@@ -505,7 +505,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
        }
 
        if (priv->post_irq)
-               priv->post_irq(dev);
+               priv->post_irq(priv);
 
        if (n >= SJA1000_MAX_IRQ)
                dev_dbg(dev->dev.parent, "%d messages handled in ISR", n);
@@ -532,8 +532,8 @@ static int sja1000_open(struct net_device *dev)
                err = request_irq(dev->irq, &sja1000_interrupt, priv->irq_flags,
                                  dev->name, (void *)dev);
                if (err) {
-                       return -EAGAIN;
                        close_candev(dev);
+                       return -EAGAIN;
                }
        }
 
index ccd3028..302d2c7 100644 (file)
@@ -155,14 +155,15 @@ struct sja1000_priv {
        struct sk_buff *echo_skb;
 
        /* the lower-layer is responsible for appropriate locking */
-       u8 (*read_reg) (const struct net_device *dev, int reg);
-       void (*write_reg) (const struct net_device *dev, int reg, u8 val);
-       void (*pre_irq) (const struct net_device *dev);
-       void (*post_irq) (const struct net_device *dev);
+       u8 (*read_reg) (const struct sja1000_priv *priv, int reg);
+       void (*write_reg) (const struct sja1000_priv *priv, int reg, u8 val);
+       void (*pre_irq) (const struct sja1000_priv *priv);
+       void (*post_irq) (const struct sja1000_priv *priv);
 
        void *priv;             /* for board-specific data */
        struct net_device *dev;
 
+       void __iomem *reg_base;  /* ioremap'ed address to registers */
        unsigned long irq_flags; /* for request_irq() */
 
        u16 flags;              /* custom mode flags */
diff --git a/drivers/net/can/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c
new file mode 100644 (file)
index 0000000..3373560
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * Driver for SJA1000 CAN controllers on the OpenFirmware platform bus
+ *
+ * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* This is a generic driver for SJA1000 chips on the OpenFirmware platform
+ * bus found on embedded PowerPC systems. You need a SJA1000 CAN node
+ * definition in your flattened device tree source (DTS) file similar to:
+ *
+ *   can@3,100 {
+ *           compatible = "nxp,sja1000";
+ *           reg = <3 0x100 0x80>;
+ *           interrupts = <2 0>;
+ *           interrupt-parent = <&mpic>;
+ *           nxp,external-clock-frequency = <16000000>;
+ *   };
+ *
+ * See "Documentation/powerpc/dts-bindings/can/sja1000.txt" for further
+ * information.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+
+#include <linux/of_platform.h>
+#include <asm/prom.h>
+
+#include "sja1000.h"
+
+#define DRV_NAME "sja1000_of_platform"
+
+MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
+MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the OF platform bus");
+MODULE_LICENSE("GPL v2");
+
+#define SJA1000_OFP_CAN_CLOCK  (16000000 / 2)
+
+#define SJA1000_OFP_OCR        OCR_TX0_PULLDOWN
+#define SJA1000_OFP_CDR        (CDR_CBP | CDR_CLK_OFF)
+
+static u8 sja1000_ofp_read_reg(const struct sja1000_priv *priv, int reg)
+{
+       return in_8(priv->reg_base + reg);
+}
+
+static void sja1000_ofp_write_reg(const struct sja1000_priv *priv,
+                                 int reg, u8 val)
+{
+       out_8(priv->reg_base + reg, val);
+}
+
+static int __devexit sja1000_ofp_remove(struct of_device *ofdev)
+{
+       struct net_device *dev = dev_get_drvdata(&ofdev->dev);
+       struct sja1000_priv *priv = netdev_priv(dev);
+       struct device_node *np = ofdev->node;
+       struct resource res;
+
+       dev_set_drvdata(&ofdev->dev, NULL);
+
+       unregister_sja1000dev(dev);
+       free_sja1000dev(dev);
+       iounmap(priv->reg_base);
+       irq_dispose_mapping(dev->irq);
+
+       of_address_to_resource(np, 0, &res);
+       release_mem_region(res.start, resource_size(&res));
+
+       return 0;
+}
+
+static int __devinit sja1000_ofp_probe(struct of_device *ofdev,
+                                      const struct of_device_id *id)
+{
+       struct device_node *np = ofdev->node;
+       struct net_device *dev;
+       struct sja1000_priv *priv;
+       struct resource res;
+       const u32 *prop;
+       int err, irq, res_size, prop_size;
+       void __iomem *base;
+
+       err = of_address_to_resource(np, 0, &res);
+       if (err) {
+               dev_err(&ofdev->dev, "invalid address\n");
+               return err;
+       }
+
+       res_size = resource_size(&res);
+
+       if (!request_mem_region(res.start, res_size, DRV_NAME)) {
+               dev_err(&ofdev->dev, "couldn't request %#llx..%#llx\n",
+                       (unsigned long long)res.start,
+                       (unsigned long long)res.end);
+               return -EBUSY;
+       }
+
+       base = ioremap_nocache(res.start, res_size);
+       if (!base) {
+               dev_err(&ofdev->dev, "couldn't ioremap %#llx..%#llx\n",
+                       (unsigned long long)res.start,
+                       (unsigned long long)res.end);
+               err = -ENOMEM;
+               goto exit_release_mem;
+       }
+
+       irq = irq_of_parse_and_map(np, 0);
+       if (irq == NO_IRQ) {
+               dev_err(&ofdev->dev, "no irq found\n");
+               err = -ENODEV;
+               goto exit_unmap_mem;
+       }
+
+       dev = alloc_sja1000dev(0);
+       if (!dev) {
+               err = -ENOMEM;
+               goto exit_dispose_irq;
+       }
+
+       priv = netdev_priv(dev);
+
+       priv->read_reg = sja1000_ofp_read_reg;
+       priv->write_reg = sja1000_ofp_write_reg;
+
+       prop = of_get_property(np, "nxp,external-clock-frequency", &prop_size);
+       if (prop && (prop_size ==  sizeof(u32)))
+               priv->can.clock.freq = *prop / 2;
+       else
+               priv->can.clock.freq = SJA1000_OFP_CAN_CLOCK; /* default */
+
+       prop = of_get_property(np, "nxp,tx-output-mode", &prop_size);
+       if (prop && (prop_size == sizeof(u32)))
+               priv->ocr |= *prop & OCR_MODE_MASK;
+       else
+               priv->ocr |= OCR_MODE_NORMAL; /* default */
+
+       prop = of_get_property(np, "nxp,tx-output-config", &prop_size);
+       if (prop && (prop_size == sizeof(u32)))
+               priv->ocr |= (*prop << OCR_TX_SHIFT) & OCR_TX_MASK;
+       else
+               priv->ocr |= OCR_TX0_PULLDOWN; /* default */
+
+       prop = of_get_property(np, "nxp,clock-out-frequency", &prop_size);
+       if (prop && (prop_size == sizeof(u32)) && *prop) {
+               u32 divider = priv->can.clock.freq * 2 / *prop;
+
+               if (divider > 1)
+                       priv->cdr |= divider / 2 - 1;
+               else
+                       priv->cdr |= CDR_CLKOUT_MASK;
+       } else {
+               priv->cdr |= CDR_CLK_OFF; /* default */
+       }
+
+       prop = of_get_property(np, "nxp,no-comparator-bypass", NULL);
+       if (!prop)
+               priv->cdr |= CDR_CBP; /* default */
+
+       priv->irq_flags = IRQF_SHARED;
+       priv->reg_base = base;
+
+       dev->irq = irq;
+
+       dev_info(&ofdev->dev,
+                "reg_base=0x%p irq=%d clock=%d ocr=0x%02x cdr=0x%02x\n",
+                priv->reg_base, dev->irq, priv->can.clock.freq,
+                priv->ocr, priv->cdr);
+
+       dev_set_drvdata(&ofdev->dev, dev);
+       SET_NETDEV_DEV(dev, &ofdev->dev);
+
+       err = register_sja1000dev(dev);
+       if (err) {
+               dev_err(&ofdev->dev, "registering %s failed (err=%d)\n",
+                       DRV_NAME, err);
+               goto exit_free_sja1000;
+       }
+
+       return 0;
+
+exit_free_sja1000:
+       free_sja1000dev(dev);
+exit_dispose_irq:
+       irq_dispose_mapping(irq);
+exit_unmap_mem:
+       iounmap(base);
+exit_release_mem:
+       release_mem_region(res.start, res_size);
+
+       return err;
+}
+
+static struct of_device_id __devinitdata sja1000_ofp_table[] = {
+       {.compatible = "nxp,sja1000"},
+       {},
+};
+
+static struct of_platform_driver sja1000_ofp_driver = {
+       .owner = THIS_MODULE,
+       .name = DRV_NAME,
+       .probe = sja1000_ofp_probe,
+       .remove = __devexit_p(sja1000_ofp_remove),
+       .match_table = sja1000_ofp_table,
+};
+
+static int __init sja1000_ofp_init(void)
+{
+       return of_register_platform_driver(&sja1000_ofp_driver);
+}
+module_init(sja1000_ofp_init);
+
+static void __exit sja1000_ofp_exit(void)
+{
+       return of_unregister_platform_driver(&sja1000_ofp_driver);
+};
+module_exit(sja1000_ofp_exit);
index 8017229..628374c 100644 (file)
@@ -37,14 +37,14 @@ MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
 MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the platform bus");
 MODULE_LICENSE("GPL v2");
 
-static u8 sp_read_reg(const struct net_device *dev, int reg)
+static u8 sp_read_reg(const struct sja1000_priv *priv, int reg)
 {
-       return ioread8((void __iomem *)(dev->base_addr + reg));
+       return ioread8(priv->reg_base + reg);
 }
 
-static void sp_write_reg(const struct net_device *dev, int reg, u8 val)
+static void sp_write_reg(const struct sja1000_priv *priv, int reg, u8 val)
 {
-       iowrite8(val, (void __iomem *)(dev->base_addr + reg));
+       iowrite8(val, priv->reg_base + reg);
 }
 
 static int sp_probe(struct platform_device *pdev)
@@ -89,9 +89,9 @@ static int sp_probe(struct platform_device *pdev)
        }
        priv = netdev_priv(dev);
 
-       dev->base_addr = (unsigned long)addr;
        dev->irq = res_irq->start;
        priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK;
+       priv->reg_base = addr;
        priv->read_reg = sp_read_reg;
        priv->write_reg = sp_write_reg;
        priv->can.clock.freq = pdata->clock;
@@ -108,8 +108,8 @@ static int sp_probe(struct platform_device *pdev)
                goto exit_free;
        }
 
-       dev_info(&pdev->dev, "%s device registered (base_addr=%#lx, irq=%d)\n",
-                DRV_NAME, dev->base_addr, dev->irq);
+       dev_info(&pdev->dev, "%s device registered (reg_base=%p, irq=%d)\n",
+                DRV_NAME, priv->reg_base, dev->irq);
        return 0;
 
  exit_free:
@@ -125,13 +125,14 @@ static int sp_probe(struct platform_device *pdev)
 static int sp_remove(struct platform_device *pdev)
 {
        struct net_device *dev = dev_get_drvdata(&pdev->dev);
+       struct sja1000_priv *priv = netdev_priv(dev);
        struct resource *res;
 
        unregister_sja1000dev(dev);
        dev_set_drvdata(&pdev->dev, NULL);
 
-       if (dev->base_addr)
-               iounmap((void __iomem *)dev->base_addr);
+       if (priv->reg_base)
+               iounmap(priv->reg_base);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        release_mem_region(res->start, resource_size(res));
index 5e97a1a..3711d64 100644 (file)
@@ -1879,7 +1879,6 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
                cpl->vlan_valid = 0;
 
 send:
-       dev->trans_start = jiffies;
        ret = t1_sge_tx(skb, adapter, 0, dev);
 
        /* If transmit busy, and we reallocated skb's due to headroom limit,
index cfb4198..58afafb 100644 (file)
@@ -615,13 +615,13 @@ static void cpmac_end_xmit(struct net_device *dev, int queue)
 
                dev_kfree_skb_irq(desc->skb);
                desc->skb = NULL;
-               if (netif_subqueue_stopped(dev, queue))
+               if (__netif_subqueue_stopped(dev, queue))
                        netif_wake_subqueue(dev, queue);
        } else {
                if (netif_msg_tx_err(priv) && net_ratelimit())
                        printk(KERN_WARNING
                               "%s: end_xmit: spurious interrupt\n", dev->name);
-               if (netif_subqueue_stopped(dev, queue))
+               if (__netif_subqueue_stopped(dev, queue))
                        netif_wake_subqueue(dev, queue);
        }
 }
@@ -731,7 +731,6 @@ static void cpmac_clear_tx(struct net_device *dev)
 
 static void cpmac_hw_error(struct work_struct *work)
 {
-       int i;
        struct cpmac_priv *priv =
                container_of(work, struct cpmac_priv, reset_work);
 
@@ -818,7 +817,6 @@ static irqreturn_t cpmac_irq(int irq, void *dev_id)
 
 static void cpmac_tx_timeout(struct net_device *dev)
 {
-       int i;
        struct cpmac_priv *priv = netdev_priv(dev);
 
        spin_lock(&priv->lock);
@@ -1110,7 +1108,7 @@ static int external_switch;
 
 static int __devinit cpmac_probe(struct platform_device *pdev)
 {
-       int rc, phy_id, i;
+       int rc, phy_id;
        char *mdio_bus_id = "0";
        struct resource *mem;
        struct cpmac_priv *priv;
index 3434679..29aff78 100644 (file)
@@ -5,4 +5,4 @@
 obj-$(CONFIG_CHELSIO_T3) += cxgb3.o
 
 cxgb3-objs := cxgb3_main.o ael1002.o vsc8211.o t3_hw.o mc5.o \
-             xgmac.o sge.o l2t.o cxgb3_offload.o
+             xgmac.o sge.o l2t.o cxgb3_offload.o aq100x.o
index 322434a..1694fad 100644 (file)
@@ -85,8 +85,8 @@ struct fl_pg_chunk {
        struct page *page;
        void *va;
        unsigned int offset;
-       u64 *p_cnt;
-       DECLARE_PCI_UNMAP_ADDR(mapping);
+       unsigned long *p_cnt;
+       dma_addr_t mapping;
 };
 
 struct rx_desc;
@@ -253,6 +253,8 @@ struct adapter {
        struct mutex mdio_lock;
        spinlock_t stats_lock;
        spinlock_t work_lock;
+
+       struct sk_buff *nofail_skb;
 };
 
 static inline u32 t3_read_reg(struct adapter *adapter, u32 reg_addr)
index df1f585..9fe008e 100644 (file)
@@ -44,12 +44,33 @@ enum {
        AEL_I2C_STAT = 0xc30c,
        AEL2005_GPIO_CTRL = 0xc214,
        AEL2005_GPIO_STAT = 0xc215,
+
+       AEL2020_GPIO_INTR   = 0xc103,   /* Latch High (LH) */
+       AEL2020_GPIO_CTRL   = 0xc108,   /* Store Clear (SC) */
+       AEL2020_GPIO_STAT   = 0xc10c,   /* Read Only (RO) */
+       AEL2020_GPIO_CFG    = 0xc110,   /* Read Write (RW) */
+
+       AEL2020_GPIO_SDA    = 0,        /* IN: i2c serial data */
+       AEL2020_GPIO_MODDET = 1,        /* IN: Module Detect */
+       AEL2020_GPIO_0      = 3,        /* IN: unassigned */
+       AEL2020_GPIO_1      = 2,        /* OUT: unassigned */
+       AEL2020_GPIO_LSTAT  = AEL2020_GPIO_1, /* wired to link status LED */
 };
 
 enum { edc_none, edc_sr, edc_twinax };
 
 /* PHY module I2C device address */
-#define MODULE_DEV_ADDR 0xa0
+enum {
+       MODULE_DEV_ADDR = 0xa0,
+       SFF_DEV_ADDR    = 0xa2,
+};
+
+/* PHY transceiver type */
+enum {
+       phy_transtype_unknown = 0,
+       phy_transtype_sfp     = 3,
+       phy_transtype_xfp     = 6,
+};
 
 #define AEL2005_MODDET_IRQ 4
 
@@ -86,6 +107,37 @@ static void ael100x_txon(struct cphy *phy)
        msleep(30);
 }
 
+/*
+ * Read an 8-bit word from a device attached to the PHY's i2c bus.
+ */
+static int ael_i2c_rd(struct cphy *phy, int dev_addr, int word_addr)
+{
+       int i, err;
+       unsigned int stat, data;
+
+       err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL_I2C_CTRL,
+                           (dev_addr << 8) | (1 << 8) | word_addr);
+       if (err)
+               return err;
+
+       for (i = 0; i < 200; i++) {
+               msleep(1);
+               err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_STAT, &stat);
+               if (err)
+                       return err;
+               if ((stat & 3) == 1) {
+                       err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_DATA,
+                                          &data);
+                       if (err)
+                               return err;
+                       return data >> 8;
+               }
+       }
+       CH_WARN(phy->adapter, "PHY %u i2c read of dev.addr %#x.%#x timed out\n",
+               phy->mdio.prtad, dev_addr, word_addr);
+       return -ETIMEDOUT;
+}
+
 static int ael1002_power_down(struct cphy *phy, int enable)
 {
        int err;
@@ -199,6 +251,51 @@ int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter,
        return 0;
 }
 
+/*
+ * Decode our module type.
+ */
+static int ael2xxx_get_module_type(struct cphy *phy, int delay_ms)
+{
+       int v;
+
+       if (delay_ms)
+               msleep(delay_ms);
+
+       /* see SFF-8472 for below */
+       v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 3);
+       if (v < 0)
+               return v;
+
+       if (v == 0x10)
+               return phy_modtype_sr;
+       if (v == 0x20)
+               return phy_modtype_lr;
+       if (v == 0x40)
+               return phy_modtype_lrm;
+
+       v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 6);
+       if (v < 0)
+               return v;
+       if (v != 4)
+               goto unknown;
+
+       v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 10);
+       if (v < 0)
+               return v;
+
+       if (v & 0x80) {
+               v = ael_i2c_rd(phy, MODULE_DEV_ADDR, 0x12);
+               if (v < 0)
+                       return v;
+               return v > 10 ? phy_modtype_twinax_long : phy_modtype_twinax;
+       }
+unknown:
+       return phy_modtype_unknown;
+}
+
+/*
+ * Code to support the Aeluros/NetLogic 2005 10Gb PHY.
+ */
 static int ael2005_setup_sr_edc(struct cphy *phy)
 {
        static struct reg_val regs[] = {
@@ -893,35 +990,7 @@ static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype)
        return err;
 }
 
-static int ael2005_i2c_rd(struct cphy *phy, int dev_addr, int word_addr)
-{
-       int i, err;
-       unsigned int stat, data;
-
-       err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL_I2C_CTRL,
-                           (dev_addr << 8) | (1 << 8) | word_addr);
-       if (err)
-               return err;
-
-       for (i = 0; i < 5; i++) {
-               msleep(1);
-               err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_STAT, &stat);
-               if (err)
-                       return err;
-               if ((stat & 3) == 1) {
-                       err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL_I2C_DATA,
-                                          &data);
-                       if (err)
-                               return err;
-                       return data >> 8;
-               }
-       }
-       CH_WARN(phy->adapter, "PHY %u I2C read of addr %u timed out\n",
-               phy->mdio.prtad, word_addr);
-       return -ETIMEDOUT;
-}
-
-static int get_module_type(struct cphy *phy, int delay_ms)
+static int ael2005_get_module_type(struct cphy *phy, int delay_ms)
 {
        int v;
        unsigned int stat;
@@ -933,39 +1002,7 @@ static int get_module_type(struct cphy *phy, int delay_ms)
        if (stat & (1 << 8))                    /* module absent */
                return phy_modtype_none;
 
-       if (delay_ms)
-               msleep(delay_ms);
-
-       /* see SFF-8472 for below */
-       v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 3);
-       if (v < 0)
-               return v;
-
-       if (v == 0x10)
-               return phy_modtype_sr;
-       if (v == 0x20)
-               return phy_modtype_lr;
-       if (v == 0x40)
-               return phy_modtype_lrm;
-
-       v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 6);
-       if (v < 0)
-               return v;
-       if (v != 4)
-               goto unknown;
-
-       v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 10);
-       if (v < 0)
-               return v;
-
-       if (v & 0x80) {
-               v = ael2005_i2c_rd(phy, MODULE_DEV_ADDR, 0x12);
-               if (v < 0)
-                       return v;
-               return v > 10 ? phy_modtype_twinax_long : phy_modtype_twinax;
-       }
-unknown:
-       return phy_modtype_unknown;
+       return ael2xxx_get_module_type(phy, delay_ms);
 }
 
 static int ael2005_intr_enable(struct cphy *phy)
@@ -1024,7 +1061,7 @@ static int ael2005_reset(struct cphy *phy, int wait)
 
        msleep(50);
 
-       err = get_module_type(phy, 0);
+       err = ael2005_get_module_type(phy, 0);
        if (err < 0)
                return err;
        phy->modtype = err;
@@ -1062,7 +1099,7 @@ static int ael2005_intr_handler(struct cphy *phy)
                        return ret;
 
                /* modules have max 300 ms init time after hot plug */
-               ret = get_module_type(phy, 300);
+               ret = ael2005_get_module_type(phy, 300);
                if (ret < 0)
                        return ret;
 
@@ -1113,6 +1150,662 @@ int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter,
 }
 
 /*
+ * Setup EDC and other parameters for operation with an optical module.
+ */
+static int ael2020_setup_sr_edc(struct cphy *phy)
+{
+       static struct reg_val regs[] = {
+               /* set CDR offset to 10 */
+               { MDIO_MMD_PMAPMD, 0xcc01, 0xffff, 0x488a },
+
+               /* adjust 10G RX bias current */
+               { MDIO_MMD_PMAPMD, 0xcb1b, 0xffff, 0x0200 },
+               { MDIO_MMD_PMAPMD, 0xcb1c, 0xffff, 0x00f0 },
+               { MDIO_MMD_PMAPMD, 0xcc06, 0xffff, 0x00e0 },
+
+               /* end */
+               { 0, 0, 0, 0 }
+       };
+       int err;
+
+       err = set_phy_regs(phy, regs);
+       msleep(50);
+       if (err)
+               return err;
+
+       phy->priv = edc_sr;
+       return 0;
+}
+
+/*
+ * Setup EDC and other parameters for operation with an TWINAX module.
+ */
+static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype)
+{
+       /* set uC to 40MHz */
+       static struct reg_val uCclock40MHz[] = {
+               { MDIO_MMD_PMAPMD, 0xff28, 0xffff, 0x4001 },
+               { MDIO_MMD_PMAPMD, 0xff2a, 0xffff, 0x0002 },
+               { 0, 0, 0, 0 }
+       };
+
+       /* activate uC clock */
+       static struct reg_val uCclockActivate[] = {
+               { MDIO_MMD_PMAPMD, 0xd000, 0xffff, 0x5200 },
+               { 0, 0, 0, 0 }
+       };
+
+       /* set PC to start of SRAM and activate uC */
+       static struct reg_val uCactivate[] = {
+               { MDIO_MMD_PMAPMD, 0xd080, 0xffff, 0x0100 },
+               { 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 */
+       err = set_phy_regs(phy, uCclock40MHz);
+       msleep(500);
+       if (err)
+               return err;
+       err = set_phy_regs(phy, uCclockActivate);
+       msleep(500);
+       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]);
+       /* activate uC */
+       err = set_phy_regs(phy, uCactivate);
+       if (!err)
+               phy->priv = edc_twinax;
+       return err;
+}
+
+/*
+ * Return Module Type.
+ */
+static int ael2020_get_module_type(struct cphy *phy, int delay_ms)
+{
+       int v;
+       unsigned int stat;
+
+       v = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_STAT, &stat);
+       if (v)
+               return v;
+
+       if (stat & (0x1 << (AEL2020_GPIO_MODDET*4))) {
+               /* module absent */
+               return phy_modtype_none;
+       }
+
+       return ael2xxx_get_module_type(phy, delay_ms);
+}
+
+/*
+ * Enable PHY interrupts.  We enable "Module Detection" interrupts (on any
+ * state transition) and then generic Link Alarm Status Interrupt (LASI).
+ */
+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);
+}
+
+/*
+ * Disable PHY interrupts.  The mirror of the above ...
+ */
+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);
+}
+
+/*
+ * Clear PHY interrupt state.
+ */
+static int ael2020_intr_clear(struct cphy *phy)
+{
+       /*
+        * The GPIO Interrupt register on the AEL2020 is a "Latching High"
+        * (LH) register which is cleared to the current state when it's read.
+        * Thus, we simply read the register and discard the result.
+        */
+       unsigned int stat;
+       int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_INTR, &stat);
+       return err ? err : t3_phy_lasi_intr_clear(phy);
+}
+
+/*
+ * 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;
+
+       /* grab current interrupt state */
+       err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL,
+                          &lasi_ctrl);
+       if (err)
+               return err;
+
+       err = t3_phy_reset(phy, MDIO_MMD_PMAPMD, 125);
+       if (err)
+               return err;
+       msleep(100);
+
+       /* basic initialization for all module types */
+       phy->priv = edc_none;
+       err = set_phy_regs(phy, regs0);
+       if (err)
+               return err;
+
+       /* determine module type and perform appropriate initialization */
+       err = ael2020_get_module_type(phy, 0);
+       if (err < 0)
+               return err;
+       phy->modtype = (u8)err;
+       if (err == phy_modtype_twinax || err == phy_modtype_twinax_long)
+               err = ael2020_setup_twinax_edc(phy, err);
+       else
+               err = ael2020_setup_sr_edc(phy);
+       if (err)
+               return err;
+
+       /* reset wipes out interrupts, reenable them if they were on */
+       if (lasi_ctrl & 1)
+               err = ael2005_intr_enable(phy);
+       return err;
+}
+
+/*
+ * Handle a PHY interrupt.
+ */
+static int ael2020_intr_handler(struct cphy *phy)
+{
+       unsigned int stat;
+       int ret, edc_needed, cause = 0;
+
+       ret = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_INTR, &stat);
+       if (ret)
+               return ret;
+
+       if (stat & (0x1 << AEL2020_GPIO_MODDET)) {
+               /* modules have max 300 ms init time after hot plug */
+               ret = ael2020_get_module_type(phy, 300);
+               if (ret < 0)
+                       return ret;
+
+               phy->modtype = (u8)ret;
+               if (ret == phy_modtype_none)
+                       edc_needed = phy->priv;       /* on unplug retain EDC */
+               else if (ret == phy_modtype_twinax ||
+                        ret == phy_modtype_twinax_long)
+                       edc_needed = edc_twinax;
+               else
+                       edc_needed = edc_sr;
+
+               if (edc_needed != phy->priv) {
+                       ret = ael2020_reset(phy, 0);
+                       return ret ? ret : cphy_cause_module_change;
+               }
+               cause = cphy_cause_module_change;
+       }
+
+       ret = t3_phy_lasi_intr_handler(phy);
+       if (ret < 0)
+               return ret;
+
+       ret |= cause;
+       return ret ? ret : cphy_cause_link_change;
+}
+
+static struct cphy_ops ael2020_ops = {
+       .reset           = ael2020_reset,
+       .intr_enable     = ael2020_intr_enable,
+       .intr_disable    = ael2020_intr_disable,
+       .intr_clear      = ael2020_intr_clear,
+       .intr_handler    = ael2020_intr_handler,
+       .get_link_status = get_link_status_r,
+       .power_down      = ael1002_power_down,
+       .mmds            = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
+};
+
+int t3_ael2020_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
+                       const struct mdio_ops *mdio_ops)
+{
+       cphy_init(phy, adapter, phy_addr, &ael2020_ops, mdio_ops,
+                 SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE |
+                 SUPPORTED_IRQ, "10GBASE-R");
+       msleep(125);
+       return 0;
+}
+
+/*
  * Get link status for a 10GBASE-X device.
  */
 static int get_link_status_x(struct cphy *phy, int *link_ok, int *speed,
diff --git a/drivers/net/cxgb3/aq100x.c b/drivers/net/cxgb3/aq100x.c
new file mode 100644 (file)
index 0000000..b1fd5bf
--- /dev/null
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common.h"
+#include "regs.h"
+
+enum {
+       /* MDIO_DEV_PMA_PMD registers */
+       AQ_LINK_STAT    = 0xe800,
+       AQ_IMASK_PMA    = 0xf000,
+
+       /* MDIO_DEV_XGXS registers */
+       AQ_XAUI_RX_CFG  = 0xc400,
+       AQ_XAUI_TX_CFG  = 0xe400,
+
+       /* MDIO_DEV_ANEG registers */
+       AQ_1G_CTRL      = 0xc400,
+       AQ_ANEG_STAT    = 0xc800,
+
+       /* MDIO_DEV_VEND1 registers */
+       AQ_FW_VERSION   = 0x0020,
+       AQ_IFLAG_GLOBAL = 0xfc00,
+       AQ_IMASK_GLOBAL = 0xff00,
+};
+
+enum {
+       IMASK_PMA       = 1 << 2,
+       IMASK_GLOBAL    = 1 << 15,
+       ADV_1G_FULL     = 1 << 15,
+       ADV_1G_HALF     = 1 << 14,
+       ADV_10G_FULL    = 1 << 12,
+       AQ_RESET        = (1 << 14) | (1 << 15),
+       AQ_LOWPOWER     = 1 << 12,
+};
+
+static int aq100x_reset(struct cphy *phy, int wait)
+{
+       /*
+        * Ignore the caller specified wait time; always wait for the reset to
+        * complete. Can take up to 3s.
+        */
+       int err = t3_phy_reset(phy, MDIO_MMD_VEND1, 3000);
+
+       if (err)
+               CH_WARN(phy->adapter, "PHY%d: reset failed (0x%x).\n",
+                       phy->mdio.prtad, err);
+
+       return err;
+}
+
+static int aq100x_intr_enable(struct cphy *phy)
+{
+       int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AQ_IMASK_PMA, IMASK_PMA);
+       if (err)
+               return err;
+
+       err = t3_mdio_write(phy, MDIO_MMD_VEND1, AQ_IMASK_GLOBAL, IMASK_GLOBAL);
+       return err;
+}
+
+static int aq100x_intr_disable(struct cphy *phy)
+{
+       return t3_mdio_write(phy, MDIO_MMD_VEND1, AQ_IMASK_GLOBAL, 0);
+}
+
+static int aq100x_intr_clear(struct cphy *phy)
+{
+       unsigned int v;
+
+       t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_IFLAG_GLOBAL, &v);
+       t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_STAT1, &v);
+
+       return 0;
+}
+
+static int aq100x_intr_handler(struct cphy *phy)
+{
+       int err;
+       unsigned int cause, v;
+
+       err = t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_IFLAG_GLOBAL, &cause);
+       if (err)
+               return err;
+
+       /* Read (and reset) the latching version of the status */
+       t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_STAT1, &v);
+
+       return cphy_cause_link_change;
+}
+
+static int aq100x_power_down(struct cphy *phy, int off)
+{
+       return mdio_set_flag(&phy->mdio, phy->mdio.prtad,
+                            MDIO_MMD_PMAPMD, MDIO_CTRL1,
+                            MDIO_CTRL1_LPOWER, off);
+}
+
+static int aq100x_autoneg_enable(struct cphy *phy)
+{
+       int err;
+
+       err = aq100x_power_down(phy, 0);
+       if (!err)
+               err = mdio_set_flag(&phy->mdio, phy->mdio.prtad,
+                                   MDIO_MMD_AN, MDIO_CTRL1,
+                                   BMCR_ANENABLE | BMCR_ANRESTART, 1);
+
+       return err;
+}
+
+static int aq100x_autoneg_restart(struct cphy *phy)
+{
+       int err;
+
+       err = aq100x_power_down(phy, 0);
+       if (!err)
+               err = mdio_set_flag(&phy->mdio, phy->mdio.prtad,
+                                   MDIO_MMD_AN, MDIO_CTRL1,
+                                   BMCR_ANENABLE | BMCR_ANRESTART, 1);
+
+       return err;
+}
+
+static int aq100x_advertise(struct cphy *phy, unsigned int advertise_map)
+{
+       unsigned int adv;
+       int err;
+
+       /* 10G advertisement */
+       adv = 0;
+       if (advertise_map & ADVERTISED_10000baseT_Full)
+               adv |= ADV_10G_FULL;
+       err = t3_mdio_change_bits(phy, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
+                                 ADV_10G_FULL, adv);
+       if (err)
+               return err;
+
+       /* 1G advertisement */
+       adv = 0;
+       if (advertise_map & ADVERTISED_1000baseT_Full)
+               adv |= ADV_1G_FULL;
+       if (advertise_map & ADVERTISED_1000baseT_Half)
+               adv |= ADV_1G_HALF;
+       err = t3_mdio_change_bits(phy, MDIO_MMD_AN, AQ_1G_CTRL,
+                                 ADV_1G_FULL | ADV_1G_HALF, adv);
+       if (err)
+               return err;
+
+       /* 100M, pause advertisement */
+       adv = 0;
+       if (advertise_map & ADVERTISED_100baseT_Half)
+               adv |= ADVERTISE_100HALF;
+       if (advertise_map & ADVERTISED_100baseT_Full)
+               adv |= ADVERTISE_100FULL;
+       if (advertise_map & ADVERTISED_Pause)
+               adv |= ADVERTISE_PAUSE_CAP;
+       if (advertise_map & ADVERTISED_Asym_Pause)
+               adv |= ADVERTISE_PAUSE_ASYM;
+       err = t3_mdio_change_bits(phy, MDIO_MMD_AN, MDIO_AN_ADVERTISE,
+                                 0xfe0, adv);
+
+       return err;
+}
+
+static int aq100x_set_loopback(struct cphy *phy, int mmd, int dir, int enable)
+{
+       return mdio_set_flag(&phy->mdio, phy->mdio.prtad,
+                            MDIO_MMD_PMAPMD, MDIO_CTRL1,
+                            BMCR_LOOPBACK, enable);
+}
+
+static int aq100x_set_speed_duplex(struct cphy *phy, int speed, int duplex)
+{
+       /* no can do */
+       return -1;
+}
+
+static int aq100x_get_link_status(struct cphy *phy, int *link_ok,
+                                 int *speed, int *duplex, int *fc)
+{
+       int err;
+       unsigned int v;
+
+       if (link_ok) {
+               err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, AQ_LINK_STAT, &v);
+               if (err)
+                       return err;
+
+               *link_ok = v & 1;
+               if (!*link_ok)
+                       return 0;
+       }
+
+       err = t3_mdio_read(phy, MDIO_MMD_AN, AQ_ANEG_STAT, &v);
+       if (err)
+               return err;
+
+       if (speed) {
+               switch (v & 0x6) {
+               case 0x6:
+                       *speed = SPEED_10000;
+                       break;
+               case 0x4:
+                       *speed = SPEED_1000;
+                       break;
+               case 0x2:
+                       *speed = SPEED_100;
+                       break;
+               case 0x0:
+                       *speed = SPEED_10;
+                       break;
+               }
+       }
+
+       if (duplex)
+               *duplex = v & 1 ? DUPLEX_FULL : DUPLEX_HALF;
+
+       return 0;
+}
+
+static struct cphy_ops aq100x_ops = {
+       .reset             = aq100x_reset,
+       .intr_enable       = aq100x_intr_enable,
+       .intr_disable      = aq100x_intr_disable,
+       .intr_clear        = aq100x_intr_clear,
+       .intr_handler      = aq100x_intr_handler,
+       .autoneg_enable    = aq100x_autoneg_enable,
+       .autoneg_restart   = aq100x_autoneg_restart,
+       .advertise         = aq100x_advertise,
+       .set_loopback      = aq100x_set_loopback,
+       .set_speed_duplex  = aq100x_set_speed_duplex,
+       .get_link_status   = aq100x_get_link_status,
+       .power_down        = aq100x_power_down,
+       .mmds              = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
+};
+
+int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
+                      const struct mdio_ops *mdio_ops)
+{
+       unsigned int v, v2, gpio, wait;
+       int err;
+
+       cphy_init(phy, adapter, phy_addr, &aq100x_ops, mdio_ops,
+                 SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full |
+                 SUPPORTED_Autoneg | SUPPORTED_AUI, "1000/10GBASE-T");
+
+       /*
+        * The PHY has been out of reset ever since the system powered up.  So
+        * we do a hard reset over here.
+        */
+       gpio = phy_addr ? F_GPIO10_OUT_VAL : F_GPIO6_OUT_VAL;
+       t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, 0);
+       msleep(1);
+       t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, gpio, gpio);
+
+       /*
+        * Give it enough time to load the firmware and get ready for mdio.
+        */
+       msleep(1000);
+       wait = 500; /* in 10ms increments */
+       do {
+               err = t3_mdio_read(phy, MDIO_MMD_VEND1, MDIO_CTRL1, &v);
+               if (err || v == 0xffff) {
+
+                       /* Allow prep_adapter to succeed when ffff is read */
+
+                       CH_WARN(adapter, "PHY%d: reset failed (0x%x, 0x%x).\n",
+                               phy_addr, err, v);
+                       goto done;
+               }
+
+               v &= AQ_RESET;
+               if (v)
+                       msleep(10);
+       } while (v && --wait);
+       if (v) {
+               CH_WARN(adapter, "PHY%d: reset timed out (0x%x).\n",
+                       phy_addr, v);
+
+               goto done; /* let prep_adapter succeed */
+       }
+
+       /* Datasheet says 3s max but this has been observed */
+       wait = (500 - wait) * 10 + 1000;
+       if (wait > 3000)
+               CH_WARN(adapter, "PHY%d: reset took %ums\n", phy_addr, wait);
+
+       /* Firmware version check. */
+       t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_FW_VERSION, &v);
+       if (v != 30) {
+               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
+        * operations.
+        */
+       err = t3_mdio_read(phy, MDIO_MMD_VEND1, MDIO_CTRL1, &v);
+       if (err)
+               return err;
+       if (v & AQ_LOWPOWER) {
+               err = t3_mdio_change_bits(phy, MDIO_MMD_VEND1, MDIO_CTRL1,
+                                         AQ_LOWPOWER, 0);
+               if (err)
+                       return err;
+               msleep(10);
+       } else
+               CH_WARN(adapter, "PHY%d does not start in low power mode.\n",
+                       phy_addr);
+
+       /*
+        * Verify XAUI settings, but let prep succeed no matter what.
+        */
+       v = v2 = 0;
+       t3_mdio_read(phy, MDIO_MMD_PHYXS, AQ_XAUI_RX_CFG, &v);
+       t3_mdio_read(phy, MDIO_MMD_PHYXS, AQ_XAUI_TX_CFG, &v2);
+       if (v != 0x1b || v2 != 0x1b)
+               CH_WARN(adapter,
+                       "PHY%d: incorrect XAUI settings (0x%x, 0x%x).\n",
+                       phy_addr, v, v2);
+
+done:
+       return err;
+}
index 79a113b..d21b705 100644 (file)
@@ -802,8 +802,12 @@ int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter,
                        int phy_addr, const struct mdio_ops *mdio_ops);
 int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter,
                        int phy_addr, const struct mdio_ops *mdio_ops);
+int t3_ael2020_phy_prep(struct cphy *phy, struct adapter *adapter,
+                       int phy_addr, const struct mdio_ops *mdio_ops);
 int t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
                       const struct mdio_ops *mdio_ops);
 int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
                            int phy_addr, const struct mdio_ops *mdio_ops);
+int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter,
+                           int phy_addr, const struct mdio_ops *mdio_ops);
 #endif                         /* __CHELSIO_COMMON_H */
index 0b87fee..538dda4 100644 (file)
@@ -91,6 +91,8 @@ static const struct pci_device_id cxgb3_pci_tbl[] = {
        CH_DEVICE(0x31, 3),     /* T3B20 */
        CH_DEVICE(0x32, 1),     /* T3B02 */
        CH_DEVICE(0x35, 6),     /* T3C20-derived T3C10 */
+       CH_DEVICE(0x36, 3),     /* S320E-CR */
+       CH_DEVICE(0x37, 7),     /* N320E-G2 */
        {0,}
 };
 
@@ -431,40 +433,78 @@ static int init_tp_parity(struct adapter *adap)
        for (i = 0; i < 16; i++) {
                struct cpl_smt_write_req *req;
 
-               skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
+               skb = alloc_skb(sizeof(*req), GFP_KERNEL);
+               if (!skb)
+                       skb = adap->nofail_skb;
+               if (!skb)
+                       goto alloc_skb_fail;
+
                req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req));
                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->iff = i;
                t3_mgmt_tx(adap, skb);
+               if (skb == adap->nofail_skb) {
+                       await_mgmt_replies(adap, cnt, i + 1);
+                       adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
+                       if (!adap->nofail_skb)
+                               goto alloc_skb_fail;
+               }
        }
 
        for (i = 0; i < 2048; i++) {
                struct cpl_l2t_write_req *req;
 
-               skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
+               skb = alloc_skb(sizeof(*req), GFP_KERNEL);
+               if (!skb)
+                       skb = adap->nofail_skb;
+               if (!skb)
+                       goto alloc_skb_fail;
+
                req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req));
                memset(req, 0, sizeof(*req));
                req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
                OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i));
                req->params = htonl(V_L2T_W_IDX(i));
                t3_mgmt_tx(adap, skb);
+               if (skb == adap->nofail_skb) {
+                       await_mgmt_replies(adap, cnt, 16 + i + 1);
+                       adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
+                       if (!adap->nofail_skb)
+                               goto alloc_skb_fail;
+               }
        }
 
        for (i = 0; i < 2048; i++) {
                struct cpl_rte_write_req *req;
 
-               skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
+               skb = alloc_skb(sizeof(*req), GFP_KERNEL);
+               if (!skb)
+                       skb = adap->nofail_skb;
+               if (!skb)
+                       goto alloc_skb_fail;
+
                req = (struct cpl_rte_write_req *)__skb_put(skb, sizeof(*req));
                memset(req, 0, sizeof(*req));
                req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
                OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i));
                req->l2t_idx = htonl(V_L2T_W_IDX(i));
                t3_mgmt_tx(adap, skb);
+               if (skb == adap->nofail_skb) {
+                       await_mgmt_replies(adap, cnt, 16 + 2048 + i + 1);
+                       adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
+                       if (!adap->nofail_skb)
+                               goto alloc_skb_fail;
+               }
        }
 
-       skb = alloc_skb(sizeof(*greq), GFP_KERNEL | __GFP_NOFAIL);
+       skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
+       if (!skb)
+               skb = adap->nofail_skb;
+       if (!skb)
+               goto alloc_skb_fail;
+
        greq = (struct cpl_set_tcb_field *)__skb_put(skb, sizeof(*greq));
        memset(greq, 0, sizeof(*greq));
        greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
@@ -473,8 +513,17 @@ static int init_tp_parity(struct adapter *adap)
        t3_mgmt_tx(adap, skb);
 
        i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1);
+       if (skb == adap->nofail_skb) {
+               i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1);
+               adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
+       }
+
        t3_tp_set_offload_mode(adap, 0);
        return i;
+
+alloc_skb_fail:
+       t3_tp_set_offload_mode(adap, 0);
+       return -ENOMEM;
 }
 
 /**
@@ -869,7 +918,12 @@ static int send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
        struct mngt_pktsched_wr *req;
        int ret;
 
-       skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
+       skb = alloc_skb(sizeof(*req), GFP_KERNEL);
+       if (!skb)
+               skb = adap->nofail_skb;
+       if (!skb)
+               return -ENOMEM;
+
        req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req));
        req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
        req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
@@ -879,6 +933,12 @@ static int send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
        req->max = hi;
        req->binding = port;
        ret = t3_mgmt_tx(adap, skb);
+       if (skb == adap->nofail_skb) {
+               adap->nofail_skb = alloc_skb(sizeof(struct cpl_set_tcb_field),
+                                            GFP_KERNEL);
+               if (!adap->nofail_skb)
+                       ret = -ENOMEM;
+       }
 
        return ret;
 }
@@ -2451,14 +2511,16 @@ static void check_link_status(struct adapter *adapter)
        for_each_port(adapter, i) {
                struct net_device *dev = adapter->port[i];
                struct port_info *p = netdev_priv(dev);
+               int link_fault;
 
                spin_lock_irq(&adapter->work_lock);
-               if (p->link_fault) {
+               link_fault = p->link_fault;
+               spin_unlock_irq(&adapter->work_lock);
+
+               if (link_fault) {
                        t3_link_fault(adapter, i);
-                       spin_unlock_irq(&adapter->work_lock);
                        continue;
                }
-               spin_unlock_irq(&adapter->work_lock);
 
                if (!(p->phy.caps & SUPPORTED_IRQ) && netif_running(dev)) {
                        t3_xgm_intr_disable(adapter, i);
@@ -3016,6 +3078,14 @@ static int __devinit init_one(struct pci_dev *pdev,
                goto out_disable_device;
        }
 
+       adapter->nofail_skb =
+               alloc_skb(sizeof(struct cpl_set_tcb_field), GFP_KERNEL);
+       if (!adapter->nofail_skb) {
+               dev_err(&pdev->dev, "cannot allocate nofail buffer\n");
+               err = -ENOMEM;
+               goto out_free_adapter;
+       }
+
        adapter->regs = ioremap_nocache(mmio_start, mmio_len);
        if (!adapter->regs) {
                dev_err(&pdev->dev, "cannot map device registers\n");
@@ -3059,7 +3129,6 @@ static int __devinit init_one(struct pci_dev *pdev,
                netdev->mem_start = mmio_start;
                netdev->mem_end = mmio_start + mmio_len - 1;
                netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
-               netdev->features |= NETIF_F_LLTX;
                netdev->features |= NETIF_F_GRO;
                if (pci_using_dac)
                        netdev->features |= NETIF_F_HIGHDMA;
@@ -3173,6 +3242,8 @@ static void __devexit remove_one(struct pci_dev *pdev)
                                free_netdev(adapter->port[i]);
 
                iounmap(adapter->regs);
+               if (adapter->nofail_skb)
+                       kfree_skb(adapter->nofail_skb);
                kfree(adapter);
                pci_release_regions(pdev);
                pci_disable_device(pdev);
index 620d80b..f9f54b5 100644 (file)
@@ -566,13 +566,31 @@ static void t3_process_tid_release_list(struct work_struct *work)
                spin_unlock_bh(&td->tid_release_lock);
 
                skb = alloc_skb(sizeof(struct cpl_tid_release),
-                               GFP_KERNEL | __GFP_NOFAIL);
+                               GFP_KERNEL);
+               if (!skb)
+                       skb = td->nofail_skb;
+               if (!skb) {
+                       spin_lock_bh(&td->tid_release_lock);
+                       p->ctx = (void *)td->tid_release_list;
+                       td->tid_release_list = (struct t3c_tid_entry *)p;
+                       break;
+               }
                mk_tid_release(skb, p - td->tid_maps.tid_tab);
                cxgb3_ofld_send(tdev, skb);
                p->ctx = NULL;
+               if (skb == td->nofail_skb)
+                       td->nofail_skb =
+                               alloc_skb(sizeof(struct cpl_tid_release),
+                                       GFP_KERNEL);
                spin_lock_bh(&td->tid_release_lock);
        }
+       td->release_list_incomplete = (td->tid_release_list == NULL) ? 0 : 1;
        spin_unlock_bh(&td->tid_release_lock);
+
+       if (!td->nofail_skb)
+               td->nofail_skb =
+                       alloc_skb(sizeof(struct cpl_tid_release),
+                               GFP_KERNEL);
 }
 
 /* use ctx as a next pointer in the tid release list */
@@ -585,7 +603,7 @@ void cxgb3_queue_tid_release(struct t3cdev *tdev, unsigned int tid)
        p->ctx = (void *)td->tid_release_list;
        p->client = NULL;
        td->tid_release_list = p;
-       if (!p->ctx)
+       if (!p->ctx || td->release_list_incomplete)
                schedule_work(&td->tid_release_task);
        spin_unlock_bh(&td->tid_release_lock);
 }
@@ -1274,6 +1292,9 @@ int cxgb3_offload_activate(struct adapter *adapter)
        if (list_empty(&adapter_list))
                register_netevent_notifier(&nb);
 
+       t->nofail_skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_KERNEL);
+       t->release_list_incomplete = 0;
+
        add_adapter(adapter);
        return 0;
 
@@ -1298,6 +1319,8 @@ void cxgb3_offload_deactivate(struct adapter *adapter)
        T3C_DATA(tdev) = NULL;
        t3_free_l2t(L2DATA(tdev));
        L2DATA(tdev) = NULL;
+       if (t->nofail_skb)
+               kfree_skb(t->nofail_skb);
        kfree(t);
 }
 
index a8e8e5f..55945f4 100644 (file)
@@ -191,6 +191,9 @@ struct t3c_data {
        struct t3c_tid_entry *tid_release_list;
        spinlock_t tid_release_lock;
        struct work_struct tid_release_task;
+
+       struct sk_buff *nofail_skb;
+       unsigned int release_list_incomplete;
 };
 
 /*
index 73d569e..29c79eb 100644 (file)
@@ -355,7 +355,7 @@ static void clear_rx_desc(struct pci_dev *pdev, const struct sge_fl *q,
                (*d->pg_chunk.p_cnt)--;
                if (!*d->pg_chunk.p_cnt)
                        pci_unmap_page(pdev,
-                                      pci_unmap_addr(&d->pg_chunk, mapping),
+                                      d->pg_chunk.mapping,
                                       q->alloc_size, PCI_DMA_FROMDEVICE);
 
                put_page(d->pg_chunk.page);
@@ -454,7 +454,7 @@ static int alloc_pg_chunk(struct adapter *adapter, struct sge_fl *q,
                q->pg_chunk.offset = 0;
                mapping = pci_map_page(adapter->pdev, q->pg_chunk.page,
                                       0, q->alloc_size, PCI_DMA_FROMDEVICE);
-               pci_unmap_addr_set(&q->pg_chunk, mapping, mapping);
+               q->pg_chunk.mapping = mapping;
        }
        sd->pg_chunk = q->pg_chunk;
 
@@ -511,8 +511,7 @@ static int refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp)
 nomem:                         q->alloc_failed++;
                                break;
                        }
-                       mapping = pci_unmap_addr(&sd->pg_chunk, mapping) +
-                                                sd->pg_chunk.offset;
+                       mapping = sd->pg_chunk.mapping + sd->pg_chunk.offset;
                        pci_unmap_addr_set(sd, dma_addr, mapping);
 
                        add_one_rx_chunk(mapping, d, q->gen);
@@ -882,7 +881,7 @@ recycle:
        (*sd->pg_chunk.p_cnt)--;
        if (!*sd->pg_chunk.p_cnt)
                pci_unmap_page(adap->pdev,
-                              pci_unmap_addr(&sd->pg_chunk, mapping),
+                              sd->pg_chunk.mapping,
                               fl->alloc_size,
                               PCI_DMA_FROMDEVICE);
        if (!skb) {
@@ -1241,7 +1240,6 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
        q = &qs->txq[TXQ_ETH];
        txq = netdev_get_tx_queue(dev, qidx);
 
-       spin_lock(&q->lock);
        reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
 
        credits = q->size - q->in_use;
@@ -1252,7 +1250,6 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
                dev_err(&adap->pdev->dev,
                        "%s: Tx ring %u full while queue awake!\n",
                        dev->name, q->cntxt_id & 7);
-               spin_unlock(&q->lock);
                return NETDEV_TX_BUSY;
        }
 
@@ -1286,9 +1283,6 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
        if (vlan_tx_tag_present(skb) && pi->vlan_grp)
                qs->port_stats[SGE_PSTAT_VLANINS]++;
 
-       dev->trans_start = jiffies;
-       spin_unlock(&q->lock);
-
        /*
         * We do not use Tx completion interrupts to free DMAd Tx packets.
         * This is good for performamce but means that we rely on new Tx
@@ -2096,7 +2090,7 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs,
        (*sd->pg_chunk.p_cnt)--;
        if (!*sd->pg_chunk.p_cnt)
                pci_unmap_page(adap->pdev,
-                              pci_unmap_addr(&sd->pg_chunk, mapping),
+                              sd->pg_chunk.mapping,
                               fl->alloc_size,
                               PCI_DMA_FROMDEVICE);
 
@@ -2858,11 +2852,12 @@ static void sge_timer_tx(unsigned long data)
        unsigned int tbd[SGE_TXQ_PER_SET] = {0, 0};
        unsigned long next_period;
 
-       if (spin_trylock(&qs->txq[TXQ_ETH].lock)) {
-               tbd[TXQ_ETH] = reclaim_completed_tx(adap, &qs->txq[TXQ_ETH],
-                                                   TX_RECLAIM_TIMER_CHUNK);
-               spin_unlock(&qs->txq[TXQ_ETH].lock);
+       if (__netif_tx_trylock(qs->tx_q)) {
+                tbd[TXQ_ETH] = reclaim_completed_tx(adap, &qs->txq[TXQ_ETH],
+                                                     TX_RECLAIM_TIMER_CHUNK);
+               __netif_tx_unlock(qs->tx_q);
        }
+
        if (spin_trylock(&qs->txq[TXQ_OFLD].lock)) {
                tbd[TXQ_OFLD] = reclaim_completed_tx(adap, &qs->txq[TXQ_OFLD],
                                                     TX_RECLAIM_TIMER_CHUNK);
@@ -2870,8 +2865,8 @@ static void sge_timer_tx(unsigned long data)
        }
 
        next_period = TX_RECLAIM_PERIOD >>
-                     (max(tbd[TXQ_ETH], tbd[TXQ_OFLD]) /
-                      TX_RECLAIM_TIMER_CHUNK);
+                      (max(tbd[TXQ_ETH], tbd[TXQ_OFLD]) /
+                      TX_RECLAIM_TIMER_CHUNK);
        mod_timer(&qs->tx_reclaim_timer, jiffies + next_period);
 }
 
index fc7db8a..870d449 100644 (file)
@@ -526,6 +526,11 @@ static const struct adapter_info t3_adap_info[] = {
         F_GPIO10_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL,
         { S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
         &mi1_mdio_ext_ops, "Chelsio T310" },
+       {1, 0, 0,
+        F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN |
+        F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL,
+        { S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
+        &mi1_mdio_ext_ops, "Chelsio N320E-G2" },
 };
 
 /*
@@ -552,6 +557,8 @@ static const struct port_type_info port_types[] = {
        { t3_qt2045_phy_prep },
        { t3_ael1006_phy_prep },
        { NULL },
+       { t3_aq100x_phy_prep },
+       { t3_ael2020_phy_prep },
 };
 
 #define VPD_ENTRY(name, len) \
@@ -1281,6 +1288,11 @@ void t3_link_fault(struct adapter *adapter, int port_id)
                                 A_XGM_INT_STATUS + mac->offset);
        link_fault &= F_LINKFAULTCHANGE;
 
+       link_ok = lc->link_ok;
+       speed = lc->speed;
+       duplex = lc->duplex;
+       fc = lc->fc;
+
        phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);
 
        if (link_fault) {
index 7bf963e..9d0bd9d 100644 (file)
 #define DRV_DESC "Chelsio T3 Network Driver"
 #define DRV_NAME "cxgb3"
 /* Driver version */
-#define DRV_VERSION "1.1.2-ko"
+#define DRV_VERSION "1.1.3-ko"
 
 /* Firmware version */
 #define FW_VERSION_MAJOR 7
-#define FW_VERSION_MINOR 1
+#define FW_VERSION_MINOR 4
 #define FW_VERSION_MICRO 0
 #endif                         /* __CHELSIO_VERSION_H */
index cf689a0..0e9b9f9 100644 (file)
@@ -1819,7 +1819,6 @@ static int emac_dev_setmac_addr(struct net_device *ndev, void *addr)
        struct emac_rxch *rxch = priv->rxch[EMAC_DEF_RX_CH];
        struct device *emac_dev = &priv->ndev->dev;
        struct sockaddr *sa = addr;
-       DECLARE_MAC_BUF(mac);
 
        /* Store mac addr in priv and rx channel and set it in EMAC hw */
        memcpy(priv->mac_addr, sa->sa_data, ndev->addr_len);
@@ -1828,8 +1827,8 @@ static int emac_dev_setmac_addr(struct net_device *ndev, void *addr)
        emac_setmac(priv, EMAC_DEF_RX_CH, rxch->mac_addr);
 
        if (netif_msg_drv(priv))
-               dev_notice(emac_dev, "DaVinci EMAC: emac_dev_setmac_addr %s\n",
-                          print_mac(mac, priv->mac_addr));
+               dev_notice(emac_dev, "DaVinci EMAC: emac_dev_setmac_addr %pM\n",
+                                       priv->mac_addr);
 
        return 0;
 }
@@ -2683,11 +2682,10 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
        ndev->irq = res->start;
 
        if (!is_valid_ether_addr(priv->mac_addr)) {
-               DECLARE_MAC_BUF(buf);
                /* Use random MAC if none passed */
                random_ether_addr(priv->mac_addr);
-               printk(KERN_WARNING "%s: using random MAC addr: %s\n",
-                       __func__, print_mac(buf, priv->mac_addr));
+               printk(KERN_WARNING "%s: using random MAC addr: %pM\n",
+                               __func__, priv->mac_addr);
        }
 
        ndev->netdev_ops = &emac_netdev_ops;
index b62405a..2b22e58 100644 (file)
@@ -895,6 +895,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
        struct lance_private *lp = netdev_priv(dev);
        volatile struct lance_regs *ll = lp->ll;
        volatile u16 *ib = (volatile u16 *)dev->mem_start;
+       unsigned long flags;
        int entry, len;
 
        len = skb->len;
@@ -907,6 +908,8 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        dev->stats.tx_bytes += len;
 
+       spin_lock_irqsave(&lp->lock, flags);
+
        entry = lp->tx_new;
        *lib_ptr(ib, btx_ring[entry].length, lp->type) = (-len);
        *lib_ptr(ib, btx_ring[entry].misc, lp->type) = 0;
@@ -925,6 +928,8 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Kick the lance: transmit now */
        writereg(&ll->rdp, LE_C0_INEA | LE_C0_TDMD);
 
+       spin_unlock_irqrestore(&lp->lock, flags);
+
        dev->trans_start = jiffies;
        dev_kfree_skb(skb);
 
index 4a1b554..895d721 100644 (file)
@@ -539,7 +539,7 @@ rio_tx_timeout (struct net_device *dev)
                dev->name, readl (ioaddr + TxStatus));
        rio_free_tx(dev, 0);
        dev->if_port = 0;
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
 }
 
  /* allocate and initialize Tx and Rx descriptors */
@@ -610,7 +610,7 @@ start_xmit (struct sk_buff *skb, struct net_device *dev)
 
        if (np->link_status == 0) {     /* Link Down */
                dev_kfree_skb(skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
        ioaddr = dev->base_addr;
        entry = np->cur_tx % TX_RING_SIZE;
@@ -665,9 +665,7 @@ start_xmit (struct sk_buff *skb, struct net_device *dev)
                writel (0, dev->base_addr + TFDListPtr1);
        }
 
-       /* NETDEV WATCHDOG timer */
-       dev->trans_start = jiffies;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static irqreturn_t
index 0f9ee13..119dc53 100644 (file)
  *     FIXES:
  * 2005/12/02 - Michael O'Donnell <Michael.ODonnell at stratus dot com>
  *     - Stratus87247: protect MDI control register manipulations
+ * 2009/06/01 - Andreas Mohr <andi at lisas dot de>
+ *      - add clean lowlevel I/O emulation for cards with MII-lacking PHYs
  */
 
 #include <linux/module.h>
@@ -372,6 +374,7 @@ enum eeprom_op {
 
 enum eeprom_offsets {
        eeprom_cnfg_mdix  = 0x03,
+       eeprom_phy_iface  = 0x06,
        eeprom_id         = 0x0A,
        eeprom_config_asf = 0x0D,
        eeprom_smbus_addr = 0x90,
@@ -381,6 +384,18 @@ enum eeprom_cnfg_mdix {
        eeprom_mdix_enabled = 0x0080,
 };
 
+enum eeprom_phy_iface {
+       NoSuchPhy = 0,
+       I82553AB,
+       I82553C,
+       I82503,
+       DP83840,
+       S80C240,
+       S80C24,
+       I82555,
+       DP83840A = 10,
+};
+
 enum eeprom_id {
        eeprom_id_wol = 0x0020,
 };
@@ -545,6 +560,7 @@ struct nic {
        u32 msg_enable                          ____cacheline_aligned;
        struct net_device *netdev;
        struct pci_dev *pdev;
+       u16 (*mdio_ctrl)(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data);
 
        struct rx *rxs                          ____cacheline_aligned;
        struct rx *rx_to_use;
@@ -899,7 +915,21 @@ err_unlock:
        return err;
 }
 
-static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data)
+static int mdio_read(struct net_device *netdev, int addr, int reg)
+{
+       struct nic *nic = netdev_priv(netdev);
+       return nic->mdio_ctrl(nic, addr, mdi_read, reg, 0);
+}
+
+static void mdio_write(struct net_device *netdev, int addr, int reg, int data)
+{
+       struct nic *nic = netdev_priv(netdev);
+
+       nic->mdio_ctrl(nic, addr, mdi_write, reg, data);
+}
+
+/* the standard mdio_ctrl() function for usual MII-compliant hardware */
+static u16 mdio_ctrl_hw(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data)
 {
        u32 data_out = 0;
        unsigned int i;
@@ -938,30 +968,83 @@ static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data)
        return (u16)data_out;
 }
 
-static int mdio_read(struct net_device *netdev, int addr, int reg)
-{
-       return mdio_ctrl(netdev_priv(netdev), addr, mdi_read, reg, 0);
+/* slightly tweaked mdio_ctrl() function for phy_82552_v specifics */
+static u16 mdio_ctrl_phy_82552_v(struct nic *nic,
+                                u32 addr,
+                                u32 dir,
+                                u32 reg,
+                                u16 data)
+{
+       if ((reg == MII_BMCR) && (dir == mdi_write)) {
+               if (data & (BMCR_ANRESTART | BMCR_ANENABLE)) {
+                       u16 advert = mdio_read(nic->netdev, nic->mii.phy_id,
+                                                       MII_ADVERTISE);
+
+                       /*
+                        * Workaround Si issue where sometimes the part will not
+                        * autoneg to 100Mbps even when advertised.
+                        */
+                       if (advert & ADVERTISE_100FULL)
+                               data |= BMCR_SPEED100 | BMCR_FULLDPLX;
+                       else if (advert & ADVERTISE_100HALF)
+                               data |= BMCR_SPEED100;
+               }
+       }
+       return mdio_ctrl_hw(nic, addr, dir, reg, data);
 }
 
-static void mdio_write(struct net_device *netdev, int addr, int reg, int data)
-{
-       struct nic *nic = netdev_priv(netdev);
-
-       if  ((nic->phy == phy_82552_v) && (reg == MII_BMCR) &&
-            (data & (BMCR_ANRESTART | BMCR_ANENABLE))) {
-               u16 advert = mdio_read(netdev, nic->mii.phy_id, MII_ADVERTISE);
-
-               /*
-                * Workaround Si issue where sometimes the part will not
-                * autoneg to 100Mbps even when advertised.
-                */
-               if (advert & ADVERTISE_100FULL)
-                       data |= BMCR_SPEED100 | BMCR_FULLDPLX;
-               else if (advert & ADVERTISE_100HALF)
-                       data |= BMCR_SPEED100;
+/* Fully software-emulated mdio_ctrl() function for cards without
+ * MII-compliant PHYs.
+ * For now, this is mainly geared towards 80c24 support; in case of further
+ * requirements for other types (i82503, ...?) either extend this mechanism
+ * or split it, whichever is cleaner.
+ */
+static u16 mdio_ctrl_phy_mii_emulated(struct nic *nic,
+                                     u32 addr,
+                                     u32 dir,
+                                     u32 reg,
+                                     u16 data)
+{
+       /* might need to allocate a netdev_priv'ed register array eventually
+        * to be able to record state changes, but for now
+        * some fully hardcoded register handling ought to be ok I guess. */
+
+       if (dir == mdi_read) {
+               switch (reg) {
+               case MII_BMCR:
+                       /* Auto-negotiation, right? */
+                       return  BMCR_ANENABLE |
+                               BMCR_FULLDPLX;
+               case MII_BMSR:
+                       return  BMSR_LSTATUS /* for mii_link_ok() */ |
+                               BMSR_ANEGCAPABLE |
+                               BMSR_10FULL;
+               case MII_ADVERTISE:
+                       /* 80c24 is a "combo card" PHY, right? */
+                       return  ADVERTISE_10HALF |
+                               ADVERTISE_10FULL;
+               default:
+                       DPRINTK(HW, DEBUG,
+               "%s:addr=%d, reg=%d, data=0x%04X: unimplemented emulation!\n",
+               dir == mdi_read ? "READ" : "WRITE", addr, reg, data);
+                       return 0xFFFF;
+               }
+       } else {
+               switch (reg) {
+               default:
+                       DPRINTK(HW, DEBUG,
+               "%s:addr=%d, reg=%d, data=0x%04X: unimplemented emulation!\n",
+               dir == mdi_read ? "READ" : "WRITE", addr, reg, data);
+                       return 0xFFFF;
+               }
        }
-
-       mdio_ctrl(netdev_priv(netdev), addr, mdi_write, reg, data);
+}
+static inline int e100_phy_supports_mii(struct nic *nic)
+{
+       /* for now, just check it by comparing whether we
+          are using MII software emulation.
+       */
+       return (nic->mdio_ctrl != mdio_ctrl_phy_mii_emulated);
 }
 
 static void e100_get_defaults(struct nic *nic)
@@ -1013,7 +1096,8 @@ static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb)
        config->standard_stat_counter = 0x1;    /* 1=standard, 0=extended */
        config->rx_discard_short_frames = 0x1;  /* 1=discard, 0=pass */
        config->tx_underrun_retry = 0x3;        /* # of underrun retries */
-       config->mii_mode = 0x1;                 /* 1=MII mode, 0=503 mode */
+       if (e100_phy_supports_mii(nic))
+               config->mii_mode = 1;           /* 1=MII mode, 0=i82503 mode */
        config->pad10 = 0x6;
        config->no_source_addr_insertion = 0x1; /* 1=no, 0=yes */
        config->preamble_length = 0x2;          /* 0=1, 1=3, 2=7, 3=15 bytes */
@@ -1270,6 +1354,42 @@ static void e100_dump(struct nic *nic, struct cb *cb, struct sk_buff *skb)
                offsetof(struct mem, dump_buf));
 }
 
+static int e100_phy_check_without_mii(struct nic *nic)
+{
+       u8 phy_type;
+       int without_mii;
+
+       phy_type = (nic->eeprom[eeprom_phy_iface] >> 8) & 0x0f;
+
+       switch (phy_type) {
+       case NoSuchPhy: /* Non-MII PHY; UNTESTED! */
+       case I82503: /* Non-MII PHY; UNTESTED! */
+       case S80C24: /* Non-MII PHY; tested and working */
+               /* paragraph from the FreeBSD driver, "FXP_PHY_80C24":
+                * The Seeq 80c24 AutoDUPLEX(tm) Ethernet Interface Adapter
+                * doesn't have a programming interface of any sort.  The
+                * media is sensed automatically based on how the link partner
+                * is configured.  This is, in essence, manual configuration.
+                */
+               DPRINTK(PROBE, INFO,
+                        "found MII-less i82503 or 80c24 or other PHY\n");
+
+               nic->mdio_ctrl = mdio_ctrl_phy_mii_emulated;
+               nic->mii.phy_id = 0; /* is this ok for an MII-less PHY? */
+
+               /* these might be needed for certain MII-less cards...
+                * nic->flags |= ich;
+                * nic->flags |= ich_10h_workaround; */
+
+               without_mii = 1;
+               break;
+       default:
+               without_mii = 0;
+               break;
+       }
+       return without_mii;
+}
+
 #define NCONFIG_AUTO_SWITCH    0x0080
 #define MII_NSC_CONG           MII_RESV1
 #define NSC_CONG_ENABLE                0x0100
@@ -1290,9 +1410,21 @@ static int e100_phy_init(struct nic *nic)
                if (!((bmcr == 0xFFFF) || ((stat == 0) && (bmcr == 0))))
                        break;
        }
-       DPRINTK(HW, DEBUG, "phy_addr = %d\n", nic->mii.phy_id);
-       if (addr == 32)
-               return -EAGAIN;
+       if (addr == 32) {
+               /* uhoh, no PHY detected: check whether we seem to be some
+                * weird, rare variant which is *known* to not have any MII.
+                * But do this AFTER MII checking only, since this does
+                * lookup of EEPROM values which may easily be unreliable. */
+               if (e100_phy_check_without_mii(nic))
+                       return 0; /* simply return and hope for the best */
+               else {
+                       /* for unknown cases log a fatal error */
+                       DPRINTK(HW, ERR,
+                               "Failed to locate any known PHY, aborting.\n");
+                       return -EAGAIN;
+               }
+       } else
+               DPRINTK(HW, DEBUG, "phy_addr = %d\n", nic->mii.phy_id);
 
        /* Isolate all the PHY ids */
        for (addr = 0; addr < 32; addr++)
@@ -1320,6 +1452,9 @@ static int e100_phy_init(struct nic *nic)
        if (nic->phy == phy_82552_v) {
                u16 advert = mdio_read(netdev, nic->mii.phy_id, MII_ADVERTISE);
 
+               /* assign special tweaked mdio_ctrl() function */
+               nic->mdio_ctrl = mdio_ctrl_phy_82552_v;
+
                /* Workaround Si not advertising flow-control during autoneg */
                advert |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
                mdio_write(netdev, nic->mii.phy_id, MII_ADVERTISE, advert);
@@ -2585,6 +2720,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
        nic->netdev = netdev;
        nic->pdev = pdev;
        nic->msg_enable = (1 << debug) - 1;
+       nic->mdio_ctrl = mdio_ctrl_hw;
        pci_set_drvdata(pdev, netdev);
 
        if ((err = pci_enable_device(pdev))) {
@@ -2822,12 +2958,13 @@ static pci_ers_result_t e100_io_error_detected(struct pci_dev *pdev, pci_channel
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct nic *nic = netdev_priv(netdev);
 
-       /* Similar to calling e100_down(), but avoids adapter I/O. */
-       e100_close(netdev);
-
-       /* Detach; put netif into a state similar to hotplug unplug. */
-       napi_enable(&nic->napi);
        netif_device_detach(netdev);
+
+       if (state == pci_channel_io_perm_failure)
+               return PCI_ERS_RESULT_DISCONNECT;
+
+       if (netif_running(netdev))
+               e100_down(nic);
        pci_disable_device(pdev);
 
        /* Request a slot reset. */
index 9a32d0c..8d36743 100644 (file)
@@ -2330,7 +2330,8 @@ static void e1000_set_rx_mode(struct net_device *netdev)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
-       struct dev_addr_list *uc_ptr;
+       struct netdev_hw_addr *ha;
+       bool use_uc = false;
        struct dev_addr_list *mc_ptr;
        u32 rctl;
        u32 hash_value;
@@ -2369,12 +2370,11 @@ static void e1000_set_rx_mode(struct net_device *netdev)
                        rctl |= E1000_RCTL_VFE;
        }
 
-       uc_ptr = NULL;
        if (netdev->uc_count > rar_entries - 1) {
                rctl |= E1000_RCTL_UPE;
        } else if (!(netdev->flags & IFF_PROMISC)) {
                rctl &= ~E1000_RCTL_UPE;
-               uc_ptr = netdev->uc_list;
+               use_uc = true;
        }
 
        ew32(RCTL, rctl);
@@ -2392,13 +2392,20 @@ static void e1000_set_rx_mode(struct net_device *netdev)
         * if there are not 14 addresses, go ahead and clear the filters
         * -- with 82571 controllers only 0-13 entries are filled here
         */
+       i = 1;
+       if (use_uc)
+               list_for_each_entry(ha, &netdev->uc_list, list) {
+                       if (i == rar_entries)
+                               break;
+                       e1000_rar_set(hw, ha->addr, i++);
+               }
+
+       WARN_ON(i == rar_entries);
+
        mc_ptr = netdev->mc_list;
 
-       for (i = 1; i < rar_entries; i++) {
-               if (uc_ptr) {
-                       e1000_rar_set(hw, uc_ptr->da_addr, i);
-                       uc_ptr = uc_ptr->next;
-               } else if (mc_ptr) {
+       for (; i < rar_entries; i++) {
+               if (mc_ptr) {
                        e1000_rar_set(hw, mc_ptr->da_addr, i);
                        mc_ptr = mc_ptr->next;
                } else {
@@ -2408,7 +2415,6 @@ static void e1000_set_rx_mode(struct net_device *netdev)
                        E1000_WRITE_FLUSH();
                }
        }
-       WARN_ON(uc_ptr != NULL);
 
        /* load any remaining addresses into the hash table */
 
@@ -2992,7 +2998,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
                        size -= 4;
 
                buffer_info->length = size;
-               buffer_info->dma = map[0] + offset;
+               buffer_info->dma = skb_shinfo(skb)->dma_head + offset;
                buffer_info->time_stamp = jiffies;
                buffer_info->next_to_watch = i;
 
@@ -3033,7 +3039,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
                                size -= 4;
 
                        buffer_info->length = size;
-                       buffer_info->dma = map[f + 1] + offset;
+                       buffer_info->dma = map[f] + offset;
                        buffer_info->time_stamp = jiffies;
                        buffer_info->next_to_watch = i;
 
@@ -3365,7 +3371,6 @@ static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 
        if (count) {
                e1000_tx_queue(adapter, tx_ring, tx_flags, count);
-               netdev->trans_start = jiffies;
                /* Make sure there is space in the ring for the next send. */
                e1000_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 2);
 
@@ -4030,8 +4035,9 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
                                 PCI_DMA_FROMDEVICE);
 
                length = le16_to_cpu(rx_desc->length);
-
-               if (unlikely(!(status & E1000_RXD_STAT_EOP))) {
+               /* !EOP means multiple descriptors were used to store a single
+                * packet, also make sure the frame isn't just CRC only */
+               if (unlikely(!(status & E1000_RXD_STAT_EOP) || (length <= 4))) {
                        /* All receives must fit into a single buffer */
                        E1000_DBG("%s: Receive packet consumed multiple"
                                  " buffers\n", netdev->name);
index 6c01a20..b53b40b 100644 (file)
@@ -71,6 +71,7 @@ static s32 e1000_setup_link_82571(struct e1000_hw *hw);
 static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw);
 static bool e1000_check_mng_mode_82574(struct e1000_hw *hw);
 static s32 e1000_led_on_82574(struct e1000_hw *hw);
+static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw);
 
 /**
  *  e1000_init_phy_params_82571 - Init PHY func ptrs.
@@ -212,6 +213,9 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter)
        struct e1000_hw *hw = &adapter->hw;
        struct e1000_mac_info *mac = &hw->mac;
        struct e1000_mac_operations *func = &mac->ops;
+       u32 swsm = 0;
+       u32 swsm2 = 0;
+       bool force_clear_smbi = false;
 
        /* Set media type */
        switch (adapter->pdev->device) {
@@ -276,6 +280,50 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter)
                break;
        }
 
+       /*
+        * Ensure that the inter-port SWSM.SMBI lock bit is clear before
+        * first NVM or PHY acess. This should be done for single-port
+        * devices, and for one port only on dual-port devices so that
+        * for those devices we can still use the SMBI lock to synchronize
+        * inter-port accesses to the PHY & NVM.
+        */
+       switch (hw->mac.type) {
+       case e1000_82571:
+       case e1000_82572:
+               swsm2 = er32(SWSM2);
+
+               if (!(swsm2 & E1000_SWSM2_LOCK)) {
+                       /* Only do this for the first interface on this card */
+                       ew32(SWSM2,
+                           swsm2 | E1000_SWSM2_LOCK);
+                       force_clear_smbi = true;
+               } else
+                       force_clear_smbi = false;
+               break;
+       default:
+               force_clear_smbi = true;
+               break;
+       }
+
+       if (force_clear_smbi) {
+               /* Make sure SWSM.SMBI is clear */
+               swsm = er32(SWSM);
+               if (swsm & E1000_SWSM_SMBI) {
+                       /* This bit should not be set on a first interface, and
+                        * indicates that the bootagent or EFI code has
+                        * improperly left this bit enabled
+                        */
+                       hw_dbg(hw, "Please update your 82571 Bootagent\n");
+               }
+               ew32(SWSM, swsm & ~E1000_SWSM_SMBI);
+       }
+
+       /*
+        * Initialze device specific counter of SMBI acquisition
+        * timeouts.
+        */
+        hw->dev_spec.e82571.smb_counter = 0;
+
        return 0;
 }
 
@@ -341,8 +389,10 @@ static s32 e1000_get_variants_82571(struct e1000_adapter *adapter)
                        if (e1000_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1,
                                       &eeprom_data) < 0)
                                break;
-                       if (eeprom_data & NVM_WORD1A_ASPM_MASK)
-                               adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES;
+                       if (!(eeprom_data & NVM_WORD1A_ASPM_MASK)) {
+                               adapter->flags |= FLAG_HAS_JUMBO_FRAMES;
+                               adapter->max_hw_frame_size = DEFAULT_JUMBO;
+                       }
                }
                break;
        default:
@@ -411,11 +461,37 @@ static s32 e1000_get_phy_id_82571(struct e1000_hw *hw)
 static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw)
 {
        u32 swsm;
-       s32 timeout = hw->nvm.word_size + 1;
+       s32 sw_timeout = hw->nvm.word_size + 1;
+       s32 fw_timeout = hw->nvm.word_size + 1;
        s32 i = 0;
 
+       /*
+        * If we have timedout 3 times on trying to acquire
+        * the inter-port SMBI semaphore, there is old code
+        * operating on the other port, and it is not
+        * releasing SMBI. Modify the number of times that
+        * we try for the semaphore to interwork with this
+        * older code.
+        */
+       if (hw->dev_spec.e82571.smb_counter > 2)
+               sw_timeout = 1;
+
+       /* Get the SW semaphore */
+       while (i < sw_timeout) {
+               swsm = er32(SWSM);
+               if (!(swsm & E1000_SWSM_SMBI))
+                       break;
+
+               udelay(50);
+               i++;
+       }
+
+       if (i == sw_timeout) {
+               hw_dbg(hw, "Driver can't access device - SMBI bit is set.\n");
+               hw->dev_spec.e82571.smb_counter++;
+       }
        /* Get the FW semaphore. */
-       for (i = 0; i < timeout; i++) {
+       for (i = 0; i < fw_timeout; i++) {
                swsm = er32(SWSM);
                ew32(SWSM, swsm | E1000_SWSM_SWESMBI);
 
@@ -426,9 +502,9 @@ static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw)
                udelay(50);
        }
 
-       if (i == timeout) {
+       if (i == fw_timeout) {
                /* Release semaphores */
-               e1000e_put_hw_semaphore(hw);
+               e1000_put_hw_semaphore_82571(hw);
                hw_dbg(hw, "Driver can't access the NVM\n");
                return -E1000_ERR_NVM;
        }
@@ -447,9 +523,7 @@ static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw)
        u32 swsm;
 
        swsm = er32(SWSM);
-
-       swsm &= ~E1000_SWSM_SWESMBI;
-
+       swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
        ew32(SWSM, swsm);
 }
 
@@ -1585,6 +1659,7 @@ static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw)
 static struct e1000_mac_operations e82571_mac_ops = {
        /* .check_mng_mode: mac type dependent */
        /* .check_for_link: media type dependent */
+       .id_led_init            = e1000e_id_led_init,
        .cleanup_led            = e1000e_cleanup_led_generic,
        .clear_hw_cntrs         = e1000_clear_hw_cntrs_82571,
        .get_bus_info           = e1000e_get_bus_info_pcie,
@@ -1596,6 +1671,7 @@ static struct e1000_mac_operations e82571_mac_ops = {
        .init_hw                = e1000_init_hw_82571,
        .setup_link             = e1000_setup_link_82571,
        /* .setup_physical_interface: media type dependent */
+       .setup_led              = e1000e_setup_led_generic,
 };
 
 static struct e1000_phy_operations e82_phy_ops_igp = {
@@ -1672,6 +1748,7 @@ struct e1000_info e1000_82571_info = {
                                  | FLAG_TARC_SPEED_MODE_BIT /* errata */
                                  | FLAG_APME_CHECK_PORT_B,
        .pba                    = 38,
+       .max_hw_frame_size      = DEFAULT_JUMBO,
        .get_variants           = e1000_get_variants_82571,
        .mac_ops                = &e82571_mac_ops,
        .phy_ops                = &e82_phy_ops_igp,
@@ -1688,6 +1765,7 @@ struct e1000_info e1000_82572_info = {
                                  | FLAG_HAS_CTRLEXT_ON_LOAD
                                  | FLAG_TARC_SPEED_MODE_BIT, /* errata */
        .pba                    = 38,
+       .max_hw_frame_size      = DEFAULT_JUMBO,
        .get_variants           = e1000_get_variants_82571,
        .mac_ops                = &e82571_mac_ops,
        .phy_ops                = &e82_phy_ops_igp,
@@ -1706,6 +1784,7 @@ struct e1000_info e1000_82573_info = {
                                  | FLAG_HAS_ERT
                                  | FLAG_HAS_SWSM_ON_LOAD,
        .pba                    = 20,
+       .max_hw_frame_size      = ETH_FRAME_LEN + ETH_FCS_LEN,
        .get_variants           = e1000_get_variants_82571,
        .mac_ops                = &e82571_mac_ops,
        .phy_ops                = &e82_phy_ops_m88,
@@ -1724,6 +1803,7 @@ struct e1000_info e1000_82574_info = {
                                  | FLAG_HAS_AMT
                                  | FLAG_HAS_CTRLEXT_ON_LOAD,
        .pba                    = 20,
+       .max_hw_frame_size      = ETH_FRAME_LEN + ETH_FCS_LEN,
        .get_variants           = e1000_get_variants_82571,
        .mac_ops                = &e82571_mac_ops,
        .phy_ops                = &e82_phy_ops_bm,
@@ -1740,6 +1820,7 @@ struct e1000_info e1000_82583_info = {
                                  | FLAG_HAS_AMT
                                  | FLAG_HAS_CTRLEXT_ON_LOAD,
        .pba                    = 20,
+       .max_hw_frame_size      = DEFAULT_JUMBO,
        .get_variants           = e1000_get_variants_82571,
        .mac_ops                = &e82571_mac_ops,
        .phy_ops                = &e82_phy_ops_bm,
index 243aa49..8890c97 100644 (file)
@@ -56,6 +56,7 @@
 /* Wake Up Control */
 #define E1000_WUC_APME       0x00000001 /* APM Enable */
 #define E1000_WUC_PME_EN     0x00000002 /* PME Enable */
+#define E1000_WUC_PHY_WAKE   0x00000100 /* if PHY supports wakeup */
 
 /* Wake Up Filter Control */
 #define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
 #define E1000_WUFC_BC   0x00000010 /* Broadcast Wakeup Enable */
 #define E1000_WUFC_ARP  0x00000020 /* ARP Request Packet Wakeup Enable */
 
+/* Wake Up Status */
+#define E1000_WUS_LNKC         E1000_WUFC_LNKC
+#define E1000_WUS_MAG          E1000_WUFC_MAG
+#define E1000_WUS_EX           E1000_WUFC_EX
+#define E1000_WUS_MC           E1000_WUFC_MC
+#define E1000_WUS_BC           E1000_WUFC_BC
+
 /* Extended Device Control */
 #define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Definable Pin 7 */
 #define E1000_CTRL_EXT_EE_RST    0x00002000 /* Reinitialize from EEPROM */
@@ -77,6 +85,7 @@
 #define E1000_CTRL_EXT_IAME           0x08000000 /* Interrupt acknowledge Auto-mask */
 #define E1000_CTRL_EXT_INT_TIMER_CLR  0x20000000 /* Clear Interrupt timers after IMS clear */
 #define E1000_CTRL_EXT_PBA_CLR        0x80000000 /* PBA Clear */
+#define E1000_CTRL_EXT_PHYPDEN        0x00100000
 
 /* Receive Descriptor bit definitions */
 #define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
 #define E1000_RCTL_DTYP_PS        0x00000400    /* Packet Split descriptor */
 #define E1000_RCTL_RDMTS_HALF     0x00000000    /* Rx desc min threshold size */
 #define E1000_RCTL_MO_SHIFT       12            /* multicast offset shift */
+#define E1000_RCTL_MO_3           0x00003000    /* multicast offset 15:4 */
 #define E1000_RCTL_BAM            0x00008000    /* broadcast enable */
 /* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
 #define E1000_RCTL_SZ_2048        0x00000000    /* Rx buffer size 2048 */
 #define E1000_RCTL_VFE            0x00040000    /* vlan filter enable */
 #define E1000_RCTL_CFIEN          0x00080000    /* canonical form enable */
 #define E1000_RCTL_CFI            0x00100000    /* canonical form indicator */
+#define E1000_RCTL_PMCF           0x00800000    /* pass MAC control frames */
 #define E1000_RCTL_BSEX           0x02000000    /* Buffer size extension */
 #define E1000_RCTL_SECRC          0x04000000    /* Strip Ethernet CRC */
 
 #define AUTONEG_ADVERTISE_SPEED_DEFAULT   E1000_ALL_SPEED_DUPLEX
 
 /* LED Control */
+#define E1000_PHY_LED0_MODE_MASK          0x00000007
+#define E1000_PHY_LED0_IVRT               0x00000008
+#define E1000_PHY_LED0_MASK               0x0000001F
+
 #define E1000_LEDCTL_LED0_MODE_MASK       0x0000000F
 #define E1000_LEDCTL_LED0_MODE_SHIFT      0
 #define E1000_LEDCTL_LED0_IVRT            0x00000040
 #define E1000_LEDCTL_LED0_BLINK           0x00000080
 
+#define E1000_LEDCTL_MODE_LINK_UP       0x2
 #define E1000_LEDCTL_MODE_LED_ON        0xE
 #define E1000_LEDCTL_MODE_LED_OFF       0xF
 
 #define E1000_SWSM_SWESMBI      0x00000002 /* FW Semaphore bit */
 #define E1000_SWSM_DRV_LOAD     0x00000008 /* Driver Loaded Bit */
 
+#define E1000_SWSM2_LOCK        0x00000002 /* Secondary driver semaphore bit */
+
 /* Interrupt Cause Read */
 #define E1000_ICR_TXDW          0x00000001 /* Transmit desc written back */
 #define E1000_ICR_LSC           0x00000004 /* Link Status Change */
 #define AUTO_READ_DONE_TIMEOUT      10
 
 /* Flow Control */
+#define E1000_FCRTH_RTH  0x0000FFF8     /* Mask Bits[15:3] for RTH */
+#define E1000_FCRTL_RTL  0x0000FFF8     /* Mask Bits[15:3] for RTL */
 #define E1000_FCRTL_XONE 0x80000000     /* Enable XON frame transmission */
 
 /* Transmit Configuration Word */
 #define IFE_C_E_PHY_ID       0x02A80310
 #define BME1000_E_PHY_ID     0x01410CB0
 #define BME1000_E_PHY_ID_R2  0x01410CB1
+#define I82577_E_PHY_ID      0x01540050
+#define I82578_E_PHY_ID      0x004DD040
 
 /* M88E1000 Specific Registers */
 #define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
 #define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK  0x0E00
 #define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X    0x0800
 
+#define I82578_EPSCR_DOWNSHIFT_ENABLE          0x0020
+#define I82578_EPSCR_DOWNSHIFT_COUNTER_MASK    0x001C
+
 /* BME1000 PHY Specific Control Register */
 #define BME1000_PSCR_ENABLE_DOWNSHIFT   0x0800 /* 1 = enable downshift */
 
index f37360a..d6e491b 100644 (file)
@@ -96,6 +96,51 @@ struct e1000_info;
 /* Number of packet split data buffers (not including the header buffer) */
 #define PS_PAGE_BUFFERS                        (MAX_PS_BUFFERS - 1)
 
+#define DEFAULT_JUMBO                  9234
+
+/* BM/HV Specific Registers */
+#define BM_PORT_CTRL_PAGE                 769
+
+#define PHY_UPPER_SHIFT                   21
+#define BM_PHY_REG(page, reg) \
+       (((reg) & MAX_PHY_REG_ADDRESS) |\
+        (((page) & 0xFFFF) << PHY_PAGE_SHIFT) |\
+        (((reg) & ~MAX_PHY_REG_ADDRESS) << (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)))
+
+/* PHY Wakeup Registers and defines */
+#define BM_RCTL         PHY_REG(BM_WUC_PAGE, 0)
+#define BM_WUC          PHY_REG(BM_WUC_PAGE, 1)
+#define BM_WUFC         PHY_REG(BM_WUC_PAGE, 2)
+#define BM_WUS          PHY_REG(BM_WUC_PAGE, 3)
+#define BM_RAR_L(_i)    (BM_PHY_REG(BM_WUC_PAGE, 16 + ((_i) << 2)))
+#define BM_RAR_M(_i)    (BM_PHY_REG(BM_WUC_PAGE, 17 + ((_i) << 2)))
+#define BM_RAR_H(_i)    (BM_PHY_REG(BM_WUC_PAGE, 18 + ((_i) << 2)))
+#define BM_RAR_CTRL(_i) (BM_PHY_REG(BM_WUC_PAGE, 19 + ((_i) << 2)))
+#define BM_MTA(_i)      (BM_PHY_REG(BM_WUC_PAGE, 128 + ((_i) << 1)))
+
+#define BM_RCTL_UPE           0x0001          /* Unicast Promiscuous Mode */
+#define BM_RCTL_MPE           0x0002          /* Multicast Promiscuous Mode */
+#define BM_RCTL_MO_SHIFT      3               /* Multicast Offset Shift */
+#define BM_RCTL_MO_MASK       (3 << 3)        /* Multicast Offset Mask */
+#define BM_RCTL_BAM           0x0020          /* Broadcast Accept Mode */
+#define BM_RCTL_PMCF          0x0040          /* Pass MAC Control Frames */
+#define BM_RCTL_RFCE          0x0080          /* Rx Flow Control Enable */
+
+#define HV_SCC_UPPER           PHY_REG(778, 16) /* Single Collision Count */
+#define HV_SCC_LOWER           PHY_REG(778, 17)
+#define HV_ECOL_UPPER          PHY_REG(778, 18) /* Excessive Collision Count */
+#define HV_ECOL_LOWER          PHY_REG(778, 19)
+#define HV_MCC_UPPER           PHY_REG(778, 20) /* Multiple Collision Count */
+#define HV_MCC_LOWER           PHY_REG(778, 21)
+#define HV_LATECOL_UPPER       PHY_REG(778, 23) /* Late Collision Count */
+#define HV_LATECOL_LOWER       PHY_REG(778, 24)
+#define HV_COLC_UPPER          PHY_REG(778, 25) /* Collision Count */
+#define HV_COLC_LOWER          PHY_REG(778, 26)
+#define HV_DC_UPPER            PHY_REG(778, 27) /* Defer Count */
+#define HV_DC_LOWER            PHY_REG(778, 28)
+#define HV_TNCRS_UPPER         PHY_REG(778, 29) /* Transmit with no CRS */
+#define HV_TNCRS_LOWER         PHY_REG(778, 30)
+
 enum e1000_boards {
        board_82571,
        board_82572,
@@ -106,6 +151,7 @@ enum e1000_boards {
        board_ich8lan,
        board_ich9lan,
        board_ich10lan,
+       board_pchlan,
 };
 
 struct e1000_queue_stats {
@@ -293,6 +339,7 @@ struct e1000_adapter {
        u32 eeprom_wol;
        u32 wol;
        u32 pba;
+       u32 max_hw_frame_size;
 
        bool fc_autoneg;
 
@@ -302,6 +349,7 @@ struct e1000_adapter {
        unsigned int flags2;
        struct work_struct downshift_task;
        struct work_struct update_phy_task;
+       struct work_struct led_blink_task;
 };
 
 struct e1000_info {
@@ -309,6 +357,7 @@ struct e1000_info {
        unsigned int            flags;
        unsigned int            flags2;
        u32                     pba;
+       u32                     max_hw_frame_size;
        s32                     (*get_variants)(struct e1000_adapter *);
        struct e1000_mac_operations *mac_ops;
        struct e1000_phy_operations *phy_ops;
@@ -351,6 +400,7 @@ struct e1000_info {
 
 /* CRC Stripping defines */
 #define FLAG2_CRC_STRIPPING               (1 << 0)
+#define FLAG2_HAS_PHY_WAKEUP              (1 << 1)
 
 #define E1000_RX_DESC_PS(R, i)     \
        (&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
@@ -404,6 +454,7 @@ extern struct e1000_info e1000_82583_info;
 extern struct e1000_info e1000_ich8_info;
 extern struct e1000_info e1000_ich9_info;
 extern struct e1000_info e1000_ich10_info;
+extern struct e1000_info e1000_pch_info;
 extern struct e1000_info e1000_es2_info;
 
 extern s32 e1000e_read_pba_num(struct e1000_hw *hw, u32 *pba_num);
@@ -425,6 +476,7 @@ extern void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw);
 extern s32 e1000e_check_for_copper_link(struct e1000_hw *hw);
 extern s32 e1000e_check_for_fiber_link(struct e1000_hw *hw);
 extern s32 e1000e_check_for_serdes_link(struct e1000_hw *hw);
+extern s32 e1000e_setup_led_generic(struct e1000_hw *hw);
 extern s32 e1000e_cleanup_led_generic(struct e1000_hw *hw);
 extern s32 e1000e_led_on_generic(struct e1000_hw *hw);
 extern s32 e1000e_led_off_generic(struct e1000_hw *hw);
@@ -493,6 +545,15 @@ extern s32 e1000e_phy_reset_dsp(struct e1000_hw *hw);
 extern s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
 extern s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
 extern s32 e1000e_check_downshift(struct e1000_hw *hw);
+extern s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data);
+extern s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data);
+extern s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow);
+extern s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw);
+extern s32 e1000_copper_link_setup_82577(struct e1000_hw *hw);
+extern s32 e1000_check_polarity_82577(struct e1000_hw *hw);
+extern s32 e1000_get_phy_info_82577(struct e1000_hw *hw);
+extern s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw);
+extern s32 e1000_get_cable_length_82577(struct e1000_hw *hw);
 
 static inline s32 e1000_phy_hw_reset(struct e1000_hw *hw)
 {
index 8964838..ae5d736 100644 (file)
@@ -1366,6 +1366,7 @@ static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw)
 }
 
 static struct e1000_mac_operations es2_mac_ops = {
+       .id_led_init            = e1000e_id_led_init,
        .check_mng_mode         = e1000e_check_mng_mode_generic,
        /* check_for_link dependent on media type */
        .cleanup_led            = e1000e_cleanup_led_generic,
@@ -1379,6 +1380,7 @@ static struct e1000_mac_operations es2_mac_ops = {
        .init_hw                = e1000_init_hw_80003es2lan,
        .setup_link             = e1000e_setup_link,
        /* setup_physical_interface dependent on media type */
+       .setup_led              = e1000e_setup_led_generic,
 };
 
 static struct e1000_phy_operations es2_phy_ops = {
@@ -1422,6 +1424,7 @@ struct e1000_info e1000_es2_info = {
                                  | FLAG_DISABLE_FC_PAUSE_TIME /* errata */
                                  | FLAG_TIPG_MEDIUM_FOR_80003ESLAN,
        .pba                    = 38,
+       .max_hw_frame_size      = DEFAULT_JUMBO,
        .get_variants           = e1000_get_variants_80003es2lan,
        .mac_ops                = &es2_mac_ops,
        .phy_ops                = &es2_phy_ops,
index 4d25ede..1bf4d2a 100644 (file)
@@ -167,6 +167,15 @@ static int e1000_get_settings(struct net_device *netdev,
 
        ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) ||
                         hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+
+       /* MDI-X => 2; MDI =>1; Invalid =>0 */
+       if ((hw->phy.media_type == e1000_media_type_copper) &&
+           !hw->mac.get_link_status)
+               ecmd->eth_tp_mdix = hw->phy.is_mdix ? ETH_TP_MDI_X :
+                                                     ETH_TP_MDI;
+       else
+               ecmd->eth_tp_mdix = ETH_TP_MDI_INVALID;
+
        return 0;
 }
 
@@ -776,6 +785,7 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
        u32 after;
        u32 i;
        u32 toggle;
+       u32 mask;
 
        /*
         * The status register is Read Only, so a write should fail.
@@ -788,17 +798,9 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
        case e1000_80003es2lan:
                toggle = 0x7FFFF3FF;
                break;
-       case e1000_82573:
-       case e1000_82574:
-       case e1000_82583:
-       case e1000_ich8lan:
-       case e1000_ich9lan:
-       case e1000_ich10lan:
+        default:
                toggle = 0x7FFFF033;
                break;
-       default:
-               toggle = 0xFFFFF833;
-               break;
        }
 
        before = er32(STATUS);
@@ -844,11 +846,18 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
                REG_PATTERN_TEST(E1000_TXCW, 0xC000FFFF, 0x0000FFFF);
        REG_PATTERN_TEST(E1000_TDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
        REG_PATTERN_TEST(E1000_TIDV, 0x0000FFFF, 0x0000FFFF);
+       mask = 0x8003FFFF;
+       switch (mac->type) {
+       case e1000_ich10lan:
+       case e1000_pchlan:
+               mask |= (1 << 18);
+               break;
+       default:
+               break;
+       }
        for (i = 0; i < mac->rar_entry_count; i++)
                REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1),
-                                      ((mac->type == e1000_ich10lan) ?
-                                          0x8007FFFF : 0x8003FFFF),
-                                      0xFFFFFFFF);
+                                      mask, 0xFFFFFFFF);
 
        for (i = 0; i < mac->mta_reg_count; i++)
                REG_PATTERN_TEST_ARRAY(E1000_MTA, i, 0xFFFFFFFF, 0xFFFFFFFF);
@@ -1786,15 +1795,22 @@ static int e1000_set_wol(struct net_device *netdev,
 /* bit defines for adapter->led_status */
 #define E1000_LED_ON           0
 
-static void e1000_led_blink_callback(unsigned long data)
+static void e1000e_led_blink_task(struct work_struct *work)
 {
-       struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+       struct e1000_adapter *adapter = container_of(work,
+                                       struct e1000_adapter, led_blink_task);
 
        if (test_and_change_bit(E1000_LED_ON, &adapter->led_status))
                adapter->hw.mac.ops.led_off(&adapter->hw);
        else
                adapter->hw.mac.ops.led_on(&adapter->hw);
+}
+
+static void e1000_led_blink_callback(unsigned long data)
+{
+       struct e1000_adapter *adapter = (struct e1000_adapter *) data;
 
+       schedule_work(&adapter->led_blink_task);
        mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL);
 }
 
@@ -1807,7 +1823,9 @@ static int e1000_phys_id(struct net_device *netdev, u32 data)
                data = INT_MAX;
 
        if ((hw->phy.type == e1000_phy_ife) ||
+           (hw->mac.type == e1000_pchlan) ||
            (hw->mac.type == e1000_82574)) {
+               INIT_WORK(&adapter->led_blink_task, e1000e_led_blink_task);
                if (!adapter->blink_timer.function) {
                        init_timer(&adapter->blink_timer);
                        adapter->blink_timer.function =
index 6cdb703..163c1c0 100644 (file)
@@ -193,7 +193,11 @@ enum e1e_registers {
        E1000_RXCSUM   = 0x05000, /* Rx Checksum Control - RW */
        E1000_RFCTL    = 0x05008, /* Receive Filter Control */
        E1000_MTA      = 0x05200, /* Multicast Table Array - RW Array */
-       E1000_RA       = 0x05400, /* Receive Address - RW Array */
+       E1000_RAL_BASE = 0x05400, /* Receive Address Low - RW */
+#define E1000_RAL(_n)   (E1000_RAL_BASE + ((_n) * 8))
+#define E1000_RA        (E1000_RAL(0))
+       E1000_RAH_BASE = 0x05404, /* Receive Address High - RW */
+#define E1000_RAH(_n)   (E1000_RAH_BASE + ((_n) * 8))
        E1000_VFTA     = 0x05600, /* VLAN Filter Table Array - RW Array */
        E1000_WUC      = 0x05800, /* Wakeup Control - RW */
        E1000_WUFC     = 0x05808, /* Wakeup Filter Control - RW */
@@ -210,6 +214,7 @@ enum e1e_registers {
        E1000_FACTPS    = 0x05B30, /* Function Active and Power State to MNG */
        E1000_SWSM      = 0x05B50, /* SW Semaphore */
        E1000_FWSM      = 0x05B54, /* FW Semaphore */
+       E1000_SWSM2     = 0x05B58, /* Driver-only SW semaphore */
        E1000_HICR      = 0x08F00, /* Host Interface Control */
 };
 
@@ -368,6 +373,10 @@ enum e1e_registers {
 #define E1000_DEV_ID_ICH10_R_BM_V              0x10CE
 #define E1000_DEV_ID_ICH10_D_BM_LM             0x10DE
 #define E1000_DEV_ID_ICH10_D_BM_LF             0x10DF
+#define E1000_DEV_ID_PCH_M_HV_LM               0x10EA
+#define E1000_DEV_ID_PCH_M_HV_LC               0x10EB
+#define E1000_DEV_ID_PCH_D_HV_DM               0x10EF
+#define E1000_DEV_ID_PCH_D_HV_DC               0x10F0
 
 #define E1000_REVISION_4 4
 
@@ -383,6 +392,7 @@ enum e1000_mac_type {
        e1000_ich8lan,
        e1000_ich9lan,
        e1000_ich10lan,
+       e1000_pchlan,
 };
 
 enum e1000_media_type {
@@ -417,6 +427,8 @@ enum e1000_phy_type {
        e1000_phy_igp_3,
        e1000_phy_ife,
        e1000_phy_bm,
+       e1000_phy_82578,
+       e1000_phy_82577,
 };
 
 enum e1000_bus_width {
@@ -720,6 +732,7 @@ struct e1000_host_mng_command_info {
 
 /* Function pointers and static data for the MAC. */
 struct e1000_mac_operations {
+       s32  (*id_led_init)(struct e1000_hw *);
        bool (*check_mng_mode)(struct e1000_hw *);
        s32  (*check_for_link)(struct e1000_hw *);
        s32  (*cleanup_led)(struct e1000_hw *);
@@ -733,11 +746,13 @@ struct e1000_mac_operations {
        s32  (*init_hw)(struct e1000_hw *);
        s32  (*setup_link)(struct e1000_hw *);
        s32  (*setup_physical_interface)(struct e1000_hw *);
+       s32  (*setup_led)(struct e1000_hw *);
 };
 
 /* Function pointers for the PHY. */
 struct e1000_phy_operations {
        s32  (*acquire_phy)(struct e1000_hw *);
+       s32  (*check_polarity)(struct e1000_hw *);
        s32  (*check_reset_block)(struct e1000_hw *);
        s32  (*commit_phy)(struct e1000_hw *);
        s32  (*force_speed_duplex)(struct e1000_hw *);
@@ -869,6 +884,7 @@ struct e1000_fc_info {
 struct e1000_dev_spec_82571 {
        bool laa_is_present;
        bool alt_mac_addr_is_present;
+       u32 smb_counter;
 };
 
 struct e1000_shadow_ram {
index 6d1aab6..9e23f50 100644 (file)
  * 82567LF-3 Gigabit Network Connection
  * 82567LM-3 Gigabit Network Connection
  * 82567LM-4 Gigabit Network Connection
+ * 82577LM Gigabit Network Connection
+ * 82577LC Gigabit Network Connection
+ * 82578DM Gigabit Network Connection
+ * 82578DC Gigabit Network Connection
  */
 
 #include <linux/netdevice.h>
 #define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK 0x0300
 #define IGP3_VR_CTRL_MODE_SHUTDOWN     0x0200
 
+#define HV_LED_CONFIG          PHY_REG(768, 30) /* LED Configuration */
+
 /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
 /* Offset 04h HSFSTS */
 union ich8_hws_flash_status {
@@ -186,6 +192,14 @@ static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
 static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw);
 static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
 static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw);
+static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw);
+static s32 e1000_led_on_ich8lan(struct e1000_hw *hw);
+static s32 e1000_led_off_ich8lan(struct e1000_hw *hw);
+static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw);
+static s32 e1000_setup_led_pchlan(struct e1000_hw *hw);
+static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw);
+static s32 e1000_led_on_pchlan(struct e1000_hw *hw);
+static s32 e1000_led_off_pchlan(struct e1000_hw *hw);
 
 static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg)
 {
@@ -213,6 +227,41 @@ static inline void __ew32flash(struct e1000_hw *hw, unsigned long reg, u32 val)
 #define ew32flash(reg,val)     __ew32flash(hw, (reg), (val))
 
 /**
+ *  e1000_init_phy_params_pchlan - Initialize PHY function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Initialize family-specific PHY parameters and function pointers.
+ **/
+static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32 ret_val = 0;
+
+       phy->addr                     = 1;
+       phy->reset_delay_us           = 100;
+
+       phy->ops.check_polarity       = e1000_check_polarity_ife_ich8lan;
+       phy->ops.read_phy_reg         = e1000_read_phy_reg_hv;
+       phy->ops.write_phy_reg        = e1000_write_phy_reg_hv;
+       phy->autoneg_mask             = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+       phy->id = e1000_phy_unknown;
+       e1000e_get_phy_id(hw);
+       phy->type = e1000e_get_phy_type_from_id(phy->id);
+
+       if (phy->type == e1000_phy_82577) {
+               phy->ops.check_polarity = e1000_check_polarity_82577;
+               phy->ops.force_speed_duplex =
+                       e1000_phy_force_speed_duplex_82577;
+               phy->ops.get_cable_length   = e1000_get_cable_length_82577;
+               phy->ops.get_phy_info = e1000_get_phy_info_82577;
+               phy->ops.commit_phy = e1000e_phy_sw_reset;
+       }
+
+       return ret_val;
+}
+
+/**
  *  e1000_init_phy_params_ich8lan - Initialize PHY function pointers
  *  @hw: pointer to the HW structure
  *
@@ -273,6 +322,8 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
                break;
        }
 
+       phy->ops.check_polarity = e1000_check_polarity_ife_ich8lan;
+
        return 0;
 }
 
@@ -358,6 +409,36 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter)
        /* Set if manageability features are enabled. */
        mac->arc_subsystem_valid = 1;
 
+       /* LED operations */
+       switch (mac->type) {
+       case e1000_ich8lan:
+       case e1000_ich9lan:
+       case e1000_ich10lan:
+               /* ID LED init */
+               mac->ops.id_led_init = e1000e_id_led_init;
+               /* setup LED */
+               mac->ops.setup_led = e1000e_setup_led_generic;
+               /* cleanup LED */
+               mac->ops.cleanup_led = e1000_cleanup_led_ich8lan;
+               /* turn on/off LED */
+               mac->ops.led_on = e1000_led_on_ich8lan;
+               mac->ops.led_off = e1000_led_off_ich8lan;
+               break;
+       case e1000_pchlan:
+               /* ID LED init */
+               mac->ops.id_led_init = e1000_id_led_init_pchlan;
+               /* setup LED */
+               mac->ops.setup_led = e1000_setup_led_pchlan;
+               /* cleanup LED */
+               mac->ops.cleanup_led = e1000_cleanup_led_pchlan;
+               /* turn on/off LED */
+               mac->ops.led_on = e1000_led_on_pchlan;
+               mac->ops.led_off = e1000_led_off_pchlan;
+               break;
+       default:
+               break;
+       }
+
        /* Enable PCS Lock-loss workaround for ICH8 */
        if (mac->type == e1000_ich8lan)
                e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, 1);
@@ -378,10 +459,18 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
        if (rc)
                return rc;
 
-       rc = e1000_init_phy_params_ich8lan(hw);
+       if (hw->mac.type == e1000_pchlan)
+               rc = e1000_init_phy_params_pchlan(hw);
+       else
+               rc = e1000_init_phy_params_ich8lan(hw);
        if (rc)
                return rc;
 
+       if (adapter->hw.phy.type == e1000_phy_ife) {
+               adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES;
+               adapter->max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN;
+       }
+
        if ((adapter->hw.mac.type == e1000_ich8lan) &&
            (adapter->hw.phy.type == e1000_phy_igp_3))
                adapter->flags |= FLAG_LSC_GIG_SPEED_DROP;
@@ -410,12 +499,15 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
 
        while (timeout) {
                extcnf_ctrl = er32(EXTCNF_CTRL);
-               extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
-               ew32(EXTCNF_CTRL, extcnf_ctrl);
 
-               extcnf_ctrl = er32(EXTCNF_CTRL);
-               if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
-                       break;
+               if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)) {
+                       extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
+                       ew32(EXTCNF_CTRL, extcnf_ctrl);
+
+                       extcnf_ctrl = er32(EXTCNF_CTRL);
+                       if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
+                               break;
+               }
                mdelay(1);
                timeout--;
        }
@@ -555,6 +647,53 @@ static s32 e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw)
 }
 
 /**
+ *  e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be
+ *  done after every PHY reset.
+ **/
+static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw)
+{
+       s32 ret_val = 0;
+
+       if (hw->mac.type != e1000_pchlan)
+               return ret_val;
+
+       if (((hw->phy.type == e1000_phy_82577) &&
+            ((hw->phy.revision == 1) || (hw->phy.revision == 2))) ||
+           ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) {
+               /* Disable generation of early preamble */
+               ret_val = e1e_wphy(hw, PHY_REG(769, 25), 0x4431);
+               if (ret_val)
+                       return ret_val;
+
+               /* Preamble tuning for SSC */
+               ret_val = e1e_wphy(hw, PHY_REG(770, 16), 0xA204);
+               if (ret_val)
+                       return ret_val;
+       }
+
+       if (hw->phy.type == e1000_phy_82578) {
+               /*
+                * Return registers to default by doing a soft reset then
+                * writing 0x3140 to the control register.
+                */
+               if (hw->phy.revision < 2) {
+                       e1000e_phy_sw_reset(hw);
+                       ret_val = e1e_wphy(hw, PHY_CONTROL, 0x3140);
+               }
+       }
+
+       /* Select page 0 */
+       ret_val = hw->phy.ops.acquire_phy(hw);
+       if (ret_val)
+               return ret_val;
+       hw->phy.addr = 1;
+       e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0);
+       hw->phy.ops.release_phy(hw);
+
+       return ret_val;
+}
+
+/**
  *  e1000_phy_hw_reset_ich8lan - Performs a PHY reset
  *  @hw: pointer to the HW structure
  *
@@ -575,6 +714,12 @@ static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
        if (ret_val)
                return ret_val;
 
+       if (hw->mac.type == e1000_pchlan) {
+               ret_val = e1000_hv_phy_workarounds_ich8lan(hw);
+               if (ret_val)
+                       return ret_val;
+       }
+
        /*
         * Initialize the PHY from the NVM on ICH platforms.  This
         * is needed due to an issue where the NVM configuration is
@@ -701,7 +846,7 @@ static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw)
        phy->polarity_correction = (!(data & IFE_PSC_AUTO_POLARITY_DISABLE));
 
        if (phy->polarity_correction) {
-               ret_val = e1000_check_polarity_ife_ich8lan(hw);
+               ret_val = phy->ops.check_polarity(hw);
                if (ret_val)
                        return ret_val;
        } else {
@@ -741,6 +886,8 @@ static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw)
                break;
        case e1000_phy_igp_3:
        case e1000_phy_bm:
+       case e1000_phy_82578:
+       case e1000_phy_82577:
                return e1000e_get_phy_info_igp(hw);
                break;
        default:
@@ -1852,6 +1999,79 @@ static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data)
 }
 
 /**
+ *  e1000_id_led_init_pchlan - store LED configurations
+ *  @hw: pointer to the HW structure
+ *
+ *  PCH does not control LEDs via the LEDCTL register, rather it uses
+ *  the PHY LED configuration register.
+ *
+ *  PCH also does not have an "always on" or "always off" mode which
+ *  complicates the ID feature.  Instead of using the "on" mode to indicate
+ *  in ledctl_mode2 the LEDs to use for ID (see e1000e_id_led_init()),
+ *  use "link_up" mode.  The LEDs will still ID on request if there is no
+ *  link based on logic in e1000_led_[on|off]_pchlan().
+ **/
+static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw)
+{
+       struct e1000_mac_info *mac = &hw->mac;
+       s32 ret_val;
+       const u32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP;
+       const u32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT;
+       u16 data, i, temp, shift;
+
+       /* Get default ID LED modes */
+       ret_val = hw->nvm.ops.valid_led_default(hw, &data);
+       if (ret_val)
+               goto out;
+
+       mac->ledctl_default = er32(LEDCTL);
+       mac->ledctl_mode1 = mac->ledctl_default;
+       mac->ledctl_mode2 = mac->ledctl_default;
+
+       for (i = 0; i < 4; i++) {
+               temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK;
+               shift = (i * 5);
+               switch (temp) {
+               case ID_LED_ON1_DEF2:
+               case ID_LED_ON1_ON2:
+               case ID_LED_ON1_OFF2:
+                       mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
+                       mac->ledctl_mode1 |= (ledctl_on << shift);
+                       break;
+               case ID_LED_OFF1_DEF2:
+               case ID_LED_OFF1_ON2:
+               case ID_LED_OFF1_OFF2:
+                       mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
+                       mac->ledctl_mode1 |= (ledctl_off << shift);
+                       break;
+               default:
+                       /* Do nothing */
+                       break;
+               }
+               switch (temp) {
+               case ID_LED_DEF1_ON2:
+               case ID_LED_ON1_ON2:
+               case ID_LED_OFF1_ON2:
+                       mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
+                       mac->ledctl_mode2 |= (ledctl_on << shift);
+                       break;
+               case ID_LED_DEF1_OFF2:
+               case ID_LED_ON1_OFF2:
+               case ID_LED_OFF1_OFF2:
+                       mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
+                       mac->ledctl_mode2 |= (ledctl_off << shift);
+                       break;
+               default:
+                       /* Do nothing */
+                       break;
+               }
+       }
+
+out:
+       return ret_val;
+}
+
+/**
  *  e1000_get_bus_info_ich8lan - Get/Set the bus type and width
  *  @hw: pointer to the HW structure
  *
@@ -1960,6 +2180,9 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
        kab |= E1000_KABGTXD_BGSQLBIAS;
        ew32(KABGTXD, kab);
 
+       if (hw->mac.type == e1000_pchlan)
+               ret_val = e1000_hv_phy_workarounds_ich8lan(hw);
+
        return ret_val;
 }
 
@@ -1985,7 +2208,7 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
        e1000_initialize_hw_bits_ich8lan(hw);
 
        /* Initialize identification LED */
-       ret_val = e1000e_id_led_init(hw);
+       ret_val = mac->ops.id_led_init(hw);
        if (ret_val) {
                hw_dbg(hw, "Error initializing identification LED\n");
                return ret_val;
@@ -2031,6 +2254,16 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
        ew32(CTRL_EXT, ctrl_ext);
 
        /*
+        * The 82578 Rx buffer will stall if wakeup is enabled in host and
+        * the ME.  Reading the BM_WUC register will clear the host wakeup bit.
+        * Reset the phy after disabling host wakeup to reset the Rx buffer.
+        */
+       if (hw->phy.type == e1000_phy_82578) {
+               e1e_rphy(hw, BM_WUC, &i);
+               e1000e_phy_hw_reset_generic(hw);
+       }
+
+       /*
         * Clear all of the statistics registers (clear on read).  It is
         * important that we do this after we have tried to establish link
         * because the symbol error count will increment wildly if there
@@ -2054,6 +2287,9 @@ static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
        /* Extended Device Control */
        reg = er32(CTRL_EXT);
        reg |= (1 << 22);
+       /* Enable PHY low-power state when MAC is at D3 w/o WoL */
+       if (hw->mac.type >= e1000_pchlan)
+               reg |= E1000_CTRL_EXT_PHYPDEN;
        ew32(CTRL_EXT, reg);
 
        /* Transmit Descriptor Control 0 */
@@ -2112,8 +2348,13 @@ static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
         * the default flow control setting, so we explicitly
         * set it to full.
         */
-       if (hw->fc.requested_mode == e1000_fc_default)
-               hw->fc.requested_mode = e1000_fc_full;
+       if (hw->fc.requested_mode == e1000_fc_default) {
+               /* Workaround h/w hang when Tx flow control enabled */
+               if (hw->mac.type == e1000_pchlan)
+                       hw->fc.requested_mode = e1000_fc_rx_pause;
+               else
+                       hw->fc.requested_mode = e1000_fc_full;
+       }
 
        /*
         * Save off the requested flow control mode for use later.  Depending
@@ -2130,6 +2371,14 @@ static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
                return ret_val;
 
        ew32(FCTTV, hw->fc.pause_time);
+       if ((hw->phy.type == e1000_phy_82578) ||
+           (hw->phy.type == e1000_phy_82577)) {
+               ret_val = hw->phy.ops.write_phy_reg(hw,
+                                            PHY_REG(BM_PORT_CTRL_PAGE, 27),
+                                            hw->fc.pause_time);
+               if (ret_val)
+                       return ret_val;
+       }
 
        return e1000e_set_fc_watermarks(hw);
 }
@@ -2169,18 +2418,26 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
        if (ret_val)
                return ret_val;
 
-       if (hw->phy.type == e1000_phy_igp_3) {
+       switch (hw->phy.type) {
+       case e1000_phy_igp_3:
                ret_val = e1000e_copper_link_setup_igp(hw);
                if (ret_val)
                        return ret_val;
-       } else if (hw->phy.type == e1000_phy_bm) {
+               break;
+       case e1000_phy_bm:
+       case e1000_phy_82578:
                ret_val = e1000e_copper_link_setup_m88(hw);
                if (ret_val)
                        return ret_val;
-       }
-
-       if (hw->phy.type == e1000_phy_ife) {
-               ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &reg_data);
+               break;
+       case e1000_phy_82577:
+               ret_val = e1000_copper_link_setup_82577(hw);
+               if (ret_val)
+                       return ret_val;
+               break;
+       case e1000_phy_ife:
+               ret_val = hw->phy.ops.read_phy_reg(hw, IFE_PHY_MDIX_CONTROL,
+                                              &reg_data);
                if (ret_val)
                        return ret_val;
 
@@ -2198,9 +2455,13 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
                        reg_data |= IFE_PMC_AUTO_MDIX;
                        break;
                }
-               ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, reg_data);
+               ret_val = hw->phy.ops.write_phy_reg(hw, IFE_PHY_MDIX_CONTROL,
+                                               reg_data);
                if (ret_val)
                        return ret_val;
+               break;
+       default:
+               break;
        }
        return e1000e_setup_copper_link(hw);
 }
@@ -2417,18 +2678,26 @@ void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
  *  'LPLU Enabled' and 'Gig Disable' to force link speed negotiation
  *  to a lower speed.
  *
- *  Should only be called for ICH9 and ICH10 devices.
+ *  Should only be called for applicable parts.
  **/
 void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw)
 {
        u32 phy_ctrl;
 
-       if ((hw->mac.type == e1000_ich10lan) ||
-           (hw->mac.type == e1000_ich9lan)) {
+       switch (hw->mac.type) {
+       case e1000_ich9lan:
+       case e1000_ich10lan:
+       case e1000_pchlan:
                phy_ctrl = er32(PHY_CTRL);
                phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU |
                            E1000_PHY_CTRL_GBE_DISABLE;
                ew32(PHY_CTRL, phy_ctrl);
+
+               /* Workaround SWFLAG unexpectedly set during S0->Sx */
+               if (hw->mac.type == e1000_pchlan)
+                       udelay(500);
+       default:
+               break;
        }
 
        return;
@@ -2482,13 +2751,99 @@ static s32 e1000_led_off_ich8lan(struct e1000_hw *hw)
 }
 
 /**
+ *  e1000_setup_led_pchlan - Configures SW controllable LED
+ *  @hw: pointer to the HW structure
+ *
+ *  This prepares the SW controllable LED for use.
+ **/
+static s32 e1000_setup_led_pchlan(struct e1000_hw *hw)
+{
+       return hw->phy.ops.write_phy_reg(hw, HV_LED_CONFIG,
+                                       (u16)hw->mac.ledctl_mode1);
+}
+
+/**
+ *  e1000_cleanup_led_pchlan - Restore the default LED operation
+ *  @hw: pointer to the HW structure
+ *
+ *  Return the LED back to the default configuration.
+ **/
+static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw)
+{
+       return hw->phy.ops.write_phy_reg(hw, HV_LED_CONFIG,
+                                       (u16)hw->mac.ledctl_default);
+}
+
+/**
+ *  e1000_led_on_pchlan - Turn LEDs on
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn on the LEDs.
+ **/
+static s32 e1000_led_on_pchlan(struct e1000_hw *hw)
+{
+       u16 data = (u16)hw->mac.ledctl_mode2;
+       u32 i, led;
+
+       /*
+        * If no link, then turn LED on by setting the invert bit
+        * for each LED that's mode is "link_up" in ledctl_mode2.
+        */
+       if (!(er32(STATUS) & E1000_STATUS_LU)) {
+               for (i = 0; i < 3; i++) {
+                       led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
+                       if ((led & E1000_PHY_LED0_MODE_MASK) !=
+                           E1000_LEDCTL_MODE_LINK_UP)
+                               continue;
+                       if (led & E1000_PHY_LED0_IVRT)
+                               data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
+                       else
+                               data |= (E1000_PHY_LED0_IVRT << (i * 5));
+               }
+       }
+
+       return hw->phy.ops.write_phy_reg(hw, HV_LED_CONFIG, data);
+}
+
+/**
+ *  e1000_led_off_pchlan - Turn LEDs off
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn off the LEDs.
+ **/
+static s32 e1000_led_off_pchlan(struct e1000_hw *hw)
+{
+       u16 data = (u16)hw->mac.ledctl_mode1;
+       u32 i, led;
+
+       /*
+        * If no link, then turn LED off by clearing the invert bit
+        * for each LED that's mode is "link_up" in ledctl_mode1.
+        */
+       if (!(er32(STATUS) & E1000_STATUS_LU)) {
+               for (i = 0; i < 3; i++) {
+                       led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
+                       if ((led & E1000_PHY_LED0_MODE_MASK) !=
+                           E1000_LEDCTL_MODE_LINK_UP)
+                               continue;
+                       if (led & E1000_PHY_LED0_IVRT)
+                               data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
+                       else
+                               data |= (E1000_PHY_LED0_IVRT << (i * 5));
+               }
+       }
+
+       return hw->phy.ops.write_phy_reg(hw, HV_LED_CONFIG, data);
+}
+
+/**
  *  e1000_get_cfg_done_ich8lan - Read config done bit
  *  @hw: pointer to the HW structure
  *
  *  Read the management control register for the config done bit for
  *  completion status.  NOTE: silicon which is EEPROM-less will fail trying
  *  to read the config done bit, so an error is *ONLY* logged and returns
- *  E1000_SUCCESS.  If we were to return with error, EEPROM-less silicon
+ *  0.  If we were to return with error, EEPROM-less silicon
  *  would not be able to be reset or change link.
  **/
 static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
@@ -2498,7 +2853,8 @@ static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
        e1000e_get_cfg_done(hw);
 
        /* If EEPROM is not marked present, init the IGP 3 PHY manually */
-       if (hw->mac.type != e1000_ich10lan) {
+       if ((hw->mac.type != e1000_ich10lan) &&
+           (hw->mac.type != e1000_pchlan)) {
                if (((er32(EECD) & E1000_EECD_PRES) == 0) &&
                    (hw->phy.type == e1000_phy_igp_3)) {
                        e1000e_phy_init_script_igp3(hw);
@@ -2524,6 +2880,7 @@ static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
 static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
 {
        u32 temp;
+       u16 phy_data;
 
        e1000e_clear_hw_cntrs_base(hw);
 
@@ -2541,22 +2898,42 @@ static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
        temp = er32(IAC);
        temp = er32(ICRXOC);
 
+       /* Clear PHY statistics registers */
+       if ((hw->phy.type == e1000_phy_82578) ||
+           (hw->phy.type == e1000_phy_82577)) {
+               hw->phy.ops.read_phy_reg(hw, HV_SCC_UPPER, &phy_data);
+               hw->phy.ops.read_phy_reg(hw, HV_SCC_LOWER, &phy_data);
+               hw->phy.ops.read_phy_reg(hw, HV_ECOL_UPPER, &phy_data);
+               hw->phy.ops.read_phy_reg(hw, HV_ECOL_LOWER, &phy_data);
+               hw->phy.ops.read_phy_reg(hw, HV_MCC_UPPER, &phy_data);
+               hw->phy.ops.read_phy_reg(hw, HV_MCC_LOWER, &phy_data);
+               hw->phy.ops.read_phy_reg(hw, HV_LATECOL_UPPER, &phy_data);
+               hw->phy.ops.read_phy_reg(hw, HV_LATECOL_LOWER, &phy_data);
+               hw->phy.ops.read_phy_reg(hw, HV_COLC_UPPER, &phy_data);
+               hw->phy.ops.read_phy_reg(hw, HV_COLC_LOWER, &phy_data);
+               hw->phy.ops.read_phy_reg(hw, HV_DC_UPPER, &phy_data);
+               hw->phy.ops.read_phy_reg(hw, HV_DC_LOWER, &phy_data);
+               hw->phy.ops.read_phy_reg(hw, HV_TNCRS_UPPER, &phy_data);
+               hw->phy.ops.read_phy_reg(hw, HV_TNCRS_LOWER, &phy_data);
+       }
 }
 
 static struct e1000_mac_operations ich8_mac_ops = {
+       .id_led_init            = e1000e_id_led_init,
        .check_mng_mode         = e1000_check_mng_mode_ich8lan,
        .check_for_link         = e1000e_check_for_copper_link,
-       .cleanup_led            = e1000_cleanup_led_ich8lan,
+       /* cleanup_led dependent on mac type */
        .clear_hw_cntrs         = e1000_clear_hw_cntrs_ich8lan,
        .get_bus_info           = e1000_get_bus_info_ich8lan,
        .get_link_up_info       = e1000_get_link_up_info_ich8lan,
-       .led_on                 = e1000_led_on_ich8lan,
-       .led_off                = e1000_led_off_ich8lan,
+       /* led_on dependent on mac type */
+       /* led_off dependent on mac type */
        .update_mc_addr_list    = e1000e_update_mc_addr_list_generic,
        .reset_hw               = e1000_reset_hw_ich8lan,
        .init_hw                = e1000_init_hw_ich8lan,
        .setup_link             = e1000_setup_link_ich8lan,
        .setup_physical_interface= e1000_setup_copper_link_ich8lan,
+       /* id_led_init dependent on mac type */
 };
 
 static struct e1000_phy_operations ich8_phy_ops = {
@@ -2595,6 +2972,7 @@ struct e1000_info e1000_ich8_info = {
                                  | FLAG_HAS_FLASH
                                  | FLAG_APME_IN_WUC,
        .pba                    = 8,
+       .max_hw_frame_size      = ETH_FRAME_LEN + ETH_FCS_LEN,
        .get_variants           = e1000_get_variants_ich8lan,
        .mac_ops                = &ich8_mac_ops,
        .phy_ops                = &ich8_phy_ops,
@@ -2613,6 +2991,7 @@ struct e1000_info e1000_ich9_info = {
                                  | FLAG_HAS_FLASH
                                  | FLAG_APME_IN_WUC,
        .pba                    = 10,
+       .max_hw_frame_size      = DEFAULT_JUMBO,
        .get_variants           = e1000_get_variants_ich8lan,
        .mac_ops                = &ich8_mac_ops,
        .phy_ops                = &ich8_phy_ops,
@@ -2631,6 +3010,25 @@ struct e1000_info e1000_ich10_info = {
                                  | FLAG_HAS_FLASH
                                  | FLAG_APME_IN_WUC,
        .pba                    = 10,
+       .max_hw_frame_size      = DEFAULT_JUMBO,
+       .get_variants           = e1000_get_variants_ich8lan,
+       .mac_ops                = &ich8_mac_ops,
+       .phy_ops                = &ich8_phy_ops,
+       .nvm_ops                = &ich8_nvm_ops,
+};
+
+struct e1000_info e1000_pch_info = {
+       .mac                    = e1000_pchlan,
+       .flags                  = FLAG_IS_ICH
+                                 | FLAG_HAS_WOL
+                                 | FLAG_RX_CSUM_ENABLED
+                                 | FLAG_HAS_CTRLEXT_ON_LOAD
+                                 | FLAG_HAS_AMT
+                                 | FLAG_HAS_FLASH
+                                 | FLAG_HAS_JUMBO_FRAMES
+                                 | FLAG_APME_IN_WUC,
+       .pba                    = 26,
+       .max_hw_frame_size      = 4096,
        .get_variants           = e1000_get_variants_ich8lan,
        .mac_ops                = &ich8_mac_ops,
        .phy_ops                = &ich8_phy_ops,
index 18a4f59..be6d9e9 100644 (file)
@@ -378,6 +378,12 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw)
 
        mac->get_link_status = 0;
 
+       if (hw->phy.type == e1000_phy_82578) {
+               ret_val = e1000_link_stall_workaround_hv(hw);
+               if (ret_val)
+                       return ret_val;
+       }
+
        /*
         * Check if there was DownShift, must be checked
         * immediately after link-up
@@ -1406,6 +1412,38 @@ s32 e1000e_id_led_init(struct e1000_hw *hw)
 }
 
 /**
+ *  e1000e_setup_led_generic - Configures SW controllable LED
+ *  @hw: pointer to the HW structure
+ *
+ *  This prepares the SW controllable LED for use and saves the current state
+ *  of the LED so it can be later restored.
+ **/
+s32 e1000e_setup_led_generic(struct e1000_hw *hw)
+{
+       u32 ledctl;
+
+       if (hw->mac.ops.setup_led != e1000e_setup_led_generic) {
+               return -E1000_ERR_CONFIG;
+       }
+
+       if (hw->phy.media_type == e1000_media_type_fiber) {
+               ledctl = er32(LEDCTL);
+               hw->mac.ledctl_default = ledctl;
+               /* Turn off LED0 */
+               ledctl &= ~(E1000_LEDCTL_LED0_IVRT |
+                           E1000_LEDCTL_LED0_BLINK |
+                           E1000_LEDCTL_LED0_MODE_MASK);
+               ledctl |= (E1000_LEDCTL_MODE_LED_OFF <<
+                          E1000_LEDCTL_LED0_MODE_SHIFT);
+               ew32(LEDCTL, ledctl);
+       } else if (hw->phy.media_type == e1000_media_type_copper) {
+               ew32(LEDCTL, hw->mac.ledctl_mode1);
+       }
+
+       return 0;
+}
+
+/**
  *  e1000e_cleanup_led_generic - Set LED config to default operation
  *  @hw: pointer to the HW structure
  *
index ccaaee0..677f604 100644 (file)
@@ -48,7 +48,7 @@
 
 #include "e1000.h"
 
-#define DRV_VERSION "0.3.3.4-k4"
+#define DRV_VERSION "1.0.2-k2"
 char e1000e_driver_name[] = "e1000e";
 const char e1000e_driver_version[] = DRV_VERSION;
 
@@ -62,6 +62,7 @@ static const struct e1000_info *e1000_info_tbl[] = {
        [board_ich8lan]         = &e1000_ich8_info,
        [board_ich9lan]         = &e1000_ich9_info,
        [board_ich10lan]        = &e1000_ich10_info,
+       [board_pchlan]          = &e1000_pch_info,
 };
 
 #ifdef DEBUG
@@ -2255,8 +2256,6 @@ static void e1000_configure_tx(struct e1000_adapter *adapter)
                ew32(TARC(1), tarc);
        }
 
-       e1000e_config_collision_dist(hw);
-
        /* Setup Transmit Descriptor Settings for eop descriptor */
        adapter->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS;
 
@@ -2269,6 +2268,8 @@ static void e1000_configure_tx(struct e1000_adapter *adapter)
 
        ew32(TCTL, tctl);
 
+       e1000e_config_collision_dist(hw);
+
        adapter->tx_queue_len = adapter->netdev->tx_queue_len;
 }
 
@@ -2308,6 +2309,23 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
        if (adapter->flags2 & FLAG2_CRC_STRIPPING)
                rctl |= E1000_RCTL_SECRC;
 
+       /* Workaround Si errata on 82577 PHY - configure IPG for jumbos */
+       if ((hw->phy.type == e1000_phy_82577) && (rctl & E1000_RCTL_LPE)) {
+               u16 phy_data;
+
+               e1e_rphy(hw, PHY_REG(770, 26), &phy_data);
+               phy_data &= 0xfff8;
+               phy_data |= (1 << 2);
+               e1e_wphy(hw, PHY_REG(770, 26), phy_data);
+
+               e1e_rphy(hw, 22, &phy_data);
+               phy_data &= 0x0fff;
+               phy_data |= (1 << 14);
+               e1e_wphy(hw, 0x10, 0x2823);
+               e1e_wphy(hw, 0x11, 0x0003);
+               e1e_wphy(hw, 22, phy_data);
+       }
+
        /* Setup buffer sizes */
        rctl &= ~E1000_RCTL_SZ_4096;
        rctl |= E1000_RCTL_BSEX;
@@ -2751,23 +2769,25 @@ void e1000e_reset(struct e1000_adapter *adapter)
        /*
         * flow control settings
         *
-        * The high water mark must be low enough to fit one full frame
+        * The high water mark must be low enough to fit two 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
+        * - the full Rx FIFO size minus two full frames
         */
-       if (adapter->flags & FLAG_HAS_ERT)
+       if ((adapter->flags & FLAG_HAS_ERT) &&
+           (adapter->netdev->mtu > ETH_DATA_LEN))
                hwm = min(((pba << 10) * 9 / 10),
                          ((pba << 10) - (E1000_ERT_2048 << 3)));
        else
                hwm = min(((pba << 10) * 9 / 10),
-                         ((pba << 10) - adapter->max_frame_size));
+                         ((pba << 10) - (2 * adapter->max_frame_size)));
 
-       fc->high_water = hwm & 0xFFF8; /* 8-byte granularity */
-       fc->low_water = fc->high_water - 8;
+       fc->high_water = hwm & E1000_FCRTH_RTH; /* 8-byte granularity */
+       fc->low_water = (fc->high_water - (2 * adapter->max_frame_size));
+       fc->low_water &= E1000_FCRTL_RTL; /* 8-byte granularity */
 
        if (adapter->flags & FLAG_DISABLE_FC_PAUSE_TIME)
                fc->pause_time = 0xFFFF;
@@ -2787,6 +2807,8 @@ void e1000e_reset(struct e1000_adapter *adapter)
                e1000_get_hw_control(adapter);
 
        ew32(WUC, 0);
+       if (adapter->flags2 & FLAG2_HAS_PHY_WAKEUP)
+               e1e_wphy(&adapter->hw, BM_WUC, 0);
 
        if (mac->ops.init_hw(hw))
                e_err("Hardware Error\n");
@@ -2799,7 +2821,8 @@ void e1000e_reset(struct e1000_adapter *adapter)
        e1000e_reset_adaptive(hw);
        e1000_get_phy_info(hw);
 
-       if (!(adapter->flags & FLAG_SMART_POWER_DOWN)) {
+       if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN) &&
+           !(adapter->flags & FLAG_SMART_POWER_DOWN)) {
                u16 phy_data = 0;
                /*
                 * speed up time to link by disabling smart power down, ignore
@@ -3266,6 +3289,7 @@ void e1000e_update_stats(struct e1000_adapter *adapter)
 {
        struct e1000_hw *hw = &adapter->hw;
        struct pci_dev *pdev = adapter->pdev;
+       u16 phy_data;
 
        /*
         * Prevent stats update while adapter is being reset, or if the pci
@@ -3285,11 +3309,34 @@ void e1000e_update_stats(struct e1000_adapter *adapter)
        adapter->stats.roc += er32(ROC);
 
        adapter->stats.mpc += er32(MPC);
-       adapter->stats.scc += er32(SCC);
-       adapter->stats.ecol += er32(ECOL);
-       adapter->stats.mcc += er32(MCC);
-       adapter->stats.latecol += er32(LATECOL);
-       adapter->stats.dc += er32(DC);
+       if ((hw->phy.type == e1000_phy_82578) ||
+           (hw->phy.type == e1000_phy_82577)) {
+               e1e_rphy(hw, HV_SCC_UPPER, &phy_data);
+               e1e_rphy(hw, HV_SCC_LOWER, &phy_data);
+               adapter->stats.scc += phy_data;
+
+               e1e_rphy(hw, HV_ECOL_UPPER, &phy_data);
+               e1e_rphy(hw, HV_ECOL_LOWER, &phy_data);
+               adapter->stats.ecol += phy_data;
+
+               e1e_rphy(hw, HV_MCC_UPPER, &phy_data);
+               e1e_rphy(hw, HV_MCC_LOWER, &phy_data);
+               adapter->stats.mcc += phy_data;
+
+               e1e_rphy(hw, HV_LATECOL_UPPER, &phy_data);
+               e1e_rphy(hw, HV_LATECOL_LOWER, &phy_data);
+               adapter->stats.latecol += phy_data;
+
+               e1e_rphy(hw, HV_DC_UPPER, &phy_data);
+               e1e_rphy(hw, HV_DC_LOWER, &phy_data);
+               adapter->stats.dc += phy_data;
+       } else {
+               adapter->stats.scc += er32(SCC);
+               adapter->stats.ecol += er32(ECOL);
+               adapter->stats.mcc += er32(MCC);
+               adapter->stats.latecol += er32(LATECOL);
+               adapter->stats.dc += er32(DC);
+       }
        adapter->stats.xonrxc += er32(XONRXC);
        adapter->stats.xontxc += er32(XONTXC);
        adapter->stats.xoffrxc += er32(XOFFRXC);
@@ -3307,13 +3354,28 @@ void e1000e_update_stats(struct e1000_adapter *adapter)
 
        hw->mac.tx_packet_delta = er32(TPT);
        adapter->stats.tpt += hw->mac.tx_packet_delta;
-       hw->mac.collision_delta = er32(COLC);
+       if ((hw->phy.type == e1000_phy_82578) ||
+           (hw->phy.type == e1000_phy_82577)) {
+               e1e_rphy(hw, HV_COLC_UPPER, &phy_data);
+               e1e_rphy(hw, HV_COLC_LOWER, &phy_data);
+               hw->mac.collision_delta = phy_data;
+       } else {
+               hw->mac.collision_delta = er32(COLC);
+       }
        adapter->stats.colc += hw->mac.collision_delta;
 
        adapter->stats.algnerrc += er32(ALGNERRC);
        adapter->stats.rxerrc += er32(RXERRC);
-       if ((hw->mac.type != e1000_82574) && (hw->mac.type != e1000_82583))
-               adapter->stats.tncrs += er32(TNCRS);
+       if ((hw->phy.type == e1000_phy_82578) ||
+           (hw->phy.type == e1000_phy_82577)) {
+               e1e_rphy(hw, HV_TNCRS_UPPER, &phy_data);
+               e1e_rphy(hw, HV_TNCRS_LOWER, &phy_data);
+               adapter->stats.tncrs += phy_data;
+       } else {
+               if ((hw->mac.type != e1000_82574) &&
+                   (hw->mac.type != e1000_82583))
+                       adapter->stats.tncrs += er32(TNCRS);
+       }
        adapter->stats.cexterr += er32(CEXTERR);
        adapter->stats.tsctc += er32(TSCTC);
        adapter->stats.tsctfc += er32(TSCTFC);
@@ -3854,7 +3916,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
                buffer_info->length = size;
                buffer_info->time_stamp = jiffies;
                buffer_info->next_to_watch = i;
-               buffer_info->dma = map[0] + offset;
+               buffer_info->dma = skb_shinfo(skb)->dma_head + offset;
                count++;
 
                len -= size;
@@ -3885,7 +3947,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
                        buffer_info->length = size;
                        buffer_info->time_stamp = jiffies;
                        buffer_info->next_to_watch = i;
-                       buffer_info->dma = map[f + 1] + offset;
+                       buffer_info->dma = map[f] + offset;
 
                        len -= size;
                        offset += size;
@@ -4149,7 +4211,6 @@ static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        count = e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss);
        if (count) {
                e1000_tx_queue(adapter, tx_flags, count);
-               netdev->trans_start = jiffies;
                /* Make sure there is space in the ring for the next send. */
                e1000_maybe_stop_tx(netdev, MAX_SKB_FRAGS + 2);
 
@@ -4210,27 +4271,17 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
        struct e1000_adapter *adapter = netdev_priv(netdev);
        int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
 
-       if ((new_mtu < ETH_ZLEN + ETH_FCS_LEN + VLAN_HLEN) ||
-           (max_frame > MAX_JUMBO_FRAME_SIZE)) {
-               e_err("Invalid MTU setting\n");
+       /* Jumbo frame support */
+       if ((max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) &&
+           !(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) {
+               e_err("Jumbo Frames not supported.\n");
                return -EINVAL;
        }
 
-       /* Jumbo frame size limits */
-       if (max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) {
-               if (!(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) {
-                       e_err("Jumbo Frames not supported.\n");
-                       return -EINVAL;
-               }
-               if (adapter->hw.phy.type == e1000_phy_ife) {
-                       e_err("Jumbo Frames not supported.\n");
-                       return -EINVAL;
-               }
-       }
-
-#define MAX_STD_JUMBO_FRAME_SIZE 9234
-       if (max_frame > MAX_STD_JUMBO_FRAME_SIZE) {
-               e_err("MTU > 9216 not supported.\n");
+       /* Supported frame sizes */
+       if ((new_mtu < ETH_ZLEN + ETH_FCS_LEN + VLAN_HLEN) ||
+           (max_frame > adapter->max_hw_frame_size)) {
+               e_err("Unsupported MTU setting\n");
                return -EINVAL;
        }
 
@@ -4350,6 +4401,81 @@ static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
        }
 }
 
+static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 i, mac_reg;
+       u16 phy_reg;
+       int retval = 0;
+
+       /* copy MAC RARs to PHY RARs */
+       for (i = 0; i < adapter->hw.mac.rar_entry_count; i++) {
+               mac_reg = er32(RAL(i));
+               e1e_wphy(hw, BM_RAR_L(i), (u16)(mac_reg & 0xFFFF));
+               e1e_wphy(hw, BM_RAR_M(i), (u16)((mac_reg >> 16) & 0xFFFF));
+               mac_reg = er32(RAH(i));
+               e1e_wphy(hw, BM_RAR_H(i), (u16)(mac_reg & 0xFFFF));
+               e1e_wphy(hw, BM_RAR_CTRL(i), (u16)((mac_reg >> 16) & 0xFFFF));
+       }
+
+       /* copy MAC MTA to PHY MTA */
+       for (i = 0; i < adapter->hw.mac.mta_reg_count; i++) {
+               mac_reg = E1000_READ_REG_ARRAY(hw, E1000_MTA, i);
+               e1e_wphy(hw, BM_MTA(i), (u16)(mac_reg & 0xFFFF));
+               e1e_wphy(hw, BM_MTA(i) + 1, (u16)((mac_reg >> 16) & 0xFFFF));
+       }
+
+       /* configure PHY Rx Control register */
+       e1e_rphy(&adapter->hw, BM_RCTL, &phy_reg);
+       mac_reg = er32(RCTL);
+       if (mac_reg & E1000_RCTL_UPE)
+               phy_reg |= BM_RCTL_UPE;
+       if (mac_reg & E1000_RCTL_MPE)
+               phy_reg |= BM_RCTL_MPE;
+       phy_reg &= ~(BM_RCTL_MO_MASK);
+       if (mac_reg & E1000_RCTL_MO_3)
+               phy_reg |= (((mac_reg & E1000_RCTL_MO_3) >> E1000_RCTL_MO_SHIFT)
+                               << BM_RCTL_MO_SHIFT);
+       if (mac_reg & E1000_RCTL_BAM)
+               phy_reg |= BM_RCTL_BAM;
+       if (mac_reg & E1000_RCTL_PMCF)
+               phy_reg |= BM_RCTL_PMCF;
+       mac_reg = er32(CTRL);
+       if (mac_reg & E1000_CTRL_RFCE)
+               phy_reg |= BM_RCTL_RFCE;
+       e1e_wphy(&adapter->hw, BM_RCTL, phy_reg);
+
+       /* enable PHY wakeup in MAC register */
+       ew32(WUFC, wufc);
+       ew32(WUC, E1000_WUC_PHY_WAKE | E1000_WUC_PME_EN);
+
+       /* configure and enable PHY wakeup in PHY registers */
+       e1e_wphy(&adapter->hw, BM_WUFC, wufc);
+       e1e_wphy(&adapter->hw, BM_WUC, E1000_WUC_PME_EN);
+
+       /* activate PHY wakeup */
+       retval = hw->phy.ops.acquire_phy(hw);
+       if (retval) {
+               e_err("Could not acquire PHY\n");
+               return retval;
+       }
+       e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
+                                (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT));
+       retval = e1000e_read_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, &phy_reg);
+       if (retval) {
+               e_err("Could not read PHY page 769\n");
+               goto out;
+       }
+       phy_reg |= BM_WUC_ENABLE_BIT | BM_WUC_HOST_WU_BIT;
+       retval = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg);
+       if (retval)
+               e_err("Could not set PHY Host Wakeup bit\n");
+out:
+       hw->phy.ops.release_phy(hw);
+
+       return retval;
+}
+
 static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
@@ -4392,8 +4518,9 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake)
                #define E1000_CTRL_ADVD3WUC 0x00100000
                /* phy power management enable */
                #define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000
-               ctrl |= E1000_CTRL_ADVD3WUC |
-                       E1000_CTRL_EN_PHY_PWR_MGMT;
+               ctrl |= E1000_CTRL_ADVD3WUC;
+               if (!(adapter->flags2 & FLAG2_HAS_PHY_WAKEUP))
+                       ctrl |= E1000_CTRL_EN_PHY_PWR_MGMT;
                ew32(CTRL, ctrl);
 
                if (adapter->hw.phy.media_type == e1000_media_type_fiber ||
@@ -4411,8 +4538,17 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake)
                /* Allow time for pending master requests to run */
                e1000e_disable_pcie_master(&adapter->hw);
 
-               ew32(WUC, E1000_WUC_PME_EN);
-               ew32(WUFC, wufc);
+               if ((adapter->flags2 & FLAG2_HAS_PHY_WAKEUP) &&
+                   !(hw->mac.ops.check_mng_mode(hw))) {
+                       /* enable wakeup by the PHY */
+                       retval = e1000_init_phy_wakeup(adapter, wufc);
+                       if (retval)
+                               return retval;
+               } else {
+                       /* enable wakeup by the MAC */
+                       ew32(WUFC, wufc);
+                       ew32(WUC, E1000_WUC_PME_EN);
+               }
        } else {
                ew32(WUC, 0);
                ew32(WUFC, 0);
@@ -4555,8 +4691,37 @@ static int e1000_resume(struct pci_dev *pdev)
        }
 
        e1000e_power_up_phy(adapter);
+
+       /* report the system wakeup cause from S3/S4 */
+       if (adapter->flags2 & FLAG2_HAS_PHY_WAKEUP) {
+               u16 phy_data;
+
+               e1e_rphy(&adapter->hw, BM_WUS, &phy_data);
+               if (phy_data) {
+                       e_info("PHY Wakeup cause - %s\n",
+                               phy_data & E1000_WUS_EX ? "Unicast Packet" :
+                               phy_data & E1000_WUS_MC ? "Multicast Packet" :
+                               phy_data & E1000_WUS_BC ? "Broadcast Packet" :
+                               phy_data & E1000_WUS_MAG ? "Magic Packet" :
+                               phy_data & E1000_WUS_LNKC ? "Link Status "
+                               " Change" : "other");
+               }
+               e1e_wphy(&adapter->hw, BM_WUS, ~0);
+       } else {
+               u32 wus = er32(WUS);
+               if (wus) {
+                       e_info("MAC Wakeup cause - %s\n",
+                               wus & E1000_WUS_EX ? "Unicast Packet" :
+                               wus & E1000_WUS_MC ? "Multicast Packet" :
+                               wus & E1000_WUS_BC ? "Broadcast Packet" :
+                               wus & E1000_WUS_MAG ? "Magic Packet" :
+                               wus & E1000_WUS_LNKC ? "Link Status Change" :
+                               "other");
+               }
+               ew32(WUS, ~0);
+       }
+
        e1000e_reset(adapter);
-       ew32(WUS, ~0);
 
        e1000_init_manageability(adapter);
 
@@ -4846,6 +5011,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
        adapter->flags2 = ei->flags2;
        adapter->hw.adapter = adapter;
        adapter->hw.mac.type = ei->mac;
+       adapter->max_hw_frame_size = ei->max_hw_frame_size;
        adapter->msg_enable = (1 << NETIF_MSG_DRV | NETIF_MSG_PROBE) - 1;
 
        mmio_start = pci_resource_start(pdev, 0);
@@ -5001,6 +5167,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
                /* APME bit in EEPROM is mapped to WUC.APME */
                eeprom_data = er32(WUC);
                eeprom_apme_mask = E1000_WUC_APME;
+               if (eeprom_data & E1000_WUC_PHY_WAKE)
+                       adapter->flags2 |= FLAG2_HAS_PHY_WAKEUP;
        } else if (adapter->flags & FLAG_APME_IN_CTRL3) {
                if (adapter->flags & FLAG_APME_CHECK_PORT_B &&
                    (adapter->hw.bus.func == 1))
@@ -5202,6 +5370,11 @@ static struct pci_device_id e1000_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LM), board_ich10lan },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LF), board_ich10lan },
 
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_M_HV_LM), board_pchlan },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_M_HV_LC), board_pchlan },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_D_HV_DM), board_pchlan },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_D_HV_DC), board_pchlan },
+
        { }     /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
index e909f96..1342e0b 100644 (file)
@@ -427,6 +427,8 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
                        e1000_validate_option(&crc_stripping, &opt, adapter);
                        if (crc_stripping == OPTION_ENABLED)
                                adapter->flags2 |= FLAG2_CRC_STRIPPING;
+               } else {
+                       adapter->flags2 |= FLAG2_CRC_STRIPPING;
                }
        }
        { /* Kumeran Lock Loss Workaround */
index dc4a9cb..e23459c 100644 (file)
@@ -37,6 +37,9 @@ static s32 e1000_wait_autoneg(struct e1000_hw *hw);
 static u32 e1000_get_phy_addr_for_bm_page(u32 page, u32 reg);
 static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,
                                          u16 *data, bool read);
+static u32 e1000_get_phy_addr_for_hv_page(u32 page);
+static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
+                                          u16 *data, bool read);
 
 /* Cable length tables */
 static const u16 e1000_m88_cable_length_table[] =
@@ -54,6 +57,55 @@ static const u16 e1000_igp_2_cable_length_table[] =
 #define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
                ARRAY_SIZE(e1000_igp_2_cable_length_table)
 
+#define BM_PHY_REG_PAGE(offset) \
+       ((u16)(((offset) >> PHY_PAGE_SHIFT) & 0xFFFF))
+#define BM_PHY_REG_NUM(offset) \
+       ((u16)(((offset) & MAX_PHY_REG_ADDRESS) |\
+        (((offset) >> (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)) &\
+               ~MAX_PHY_REG_ADDRESS)))
+
+#define HV_INTC_FC_PAGE_START             768
+#define I82578_ADDR_REG                   29
+#define I82577_ADDR_REG                   16
+#define I82577_CFG_REG                    22
+#define I82577_CFG_ASSERT_CRS_ON_TX       (1 << 15)
+#define I82577_CFG_ENABLE_DOWNSHIFT       (3 << 10) /* auto downshift 100/10 */
+#define I82577_CTRL_REG                   23
+#define I82577_CTRL_DOWNSHIFT_MASK        (7 << 10)
+
+/* 82577 specific PHY registers */
+#define I82577_PHY_CTRL_2            18
+#define I82577_PHY_STATUS_2          26
+#define I82577_PHY_DIAG_STATUS       31
+
+/* I82577 PHY Status 2 */
+#define I82577_PHY_STATUS2_REV_POLARITY   0x0400
+#define I82577_PHY_STATUS2_MDIX           0x0800
+#define I82577_PHY_STATUS2_SPEED_MASK     0x0300
+#define I82577_PHY_STATUS2_SPEED_1000MBPS 0x0200
+
+/* I82577 PHY Control 2 */
+#define I82577_PHY_CTRL2_AUTO_MDIX        0x0400
+#define I82577_PHY_CTRL2_FORCE_MDI_MDIX   0x0200
+
+/* I82577 PHY Diagnostics Status */
+#define I82577_DSTATUS_CABLE_LENGTH       0x03FC
+#define I82577_DSTATUS_CABLE_LENGTH_SHIFT 2
+
+/* BM PHY Copper Specific Control 1 */
+#define BM_CS_CTRL1                       16
+
+/* BM PHY Copper Specific Status */
+#define BM_CS_STATUS                      17
+#define BM_CS_STATUS_LINK_UP              0x0400
+#define BM_CS_STATUS_RESOLVED             0x0800
+#define BM_CS_STATUS_SPEED_MASK           0xC000
+#define BM_CS_STATUS_SPEED_1000           0x8000
+
+#define HV_MUX_DATA_CTRL               PHY_REG(776, 16)
+#define HV_MUX_DATA_CTRL_GEN_TO_MAC    0x0400
+#define HV_MUX_DATA_CTRL_FORCE_SPEED   0x0004
+
 /**
  *  e1000e_check_reset_block_generic - Check if PHY reset is blocked
  *  @hw: pointer to the HW structure
@@ -82,23 +134,48 @@ s32 e1000e_check_reset_block_generic(struct e1000_hw *hw)
 s32 e1000e_get_phy_id(struct e1000_hw *hw)
 {
        struct e1000_phy_info *phy = &hw->phy;
-       s32 ret_val;
+       s32 ret_val = 0;
        u16 phy_id;
+       u16 retry_count = 0;
 
-       ret_val = e1e_rphy(hw, PHY_ID1, &phy_id);
-       if (ret_val)
-               return ret_val;
+       if (!(phy->ops.read_phy_reg))
+               goto out;
 
-       phy->id = (u32)(phy_id << 16);
-       udelay(20);
-       ret_val = e1e_rphy(hw, PHY_ID2, &phy_id);
-       if (ret_val)
-               return ret_val;
+       while (retry_count < 2) {
+               ret_val = e1e_rphy(hw, PHY_ID1, &phy_id);
+               if (ret_val)
+                       goto out;
 
-       phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
-       phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
+               phy->id = (u32)(phy_id << 16);
+               udelay(20);
+               ret_val = e1e_rphy(hw, PHY_ID2, &phy_id);
+               if (ret_val)
+                       goto out;
 
-       return 0;
+               phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
+               phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
+
+               if (phy->id != 0 && phy->id != PHY_REVISION_MASK)
+                       goto out;
+
+               /*
+                * If the PHY ID is still unknown, we may have an 82577i
+                * without link.  We will try again after setting Slow
+                * MDIC mode. No harm in trying again in this case since
+                * the PHY ID is unknown at this point anyway
+                */
+               ret_val = e1000_set_mdio_slow_mode_hv(hw, true);
+               if (ret_val)
+                       goto out;
+
+               retry_count++;
+       }
+out:
+       /* Revert to MDIO fast mode, if applicable */
+       if (retry_count)
+               ret_val = e1000_set_mdio_slow_mode_hv(hw, false);
+
+       return ret_val;
 }
 
 /**
@@ -410,6 +487,43 @@ s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data)
 }
 
 /**
+ *  e1000_copper_link_setup_82577 - Setup 82577 PHY for copper link
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets up Carrier-sense on Transmit and downshift values.
+ **/
+s32 e1000_copper_link_setup_82577(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32 ret_val;
+       u16 phy_data;
+
+       /* Enable CRS on TX. This must be set for half-duplex operation. */
+       ret_val = phy->ops.read_phy_reg(hw, I82577_CFG_REG, &phy_data);
+       if (ret_val)
+               goto out;
+
+       phy_data |= I82577_CFG_ASSERT_CRS_ON_TX;
+
+       /* Enable downshift */
+       phy_data |= I82577_CFG_ENABLE_DOWNSHIFT;
+
+       ret_val = phy->ops.write_phy_reg(hw, I82577_CFG_REG, phy_data);
+       if (ret_val)
+               goto out;
+
+       /* Set number of link attempts before downshift */
+       ret_val = phy->ops.read_phy_reg(hw, I82577_CTRL_REG, &phy_data);
+       if (ret_val)
+               goto out;
+       phy_data &= ~I82577_CTRL_DOWNSHIFT_MASK;
+       ret_val = phy->ops.write_phy_reg(hw, I82577_CTRL_REG, phy_data);
+
+out:
+       return ret_val;
+}
+
+/**
  *  e1000e_copper_link_setup_m88 - Setup m88 PHY's for copper link
  *  @hw: pointer to the HW structure
  *
@@ -427,8 +541,8 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw)
        if (ret_val)
                return ret_val;
 
-       /* For newer PHYs this bit is downshift enable */
-       if (phy->type == e1000_phy_m88)
+       /* For BM PHY this bit is downshift enable */
+       if (phy->type != e1000_phy_bm)
                phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
 
        /*
@@ -520,10 +634,27 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw)
 
        /* Commit the changes. */
        ret_val = e1000e_commit_phy(hw);
-       if (ret_val)
+       if (ret_val) {
                hw_dbg(hw, "Error committing the PHY changes\n");
+               return ret_val;
+       }
 
-       return ret_val;
+       if (phy->type == e1000_phy_82578) {
+               ret_val = phy->ops.read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+                                           &phy_data);
+               if (ret_val)
+                       return ret_val;
+
+               /* 82578 PHY - set the downshift count to 1x. */
+               phy_data |= I82578_EPSCR_DOWNSHIFT_ENABLE;
+               phy_data &= ~I82578_EPSCR_DOWNSHIFT_COUNTER_MASK;
+               ret_val = phy->ops.write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+                                            phy_data);
+               if (ret_val)
+                       return ret_val;
+       }
+
+       return 0;
 }
 
 /**
@@ -1251,6 +1382,8 @@ s32 e1000e_check_downshift(struct e1000_hw *hw)
        switch (phy->type) {
        case e1000_phy_m88:
        case e1000_phy_gg82563:
+       case e1000_phy_82578:
+       case e1000_phy_82577:
                offset  = M88E1000_PHY_SPEC_STATUS;
                mask    = M88E1000_PSSR_DOWNSHIFT;
                break;
@@ -1886,6 +2019,12 @@ enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id)
        case BME1000_E_PHY_ID_R2:
                phy_type = e1000_phy_bm;
                break;
+       case I82578_E_PHY_ID:
+               phy_type = e1000_phy_82578;
+               break;
+       case I82577_E_PHY_ID:
+               phy_type = e1000_phy_82577;
+               break;
        default:
                phy_type = e1000_phy_unknown;
                break;
@@ -2181,11 +2320,16 @@ static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,
                                          u16 *data, bool read)
 {
        s32 ret_val;
-       u16 reg = ((u16)offset) & PHY_REG_MASK;
+       u16 reg = BM_PHY_REG_NUM(offset);
        u16 phy_reg = 0;
        u8  phy_acquired = 1;
 
 
+       /* Gig must be disabled for MDIO accesses to page 800 */
+       if ((hw->mac.type == e1000_pchlan) &&
+          (!(er32(PHY_CTRL) & E1000_PHY_CTRL_GBE_DISABLE)))
+               hw_dbg(hw, "Attempting to access page 800 while gig enabled\n");
+
        ret_val = hw->phy.ops.acquire_phy(hw);
        if (ret_val) {
                phy_acquired = 0;
@@ -2289,3 +2433,524 @@ static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active)
 
        return 0;
 }
+
+s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow)
+{
+       s32 ret_val = 0;
+       u16 data = 0;
+
+       ret_val = hw->phy.ops.acquire_phy(hw);
+       if (ret_val)
+               return ret_val;
+
+       /* Set MDIO mode - page 769, register 16: 0x2580==slow, 0x2180==fast */
+       hw->phy.addr = 1;
+       ret_val = e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
+                                        (BM_PORT_CTRL_PAGE << IGP_PAGE_SHIFT));
+       if (ret_val) {
+               hw->phy.ops.release_phy(hw);
+               return ret_val;
+       }
+       ret_val = e1000e_write_phy_reg_mdic(hw, BM_CS_CTRL1,
+                                          (0x2180 | (slow << 10)));
+
+       /* dummy read when reverting to fast mode - throw away result */
+       if (!slow)
+               e1000e_read_phy_reg_mdic(hw, BM_CS_CTRL1, &data);
+
+       hw->phy.ops.release_phy(hw);
+
+       return ret_val;
+}
+
+/**
+ *  e1000_read_phy_reg_hv -  Read HV PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquires semaphore, if necessary, then reads the PHY register at offset
+ *  and storing the retrieved information in data.  Release any acquired
+ *  semaphore before exiting.
+ **/
+s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+       s32 ret_val;
+       u16 page = BM_PHY_REG_PAGE(offset);
+       u16 reg = BM_PHY_REG_NUM(offset);
+       bool in_slow_mode = false;
+
+       /* Workaround failure in MDIO access while cable is disconnected */
+       if ((hw->phy.type == e1000_phy_82577) &&
+           !(er32(STATUS) & E1000_STATUS_LU)) {
+               ret_val = e1000_set_mdio_slow_mode_hv(hw, true);
+               if (ret_val)
+                       goto out;
+
+               in_slow_mode = true;
+       }
+
+       /* Page 800 works differently than the rest so it has its own func */
+       if (page == BM_WUC_PAGE) {
+               ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset,
+                                                        data, true);
+               goto out;
+       }
+
+       if (page > 0 && page < HV_INTC_FC_PAGE_START) {
+               ret_val = e1000_access_phy_debug_regs_hv(hw, offset,
+                                                        data, true);
+               goto out;
+       }
+
+       ret_val = hw->phy.ops.acquire_phy(hw);
+       if (ret_val)
+               goto out;
+
+       hw->phy.addr = e1000_get_phy_addr_for_hv_page(page);
+
+       if (page == HV_INTC_FC_PAGE_START)
+               page = 0;
+
+       if (reg > MAX_PHY_MULTI_PAGE_REG) {
+               if ((hw->phy.type != e1000_phy_82578) ||
+                   ((reg != I82578_ADDR_REG) &&
+                    (reg != I82578_ADDR_REG + 1))) {
+                       u32 phy_addr = hw->phy.addr;
+
+                       hw->phy.addr = 1;
+
+                       /* Page is shifted left, PHY expects (page x 32) */
+                       ret_val = e1000e_write_phy_reg_mdic(hw,
+                                                    IGP01E1000_PHY_PAGE_SELECT,
+                                                    (page << IGP_PAGE_SHIFT));
+                       if (ret_val) {
+                               hw->phy.ops.release_phy(hw);
+                               goto out;
+                       }
+                       hw->phy.addr = phy_addr;
+               }
+       }
+
+       ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg,
+                                         data);
+       hw->phy.ops.release_phy(hw);
+
+out:
+       /* Revert to MDIO fast mode, if applicable */
+       if ((hw->phy.type == e1000_phy_82577) && in_slow_mode)
+               ret_val = e1000_set_mdio_slow_mode_hv(hw, false);
+
+       return ret_val;
+}
+
+/**
+ *  e1000_write_phy_reg_hv - Write HV PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore, if necessary, then writes the data to PHY register
+ *  at the offset.  Release any acquired semaphores before exiting.
+ **/
+s32 e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data)
+{
+       s32 ret_val;
+       u16 page = BM_PHY_REG_PAGE(offset);
+       u16 reg = BM_PHY_REG_NUM(offset);
+       bool in_slow_mode = false;
+
+       /* Workaround failure in MDIO access while cable is disconnected */
+       if ((hw->phy.type == e1000_phy_82577) &&
+           !(er32(STATUS) & E1000_STATUS_LU)) {
+               ret_val = e1000_set_mdio_slow_mode_hv(hw, true);
+               if (ret_val)
+                       goto out;
+
+               in_slow_mode = true;
+       }
+
+       /* Page 800 works differently than the rest so it has its own func */
+       if (page == BM_WUC_PAGE) {
+               ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset,
+                                                        &data, false);
+               goto out;
+       }
+
+       if (page > 0 && page < HV_INTC_FC_PAGE_START) {
+               ret_val = e1000_access_phy_debug_regs_hv(hw, offset,
+                                                        &data, false);
+               goto out;
+       }
+
+       ret_val = hw->phy.ops.acquire_phy(hw);
+       if (ret_val)
+               goto out;
+
+       hw->phy.addr = e1000_get_phy_addr_for_hv_page(page);
+
+       if (page == HV_INTC_FC_PAGE_START)
+               page = 0;
+
+       /*
+        * Workaround MDIO accesses being disabled after entering IEEE Power
+        * Down (whenever bit 11 of the PHY Control register is set)
+        */
+       if ((hw->phy.type == e1000_phy_82578) &&
+           (hw->phy.revision >= 1) &&
+           (hw->phy.addr == 2) &&
+           ((MAX_PHY_REG_ADDRESS & reg) == 0) &&
+           (data & (1 << 11))) {
+               u16 data2 = 0x7EFF;
+               hw->phy.ops.release_phy(hw);
+               ret_val = e1000_access_phy_debug_regs_hv(hw, (1 << 6) | 0x3,
+                                                        &data2, false);
+               if (ret_val)
+                       goto out;
+
+               ret_val = hw->phy.ops.acquire_phy(hw);
+               if (ret_val)
+                       goto out;
+       }
+
+       if (reg > MAX_PHY_MULTI_PAGE_REG) {
+               if ((hw->phy.type != e1000_phy_82578) ||
+                   ((reg != I82578_ADDR_REG) &&
+                    (reg != I82578_ADDR_REG + 1))) {
+                       u32 phy_addr = hw->phy.addr;
+
+                       hw->phy.addr = 1;
+
+                       /* Page is shifted left, PHY expects (page x 32) */
+                       ret_val = e1000e_write_phy_reg_mdic(hw,
+                                                    IGP01E1000_PHY_PAGE_SELECT,
+                                                    (page << IGP_PAGE_SHIFT));
+                       if (ret_val) {
+                               hw->phy.ops.release_phy(hw);
+                               goto out;
+                       }
+                       hw->phy.addr = phy_addr;
+               }
+       }
+
+       ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg,
+                                         data);
+       hw->phy.ops.release_phy(hw);
+
+out:
+       /* Revert to MDIO fast mode, if applicable */
+       if ((hw->phy.type == e1000_phy_82577) && in_slow_mode)
+               ret_val = e1000_set_mdio_slow_mode_hv(hw, false);
+
+       return ret_val;
+}
+
+/**
+ *  e1000_get_phy_addr_for_hv_page - Get PHY adrress based on page
+ *  @page: page to be accessed
+ **/
+static u32 e1000_get_phy_addr_for_hv_page(u32 page)
+{
+       u32 phy_addr = 2;
+
+       if (page >= HV_INTC_FC_PAGE_START)
+               phy_addr = 1;
+
+       return phy_addr;
+}
+
+/**
+ *  e1000_access_phy_debug_regs_hv - Read HV PHY vendor specific high registers
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read or written
+ *  @data: pointer to the data to be read or written
+ *  @read: determines if operation is read or written
+ *
+ *  Acquires semaphore, if necessary, then reads the PHY register at offset
+ *  and storing the retreived information in data.  Release any acquired
+ *  semaphores before exiting.  Note that the procedure to read these regs
+ *  uses the address port and data port to read/write.
+ **/
+static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
+                                          u16 *data, bool read)
+{
+       s32 ret_val;
+       u32 addr_reg = 0;
+       u32 data_reg = 0;
+       u8  phy_acquired = 1;
+
+       /* This takes care of the difference with desktop vs mobile phy */
+       addr_reg = (hw->phy.type == e1000_phy_82578) ?
+                  I82578_ADDR_REG : I82577_ADDR_REG;
+       data_reg = addr_reg + 1;
+
+       ret_val = hw->phy.ops.acquire_phy(hw);
+       if (ret_val) {
+               hw_dbg(hw, "Could not acquire PHY\n");
+               phy_acquired = 0;
+               goto out;
+       }
+
+       /* All operations in this function are phy address 2 */
+       hw->phy.addr = 2;
+
+       /* masking with 0x3F to remove the page from offset */
+       ret_val = e1000e_write_phy_reg_mdic(hw, addr_reg, (u16)offset & 0x3F);
+       if (ret_val) {
+               hw_dbg(hw, "Could not write PHY the HV address register\n");
+               goto out;
+       }
+
+       /* Read or write the data value next */
+       if (read)
+               ret_val = e1000e_read_phy_reg_mdic(hw, data_reg, data);
+       else
+               ret_val = e1000e_write_phy_reg_mdic(hw, data_reg, *data);
+
+       if (ret_val) {
+               hw_dbg(hw, "Could not read data value from HV data register\n");
+               goto out;
+       }
+
+out:
+       if (phy_acquired == 1)
+               hw->phy.ops.release_phy(hw);
+       return ret_val;
+}
+
+/**
+ *  e1000_link_stall_workaround_hv - Si workaround
+ *  @hw: pointer to the HW structure
+ *
+ *  This function works around a Si bug where the link partner can get
+ *  a link up indication before the PHY does.  If small packets are sent
+ *  by the link partner they can be placed in the packet buffer without
+ *  being properly accounted for by the PHY and will stall preventing
+ *  further packets from being received.  The workaround is to clear the
+ *  packet buffer after the PHY detects link up.
+ **/
+s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw)
+{
+       s32 ret_val = 0;
+       u16 data;
+
+       if (hw->phy.type != e1000_phy_82578)
+               goto out;
+
+       /* check if link is up and at 1Gbps */
+       ret_val = hw->phy.ops.read_phy_reg(hw, BM_CS_STATUS, &data);
+       if (ret_val)
+               goto out;
+
+       data &= BM_CS_STATUS_LINK_UP |
+               BM_CS_STATUS_RESOLVED |
+               BM_CS_STATUS_SPEED_MASK;
+
+       if (data != (BM_CS_STATUS_LINK_UP |
+                    BM_CS_STATUS_RESOLVED |
+                    BM_CS_STATUS_SPEED_1000))
+               goto out;
+
+       mdelay(200);
+
+       /* flush the packets in the fifo buffer */
+       ret_val = hw->phy.ops.write_phy_reg(hw, HV_MUX_DATA_CTRL,
+                                       HV_MUX_DATA_CTRL_GEN_TO_MAC |
+                                       HV_MUX_DATA_CTRL_FORCE_SPEED);
+       if (ret_val)
+               goto out;
+
+       ret_val = hw->phy.ops.write_phy_reg(hw, HV_MUX_DATA_CTRL,
+                                       HV_MUX_DATA_CTRL_GEN_TO_MAC);
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_check_polarity_82577 - Checks the polarity.
+ *  @hw: pointer to the HW structure
+ *
+ *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ *  Polarity is determined based on the PHY specific status register.
+ **/
+s32 e1000_check_polarity_82577(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32 ret_val;
+       u16 data;
+
+       ret_val = phy->ops.read_phy_reg(hw, I82577_PHY_STATUS_2, &data);
+
+       if (!ret_val)
+               phy->cable_polarity = (data & I82577_PHY_STATUS2_REV_POLARITY)
+                                     ? e1000_rev_polarity_reversed
+                                     : e1000_rev_polarity_normal;
+
+       return ret_val;
+}
+
+/**
+ *  e1000_phy_force_speed_duplex_82577 - Force speed/duplex for I82577 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Calls the PHY setup function to force speed and duplex.  Clears the
+ *  auto-crossover to force MDI manually.  Waits for link and returns
+ *  successful if link up is successful, else -E1000_ERR_PHY (-2).
+ **/
+s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32 ret_val;
+       u16 phy_data;
+       bool link;
+
+       ret_val = phy->ops.read_phy_reg(hw, PHY_CONTROL, &phy_data);
+       if (ret_val)
+               goto out;
+
+       e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
+
+       ret_val = phy->ops.write_phy_reg(hw, PHY_CONTROL, phy_data);
+       if (ret_val)
+               goto out;
+
+       /*
+        * Clear Auto-Crossover to force MDI manually.  82577 requires MDI
+        * forced whenever speed and duplex are forced.
+        */
+       ret_val = phy->ops.read_phy_reg(hw, I82577_PHY_CTRL_2, &phy_data);
+       if (ret_val)
+               goto out;
+
+       phy_data &= ~I82577_PHY_CTRL2_AUTO_MDIX;
+       phy_data &= ~I82577_PHY_CTRL2_FORCE_MDI_MDIX;
+
+       ret_val = phy->ops.write_phy_reg(hw, I82577_PHY_CTRL_2, phy_data);
+       if (ret_val)
+               goto out;
+
+       hw_dbg(hw, "I82577_PHY_CTRL_2: %X\n", phy_data);
+
+       udelay(1);
+
+       if (phy->autoneg_wait_to_complete) {
+               hw_dbg(hw, "Waiting for forced speed/duplex link on 82577 phy\n");
+
+               ret_val = e1000e_phy_has_link_generic(hw,
+                                                    PHY_FORCE_LIMIT,
+                                                    100000,
+                                                    &link);
+               if (ret_val)
+                       goto out;
+
+               if (!link)
+                       hw_dbg(hw, "Link taking longer than expected.\n");
+
+               /* Try once more */
+               ret_val = e1000e_phy_has_link_generic(hw,
+                                                    PHY_FORCE_LIMIT,
+                                                    100000,
+                                                    &link);
+               if (ret_val)
+                       goto out;
+       }
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_get_phy_info_82577 - Retrieve I82577 PHY information
+ *  @hw: pointer to the HW structure
+ *
+ *  Read PHY status to determine if link is up.  If link is up, then
+ *  set/determine 10base-T extended distance and polarity correction.  Read
+ *  PHY port status to determine MDI/MDIx and speed.  Based on the speed,
+ *  determine on the cable length, local and remote receiver.
+ **/
+s32 e1000_get_phy_info_82577(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32 ret_val;
+       u16 data;
+       bool link;
+
+       ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+       if (ret_val)
+               goto out;
+
+       if (!link) {
+               hw_dbg(hw, "Phy info is only valid if link is up\n");
+               ret_val = -E1000_ERR_CONFIG;
+               goto out;
+       }
+
+       phy->polarity_correction = true;
+
+       ret_val = e1000_check_polarity_82577(hw);
+       if (ret_val)
+               goto out;
+
+       ret_val = phy->ops.read_phy_reg(hw, I82577_PHY_STATUS_2, &data);
+       if (ret_val)
+               goto out;
+
+       phy->is_mdix = (data & I82577_PHY_STATUS2_MDIX) ? true : false;
+
+       if ((data & I82577_PHY_STATUS2_SPEED_MASK) ==
+           I82577_PHY_STATUS2_SPEED_1000MBPS) {
+               ret_val = hw->phy.ops.get_cable_length(hw);
+               if (ret_val)
+                       goto out;
+
+               ret_val = phy->ops.read_phy_reg(hw, PHY_1000T_STATUS, &data);
+               if (ret_val)
+                       goto out;
+
+               phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
+                               ? e1000_1000t_rx_status_ok
+                               : e1000_1000t_rx_status_not_ok;
+
+               phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
+                                ? e1000_1000t_rx_status_ok
+                                : e1000_1000t_rx_status_not_ok;
+       } else {
+               phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+               phy->local_rx = e1000_1000t_rx_status_undefined;
+               phy->remote_rx = e1000_1000t_rx_status_undefined;
+       }
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_get_cable_length_82577 - Determine cable length for 82577 PHY
+ *  @hw: pointer to the HW structure
+ *
+ * Reads the diagnostic status register and verifies result is valid before
+ * placing it in the phy_cable_length field.
+ **/
+s32 e1000_get_cable_length_82577(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32 ret_val;
+       u16 phy_data, length;
+
+       ret_val = phy->ops.read_phy_reg(hw, I82577_PHY_DIAG_STATUS, &phy_data);
+       if (ret_val)
+               goto out;
+
+       length = (phy_data & I82577_DSTATUS_CABLE_LENGTH) >>
+                I82577_DSTATUS_CABLE_LENGTH_SHIFT;
+
+       if (length == E1000_CABLE_LENGTH_UNDEFINED)
+               ret_val = E1000_ERR_PHY;
+
+       phy->cable_length = length;
+
+out:
+       return ret_val;
+}
index 9080f07..8005b60 100644 (file)
@@ -661,8 +661,6 @@ static int enic_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev)
        if (vnic_wq_desc_avail(wq) < MAX_SKB_FRAGS + 1)
                netif_stop_queue(netdev);
 
-       netdev->trans_start = jiffies;
-
        spin_unlock_irqrestore(&enic->wq_lock[0], flags);
 
        return NETDEV_TX_OK;
index d0b1d9f..b60a304 100644 (file)
  * Hardware access:
  */
 
-#define DEV_NEED_TIMERIRQ          0x000001  /* set the timer irq flag in the irq mask */
-#define DEV_NEED_LINKTIMER         0x000002  /* poll link settings. Relies on the timer irq */
-#define DEV_HAS_LARGEDESC          0x000004  /* device supports jumbo frames and needs packet format 2 */
-#define DEV_HAS_HIGH_DMA           0x000008  /* device supports 64bit dma */
-#define DEV_HAS_CHECKSUM           0x000010  /* device supports tx and rx checksum offloads */
-#define DEV_HAS_VLAN               0x000020  /* device supports vlan tagging and striping */
-#define DEV_HAS_MSI                0x000040  /* device supports MSI */
-#define DEV_HAS_MSI_X              0x000080  /* device supports MSI-X */
-#define DEV_HAS_POWER_CNTRL        0x000100  /* device supports power savings */
-#define DEV_HAS_STATISTICS_V1      0x000200  /* device supports hw statistics version 1 */
-#define DEV_HAS_STATISTICS_V2      0x000600  /* device supports hw statistics version 2 */
-#define DEV_HAS_STATISTICS_V3      0x000e00  /* device supports hw statistics version 3 */
-#define DEV_HAS_TEST_EXTENDED      0x001000  /* device supports extended diagnostic test */
-#define DEV_HAS_MGMT_UNIT          0x002000  /* device supports management unit */
-#define DEV_HAS_CORRECT_MACADDR    0x004000  /* device supports correct mac address order */
-#define DEV_HAS_COLLISION_FIX      0x008000  /* device supports tx collision fix */
-#define DEV_HAS_PAUSEFRAME_TX_V1   0x010000  /* device supports tx pause frames version 1 */
-#define DEV_HAS_PAUSEFRAME_TX_V2   0x020000  /* device supports tx pause frames version 2 */
-#define DEV_HAS_PAUSEFRAME_TX_V3   0x040000  /* device supports tx pause frames version 3 */
-#define DEV_NEED_TX_LIMIT          0x080000  /* device needs to limit tx */
-#define DEV_HAS_GEAR_MODE          0x100000  /* device supports gear mode */
+#define DEV_NEED_TIMERIRQ          0x0000001  /* set the timer irq flag in the irq mask */
+#define DEV_NEED_LINKTIMER         0x0000002  /* poll link settings. Relies on the timer irq */
+#define DEV_HAS_LARGEDESC          0x0000004  /* device supports jumbo frames and needs packet format 2 */
+#define DEV_HAS_HIGH_DMA           0x0000008  /* device supports 64bit dma */
+#define DEV_HAS_CHECKSUM           0x0000010  /* device supports tx and rx checksum offloads */
+#define DEV_HAS_VLAN               0x0000020  /* device supports vlan tagging and striping */
+#define DEV_HAS_MSI                0x0000040  /* device supports MSI */
+#define DEV_HAS_MSI_X              0x0000080  /* device supports MSI-X */
+#define DEV_HAS_POWER_CNTRL        0x0000100  /* device supports power savings */
+#define DEV_HAS_STATISTICS_V1      0x0000200  /* device supports hw statistics version 1 */
+#define DEV_HAS_STATISTICS_V2      0x0000600  /* device supports hw statistics version 2 */
+#define DEV_HAS_STATISTICS_V3      0x0000e00  /* device supports hw statistics version 3 */
+#define DEV_HAS_TEST_EXTENDED      0x0001000  /* device supports extended diagnostic test */
+#define DEV_HAS_MGMT_UNIT          0x0002000  /* device supports management unit */
+#define DEV_HAS_CORRECT_MACADDR    0x0004000  /* device supports correct mac address order */
+#define DEV_HAS_COLLISION_FIX      0x0008000  /* device supports tx collision fix */
+#define DEV_HAS_PAUSEFRAME_TX_V1   0x0010000  /* device supports tx pause frames version 1 */
+#define DEV_HAS_PAUSEFRAME_TX_V2   0x0020000  /* device supports tx pause frames version 2 */
+#define DEV_HAS_PAUSEFRAME_TX_V3   0x0040000  /* device supports tx pause frames version 3 */
+#define DEV_NEED_TX_LIMIT          0x0080000  /* device needs to limit tx */
+#define DEV_NEED_TX_LIMIT2         0x0180000  /* device needs to limit tx, expect for some revs */
+#define DEV_HAS_GEAR_MODE          0x0200000  /* device supports gear mode */
+#define DEV_NEED_PHY_INIT_FIX      0x0400000  /* device needs specific phy workaround */
+#define DEV_NEED_LOW_POWER_FIX     0x0800000  /* device needs special power up workaround */
+#define DEV_NEED_MSI_FIX           0x1000000  /* device needs msi workaround */
 
 enum {
        NvRegIrqStatus = 0x000,
@@ -898,6 +902,12 @@ enum {
 };
 static int phy_cross = NV_CROSSOVER_DETECTION_DISABLED;
 
+/*
+ * Power down phy when interface is down (persists through reboot;
+ * older Linux and other OSes may not power it up again)
+ */
+static int phy_power_down = 0;
+
 static inline struct fe_priv *get_nvpriv(struct net_device *dev)
 {
        return netdev_priv(dev);
@@ -1265,14 +1275,7 @@ static int phy_init(struct net_device *dev)
                        }
                }
                if (np->phy_model == PHY_MODEL_REALTEK_8201) {
-                       if (np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_32 ||
-                           np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_33 ||
-                           np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_34 ||
-                           np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_35 ||
-                           np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_36 ||
-                           np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_37 ||
-                           np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_38 ||
-                           np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_39) {
+                       if (np->driver_data & DEV_NEED_PHY_INIT_FIX) {
                                phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, MII_READ);
                                phy_reserved |= PHY_REALTEK_INIT7;
                                if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, phy_reserved)) {
@@ -1463,14 +1466,7 @@ static int phy_init(struct net_device *dev)
                        }
                }
                if (np->phy_model == PHY_MODEL_REALTEK_8201) {
-                       if (np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_32 ||
-                           np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_33 ||
-                           np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_34 ||
-                           np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_35 ||
-                           np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_36 ||
-                           np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_37 ||
-                           np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_38 ||
-                           np->device_id == PCI_DEVICE_ID_NVIDIA_NVENET_39) {
+                       if (np->driver_data & DEV_NEED_PHY_INIT_FIX) {
                                phy_reserved = mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, MII_READ);
                                phy_reserved |= PHY_REALTEK_INIT7;
                                if (mii_rw(dev, np->phyaddr, PHY_REALTEK_INIT_REG6, phy_reserved)) {
@@ -1503,7 +1499,10 @@ static int phy_init(struct net_device *dev)
 
        /* restart auto negotiation, power down phy */
        mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
-       mii_control |= (BMCR_ANRESTART | BMCR_ANENABLE | BMCR_PDOWN);
+       mii_control |= (BMCR_ANRESTART | BMCR_ANENABLE);
+       if (phy_power_down) {
+               mii_control |= BMCR_PDOWN;
+       }
        if (mii_rw(dev, np->phyaddr, MII_BMCR, mii_control)) {
                return PHY_ERROR;
        }
@@ -5534,7 +5533,7 @@ static int nv_close(struct net_device *dev)
 
        nv_drain_rxtx(dev);
 
-       if (np->wolenabled) {
+       if (np->wolenabled || !phy_power_down) {
                nv_txrx_gate(dev, false);
                writel(NVREG_PFF_ALWAYS|NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags);
                nv_start_rx(dev);
@@ -5835,8 +5834,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
                /* take phy and nic out of low power mode */
                powerstate = readl(base + NvRegPowerState2);
                powerstate &= ~NVREG_POWERSTATE2_POWERUP_MASK;
-               if ((id->device == PCI_DEVICE_ID_NVIDIA_NVENET_12 ||
-                    id->device == PCI_DEVICE_ID_NVIDIA_NVENET_13) &&
+               if ((id->driver_data & DEV_NEED_LOW_POWER_FIX) &&
                    pci_dev->revision >= 0xA3)
                        powerstate |= NVREG_POWERSTATE2_POWERUP_REV_A3;
                writel(powerstate, base + NvRegPowerState2);
@@ -5892,14 +5890,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
        /* Limit the number of tx's outstanding for hw bug */
        if (id->driver_data & DEV_NEED_TX_LIMIT) {
                np->tx_limit = 1;
-               if ((id->device == PCI_DEVICE_ID_NVIDIA_NVENET_32 ||
-                    id->device == PCI_DEVICE_ID_NVIDIA_NVENET_33 ||
-                    id->device == PCI_DEVICE_ID_NVIDIA_NVENET_34 ||
-                    id->device == PCI_DEVICE_ID_NVIDIA_NVENET_35 ||
-                    id->device == PCI_DEVICE_ID_NVIDIA_NVENET_36 ||
-                    id->device == PCI_DEVICE_ID_NVIDIA_NVENET_37 ||
-                    id->device == PCI_DEVICE_ID_NVIDIA_NVENET_38 ||
-                    id->device == PCI_DEVICE_ID_NVIDIA_NVENET_39) &&
+               if ((id->driver_data & DEV_NEED_TX_LIMIT2) &&
                    pci_dev->revision >= 0xA2)
                        np->tx_limit = 0;
        }
@@ -6149,7 +6140,8 @@ static int nv_resume(struct pci_dev *pdev)
        for (i = 0;i <= np->register_size/sizeof(u32); i++)
                writel(np->saved_config_space[i], base+i*sizeof(u32));
 
-       pci_write_config_dword(pdev, NV_MSI_PRIV_OFFSET, NV_MSI_PRIV_VALUE);
+       if (np->driver_data & DEV_NEED_MSI_FIX)
+               pci_write_config_dword(pdev, NV_MSI_PRIV_OFFSET, NV_MSI_PRIV_VALUE);
 
        /* restore phy state, including autoneg */
        phy_init(dev);
@@ -6198,160 +6190,164 @@ static void nv_shutdown(struct pci_dev *pdev)
 
 static struct pci_device_id pci_tbl[] = {
        {       /* nForce Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_1),
+               PCI_DEVICE(0x10DE, 0x01C3),
                .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* nForce2 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_2),
+               PCI_DEVICE(0x10DE, 0x0066),
                .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* nForce3 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_3),
+               PCI_DEVICE(0x10DE, 0x00D6),
                .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
        },
        {       /* nForce3 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_4),
+               PCI_DEVICE(0x10DE, 0x0086),
                .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM,
        },
        {       /* nForce3 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_5),
+               PCI_DEVICE(0x10DE, 0x008C),
                .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM,
        },
        {       /* nForce3 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_6),
+               PCI_DEVICE(0x10DE, 0x00E6),
                .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM,
        },
        {       /* nForce3 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_7),
+               PCI_DEVICE(0x10DE, 0x00DF),
                .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM,
        },
        {       /* CK804 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8),
+               PCI_DEVICE(0x10DE, 0x0056),
                .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT,
        },
        {       /* CK804 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9),
+               PCI_DEVICE(0x10DE, 0x0057),
                .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT,
        },
        {       /* MCP04 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10),
+               PCI_DEVICE(0x10DE, 0x0037),
                .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT,
        },
        {       /* MCP04 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11),
+               PCI_DEVICE(0x10DE, 0x0038),
                .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT,
        },
        {       /* MCP51 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1,
+               PCI_DEVICE(0x10DE, 0x0268),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1|DEV_NEED_LOW_POWER_FIX,
        },
        {       /* MCP51 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1,
+               PCI_DEVICE(0x10DE, 0x0269),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1|DEV_NEED_LOW_POWER_FIX,
        },
        {       /* MCP55 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT,
+               PCI_DEVICE(0x10DE, 0x0372),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT|DEV_NEED_MSI_FIX,
        },
        {       /* MCP55 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT,
+               PCI_DEVICE(0x10DE, 0x0373),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_NEED_TX_LIMIT|DEV_NEED_MSI_FIX,
        },
        {       /* MCP61 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_16),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+               PCI_DEVICE(0x10DE, 0x03E5),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX,
        },
        {       /* MCP61 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_17),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+               PCI_DEVICE(0x10DE, 0x03E6),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX,
        },
        {       /* MCP61 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_18),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+               PCI_DEVICE(0x10DE, 0x03EE),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX,
        },
        {       /* MCP61 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_19),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+               PCI_DEVICE(0x10DE, 0x03EF),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_MSI_FIX,
        },
        {       /* MCP65 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_20),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               PCI_DEVICE(0x10DE, 0x0450),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
        },
        {       /* MCP65 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_21),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               PCI_DEVICE(0x10DE, 0x0451),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
        },
        {       /* MCP65 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_22),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               PCI_DEVICE(0x10DE, 0x0452),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
        },
        {       /* MCP65 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_23),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               PCI_DEVICE(0x10DE, 0x0453),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
        },
        {       /* MCP67 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_24),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE,
+               PCI_DEVICE(0x10DE, 0x054C),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
        },
        {       /* MCP67 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_25),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE,
+               PCI_DEVICE(0x10DE, 0x054D),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
        },
        {       /* MCP67 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_26),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE,
+               PCI_DEVICE(0x10DE, 0x054E),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
        },
        {       /* MCP67 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_27),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE,
+               PCI_DEVICE(0x10DE, 0x054F),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
        },
        {       /* MCP73 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_28),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE,
+               PCI_DEVICE(0x10DE, 0x07DC),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
        },
        {       /* MCP73 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_29),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE,
+               PCI_DEVICE(0x10DE, 0x07DD),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
        },
        {       /* MCP73 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_30),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE,
+               PCI_DEVICE(0x10DE, 0x07DE),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
        },
        {       /* MCP73 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_31),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE,
+               PCI_DEVICE(0x10DE, 0x07DF),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_MSI_FIX,
        },
        {       /* MCP77 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_32),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               PCI_DEVICE(0x10DE, 0x0760),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
        },
        {       /* MCP77 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_33),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               PCI_DEVICE(0x10DE, 0x0761),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
        },
        {       /* MCP77 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_34),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               PCI_DEVICE(0x10DE, 0x0762),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
        },
        {       /* MCP77 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_35),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               PCI_DEVICE(0x10DE, 0x0763),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
        },
        {       /* MCP79 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_36),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               PCI_DEVICE(0x10DE, 0x0AB0),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
        },
        {       /* MCP79 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_37),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               PCI_DEVICE(0x10DE, 0x0AB1),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
        },
        {       /* MCP79 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_38),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               PCI_DEVICE(0x10DE, 0x0AB2),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
        },
        {       /* MCP79 Ethernet Controller */
-               PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_39),
-               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               PCI_DEVICE(0x10DE, 0x0AB3),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT2|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX|DEV_NEED_MSI_FIX,
+       },
+       {       /* MCP89 Ethernet Controller */
+               PCI_DEVICE(0x10DE, 0x0D7D),
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE|DEV_NEED_PHY_INIT_FIX,
        },
        {0,},
 };
@@ -6390,6 +6386,8 @@ module_param(dma_64bit, int, 0);
 MODULE_PARM_DESC(dma_64bit, "High DMA is enabled by setting to 1 and disabled by setting to 0.");
 module_param(phy_cross, int, 0);
 MODULE_PARM_DESC(phy_cross, "Phy crossover detection for Realtek 8201 phy is enabled by setting to 1 and disabled by setting to 0.");
+module_param(phy_power_down, int, 0);
+MODULE_PARM_DESC(phy_power_down, "Power down phy and disable link when interface is down (1), or leave phy powered up (0).");
 
 MODULE_AUTHOR("Manfred Spraul <manfred@colorfullife.com>");
 MODULE_DESCRIPTION("Reverse Engineered nForce ethernet driver");
index d12e0e0..3af5813 100644 (file)
@@ -301,13 +301,17 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev,
                        of_device_is_compatible(np, "ucc_geth_phy")) {
 #ifdef CONFIG_UCC_GETH
                u32 id;
+               static u32 mii_mng_master;
 
                tbipa = &regs->utbipar;
 
                if ((err = get_ucc_id_for_range(addr, addr + size, &id)))
                        goto err_free_irqs;
 
-               ucc_set_qe_mux_mii_mng(id - 1);
+               if (!mii_mng_master) {
+                       mii_mng_master = id;
+                       ucc_set_qe_mux_mii_mng(id - 1);
+               }
 #else
                err = -ENODEV;
                goto err_free_irqs;
index 91317bc..2cd9433 100644 (file)
@@ -259,7 +259,7 @@ extern const char gfar_driver_version[];
 (IEVENT_RXC | IEVENT_BSY | IEVENT_EBERR | IEVENT_MSRO | \
  IEVENT_BABT | IEVENT_TXC | IEVENT_TXE | IEVENT_LC \
  | IEVENT_CRL | IEVENT_XFUN | IEVENT_DPE | IEVENT_PERR \
- | IEVENT_MAG)
+ | IEVENT_MAG | IEVENT_BABR)
 
 #define IMASK_INIT_CLEAR       0x00000000
 #define IMASK_BABR              0x80000000
index 310ee03..26151fa 100644 (file)
@@ -1163,7 +1163,7 @@ static void hamachi_tx_timeout(struct net_device *dev)
        hmp->rx_ring[RX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing);
 
        /* Trigger an immediate transmit demand. */
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        hmp->stats.tx_errors++;
 
        /* Restart the chip's Tx/Rx processes . */
@@ -1364,7 +1364,6 @@ static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev)
                hmp->tx_full = 1;
                netif_stop_queue(dev);
        }
-       dev->trans_start = jiffies;
 
        if (hamachi_debug > 4) {
                printk(KERN_DEBUG "%s: Hamachi transmit frame #%d queued in slot %d.\n",
index 8e93750..ea17319 100644 (file)
@@ -3139,8 +3139,7 @@ static inline int igb_tx_map_adv(struct igb_adapter *adapter,
        /* set time_stamp *before* dma to help avoid a possible race */
        buffer_info->time_stamp = jiffies;
        buffer_info->next_to_watch = i;
-       buffer_info->dma = map[count];
-       count++;
+       buffer_info->dma = skb_shinfo(skb)->dma_head;
 
        for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
                struct skb_frag_struct *frag;
@@ -3164,7 +3163,7 @@ static inline int igb_tx_map_adv(struct igb_adapter *adapter,
        tx_ring->buffer_info[i].skb = skb;
        tx_ring->buffer_info[first].next_to_watch = i;
 
-       return count;
+       return count + 1;
 }
 
 static inline void igb_tx_queue_adv(struct igb_adapter *adapter,
@@ -3344,7 +3343,6 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb,
        if (count) {
                igb_tx_queue_adv(adapter, tx_ring, tx_flags, count,
                                 skb->len, hdr_len);
-               netdev->trans_start = jiffies;
                /* Make sure there is space in the ring for the next send. */
                igb_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 4);
        } else {
index 44a8eef..22aadb7 100644 (file)
@@ -2119,8 +2119,7 @@ static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter,
        /* set time_stamp *before* dma to help avoid a possible race */
        buffer_info->time_stamp = jiffies;
        buffer_info->next_to_watch = i;
-       buffer_info->dma = map[count];
-       count++;
+       buffer_info->dma = skb_shinfo(skb)->dma_head;
 
        for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
                struct skb_frag_struct *frag;
@@ -2144,7 +2143,7 @@ static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter,
        tx_ring->buffer_info[i].skb = skb;
        tx_ring->buffer_info[first].next_to_watch = i;
 
-       return count;
+       return count + 1;
 }
 
 static inline void igbvf_tx_queue_adv(struct igbvf_adapter *adapter,
@@ -2270,7 +2269,6 @@ static int igbvf_xmit_frame_ring_adv(struct sk_buff *skb,
        if (count) {
                igbvf_tx_queue_adv(adapter, tx_ring, tx_flags, count,
                                   skb->len, hdr_len);
-               netdev->trans_start = jiffies;
                /* Make sure there is space in the ring for the next send. */
                igbvf_maybe_stop_tx(netdev, MAX_SKB_FRAGS + 4);
        } else {
index 006ba23..394b2b1 100644 (file)
@@ -1859,6 +1859,42 @@ static void irda_usb_disconnect(struct usb_interface *intf)
        IRDA_DEBUG(0, "%s(), USB IrDA Disconnected\n", __func__);
 }
 
+#ifdef CONFIG_PM
+/* USB suspend, so power off the transmitter/receiver */
+static int irda_usb_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct irda_usb_cb *self = usb_get_intfdata(intf);
+       int i;
+
+       netif_device_detach(self->netdev);
+
+       if (self->tx_urb != NULL)
+               usb_kill_urb(self->tx_urb);
+       if (self->speed_urb != NULL)
+               usb_kill_urb(self->speed_urb);
+       for (i = 0; i < self->max_rx_urb; i++) {
+               if (self->rx_urb[i] != NULL)
+                       usb_kill_urb(self->rx_urb[i]);
+       }
+       return 0;
+}
+
+/* Coming out of suspend, so reset hardware */
+static int irda_usb_resume(struct usb_interface *intf)
+{
+       struct irda_usb_cb *self = usb_get_intfdata(intf);
+       int i;
+
+       for (i = 0; i < self->max_rx_urb; i++) {
+               if (self->rx_urb[i] != NULL)
+                       usb_submit_urb(self->rx_urb[i], GFP_KERNEL);
+       }
+
+       netif_device_attach(self->netdev);
+       return 0;
+}
+#endif
+
 /*------------------------------------------------------------------*/
 /*
  * USB device callbacks
@@ -1868,6 +1904,10 @@ static struct usb_driver irda_driver = {
        .probe          = irda_usb_probe,
        .disconnect     = irda_usb_disconnect,
        .id_table       = dongles,
+#ifdef CONFIG_PM
+       .suspend        = irda_usb_suspend,
+       .resume         = irda_usb_resume,
+#endif
 };
 
 /************************* MODULE CALLBACKS *************************/
index 04cb81a..9c897cf 100644 (file)
@@ -1300,7 +1300,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
                buffer_info->length = size;
                WARN_ON(buffer_info->dma != 0);
                buffer_info->time_stamp = jiffies;
-               buffer_info->dma = map[0] + offset;
+               buffer_info->dma = skb_shinfo(skb)->dma_head + offset;
                        pci_map_single(adapter->pdev,
                                skb->data + offset,
                                size,
@@ -1340,7 +1340,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
 
                        buffer_info->length = size;
                        buffer_info->time_stamp = jiffies;
-                       buffer_info->dma = map[f + 1] + offset;
+                       buffer_info->dma = map[f] + offset;
                        buffer_info->next_to_watch = 0;
 
                        len -= size;
@@ -1488,7 +1488,6 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 
        if (count) {
                ixgb_tx_queue(adapter, count, vlan_id, tx_flags);
-               netdev->trans_start = jiffies;
                /* Make sure there is space in the ring for the next send. */
                ixgb_maybe_stop_tx(netdev, &adapter->tx_ring, DESC_NEEDED);
 
index 05a2405..cd22323 100644 (file)
@@ -121,17 +121,18 @@ struct ixgbe_queue_stats {
 
 struct ixgbe_ring {
        void *desc;                     /* descriptor ring memory */
-       dma_addr_t dma;                 /* phys. address of descriptor ring */
-       unsigned int size;              /* length in bytes */
-       unsigned int count;             /* amount of descriptors */
-       unsigned int next_to_use;
-       unsigned int next_to_clean;
-
-       int queue_index; /* needed for multiqueue queue management */
        union {
                struct ixgbe_tx_buffer *tx_buffer_info;
                struct ixgbe_rx_buffer *rx_buffer_info;
        };
+       u8 atr_sample_rate;
+       u8 atr_count;
+       u16 count;                      /* amount of descriptors */
+       u16 rx_buf_len;
+       u16 next_to_use;
+       u16 next_to_clean;
+
+       u8 queue_index; /* needed for multiqueue queue management */
 
        u16 head;
        u16 tail;
@@ -139,23 +140,24 @@ struct ixgbe_ring {
        unsigned int total_bytes;
        unsigned int total_packets;
 
-       u16 reg_idx; /* holds the special value that gets the hardware register
-                     * offset associated with this ring, which is different
-                     * for DCB and RSS modes */
-
 #ifdef CONFIG_IXGBE_DCA
        /* cpu for tx queue */
        int cpu;
 #endif
-       struct ixgbe_queue_stats stats;
-       u64 v_idx; /* maps directly to the index for this ring in the hardware
-                   * vector array, can also be used for finding the bit in EICR
-                   * and friends that represents the vector for this ring */
 
+       u16 work_limit;                 /* max work per interrupt */
+       u16 reg_idx;                    /* holds the special value that gets
+                                        * the hardware register offset
+                                        * associated with this ring, which is
+                                        * different for DCB and RSS modes
+                                        */
 
-       u16 work_limit;                /* max work per interrupt */
-       u16 rx_buf_len;
-       u64 rsc_count;                 /* stat for coalesced packets */
+       struct ixgbe_queue_stats stats;
+       unsigned long reinit_state;
+       u64 rsc_count;                  /* stat for coalesced packets */
+
+       unsigned int size;              /* length in bytes */
+       dma_addr_t dma;                 /* phys. address of descriptor ring */
 };
 
 enum ixgbe_ring_f_enum {
@@ -163,6 +165,7 @@ enum ixgbe_ring_f_enum {
        RING_F_DCB,
        RING_F_VMDQ,
        RING_F_RSS,
+       RING_F_FDIR,
 #ifdef IXGBE_FCOE
        RING_F_FCOE,
 #endif /* IXGBE_FCOE */
@@ -173,6 +176,7 @@ enum ixgbe_ring_f_enum {
 #define IXGBE_MAX_DCB_INDICES   8
 #define IXGBE_MAX_RSS_INDICES  16
 #define IXGBE_MAX_VMDQ_INDICES 16
+#define IXGBE_MAX_FDIR_INDICES 64
 #ifdef IXGBE_FCOE
 #define IXGBE_MAX_FCOE_INDICES  8
 #endif /* IXGBE_FCOE */
@@ -193,6 +197,9 @@ struct ixgbe_ring_feature {
  */
 struct ixgbe_q_vector {
        struct ixgbe_adapter *adapter;
+       unsigned int v_idx; /* index of q_vector within array, also used for
+                            * finding the bit in EICR and friends that
+                            * represents the vector for this ring */
        struct napi_struct napi;
        DECLARE_BITMAP(rxr_idx, MAX_RX_QUEUES); /* Rx ring indices */
        DECLARE_BITMAP(txr_idx, MAX_TX_QUEUES); /* Tx ring indices */
@@ -201,7 +208,6 @@ struct ixgbe_q_vector {
        u8 tx_itr;
        u8 rx_itr;
        u32 eitr;
-       u32 v_idx;        /* vector index in list */
 };
 
 /* Helper macros to switch between ints/sec and what the register uses.
@@ -223,6 +229,10 @@ 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 */
@@ -315,10 +325,13 @@ struct ixgbe_adapter {
 #define IXGBE_FLAG_IN_WATCHDOG_TASK             (u32)(1 << 23)
 #define IXGBE_FLAG_IN_SFP_LINK_TASK             (u32)(1 << 24)
 #define IXGBE_FLAG_IN_SFP_MOD_TASK              (u32)(1 << 25)
-#define IXGBE_FLAG_RSC_CAPABLE                  (u32)(1 << 26)
-#define IXGBE_FLAG_RSC_ENABLED                  (u32)(1 << 27)
+#define IXGBE_FLAG_FDIR_HASH_CAPABLE            (u32)(1 << 26)
+#define IXGBE_FLAG_FDIR_PERFECT_CAPABLE         (u32)(1 << 27)
 #define IXGBE_FLAG_FCOE_ENABLED                 (u32)(1 << 29)
 
+       u32 flags2;
+#define IXGBE_FLAG2_RSC_CAPABLE                 (u32)(1)
+#define IXGBE_FLAG2_RSC_ENABLED                 (u32)(1 << 1)
 /* default to trying for four seconds */
 #define IXGBE_TRY_LINK_TIMEOUT (4 * HZ)
 
@@ -327,6 +340,10 @@ struct ixgbe_adapter {
        struct pci_dev *pdev;
        struct net_device_stats net_stats;
 
+       u32 test_icr;
+       struct ixgbe_ring test_tx_ring;
+       struct ixgbe_ring test_rx_ring;
+
        /* structs defined in ixgbe_hw.h */
        struct ixgbe_hw hw;
        u16 msg_enable;
@@ -349,6 +366,10 @@ struct ixgbe_adapter {
        struct timer_list sfp_timer;
        struct work_struct multispeed_fiber_task;
        struct work_struct sfp_config_module_task;
+       u32 fdir_pballoc;
+       u32 atr_sample_rate;
+       spinlock_t fdir_perfect_lock;
+       struct work_struct fdir_reinit_task;
 #ifdef IXGBE_FCOE
        struct ixgbe_fcoe fcoe;
 #endif /* IXGBE_FCOE */
@@ -361,6 +382,7 @@ enum ixbge_state_t {
        __IXGBE_TESTING,
        __IXGBE_RESETTING,
        __IXGBE_DOWN,
+       __IXGBE_FDIR_INIT_DONE,
        __IXGBE_SFP_MODULE_NOT_FOUND
 };
 
@@ -393,7 +415,63 @@ extern void ixgbe_free_tx_resources(struct ixgbe_adapter *, struct ixgbe_ring *)
 extern void ixgbe_update_stats(struct ixgbe_adapter *adapter);
 extern int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter);
 extern void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter);
-extern void ixgbe_write_eitr(struct ixgbe_adapter *, int, u32);
+extern void ixgbe_write_eitr(struct ixgbe_q_vector *);
+extern int ethtool_ioctl(struct ifreq *ifr);
+extern s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw);
+extern s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 pballoc);
+extern s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc);
+extern s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw,
+                                                 struct ixgbe_atr_input *input,
+                                                 u8 queue);
+extern s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw,
+                                               struct ixgbe_atr_input *input,
+                                               u16 soft_id,
+                                               u8 queue);
+extern u16 ixgbe_atr_compute_hash_82599(struct ixgbe_atr_input *input, u32 key);
+extern s32 ixgbe_atr_set_vlan_id_82599(struct ixgbe_atr_input *input,
+                                       u16 vlan_id);
+extern s32 ixgbe_atr_set_src_ipv4_82599(struct ixgbe_atr_input *input,
+                                        u32 src_addr);
+extern s32 ixgbe_atr_set_dst_ipv4_82599(struct ixgbe_atr_input *input,
+                                        u32 dst_addr);
+extern s32 ixgbe_atr_set_src_ipv6_82599(struct ixgbe_atr_input *input,
+                                        u32 src_addr_1, u32 src_addr_2,
+                                        u32 src_addr_3, u32 src_addr_4);
+extern s32 ixgbe_atr_set_dst_ipv6_82599(struct ixgbe_atr_input *input,
+                                        u32 dst_addr_1, u32 dst_addr_2,
+                                        u32 dst_addr_3, u32 dst_addr_4);
+extern s32 ixgbe_atr_set_src_port_82599(struct ixgbe_atr_input *input,
+                                        u16 src_port);
+extern s32 ixgbe_atr_set_dst_port_82599(struct ixgbe_atr_input *input,
+                                        u16 dst_port);
+extern s32 ixgbe_atr_set_flex_byte_82599(struct ixgbe_atr_input *input,
+                                         u16 flex_byte);
+extern s32 ixgbe_atr_set_vm_pool_82599(struct ixgbe_atr_input *input,
+                                       u8 vm_pool);
+extern s32 ixgbe_atr_set_l4type_82599(struct ixgbe_atr_input *input,
+                                      u8 l4type);
+extern s32 ixgbe_atr_get_vlan_id_82599(struct ixgbe_atr_input *input,
+                                       u16 *vlan_id);
+extern s32 ixgbe_atr_get_src_ipv4_82599(struct ixgbe_atr_input *input,
+                                        u32 *src_addr);
+extern s32 ixgbe_atr_get_dst_ipv4_82599(struct ixgbe_atr_input *input,
+                                        u32 *dst_addr);
+extern s32 ixgbe_atr_get_src_ipv6_82599(struct ixgbe_atr_input *input,
+                                        u32 *src_addr_1, u32 *src_addr_2,
+                                        u32 *src_addr_3, u32 *src_addr_4);
+extern s32 ixgbe_atr_get_dst_ipv6_82599(struct ixgbe_atr_input *input,
+                                        u32 *dst_addr_1, u32 *dst_addr_2,
+                                        u32 *dst_addr_3, u32 *dst_addr_4);
+extern s32 ixgbe_atr_get_src_port_82599(struct ixgbe_atr_input *input,
+                                        u16 *src_port);
+extern s32 ixgbe_atr_get_dst_port_82599(struct ixgbe_atr_input *input,
+                                        u16 *dst_port);
+extern s32 ixgbe_atr_get_flex_byte_82599(struct ixgbe_atr_input *input,
+                                         u16 *flex_byte);
+extern s32 ixgbe_atr_get_vm_pool_82599(struct ixgbe_atr_input *input,
+                                       u8 *vm_pool);
+extern s32 ixgbe_atr_get_l4type_82599(struct ixgbe_atr_input *input,
+                                      u8 *l4type);
 #ifdef IXGBE_FCOE
 extern void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter);
 extern int ixgbe_fso(struct ixgbe_adapter *adapter,
index 88e8350..b992304 100644 (file)
@@ -293,6 +293,17 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num)
        u32 rmcs_reg;
        u32 reg;
 
+#ifdef CONFIG_DCB
+       if (hw->fc.requested_mode == ixgbe_fc_pfc)
+               goto out;
+
+#endif /* CONFIG_DCB */
+       /* Negotiate the fc mode to use */
+       ret_val = ixgbe_fc_autoneg(hw);
+       if (ret_val)
+               goto out;
+
+       /* Disable any previous flow control settings */
        fctrl_reg = IXGBE_READ_REG(hw, IXGBE_FCTRL);
        fctrl_reg &= ~(IXGBE_FCTRL_RFCE | IXGBE_FCTRL_RPFCE);
 
@@ -304,14 +315,20 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num)
         * 0: Flow control is completely disabled
         * 1: Rx flow control is enabled (we can receive pause frames,
         *    but not send pause frames).
-        * 2:  Tx flow control is enabled (we can send pause frames but
+        * 2: Tx flow control is enabled (we can send pause frames but
         *     we do not support receiving pause frames).
         * 3: Both Rx and Tx flow control (symmetric) are enabled.
         * other: Invalid.
+#ifdef CONFIG_DCB
+        * 4: Priority Flow Control is enabled.
+#endif
         */
        switch (hw->fc.current_mode) {
        case ixgbe_fc_none:
-               /* Flow control completely disabled by software override. */
+               /*
+                * Flow control is disabled by software override or autoneg.
+                * The code below will actually disable it in the HW.
+                */
                break;
        case ixgbe_fc_rx_pause:
                /*
@@ -336,6 +353,11 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num)
                fctrl_reg |= IXGBE_FCTRL_RFCE;
                rmcs_reg |= IXGBE_RMCS_TFCE_802_3X;
                break;
+#ifdef CONFIG_DCB
+       case ixgbe_fc_pfc:
+               goto out;
+               break;
+#endif /* CONFIG_DCB */
        default:
                hw_dbg(hw, "Flow control param set incorrectly\n");
                ret_val = -IXGBE_ERR_CONFIG;
@@ -343,7 +365,7 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num)
                break;
        }
 
-       /* Enable 802.3x based flow control settings. */
+       /* Set 802.3x based flow control settings. */
        fctrl_reg |= IXGBE_FCTRL_DPF;
        IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl_reg);
        IXGBE_WRITE_REG(hw, IXGBE_RMCS, rmcs_reg);
@@ -377,79 +399,6 @@ out:
 }
 
 /**
- *  ixgbe_setup_fc_82598 - Configure flow control settings
- *  @hw: pointer to hardware structure
- *  @packetbuf_num: packet buffer number (0-7)
- *
- *  Configures the flow control settings based on SW configuration.  This
- *  function is used for 802.3x flow control configuration only.
- **/
-static s32 ixgbe_setup_fc_82598(struct ixgbe_hw *hw, s32 packetbuf_num)
-{
-       s32 ret_val = 0;
-       ixgbe_link_speed speed;
-       bool link_up;
-
-       /* Validate the packetbuf configuration */
-       if (packetbuf_num < 0 || packetbuf_num > 7) {
-               hw_dbg(hw, "Invalid packet buffer number [%d], expected range is"
-                         " 0-7\n", packetbuf_num);
-               ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS;
-               goto out;
-       }
-
-       /*
-        * Validate the water mark configuration.  Zero water marks are invalid
-        * because it causes the controller to just blast out fc packets.
-        */
-       if (!hw->fc.low_water || !hw->fc.high_water || !hw->fc.pause_time) {
-               if (hw->fc.requested_mode != ixgbe_fc_none) {
-                       hw_dbg(hw, "Invalid water mark configuration\n");
-                       ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS;
-                       goto out;
-               }
-       }
-
-       /*
-        * Validate the requested mode.  Strict IEEE mode does not allow
-        * ixgbe_fc_rx_pause because it will cause testing anomalies.
-        */
-       if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) {
-               hw_dbg(hw, "ixgbe_fc_rx_pause not valid in strict IEEE mode\n");
-               ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS;
-               goto out;
-       }
-
-       /*
-        * 10gig parts do not have a word in the EEPROM to determine the
-        * default flow control setting, so we explicitly set it to full.
-        */
-       if (hw->fc.requested_mode == ixgbe_fc_default)
-               hw->fc.requested_mode = ixgbe_fc_full;
-
-       /*
-        * Save off the requested flow control mode for use later.  Depending
-        * on the link partner's capabilities, we may or may not use this mode.
-        */
-
-       hw->fc.current_mode = hw->fc.requested_mode;
-
-       /* Decide whether to use autoneg or not. */
-       hw->mac.ops.check_link(hw, &speed, &link_up, false);
-       if (!hw->fc.disable_fc_autoneg && hw->phy.multispeed_fiber &&
-           (speed == IXGBE_LINK_SPEED_1GB_FULL))
-               ret_val = ixgbe_fc_autoneg(hw);
-
-       if (ret_val)
-               goto out;
-
-       ret_val = ixgbe_fc_enable_82598(hw, packetbuf_num);
-
-out:
-       return ret_val;
-}
-
-/**
  *  ixgbe_setup_mac_link_82598 - Configures MAC link settings
  *  @hw: pointer to hardware structure
  *
@@ -488,13 +437,6 @@ static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw)
                }
        }
 
-       /*
-        * 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.
-        */
-       ixgbe_setup_fc_82598(hw, 0);
-
        /* Add delay to filter out noises during initial link setup */
        msleep(50);
 
@@ -581,6 +523,11 @@ static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw,
        else
                *speed = IXGBE_LINK_SPEED_1GB_FULL;
 
+       /* if link is down, zero out the current_mode */
+       if (*link_up == false) {
+               hw->fc.current_mode = ixgbe_fc_none;
+               hw->fc.fc_was_autonegged = false;
+       }
 out:
        return 0;
 }
@@ -1168,7 +1115,7 @@ static struct ixgbe_mac_operations mac_ops_82598 = {
        .disable_mc             = &ixgbe_disable_mc_generic,
        .clear_vfta             = &ixgbe_clear_vfta_82598,
        .set_vfta               = &ixgbe_set_vfta_82598,
-       .setup_fc               = &ixgbe_setup_fc_82598,
+       .fc_enable              = &ixgbe_fc_enable_82598,
 };
 
 static struct ixgbe_eeprom_operations eeprom_ops_82598 = {
index 5d27830..1984cab 100644 (file)
@@ -71,10 +71,10 @@ s32 ixgbe_clear_vfta_82599(struct ixgbe_hw *hw);
 s32 ixgbe_init_uta_tables_82599(struct ixgbe_hw *hw);
 s32 ixgbe_read_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 *val);
 s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val);
-s32 ixgbe_start_hw_rev_0_82599(struct ixgbe_hw *hw);
 s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw);
 s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw);
 u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw);
+static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw);
 
 void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw)
 {
@@ -122,10 +122,9 @@ s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw)
                        IXGBE_WRITE_FLUSH(hw);
                        hw->eeprom.ops.read(hw, ++data_offset, &data_value);
                }
-               /* Now restart DSP */
-               IXGBE_WRITE_REG(hw, IXGBE_CORECTL, 0x00000102);
-               IXGBE_WRITE_REG(hw, IXGBE_CORECTL, 0x00000b1d);
-               IXGBE_WRITE_FLUSH(hw);
+               /* Now restart DSP by setting Restart_AN */
+               IXGBE_WRITE_REG(hw, IXGBE_AUTOC,
+                   (IXGBE_READ_REG(hw, IXGBE_AUTOC) | IXGBE_AUTOC_AN_RESTART));
 
                /* Release the semaphore */
                ixgbe_release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM);
@@ -414,9 +413,6 @@ s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw)
                }
        }
 
-       /* Set up flow control */
-       status = ixgbe_setup_fc_generic(hw, 0);
-
        /* Add delay to filter out noises during initial link setup */
        msleep(50);
 
@@ -462,11 +458,31 @@ s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw,
        u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP);
        bool link_up = false;
        bool negotiation;
+       int i;
 
        /* Mask off requested but non-supported speeds */
        hw->mac.ops.get_link_capabilities(hw, &phy_link_speed, &negotiation);
        speed &= phy_link_speed;
 
+        /* Set autoneg_advertised value based on input link speed */
+       hw->phy.autoneg_advertised = 0;
+
+       if (speed & IXGBE_LINK_SPEED_10GB_FULL)
+               hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL;
+
+       if (speed & IXGBE_LINK_SPEED_1GB_FULL)
+               hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL;
+
+       /*
+        * When the driver changes the link speeds that it can support,
+        * it sets autotry_restart to true to indicate that we need to
+        * initiate a new autotry session with the link partner.  To do
+        * so, we set the speed then disable and re-enable the tx laser, to
+        * alert the link partner that it also needs to restart autotry on its
+        * end.  This is consistent with true clause 37 autoneg, which also
+        * involves a loss of signal.
+        */
+
        /*
         * Try each speed one by one, highest priority first.  We do this in
         * software because 10gb fiber doesn't support speed autonegotiation.
@@ -475,21 +491,52 @@ s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw,
                speedcnt++;
                highest_link_speed = IXGBE_LINK_SPEED_10GB_FULL;
 
-               /* Set hardware SDP's */
+               /* If we already have link at this speed, just jump out */
+               hw->mac.ops.check_link(hw, &phy_link_speed, &link_up, false);
+
+               if ((phy_link_speed == IXGBE_LINK_SPEED_10GB_FULL) && link_up)
+                       goto out;
+
+               /* Set the module link speed */
                esdp_reg |= (IXGBE_ESDP_SDP5_DIR | IXGBE_ESDP_SDP5);
                IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
 
-               ixgbe_setup_mac_link_speed_82599(hw,
-                                                IXGBE_LINK_SPEED_10GB_FULL,
-                                                autoneg,
-                                                autoneg_wait_to_complete);
+               /* Allow module to change analog characteristics (1G->10G) */
+               msleep(40);
 
-               msleep(50);
-
-               /* If we have link, just jump out */
-               hw->mac.ops.check_link(hw, &phy_link_speed, &link_up, false);
-               if (link_up)
+               status = ixgbe_setup_mac_link_speed_82599(hw,
+                                                    IXGBE_LINK_SPEED_10GB_FULL,
+                                                    autoneg,
+                                                    autoneg_wait_to_complete);
+               if (status != 0)
                        goto out;
+
+               /* Flap the tx laser if it has not already been done */
+               if (hw->mac.autotry_restart) {
+                       /* Disable tx laser; allow 100us to go dark per spec */
+                       esdp_reg |= IXGBE_ESDP_SDP3;
+                       IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
+                       udelay(100);
+
+                       /* Enable tx laser; allow 2ms to light up per spec */
+                       esdp_reg &= ~IXGBE_ESDP_SDP3;
+                       IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
+                       msleep(2);
+
+                       hw->mac.autotry_restart = false;
+               }
+
+               /* The controller may take up to 500ms at 10g to acquire link */
+               for (i = 0; i < 5; i++) {
+                       /* Wait for the link partner to also set speed */
+                       msleep(100);
+
+                       /* If we have link, just jump out */
+                       hw->mac.ops.check_link(hw, &phy_link_speed,
+                                              &link_up, false);
+                       if (link_up)
+                               goto out;
+               }
        }
 
        if (speed & IXGBE_LINK_SPEED_1GB_FULL) {
@@ -497,16 +544,44 @@ s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw,
                if (highest_link_speed == IXGBE_LINK_SPEED_UNKNOWN)
                        highest_link_speed = IXGBE_LINK_SPEED_1GB_FULL;
 
-               /* Set hardware SDP's */
+               /* If we already have link at this speed, just jump out */
+               hw->mac.ops.check_link(hw, &phy_link_speed, &link_up, false);
+
+               if ((phy_link_speed == IXGBE_LINK_SPEED_1GB_FULL) && link_up)
+                       goto out;
+
+               /* Set the module link speed */
                esdp_reg &= ~IXGBE_ESDP_SDP5;
                esdp_reg |= IXGBE_ESDP_SDP5_DIR;
                IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
 
-               ixgbe_setup_mac_link_speed_82599(
-                       hw, IXGBE_LINK_SPEED_1GB_FULL, autoneg,
-                       autoneg_wait_to_complete);
+               /* Allow module to change analog characteristics (10G->1G) */
+               msleep(40);
 
-               msleep(50);
+               status = ixgbe_setup_mac_link_speed_82599(hw,
+                                                     IXGBE_LINK_SPEED_1GB_FULL,
+                                                     autoneg,
+                                                     autoneg_wait_to_complete);
+               if (status != 0)
+                       goto out;
+
+               /* Flap the tx laser if it has not already been done */
+               if (hw->mac.autotry_restart) {
+                       /* Disable tx laser; allow 100us to go dark per spec */
+                       esdp_reg |= IXGBE_ESDP_SDP3;
+                       IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
+                       udelay(100);
+
+                       /* Enable tx laser; allow 2ms to light up per spec */
+                       esdp_reg &= ~IXGBE_ESDP_SDP3;
+                       IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
+                       msleep(2);
+
+                       hw->mac.autotry_restart = false;
+               }
+
+               /* Wait for the link partner to also set speed */
+               msleep(100);
 
                /* If we have link, just jump out */
                hw->mac.ops.check_link(hw, &phy_link_speed, &link_up, false);
@@ -572,6 +647,11 @@ s32 ixgbe_check_mac_link_82599(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
        else
                *speed = IXGBE_LINK_SPEED_100_FULL;
 
+       /* if link is down, zero out the current_mode */
+       if (*link_up == false) {
+               hw->fc.current_mode = ixgbe_fc_none;
+               hw->fc.fc_was_autonegged = false;
+       }
 
        return 0;
 }
@@ -592,6 +672,7 @@ s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw,
        s32 status = 0;
        u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
        u32 autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2);
+       u32 start_autoc = autoc;
        u32 orig_autoc = 0;
        u32 link_mode = autoc & IXGBE_AUTOC_LMS_MASK;
        u32 pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK;
@@ -604,6 +685,11 @@ s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw,
        hw->mac.ops.get_link_capabilities(hw, &link_capabilities, &autoneg);
        speed &= link_capabilities;
 
+       if (speed == IXGBE_LINK_SPEED_UNKNOWN) {
+               status = IXGBE_ERR_LINK_SETUP;
+               goto out;
+       }
+
        /* Use stored value (EEPROM defaults) of AUTOC to find KR/KX4 support*/
        if (hw->mac.orig_link_settings_stored)
                orig_autoc = hw->mac.orig_autoc;
@@ -611,11 +697,9 @@ s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw,
                orig_autoc = autoc;
 
 
-       if (speed == IXGBE_LINK_SPEED_UNKNOWN) {
-               status = IXGBE_ERR_LINK_SETUP;
-       } else if (link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR ||
-                  link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN ||
-                  link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII) {
+       if (link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR ||
+           link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN ||
+           link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII) {
                /* Set KX4/KX/KR support according to speed requested */
                autoc &= ~(IXGBE_AUTOC_KX4_KX_SUPP_MASK | IXGBE_AUTOC_KR_SUPP);
                if (speed & IXGBE_LINK_SPEED_10GB_FULL)
@@ -647,7 +731,7 @@ s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw,
                }
        }
 
-       if (status == 0) {
+       if (autoc != start_autoc) {
                /* Restart link */
                autoc |= IXGBE_AUTOC_AN_RESTART;
                IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc);
@@ -674,13 +758,11 @@ s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw,
                        }
                }
 
-               /* Set up flow control */
-               status = ixgbe_setup_fc_generic(hw, 0);
-
                /* Add delay to filter out noises during initial link setup */
                msleep(50);
        }
 
+out:
        return status;
 }
 
@@ -1083,6 +1165,931 @@ s32 ixgbe_init_uta_tables_82599(struct ixgbe_hw *hw)
 }
 
 /**
+ *  ixgbe_reinit_fdir_tables_82599 - Reinitialize Flow Director tables.
+ *  @hw: pointer to hardware structure
+ **/
+s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw)
+{
+       int i;
+       u32 fdirctrl = IXGBE_READ_REG(hw, IXGBE_FDIRCTRL);
+       fdirctrl &= ~IXGBE_FDIRCTRL_INIT_DONE;
+
+       /*
+        * Before starting reinitialization process,
+        * FDIRCMD.CMD must be zero.
+        */
+       for (i = 0; i < IXGBE_FDIRCMD_CMD_POLL; i++) {
+               if (!(IXGBE_READ_REG(hw, IXGBE_FDIRCMD) &
+                     IXGBE_FDIRCMD_CMD_MASK))
+                       break;
+               udelay(10);
+       }
+       if (i >= IXGBE_FDIRCMD_CMD_POLL) {
+               hw_dbg(hw ,"Flow Director previous command isn't complete, "
+                      "aborting table re-initialization. \n");
+               return IXGBE_ERR_FDIR_REINIT_FAILED;
+       }
+
+       IXGBE_WRITE_REG(hw, IXGBE_FDIRFREE, 0);
+       IXGBE_WRITE_FLUSH(hw);
+       /*
+        * 82599 adapters flow director init flow cannot be restarted,
+        * Workaround 82599 silicon errata by performing the following steps
+        * before re-writing the FDIRCTRL control register with the same value.
+        * - write 1 to bit 8 of FDIRCMD register &
+        * - write 0 to bit 8 of FDIRCMD register
+        */
+       IXGBE_WRITE_REG(hw, IXGBE_FDIRCMD,
+                       (IXGBE_READ_REG(hw, IXGBE_FDIRCMD) |
+                        IXGBE_FDIRCMD_CLEARHT));
+       IXGBE_WRITE_FLUSH(hw);
+       IXGBE_WRITE_REG(hw, IXGBE_FDIRCMD,
+                       (IXGBE_READ_REG(hw, IXGBE_FDIRCMD) &
+                        ~IXGBE_FDIRCMD_CLEARHT));
+       IXGBE_WRITE_FLUSH(hw);
+       /*
+        * Clear FDIR Hash register to clear any leftover hashes
+        * waiting to be programmed.
+        */
+       IXGBE_WRITE_REG(hw, IXGBE_FDIRHASH, 0x00);
+       IXGBE_WRITE_FLUSH(hw);
+
+       IXGBE_WRITE_REG(hw, IXGBE_FDIRCTRL, fdirctrl);
+       IXGBE_WRITE_FLUSH(hw);
+
+       /* Poll init-done after we write FDIRCTRL register */
+       for (i = 0; i < IXGBE_FDIR_INIT_DONE_POLL; i++) {
+               if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) &
+                                  IXGBE_FDIRCTRL_INIT_DONE)
+                       break;
+               udelay(10);
+       }
+       if (i >= IXGBE_FDIR_INIT_DONE_POLL) {
+               hw_dbg(hw, "Flow Director Signature poll time exceeded!\n");
+               return IXGBE_ERR_FDIR_REINIT_FAILED;
+       }
+
+       /* Clear FDIR statistics registers (read to clear) */
+       IXGBE_READ_REG(hw, IXGBE_FDIRUSTAT);
+       IXGBE_READ_REG(hw, IXGBE_FDIRFSTAT);
+       IXGBE_READ_REG(hw, IXGBE_FDIRMATCH);
+       IXGBE_READ_REG(hw, IXGBE_FDIRMISS);
+       IXGBE_READ_REG(hw, IXGBE_FDIRLEN);
+
+       return 0;
+}
+
+/**
+ *  ixgbe_init_fdir_signature_82599 - Initialize Flow Director signature filters
+ *  @hw: pointer to hardware structure
+ *  @pballoc: which mode to allocate filters with
+ **/
+s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 pballoc)
+{
+       u32 fdirctrl = 0;
+       u32 pbsize;
+       int i;
+
+       /*
+        * Before enabling Flow Director, the Rx Packet Buffer size
+        * must be reduced.  The new value is the current size minus
+        * flow director memory usage size.
+        */
+       pbsize = (1 << (IXGBE_FDIR_PBALLOC_SIZE_SHIFT + pballoc));
+       IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(0),
+           (IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) - pbsize));
+
+       /*
+        * The defaults in the HW for RX PB 1-7 are not zero and so should be
+        * intialized to zero for non DCB mode otherwise actual total RX PB
+        * would be bigger than programmed and filter space would run into
+        * the PB 0 region.
+        */
+       for (i = 1; i < 8; i++)
+               IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), 0);
+
+       /* Send interrupt when 64 filters are left */
+       fdirctrl |= 4 << IXGBE_FDIRCTRL_FULL_THRESH_SHIFT;
+
+       /* Set the maximum length per hash bucket to 0xA filters */
+       fdirctrl |= 0xA << IXGBE_FDIRCTRL_MAX_LENGTH_SHIFT;
+
+       switch (pballoc) {
+       case IXGBE_FDIR_PBALLOC_64K:
+               /* 8k - 1 signature filters */
+               fdirctrl |= IXGBE_FDIRCTRL_PBALLOC_64K;
+               break;
+       case IXGBE_FDIR_PBALLOC_128K:
+               /* 16k - 1 signature filters */
+               fdirctrl |= IXGBE_FDIRCTRL_PBALLOC_128K;
+               break;
+       case IXGBE_FDIR_PBALLOC_256K:
+               /* 32k - 1 signature filters */
+               fdirctrl |= IXGBE_FDIRCTRL_PBALLOC_256K;
+               break;
+       default:
+               /* bad value */
+               return IXGBE_ERR_CONFIG;
+       };
+
+       /* Move the flexible bytes to use the ethertype - shift 6 words */
+       fdirctrl |= (0x6 << IXGBE_FDIRCTRL_FLEX_SHIFT);
+
+       fdirctrl |= IXGBE_FDIRCTRL_REPORT_STATUS;
+
+       /* Prime the keys for hashing */
+       IXGBE_WRITE_REG(hw, IXGBE_FDIRHKEY,
+                       htonl(IXGBE_ATR_BUCKET_HASH_KEY));
+       IXGBE_WRITE_REG(hw, IXGBE_FDIRSKEY,
+                       htonl(IXGBE_ATR_SIGNATURE_HASH_KEY));
+
+       /*
+        * Poll init-done after we write the register.  Estimated times:
+        *      10G: PBALLOC = 11b, timing is 60us
+        *       1G: PBALLOC = 11b, timing is 600us
+        *     100M: PBALLOC = 11b, timing is 6ms
+        *
+        *     Multiple these timings by 4 if under full Rx load
+        *
+        * So we'll poll for IXGBE_FDIR_INIT_DONE_POLL times, sleeping for
+        * 1 msec per poll time.  If we're at line rate and drop to 100M, then
+        * this might not finish in our poll time, but we can live with that
+        * for now.
+        */
+       IXGBE_WRITE_REG(hw, IXGBE_FDIRCTRL, fdirctrl);
+       IXGBE_WRITE_FLUSH(hw);
+       for (i = 0; i < IXGBE_FDIR_INIT_DONE_POLL; i++) {
+               if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) &
+                                  IXGBE_FDIRCTRL_INIT_DONE)
+                       break;
+               msleep(1);
+       }
+       if (i >= IXGBE_FDIR_INIT_DONE_POLL)
+               hw_dbg(hw, "Flow Director Signature poll time exceeded!\n");
+
+       return 0;
+}
+
+/**
+ *  ixgbe_init_fdir_perfect_82599 - Initialize Flow Director perfect filters
+ *  @hw: pointer to hardware structure
+ *  @pballoc: which mode to allocate filters with
+ **/
+s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc)
+{
+       u32 fdirctrl = 0;
+       u32 pbsize;
+       int i;
+
+       /*
+        * Before enabling Flow Director, the Rx Packet Buffer size
+        * must be reduced.  The new value is the current size minus
+        * flow director memory usage size.
+        */
+       pbsize = (1 << (IXGBE_FDIR_PBALLOC_SIZE_SHIFT + pballoc));
+       IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(0),
+           (IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) - pbsize));
+
+       /*
+        * The defaults in the HW for RX PB 1-7 are not zero and so should be
+        * intialized to zero for non DCB mode otherwise actual total RX PB
+        * would be bigger than programmed and filter space would run into
+        * the PB 0 region.
+        */
+       for (i = 1; i < 8; i++)
+               IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), 0);
+
+       /* Send interrupt when 64 filters are left */
+       fdirctrl |= 4 << IXGBE_FDIRCTRL_FULL_THRESH_SHIFT;
+
+       switch (pballoc) {
+       case IXGBE_FDIR_PBALLOC_64K:
+               /* 2k - 1 perfect filters */
+               fdirctrl |= IXGBE_FDIRCTRL_PBALLOC_64K;
+               break;
+       case IXGBE_FDIR_PBALLOC_128K:
+               /* 4k - 1 perfect filters */
+               fdirctrl |= IXGBE_FDIRCTRL_PBALLOC_128K;
+               break;
+       case IXGBE_FDIR_PBALLOC_256K:
+               /* 8k - 1 perfect filters */
+               fdirctrl |= IXGBE_FDIRCTRL_PBALLOC_256K;
+               break;
+       default:
+               /* bad value */
+               return IXGBE_ERR_CONFIG;
+       };
+
+       /* Turn perfect match filtering on */
+       fdirctrl |= IXGBE_FDIRCTRL_PERFECT_MATCH;
+       fdirctrl |= IXGBE_FDIRCTRL_REPORT_STATUS;
+
+       /* Move the flexible bytes to use the ethertype - shift 6 words */
+       fdirctrl |= (0x6 << IXGBE_FDIRCTRL_FLEX_SHIFT);
+
+       /* Prime the keys for hashing */
+       IXGBE_WRITE_REG(hw, IXGBE_FDIRHKEY,
+                       htonl(IXGBE_ATR_BUCKET_HASH_KEY));
+       IXGBE_WRITE_REG(hw, IXGBE_FDIRSKEY,
+                       htonl(IXGBE_ATR_SIGNATURE_HASH_KEY));
+
+       /*
+        * Poll init-done after we write the register.  Estimated times:
+        *      10G: PBALLOC = 11b, timing is 60us
+        *       1G: PBALLOC = 11b, timing is 600us
+        *     100M: PBALLOC = 11b, timing is 6ms
+        *
+        *     Multiple these timings by 4 if under full Rx load
+        *
+        * So we'll poll for IXGBE_FDIR_INIT_DONE_POLL times, sleeping for
+        * 1 msec per poll time.  If we're at line rate and drop to 100M, then
+        * this might not finish in our poll time, but we can live with that
+        * for now.
+        */
+
+       /* Set the maximum length per hash bucket to 0xA filters */
+       fdirctrl |= (0xA << IXGBE_FDIRCTRL_MAX_LENGTH_SHIFT);
+
+       IXGBE_WRITE_REG(hw, IXGBE_FDIRCTRL, fdirctrl);
+       IXGBE_WRITE_FLUSH(hw);
+       for (i = 0; i < IXGBE_FDIR_INIT_DONE_POLL; i++) {
+               if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) &
+                                  IXGBE_FDIRCTRL_INIT_DONE)
+                       break;
+               msleep(1);
+       }
+       if (i >= IXGBE_FDIR_INIT_DONE_POLL)
+               hw_dbg(hw, "Flow Director Perfect poll time exceeded!\n");
+
+       return 0;
+}
+
+
+/**
+ *  ixgbe_atr_compute_hash_82599 - Compute the hashes for SW ATR
+ *  @stream: input bitstream to compute the hash on
+ *  @key: 32-bit hash key
+ **/
+u16 ixgbe_atr_compute_hash_82599(struct ixgbe_atr_input *atr_input, u32 key)
+{
+       /*
+        * The algorithm is as follows:
+        *    Hash[15:0] = Sum { S[n] x K[n+16] }, n = 0...350
+        *    where Sum {A[n]}, n = 0...n is bitwise XOR of A[0], A[1]...A[n]
+        *    and A[n] x B[n] is bitwise AND between same length strings
+        *
+        *    K[n] is 16 bits, defined as:
+        *       for n modulo 32 >= 15, K[n] = K[n % 32 : (n % 32) - 15]
+        *       for n modulo 32 < 15, K[n] =
+        *             K[(n % 32:0) | (31:31 - (14 - (n % 32)))]
+        *
+        *    S[n] is 16 bits, defined as:
+        *       for n >= 15, S[n] = S[n:n - 15]
+        *       for n < 15, S[n] = S[(n:0) | (350:350 - (14 - n))]
+        *
+        *    To simplify for programming, the algorithm is implemented
+        *    in software this way:
+        *
+        *    Key[31:0], Stream[335:0]
+        *
+        *    tmp_key[11 * 32 - 1:0] = 11{Key[31:0] = key concatenated 11 times
+        *    int_key[350:0] = tmp_key[351:1]
+        *    int_stream[365:0] = Stream[14:0] | Stream[335:0] | Stream[335:321]
+        *
+        *    hash[15:0] = 0;
+        *    for (i = 0; i < 351; i++) {
+        *        if (int_key[i])
+        *            hash ^= int_stream[(i + 15):i];
+        *    }
+        */
+
+       union {
+               u64    fill[6];
+               u32    key[11];
+               u8     key_stream[44];
+       } tmp_key;
+
+       u8   *stream = (u8 *)atr_input;
+       u8   int_key[44];      /* upper-most bit unused */
+       u8   hash_str[46];     /* upper-most 2 bits unused */
+       u16  hash_result = 0;
+       int  i, j, k, h;
+
+       /*
+        * Initialize the fill member to prevent warnings
+        * on some compilers
+        */
+        tmp_key.fill[0] = 0;
+
+       /* First load the temporary key stream */
+       for (i = 0; i < 6; i++) {
+               u64 fillkey = ((u64)key << 32) | key;
+               tmp_key.fill[i] = fillkey;
+       }
+
+       /*
+        * Set the interim key for the hashing.  Bit 352 is unused, so we must
+        * shift and compensate when building the key.
+        */
+
+       int_key[0] = tmp_key.key_stream[0] >> 1;
+       for (i = 1, j = 0; i < 44; i++) {
+               unsigned int this_key = tmp_key.key_stream[j] << 7;
+               j++;
+               int_key[i] = (u8)(this_key | (tmp_key.key_stream[j] >> 1));
+       }
+
+       /*
+        * Set the interim bit string for the hashing.  Bits 368 and 367 are
+        * unused, so shift and compensate when building the string.
+        */
+       hash_str[0] = (stream[40] & 0x7f) >> 1;
+       for (i = 1, j = 40; i < 46; i++) {
+               unsigned int this_str = stream[j] << 7;
+               j++;
+               if (j > 41)
+                       j = 0;
+               hash_str[i] = (u8)(this_str | (stream[j] >> 1));
+       }
+
+       /*
+        * Now compute the hash.  i is the index into hash_str, j is into our
+        * key stream, k is counting the number of bits, and h interates within
+        * each byte.
+        */
+       for (i = 45, j = 43, k = 0; k < 351 && i >= 2 && j >= 0; i--, j--) {
+               for (h = 0; h < 8 && k < 351; h++, k++) {
+                       if (int_key[j] & (1 << h)) {
+                               /*
+                                * Key bit is set, XOR in the current 16-bit
+                                * string.  Example of processing:
+                                *    h = 0,
+                                *      tmp = (hash_str[i - 2] & 0 << 16) |
+                                *            (hash_str[i - 1] & 0xff << 8) |
+                                *            (hash_str[i] & 0xff >> 0)
+                                *      So tmp = hash_str[15 + k:k], since the
+                                *      i + 2 clause rolls off the 16-bit value
+                                *    h = 7,
+                                *      tmp = (hash_str[i - 2] & 0x7f << 9) |
+                                *            (hash_str[i - 1] & 0xff << 1) |
+                                *            (hash_str[i] & 0x80 >> 7)
+                                */
+                               int tmp = (hash_str[i] >> h);
+                               tmp |= (hash_str[i - 1] << (8 - h));
+                               tmp |= (int)(hash_str[i - 2] & ((1 << h) - 1))
+                                            << (16 - h);
+                               hash_result ^= (u16)tmp;
+                       }
+               }
+       }
+
+       return hash_result;
+}
+
+/**
+ *  ixgbe_atr_set_vlan_id_82599 - Sets the VLAN id in the ATR input stream
+ *  @input: input stream to modify
+ *  @vlan: the VLAN id to load
+ **/
+s32 ixgbe_atr_set_vlan_id_82599(struct ixgbe_atr_input *input, u16 vlan)
+{
+       input->byte_stream[IXGBE_ATR_VLAN_OFFSET + 1] = vlan >> 8;
+       input->byte_stream[IXGBE_ATR_VLAN_OFFSET] = vlan & 0xff;
+
+       return 0;
+}
+
+/**
+ *  ixgbe_atr_set_src_ipv4_82599 - Sets the source IPv4 address
+ *  @input: input stream to modify
+ *  @src_addr: the IP address to load
+ **/
+s32 ixgbe_atr_set_src_ipv4_82599(struct ixgbe_atr_input *input, u32 src_addr)
+{
+       input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 3] = src_addr >> 24;
+       input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 2] =
+                                                      (src_addr >> 16) & 0xff;
+       input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 1] =
+                                                       (src_addr >> 8) & 0xff;
+       input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET] = src_addr & 0xff;
+
+       return 0;
+}
+
+/**
+ *  ixgbe_atr_set_dst_ipv4_82599 - Sets the destination IPv4 address
+ *  @input: input stream to modify
+ *  @dst_addr: the IP address to load
+ **/
+s32 ixgbe_atr_set_dst_ipv4_82599(struct ixgbe_atr_input *input, u32 dst_addr)
+{
+       input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 3] = dst_addr >> 24;
+       input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 2] =
+                                                      (dst_addr >> 16) & 0xff;
+       input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 1] =
+                                                       (dst_addr >> 8) & 0xff;
+       input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET] = dst_addr & 0xff;
+
+       return 0;
+}
+
+/**
+ *  ixgbe_atr_set_src_ipv6_82599 - Sets the source IPv6 address
+ *  @input: input stream to modify
+ *  @src_addr_1: the first 4 bytes of the IP address to load
+ *  @src_addr_2: the second 4 bytes of the IP address to load
+ *  @src_addr_3: the third 4 bytes of the IP address to load
+ *  @src_addr_4: the fourth 4 bytes of the IP address to load
+ **/
+s32 ixgbe_atr_set_src_ipv6_82599(struct ixgbe_atr_input *input,
+                                 u32 src_addr_1, u32 src_addr_2,
+                                 u32 src_addr_3, u32 src_addr_4)
+{
+       input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET] = src_addr_4 & 0xff;
+       input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 1] =
+                                                      (src_addr_4 >> 8) & 0xff;
+       input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 2] =
+                                                     (src_addr_4 >> 16) & 0xff;
+       input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 3] = src_addr_4 >> 24;
+
+       input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 4] = src_addr_3 & 0xff;
+       input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 5] =
+                                                      (src_addr_3 >> 8) & 0xff;
+       input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 6] =
+                                                     (src_addr_3 >> 16) & 0xff;
+       input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 7] = src_addr_3 >> 24;
+
+       input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 8] = src_addr_2 & 0xff;
+       input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 9] =
+                                                      (src_addr_2 >> 8) & 0xff;
+       input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 10] =
+                                                     (src_addr_2 >> 16) & 0xff;
+       input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 11] = src_addr_2 >> 24;
+
+       input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 12] = src_addr_1 & 0xff;
+       input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 13] =
+                                                      (src_addr_1 >> 8) & 0xff;
+       input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 14] =
+                                                     (src_addr_1 >> 16) & 0xff;
+       input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 15] = src_addr_1 >> 24;
+
+       return 0;
+}
+
+/**
+ *  ixgbe_atr_set_dst_ipv6_82599 - Sets the destination IPv6 address
+ *  @input: input stream to modify
+ *  @dst_addr_1: the first 4 bytes of the IP address to load
+ *  @dst_addr_2: the second 4 bytes of the IP address to load
+ *  @dst_addr_3: the third 4 bytes of the IP address to load
+ *  @dst_addr_4: the fourth 4 bytes of the IP address to load
+ **/
+s32 ixgbe_atr_set_dst_ipv6_82599(struct ixgbe_atr_input *input,
+                                 u32 dst_addr_1, u32 dst_addr_2,
+                                 u32 dst_addr_3, u32 dst_addr_4)
+{
+       input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET] = dst_addr_4 & 0xff;
+       input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 1] =
+                                                      (dst_addr_4 >> 8) & 0xff;
+       input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 2] =
+                                                     (dst_addr_4 >> 16) & 0xff;
+       input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 3] = dst_addr_4 >> 24;
+
+       input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 4] = dst_addr_3 & 0xff;
+       input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 5] =
+                                                      (dst_addr_3 >> 8) & 0xff;
+       input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 6] =
+                                                     (dst_addr_3 >> 16) & 0xff;
+       input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 7] = dst_addr_3 >> 24;
+
+       input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 8] = dst_addr_2 & 0xff;
+       input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 9] =
+                                                      (dst_addr_2 >> 8) & 0xff;
+       input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 10] =
+                                                     (dst_addr_2 >> 16) & 0xff;
+       input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 11] = dst_addr_2 >> 24;
+
+       input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 12] = dst_addr_1 & 0xff;
+       input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 13] =
+                                                      (dst_addr_1 >> 8) & 0xff;
+       input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 14] =
+                                                     (dst_addr_1 >> 16) & 0xff;
+       input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 15] = dst_addr_1 >> 24;
+
+       return 0;
+}
+
+/**
+ *  ixgbe_atr_set_src_port_82599 - Sets the source port
+ *  @input: input stream to modify
+ *  @src_port: the source port to load
+ **/
+s32 ixgbe_atr_set_src_port_82599(struct ixgbe_atr_input *input, u16 src_port)
+{
+       input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET + 1] = src_port >> 8;
+       input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET] = src_port & 0xff;
+
+       return 0;
+}
+
+/**
+ *  ixgbe_atr_set_dst_port_82599 - Sets the destination port
+ *  @input: input stream to modify
+ *  @dst_port: the destination port to load
+ **/
+s32 ixgbe_atr_set_dst_port_82599(struct ixgbe_atr_input *input, u16 dst_port)
+{
+       input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET + 1] = dst_port >> 8;
+       input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET] = dst_port & 0xff;
+
+       return 0;
+}
+
+/**
+ *  ixgbe_atr_set_flex_byte_82599 - Sets the flexible bytes
+ *  @input: input stream to modify
+ *  @flex_bytes: the flexible bytes to load
+ **/
+s32 ixgbe_atr_set_flex_byte_82599(struct ixgbe_atr_input *input, u16 flex_byte)
+{
+       input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET + 1] = flex_byte >> 8;
+       input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET] = flex_byte & 0xff;
+
+       return 0;
+}
+
+/**
+ *  ixgbe_atr_set_vm_pool_82599 - Sets the Virtual Machine pool
+ *  @input: input stream to modify
+ *  @vm_pool: the Virtual Machine pool to load
+ **/
+s32 ixgbe_atr_set_vm_pool_82599(struct ixgbe_atr_input *input, u8 vm_pool)
+{
+       input->byte_stream[IXGBE_ATR_VM_POOL_OFFSET] = vm_pool;
+
+       return 0;
+}
+
+/**
+ *  ixgbe_atr_set_l4type_82599 - Sets the layer 4 packet type
+ *  @input: input stream to modify
+ *  @l4type: the layer 4 type value to load
+ **/
+s32 ixgbe_atr_set_l4type_82599(struct ixgbe_atr_input *input, u8 l4type)
+{
+       input->byte_stream[IXGBE_ATR_L4TYPE_OFFSET] = l4type;
+
+       return 0;
+}
+
+/**
+ *  ixgbe_atr_get_vlan_id_82599 - Gets the VLAN id from the ATR input stream
+ *  @input: input stream to search
+ *  @vlan: the VLAN id to load
+ **/
+s32 ixgbe_atr_get_vlan_id_82599(struct ixgbe_atr_input *input, u16 *vlan)
+{
+       *vlan = input->byte_stream[IXGBE_ATR_VLAN_OFFSET];
+       *vlan |= input->byte_stream[IXGBE_ATR_VLAN_OFFSET + 1] << 8;
+
+       return 0;
+}
+
+/**
+ *  ixgbe_atr_get_src_ipv4_82599 - Gets the source IPv4 address
+ *  @input: input stream to search
+ *  @src_addr: the IP address to load
+ **/
+s32 ixgbe_atr_get_src_ipv4_82599(struct ixgbe_atr_input *input, u32 *src_addr)
+{
+       *src_addr = input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET];
+       *src_addr |= input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 1] << 8;
+       *src_addr |= input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 2] << 16;
+       *src_addr |= input->byte_stream[IXGBE_ATR_SRC_IPV4_OFFSET + 3] << 24;
+
+       return 0;
+}
+
+/**
+ *  ixgbe_atr_get_dst_ipv4_82599 - Gets the destination IPv4 address
+ *  @input: input stream to search
+ *  @dst_addr: the IP address to load
+ **/
+s32 ixgbe_atr_get_dst_ipv4_82599(struct ixgbe_atr_input *input, u32 *dst_addr)
+{
+       *dst_addr = input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET];
+       *dst_addr |= input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 1] << 8;
+       *dst_addr |= input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 2] << 16;
+       *dst_addr |= input->byte_stream[IXGBE_ATR_DST_IPV4_OFFSET + 3] << 24;
+
+       return 0;
+}
+
+/**
+ *  ixgbe_atr_get_src_ipv6_82599 - Gets the source IPv6 address
+ *  @input: input stream to search
+ *  @src_addr_1: the first 4 bytes of the IP address to load
+ *  @src_addr_2: the second 4 bytes of the IP address to load
+ *  @src_addr_3: the third 4 bytes of the IP address to load
+ *  @src_addr_4: the fourth 4 bytes of the IP address to load
+ **/
+s32 ixgbe_atr_get_src_ipv6_82599(struct ixgbe_atr_input *input,
+                                 u32 *src_addr_1, u32 *src_addr_2,
+                                 u32 *src_addr_3, u32 *src_addr_4)
+{
+       *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 12];
+       *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 13] << 8;
+       *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 14] << 16;
+       *src_addr_1 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 15] << 24;
+
+       *src_addr_2 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 8];
+       *src_addr_2 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 9] << 8;
+       *src_addr_2 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 10] << 16;
+       *src_addr_2 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 11] << 24;
+
+       *src_addr_3 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 4];
+       *src_addr_3 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 5] << 8;
+       *src_addr_3 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 6] << 16;
+       *src_addr_3 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 7] << 24;
+
+       *src_addr_4 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET];
+       *src_addr_4 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 1] << 8;
+       *src_addr_4 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 2] << 16;
+       *src_addr_4 = input->byte_stream[IXGBE_ATR_SRC_IPV6_OFFSET + 3] << 24;
+
+       return 0;
+}
+
+/**
+ *  ixgbe_atr_get_dst_ipv6_82599 - Gets the destination IPv6 address
+ *  @input: input stream to search
+ *  @dst_addr_1: the first 4 bytes of the IP address to load
+ *  @dst_addr_2: the second 4 bytes of the IP address to load
+ *  @dst_addr_3: the third 4 bytes of the IP address to load
+ *  @dst_addr_4: the fourth 4 bytes of the IP address to load
+ **/
+s32 ixgbe_atr_get_dst_ipv6_82599(struct ixgbe_atr_input *input,
+                                 u32 *dst_addr_1, u32 *dst_addr_2,
+                                 u32 *dst_addr_3, u32 *dst_addr_4)
+{
+       *dst_addr_1 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 12];
+       *dst_addr_1 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 13] << 8;
+       *dst_addr_1 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 14] << 16;
+       *dst_addr_1 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 15] << 24;
+
+       *dst_addr_2 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 8];
+       *dst_addr_2 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 9] << 8;
+       *dst_addr_2 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 10] << 16;
+       *dst_addr_2 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 11] << 24;
+
+       *dst_addr_3 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 4];
+       *dst_addr_3 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 5] << 8;
+       *dst_addr_3 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 6] << 16;
+       *dst_addr_3 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 7] << 24;
+
+       *dst_addr_4 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET];
+       *dst_addr_4 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 1] << 8;
+       *dst_addr_4 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 2] << 16;
+       *dst_addr_4 = input->byte_stream[IXGBE_ATR_DST_IPV6_OFFSET + 3] << 24;
+
+       return 0;
+}
+
+/**
+ *  ixgbe_atr_get_src_port_82599 - Gets the source port
+ *  @input: input stream to modify
+ *  @src_port: the source port to load
+ *
+ *  Even though the input is given in big-endian, the FDIRPORT registers
+ *  expect the ports to be programmed in little-endian.  Hence the need to swap
+ *  endianness when retrieving the data.  This can be confusing since the
+ *  internal hash engine expects it to be big-endian.
+ **/
+s32 ixgbe_atr_get_src_port_82599(struct ixgbe_atr_input *input, u16 *src_port)
+{
+       *src_port = input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET] << 8;
+       *src_port |= input->byte_stream[IXGBE_ATR_SRC_PORT_OFFSET + 1];
+
+       return 0;
+}
+
+/**
+ *  ixgbe_atr_get_dst_port_82599 - Gets the destination port
+ *  @input: input stream to modify
+ *  @dst_port: the destination port to load
+ *
+ *  Even though the input is given in big-endian, the FDIRPORT registers
+ *  expect the ports to be programmed in little-endian.  Hence the need to swap
+ *  endianness when retrieving the data.  This can be confusing since the
+ *  internal hash engine expects it to be big-endian.
+ **/
+s32 ixgbe_atr_get_dst_port_82599(struct ixgbe_atr_input *input, u16 *dst_port)
+{
+       *dst_port = input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET] << 8;
+       *dst_port |= input->byte_stream[IXGBE_ATR_DST_PORT_OFFSET + 1];
+
+       return 0;
+}
+
+/**
+ *  ixgbe_atr_get_flex_byte_82599 - Gets the flexible bytes
+ *  @input: input stream to modify
+ *  @flex_bytes: the flexible bytes to load
+ **/
+s32 ixgbe_atr_get_flex_byte_82599(struct ixgbe_atr_input *input, u16 *flex_byte)
+{
+       *flex_byte = input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET];
+       *flex_byte |= input->byte_stream[IXGBE_ATR_FLEX_BYTE_OFFSET + 1] << 8;
+
+       return 0;
+}
+
+/**
+ *  ixgbe_atr_get_vm_pool_82599 - Gets the Virtual Machine pool
+ *  @input: input stream to modify
+ *  @vm_pool: the Virtual Machine pool to load
+ **/
+s32 ixgbe_atr_get_vm_pool_82599(struct ixgbe_atr_input *input, u8 *vm_pool)
+{
+       *vm_pool = input->byte_stream[IXGBE_ATR_VM_POOL_OFFSET];
+
+       return 0;
+}
+
+/**
+ *  ixgbe_atr_get_l4type_82599 - Gets the layer 4 packet type
+ *  @input: input stream to modify
+ *  @l4type: the layer 4 type value to load
+ **/
+s32 ixgbe_atr_get_l4type_82599(struct ixgbe_atr_input *input, u8 *l4type)
+{
+       *l4type = input->byte_stream[IXGBE_ATR_L4TYPE_OFFSET];
+
+       return 0;
+}
+
+/**
+ *  ixgbe_atr_add_signature_filter_82599 - Adds a signature hash filter
+ *  @hw: pointer to hardware structure
+ *  @stream: input bitstream
+ *  @queue: queue index to direct traffic to
+ **/
+s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw,
+                                          struct ixgbe_atr_input *input,
+                                          u8 queue)
+{
+       u64  fdirhashcmd;
+       u64  fdircmd;
+       u32  fdirhash;
+       u16  bucket_hash, sig_hash;
+       u8   l4type;
+
+       bucket_hash = ixgbe_atr_compute_hash_82599(input,
+                                                  IXGBE_ATR_BUCKET_HASH_KEY);
+
+       /* bucket_hash is only 15 bits */
+       bucket_hash &= IXGBE_ATR_HASH_MASK;
+
+       sig_hash = ixgbe_atr_compute_hash_82599(input,
+                                               IXGBE_ATR_SIGNATURE_HASH_KEY);
+
+       /* Get the l4type in order to program FDIRCMD properly */
+       /* lowest 2 bits are FDIRCMD.L4TYPE, third lowest bit is FDIRCMD.IPV6 */
+       ixgbe_atr_get_l4type_82599(input, &l4type);
+
+       /*
+        * The lower 32-bits of fdirhashcmd is for FDIRHASH, the upper 32-bits
+        * is for FDIRCMD.  Then do a 64-bit register write from FDIRHASH.
+        */
+       fdirhash = sig_hash << IXGBE_FDIRHASH_SIG_SW_INDEX_SHIFT | bucket_hash;
+
+       fdircmd = (IXGBE_FDIRCMD_CMD_ADD_FLOW | IXGBE_FDIRCMD_FILTER_UPDATE |
+                  IXGBE_FDIRCMD_LAST | IXGBE_FDIRCMD_QUEUE_EN);
+
+       switch (l4type & IXGBE_ATR_L4TYPE_MASK) {
+       case IXGBE_ATR_L4TYPE_TCP:
+               fdircmd |= IXGBE_FDIRCMD_L4TYPE_TCP;
+               break;
+       case IXGBE_ATR_L4TYPE_UDP:
+               fdircmd |= IXGBE_FDIRCMD_L4TYPE_UDP;
+               break;
+       case IXGBE_ATR_L4TYPE_SCTP:
+               fdircmd |= IXGBE_FDIRCMD_L4TYPE_SCTP;
+               break;
+       default:
+               hw_dbg(hw, "Error on l4type input\n");
+               return IXGBE_ERR_CONFIG;
+       }
+
+       if (l4type & IXGBE_ATR_L4TYPE_IPV6_MASK)
+               fdircmd |= IXGBE_FDIRCMD_IPV6;
+
+       fdircmd |= ((u64)queue << IXGBE_FDIRCMD_RX_QUEUE_SHIFT);
+       fdirhashcmd = ((fdircmd << 32) | fdirhash);
+
+       IXGBE_WRITE_REG64(hw, IXGBE_FDIRHASH, fdirhashcmd);
+
+       return 0;
+}
+
+/**
+ *  ixgbe_fdir_add_perfect_filter_82599 - Adds a perfect filter
+ *  @hw: pointer to hardware structure
+ *  @input: input bitstream
+ *  @queue: queue index to direct traffic to
+ *
+ *  Note that the caller to this function must lock before calling, since the
+ *  hardware writes must be protected from one another.
+ **/
+s32 ixgbe_fdir_add_perfect_filter_82599(struct ixgbe_hw *hw,
+                                        struct ixgbe_atr_input *input,
+                                        u16 soft_id,
+                                        u8 queue)
+{
+       u32 fdircmd = 0;
+       u32 fdirhash;
+       u32 src_ipv4, dst_ipv4;
+       u32 src_ipv6_1, src_ipv6_2, src_ipv6_3, src_ipv6_4;
+       u16 src_port, dst_port, vlan_id, flex_bytes;
+       u16 bucket_hash;
+       u8  l4type;
+
+       /* Get our input values */
+       ixgbe_atr_get_l4type_82599(input, &l4type);
+
+       /*
+        * Check l4type formatting, and bail out before we touch the hardware
+        * if there's a configuration issue
+        */
+       switch (l4type & IXGBE_ATR_L4TYPE_MASK) {
+       case IXGBE_ATR_L4TYPE_TCP:
+               fdircmd |= IXGBE_FDIRCMD_L4TYPE_TCP;
+               break;
+       case IXGBE_ATR_L4TYPE_UDP:
+               fdircmd |= IXGBE_FDIRCMD_L4TYPE_UDP;
+               break;
+       case IXGBE_ATR_L4TYPE_SCTP:
+               fdircmd |= IXGBE_FDIRCMD_L4TYPE_SCTP;
+               break;
+       default:
+               hw_dbg(hw, "Error on l4type input\n");
+               return IXGBE_ERR_CONFIG;
+       }
+
+       bucket_hash = ixgbe_atr_compute_hash_82599(input,
+                                                  IXGBE_ATR_BUCKET_HASH_KEY);
+
+       /* bucket_hash is only 15 bits */
+       bucket_hash &= IXGBE_ATR_HASH_MASK;
+
+       ixgbe_atr_get_vlan_id_82599(input, &vlan_id);
+       ixgbe_atr_get_src_port_82599(input, &src_port);
+       ixgbe_atr_get_dst_port_82599(input, &dst_port);
+       ixgbe_atr_get_flex_byte_82599(input, &flex_bytes);
+
+       fdirhash = soft_id << IXGBE_FDIRHASH_SIG_SW_INDEX_SHIFT | bucket_hash;
+
+       /* Now figure out if we're IPv4 or IPv6 */
+       if (l4type & IXGBE_ATR_L4TYPE_IPV6_MASK) {
+               /* IPv6 */
+               ixgbe_atr_get_src_ipv6_82599(input, &src_ipv6_1, &src_ipv6_2,
+                                            &src_ipv6_3, &src_ipv6_4);
+
+               IXGBE_WRITE_REG(hw, IXGBE_FDIRSIPv6(0), src_ipv6_1);
+               IXGBE_WRITE_REG(hw, IXGBE_FDIRSIPv6(1), src_ipv6_2);
+               IXGBE_WRITE_REG(hw, IXGBE_FDIRSIPv6(2), src_ipv6_3);
+               /* The last 4 bytes is the same register as IPv4 */
+               IXGBE_WRITE_REG(hw, IXGBE_FDIRIPSA, src_ipv6_4);
+
+               fdircmd |= IXGBE_FDIRCMD_IPV6;
+               fdircmd |= IXGBE_FDIRCMD_IPv6DMATCH;
+       } else {
+               /* IPv4 */
+               ixgbe_atr_get_src_ipv4_82599(input, &src_ipv4);
+               IXGBE_WRITE_REG(hw, IXGBE_FDIRIPSA, src_ipv4);
+
+       }
+
+       ixgbe_atr_get_dst_ipv4_82599(input, &dst_ipv4);
+       IXGBE_WRITE_REG(hw, IXGBE_FDIRIPDA, dst_ipv4);
+
+       IXGBE_WRITE_REG(hw, IXGBE_FDIRVLAN, (vlan_id |
+                                   (flex_bytes << IXGBE_FDIRVLAN_FLEX_SHIFT)));
+       IXGBE_WRITE_REG(hw, IXGBE_FDIRPORT, (src_port |
+                              (dst_port << IXGBE_FDIRPORT_DESTINATION_SHIFT)));
+
+       fdircmd |= IXGBE_FDIRCMD_CMD_ADD_FLOW;
+       fdircmd |= IXGBE_FDIRCMD_FILTER_UPDATE;
+       fdircmd |= IXGBE_FDIRCMD_LAST;
+       fdircmd |= IXGBE_FDIRCMD_QUEUE_EN;
+       fdircmd |= queue << IXGBE_FDIRCMD_RX_QUEUE_SHIFT;
+
+       IXGBE_WRITE_REG(hw, IXGBE_FDIRHASH, fdirhash);
+       IXGBE_WRITE_REG(hw, IXGBE_FDIRCMD, fdircmd);
+
+       return 0;
+}
+/**
  *  ixgbe_read_analog_reg8_82599 - Reads 8 bit Omer analog register
  *  @hw: pointer to hardware structure
  *  @reg: analog register to read
@@ -1135,8 +2142,9 @@ s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val)
 s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw)
 {
        u32 q_num;
+       s32 ret_val;
 
-       ixgbe_start_hw_generic(hw);
+       ret_val = ixgbe_start_hw_generic(hw);
 
        /* Clear the rate limiters */
        for (q_num = 0; q_num < hw->mac.max_tx_queues; q_num++) {
@@ -1145,7 +2153,13 @@ s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw)
        }
        IXGBE_WRITE_FLUSH(hw);
 
-       return 0;
+       /* We need to run link autotry after the driver loads */
+       hw->mac.autotry_restart = true;
+
+       if (ret_val == 0)
+               ret_val = ixgbe_verify_fw_version_82599(hw);
+
+       return ret_val;
 }
 
 /**
@@ -1397,6 +2411,54 @@ san_mac_addr_out:
        return 0;
 }
 
+/**
+ *  ixgbe_verify_fw_version_82599 - verify fw version for 82599
+ *  @hw: pointer to hardware structure
+ *
+ *  Verifies that installed the firmware version is 0.6 or higher
+ *  for SFI devices. All 82599 SFI devices should have version 0.6 or higher.
+ *
+ *  Returns IXGBE_ERR_EEPROM_VERSION if the FW is not present or
+ *  if the FW version is not supported.
+ **/
+static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw)
+{
+       s32 status = IXGBE_ERR_EEPROM_VERSION;
+       u16 fw_offset, fw_ptp_cfg_offset;
+       u16 fw_version = 0;
+
+       /* firmware check is only necessary for SFI devices */
+       if (hw->phy.media_type != ixgbe_media_type_fiber) {
+               status = 0;
+               goto fw_version_out;
+       }
+
+       /* get the offset to the Firmware Module block */
+       hw->eeprom.ops.read(hw, IXGBE_FW_PTR, &fw_offset);
+
+       if ((fw_offset == 0) || (fw_offset == 0xFFFF))
+               goto fw_version_out;
+
+       /* get the offset to the Pass Through Patch Configuration block */
+       hw->eeprom.ops.read(hw, (fw_offset +
+                                IXGBE_FW_PASSTHROUGH_PATCH_CONFIG_PTR),
+                                &fw_ptp_cfg_offset);
+
+       if ((fw_ptp_cfg_offset == 0) || (fw_ptp_cfg_offset == 0xFFFF))
+               goto fw_version_out;
+
+       /* get the firmware version */
+       hw->eeprom.ops.read(hw, (fw_ptp_cfg_offset +
+                                IXGBE_FW_PATCH_VERSION_4),
+                                &fw_version);
+
+       if (fw_version > 0x5)
+               status = 0;
+
+fw_version_out:
+       return status;
+}
+
 static struct ixgbe_mac_operations mac_ops_82599 = {
        .init_hw                = &ixgbe_init_hw_generic,
        .reset_hw               = &ixgbe_reset_hw_82599,
@@ -1432,7 +2494,7 @@ static struct ixgbe_mac_operations mac_ops_82599 = {
        .disable_mc             = &ixgbe_disable_mc_generic,
        .clear_vfta             = &ixgbe_clear_vfta_82599,
        .set_vfta               = &ixgbe_set_vfta_82599,
-       .setup_fc               = &ixgbe_setup_fc_generic,
+       .fc_enable               = &ixgbe_fc_enable_generic,
        .init_uta_tables        = &ixgbe_init_uta_tables_82599,
        .setup_sfp              = &ixgbe_setup_sfp_modules_82599,
 };
index 0cc3c47..96a1859 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
 
 #include "ixgbe.h"
 #include "ixgbe_common.h"
@@ -83,6 +85,9 @@ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw)
        IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
        IXGBE_WRITE_FLUSH(hw);
 
+       /* Setup flow control */
+       ixgbe_setup_fc(hw, 0);
+
        /* Clear adapter stopped flag */
        hw->adapter_stopped = false;
 
@@ -101,13 +106,17 @@ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw)
  **/
 s32 ixgbe_init_hw_generic(struct ixgbe_hw *hw)
 {
+       s32 status;
+
        /* Reset the hardware */
-       hw->mac.ops.reset_hw(hw);
+       status = hw->mac.ops.reset_hw(hw);
 
-       /* Start the HW */
-       hw->mac.ops.start_hw(hw);
+       if (status == 0) {
+               /* Start the HW */
+               status = hw->mac.ops.start_hw(hw);
+       }
 
-       return 0;
+       return status;
 }
 
 /**
@@ -1356,15 +1365,14 @@ static void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq)
  *  Drivers using secondary unicast addresses must set user_set_promisc when
  *  manually putting the device into promiscuous mode.
  **/
-s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, u8 *addr_list,
-                              u32 addr_count, ixgbe_mc_addr_itr next)
+s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw,
+                                     struct list_head *uc_list)
 {
-       u8 *addr;
        u32 i;
        u32 old_promisc_setting = hw->addr_ctrl.overflow_promisc;
        u32 uc_addr_in_use;
        u32 fctrl;
-       u32 vmdq;
+       struct netdev_hw_addr *ha;
 
        /*
         * Clear accounting of old secondary address list,
@@ -1382,10 +1390,9 @@ s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, u8 *addr_list,
        }
 
        /* Add the new addresses */
-       for (i = 0; i < addr_count; i++) {
+       list_for_each_entry(ha, uc_list, list) {
                hw_dbg(hw, " Adding the secondary addresses:\n");
-               addr = next(hw, &addr_list, &vmdq);
-               ixgbe_add_uc_addr(hw, addr, vmdq);
+               ixgbe_add_uc_addr(hw, ha->addr, 0);
        }
 
        if (hw->addr_ctrl.overflow_promisc) {
@@ -1577,17 +1584,16 @@ s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw)
 }
 
 /**
- *  ixgbe_fc_enable - Enable flow control
+ *  ixgbe_fc_enable_generic - Enable flow control
  *  @hw: pointer to hardware structure
  *  @packetbuf_num: packet buffer number (0-7)
  *
  *  Enable flow control according to the current settings.
  **/
-s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num)
+s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packetbuf_num)
 {
        s32 ret_val = 0;
-       u32 mflcn_reg;
-       u32 fccfg_reg;
+       u32 mflcn_reg, fccfg_reg;
        u32 reg;
        u32 rx_pba_size;
 
@@ -1596,7 +1602,12 @@ s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num)
                goto out;
 
 #endif /* CONFIG_DCB */
+       /* Negotiate the fc mode to use */
+       ret_val = ixgbe_fc_autoneg(hw);
+       if (ret_val)
+               goto out;
 
+       /* Disable any previous flow control settings */
        mflcn_reg = IXGBE_READ_REG(hw, IXGBE_MFLCN);
        mflcn_reg &= ~(IXGBE_MFLCN_RFCE | IXGBE_MFLCN_RPFCE);
 
@@ -1616,7 +1627,10 @@ s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num)
         */
        switch (hw->fc.current_mode) {
        case ixgbe_fc_none:
-               /* Flow control completely disabled by software override. */
+               /*
+                * Flow control is disabled by software override or autoneg.
+                * The code below will actually disable it in the HW.
+                */
                break;
        case ixgbe_fc_rx_pause:
                /*
@@ -1645,7 +1659,7 @@ s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num)
        case ixgbe_fc_pfc:
                goto out;
                break;
-#endif
+#endif /* CONFIG_DCB */
        default:
                hw_dbg(hw, "Flow control param set incorrectly\n");
                ret_val = -IXGBE_ERR_CONFIG;
@@ -1653,7 +1667,7 @@ s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num)
                break;
        }
 
-       /* Enable 802.3x based flow control settings. */
+       /* Set 802.3x based flow control settings. */
        mflcn_reg |= IXGBE_MFLCN_DPF;
        IXGBE_WRITE_REG(hw, IXGBE_MFLCN, mflcn_reg);
        IXGBE_WRITE_REG(hw, IXGBE_FCCFG, fccfg_reg);
@@ -1661,10 +1675,12 @@ s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num)
        reg = IXGBE_READ_REG(hw, IXGBE_MTQC);
        /* Thresholds are different for link flow control when in DCB mode */
        if (reg & IXGBE_MTQC_RT_ENA) {
+               rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(packetbuf_num));
+
                /* Always disable XON for LFC when in DCB mode */
-               IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(packetbuf_num), 0);
+               reg = (rx_pba_size >> 5) & 0xFFE0;
+               IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(packetbuf_num), reg);
 
-               rx_pba_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(packetbuf_num));
                reg = (rx_pba_size >> 2) & 0xFFE0;
                if (hw->fc.current_mode & ixgbe_fc_tx_pause)
                        reg |= IXGBE_FCRTH_FCEN;
@@ -1709,100 +1725,41 @@ out:
  *  ixgbe_fc_autoneg - Configure flow control
  *  @hw: pointer to hardware structure
  *
- *  Negotiates flow control capabilities with link partner using autoneg and
- *  applies the results.
+ *  Compares our advertised flow control capabilities to those advertised by
+ *  our link partner, and determines the proper flow control mode to use.
  **/
 s32 ixgbe_fc_autoneg(struct ixgbe_hw *hw)
 {
        s32 ret_val = 0;
-       u32 i, reg, pcs_anadv_reg, pcs_lpab_reg;
-
-       reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA);
+       ixgbe_link_speed speed;
+       u32 pcs_anadv_reg, pcs_lpab_reg, linkstat;
+       bool link_up;
 
        /*
-        * The possible values of fc.current_mode are:
-        * 0:  Flow control is completely disabled
-        * 1:  Rx flow control is enabled (we can receive pause frames,
-        *     but not send pause frames).
-        * 2:  Tx flow control is enabled (we can send pause frames but
-        *     we do not support receiving pause frames).
-        * 3:  Both Rx and Tx flow control (symmetric) are enabled.
-        * 4:  Priority Flow Control is enabled.
-        * other: Invalid.
+        * AN should have completed when the cable was plugged in.
+        * Look for reasons to bail out.  Bail out if:
+        * - FC autoneg is disabled, or if
+        * - we don't have multispeed fiber, or if
+        * - we're not running at 1G, or if
+        * - link is not up, or if
+        * - link is up but AN did not complete, or if
+        * - link is up and AN completed but timed out
+        *
+        * Since we're being called from an LSC, link is already know to be up.
+        * So use link_up_wait_to_complete=false.
         */
-       switch (hw->fc.current_mode) {
-       case ixgbe_fc_none:
-               /* Flow control completely disabled by software override. */
-               reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE);
-               break;
-       case ixgbe_fc_rx_pause:
-               /*
-                * Rx Flow control is enabled and Tx Flow control is
-                * disabled by software override. Since there really
-                * isn't a way to advertise that we are capable of RX
-                * Pause ONLY, we will advertise that we support both
-                * symmetric and asymmetric Rx PAUSE.  Later, we will
-                * disable the adapter's ability to send PAUSE frames.
-                */
-               reg |= (IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE);
-               break;
-       case ixgbe_fc_tx_pause:
-               /*
-                * Tx Flow control is enabled, and Rx Flow control is
-                * disabled by software override.
-                */
-               reg |= (IXGBE_PCS1GANA_ASM_PAUSE);
-               reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE);
-               break;
-       case ixgbe_fc_full:
-               /* Flow control (both Rx and Tx) is enabled by SW override. */
-               reg |= (IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE);
-               break;
-#ifdef CONFIG_DCB
-       case ixgbe_fc_pfc:
-               goto out;
-               break;
-#endif
-       default:
-               hw_dbg(hw, "Flow control param set incorrectly\n");
-               ret_val = -IXGBE_ERR_CONFIG;
-               goto out;
-               break;
-       }
-
-       IXGBE_WRITE_REG(hw, IXGBE_PCS1GANA, reg);
-       reg = IXGBE_READ_REG(hw, IXGBE_PCS1GLCTL);
-
-       /* Set PCS register for autoneg */
-       /* Enable and restart autoneg */
-       reg |= IXGBE_PCS1GLCTL_AN_ENABLE | IXGBE_PCS1GLCTL_AN_RESTART;
-
-       /* Disable AN timeout */
-       if (hw->fc.strict_ieee)
-               reg &= ~IXGBE_PCS1GLCTL_AN_1G_TIMEOUT_EN;
-
-       hw_dbg(hw, "Configuring Autoneg; PCS_LCTL = 0x%08X\n", reg);
-       IXGBE_WRITE_REG(hw, IXGBE_PCS1GLCTL, reg);
-
-       /* See if autonegotiation has succeeded */
-       hw->mac.autoneg_succeeded = 0;
-       for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) {
-               msleep(10);
-               reg = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA);
-               if ((reg & (IXGBE_PCS1GLSTA_LINK_OK |
-                    IXGBE_PCS1GLSTA_AN_COMPLETE)) ==
-                   (IXGBE_PCS1GLSTA_LINK_OK |
-                    IXGBE_PCS1GLSTA_AN_COMPLETE)) {
-                       if (!(reg & IXGBE_PCS1GLSTA_AN_TIMED_OUT))
-                               hw->mac.autoneg_succeeded = 1;
-                       break;
-               }
-       }
-
-       if (!hw->mac.autoneg_succeeded) {
-               /* Autoneg failed to achieve a link, so we turn fc off */
-               hw->fc.current_mode = ixgbe_fc_none;
-               hw_dbg(hw, "Flow Control = NONE.\n");
+       hw->mac.ops.check_link(hw, &speed, &link_up, false);
+       linkstat = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA);
+
+       if (hw->fc.disable_fc_autoneg ||
+           !hw->phy.multispeed_fiber ||
+           (speed != IXGBE_LINK_SPEED_1GB_FULL) ||
+           !link_up ||
+           ((linkstat & IXGBE_PCS1GLSTA_AN_COMPLETE) == 0) ||
+           ((linkstat & IXGBE_PCS1GLSTA_AN_TIMED_OUT) == 1)) {
+               hw->fc.fc_was_autonegged = false;
+               hw->fc.current_mode = hw->fc.requested_mode;
+               hw_dbg(hw, "Autoneg FC was skipped.\n");
                goto out;
        }
 
@@ -1845,21 +1802,23 @@ s32 ixgbe_fc_autoneg(struct ixgbe_hw *hw)
                hw_dbg(hw, "Flow Control = NONE.\n");
        }
 
+       /* Record that current_mode is the result of a successful autoneg */
+       hw->fc.fc_was_autonegged = true;
+
 out:
        return ret_val;
 }
 
 /**
- *  ixgbe_setup_fc_generic - Set up flow control
+ *  ixgbe_setup_fc - Set up flow control
  *  @hw: pointer to hardware structure
  *
- *  Sets up flow control.
+ *  Called at init time to set up flow control.
  **/
-s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw, s32 packetbuf_num)
+s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num)
 {
        s32 ret_val = 0;
-       ixgbe_link_speed speed;
-       bool link_up;
+       u32 reg;
 
 #ifdef CONFIG_DCB
        if (hw->fc.requested_mode == ixgbe_fc_pfc) {
@@ -1881,16 +1840,14 @@ s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw, s32 packetbuf_num)
         * because it causes the controller to just blast out fc packets.
         */
        if (!hw->fc.low_water || !hw->fc.high_water || !hw->fc.pause_time) {
-               if (hw->fc.requested_mode != ixgbe_fc_none) {
-                       hw_dbg(hw, "Invalid water mark configuration\n");
-                       ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS;
-                       goto out;
-               }
+               hw_dbg(hw, "Invalid water mark configuration\n");
+               ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS;
+               goto out;
        }
 
        /*
         * Validate the requested mode.  Strict IEEE mode does not allow
-        * ixgbe_fc_rx_pause because it will cause testing anomalies.
+        * ixgbe_fc_rx_pause because it will cause us to fail at UNH.
         */
        if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) {
                hw_dbg(hw, "ixgbe_fc_rx_pause not valid in strict "
@@ -1907,21 +1864,77 @@ s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw, s32 packetbuf_num)
                hw->fc.requested_mode = ixgbe_fc_full;
 
        /*
-        * Save off the requested flow control mode for use later.  Depending
-        * on the link partner's capabilities, we may or may not use this mode.
+        * Set up the 1G flow control advertisement registers so the HW will be
+        * able to do fc autoneg once the cable is plugged in.  If we end up
+        * using 10g instead, this is harmless.
         */
-       hw->fc.current_mode = hw->fc.requested_mode;
-
-       /* Decide whether to use autoneg or not. */
-       hw->mac.ops.check_link(hw, &speed, &link_up, false);
-       if (!hw->fc.disable_fc_autoneg && hw->phy.multispeed_fiber &&
-           (speed == IXGBE_LINK_SPEED_1GB_FULL))
-               ret_val = ixgbe_fc_autoneg(hw);
+       reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA);
 
-       if (ret_val)
+       /*
+        * The possible values of fc.requested_mode are:
+        * 0: Flow control is completely disabled
+        * 1: Rx flow control is enabled (we can receive pause frames,
+        *    but not send pause frames).
+        * 2: Tx flow control is enabled (we can send pause frames but
+        *    we do not support receiving pause frames).
+        * 3: Both Rx and Tx flow control (symmetric) are enabled.
+#ifdef CONFIG_DCB
+        * 4: Priority Flow Control is enabled.
+#endif
+        * other: Invalid.
+        */
+       switch (hw->fc.requested_mode) {
+       case ixgbe_fc_none:
+               /* Flow control completely disabled by software override. */
+               reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE);
+               break;
+       case ixgbe_fc_rx_pause:
+               /*
+                * Rx Flow control is enabled and Tx Flow control is
+                * disabled by software override. Since there really
+                * isn't a way to advertise that we are capable of RX
+                * Pause ONLY, we will advertise that we support both
+                * symmetric and asymmetric Rx PAUSE.  Later, we will
+                * disable the adapter's ability to send PAUSE frames.
+                */
+               reg |= (IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE);
+               break;
+       case ixgbe_fc_tx_pause:
+               /*
+                * Tx Flow control is enabled, and Rx Flow control is
+                * disabled by software override.
+                */
+               reg |= (IXGBE_PCS1GANA_ASM_PAUSE);
+               reg &= ~(IXGBE_PCS1GANA_SYM_PAUSE);
+               break;
+       case ixgbe_fc_full:
+               /* Flow control (both Rx and Tx) is enabled by SW override. */
+               reg |= (IXGBE_PCS1GANA_SYM_PAUSE | IXGBE_PCS1GANA_ASM_PAUSE);
+               break;
+#ifdef CONFIG_DCB
+       case ixgbe_fc_pfc:
+               goto out;
+               break;
+#endif /* CONFIG_DCB */
+       default:
+               hw_dbg(hw, "Flow control param set incorrectly\n");
+               ret_val = -IXGBE_ERR_CONFIG;
                goto out;
+               break;
+       }
 
-       ret_val = ixgbe_fc_enable(hw, packetbuf_num);
+       IXGBE_WRITE_REG(hw, IXGBE_PCS1GANA, reg);
+       reg = IXGBE_READ_REG(hw, IXGBE_PCS1GLCTL);
+
+       /* Enable and restart autoneg to inform the link partner */
+       reg |= IXGBE_PCS1GLCTL_AN_ENABLE | IXGBE_PCS1GLCTL_AN_RESTART;
+
+       /* Disable AN timeout */
+       if (hw->fc.strict_ieee)
+               reg &= ~IXGBE_PCS1GLCTL_AN_1G_TIMEOUT_EN;
+
+       IXGBE_WRITE_REG(hw, IXGBE_PCS1GLCTL, reg);
+       hw_dbg(hw, "Set up FC; PCS1GLCTL = 0x%08X\n", reg);
 
 out:
        return ret_val;
@@ -2068,6 +2081,7 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index)
        hw->mac.ops.check_link(hw, &speed, &link_up, false);
 
        if (!link_up) {
+               autoc_reg |= IXGBE_AUTOC_AN_RESTART;
                autoc_reg |= IXGBE_AUTOC_FLU;
                IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg);
                msleep(10);
index dd26089..0d34d4d 100644 (file)
@@ -59,13 +59,13 @@ s32 ixgbe_init_rx_addrs_generic(struct ixgbe_hw *hw);
 s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, u8 *mc_addr_list,
                                       u32 mc_addr_count,
                                       ixgbe_mc_addr_itr func);
-s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, u8 *addr_list,
-                                      u32 addr_count, ixgbe_mc_addr_itr func);
+s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw,
+                                     struct list_head *uc_list);
 s32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw);
 s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw);
 s32 ixgbe_enable_rx_dma_generic(struct ixgbe_hw *hw, u32 regval);
-s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw, s32 packetbuf_num);
-s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packtetbuf_num);
+s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num);
+s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw, s32 packtetbuf_num);
 s32 ixgbe_fc_autoneg(struct ixgbe_hw *hw);
 
 s32 ixgbe_validate_mac_addr(u8 *mac_addr);
index f4417fc..589f62c 100644 (file)
@@ -295,7 +295,7 @@ s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw,
        /* If PFC is disabled globally then fall back to LFC. */
        if (!dcb_config->pfc_mode_enable) {
                for (i = 0; i < MAX_TRAFFIC_CLASS; i++)
-                       hw->mac.ops.setup_fc(hw, i);
+                       hw->mac.ops.fc_enable(hw, i);
                goto out;
        }
 
index 35255b8..86f4f3e 100644 (file)
@@ -68,6 +68,8 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = {
        {"rx_crc_errors", IXGBE_STAT(net_stats.rx_crc_errors)},
        {"rx_frame_errors", IXGBE_STAT(net_stats.rx_frame_errors)},
        {"hw_rsc_count", IXGBE_STAT(rsc_count)},
+       {"fdir_match", IXGBE_STAT(stats.fdirmatch)},
+       {"fdir_miss", IXGBE_STAT(stats.fdirmiss)},
        {"rx_fifo_errors", IXGBE_STAT(net_stats.rx_fifo_errors)},
        {"rx_missed_errors", IXGBE_STAT(net_stats.rx_missed_errors)},
        {"tx_aborted_errors", IXGBE_STAT(net_stats.tx_aborted_errors)},
@@ -118,6 +120,13 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = {
                          IXGBE_PB_STATS_LEN + \
                          IXGBE_QUEUE_STATS_LEN)
 
+static const char ixgbe_gstrings_test[][ETH_GSTRING_LEN] = {
+       "Register test  (offline)", "Eeprom test    (offline)",
+       "Interrupt test (offline)", "Loopback test  (offline)",
+       "Link test   (on/offline)"
+};
+#define IXGBE_TEST_LEN sizeof(ixgbe_gstrings_test) / ETH_GSTRING_LEN
+
 static int ixgbe_get_settings(struct net_device *netdev,
                               struct ethtool_cmd *ecmd)
 {
@@ -129,11 +138,12 @@ static int ixgbe_get_settings(struct net_device *netdev,
        ecmd->supported = SUPPORTED_10000baseT_Full;
        ecmd->autoneg = AUTONEG_ENABLE;
        ecmd->transceiver = XCVR_EXTERNAL;
-       if (hw->phy.media_type == ixgbe_media_type_copper) {
+       if ((hw->phy.media_type == ixgbe_media_type_copper) ||
+           (hw->mac.type == ixgbe_mac_82599EB)) {
                ecmd->supported |= (SUPPORTED_1000baseT_Full |
-                                   SUPPORTED_TP | SUPPORTED_Autoneg);
+                                   SUPPORTED_Autoneg);
 
-               ecmd->advertising = (ADVERTISED_TP | ADVERTISED_Autoneg);
+               ecmd->advertising = ADVERTISED_Autoneg;
                if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL)
                        ecmd->advertising |= ADVERTISED_10000baseT_Full;
                if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL)
@@ -148,7 +158,15 @@ static int ixgbe_get_settings(struct net_device *netdev,
                        ecmd->advertising |= (ADVERTISED_10000baseT_Full |
                                              ADVERTISED_1000baseT_Full);
 
-               ecmd->port = PORT_TP;
+               if (hw->phy.media_type == ixgbe_media_type_copper) {
+                       ecmd->supported |= SUPPORTED_TP;
+                       ecmd->advertising |= ADVERTISED_TP;
+                       ecmd->port = PORT_TP;
+               } else {
+                       ecmd->supported |= SUPPORTED_FIBRE;
+                       ecmd->advertising |= ADVERTISED_FIBRE;
+                       ecmd->port = PORT_FIBRE;
+               }
        } else if (hw->phy.media_type == ixgbe_media_type_backplane) {
                /* Set as FIBRE until SERDES defined in kernel */
                switch (hw->device_id) {
@@ -196,16 +214,10 @@ static int ixgbe_set_settings(struct net_device *netdev,
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        struct ixgbe_hw *hw = &adapter->hw;
        u32 advertised, old;
-       s32 err;
+       s32 err = 0;
 
-       switch (hw->phy.media_type) {
-       case ixgbe_media_type_fiber:
-               if ((ecmd->autoneg == AUTONEG_ENABLE) ||
-                   (ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL))
-                       return -EINVAL;
-               /* in this case we currently only support 10Gb/FULL */
-               break;
-       case ixgbe_media_type_copper:
+       if ((hw->phy.media_type == ixgbe_media_type_copper) ||
+           (hw->mac.type == ixgbe_mac_82599EB)) {
                /* 10000/copper and 1000/copper must autoneg
                 * this function does not support any duplex forcing, but can
                 * limit the advertising of the adapter to only 10000 or 1000 */
@@ -221,20 +233,23 @@ static int ixgbe_set_settings(struct net_device *netdev,
                        advertised |= IXGBE_LINK_SPEED_1GB_FULL;
 
                if (old == advertised)
-                       break;
+                       return err;
                /* this sets the link speed and restarts auto-neg */
+               hw->mac.autotry_restart = true;
                err = hw->mac.ops.setup_link_speed(hw, advertised, true, true);
                if (err) {
                        DPRINTK(PROBE, INFO,
                                "setup link failed with code %d\n", err);
                        hw->mac.ops.setup_link_speed(hw, old, true, true);
                }
-               break;
-       default:
-               break;
+       } else {
+               /* in this case we currently only support 10Gb/FULL */
+               if ((ecmd->autoneg == AUTONEG_ENABLE) ||
+                   (ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL))
+                       return -EINVAL;
        }
 
-       return 0;
+       return err;
 }
 
 static void ixgbe_get_pauseparam(struct net_device *netdev,
@@ -276,6 +291,7 @@ static int ixgbe_set_pauseparam(struct net_device *netdev,
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        struct ixgbe_hw *hw = &adapter->hw;
+       struct ixgbe_fc_info fc;
 
 #ifdef CONFIG_DCB
        if (adapter->dcb_cfg.pfc_mode_enable ||
@@ -284,26 +300,37 @@ static int ixgbe_set_pauseparam(struct net_device *netdev,
                return -EINVAL;
 
 #endif
+
+       fc = hw->fc;
+
        if (pause->autoneg != AUTONEG_ENABLE)
-               hw->fc.disable_fc_autoneg = true;
+               fc.disable_fc_autoneg = true;
        else
-               hw->fc.disable_fc_autoneg = false;
+               fc.disable_fc_autoneg = false;
 
        if (pause->rx_pause && pause->tx_pause)
-               hw->fc.requested_mode = ixgbe_fc_full;
+               fc.requested_mode = ixgbe_fc_full;
        else if (pause->rx_pause && !pause->tx_pause)
-               hw->fc.requested_mode = ixgbe_fc_rx_pause;
+               fc.requested_mode = ixgbe_fc_rx_pause;
        else if (!pause->rx_pause && pause->tx_pause)
-               hw->fc.requested_mode = ixgbe_fc_tx_pause;
+               fc.requested_mode = ixgbe_fc_tx_pause;
        else if (!pause->rx_pause && !pause->tx_pause)
-               hw->fc.requested_mode = ixgbe_fc_none;
+               fc.requested_mode = ixgbe_fc_none;
        else
                return -EINVAL;
 
 #ifdef CONFIG_DCB
-       adapter->last_lfc_mode = hw->fc.requested_mode;
+       adapter->last_lfc_mode = fc.requested_mode;
 #endif
-       hw->mac.ops.setup_fc(hw, 0);
+
+       /* if the thing changed then we'll update and use new autoneg */
+       if (memcmp(&fc, &hw->fc, sizeof(struct ixgbe_fc_info))) {
+               hw->fc = fc;
+               if (netif_running(netdev))
+                       ixgbe_reinit_locked(adapter);
+               else
+                       ixgbe_reset(adapter);
+       }
 
        return 0;
 }
@@ -743,6 +770,7 @@ static void ixgbe_get_drvinfo(struct net_device *netdev,
        strncpy(drvinfo->fw_version, firmware_version, 32);
        strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
        drvinfo->n_stats = IXGBE_STATS_LEN;
+       drvinfo->testinfo_len = IXGBE_TEST_LEN;
        drvinfo->regdump_len = ixgbe_get_regs_len(netdev);
 }
 
@@ -814,7 +842,6 @@ static int ixgbe_set_ringparam(struct net_device *netdev,
                                }
                                goto err_setup;
                        }
-                       temp_tx_ring[i].v_idx = adapter->tx_ring[i].v_idx;
                }
                need_update = true;
        }
@@ -844,7 +871,6 @@ static int ixgbe_set_ringparam(struct net_device *netdev,
                                }
                                goto err_setup;
                        }
-                       temp_rx_ring[i].v_idx = adapter->rx_ring[i].v_idx;
                }
                need_update = true;
        }
@@ -884,6 +910,8 @@ err_setup:
 static int ixgbe_get_sset_count(struct net_device *netdev, int sset)
 {
        switch (sset) {
+       case ETH_SS_TEST:
+               return IXGBE_TEST_LEN;
        case ETH_SS_STATS:
                return IXGBE_STATS_LEN;
        default:
@@ -938,6 +966,10 @@ static void ixgbe_get_strings(struct net_device *netdev, u32 stringset,
        int i;
 
        switch (stringset) {
+       case ETH_SS_TEST:
+               memcpy(data, *ixgbe_gstrings_test,
+                      IXGBE_TEST_LEN * ETH_GSTRING_LEN);
+               break;
        case ETH_SS_STATS:
                for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
                        memcpy(p, ixgbe_gstrings_stats[i].stat_string,
@@ -975,6 +1007,815 @@ static void ixgbe_get_strings(struct net_device *netdev, u32 stringset,
        }
 }
 
+static int ixgbe_link_test(struct ixgbe_adapter *adapter, u64 *data)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       bool link_up;
+       u32 link_speed = 0;
+       *data = 0;
+
+       hw->mac.ops.check_link(hw, &link_speed, &link_up, true);
+       if (link_up)
+               return *data;
+       else
+               *data = 1;
+       return *data;
+}
+
+/* ethtool register test data */
+struct ixgbe_reg_test {
+       u16 reg;
+       u8  array_len;
+       u8  test_type;
+       u32 mask;
+       u32 write;
+};
+
+/* In the hardware, registers are laid out either singly, in arrays
+ * spaced 0x40 bytes apart, or in contiguous tables.  We assume
+ * most tests take place on arrays or single registers (handled
+ * as a single-element array) and special-case the tables.
+ * Table tests are always pattern tests.
+ *
+ * We also make provision for some required setup steps by specifying
+ * registers to be written without any read-back testing.
+ */
+
+#define PATTERN_TEST   1
+#define SET_READ_TEST  2
+#define WRITE_NO_TEST  3
+#define TABLE32_TEST   4
+#define TABLE64_TEST_LO        5
+#define TABLE64_TEST_HI        6
+
+/* default 82599 register test */
+static struct ixgbe_reg_test reg_test_82599[] = {
+       { IXGBE_FCRTL_82599(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 },
+       { IXGBE_FCRTH_82599(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 },
+       { IXGBE_PFCTOP, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { IXGBE_VLNCTRL, 1, PATTERN_TEST, 0x00000000, 0x00000000 },
+       { IXGBE_RDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFF80 },
+       { IXGBE_RDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { IXGBE_RDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
+       { IXGBE_RXDCTL(0), 4, WRITE_NO_TEST, 0, IXGBE_RXDCTL_ENABLE },
+       { IXGBE_RDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
+       { IXGBE_RXDCTL(0), 4, WRITE_NO_TEST, 0, 0 },
+       { IXGBE_FCRTH(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 },
+       { IXGBE_FCTTV(0), 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { IXGBE_TDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
+       { IXGBE_TDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { IXGBE_TDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFF80 },
+       { IXGBE_RXCTRL, 1, SET_READ_TEST, 0x00000001, 0x00000001 },
+       { IXGBE_RAL(0), 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF },
+       { IXGBE_RAL(0), 16, TABLE64_TEST_HI, 0x8001FFFF, 0x800CFFFF },
+       { IXGBE_MTA(0), 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { 0, 0, 0, 0 }
+};
+
+/* default 82598 register test */
+static struct ixgbe_reg_test reg_test_82598[] = {
+       { IXGBE_FCRTL(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 },
+       { IXGBE_FCRTH(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 },
+       { IXGBE_PFCTOP, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { IXGBE_VLNCTRL, 1, PATTERN_TEST, 0x00000000, 0x00000000 },
+       { IXGBE_RDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
+       { IXGBE_RDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { IXGBE_RDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
+       /* Enable all four RX queues before testing. */
+       { IXGBE_RXDCTL(0), 4, WRITE_NO_TEST, 0, IXGBE_RXDCTL_ENABLE },
+       /* RDH is read-only for 82598, only test RDT. */
+       { IXGBE_RDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
+       { IXGBE_RXDCTL(0), 4, WRITE_NO_TEST, 0, 0 },
+       { IXGBE_FCRTH(0), 1, PATTERN_TEST, 0x8007FFF0, 0x8007FFF0 },
+       { IXGBE_FCTTV(0), 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { IXGBE_TIPG, 1, PATTERN_TEST, 0x000000FF, 0x000000FF },
+       { IXGBE_TDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
+       { IXGBE_TDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { IXGBE_TDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
+       { IXGBE_RXCTRL, 1, SET_READ_TEST, 0x00000003, 0x00000003 },
+       { IXGBE_DTXCTL, 1, SET_READ_TEST, 0x00000005, 0x00000005 },
+       { IXGBE_RAL(0), 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF },
+       { IXGBE_RAL(0), 16, TABLE64_TEST_HI, 0x800CFFFF, 0x800CFFFF },
+       { IXGBE_MTA(0), 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { 0, 0, 0, 0 }
+};
+
+#define REG_PATTERN_TEST(R, M, W)                                             \
+{                                                                             \
+       u32 pat, val, before;                                                 \
+       const u32 _test[] = {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \
+       for (pat = 0; pat < ARRAY_SIZE(_test); pat++) {                       \
+               before = readl(adapter->hw.hw_addr + R);                      \
+               writel((_test[pat] & W), (adapter->hw.hw_addr + R));          \
+               val = readl(adapter->hw.hw_addr + R);                         \
+               if (val != (_test[pat] & W & M)) {                            \
+                       DPRINTK(DRV, ERR, "pattern test reg %04X failed: got "\
+                                         "0x%08X expected 0x%08X\n",         \
+                               R, val, (_test[pat] & W & M));                \
+                       *data = R;                                            \
+                       writel(before, adapter->hw.hw_addr + R);              \
+                       return 1;                                             \
+               }                                                             \
+               writel(before, adapter->hw.hw_addr + R);                      \
+       }                                                                     \
+}
+
+#define REG_SET_AND_CHECK(R, M, W)                                            \
+{                                                                             \
+       u32 val, before;                                                      \
+       before = readl(adapter->hw.hw_addr + R);                              \
+       writel((W & M), (adapter->hw.hw_addr + R));                           \
+       val = readl(adapter->hw.hw_addr + R);                                 \
+       if ((W & M) != (val & M)) {                                           \
+               DPRINTK(DRV, ERR, "set/check reg %04X test failed: got 0x%08X "\
+                                "expected 0x%08X\n", R, (val & M), (W & M)); \
+               *data = R;                                                    \
+               writel(before, (adapter->hw.hw_addr + R));                    \
+               return 1;                                                     \
+       }                                                                     \
+       writel(before, (adapter->hw.hw_addr + R));                            \
+}
+
+static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data)
+{
+       struct ixgbe_reg_test *test;
+       u32 value, before, after;
+       u32 i, toggle;
+
+       if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+               toggle = 0x7FFFF30F;
+               test = reg_test_82599;
+       } else {
+               toggle = 0x7FFFF3FF;
+               test = reg_test_82598;
+       }
+
+       /*
+        * Because the status register is such a special case,
+        * we handle it separately from the rest of the register
+        * tests.  Some bits are read-only, some toggle, and some
+        * are writeable on newer MACs.
+        */
+       before = IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS);
+       value = (IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS) & toggle);
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_STATUS, toggle);
+       after = IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS) & toggle;
+       if (value != after) {
+               DPRINTK(DRV, ERR, "failed STATUS register test got: "
+                       "0x%08X expected: 0x%08X\n", after, value);
+               *data = 1;
+               return 1;
+       }
+       /* restore previous status */
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_STATUS, before);
+
+       /*
+        * Perform the remainder of the register test, looping through
+        * the test table until we either fail or reach the null entry.
+        */
+       while (test->reg) {
+               for (i = 0; i < test->array_len; i++) {
+                       switch (test->test_type) {
+                       case PATTERN_TEST:
+                               REG_PATTERN_TEST(test->reg + (i * 0x40),
+                                               test->mask,
+                                               test->write);
+                               break;
+                       case SET_READ_TEST:
+                               REG_SET_AND_CHECK(test->reg + (i * 0x40),
+                                               test->mask,
+                                               test->write);
+                               break;
+                       case WRITE_NO_TEST:
+                               writel(test->write,
+                                      (adapter->hw.hw_addr + test->reg)
+                                      + (i * 0x40));
+                               break;
+                       case TABLE32_TEST:
+                               REG_PATTERN_TEST(test->reg + (i * 4),
+                                               test->mask,
+                                               test->write);
+                               break;
+                       case TABLE64_TEST_LO:
+                               REG_PATTERN_TEST(test->reg + (i * 8),
+                                               test->mask,
+                                               test->write);
+                               break;
+                       case TABLE64_TEST_HI:
+                               REG_PATTERN_TEST((test->reg + 4) + (i * 8),
+                                               test->mask,
+                                               test->write);
+                               break;
+                       }
+               }
+               test++;
+       }
+
+       *data = 0;
+       return 0;
+}
+
+static int ixgbe_eeprom_test(struct ixgbe_adapter *adapter, u64 *data)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       if (hw->eeprom.ops.validate_checksum(hw, NULL))
+               *data = 1;
+       else
+               *data = 0;
+       return *data;
+}
+
+static irqreturn_t ixgbe_test_intr(int irq, void *data)
+{
+       struct net_device *netdev = (struct net_device *) data;
+       struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+       adapter->test_icr |= IXGBE_READ_REG(&adapter->hw, IXGBE_EICR);
+
+       return IRQ_HANDLED;
+}
+
+static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data)
+{
+       struct net_device *netdev = adapter->netdev;
+       u32 mask, i = 0, shared_int = true;
+       u32 irq = adapter->pdev->irq;
+
+       *data = 0;
+
+       /* Hook up test interrupt handler just for this test */
+       if (adapter->msix_entries) {
+               /* NOTE: we don't test MSI-X interrupts here, yet */
+               return 0;
+       } else if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) {
+               shared_int = false;
+               if (request_irq(irq, &ixgbe_test_intr, 0, netdev->name,
+                               netdev)) {
+                       *data = 1;
+                       return -1;
+               }
+       } else if (!request_irq(irq, &ixgbe_test_intr, IRQF_PROBE_SHARED,
+                               netdev->name, netdev)) {
+               shared_int = false;
+       } else if (request_irq(irq, &ixgbe_test_intr, IRQF_SHARED,
+                              netdev->name, netdev)) {
+               *data = 1;
+               return -1;
+       }
+       DPRINTK(HW, INFO, "testing %s interrupt\n",
+               (shared_int ? "shared" : "unshared"));
+
+       /* Disable all the interrupts */
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF);
+       msleep(10);
+
+       /* Test each interrupt */
+       for (; i < 10; i++) {
+               /* Interrupt to test */
+               mask = 1 << i;
+
+               if (!shared_int) {
+                       /*
+                        * Disable the interrupts to be reported in
+                        * the cause register and then force the same
+                        * interrupt and see if one gets posted.  If
+                        * an interrupt was posted to the bus, the
+                        * test failed.
+                        */
+                       adapter->test_icr = 0;
+                       IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC,
+                                       ~mask & 0x00007FFF);
+                       IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS,
+                                       ~mask & 0x00007FFF);
+                       msleep(10);
+
+                       if (adapter->test_icr & mask) {
+                               *data = 3;
+                               break;
+                       }
+               }
+
+               /*
+                * Enable the interrupt to be reported in the cause
+                * register and then force the same interrupt and see
+                * if one gets posted.  If an interrupt was not posted
+                * to the bus, the test failed.
+                */
+               adapter->test_icr = 0;
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask);
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask);
+               msleep(10);
+
+               if (!(adapter->test_icr &mask)) {
+                       *data = 4;
+                       break;
+               }
+
+               if (!shared_int) {
+                       /*
+                        * Disable the other interrupts to be reported in
+                        * the cause register and then force the other
+                        * interrupts and see if any get posted.  If
+                        * an interrupt was posted to the bus, the
+                        * test failed.
+                        */
+                       adapter->test_icr = 0;
+                       IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC,
+                                       ~mask & 0x00007FFF);
+                       IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS,
+                                       ~mask & 0x00007FFF);
+                       msleep(10);
+
+                       if (adapter->test_icr) {
+                               *data = 5;
+                               break;
+                       }
+               }
+       }
+
+       /* Disable all the interrupts */
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF);
+       msleep(10);
+
+       /* Unhook test interrupt handler */
+       free_irq(irq, netdev);
+
+       return *data;
+}
+
+static void ixgbe_free_desc_rings(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_ring *tx_ring = &adapter->test_tx_ring;
+       struct ixgbe_ring *rx_ring = &adapter->test_rx_ring;
+       struct ixgbe_hw *hw = &adapter->hw;
+       struct pci_dev *pdev = adapter->pdev;
+       u32 reg_ctl;
+       int i;
+
+       /* shut down the DMA engines now so they can be reinitialized later */
+
+       /* first Rx */
+       reg_ctl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+       reg_ctl &= ~IXGBE_RXCTRL_RXEN;
+       IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_ctl);
+       reg_ctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(0));
+       reg_ctl &= ~IXGBE_RXDCTL_ENABLE;
+       IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(0), reg_ctl);
+
+       /* now Tx */
+       reg_ctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(0));
+       reg_ctl &= ~IXGBE_TXDCTL_ENABLE;
+       IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(0), reg_ctl);
+       if (hw->mac.type == ixgbe_mac_82599EB) {
+               reg_ctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
+               reg_ctl &= ~IXGBE_DMATXCTL_TE;
+               IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg_ctl);
+       }
+
+       ixgbe_reset(adapter);
+
+       if (tx_ring->desc && tx_ring->tx_buffer_info) {
+               for (i = 0; i < tx_ring->count; i++) {
+                       struct ixgbe_tx_buffer *buf =
+                                       &(tx_ring->tx_buffer_info[i]);
+                       if (buf->dma)
+                               pci_unmap_single(pdev, buf->dma, buf->length,
+                                                PCI_DMA_TODEVICE);
+                       if (buf->skb)
+                               dev_kfree_skb(buf->skb);
+               }
+       }
+
+       if (rx_ring->desc && rx_ring->rx_buffer_info) {
+               for (i = 0; i < rx_ring->count; i++) {
+                       struct ixgbe_rx_buffer *buf =
+                                       &(rx_ring->rx_buffer_info[i]);
+                       if (buf->dma)
+                               pci_unmap_single(pdev, buf->dma,
+                                                IXGBE_RXBUFFER_2048,
+                                                PCI_DMA_FROMDEVICE);
+                       if (buf->skb)
+                               dev_kfree_skb(buf->skb);
+               }
+       }
+
+       if (tx_ring->desc) {
+               pci_free_consistent(pdev, tx_ring->size, tx_ring->desc,
+                                   tx_ring->dma);
+               tx_ring->desc = NULL;
+       }
+       if (rx_ring->desc) {
+               pci_free_consistent(pdev, rx_ring->size, rx_ring->desc,
+                                   rx_ring->dma);
+               rx_ring->desc = NULL;
+       }
+
+       kfree(tx_ring->tx_buffer_info);
+       tx_ring->tx_buffer_info = NULL;
+       kfree(rx_ring->rx_buffer_info);
+       rx_ring->rx_buffer_info = NULL;
+
+       return;
+}
+
+static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_ring *tx_ring = &adapter->test_tx_ring;
+       struct ixgbe_ring *rx_ring = &adapter->test_rx_ring;
+       struct pci_dev *pdev = adapter->pdev;
+       u32 rctl, reg_data;
+       int i, ret_val;
+
+       /* Setup Tx descriptor ring and Tx buffers */
+
+       if (!tx_ring->count)
+               tx_ring->count = IXGBE_DEFAULT_TXD;
+
+       tx_ring->tx_buffer_info = kcalloc(tx_ring->count,
+                                         sizeof(struct ixgbe_tx_buffer),
+                                         GFP_KERNEL);
+       if (!(tx_ring->tx_buffer_info)) {
+               ret_val = 1;
+               goto err_nomem;
+       }
+
+       tx_ring->size = tx_ring->count * sizeof(struct ixgbe_legacy_tx_desc);
+       tx_ring->size = ALIGN(tx_ring->size, 4096);
+       if (!(tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size,
+                                                  &tx_ring->dma))) {
+               ret_val = 2;
+               goto err_nomem;
+       }
+       tx_ring->next_to_use = tx_ring->next_to_clean = 0;
+
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDBAL(0),
+                       ((u64) tx_ring->dma & 0x00000000FFFFFFFF));
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDBAH(0),
+                       ((u64) tx_ring->dma >> 32));
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDLEN(0),
+                       tx_ring->count * sizeof(struct ixgbe_legacy_tx_desc));
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDH(0), 0);
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDT(0), 0);
+
+       reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0);
+       reg_data |= IXGBE_HLREG0_TXPADEN;
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data);
+
+       if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+               reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_DMATXCTL);
+               reg_data |= IXGBE_DMATXCTL_TE;
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_DMATXCTL, reg_data);
+       }
+       reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_TXDCTL(0));
+       reg_data |= IXGBE_TXDCTL_ENABLE;
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_TXDCTL(0), reg_data);
+
+       for (i = 0; i < tx_ring->count; i++) {
+               struct ixgbe_legacy_tx_desc *desc = IXGBE_TX_DESC(*tx_ring, i);
+               struct sk_buff *skb;
+               unsigned int size = 1024;
+
+               skb = alloc_skb(size, GFP_KERNEL);
+               if (!skb) {
+                       ret_val = 3;
+                       goto err_nomem;
+               }
+               skb_put(skb, size);
+               tx_ring->tx_buffer_info[i].skb = skb;
+               tx_ring->tx_buffer_info[i].length = skb->len;
+               tx_ring->tx_buffer_info[i].dma =
+                       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;
+       }
+
+       /* Setup Rx Descriptor ring and Rx buffers */
+
+       if (!rx_ring->count)
+               rx_ring->count = IXGBE_DEFAULT_RXD;
+
+       rx_ring->rx_buffer_info = kcalloc(rx_ring->count,
+                                         sizeof(struct ixgbe_rx_buffer),
+                                         GFP_KERNEL);
+       if (!(rx_ring->rx_buffer_info)) {
+               ret_val = 4;
+               goto err_nomem;
+       }
+
+       rx_ring->size = rx_ring->count * sizeof(struct ixgbe_legacy_rx_desc);
+       rx_ring->size = ALIGN(rx_ring->size, 4096);
+       if (!(rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size,
+                                                  &rx_ring->dma))) {
+               ret_val = 5;
+               goto err_nomem;
+       }
+       rx_ring->next_to_use = rx_ring->next_to_clean = 0;
+
+       rctl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXCTRL);
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, rctl & ~IXGBE_RXCTRL_RXEN);
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDBAL(0),
+                       ((u64)rx_ring->dma & 0xFFFFFFFF));
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDBAH(0),
+                       ((u64) rx_ring->dma >> 32));
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDLEN(0), rx_ring->size);
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDH(0), 0);
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDT(0), 0);
+
+       reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL);
+       reg_data |= IXGBE_FCTRL_BAM | IXGBE_FCTRL_SBP | IXGBE_FCTRL_MPE;
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_data);
+
+       reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0);
+       reg_data &= ~IXGBE_HLREG0_LPBK;
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data);
+
+       reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_RDRXCTL);
+#define IXGBE_RDRXCTL_RDMTS_MASK    0x00000003 /* Receive Descriptor Minimum
+                                                  Threshold Size mask */
+       reg_data &= ~IXGBE_RDRXCTL_RDMTS_MASK;
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDRXCTL, reg_data);
+
+       reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_MCSTCTRL);
+#define IXGBE_MCSTCTRL_MO_MASK      0x00000003 /* Multicast Offset mask */
+       reg_data &= ~IXGBE_MCSTCTRL_MO_MASK;
+       reg_data |= adapter->hw.mac.mc_filter_type;
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_MCSTCTRL, reg_data);
+
+       reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_RXDCTL(0));
+       reg_data |= IXGBE_RXDCTL_ENABLE;
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXDCTL(0), reg_data);
+       if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+               int j = adapter->rx_ring[0].reg_idx;
+               u32 k;
+               for (k = 0; k < 10; k++) {
+                       if (IXGBE_READ_REG(&adapter->hw,
+                                          IXGBE_RXDCTL(j)) & IXGBE_RXDCTL_ENABLE)
+                               break;
+                       else
+                               msleep(1);
+               }
+       }
+
+       rctl |= IXGBE_RXCTRL_RXEN | IXGBE_RXCTRL_DMBYPS;
+       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);
+               struct sk_buff *skb;
+
+               skb = alloc_skb(IXGBE_RXBUFFER_2048 + NET_IP_ALIGN, GFP_KERNEL);
+               if (!skb) {
+                       ret_val = 6;
+                       goto err_nomem;
+               }
+               skb_reserve(skb, NET_IP_ALIGN);
+               rx_ring->rx_buffer_info[i].skb = skb;
+               rx_ring->rx_buffer_info[i].dma =
+                       pci_map_single(pdev, skb->data, IXGBE_RXBUFFER_2048,
+                                      PCI_DMA_FROMDEVICE);
+               rx_desc->buffer_addr =
+                               cpu_to_le64(rx_ring->rx_buffer_info[i].dma);
+               memset(skb->data, 0x00, skb->len);
+       }
+
+       return 0;
+
+err_nomem:
+       ixgbe_free_desc_rings(adapter);
+       return ret_val;
+}
+
+static int ixgbe_setup_loopback_test(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 reg_data;
+
+       /* right now we only support MAC loopback in the driver */
+
+       /* Setup MAC loopback */
+       reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0);
+       reg_data |= IXGBE_HLREG0_LPBK;
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data);
+
+       reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_AUTOC);
+       reg_data &= ~IXGBE_AUTOC_LMS_MASK;
+       reg_data |= IXGBE_AUTOC_LMS_10G_LINK_NO_AN | IXGBE_AUTOC_FLU;
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_AUTOC, reg_data);
+
+       /* Disable Atlas Tx lanes; re-enabled in reset path */
+       if (hw->mac.type == ixgbe_mac_82598EB) {
+               u8 atlas;
+
+               hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &atlas);
+               atlas |= IXGBE_ATLAS_PDN_TX_REG_EN;
+               hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, atlas);
+
+               hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, &atlas);
+               atlas |= IXGBE_ATLAS_PDN_TX_10G_QL_ALL;
+               hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, atlas);
+
+               hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, &atlas);
+               atlas |= IXGBE_ATLAS_PDN_TX_1G_QL_ALL;
+               hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, atlas);
+
+               hw->mac.ops.read_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, &atlas);
+               atlas |= IXGBE_ATLAS_PDN_TX_AN_QL_ALL;
+               hw->mac.ops.write_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, atlas);
+       }
+
+       return 0;
+}
+
+static void ixgbe_loopback_cleanup(struct ixgbe_adapter *adapter)
+{
+       u32 reg_data;
+
+       reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0);
+       reg_data &= ~IXGBE_HLREG0_LPBK;
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_HLREG0, reg_data);
+}
+
+static void ixgbe_create_lbtest_frame(struct sk_buff *skb,
+                                      unsigned int frame_size)
+{
+       memset(skb->data, 0xFF, frame_size);
+       frame_size &= ~1;
+       memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1);
+       memset(&skb->data[frame_size / 2 + 10], 0xBE, 1);
+       memset(&skb->data[frame_size / 2 + 12], 0xAF, 1);
+}
+
+static int ixgbe_check_lbtest_frame(struct sk_buff *skb,
+                                    unsigned int frame_size)
+{
+       frame_size &= ~1;
+       if (*(skb->data + 3) == 0xFF) {
+               if ((*(skb->data + frame_size / 2 + 10) == 0xBE) &&
+                   (*(skb->data + frame_size / 2 + 12) == 0xAF)) {
+                       return 0;
+               }
+       }
+       return 13;
+}
+
+static int ixgbe_run_loopback_test(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_ring *tx_ring = &adapter->test_tx_ring;
+       struct ixgbe_ring *rx_ring = &adapter->test_rx_ring;
+       struct pci_dev *pdev = adapter->pdev;
+       int i, j, k, l, lc, good_cnt, ret_val = 0;
+       unsigned long time;
+
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_RDT(0), rx_ring->count - 1);
+
+       /*
+        * Calculate the loop count based on the largest descriptor ring
+        * The idea is to wrap the largest ring a number of times using 64
+        * send/receive pairs during each loop
+        */
+
+       if (rx_ring->count <= tx_ring->count)
+               lc = ((tx_ring->count / 64) * 2) + 1;
+       else
+               lc = ((rx_ring->count / 64) * 2) + 1;
+
+       k = l = 0;
+       for (j = 0; j <= lc; j++) {
+               for (i = 0; i < 64; i++) {
+                       ixgbe_create_lbtest_frame(
+                                       tx_ring->tx_buffer_info[k].skb,
+                                       1024);
+                       pci_dma_sync_single_for_device(pdev,
+                               tx_ring->tx_buffer_info[k].dma,
+                               tx_ring->tx_buffer_info[k].length,
+                               PCI_DMA_TODEVICE);
+                       if (unlikely(++k == tx_ring->count))
+                               k = 0;
+               }
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDT(0), k);
+               msleep(200);
+               /* set the start time for the receive */
+               time = jiffies;
+               good_cnt = 0;
+               do {
+                       /* receive the sent packets */
+                       pci_dma_sync_single_for_cpu(pdev,
+                                       rx_ring->rx_buffer_info[l].dma,
+                                       IXGBE_RXBUFFER_2048,
+                                       PCI_DMA_FROMDEVICE);
+                       ret_val = ixgbe_check_lbtest_frame(
+                                       rx_ring->rx_buffer_info[l].skb, 1024);
+                       if (!ret_val)
+                               good_cnt++;
+                       if (++l == rx_ring->count)
+                               l = 0;
+                       /*
+                        * time + 20 msecs (200 msecs on 2.4) is more than
+                        * enough time to complete the receives, if it's
+                        * exceeded, break and error off
+                        */
+               } while (good_cnt < 64 && jiffies < (time + 20));
+               if (good_cnt != 64) {
+                       /* ret_val is the same as mis-compare */
+                       ret_val = 13;
+                       break;
+               }
+               if (jiffies >= (time + 20)) {
+                       /* Error code for time out error */
+                       ret_val = 14;
+                       break;
+               }
+       }
+
+       return ret_val;
+}
+
+static int ixgbe_loopback_test(struct ixgbe_adapter *adapter, u64 *data)
+{
+       *data = ixgbe_setup_desc_rings(adapter);
+       if (*data)
+               goto out;
+       *data = ixgbe_setup_loopback_test(adapter);
+       if (*data)
+               goto err_loopback;
+       *data = ixgbe_run_loopback_test(adapter);
+       ixgbe_loopback_cleanup(adapter);
+
+err_loopback:
+       ixgbe_free_desc_rings(adapter);
+out:
+       return *data;
+}
+
+static void ixgbe_diag_test(struct net_device *netdev,
+                            struct ethtool_test *eth_test, u64 *data)
+{
+       struct ixgbe_adapter *adapter = netdev_priv(netdev);
+       bool if_running = netif_running(netdev);
+
+       set_bit(__IXGBE_TESTING, &adapter->state);
+       if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
+               /* Offline tests */
+
+               DPRINTK(HW, INFO, "offline testing starting\n");
+
+               /* Link test performed before hardware reset so autoneg doesn't
+                * interfere with test result */
+               if (ixgbe_link_test(adapter, &data[4]))
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
+
+               if (if_running)
+                       /* indicate we're in test mode */
+                       dev_close(netdev);
+               else
+                       ixgbe_reset(adapter);
+
+               DPRINTK(HW, INFO, "register testing starting\n");
+               if (ixgbe_reg_test(adapter, &data[0]))
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
+
+               ixgbe_reset(adapter);
+               DPRINTK(HW, INFO, "eeprom testing starting\n");
+               if (ixgbe_eeprom_test(adapter, &data[1]))
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
+
+               ixgbe_reset(adapter);
+               DPRINTK(HW, INFO, "interrupt testing starting\n");
+               if (ixgbe_intr_test(adapter, &data[2]))
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
+
+               ixgbe_reset(adapter);
+               DPRINTK(HW, INFO, "loopback testing starting\n");
+               if (ixgbe_loopback_test(adapter, &data[3]))
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
+
+               ixgbe_reset(adapter);
+
+               clear_bit(__IXGBE_TESTING, &adapter->state);
+               if (if_running)
+                       dev_open(netdev);
+       } else {
+               DPRINTK(HW, INFO, "online testing starting\n");
+               /* Online tests */
+               if (ixgbe_link_test(adapter, &data[4]))
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
+
+               /* Online tests aren't run; pass by default */
+               data[0] = 0;
+               data[1] = 0;
+               data[2] = 0;
+               data[3] = 0;
+
+               clear_bit(__IXGBE_TESTING, &adapter->state);
+       }
+       msleep_interruptible(4 * 1000);
+}
 
 static int ixgbe_wol_exclusion(struct ixgbe_adapter *adapter,
                                struct ethtool_wolinfo *wol)
@@ -1146,8 +1987,7 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
                else
                        /* rx only or mixed */
                        q_vector->eitr = adapter->eitr_param;
-               ixgbe_write_eitr(adapter, i,
-                                EITR_INTS_PER_SEC_TO_REG(q_vector->eitr));
+               ixgbe_write_eitr(q_vector);
        }
 
        return 0;
@@ -1159,13 +1999,13 @@ static int ixgbe_set_flags(struct net_device *netdev, u32 data)
 
        ethtool_op_set_flags(netdev, data);
 
-       if (!(adapter->flags & IXGBE_FLAG_RSC_CAPABLE))
+       if (!(adapter->flags & IXGBE_FLAG2_RSC_CAPABLE))
                return 0;
 
        /* if state changes we need to update adapter->flags and reset */
        if ((!!(data & ETH_FLAG_LRO)) != 
-           (!!(adapter->flags & IXGBE_FLAG_RSC_ENABLED))) {
-               adapter->flags ^= IXGBE_FLAG_RSC_ENABLED;
+           (!!(adapter->flags & IXGBE_FLAG2_RSC_ENABLED))) {
+               adapter->flags ^= IXGBE_FLAG2_RSC_ENABLED;
                if (netif_running(netdev))
                        ixgbe_reinit_locked(adapter);
                else
@@ -1201,6 +2041,7 @@ static const struct ethtool_ops ixgbe_ethtool_ops = {
        .set_msglevel           = ixgbe_set_msglevel,
        .get_tso                = ethtool_op_get_tso,
        .set_tso                = ixgbe_set_tso,
+       .self_test              = ixgbe_diag_test,
        .get_strings            = ixgbe_get_strings,
        .phys_id                = ixgbe_phys_id,
        .get_sset_count         = ixgbe_get_sset_count,
index d5939de..3c3bf1f 100644 (file)
@@ -280,7 +280,9 @@ out_noddp_unmap:
  *
  * This checks ddp status.
  *
- * Returns : 0 for success and skb will not be delivered to ULD
+ * Returns : < 0 indicates an error or not a FCiE ddp, 0 indicates
+ * not passing the skb to ULD, > 0 indicates is the length of data
+ * being ddped.
  */
 int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter,
                   union ixgbe_adv_rx_desc *rx_desc,
@@ -334,6 +336,8 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter,
                /* return 0 to bypass going to ULD for DDPed data */
                if (fcstat == IXGBE_RXDADV_STAT_FCSTAT_DDP)
                        rc = 0;
+               else
+                       rc = ddp->len;
        }
 
 ddp_out:
index b7f9b63..c5b5002 100644 (file)
@@ -28,6 +28,7 @@
 #ifndef _IXGBE_FCOE_H
 #define _IXGBE_FCOE_H
 
+#include <scsi/fc/fc_fs.h>
 #include <scsi/fc/fc_fcoe.h>
 
 /* shift bits within STAT fo FCSTAT */
index dff1da8..a551a96 100644 (file)
@@ -48,7 +48,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.24-k2"
+#define DRV_VERSION "2.0.34-k2"
 const char ixgbe_driver_version[] = DRV_VERSION;
 static char ixgbe_copyright[] = "Copyright (c) 1999-2009 Intel Corporation.";
 
@@ -186,6 +186,22 @@ static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, s8 direction,
        }
 }
 
+static inline void ixgbe_irq_rearm_queues(struct ixgbe_adapter *adapter,
+                                          u64 qmask)
+{
+       u32 mask;
+
+       if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
+               mask = (IXGBE_EIMS_RTX_QUEUE & qmask);
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask);
+       } else {
+               mask = (qmask & 0xFFFFFFFF);
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), mask);
+               mask = (qmask >> 32);
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(1), mask);
+       }
+}
+
 static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter,
                                              struct ixgbe_tx_buffer
                                              *tx_buffer_info)
@@ -248,14 +264,13 @@ static void ixgbe_tx_timeout(struct net_device *netdev);
 
 /**
  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
- * @adapter: board private structure
+ * @q_vector: structure containing interrupt and ring information
  * @tx_ring: tx ring to clean
- *
- * returns true if transmit work is done
  **/
-static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter,
+static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
                                struct ixgbe_ring *tx_ring)
 {
+       struct ixgbe_adapter *adapter = q_vector->adapter;
        struct net_device *netdev = adapter->netdev;
        union ixgbe_adv_tx_desc *tx_desc, *eop_desc;
        struct ixgbe_tx_buffer *tx_buffer_info;
@@ -278,12 +293,24 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter,
 
                        if (cleaned && skb) {
                                unsigned int segs, bytecount;
+                               unsigned int hlen = skb_headlen(skb);
 
                                /* gso_segs is currently only valid for tcp */
                                segs = skb_shinfo(skb)->gso_segs ?: 1;
+#ifdef IXGBE_FCOE
+                               /* adjust for FCoE Sequence Offload */
+                               if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED)
+                                   && (skb->protocol == htons(ETH_P_FCOE)) &&
+                                   skb_is_gso(skb)) {
+                                       hlen = skb_transport_offset(skb) +
+                                               sizeof(struct fc_frame_header) +
+                                               sizeof(struct fcoe_crc_eof);
+                                       segs = DIV_ROUND_UP(skb->len - hlen,
+                                               skb_shinfo(skb)->gso_size);
+                               }
+#endif /* IXGBE_FCOE */
                                /* multiply data chunks by size of headers */
-                               bytecount = ((segs - 1) * skb_headlen(skb)) +
-                                           skb->len;
+                               bytecount = ((segs - 1) * hlen) + skb->len;
                                total_packets += segs;
                                total_bytes += bytecount;
                        }
@@ -329,18 +356,8 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter,
        }
 
        /* re-arm the interrupt */
-       if (count >= tx_ring->work_limit) {
-               if (adapter->hw.mac.type == ixgbe_mac_82598EB)
-                       IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS,
-                                       tx_ring->v_idx);
-               else if (tx_ring->v_idx & 0xFFFFFFFF)
-                       IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0),
-                                       tx_ring->v_idx);
-               else
-                       IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(1),
-                                       (tx_ring->v_idx >> 32));
-       }
-
+       if (count >= tx_ring->work_limit)
+               ixgbe_irq_rearm_queues(adapter, ((u64)1 << q_vector->v_idx));
 
        tx_ring->total_bytes += total_bytes;
        tx_ring->total_packets += total_packets;
@@ -678,6 +695,9 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
        bool cleaned = false;
        int cleaned_count = 0;
        unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+#ifdef IXGBE_FCOE
+       int ddp_bytes = 0;
+#endif /* IXGBE_FCOE */
 
        i = rx_ring->next_to_clean;
        rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
@@ -708,7 +728,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
                prefetch(skb->data - NET_IP_ALIGN);
                rx_buffer_info->skb = NULL;
 
-               if (len && !skb_shinfo(skb)->nr_frags) {
+               if (rx_buffer_info->dma) {
                        pci_unmap_single(pdev, rx_buffer_info->dma,
                                         rx_ring->rx_buf_len,
                                         PCI_DMA_FROMDEVICE);
@@ -743,7 +763,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
                prefetch(next_rxd);
                cleaned_count++;
 
-               if (adapter->flags & IXGBE_FLAG_RSC_CAPABLE)
+               if (adapter->flags & IXGBE_FLAG2_RSC_CAPABLE)
                        rsc_count = ixgbe_get_rsc_count(rx_desc);
 
                if (rsc_count) {
@@ -788,9 +808,11 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
                skb->protocol = eth_type_trans(skb, adapter->netdev);
 #ifdef IXGBE_FCOE
                /* if ddp, not passing to ULD unless for FCP_RSP or error */
-               if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED)
-                       if (!ixgbe_fcoe_ddp(adapter, rx_desc, skb))
+               if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) {
+                       ddp_bytes = ixgbe_fcoe_ddp(adapter, rx_desc, skb);
+                       if (!ddp_bytes)
                                goto next_desc;
+               }
 #endif /* IXGBE_FCOE */
                ixgbe_receive_skb(q_vector, skb, staterr, rx_ring, rx_desc);
 
@@ -816,6 +838,21 @@ next_desc:
        if (cleaned_count)
                ixgbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count);
 
+#ifdef IXGBE_FCOE
+       /* include DDPed FCoE data */
+       if (ddp_bytes > 0) {
+               unsigned int mss;
+
+               mss = adapter->netdev->mtu - sizeof(struct fcoe_hdr) -
+                       sizeof(struct fc_frame_header) -
+                       sizeof(struct fcoe_crc_eof);
+               if (mss > 512)
+                       mss &= ~511;
+               total_rx_bytes += ddp_bytes;
+               total_rx_packets += DIV_ROUND_UP(ddp_bytes, mss);
+       }
+#endif /* IXGBE_FCOE */
+
        rx_ring->total_packets += total_rx_packets;
        rx_ring->total_bytes += total_rx_bytes;
        adapter->net_stats.rx_bytes += total_rx_bytes;
@@ -875,12 +912,7 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
                        /* rx only */
                        q_vector->eitr = adapter->eitr_param;
 
-               /*
-                * since this is initial set up don't need to call
-                * ixgbe_write_eitr helper
-                */
-               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(v_idx),
-                               EITR_INTS_PER_SEC_TO_REG(q_vector->eitr));
+               ixgbe_write_eitr(q_vector);
        }
 
        if (adapter->hw.mac.type == ixgbe_mac_82598EB)
@@ -965,17 +997,19 @@ update_itr_done:
 
 /**
  * ixgbe_write_eitr - write EITR register in hardware specific way
- * @adapter: pointer to adapter struct
- * @v_idx: vector index into q_vector array
- * @itr_reg: new value to be written in *register* format, not ints/s
+ * @q_vector: structure containing interrupt and ring information
  *
  * This function is made to be called by ethtool and by the driver
  * when it needs to update EITR registers at runtime.  Hardware
  * specific quirks/differences are taken care of here.
  */
-void ixgbe_write_eitr(struct ixgbe_adapter *adapter, int v_idx, u32 itr_reg)
+void ixgbe_write_eitr(struct ixgbe_q_vector *q_vector)
 {
+       struct ixgbe_adapter *adapter = q_vector->adapter;
        struct ixgbe_hw *hw = &adapter->hw;
+       int v_idx = q_vector->v_idx;
+       u32 itr_reg = EITR_INTS_PER_SEC_TO_REG(q_vector->eitr);
+
        if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
                /* must write high and low 16 bits to reset counter */
                itr_reg |= (itr_reg << 16);
@@ -994,7 +1028,7 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector)
        struct ixgbe_adapter *adapter = q_vector->adapter;
        u32 new_itr;
        u8 current_itr, ret_itr;
-       int i, r_idx, v_idx = q_vector->v_idx;
+       int i, r_idx;
        struct ixgbe_ring *rx_ring, *tx_ring;
 
        r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues);
@@ -1044,14 +1078,13 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector)
        }
 
        if (new_itr != q_vector->eitr) {
-               u32 itr_reg;
+               /* do an exponential smoothing */
+               new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100);
 
                /* save the algorithm value here, not the smoothed one */
                q_vector->eitr = new_itr;
-               /* do an exponential smoothing */
-               new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100);
-               itr_reg = EITR_INTS_PER_SEC_TO_REG(new_itr);
-               ixgbe_write_eitr(adapter, v_idx, itr_reg);
+
+               ixgbe_write_eitr(q_vector);
        }
 
        return;
@@ -1122,14 +1155,64 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data)
        if (hw->mac.type == ixgbe_mac_82598EB)
                ixgbe_check_fan_failure(adapter, eicr);
 
-       if (hw->mac.type == ixgbe_mac_82599EB)
+       if (hw->mac.type == ixgbe_mac_82599EB) {
                ixgbe_check_sfp_event(adapter, eicr);
+
+               /* Handle Flow Director Full threshold interrupt */
+               if (eicr & IXGBE_EICR_FLOW_DIR) {
+                       int i;
+                       IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_FLOW_DIR);
+                       /* Disable transmits before FDIR Re-initialization */
+                       netif_tx_stop_all_queues(netdev);
+                       for (i = 0; i < adapter->num_tx_queues; i++) {
+                               struct ixgbe_ring *tx_ring =
+                                                          &adapter->tx_ring[i];
+                               if (test_and_clear_bit(__IXGBE_FDIR_INIT_DONE,
+                                                      &tx_ring->reinit_state))
+                                       schedule_work(&adapter->fdir_reinit_task);
+                       }
+               }
+       }
        if (!test_bit(__IXGBE_DOWN, &adapter->state))
                IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
 
        return IRQ_HANDLED;
 }
 
+static inline void ixgbe_irq_enable_queues(struct ixgbe_adapter *adapter,
+                                          u64 qmask)
+{
+       u32 mask;
+
+       if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
+               mask = (IXGBE_EIMS_RTX_QUEUE & qmask);
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask);
+       } else {
+               mask = (qmask & 0xFFFFFFFF);
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(0), mask);
+               mask = (qmask >> 32);
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(1), mask);
+       }
+       /* skip the flush */
+}
+
+static inline void ixgbe_irq_disable_queues(struct ixgbe_adapter *adapter,
+                                            u64 qmask)
+{
+       u32 mask;
+
+       if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
+               mask = (IXGBE_EIMS_RTX_QUEUE & qmask);
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, mask);
+       } else {
+               mask = (qmask & 0xFFFFFFFF);
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), mask);
+               mask = (qmask >> 32);
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), mask);
+       }
+       /* skip the flush */
+}
+
 static irqreturn_t ixgbe_msix_clean_tx(int irq, void *data)
 {
        struct ixgbe_q_vector *q_vector = data;
@@ -1143,17 +1226,16 @@ static irqreturn_t ixgbe_msix_clean_tx(int irq, void *data)
        r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues);
        for (i = 0; i < q_vector->txr_count; i++) {
                tx_ring = &(adapter->tx_ring[r_idx]);
-#ifdef CONFIG_IXGBE_DCA
-               if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
-                       ixgbe_update_tx_dca(adapter, tx_ring);
-#endif
                tx_ring->total_bytes = 0;
                tx_ring->total_packets = 0;
-               ixgbe_clean_tx_irq(adapter, tx_ring);
                r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues,
                                      r_idx + 1);
        }
 
+       /* disable interrupts on this vector only */
+       ixgbe_irq_disable_queues(adapter, ((u64)1 << q_vector->v_idx));
+       napi_schedule(&q_vector->napi);
+
        return IRQ_HANDLED;
 }
 
@@ -1185,13 +1267,7 @@ static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data)
        r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
        rx_ring = &(adapter->rx_ring[r_idx]);
        /* disable interrupts on this vector only */
-       if (adapter->hw.mac.type == ixgbe_mac_82598EB)
-               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, rx_ring->v_idx);
-       else if (rx_ring->v_idx & 0xFFFFFFFF)
-               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), rx_ring->v_idx);
-       else
-               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1),
-                               (rx_ring->v_idx >> 32));
+       ixgbe_irq_disable_queues(adapter, ((u64)1 << q_vector->v_idx));
        napi_schedule(&q_vector->napi);
 
        return IRQ_HANDLED;
@@ -1199,27 +1275,38 @@ static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data)
 
 static irqreturn_t ixgbe_msix_clean_many(int irq, void *data)
 {
-       ixgbe_msix_clean_rx(irq, data);
-       ixgbe_msix_clean_tx(irq, data);
+       struct ixgbe_q_vector *q_vector = data;
+       struct ixgbe_adapter  *adapter = q_vector->adapter;
+       struct ixgbe_ring  *ring;
+       int r_idx;
+       int i;
 
-       return IRQ_HANDLED;
-}
+       if (!q_vector->txr_count && !q_vector->rxr_count)
+               return IRQ_HANDLED;
 
-static inline void ixgbe_irq_enable_queues(struct ixgbe_adapter *adapter,
-                                          u64 qmask)
-{
-       u32 mask;
+       r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues);
+       for (i = 0; i < q_vector->txr_count; i++) {
+               ring = &(adapter->tx_ring[r_idx]);
+               ring->total_bytes = 0;
+               ring->total_packets = 0;
+               r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues,
+                                     r_idx + 1);
+       }
 
-       if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
-               mask = (IXGBE_EIMS_RTX_QUEUE & qmask);
-               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask);
-       } else {
-               mask = (qmask & 0xFFFFFFFF);
-               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(0), mask);
-               mask = (qmask >> 32);
-               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(1), mask);
+       r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
+       for (i = 0; i < q_vector->rxr_count; i++) {
+               ring = &(adapter->rx_ring[r_idx]);
+               ring->total_bytes = 0;
+               ring->total_packets = 0;
+               r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
+                                     r_idx + 1);
        }
-       /* skip the flush */
+
+       /* disable interrupts on this vector only */
+       ixgbe_irq_disable_queues(adapter, ((u64)1 << q_vector->v_idx));
+       napi_schedule(&q_vector->napi);
+
+       return IRQ_HANDLED;
 }
 
 /**
@@ -1254,29 +1341,42 @@ static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget)
                if (adapter->itr_setting & 1)
                        ixgbe_set_itr_msix(q_vector);
                if (!test_bit(__IXGBE_DOWN, &adapter->state))
-                       ixgbe_irq_enable_queues(adapter, rx_ring->v_idx);
+                       ixgbe_irq_enable_queues(adapter,
+                                               ((u64)1 << q_vector->v_idx));
        }
 
        return work_done;
 }
 
 /**
- * ixgbe_clean_rxonly_many - msix (aka one shot) rx clean routine
+ * ixgbe_clean_rxtx_many - msix (aka one shot) rx clean routine
  * @napi: napi struct with our devices info in it
  * @budget: amount of work driver is allowed to do this pass, in packets
  *
  * This function will clean more than one rx queue associated with a
  * q_vector.
  **/
-static int ixgbe_clean_rxonly_many(struct napi_struct *napi, int budget)
+static int ixgbe_clean_rxtx_many(struct napi_struct *napi, int budget)
 {
        struct ixgbe_q_vector *q_vector =
                               container_of(napi, struct ixgbe_q_vector, napi);
        struct ixgbe_adapter *adapter = q_vector->adapter;
-       struct ixgbe_ring *rx_ring = NULL;
+       struct ixgbe_ring *ring = NULL;
        int work_done = 0, i;
        long r_idx;
-       u64 enable_mask = 0;
+       bool tx_clean_complete = true;
+
+       r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues);
+       for (i = 0; i < q_vector->txr_count; i++) {
+               ring = &(adapter->tx_ring[r_idx]);
+#ifdef CONFIG_IXGBE_DCA
+               if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
+                       ixgbe_update_tx_dca(adapter, ring);
+#endif
+               tx_clean_complete &= ixgbe_clean_tx_irq(q_vector, ring);
+               r_idx = find_next_bit(q_vector->txr_idx, adapter->num_tx_queues,
+                                     r_idx + 1);
+       }
 
        /* attempt to distribute budget to each queue fairly, but don't allow
         * the budget to go below 1 because we'll exit polling */
@@ -1284,31 +1384,71 @@ static int ixgbe_clean_rxonly_many(struct napi_struct *napi, int budget)
        budget = max(budget, 1);
        r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
        for (i = 0; i < q_vector->rxr_count; i++) {
-               rx_ring = &(adapter->rx_ring[r_idx]);
+               ring = &(adapter->rx_ring[r_idx]);
 #ifdef CONFIG_IXGBE_DCA
                if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
-                       ixgbe_update_rx_dca(adapter, rx_ring);
+                       ixgbe_update_rx_dca(adapter, ring);
 #endif
-               ixgbe_clean_rx_irq(q_vector, rx_ring, &work_done, budget);
-               enable_mask |= rx_ring->v_idx;
+               ixgbe_clean_rx_irq(q_vector, ring, &work_done, budget);
                r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
                                      r_idx + 1);
        }
 
        r_idx = find_first_bit(q_vector->rxr_idx, adapter->num_rx_queues);
-       rx_ring = &(adapter->rx_ring[r_idx]);
+       ring = &(adapter->rx_ring[r_idx]);
        /* If all Rx work done, exit the polling mode */
        if (work_done < budget) {
                napi_complete(napi);
                if (adapter->itr_setting & 1)
                        ixgbe_set_itr_msix(q_vector);
                if (!test_bit(__IXGBE_DOWN, &adapter->state))
-                       ixgbe_irq_enable_queues(adapter, enable_mask);
+                       ixgbe_irq_enable_queues(adapter,
+                                               ((u64)1 << q_vector->v_idx));
                return 0;
        }
 
        return work_done;
 }
+
+/**
+ * ixgbe_clean_txonly - msix (aka one shot) tx clean routine
+ * @napi: napi struct with our devices info in it
+ * @budget: amount of work driver is allowed to do this pass, in packets
+ *
+ * This function is optimized for cleaning one queue only on a single
+ * q_vector!!!
+ **/
+static int ixgbe_clean_txonly(struct napi_struct *napi, int budget)
+{
+       struct ixgbe_q_vector *q_vector =
+                              container_of(napi, struct ixgbe_q_vector, napi);
+       struct ixgbe_adapter *adapter = q_vector->adapter;
+       struct ixgbe_ring *tx_ring = NULL;
+       int work_done = 0;
+       long r_idx;
+
+       r_idx = find_first_bit(q_vector->txr_idx, adapter->num_tx_queues);
+       tx_ring = &(adapter->tx_ring[r_idx]);
+#ifdef CONFIG_IXGBE_DCA
+       if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
+               ixgbe_update_tx_dca(adapter, tx_ring);
+#endif
+
+       if (!ixgbe_clean_tx_irq(q_vector, tx_ring))
+               work_done = budget;
+
+       /* If all Rx work done, exit the polling mode */
+       if (work_done < budget) {
+               napi_complete(napi);
+               if (adapter->itr_setting & 1)
+                       ixgbe_set_itr_msix(q_vector);
+               if (!test_bit(__IXGBE_DOWN, &adapter->state))
+                       ixgbe_irq_enable_queues(adapter, ((u64)1 << q_vector->v_idx));
+       }
+
+       return work_done;
+}
+
 static inline void map_vector_to_rxq(struct ixgbe_adapter *a, int v_idx,
                                      int r_idx)
 {
@@ -1316,7 +1456,6 @@ static inline void map_vector_to_rxq(struct ixgbe_adapter *a, int v_idx,
 
        set_bit(r_idx, q_vector->rxr_idx);
        q_vector->rxr_count++;
-       a->rx_ring[r_idx].v_idx = (u64)1 << v_idx;
 }
 
 static inline void map_vector_to_txq(struct ixgbe_adapter *a, int v_idx,
@@ -1326,7 +1465,6 @@ static inline void map_vector_to_txq(struct ixgbe_adapter *a, int v_idx,
 
        set_bit(t_idx, q_vector->txr_idx);
        q_vector->txr_count++;
-       a->tx_ring[t_idx].v_idx = (u64)1 << v_idx;
 }
 
 /**
@@ -1505,14 +1643,13 @@ static void ixgbe_set_itr(struct ixgbe_adapter *adapter)
        }
 
        if (new_itr != q_vector->eitr) {
-               u32 itr_reg;
+               /* do an exponential smoothing */
+               new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100);
 
                /* save the algorithm value here, not the smoothed one */
                q_vector->eitr = new_itr;
-               /* do an exponential smoothing */
-               new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100);
-               itr_reg = EITR_INTS_PER_SEC_TO_REG(new_itr);
-               ixgbe_write_eitr(adapter, 0, itr_reg);
+
+               ixgbe_write_eitr(q_vector);
        }
 
        return;
@@ -1534,6 +1671,9 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter)
                mask |= IXGBE_EIMS_GPI_SDP1;
                mask |= IXGBE_EIMS_GPI_SDP2;
        }
+       if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE ||
+           adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
+               mask |= IXGBE_EIMS_FLOW_DIR;
 
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask);
        ixgbe_irq_enable_queues(adapter, ~0);
@@ -1879,7 +2019,7 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
                        IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype);
                }
        } else {
-               if (!(adapter->flags & IXGBE_FLAG_RSC_ENABLED) &&
+               if (!(adapter->flags & IXGBE_FLAG2_RSC_ENABLED) &&
                    (netdev->mtu <= ETH_DATA_LEN))
                        rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE;
                else
@@ -2008,7 +2148,7 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
                IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl);
        }
 
-       if (adapter->flags & IXGBE_FLAG_RSC_ENABLED) {
+       if (adapter->flags & IXGBE_FLAG2_RSC_ENABLED) {
                /* Enable 82599 HW-RSC */
                for (i = 0; i < adapter->num_rx_queues; i++) {
                        j = adapter->rx_ring[i].reg_idx;
@@ -2181,11 +2321,7 @@ static void ixgbe_set_rx_mode(struct net_device *netdev)
        IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
 
        /* reprogram secondary unicast list */
-       addr_count = netdev->uc_count;
-       if (addr_count)
-               addr_list = netdev->uc_list->dmi_addr;
-       hw->mac.ops.update_uc_addr_list(hw, addr_list, addr_count,
-                                         ixgbe_addr_list_itr);
+       hw->mac.ops.update_uc_addr_list(hw, &netdev->uc_list);
 
        /* reprogram multicast list */
        addr_count = netdev->mc_count;
@@ -2208,12 +2344,15 @@ static void ixgbe_napi_enable_all(struct ixgbe_adapter *adapter)
        for (q_idx = 0; q_idx < q_vectors; q_idx++) {
                struct napi_struct *napi;
                q_vector = adapter->q_vector[q_idx];
-               if (!q_vector->rxr_count)
-                       continue;
                napi = &q_vector->napi;
-               if ((adapter->flags & IXGBE_FLAG_MSIX_ENABLED) &&
-                   (q_vector->rxr_count > 1))
-                       napi->poll = &ixgbe_clean_rxonly_many;
+               if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
+                       if (!q_vector->rxr_count || !q_vector->txr_count) {
+                               if (q_vector->txr_count == 1)
+                                       napi->poll = &ixgbe_clean_txonly;
+                               else if (q_vector->rxr_count == 1)
+                                       napi->poll = &ixgbe_clean_rxonly;
+                       }
+               }
 
                napi_enable(napi);
        }
@@ -2231,8 +2370,6 @@ static void ixgbe_napi_disable_all(struct ixgbe_adapter *adapter)
 
        for (q_idx = 0; q_idx < q_vectors; q_idx++) {
                q_vector = adapter->q_vector[q_idx];
-               if (!q_vector->rxr_count)
-                       continue;
                napi_disable(&q_vector->napi);
        }
 }
@@ -2290,6 +2427,7 @@ static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter)
 static void ixgbe_configure(struct ixgbe_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
+       struct ixgbe_hw *hw = &adapter->hw;
        int i;
 
        ixgbe_set_rx_mode(netdev);
@@ -2311,6 +2449,15 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter)
                ixgbe_configure_fcoe(adapter);
 
 #endif /* IXGBE_FCOE */
+       if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) {
+               for (i = 0; i < adapter->num_tx_queues; i++)
+                       adapter->tx_ring[i].atr_sample_rate =
+                                                      adapter->atr_sample_rate;
+               ixgbe_init_fdir_signature_82599(hw, adapter->fdir_pballoc);
+       } else if (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) {
+               ixgbe_init_fdir_perfect_82599(hw, adapter->fdir_pballoc);
+       }
+
        ixgbe_configure_tx(adapter);
        ixgbe_configure_rx(adapter);
        for (i = 0; i < adapter->num_rx_queues; i++)
@@ -2567,6 +2714,10 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
                        DPRINTK(PROBE, ERR, "link_config FAILED %d\n", err);
        }
 
+       for (i = 0; i < adapter->num_tx_queues; i++)
+               set_bit(__IXGBE_FDIR_INIT_DONE,
+                       &(adapter->tx_ring[i].reinit_state));
+
        /* enable transmits */
        netif_tx_start_all_queues(netdev);
 
@@ -2602,12 +2753,28 @@ void ixgbe_reset(struct ixgbe_adapter *adapter)
        int err;
 
        err = hw->mac.ops.init_hw(hw);
-       if (err && (err != IXGBE_ERR_SFP_NOT_PRESENT))
-               dev_err(&adapter->pdev->dev, "Hardware Error\n");
+       switch (err) {
+       case 0:
+       case IXGBE_ERR_SFP_NOT_PRESENT:
+               break;
+       case IXGBE_ERR_MASTER_REQUESTS_PENDING:
+               dev_err(&adapter->pdev->dev, "master disable timed out\n");
+               break;
+       case IXGBE_ERR_EEPROM_VERSION:
+               /* We are running on a pre-production device, log a warning */
+               dev_warn(&adapter->pdev->dev, "This device is a pre-production "
+                        "adapter/LOM.  Please be aware there may be issues "
+                        "associated with your hardware.  If you are "
+                        "experiencing problems please contact your Intel or "
+                        "hardware representative who provided you with this "
+                        "hardware.\n");
+               break;
+       default:
+               dev_err(&adapter->pdev->dev, "Hardware Error: %d\n", err);
+       }
 
        /* reprogram the RAR[0] in case user changed it. */
        hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV);
-
 }
 
 /**
@@ -2755,6 +2922,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
        del_timer_sync(&adapter->watchdog_timer);
        cancel_work_sync(&adapter->watchdog_task);
 
+       if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE ||
+           adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
+               cancel_work_sync(&adapter->fdir_reinit_task);
+
        /* disable transmits in the hardware now that interrupts are off */
        for (i = 0; i < adapter->num_tx_queues; i++) {
                j = adapter->tx_ring[i].reg_idx;
@@ -2802,7 +2973,7 @@ static int ixgbe_poll(struct napi_struct *napi, int budget)
        }
 #endif
 
-       tx_clean_complete = ixgbe_clean_tx_irq(adapter, adapter->tx_ring);
+       tx_clean_complete = ixgbe_clean_tx_irq(q_vector, adapter->tx_ring);
        ixgbe_clean_rx_irq(q_vector, adapter->rx_ring, &work_done, budget);
 
        if (!tx_clean_complete)
@@ -2889,6 +3060,38 @@ static inline bool ixgbe_set_rss_queues(struct ixgbe_adapter *adapter)
        return ret;
 }
 
+/**
+ * ixgbe_set_fdir_queues: Allocate queues for Flow Director
+ * @adapter: board private structure to initialize
+ *
+ * Flow Director is an advanced Rx filter, attempting to get Rx flows back
+ * to the original CPU that initiated the Tx session.  This runs in addition
+ * to RSS, so if a packet doesn't match an FDIR filter, we can still spread the
+ * Rx load across CPUs using RSS.
+ *
+ **/
+static bool inline ixgbe_set_fdir_queues(struct ixgbe_adapter *adapter)
+{
+       bool ret = false;
+       struct ixgbe_ring_feature *f_fdir = &adapter->ring_feature[RING_F_FDIR];
+
+       f_fdir->indices = min((int)num_online_cpus(), f_fdir->indices);
+       f_fdir->mask = 0;
+
+       /* Flow Director must have RSS enabled */
+       if (adapter->flags & IXGBE_FLAG_RSS_ENABLED &&
+           ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE ||
+            (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)))) {
+               adapter->num_tx_queues = f_fdir->indices;
+               adapter->num_rx_queues = f_fdir->indices;
+               ret = true;
+       } else {
+               adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE;
+               adapter->flags &= ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
+       }
+       return ret;
+}
+
 #ifdef IXGBE_FCOE
 /**
  * ixgbe_set_fcoe_queues: Allocate queues for Fiber Channel over Ethernet (FCoE)
@@ -2953,6 +3156,9 @@ static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter)
                goto done;
 
 #endif
+       if (ixgbe_set_fdir_queues(adapter))
+               goto done;
+
        if (ixgbe_set_rss_queues(adapter))
                goto done;
 
@@ -3123,6 +3329,31 @@ static inline bool ixgbe_cache_ring_dcb(struct ixgbe_adapter *adapter)
 }
 #endif
 
+/**
+ * ixgbe_cache_ring_fdir - Descriptor ring to register mapping for Flow Director
+ * @adapter: board private structure to initialize
+ *
+ * Cache the descriptor ring offsets for Flow Director to the assigned rings.
+ *
+ **/
+static bool inline ixgbe_cache_ring_fdir(struct ixgbe_adapter *adapter)
+{
+       int i;
+       bool ret = false;
+
+       if (adapter->flags & IXGBE_FLAG_RSS_ENABLED &&
+           ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) ||
+            (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))) {
+               for (i = 0; i < adapter->num_rx_queues; i++)
+                       adapter->rx_ring[i].reg_idx = i;
+               for (i = 0; i < adapter->num_tx_queues; i++)
+                       adapter->tx_ring[i].reg_idx = i;
+               ret = true;
+       }
+
+       return ret;
+}
+
 #ifdef IXGBE_FCOE
 /**
  * ixgbe_cache_ring_fcoe - Descriptor ring to register mapping for the FCoE
@@ -3183,6 +3414,9 @@ static void ixgbe_cache_ring_register(struct ixgbe_adapter *adapter)
                return;
 
 #endif
+       if (ixgbe_cache_ring_fdir(adapter))
+               return;
+
        if (ixgbe_cache_ring_rss(adapter))
                return;
 }
@@ -3276,6 +3510,9 @@ static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter)
 
        adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED;
        adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED;
+       adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE;
+       adapter->flags &= ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
+       adapter->atr_sample_rate = 0;
        ixgbe_set_num_queues(adapter);
 
        err = pci_enable_msi(adapter->pdev);
@@ -3309,7 +3546,7 @@ static int ixgbe_alloc_q_vectors(struct ixgbe_adapter *adapter)
        if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
                num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
                napi_vectors = adapter->num_rx_queues;
-               poll = &ixgbe_clean_rxonly;
+               poll = &ixgbe_clean_rxtx_many;
        } else {
                num_q_vectors = 1;
                napi_vectors = 1;
@@ -3321,11 +3558,9 @@ static int ixgbe_alloc_q_vectors(struct ixgbe_adapter *adapter)
                if (!q_vector)
                        goto err_out;
                q_vector->adapter = adapter;
-               q_vector->v_idx = q_idx;
                q_vector->eitr = adapter->eitr_param;
-               if (q_idx < napi_vectors)
-                       netif_napi_add(adapter->netdev, &q_vector->napi,
-                                      (*poll), 64);
+               q_vector->v_idx = q_idx;
+               netif_napi_add(adapter->netdev, &q_vector->napi, (*poll), 64);
                adapter->q_vector[q_idx] = q_vector;
        }
 
@@ -3353,22 +3588,16 @@ err_out:
 static void ixgbe_free_q_vectors(struct ixgbe_adapter *adapter)
 {
        int q_idx, num_q_vectors;
-       int napi_vectors;
 
-       if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
+       if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
                num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
-               napi_vectors = adapter->num_rx_queues;
-       } else {
+       else
                num_q_vectors = 1;
-               napi_vectors = 1;
-       }
 
        for (q_idx = 0; q_idx < num_q_vectors; q_idx++) {
                struct ixgbe_q_vector *q_vector = adapter->q_vector[q_idx];
-
                adapter->q_vector[q_idx] = NULL;
-               if (q_idx < napi_vectors)
-                       netif_napi_del(&q_vector->napi);
+               netif_napi_del(&q_vector->napi);
                kfree(q_vector);
        }
 }
@@ -3547,8 +3776,13 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
                adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82598;
        } else if (hw->mac.type == ixgbe_mac_82599EB) {
                adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82599;
-               adapter->flags |= IXGBE_FLAG_RSC_CAPABLE;
-               adapter->flags |= IXGBE_FLAG_RSC_ENABLED;
+               adapter->flags |= IXGBE_FLAG2_RSC_CAPABLE;
+               adapter->flags |= IXGBE_FLAG2_RSC_ENABLED;
+               adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE;
+               adapter->ring_feature[RING_F_FDIR].indices =
+                                                        IXGBE_MAX_FDIR_INDICES;
+               adapter->atr_sample_rate = 20;
+               adapter->fdir_pballoc = 0;
 #ifdef IXGBE_FCOE
                adapter->flags |= IXGBE_FLAG_FCOE_ENABLED;
                adapter->ring_feature[RING_F_FCOE].indices = IXGBE_FCRETA_SIZE;
@@ -4138,6 +4372,8 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
                IXGBE_READ_REG(hw, IXGBE_TORH); /* to clear */
                adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT);
                adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT);
+               adapter->stats.fdirmatch += IXGBE_READ_REG(hw, IXGBE_FDIRMATCH);
+               adapter->stats.fdirmiss += IXGBE_READ_REG(hw, IXGBE_FDIRMISS);
 #ifdef IXGBE_FCOE
                adapter->stats.fccrc += IXGBE_READ_REG(hw, IXGBE_FCCRC);
                adapter->stats.fcoerpdc += IXGBE_READ_REG(hw, IXGBE_FCOERPDC);
@@ -4213,57 +4449,43 @@ static void ixgbe_watchdog(unsigned long data)
 {
        struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data;
        struct ixgbe_hw *hw = &adapter->hw;
+       u64 eics = 0;
+       int i;
 
-       /* Do the watchdog outside of interrupt context due to the lovely
-        * delays that some of the newer hardware requires */
-       if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
-               u64 eics = 0;
-               int i;
+       /*
+        *  Do the watchdog outside of interrupt context due to the lovely
+        * delays that some of the newer hardware requires
+        */
 
-               for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++)
-                       eics |= ((u64)1 << i);
+       if (test_bit(__IXGBE_DOWN, &adapter->state))
+               goto watchdog_short_circuit;
 
-               /* Cause software interrupt to ensure rx rings are cleaned */
-               switch (hw->mac.type) {
-               case ixgbe_mac_82598EB:
-                       if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
-                               IXGBE_WRITE_REG(hw, IXGBE_EICS, (u32)eics);
-                       } else {
-                               /*
-                                * for legacy and MSI interrupts don't set any
-                                * bits that are enabled for EIAM, because this
-                                * operation would set *both* EIMS and EICS for
-                                * any bit in EIAM
-                                */
-                               IXGBE_WRITE_REG(hw, IXGBE_EICS,
-                                    (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER));
-                       }
-                       break;
-               case ixgbe_mac_82599EB:
-                       if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
-                               IXGBE_WRITE_REG(hw, IXGBE_EICS_EX(0),
-                                               (u32)(eics & 0xFFFFFFFF));
-                               IXGBE_WRITE_REG(hw, IXGBE_EICS_EX(1),
-                                               (u32)(eics >> 32));
-                       } else {
-                               /*
-                                * for legacy and MSI interrupts don't set any
-                                * bits that are enabled for EIAM, because this
-                                * operation would set *both* EIMS and EICS for
-                                * any bit in EIAM
-                                */
-                               IXGBE_WRITE_REG(hw, IXGBE_EICS,
-                                    (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER));
-                       }
-                       break;
-               default:
-                       break;
-               }
-               /* Reset the timer */
-               mod_timer(&adapter->watchdog_timer,
-                         round_jiffies(jiffies + 2 * HZ));
+       if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) {
+               /*
+                * for legacy and MSI interrupts don't set any bits
+                * that are enabled for EIAM, because this operation
+                * would set *both* EIMS and EICS for any bit in EIAM
+                */
+               IXGBE_WRITE_REG(hw, IXGBE_EICS,
+                       (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER));
+               goto watchdog_reschedule;
        }
 
+       /* get one bit for every active tx/rx interrupt vector */
+       for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) {
+               struct ixgbe_q_vector *qv = adapter->q_vector[i];
+               if (qv->rxr_count || qv->txr_count)
+                       eics |= ((u64)1 << i);
+       }
+
+       /* Cause software interrupt to ensure rx rings are cleaned */
+       ixgbe_irq_rearm_queues(adapter, eics);
+
+watchdog_reschedule:
+       /* Reset the timer */
+       mod_timer(&adapter->watchdog_timer, round_jiffies(jiffies + 2 * HZ));
+
+watchdog_short_circuit:
        schedule_work(&adapter->watchdog_task);
 }
 
@@ -4317,6 +4539,30 @@ static void ixgbe_sfp_config_module_task(struct work_struct *work)
 }
 
 /**
+ * ixgbe_fdir_reinit_task - worker thread to reinit FDIR filter table
+ * @work: pointer to work_struct containing our data
+ **/
+static void ixgbe_fdir_reinit_task(struct work_struct *work)
+{
+       struct ixgbe_adapter *adapter = container_of(work,
+                                                    struct ixgbe_adapter,
+                                                    fdir_reinit_task);
+       struct ixgbe_hw *hw = &adapter->hw;
+       int i;
+
+       if (ixgbe_reinit_fdir_tables_82599(hw) == 0) {
+               for (i = 0; i < adapter->num_tx_queues; i++)
+                       set_bit(__IXGBE_FDIR_INIT_DONE,
+                               &(adapter->tx_ring[i].reinit_state));
+       } else {
+               DPRINTK(PROBE, ERR, "failed to finish FDIR re-initialization, "
+                       "ignored adding FDIR ATR filters \n");
+       }
+       /* Done FDIR Re-initialization, enable transmits */
+       netif_tx_start_all_queues(adapter->netdev);
+}
+
+/**
  * ixgbe_watchdog_task - worker thread to bring link up
  * @work: pointer to work_struct containing our data
  **/
@@ -4341,12 +4587,12 @@ static void ixgbe_watchdog_task(struct work_struct *work)
 #ifdef CONFIG_DCB
                        if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
                                for (i = 0; i < MAX_TRAFFIC_CLASS; i++)
-                                       hw->mac.ops.setup_fc(hw, i);
+                                       hw->mac.ops.fc_enable(hw, i);
                        } else {
-                               hw->mac.ops.setup_fc(hw, 0);
+                               hw->mac.ops.fc_enable(hw, 0);
                        }
 #else
-                       hw->mac.ops.setup_fc(hw, 0);
+                       hw->mac.ops.fc_enable(hw, 0);
 #endif
                }
 
@@ -4623,7 +4869,7 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter,
                size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD);
 
                tx_buffer_info->length = size;
-               tx_buffer_info->dma = map[0] + offset;
+               tx_buffer_info->dma = skb_shinfo(skb)->dma_head + offset;
                tx_buffer_info->time_stamp = jiffies;
                tx_buffer_info->next_to_watch = i;
 
@@ -4655,7 +4901,7 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter,
                        size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD);
 
                        tx_buffer_info->length = size;
-                       tx_buffer_info->dma = map[f + 1] + offset;
+                       tx_buffer_info->dma = map[f] + offset;
                        tx_buffer_info->time_stamp = jiffies;
                        tx_buffer_info->next_to_watch = i;
 
@@ -4743,6 +4989,58 @@ static void ixgbe_tx_queue(struct ixgbe_adapter *adapter,
        writel(i, adapter->hw.hw_addr + tx_ring->tail);
 }
 
+static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb,
+                     int queue, u32 tx_flags)
+{
+       /* Right now, we support IPv4 only */
+       struct ixgbe_atr_input atr_input;
+       struct tcphdr *th;
+       struct udphdr *uh;
+       struct iphdr *iph = ip_hdr(skb);
+       struct ethhdr *eth = (struct ethhdr *)skb->data;
+       u16 vlan_id, src_port, dst_port, flex_bytes;
+       u32 src_ipv4_addr, dst_ipv4_addr;
+       u8 l4type = 0;
+
+       /* check if we're UDP or TCP */
+       if (iph->protocol == IPPROTO_TCP) {
+               th = tcp_hdr(skb);
+               src_port = th->source;
+               dst_port = th->dest;
+               l4type |= IXGBE_ATR_L4TYPE_TCP;
+               /* l4type IPv4 type is 0, no need to assign */
+       } else if(iph->protocol == IPPROTO_UDP) {
+               uh = udp_hdr(skb);
+               src_port = uh->source;
+               dst_port = uh->dest;
+               l4type |= IXGBE_ATR_L4TYPE_UDP;
+               /* l4type IPv4 type is 0, no need to assign */
+       } else {
+               /* Unsupported L4 header, just bail here */
+               return;
+       }
+
+       memset(&atr_input, 0, sizeof(struct ixgbe_atr_input));
+
+       vlan_id = (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK) >>
+                  IXGBE_TX_FLAGS_VLAN_SHIFT;
+       src_ipv4_addr = iph->saddr;
+       dst_ipv4_addr = iph->daddr;
+       flex_bytes = eth->h_proto;
+
+       ixgbe_atr_set_vlan_id_82599(&atr_input, vlan_id);
+       ixgbe_atr_set_src_port_82599(&atr_input, dst_port);
+       ixgbe_atr_set_dst_port_82599(&atr_input, src_port);
+       ixgbe_atr_set_flex_byte_82599(&atr_input, flex_bytes);
+       ixgbe_atr_set_l4type_82599(&atr_input, l4type);
+       /* src and dst are inverted, think how the receiver sees them */
+       ixgbe_atr_set_src_ipv4_82599(&atr_input, dst_ipv4_addr);
+       ixgbe_atr_set_dst_ipv4_82599(&atr_input, src_ipv4_addr);
+
+       /* This assumes the Rx queue and Tx queue are bound to the same CPU */
+       ixgbe_fdir_add_signature_filter_82599(&adapter->hw, &atr_input, queue);
+}
+
 static int __ixgbe_maybe_stop_tx(struct net_device *netdev,
                                  struct ixgbe_ring *tx_ring, int size)
 {
@@ -4777,6 +5075,9 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb)
 {
        struct ixgbe_adapter *adapter = netdev_priv(dev);
 
+       if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE)
+               return smp_processor_id();
+
        if (adapter->flags & IXGBE_FLAG_DCB_ENABLED)
                return 0;  /* All traffic should default to class 0 */
 
@@ -4861,9 +5162,19 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 
        count = ixgbe_tx_map(adapter, tx_ring, skb, tx_flags, first);
        if (count) {
+               /* add the ATR filter if ATR is on */
+               if (tx_ring->atr_sample_rate) {
+                       ++tx_ring->atr_count;
+                       if ((tx_ring->atr_count >= tx_ring->atr_sample_rate) &&
+                            test_bit(__IXGBE_FDIR_INIT_DONE,
+                                      &tx_ring->reinit_state)) {
+                               ixgbe_atr(adapter, skb, tx_ring->queue_index,
+                                         tx_flags);
+                               tx_ring->atr_count = 0;
+                       }
+               }
                ixgbe_tx_queue(adapter, tx_ring, tx_flags, count, skb->len,
                               hdr_len);
-               netdev->trans_start = jiffies;
                ixgbe_maybe_stop_tx(netdev, tx_ring, DESC_NEEDED);
 
        } else {
@@ -5244,6 +5555,12 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
                                netdev->features |= NETIF_F_FCOE_CRC;
                                netdev->features |= NETIF_F_FSO;
                                netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1;
+                               DPRINTK(DRV, INFO, "FCoE enabled, "
+                                       "disabling Flow Director\n");
+                               adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE;
+                               adapter->flags &=
+                                       ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
+                               adapter->atr_sample_rate = 0;
                        } else {
                                adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED;
                        }
@@ -5253,7 +5570,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
        if (pci_using_dac)
                netdev->features |= NETIF_F_HIGHDMA;
 
-       if (adapter->flags & IXGBE_FLAG_RSC_ENABLED)
+       if (adapter->flags & IXGBE_FLAG2_RSC_ENABLED)
                netdev->features |= NETIF_F_LRO;
 
        /* make sure the EEPROM is good */
@@ -5287,6 +5604,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
        case IXGBE_DEV_ID_82599_KX4:
                adapter->wol = (IXGBE_WUFC_MAG | IXGBE_WUFC_EX |
                                IXGBE_WUFC_MC | IXGBE_WUFC_BC);
+               /* Enable ACPI wakeup in GRC */
+               IXGBE_WRITE_REG(hw, IXGBE_GRC,
+                            (IXGBE_READ_REG(hw, IXGBE_GRC) & ~IXGBE_GRC_APME));
                break;
        default:
                adapter->wol = 0;
@@ -5329,8 +5649,17 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
        hw->eeprom.ops.read(hw, 0x29, &adapter->eeprom_version);
 
        /* reset the hardware with the new settings */
-       hw->mac.ops.start_hw(hw);
+       err = hw->mac.ops.start_hw(hw);
 
+       if (err == IXGBE_ERR_EEPROM_VERSION) {
+               /* We are running on a pre-production device, log a warning */
+               dev_warn(&pdev->dev, "This device is a pre-production "
+                        "adapter/LOM.  Please be aware there may be issues "
+                        "associated with your hardware.  If you are "
+                        "experiencing problems please contact your Intel or "
+                        "hardware representative who provided you with this "
+                        "hardware.\n");
+       }
        strcpy(netdev->name, "eth%d");
        err = register_netdev(netdev);
        if (err)
@@ -5339,6 +5668,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
        /* carrier off reporting is important to ethtool even BEFORE open */
        netif_carrier_off(netdev);
 
+       if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE ||
+           adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
+               INIT_WORK(&adapter->fdir_reinit_task, ixgbe_fdir_reinit_task);
+
 #ifdef CONFIG_IXGBE_DCA
        if (dca_add_requester(&pdev->dev) == 0) {
                adapter->flags |= IXGBE_FLAG_DCA_ENABLED;
@@ -5401,6 +5734,9 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
        cancel_work_sync(&adapter->sfp_task);
        cancel_work_sync(&adapter->multispeed_fiber_task);
        cancel_work_sync(&adapter->sfp_config_module_task);
+       if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE ||
+           adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
+               cancel_work_sync(&adapter->fdir_reinit_task);
        flush_scheduled_work();
 
 #ifdef CONFIG_IXGBE_DCA
index e43d624..453e966 100644 (file)
@@ -606,6 +606,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
                        hw->phy.sfp_setup_needed = true;
 
                /* Determine if the SFP+ PHY is dual speed or not. */
+               hw->phy.multispeed_fiber = false;
                if (((comp_codes_1g & IXGBE_SFF_1GBASESX_CAPABLE) &&
                   (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)) ||
                   ((comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) &&
index df1f703..fa87309 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <linux/types.h>
 #include <linux/mdio.h>
+#include <linux/list.h>
 
 /* Vendor ID */
 #define IXGBE_INTEL_VENDOR_ID   0x8086
 #define IXGBE_RETA(_i)  (0x05C00 + ((_i) * 4))  /* 32 of these (0-31) */
 #define IXGBE_RSSRK(_i) (0x05C80 + ((_i) * 4))  /* 10 of these (0-9) */
 
+/* Flow Director registers */
+#define IXGBE_FDIRCTRL  0x0EE00
+#define IXGBE_FDIRHKEY  0x0EE68
+#define IXGBE_FDIRSKEY  0x0EE6C
+#define IXGBE_FDIRDIP4M 0x0EE3C
+#define IXGBE_FDIRSIP4M 0x0EE40
+#define IXGBE_FDIRTCPM  0x0EE44
+#define IXGBE_FDIRUDPM  0x0EE48
+#define IXGBE_FDIRIP6M  0x0EE74
+#define IXGBE_FDIRM     0x0EE70
+
+/* Flow Director Stats registers */
+#define IXGBE_FDIRFREE  0x0EE38
+#define IXGBE_FDIRLEN   0x0EE4C
+#define IXGBE_FDIRUSTAT 0x0EE50
+#define IXGBE_FDIRFSTAT 0x0EE54
+#define IXGBE_FDIRMATCH 0x0EE58
+#define IXGBE_FDIRMISS  0x0EE5C
+
+/* Flow Director Programming registers */
+#define IXGBE_FDIRSIPv6(_i) (0x0EE0C + ((_i) * 4)) /* 3 of these (0-2) */
+#define IXGBE_FDIRIPSA      0x0EE18
+#define IXGBE_FDIRIPDA      0x0EE1C
+#define IXGBE_FDIRPORT      0x0EE20
+#define IXGBE_FDIRVLAN      0x0EE24
+#define IXGBE_FDIRHASH      0x0EE28
+#define IXGBE_FDIRCMD       0x0EE2C
+
 /* Transmit DMA registers */
 #define IXGBE_TDBAL(_i) (0x06000 + ((_i) * 0x40)) /* 32 of these (0-31)*/
 #define IXGBE_TDBAH(_i) (0x06004 + ((_i) * 0x40))
 #define IXGBE_STATUS_LAN_ID_1   0x00000004 /* LAN ID 1 */
 
 /* ESDP Bit Masks */
-#define IXGBE_ESDP_SDP0 0x00000001
-#define IXGBE_ESDP_SDP1 0x00000002
+#define IXGBE_ESDP_SDP0 0x00000001 /* SDP0 Data Value */
+#define IXGBE_ESDP_SDP1 0x00000002 /* SDP1 Data Value */
+#define IXGBE_ESDP_SDP2 0x00000004 /* SDP2 Data Value */
+#define IXGBE_ESDP_SDP3 0x00000008 /* SDP3 Data Value */
 #define IXGBE_ESDP_SDP4 0x00000010 /* SDP4 Data Value */
 #define IXGBE_ESDP_SDP5 0x00000020 /* SDP5 Data Value */
 #define IXGBE_ESDP_SDP6 0x00000040 /* SDP6 Data Value */
 #define IXGBE_LINK_UP_TIME      90 /* 9.0 Seconds */
 #define IXGBE_AUTO_NEG_TIME     45 /* 4.5 Seconds */
 
-#define FIBER_LINK_UP_LIMIT     50
-
 /* PCS1GLSTA Bit Masks */
 #define IXGBE_PCS1GLSTA_LINK_OK         1
 #define IXGBE_PCS1GLSTA_SYNK_OK         0x10
 #define IXGBE_SAN_MAC_ADDR_PORT1_OFFSET  0x3
 #define IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP  0x1
 #define IXGBE_DEVICE_CAPS_FCOE_OFFLOADS  0x2
+#define IXGBE_FW_PASSTHROUGH_PATCH_CONFIG_PTR   0x4
+#define IXGBE_FW_PATCH_VERSION_4   0x7
 
 /* PCI Bus Info */
 #define IXGBE_PCI_LINK_STATUS     0xB2
 #define IXGBE_RXDADV_ERR_SHIFT          20         /* RDESC.ERRORS shift */
 #define IXGBE_RXDADV_ERR_FCEOFE         0x80000000 /* FCoEFe/IPE */
 #define IXGBE_RXDADV_ERR_FCERR          0x00700000 /* FCERR/FDIRERR */
+#define IXGBE_RXDADV_ERR_FDIR_LEN       0x00100000 /* FDIR Length error */
+#define IXGBE_RXDADV_ERR_FDIR_DROP      0x00200000 /* FDIR Drop error */
+#define IXGBE_RXDADV_ERR_FDIR_COLL      0x00400000 /* FDIR Collision error */
 #define IXGBE_RXDADV_ERR_HBO    0x00800000 /*Header Buffer Overflow */
 #define IXGBE_RXDADV_ERR_CE     0x01000000 /* CRC Error */
 #define IXGBE_RXDADV_ERR_LE     0x02000000 /* Length Error */
 
 #endif
 
+enum ixgbe_fdir_pballoc_type {
+       IXGBE_FDIR_PBALLOC_64K = 0,
+       IXGBE_FDIR_PBALLOC_128K,
+       IXGBE_FDIR_PBALLOC_256K,
+};
+#define IXGBE_FDIR_PBALLOC_SIZE_SHIFT           16
+
+/* Flow Director register values */
+#define IXGBE_FDIRCTRL_PBALLOC_64K              0x00000001
+#define IXGBE_FDIRCTRL_PBALLOC_128K             0x00000002
+#define IXGBE_FDIRCTRL_PBALLOC_256K             0x00000003
+#define IXGBE_FDIRCTRL_INIT_DONE                0x00000008
+#define IXGBE_FDIRCTRL_PERFECT_MATCH            0x00000010
+#define IXGBE_FDIRCTRL_REPORT_STATUS            0x00000020
+#define IXGBE_FDIRCTRL_REPORT_STATUS_ALWAYS     0x00000080
+#define IXGBE_FDIRCTRL_DROP_Q_SHIFT             8
+#define IXGBE_FDIRCTRL_FLEX_SHIFT               16
+#define IXGBE_FDIRCTRL_SEARCHLIM                0x00800000
+#define IXGBE_FDIRCTRL_MAX_LENGTH_SHIFT         24
+#define IXGBE_FDIRCTRL_FULL_THRESH_MASK         0xF0000000
+#define IXGBE_FDIRCTRL_FULL_THRESH_SHIFT        28
+
+#define IXGBE_FDIRTCPM_DPORTM_SHIFT             16
+#define IXGBE_FDIRUDPM_DPORTM_SHIFT             16
+#define IXGBE_FDIRIP6M_DIPM_SHIFT               16
+#define IXGBE_FDIRM_VLANID                      0x00000001
+#define IXGBE_FDIRM_VLANP                       0x00000002
+#define IXGBE_FDIRM_POOL                        0x00000004
+#define IXGBE_FDIRM_L3P                         0x00000008
+#define IXGBE_FDIRM_L4P                         0x00000010
+#define IXGBE_FDIRM_FLEX                        0x00000020
+#define IXGBE_FDIRM_DIPv6                       0x00000040
+
+#define IXGBE_FDIRFREE_FREE_MASK                0xFFFF
+#define IXGBE_FDIRFREE_FREE_SHIFT               0
+#define IXGBE_FDIRFREE_COLL_MASK                0x7FFF0000
+#define IXGBE_FDIRFREE_COLL_SHIFT               16
+#define IXGBE_FDIRLEN_MAXLEN_MASK               0x3F
+#define IXGBE_FDIRLEN_MAXLEN_SHIFT              0
+#define IXGBE_FDIRLEN_MAXHASH_MASK              0x7FFF0000
+#define IXGBE_FDIRLEN_MAXHASH_SHIFT             16
+#define IXGBE_FDIRUSTAT_ADD_MASK                0xFFFF
+#define IXGBE_FDIRUSTAT_ADD_SHIFT               0
+#define IXGBE_FDIRUSTAT_REMOVE_MASK             0xFFFF0000
+#define IXGBE_FDIRUSTAT_REMOVE_SHIFT            16
+#define IXGBE_FDIRFSTAT_FADD_MASK               0x00FF
+#define IXGBE_FDIRFSTAT_FADD_SHIFT              0
+#define IXGBE_FDIRFSTAT_FREMOVE_MASK            0xFF00
+#define IXGBE_FDIRFSTAT_FREMOVE_SHIFT           8
+#define IXGBE_FDIRPORT_DESTINATION_SHIFT        16
+#define IXGBE_FDIRVLAN_FLEX_SHIFT               16
+#define IXGBE_FDIRHASH_BUCKET_VALID_SHIFT       15
+#define IXGBE_FDIRHASH_SIG_SW_INDEX_SHIFT       16
+
+#define IXGBE_FDIRCMD_CMD_MASK                  0x00000003
+#define IXGBE_FDIRCMD_CMD_ADD_FLOW              0x00000001
+#define IXGBE_FDIRCMD_CMD_REMOVE_FLOW           0x00000002
+#define IXGBE_FDIRCMD_CMD_QUERY_REM_FILT        0x00000003
+#define IXGBE_FDIRCMD_CMD_QUERY_REM_HASH        0x00000007
+#define IXGBE_FDIRCMD_FILTER_UPDATE             0x00000008
+#define IXGBE_FDIRCMD_IPv6DMATCH                0x00000010
+#define IXGBE_FDIRCMD_L4TYPE_UDP                0x00000020
+#define IXGBE_FDIRCMD_L4TYPE_TCP                0x00000040
+#define IXGBE_FDIRCMD_L4TYPE_SCTP               0x00000060
+#define IXGBE_FDIRCMD_IPV6                      0x00000080
+#define IXGBE_FDIRCMD_CLEARHT                   0x00000100
+#define IXGBE_FDIRCMD_DROP                      0x00000200
+#define IXGBE_FDIRCMD_INT                       0x00000400
+#define IXGBE_FDIRCMD_LAST                      0x00000800
+#define IXGBE_FDIRCMD_COLLISION                 0x00001000
+#define IXGBE_FDIRCMD_QUEUE_EN                  0x00008000
+#define IXGBE_FDIRCMD_RX_QUEUE_SHIFT            16
+#define IXGBE_FDIRCMD_VT_POOL_SHIFT             24
+#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 */
@@ -1956,6 +2066,45 @@ typedef u32 ixgbe_physical_layer;
 #define IXGBE_PHYSICAL_LAYER_10GBASE_KR   0x0800
 #define IXGBE_PHYSICAL_LAYER_10GBASE_XAUI 0x1000
 
+/* Software ATR hash keys */
+#define IXGBE_ATR_BUCKET_HASH_KEY    0xE214AD3D
+#define IXGBE_ATR_SIGNATURE_HASH_KEY 0x14364D17
+
+/* Software ATR input stream offsets and masks */
+#define IXGBE_ATR_VLAN_OFFSET       0
+#define IXGBE_ATR_SRC_IPV6_OFFSET   2
+#define IXGBE_ATR_SRC_IPV4_OFFSET  14
+#define IXGBE_ATR_DST_IPV6_OFFSET  18
+#define IXGBE_ATR_DST_IPV4_OFFSET  30
+#define IXGBE_ATR_SRC_PORT_OFFSET  34
+#define IXGBE_ATR_DST_PORT_OFFSET  36
+#define IXGBE_ATR_FLEX_BYTE_OFFSET 38
+#define IXGBE_ATR_VM_POOL_OFFSET   40
+#define IXGBE_ATR_L4TYPE_OFFSET    41
+
+#define IXGBE_ATR_L4TYPE_MASK      0x3
+#define IXGBE_ATR_L4TYPE_IPV6_MASK 0x4
+#define IXGBE_ATR_L4TYPE_UDP       0x1
+#define IXGBE_ATR_L4TYPE_TCP       0x2
+#define IXGBE_ATR_L4TYPE_SCTP      0x3
+#define IXGBE_ATR_HASH_MASK     0x7fff
+
+/* Flow Director ATR input struct. */
+struct ixgbe_atr_input {
+       /* Byte layout in order, all values with MSB first:
+        *
+        * vlan_id    - 2 bytes
+        * src_ip     - 16 bytes
+        * dst_ip     - 16 bytes
+        * src_port   - 2 bytes
+        * dst_port   - 2 bytes
+        * flex_bytes - 2 bytes
+        * vm_pool    - 1 byte
+        * l4type     - 1 byte
+        */
+       u8 byte_stream[42];
+};
+
 enum ixgbe_eeprom_type {
        ixgbe_eeprom_uninitialized = 0,
        ixgbe_eeprom_spi,
@@ -2091,7 +2240,8 @@ struct ixgbe_fc_info {
        u16 pause_time; /* Flow Control Pause timer */
        bool send_xon; /* Flow control send XON */
        bool strict_ieee; /* Strict IEEE mode */
-       bool disable_fc_autoneg; /* Turn off autoneg FC mode */
+       bool disable_fc_autoneg; /* Do not autonegotiate FC */
+       bool fc_was_autonegged; /* Is current_mode the result of autonegging? */
        enum ixgbe_fc_mode current_mode; /* FC mode in effect */
        enum ixgbe_fc_mode requested_mode; /* FC mode requested by caller */
 };
@@ -2223,8 +2373,7 @@ struct ixgbe_mac_operations {
        s32 (*set_vmdq)(struct ixgbe_hw *, u32, u32);
        s32 (*clear_vmdq)(struct ixgbe_hw *, u32, u32);
        s32 (*init_rx_addrs)(struct ixgbe_hw *);
-       s32 (*update_uc_addr_list)(struct ixgbe_hw *, u8 *, u32,
-                                  ixgbe_mc_addr_itr);
+       s32 (*update_uc_addr_list)(struct ixgbe_hw *, struct list_head *);
        s32 (*update_mc_addr_list)(struct ixgbe_hw *, u8 *, u32,
                                   ixgbe_mc_addr_itr);
        s32 (*enable_mc)(struct ixgbe_hw *);
@@ -2234,7 +2383,7 @@ struct ixgbe_mac_operations {
        s32 (*init_uta_tables)(struct ixgbe_hw *);
 
        /* Flow Control */
-       s32 (*setup_fc)(struct ixgbe_hw *, s32);
+       s32 (*fc_enable)(struct ixgbe_hw *, s32);
 };
 
 struct ixgbe_phy_operations {
@@ -2281,6 +2430,7 @@ struct ixgbe_mac_info {
        bool                            orig_link_settings_stored;
        bool                            autoneg;
        bool                            autoneg_succeeded;
+       bool                            autotry_restart;
 };
 
 struct ixgbe_phy_info {
@@ -2346,6 +2496,8 @@ struct ixgbe_info {
 #define IXGBE_ERR_SFP_NOT_SUPPORTED             -19
 #define IXGBE_ERR_SFP_NOT_PRESENT               -20
 #define IXGBE_ERR_SFP_NO_INIT_SEQ_PRESENT       -21
+#define IXGBE_ERR_FDIR_REINIT_FAILED            -23
+#define IXGBE_ERR_EEPROM_VERSION                -24
 #define IXGBE_NOT_IMPLEMENTED                   0x7FFFFFFF
 
 #endif /* _IXGBE_TYPE_H_ */
index 621a7c0..1e3c63d 100644 (file)
@@ -1939,7 +1939,6 @@ jme_start_xmit(struct sk_buff *skb, struct net_device *netdev)
                                TXCS_SELECT_QUEUE0 |
                                TXCS_QUEUE0S |
                                TXCS_ENABLE);
-       netdev->trans_start = jiffies;
 
        tx_dbg(jme, "xmit: %d+%d@%lu\n", idx,
                        skb_shinfo(skb)->nr_frags + 2,
index dc23856..b4cf602 100644 (file)
@@ -133,6 +133,7 @@ struct korina_private {
        int dma_halt_cnt;
        int dma_run_cnt;
        struct napi_struct napi;
+       struct timer_list media_check_timer;
        struct mii_if_info mii_if;
        struct net_device *dev;
        int phy_addr;
@@ -664,6 +665,15 @@ static void korina_check_media(struct net_device *dev, unsigned int init_media)
                                                &lp->eth_regs->ethmac2);
 }
 
+static void korina_poll_media(unsigned long data)
+{
+       struct net_device *dev = (struct net_device *) data;
+       struct korina_private *lp = netdev_priv(dev);
+
+       korina_check_media(dev, 0);
+       mod_timer(&lp->media_check_timer, jiffies + HZ);
+}
+
 static void korina_set_carrier(struct mii_if_info *mii)
 {
        if (mii->force_media) {
@@ -1034,6 +1044,7 @@ static int korina_open(struct net_device *dev)
                    dev->name, lp->und_irq);
                goto err_free_ovr_irq;
        }
+       mod_timer(&lp->media_check_timer, jiffies + 1);
 out:
        return ret;
 
@@ -1053,6 +1064,8 @@ static int korina_close(struct net_device *dev)
        struct korina_private *lp = netdev_priv(dev);
        u32 tmp;
 
+       del_timer(&lp->media_check_timer);
+
        /* Disable interrupts */
        disable_irq(lp->rx_irq);
        disable_irq(lp->tx_irq);
@@ -1183,6 +1196,7 @@ static int korina_probe(struct platform_device *pdev)
                        ": cannot register net device %d\n", rc);
                goto probe_err_register;
        }
+       setup_timer(&lp->media_check_timer, korina_poll_media, (unsigned long) dev);
 out:
        return rc;
 
diff --git a/drivers/net/ks8842.c b/drivers/net/ks8842.c
new file mode 100644 (file)
index 0000000..39b0aea
--- /dev/null
@@ -0,0 +1,732 @@
+/*
+ * ks8842_main.c timberdale KS8842 ethernet driver
+ * Copyright (c) 2009 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Supports:
+ * The Micrel KS8842 behind the timberdale FPGA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+
+#define DRV_NAME "ks8842"
+
+/* Timberdale specific Registers */
+#define REG_TIMB_RST   0x1c
+
+/* KS8842 registers */
+
+#define REG_SELECT_BANK 0x0e
+
+/* bank 0 registers */
+#define REG_QRFCR      0x04
+
+/* bank 2 registers */
+#define REG_MARL       0x00
+#define REG_MARM       0x02
+#define REG_MARH       0x04
+
+/* bank 3 registers */
+#define REG_GRR                0x06
+
+/* bank 16 registers */
+#define REG_TXCR       0x00
+#define REG_TXSR       0x02
+#define REG_RXCR       0x04
+#define REG_TXMIR      0x08
+#define REG_RXMIR      0x0A
+
+/* bank 17 registers */
+#define REG_TXQCR      0x00
+#define REG_RXQCR      0x02
+#define REG_TXFDPR     0x04
+#define REG_RXFDPR     0x06
+#define REG_QMU_DATA_LO 0x08
+#define REG_QMU_DATA_HI 0x0A
+
+/* bank 18 registers */
+#define REG_IER                0x00
+#define IRQ_LINK_CHANGE        0x8000
+#define IRQ_TX         0x4000
+#define IRQ_RX         0x2000
+#define IRQ_RX_OVERRUN 0x0800
+#define IRQ_TX_STOPPED 0x0200
+#define IRQ_RX_STOPPED 0x0100
+#define IRQ_RX_ERROR   0x0080
+#define ENABLED_IRQS   (IRQ_LINK_CHANGE | IRQ_TX | IRQ_RX | IRQ_RX_STOPPED | \
+               IRQ_TX_STOPPED | IRQ_RX_OVERRUN | IRQ_RX_ERROR)
+#define REG_ISR                0x02
+#define REG_RXSR       0x04
+#define RXSR_VALID     0x8000
+#define RXSR_BROADCAST 0x80
+#define RXSR_MULTICAST 0x40
+#define RXSR_UNICAST   0x20
+#define RXSR_FRAMETYPE 0x08
+#define RXSR_TOO_LONG  0x04
+#define RXSR_RUNT      0x02
+#define RXSR_CRC_ERROR 0x01
+#define RXSR_ERROR     (RXSR_TOO_LONG | RXSR_RUNT | RXSR_CRC_ERROR)
+
+/* bank 32 registers */
+#define REG_SW_ID_AND_ENABLE   0x00
+#define REG_SGCR1              0x02
+#define REG_SGCR2              0x04
+#define REG_SGCR3              0x06
+
+/* bank 39 registers */
+#define REG_MACAR1             0x00
+#define REG_MACAR2             0x02
+#define REG_MACAR3             0x04
+
+/* bank 45 registers */
+#define REG_P1MBCR             0x00
+#define REG_P1MBSR             0x02
+
+/* bank 46 registers */
+#define REG_P2MBCR             0x00
+#define REG_P2MBSR             0x02
+
+/* bank 48 registers */
+#define REG_P1CR2              0x02
+
+/* bank 49 registers */
+#define REG_P1CR4              0x02
+#define REG_P1SR               0x04
+
+struct ks8842_adapter {
+       void __iomem    *hw_addr;
+       int             irq;
+       struct tasklet_struct   tasklet;
+       spinlock_t      lock; /* spinlock to be interrupt safe */
+       struct platform_device *pdev;
+};
+
+static inline void ks8842_select_bank(struct ks8842_adapter *adapter, u16 bank)
+{
+       iowrite16(bank, adapter->hw_addr + REG_SELECT_BANK);
+}
+
+static inline void ks8842_write8(struct ks8842_adapter *adapter, u16 bank,
+       u8 value, int offset)
+{
+       ks8842_select_bank(adapter, bank);
+       iowrite8(value, adapter->hw_addr + offset);
+}
+
+static inline void ks8842_write16(struct ks8842_adapter *adapter, u16 bank,
+       u16 value, int offset)
+{
+       ks8842_select_bank(adapter, bank);
+       iowrite16(value, adapter->hw_addr + offset);
+}
+
+static inline void ks8842_enable_bits(struct ks8842_adapter *adapter, u16 bank,
+       u16 bits, int offset)
+{
+       u16 reg;
+       ks8842_select_bank(adapter, bank);
+       reg = ioread16(adapter->hw_addr + offset);
+       reg |= bits;
+       iowrite16(reg, adapter->hw_addr + offset);
+}
+
+static inline void ks8842_clear_bits(struct ks8842_adapter *adapter, u16 bank,
+       u16 bits, int offset)
+{
+       u16 reg;
+       ks8842_select_bank(adapter, bank);
+       reg = ioread16(adapter->hw_addr + offset);
+       reg &= ~bits;
+       iowrite16(reg, adapter->hw_addr + offset);
+}
+
+static inline void ks8842_write32(struct ks8842_adapter *adapter, u16 bank,
+       u32 value, int offset)
+{
+       ks8842_select_bank(adapter, bank);
+       iowrite32(value, adapter->hw_addr + offset);
+}
+
+static inline u8 ks8842_read8(struct ks8842_adapter *adapter, u16 bank,
+       int offset)
+{
+       ks8842_select_bank(adapter, bank);
+       return ioread8(adapter->hw_addr + offset);
+}
+
+static inline u16 ks8842_read16(struct ks8842_adapter *adapter, u16 bank,
+       int offset)
+{
+       ks8842_select_bank(adapter, bank);
+       return ioread16(adapter->hw_addr + offset);
+}
+
+static inline u32 ks8842_read32(struct ks8842_adapter *adapter, u16 bank,
+       int offset)
+{
+       ks8842_select_bank(adapter, bank);
+       return ioread32(adapter->hw_addr + offset);
+}
+
+static void ks8842_reset(struct ks8842_adapter *adapter)
+{
+       /* The KS8842 goes haywire when doing softare reset
+        * a work around in the timberdale IP is implemented to
+        * do a hardware reset instead
+       ks8842_write16(adapter, 3, 1, REG_GRR);
+       msleep(10);
+       iowrite16(0, adapter->hw_addr + REG_GRR);
+       */
+       iowrite16(32, adapter->hw_addr + REG_SELECT_BANK);
+       iowrite32(0x1, adapter->hw_addr + REG_TIMB_RST);
+       msleep(20);
+}
+
+static void ks8842_update_link_status(struct net_device *netdev,
+       struct ks8842_adapter *adapter)
+{
+       /* check the status of the link */
+       if (ks8842_read16(adapter, 45, REG_P1MBSR) & 0x4) {
+               netif_carrier_on(netdev);
+               netif_wake_queue(netdev);
+       } else {
+               netif_stop_queue(netdev);
+               netif_carrier_off(netdev);
+       }
+}
+
+static void ks8842_enable_tx(struct ks8842_adapter *adapter)
+{
+       ks8842_enable_bits(adapter, 16, 0x01, REG_TXCR);
+}
+
+static void ks8842_disable_tx(struct ks8842_adapter *adapter)
+{
+       ks8842_clear_bits(adapter, 16, 0x01, REG_TXCR);
+}
+
+static void ks8842_enable_rx(struct ks8842_adapter *adapter)
+{
+       ks8842_enable_bits(adapter, 16, 0x01, REG_RXCR);
+}
+
+static void ks8842_disable_rx(struct ks8842_adapter *adapter)
+{
+       ks8842_clear_bits(adapter, 16, 0x01, REG_RXCR);
+}
+
+static void ks8842_reset_hw(struct ks8842_adapter *adapter)
+{
+       /* reset the HW */
+       ks8842_reset(adapter);
+
+       /* Enable QMU Transmit flow control / transmit padding / Transmit CRC */
+       ks8842_write16(adapter, 16, 0x000E, REG_TXCR);
+
+       /* enable the receiver, uni + multi + broadcast + flow ctrl
+               + crc strip */
+       ks8842_write16(adapter, 16, 0x8 | 0x20 | 0x40 | 0x80 | 0x400,
+               REG_RXCR);
+
+       /* TX frame pointer autoincrement */
+       ks8842_write16(adapter, 17, 0x4000, REG_TXFDPR);
+
+       /* RX frame pointer autoincrement */
+       ks8842_write16(adapter, 17, 0x4000, REG_RXFDPR);
+
+       /* RX 2 kb high watermark */
+       ks8842_write16(adapter, 0, 0x1000, REG_QRFCR);
+
+       /* aggresive back off in half duplex */
+       ks8842_enable_bits(adapter, 32, 1 << 8, REG_SGCR1);
+
+       /* enable no excessive collison drop */
+       ks8842_enable_bits(adapter, 32, 1 << 3, REG_SGCR2);
+
+       /* Enable port 1 force flow control / back pressure / transmit / recv */
+       ks8842_write16(adapter, 48, 0x1E07, REG_P1CR2);
+
+       /* restart port auto-negotiation */
+       ks8842_enable_bits(adapter, 49, 1 << 13, REG_P1CR4);
+       /* only advertise 10Mbps */
+       ks8842_clear_bits(adapter, 49, 3 << 2, REG_P1CR4);
+
+       /* Enable the transmitter */
+       ks8842_enable_tx(adapter);
+
+       /* Enable the receiver */
+       ks8842_enable_rx(adapter);
+
+       /* clear all interrupts */
+       ks8842_write16(adapter, 18, 0xffff, REG_ISR);
+
+       /* enable interrupts */
+       ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER);
+
+       /* enable the switch */
+       ks8842_write16(adapter, 32, 0x1, REG_SW_ID_AND_ENABLE);
+}
+
+static void ks8842_read_mac_addr(struct ks8842_adapter *adapter, u8 *dest)
+{
+       int i;
+       u16 mac;
+
+       for (i = 0; i < ETH_ALEN; i++)
+               dest[ETH_ALEN - i - 1] = ks8842_read8(adapter, 2, REG_MARL + i);
+
+       /* make sure the switch port uses the same MAC as the QMU */
+       mac = ks8842_read16(adapter, 2, REG_MARL);
+       ks8842_write16(adapter, 39, mac, REG_MACAR1);
+       mac = ks8842_read16(adapter, 2, REG_MARM);
+       ks8842_write16(adapter, 39, mac, REG_MACAR2);
+       mac = ks8842_read16(adapter, 2, REG_MARH);
+       ks8842_write16(adapter, 39, mac, REG_MACAR3);
+}
+
+static inline u16 ks8842_tx_fifo_space(struct ks8842_adapter *adapter)
+{
+       return ks8842_read16(adapter, 16, REG_TXMIR) & 0x1fff;
+}
+
+static int ks8842_tx_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+       struct ks8842_adapter *adapter = netdev_priv(netdev);
+       int len = skb->len;
+       u32 *ptr = (u32 *)skb->data;
+       u32 ctrl;
+
+       dev_dbg(&adapter->pdev->dev,
+               "%s: len %u head %p data %p tail %p end %p\n",
+               __func__, skb->len, skb->head, skb->data,
+               skb_tail_pointer(skb), skb_end_pointer(skb));
+
+       /* check FIFO buffer space, we need space for CRC and command bits */
+       if (ks8842_tx_fifo_space(adapter) < len + 8)
+               return NETDEV_TX_BUSY;
+
+       /* the control word, enable IRQ, port 1 and the length */
+       ctrl = 0x8000 | 0x100 | (len << 16);
+       ks8842_write32(adapter, 17, ctrl, REG_QMU_DATA_LO);
+
+       netdev->stats.tx_bytes += len;
+
+       /* copy buffer */
+       while (len > 0) {
+               iowrite32(*ptr, adapter->hw_addr + REG_QMU_DATA_LO);
+               len -= sizeof(u32);
+               ptr++;
+       }
+
+       /* enqueue packet */
+       ks8842_write16(adapter, 17, 1, REG_TXQCR);
+
+       dev_kfree_skb(skb);
+
+       return NETDEV_TX_OK;
+}
+
+static void ks8842_rx_frame(struct net_device *netdev,
+       struct ks8842_adapter *adapter)
+{
+       u32 status = ks8842_read32(adapter, 17, REG_QMU_DATA_LO);
+       int len = (status >> 16) & 0x7ff;
+
+       status &= 0xffff;
+
+       dev_dbg(&adapter->pdev->dev, "%s - rx_data: status: %x\n",
+               __func__, status);
+
+       /* check the status */
+       if ((status & RXSR_VALID) && !(status & RXSR_ERROR)) {
+               struct sk_buff *skb = netdev_alloc_skb(netdev, len + 2);
+
+               dev_dbg(&adapter->pdev->dev, "%s, got package, len: %d\n",
+                       __func__, len);
+               if (skb) {
+                       u32 *data;
+
+                       netdev->stats.rx_packets++;
+                       netdev->stats.rx_bytes += len;
+                       if (status & RXSR_MULTICAST)
+                               netdev->stats.multicast++;
+
+                       /* Align socket buffer in 4-byte boundary for
+                                better performance. */
+                       skb_reserve(skb, 2);
+                       data = (u32 *)skb_put(skb, len);
+
+                       ks8842_select_bank(adapter, 17);
+                       while (len > 0) {
+                               *data++ = ioread32(adapter->hw_addr +
+                                       REG_QMU_DATA_LO);
+                               len -= sizeof(u32);
+                       }
+
+                       skb->protocol = eth_type_trans(skb, netdev);
+                       netif_rx(skb);
+               } else
+                       netdev->stats.rx_dropped++;
+       } else {
+               dev_dbg(&adapter->pdev->dev, "RX error, status: %x\n", status);
+               netdev->stats.rx_errors++;
+               if (status & RXSR_TOO_LONG)
+                       netdev->stats.rx_length_errors++;
+               if (status & RXSR_CRC_ERROR)
+                       netdev->stats.rx_crc_errors++;
+               if (status & RXSR_RUNT)
+                       netdev->stats.rx_frame_errors++;
+       }
+
+       /* set high watermark to 3K */
+       ks8842_clear_bits(adapter, 0, 1 << 12, REG_QRFCR);
+
+       /* release the frame */
+       ks8842_write16(adapter, 17, 0x01, REG_RXQCR);
+
+       /* set high watermark to 2K */
+       ks8842_enable_bits(adapter, 0, 1 << 12, REG_QRFCR);
+}
+
+void ks8842_handle_rx(struct net_device *netdev, struct ks8842_adapter *adapter)
+{
+       u16 rx_data = ks8842_read16(adapter, 16, REG_RXMIR) & 0x1fff;
+       dev_dbg(&adapter->pdev->dev, "%s Entry - rx_data: %d\n",
+               __func__, rx_data);
+       while (rx_data) {
+               ks8842_rx_frame(netdev, adapter);
+               rx_data = ks8842_read16(adapter, 16, REG_RXMIR) & 0x1fff;
+       }
+}
+
+void ks8842_handle_tx(struct net_device *netdev, struct ks8842_adapter *adapter)
+{
+       u16 sr = ks8842_read16(adapter, 16, REG_TXSR);
+       dev_dbg(&adapter->pdev->dev, "%s - entry, sr: %x\n", __func__, sr);
+       netdev->stats.tx_packets++;
+       if (netif_queue_stopped(netdev))
+               netif_wake_queue(netdev);
+}
+
+void ks8842_handle_rx_overrun(struct net_device *netdev,
+       struct ks8842_adapter *adapter)
+{
+       dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__);
+       netdev->stats.rx_errors++;
+       netdev->stats.rx_fifo_errors++;
+}
+
+void ks8842_tasklet(unsigned long arg)
+{
+       struct net_device *netdev = (struct net_device *)arg;
+       struct ks8842_adapter *adapter = netdev_priv(netdev);
+       u16 isr;
+       unsigned long flags;
+       u16 entry_bank;
+
+       /* read current bank to be able to set it back */
+       spin_lock_irqsave(&adapter->lock, flags);
+       entry_bank = ioread16(adapter->hw_addr + REG_SELECT_BANK);
+       spin_unlock_irqrestore(&adapter->lock, flags);
+
+       isr = ks8842_read16(adapter, 18, REG_ISR);
+       dev_dbg(&adapter->pdev->dev, "%s - ISR: 0x%x\n", __func__, isr);
+
+       /* Ack */
+       ks8842_write16(adapter, 18, isr, REG_ISR);
+
+       if (!netif_running(netdev))
+               return;
+
+       if (isr & IRQ_LINK_CHANGE)
+               ks8842_update_link_status(netdev, adapter);
+
+       if (isr & (IRQ_RX | IRQ_RX_ERROR))
+               ks8842_handle_rx(netdev, adapter);
+
+       if (isr & IRQ_TX)
+               ks8842_handle_tx(netdev, adapter);
+
+       if (isr & IRQ_RX_OVERRUN)
+               ks8842_handle_rx_overrun(netdev, adapter);
+
+       if (isr & IRQ_TX_STOPPED) {
+               ks8842_disable_tx(adapter);
+               ks8842_enable_tx(adapter);
+       }
+
+       if (isr & IRQ_RX_STOPPED) {
+               ks8842_disable_rx(adapter);
+               ks8842_enable_rx(adapter);
+       }
+
+       /* re-enable interrupts, put back the bank selection register */
+       spin_lock_irqsave(&adapter->lock, flags);
+       ks8842_write16(adapter, 18, ENABLED_IRQS, REG_IER);
+       iowrite16(entry_bank, adapter->hw_addr + REG_SELECT_BANK);
+       spin_unlock_irqrestore(&adapter->lock, flags);
+}
+
+static irqreturn_t ks8842_irq(int irq, void *devid)
+{
+       struct ks8842_adapter *adapter = devid;
+       u16 isr;
+       u16 entry_bank = ioread16(adapter->hw_addr + REG_SELECT_BANK);
+       irqreturn_t ret = IRQ_NONE;
+
+       isr = ks8842_read16(adapter, 18, REG_ISR);
+       dev_dbg(&adapter->pdev->dev, "%s - ISR: 0x%x\n", __func__, isr);
+
+       if (isr) {
+               /* disable IRQ */
+               ks8842_write16(adapter, 18, 0x00, REG_IER);
+
+               /* schedule tasklet */
+               tasklet_schedule(&adapter->tasklet);
+
+               ret = IRQ_HANDLED;
+       }
+
+       iowrite16(entry_bank, adapter->hw_addr + REG_SELECT_BANK);
+
+       return ret;
+}
+
+
+/* Netdevice operations */
+
+static int ks8842_open(struct net_device *netdev)
+{
+       struct ks8842_adapter *adapter = netdev_priv(netdev);
+       int err;
+
+       dev_dbg(&adapter->pdev->dev, "%s - entry\n", __func__);
+
+       /* reset the HW */
+       ks8842_reset_hw(adapter);
+
+       ks8842_update_link_status(netdev, adapter);
+
+       err = request_irq(adapter->irq, ks8842_irq, IRQF_SHARED, DRV_NAME,
+               adapter);
+       if (err) {
+               printk(KERN_ERR "Failed to request IRQ: %d: %d\n",
+                       adapter->irq, err);
+               return err;
+       }
+
+       return 0;
+}
+
+static int ks8842_close(struct net_device *netdev)
+{
+       struct ks8842_adapter *adapter = netdev_priv(netdev);
+
+       dev_dbg(&adapter->pdev->dev, "%s - entry\n", __func__);
+
+       /* free the irq */
+       free_irq(adapter->irq, adapter);
+
+       /* disable the switch */
+       ks8842_write16(adapter, 32, 0x0, REG_SW_ID_AND_ENABLE);
+
+       return 0;
+}
+
+static int ks8842_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+       int ret;
+       struct ks8842_adapter *adapter = netdev_priv(netdev);
+
+       dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__);
+
+       ret = ks8842_tx_frame(skb, netdev);
+
+       if (ks8842_tx_fifo_space(adapter) <  netdev->mtu + 8)
+               netif_stop_queue(netdev);
+
+       return ret;
+}
+
+static int ks8842_set_mac(struct net_device *netdev, void *p)
+{
+       struct ks8842_adapter *adapter = netdev_priv(netdev);
+       unsigned long flags;
+       struct sockaddr *addr = p;
+       char *mac = (u8 *)addr->sa_data;
+       int i;
+
+       dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__);
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       memcpy(netdev->dev_addr, mac, netdev->addr_len);
+
+       spin_lock_irqsave(&adapter->lock, flags);
+       for (i = 0; i < ETH_ALEN; i++) {
+               ks8842_write8(adapter, 2, mac[ETH_ALEN - i - 1], REG_MARL + i);
+               ks8842_write8(adapter, 39, mac[ETH_ALEN - i - 1],
+                       REG_MACAR1 + i);
+       }
+       spin_unlock_irqrestore(&adapter->lock, flags);
+       return 0;
+}
+
+static void ks8842_tx_timeout(struct net_device *netdev)
+{
+       struct ks8842_adapter *adapter = netdev_priv(netdev);
+       unsigned long flags;
+
+       dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__);
+
+       spin_lock_irqsave(&adapter->lock, flags);
+       /* disable interrupts */
+       ks8842_write16(adapter, 18, 0, REG_IER);
+       ks8842_write16(adapter, 18, 0xFFFF, REG_ISR);
+       spin_unlock_irqrestore(&adapter->lock, flags);
+
+       ks8842_reset_hw(adapter);
+
+       ks8842_update_link_status(netdev, adapter);
+}
+
+static const struct net_device_ops ks8842_netdev_ops = {
+       .ndo_open               = ks8842_open,
+       .ndo_stop               = ks8842_close,
+       .ndo_start_xmit         = ks8842_xmit_frame,
+       .ndo_set_mac_address    = ks8842_set_mac,
+       .ndo_tx_timeout         = ks8842_tx_timeout,
+       .ndo_validate_addr      = eth_validate_addr
+};
+
+static struct ethtool_ops ks8842_ethtool_ops = {
+       .get_link               = ethtool_op_get_link,
+};
+
+static int __devinit ks8842_probe(struct platform_device *pdev)
+{
+       int err = -ENOMEM;
+       struct resource *iomem;
+       struct net_device *netdev;
+       struct ks8842_adapter *adapter;
+       u16 id;
+
+       iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!request_mem_region(iomem->start, resource_size(iomem), DRV_NAME))
+               goto err_mem_region;
+
+       netdev = alloc_etherdev(sizeof(struct ks8842_adapter));
+       if (!netdev)
+               goto err_alloc_etherdev;
+
+       SET_NETDEV_DEV(netdev, &pdev->dev);
+
+       adapter = netdev_priv(netdev);
+       adapter->hw_addr = ioremap(iomem->start, resource_size(iomem));
+       if (!adapter->hw_addr)
+               goto err_ioremap;
+
+       adapter->irq = platform_get_irq(pdev, 0);
+       if (adapter->irq < 0) {
+               err = adapter->irq;
+               goto err_get_irq;
+       }
+
+       adapter->pdev = pdev;
+
+       tasklet_init(&adapter->tasklet, ks8842_tasklet, (unsigned long)netdev);
+       spin_lock_init(&adapter->lock);
+
+       netdev->netdev_ops = &ks8842_netdev_ops;
+       netdev->ethtool_ops = &ks8842_ethtool_ops;
+
+       ks8842_read_mac_addr(adapter, netdev->dev_addr);
+
+       id = ks8842_read16(adapter, 32, REG_SW_ID_AND_ENABLE);
+
+       strcpy(netdev->name, "eth%d");
+       err = register_netdev(netdev);
+       if (err)
+               goto err_register;
+
+       platform_set_drvdata(pdev, netdev);
+
+       printk(KERN_INFO DRV_NAME
+               " Found chip, family: 0x%x, id: 0x%x, rev: 0x%x\n",
+               (id >> 8) & 0xff, (id >> 4) & 0xf, (id >> 1) & 0x7);
+
+       return 0;
+
+err_register:
+err_get_irq:
+       iounmap(adapter->hw_addr);
+err_ioremap:
+       free_netdev(netdev);
+err_alloc_etherdev:
+       release_mem_region(iomem->start, resource_size(iomem));
+err_mem_region:
+       return err;
+}
+
+static int __devexit ks8842_remove(struct platform_device *pdev)
+{
+       struct net_device *netdev = platform_get_drvdata(pdev);
+       struct ks8842_adapter *adapter = netdev_priv(netdev);
+       struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       unregister_netdev(netdev);
+       tasklet_kill(&adapter->tasklet);
+       iounmap(adapter->hw_addr);
+       free_netdev(netdev);
+       release_mem_region(iomem->start, resource_size(iomem));
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+
+static struct platform_driver ks8842_platform_driver = {
+       .driver = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ks8842_probe,
+       .remove         = ks8842_remove,
+};
+
+static int __init ks8842_init(void)
+{
+       return platform_driver_register(&ks8842_platform_driver);
+}
+
+static void __exit ks8842_exit(void)
+{
+       platform_driver_unregister(&ks8842_platform_driver);
+}
+
+module_init(ks8842_init);
+module_exit(ks8842_exit);
+
+MODULE_DESCRIPTION("Timberdale KS8842 ethernet driver");
+MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:ks8842");
+
index 8e88486..f8fa0c3 100644 (file)
@@ -304,7 +304,7 @@ struct net_device * __init mac8390_probe(int unit)
        if (!MACH_IS_MAC)
                return ERR_PTR(-ENODEV);
 
-       dev = alloc_ei_netdev();
+       dev = ____alloc_ei_netdev(0);
        if (!dev)
                return ERR_PTR(-ENOMEM);
 
@@ -481,15 +481,15 @@ void cleanup_module(void)
 static const struct net_device_ops mac8390_netdev_ops = {
        .ndo_open               = mac8390_open,
        .ndo_stop               = mac8390_close,
-       .ndo_start_xmit         = ei_start_xmit,
-       .ndo_tx_timeout         = ei_tx_timeout,
-       .ndo_get_stats          = ei_get_stats,
-       .ndo_set_multicast_list = ei_set_multicast_list,
+       .ndo_start_xmit         = __ei_start_xmit,
+       .ndo_tx_timeout         = __ei_tx_timeout,
+       .ndo_get_stats          = __ei_get_stats,
+       .ndo_set_multicast_list = __ei_set_multicast_list,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = eth_mac_addr,
        .ndo_change_mtu         = eth_change_mtu,
 #ifdef CONFIG_NET_POLL_CONTROLLER
-       .ndo_poll_controller    = ei_poll,
+       .ndo_poll_controller    = __ei_poll,
 #endif
 };
 
@@ -620,19 +620,12 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd
 
        /* Good, done, now spit out some messages */
        printk(KERN_INFO "%s: %s in slot %X (type %s)\n",
-                  dev->name, ndev->board->name, ndev->board->slot, cardname[type]);
-       printk(KERN_INFO "MAC ");
-       {
-               int i;
-               for (i = 0; i < 6; i++) {
-                       printk("%2.2x", dev->dev_addr[i]);
-                       if (i < 5)
-                               printk(":");
-               }
-       }
-       printk(" IRQ %d, %d KB shared memory at %#lx,  %d-bit access.\n",
-                  dev->irq, (int)((dev->mem_end - dev->mem_start)/0x1000) * 4,
-                  dev->mem_start, access_bitmode?32:16);
+              dev->name, ndev->board->name, ndev->board->slot, cardname[type]);
+       printk(KERN_INFO
+              "MAC %pM IRQ %d, %d KB shared memory at %#lx, %d-bit access.\n",
+              dev->dev_addr, dev->irq,
+              (unsigned int)(dev->mem_end - dev->mem_start) >> 10,
+              dev->mem_start, access_bitmode ? 32 : 16);
        return 0;
 }
 
index d5334b4..99eed9f 100644 (file)
@@ -232,7 +232,7 @@ static int macvlan_open(struct net_device *dev)
        if (macvlan_addr_busy(vlan->port, dev->dev_addr))
                goto out;
 
-       err = dev_unicast_add(lowerdev, dev->dev_addr, ETH_ALEN);
+       err = dev_unicast_add(lowerdev, dev->dev_addr);
        if (err < 0)
                goto out;
        if (dev->flags & IFF_ALLMULTI) {
@@ -244,7 +244,7 @@ static int macvlan_open(struct net_device *dev)
        return 0;
 
 del_unicast:
-       dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN);
+       dev_unicast_delete(lowerdev, dev->dev_addr);
 out:
        return err;
 }
@@ -258,7 +258,7 @@ static int macvlan_stop(struct net_device *dev)
        if (dev->flags & IFF_ALLMULTI)
                dev_set_allmulti(lowerdev, -1);
 
-       dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN);
+       dev_unicast_delete(lowerdev, dev->dev_addr);
 
        macvlan_hash_del(vlan);
        return 0;
@@ -282,10 +282,11 @@ static int macvlan_set_mac_address(struct net_device *dev, void *p)
                if (macvlan_addr_busy(vlan->port, addr->sa_data))
                        return -EBUSY;
 
-               if ((err = dev_unicast_add(lowerdev, addr->sa_data, ETH_ALEN)))
+               err = dev_unicast_add(lowerdev, addr->sa_data);
+               if (err)
                        return err;
 
-               dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN);
+               dev_unicast_delete(lowerdev, dev->dev_addr);
 
                macvlan_hash_change_addr(vlan, addr->sa_data);
        }
@@ -358,6 +359,7 @@ static int macvlan_init(struct net_device *dev)
                                  (lowerdev->state & MACVLAN_STATE_MASK);
        dev->features           = lowerdev->features & MACVLAN_FEATURES;
        dev->iflink             = lowerdev->ifindex;
+       dev->hard_header_len    = lowerdev->hard_header_len;
 
        macvlan_set_lockdep_class(dev);
 
index 6648303..dc45e98 100644 (file)
@@ -296,6 +296,23 @@ void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio,
                ecmd->duplex = (reg & MDIO_CTRL1_FULLDPLX ||
                                ecmd->speed == SPEED_10000);
        }
+
+       /* 10GBASE-T MDI/MDI-X */
+       if (ecmd->port == PORT_TP && ecmd->speed == SPEED_10000) {
+               switch (mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
+                                       MDIO_PMA_10GBT_SWAPPOL)) {
+               case MDIO_PMA_10GBT_SWAPPOL_ABNX | MDIO_PMA_10GBT_SWAPPOL_CDNX:
+                       ecmd->eth_tp_mdix = ETH_TP_MDI;
+                       break;
+               case 0:
+                       ecmd->eth_tp_mdix = ETH_TP_MDI_X;
+                       break;
+               default:
+                       /* It's complicated... */
+                       ecmd->eth_tp_mdix = ETH_TP_MDI_INVALID;
+                       break;
+               }
+       }
 }
 EXPORT_SYMBOL(mdio45_ethtool_gset_npage);
 
index 21040a0..1fd068e 100644 (file)
@@ -5,5 +5,5 @@ mlx4_core-y :=  alloc.o catas.o cmd.o cq.o eq.o fw.o icm.o intf.o main.o mcg.o \
 
 obj-$(CONFIG_MLX4_EN)               += mlx4_en.o
 
-mlx4_en-y :=   en_main.o en_tx.o en_rx.o en_params.o en_port.o en_cq.o \
+mlx4_en-y :=   en_main.o en_tx.o en_rx.o en_ethtool.o en_port.o en_cq.o \
                en_resources.o en_netdev.o
similarity index 86%
rename from drivers/net/mlx4/en_params.c
rename to drivers/net/mlx4/en_ethtool.c
index c1bd040..091f990 100644 (file)
 #include "mlx4_en.h"
 #include "en_port.h"
 
-#define MLX4_EN_PARM_INT(X, def_val, desc) \
-       static unsigned int X = def_val;\
-       module_param(X , uint, 0444); \
-       MODULE_PARM_DESC(X, desc);
-
-
-/*
- * Device scope module parameters
- */
-
-
-/* Use a XOR rathern than Toeplitz hash function for RSS */
-MLX4_EN_PARM_INT(rss_xor, 0, "Use XOR hash function for RSS");
-
-/* RSS hash type mask - default to <saddr, daddr, sport, dport> */
-MLX4_EN_PARM_INT(rss_mask, 0xf, "RSS hash type bitmask");
-
-/* Number of LRO sessions per Rx ring (rounded up to a power of two) */
-MLX4_EN_PARM_INT(num_lro, MLX4_EN_MAX_LRO_DESCRIPTORS,
-                "Number of LRO sessions per ring or disabled (0)");
-
-/* Priority pausing */
-MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]."
-                          " Per priority bit mask");
-MLX4_EN_PARM_INT(pfcrx, 0, "Priority based Flow Control policy on RX[7:0]."
-                          " Per priority bit mask");
-
-int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
-{
-       struct mlx4_en_profile *params = &mdev->profile;
-       int i;
-
-       params->rss_xor = (rss_xor != 0);
-       params->rss_mask = rss_mask & 0x1f;
-       params->num_lro = min_t(int, num_lro , MLX4_EN_MAX_LRO_DESCRIPTORS);
-       for (i = 1; i <= MLX4_MAX_PORTS; i++) {
-               params->prof[i].rx_pause = 1;
-               params->prof[i].rx_ppp = pfcrx;
-               params->prof[i].tx_pause = 1;
-               params->prof[i].tx_ppp = pfctx;
-               params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE;
-               params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE;
-       }
-       if (pfcrx || pfctx) {
-               params->prof[1].tx_ring_num = MLX4_EN_TX_RING_NUM;
-               params->prof[2].tx_ring_num = MLX4_EN_TX_RING_NUM;
-       } else {
-               params->prof[1].tx_ring_num = 1;
-               params->prof[2].tx_ring_num = 1;
-       }
-
-       return 0;
-}
-
-
-/*
- * Ethtool support
- */
 
 static void mlx4_en_update_lro_stats(struct mlx4_en_priv *priv)
 {
@@ -326,8 +268,7 @@ static int mlx4_en_set_coalesce(struct net_device *dev,
 
        priv->rx_frames = (coal->rx_max_coalesced_frames ==
                           MLX4_EN_AUTO_CONF) ?
-                               MLX4_EN_RX_COAL_TARGET /
-                               priv->dev->mtu + 1 :
+                               MLX4_EN_RX_COAL_TARGET :
                                coal->rx_max_coalesced_frames;
        priv->rx_usecs = (coal->rx_coalesce_usecs ==
                          MLX4_EN_AUTO_CONF) ?
@@ -371,7 +312,7 @@ static int mlx4_en_set_pauseparam(struct net_device *dev,
                                    priv->prof->rx_pause,
                                    priv->prof->rx_ppp);
        if (err)
-               mlx4_err(mdev, "Failed setting pause params to\n");
+               en_err(priv, "Failed setting pause params\n");
 
        return err;
 }
@@ -421,13 +362,13 @@ static int mlx4_en_set_ringparam(struct net_device *dev,
 
        err = mlx4_en_alloc_resources(priv);
        if (err) {
-               mlx4_err(mdev, "Failed reallocating port resources\n");
+               en_err(priv, "Failed reallocating port resources\n");
                goto out;
        }
        if (port_up) {
                err = mlx4_en_start_port(dev);
                if (err)
-                       mlx4_err(mdev, "Failed starting port\n");
+                       en_err(priv, "Failed starting port\n");
        }
 
 out:
index 510633f..9ed4a15 100644 (file)
@@ -51,6 +51,55 @@ static const char mlx4_en_version[] =
        DRV_NAME ": Mellanox ConnectX HCA Ethernet driver v"
        DRV_VERSION " (" DRV_RELDATE ")\n";
 
+#define MLX4_EN_PARM_INT(X, def_val, desc) \
+       static unsigned int X = def_val;\
+       module_param(X , uint, 0444); \
+       MODULE_PARM_DESC(X, desc);
+
+
+/*
+ * Device scope module parameters
+ */
+
+
+/* Use a XOR rathern than Toeplitz hash function for RSS */
+MLX4_EN_PARM_INT(rss_xor, 0, "Use XOR hash function for RSS");
+
+/* RSS hash type mask - default to <saddr, daddr, sport, dport> */
+MLX4_EN_PARM_INT(rss_mask, 0xf, "RSS hash type bitmask");
+
+/* Number of LRO sessions per Rx ring (rounded up to a power of two) */
+MLX4_EN_PARM_INT(num_lro, MLX4_EN_MAX_LRO_DESCRIPTORS,
+                "Number of LRO sessions per ring or disabled (0)");
+
+/* Priority pausing */
+MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]."
+                          " Per priority bit mask");
+MLX4_EN_PARM_INT(pfcrx, 0, "Priority based Flow Control policy on RX[7:0]."
+                          " Per priority bit mask");
+
+static int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
+{
+       struct mlx4_en_profile *params = &mdev->profile;
+       int i;
+
+       params->rss_xor = (rss_xor != 0);
+       params->rss_mask = rss_mask & 0x1f;
+       params->num_lro = min_t(int, num_lro , MLX4_EN_MAX_LRO_DESCRIPTORS);
+       for (i = 1; i <= MLX4_MAX_PORTS; i++) {
+               params->prof[i].rx_pause = 1;
+               params->prof[i].rx_ppp = pfcrx;
+               params->prof[i].tx_pause = 1;
+               params->prof[i].tx_ppp = pfctx;
+               params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE;
+               params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE;
+               params->prof[i].tx_ring_num = MLX4_EN_NUM_TX_RINGS +
+                       (!!pfcrx) * MLX4_EN_NUM_PPP_RINGS;
+       }
+
+       return 0;
+}
+
 static void mlx4_en_event(struct mlx4_dev *dev, void *endev_ptr,
                          enum mlx4_dev_event event, int port)
 {
@@ -194,28 +243,11 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
        /* Create a netdev for each port */
        mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) {
                mlx4_info(mdev, "Activating port:%d\n", i);
-               if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i])) {
+               if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i]))
                        mdev->pndev[i] = NULL;
-                       goto err_free_netdev;
-               }
        }
        return mdev;
 
-
-err_free_netdev:
-       mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) {
-               if (mdev->pndev[i])
-                       mlx4_en_destroy_netdev(mdev->pndev[i]);
-       }
-
-       mutex_lock(&mdev->state_lock);
-       mdev->device_up = false;
-       mutex_unlock(&mdev->state_lock);
-       flush_workqueue(mdev->workqueue);
-
-       /* Stop event queue before we drop down to release shared SW state */
-       destroy_workqueue(mdev->workqueue);
-
 err_mr:
        mlx4_mr_free(dev, &mdev->mr);
 err_uar:
index 0cd185a..0a7e78a 100644 (file)
@@ -51,14 +51,14 @@ static void mlx4_en_vlan_rx_register(struct net_device *dev, struct vlan_group *
        struct mlx4_en_dev *mdev = priv->mdev;
        int err;
 
-       mlx4_dbg(HW, priv, "Registering VLAN group:%p\n", grp);
+       en_dbg(HW, priv, "Registering VLAN group:%p\n", grp);
        priv->vlgrp = grp;
 
        mutex_lock(&mdev->state_lock);
        if (mdev->device_up && priv->port_up) {
                err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, grp);
                if (err)
-                       mlx4_err(mdev, "Failed configuring VLAN filter\n");
+                       en_err(priv, "Failed configuring VLAN filter\n");
        }
        mutex_unlock(&mdev->state_lock);
 }
@@ -72,15 +72,15 @@ static void mlx4_en_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
        if (!priv->vlgrp)
                return;
 
-       mlx4_dbg(HW, priv, "adding VLAN:%d (vlgrp entry:%p)\n",
-                vid, vlan_group_get_device(priv->vlgrp, vid));
+       en_dbg(HW, priv, "adding VLAN:%d (vlgrp entry:%p)\n",
+              vid, vlan_group_get_device(priv->vlgrp, vid));
 
        /* Add VID to port VLAN filter */
        mutex_lock(&mdev->state_lock);
        if (mdev->device_up && priv->port_up) {
                err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlgrp);
                if (err)
-                       mlx4_err(mdev, "Failed configuring VLAN filter\n");
+                       en_err(priv, "Failed configuring VLAN filter\n");
        }
        mutex_unlock(&mdev->state_lock);
 }
@@ -94,9 +94,8 @@ static void mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
        if (!priv->vlgrp)
                return;
 
-       mlx4_dbg(HW, priv, "Killing VID:%d (vlgrp:%p vlgrp "
-                "entry:%p)\n", vid, priv->vlgrp,
-                vlan_group_get_device(priv->vlgrp, vid));
+       en_dbg(HW, priv, "Killing VID:%d (vlgrp:%p vlgrp entry:%p)\n",
+              vid, priv->vlgrp, vlan_group_get_device(priv->vlgrp, vid));
        vlan_group_set_device(priv->vlgrp, vid, NULL);
 
        /* Remove VID from port VLAN filter */
@@ -104,7 +103,7 @@ static void mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
        if (mdev->device_up && priv->port_up) {
                err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlgrp);
                if (err)
-                       mlx4_err(mdev, "Failed configuring VLAN filter\n");
+                       en_err(priv, "Failed configuring VLAN filter\n");
        }
        mutex_unlock(&mdev->state_lock);
 }
@@ -150,9 +149,10 @@ static void mlx4_en_do_set_mac(struct work_struct *work)
                err = mlx4_register_mac(mdev->dev, priv->port,
                                        priv->mac, &priv->mac_index);
                if (err)
-                       mlx4_err(mdev, "Failed changing HW MAC address\n");
+                       en_err(priv, "Failed changing HW MAC address\n");
        } else
-               mlx4_dbg(HW, priv, "Port is down, exiting...\n");
+               en_dbg(HW, priv, "Port is down while "
+                                "registering mac, exiting...\n");
 
        mutex_unlock(&mdev->state_lock);
 }
@@ -174,7 +174,6 @@ static void mlx4_en_clear_list(struct net_device *dev)
 static void mlx4_en_cache_mclist(struct net_device *dev)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
-       struct mlx4_en_dev *mdev = priv->mdev;
        struct dev_mc_list *mclist;
        struct dev_mc_list *tmp;
        struct dev_mc_list *plist = NULL;
@@ -182,7 +181,7 @@ static void mlx4_en_cache_mclist(struct net_device *dev)
        for (mclist = dev->mc_list; mclist; mclist = mclist->next) {
                tmp = kmalloc(sizeof(struct dev_mc_list), GFP_ATOMIC);
                if (!tmp) {
-                       mlx4_err(mdev, "failed to allocate multicast list\n");
+                       en_err(priv, "failed to allocate multicast list\n");
                        mlx4_en_clear_list(dev);
                        return;
                }
@@ -219,13 +218,13 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
 
        mutex_lock(&mdev->state_lock);
        if (!mdev->device_up) {
-               mlx4_dbg(HW, priv, "Card is not up, ignoring "
-                                  "multicast change.\n");
+               en_dbg(HW, priv, "Card is not up, "
+                                "ignoring multicast change.\n");
                goto out;
        }
        if (!priv->port_up) {
-               mlx4_dbg(HW, priv, "Port is down, ignoring "
-                                  "multicast change.\n");
+               en_dbg(HW, priv, "Port is down, "
+                                "ignoring  multicast change.\n");
                goto out;
        }
 
@@ -236,29 +235,27 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
        if (dev->flags & IFF_PROMISC) {
                if (!(priv->flags & MLX4_EN_FLAG_PROMISC)) {
                        if (netif_msg_rx_status(priv))
-                               mlx4_warn(mdev, "Port:%d entering promiscuous mode\n",
-                                         priv->port);
+                               en_warn(priv, "Entering promiscuous mode\n");
                        priv->flags |= MLX4_EN_FLAG_PROMISC;
 
                        /* Enable promiscouos mode */
                        err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port,
                                                     priv->base_qpn, 1);
                        if (err)
-                               mlx4_err(mdev, "Failed enabling "
-                                        "promiscous mode\n");
+                               en_err(priv, "Failed enabling "
+                                            "promiscous mode\n");
 
                        /* Disable port multicast filter (unconditionally) */
                        err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0,
                                                  0, MLX4_MCAST_DISABLE);
                        if (err)
-                               mlx4_err(mdev, "Failed disabling "
-                                        "multicast filter\n");
+                               en_err(priv, "Failed disabling "
+                                            "multicast filter\n");
 
                        /* Disable port VLAN filter */
                        err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, NULL);
                        if (err)
-                               mlx4_err(mdev, "Failed disabling "
-                                        "VLAN filter\n");
+                               en_err(priv, "Failed disabling VLAN filter\n");
                }
                goto out;
        }
@@ -269,20 +266,19 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
 
        if (priv->flags & MLX4_EN_FLAG_PROMISC) {
                if (netif_msg_rx_status(priv))
-                       mlx4_warn(mdev, "Port:%d leaving promiscuous mode\n",
-                                 priv->port);
+                       en_warn(priv, "Leaving promiscuous mode\n");
                priv->flags &= ~MLX4_EN_FLAG_PROMISC;
 
                /* Disable promiscouos mode */
                err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port,
                                             priv->base_qpn, 0);
                if (err)
-                       mlx4_err(mdev, "Failed disabling promiscous mode\n");
+                       en_err(priv, "Failed disabling promiscous mode\n");
 
                /* Enable port VLAN filter */
                err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlgrp);
                if (err)
-                       mlx4_err(mdev, "Failed enabling VLAN filter\n");
+                       en_err(priv, "Failed enabling VLAN filter\n");
        }
 
        /* Enable/disable the multicast filter according to IFF_ALLMULTI */
@@ -290,12 +286,12 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
                err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0,
                                          0, MLX4_MCAST_DISABLE);
                if (err)
-                       mlx4_err(mdev, "Failed disabling multicast filter\n");
+                       en_err(priv, "Failed disabling multicast filter\n");
        } else {
                err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0,
                                          0, MLX4_MCAST_DISABLE);
                if (err)
-                       mlx4_err(mdev, "Failed disabling multicast filter\n");
+                       en_err(priv, "Failed disabling multicast filter\n");
 
                /* Flush mcast filter and init it with broadcast address */
                mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, ETH_BCAST,
@@ -314,7 +310,7 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
                err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0,
                                          0, MLX4_MCAST_ENABLE);
                if (err)
-                       mlx4_err(mdev, "Failed enabling multicast filter\n");
+                       en_err(priv, "Failed enabling multicast filter\n");
 
                mlx4_en_clear_list(dev);
        }
@@ -346,10 +342,10 @@ static void mlx4_en_tx_timeout(struct net_device *dev)
        struct mlx4_en_dev *mdev = priv->mdev;
 
        if (netif_msg_timer(priv))
-               mlx4_warn(mdev, "Tx timeout called on port:%d\n", priv->port);
+               en_warn(priv, "Tx timeout called on port:%d\n", priv->port);
 
        priv->port_stats.tx_timeout++;
-       mlx4_dbg(DRV, priv, "Scheduling watchdog\n");
+       en_dbg(DRV, priv, "Scheduling watchdog\n");
        queue_work(mdev->workqueue, &priv->watchdog_task);
 }
 
@@ -376,10 +372,10 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv)
         *   satisfy our coelsing target.
         * - moder_time is set to a fixed value.
         */
-       priv->rx_frames = MLX4_EN_RX_COAL_TARGET / priv->dev->mtu + 1;
+       priv->rx_frames = MLX4_EN_RX_COAL_TARGET;
        priv->rx_usecs = MLX4_EN_RX_COAL_TIME;
-       mlx4_dbg(INTR, priv, "Default coalesing params for mtu:%d - "
-                            "rx_frames:%d rx_usecs:%d\n",
+       en_dbg(INTR, priv, "Default coalesing params for mtu:%d - "
+                          "rx_frames:%d rx_usecs:%d\n",
                 priv->dev->mtu, priv->rx_frames, priv->rx_usecs);
 
        /* Setup cq moderation params */
@@ -412,7 +408,6 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv)
 static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv)
 {
        unsigned long period = (unsigned long) (jiffies - priv->last_moder_jiffies);
-       struct mlx4_en_dev *mdev = priv->mdev;
        struct mlx4_en_cq *cq;
        unsigned long packets;
        unsigned long rate;
@@ -472,11 +467,11 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv)
                moder_time = priv->rx_usecs;
        }
 
-       mlx4_dbg(INTR, priv, "tx rate:%lu rx_rate:%lu\n",
-                tx_pkt_diff * HZ / period, rx_pkt_diff * HZ / period);
+       en_dbg(INTR, priv, "tx rate:%lu rx_rate:%lu\n",
+              tx_pkt_diff * HZ / period, rx_pkt_diff * HZ / period);
 
-       mlx4_dbg(INTR, priv, "Rx moder_time changed from:%d to %d period:%lu "
-                "[jiff] packets:%lu avg_pkt_size:%lu rate:%lu [p/s])\n",
+       en_dbg(INTR, priv, "Rx moder_time changed from:%d to %d period:%lu "
+              "[jiff] packets:%lu avg_pkt_size:%lu rate:%lu [p/s])\n",
                 priv->last_moder_time, moder_time, period, packets,
                 avg_pkt_size, rate);
 
@@ -487,8 +482,7 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv)
                        cq->moder_time = moder_time;
                        err = mlx4_en_set_cq_moder(priv, cq);
                        if (err) {
-                               mlx4_err(mdev, "Failed modifying moderation for cq:%d "
-                                        "on port:%d\n", i, priv->port);
+                               en_err(priv, "Failed modifying moderation for cq:%d\n", i);
                                break;
                        }
                }
@@ -511,8 +505,7 @@ static void mlx4_en_do_get_stats(struct work_struct *work)
 
        err = mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 0);
        if (err)
-               mlx4_dbg(HW, priv, "Could not update stats for "
-                                  "port:%d\n", priv->port);
+               en_dbg(HW, priv, "Could not update stats \n");
 
        mutex_lock(&mdev->state_lock);
        if (mdev->device_up) {
@@ -536,12 +529,10 @@ static void mlx4_en_linkstate(struct work_struct *work)
         * report to system log */
        if (priv->last_link_state != linkstate) {
                if (linkstate == MLX4_DEV_EVENT_PORT_DOWN) {
-                       if (netif_msg_link(priv))
-                               mlx4_info(mdev, "Port %d - link down\n", priv->port);
+                       en_dbg(LINK, priv, "Link Down\n");
                        netif_carrier_off(priv->dev);
                } else {
-                       if (netif_msg_link(priv))
-                               mlx4_info(mdev, "Port %d - link up\n", priv->port);
+                       en_dbg(LINK, priv, "Link Up\n");
                        netif_carrier_on(priv->dev);
                }
        }
@@ -563,19 +554,19 @@ int mlx4_en_start_port(struct net_device *dev)
        int j;
 
        if (priv->port_up) {
-               mlx4_dbg(DRV, priv, "start port called while port already up\n");
+               en_dbg(DRV, priv, "start port called while port already up\n");
                return 0;
        }
 
        /* Calculate Rx buf size */
        dev->mtu = min(dev->mtu, priv->max_mtu);
        mlx4_en_calc_rx_buf(dev);
-       mlx4_dbg(DRV, priv, "Rx buf size:%d\n", priv->rx_skb_size);
+       en_dbg(DRV, priv, "Rx buf size:%d\n", priv->rx_skb_size);
 
        /* Configure rx cq's and rings */
        err = mlx4_en_activate_rx_rings(priv);
        if (err) {
-               mlx4_err(mdev, "Failed to activate RX rings\n");
+               en_err(priv, "Failed to activate RX rings\n");
                return err;
        }
        for (i = 0; i < priv->rx_ring_num; i++) {
@@ -583,14 +574,14 @@ int mlx4_en_start_port(struct net_device *dev)
 
                err = mlx4_en_activate_cq(priv, cq);
                if (err) {
-                       mlx4_err(mdev, "Failed activating Rx CQ\n");
+                       en_err(priv, "Failed activating Rx CQ\n");
                        goto cq_err;
                }
                for (j = 0; j < cq->size; j++)
                        cq->buf[j].owner_sr_opcode = MLX4_CQE_OWNER_MASK;
                err = mlx4_en_set_cq_moder(priv, cq);
                if (err) {
-                       mlx4_err(mdev, "Failed setting cq moderation parameters");
+                       en_err(priv, "Failed setting cq moderation parameters");
                        mlx4_en_deactivate_cq(priv, cq);
                        goto cq_err;
                }
@@ -601,7 +592,7 @@ int mlx4_en_start_port(struct net_device *dev)
 
        err = mlx4_en_config_rss_steer(priv);
        if (err) {
-               mlx4_err(mdev, "Failed configuring rss steering\n");
+               en_err(priv, "Failed configuring rss steering\n");
                goto cq_err;
        }
 
@@ -611,16 +602,16 @@ int mlx4_en_start_port(struct net_device *dev)
                cq = &priv->tx_cq[i];
                err = mlx4_en_activate_cq(priv, cq);
                if (err) {
-                       mlx4_err(mdev, "Failed allocating Tx CQ\n");
+                       en_err(priv, "Failed allocating Tx CQ\n");
                        goto tx_err;
                }
                err = mlx4_en_set_cq_moder(priv, cq);
                if (err) {
-                       mlx4_err(mdev, "Failed setting cq moderation parameters");
+                       en_err(priv, "Failed setting cq moderation parameters");
                        mlx4_en_deactivate_cq(priv, cq);
                        goto tx_err;
                }
-               mlx4_dbg(DRV, priv, "Resetting index of collapsed CQ:%d to -1\n", i);
+               en_dbg(DRV, priv, "Resetting index of collapsed CQ:%d to -1\n", i);
                cq->buf->wqe_index = cpu_to_be16(0xffff);
 
                /* Configure ring */
@@ -628,7 +619,7 @@ int mlx4_en_start_port(struct net_device *dev)
                err = mlx4_en_activate_tx_ring(priv, tx_ring, cq->mcq.cqn,
                                               priv->rx_ring[0].srq.srqn);
                if (err) {
-                       mlx4_err(mdev, "Failed allocating Tx ring\n");
+                       en_err(priv, "Failed allocating Tx ring\n");
                        mlx4_en_deactivate_cq(priv, cq);
                        goto tx_err;
                }
@@ -646,30 +637,30 @@ int mlx4_en_start_port(struct net_device *dev)
                                    priv->prof->rx_pause,
                                    priv->prof->rx_ppp);
        if (err) {
-               mlx4_err(mdev, "Failed setting port general configurations"
-                              " for port %d, with error %d\n", priv->port, err);
+               en_err(priv, "Failed setting port general configurations "
+                            "for port %d, with error %d\n", priv->port, err);
                goto tx_err;
        }
        /* Set default qp number */
        err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, priv->base_qpn, 0);
        if (err) {
-               mlx4_err(mdev, "Failed setting default qp numbers\n");
+               en_err(priv, "Failed setting default qp numbers\n");
                goto tx_err;
        }
        /* Set port mac number */
-       mlx4_dbg(DRV, priv, "Setting mac for port %d\n", priv->port);
+       en_dbg(DRV, priv, "Setting mac for port %d\n", priv->port);
        err = mlx4_register_mac(mdev->dev, priv->port,
                                priv->mac, &priv->mac_index);
        if (err) {
-               mlx4_err(mdev, "Failed setting port mac\n");
+               en_err(priv, "Failed setting port mac\n");
                goto tx_err;
        }
 
        /* Init port */
-       mlx4_dbg(HW, priv, "Initializing port\n");
+       en_dbg(HW, priv, "Initializing port\n");
        err = mlx4_INIT_PORT(mdev->dev, priv->port);
        if (err) {
-               mlx4_err(mdev, "Failed Initializing port\n");
+               en_err(priv, "Failed Initializing port\n");
                goto mac_err;
        }
 
@@ -706,8 +697,7 @@ void mlx4_en_stop_port(struct net_device *dev)
        int i;
 
        if (!priv->port_up) {
-               mlx4_dbg(DRV, priv, "stop port (%d) called while port already down\n",
-                        priv->port);
+               en_dbg(DRV, priv, "stop port called while port already down\n");
                return;
        }
        netif_stop_queue(dev);
@@ -752,13 +742,13 @@ static void mlx4_en_restart(struct work_struct *work)
        struct mlx4_en_dev *mdev = priv->mdev;
        struct net_device *dev = priv->dev;
 
-       mlx4_dbg(DRV, priv, "Watchdog task called for port %d\n", priv->port);
+       en_dbg(DRV, priv, "Watchdog task called for port %d\n", priv->port);
 
        mutex_lock(&mdev->state_lock);
        if (priv->port_up) {
                mlx4_en_stop_port(dev);
                if (mlx4_en_start_port(dev))
-                       mlx4_err(mdev, "Failed restarting port %d\n", priv->port);
+                       en_err(priv, "Failed restarting port %d\n", priv->port);
        }
        mutex_unlock(&mdev->state_lock);
 }
@@ -774,14 +764,14 @@ static int mlx4_en_open(struct net_device *dev)
        mutex_lock(&mdev->state_lock);
 
        if (!mdev->device_up) {
-               mlx4_err(mdev, "Cannot open - device down/disabled\n");
+               en_err(priv, "Cannot open - device down/disabled\n");
                err = -EBUSY;
                goto out;
        }
 
        /* Reset HW statistics and performance counters */
        if (mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 1))
-               mlx4_dbg(HW, priv, "Failed dumping statistics\n");
+               en_dbg(HW, priv, "Failed dumping statistics\n");
 
        memset(&priv->stats, 0, sizeof(priv->stats));
        memset(&priv->pstats, 0, sizeof(priv->pstats));
@@ -798,7 +788,7 @@ static int mlx4_en_open(struct net_device *dev)
        mlx4_en_set_default_moderation(priv);
        err = mlx4_en_start_port(dev);
        if (err)
-               mlx4_err(mdev, "Failed starting port:%d\n", priv->port);
+               en_err(priv, "Failed starting port:%d\n", priv->port);
 
 out:
        mutex_unlock(&mdev->state_lock);
@@ -811,8 +801,7 @@ static int mlx4_en_close(struct net_device *dev)
        struct mlx4_en_priv *priv = netdev_priv(dev);
        struct mlx4_en_dev *mdev = priv->mdev;
 
-       if (netif_msg_ifdown(priv))
-               mlx4_info(mdev, "Close called for port:%d\n", priv->port);
+       en_dbg(IFDOWN, priv, "Close port called\n");
 
        mutex_lock(&mdev->state_lock);
 
@@ -844,7 +833,6 @@ void mlx4_en_free_resources(struct mlx4_en_priv *priv)
 
 int mlx4_en_alloc_resources(struct mlx4_en_priv *priv)
 {
-       struct mlx4_en_dev *mdev = priv->mdev;
        struct mlx4_en_port_profile *prof = priv->prof;
        int i;
 
@@ -873,7 +861,7 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv)
        return 0;
 
 err:
-       mlx4_err(mdev, "Failed to allocate NIC resources\n");
+       en_err(priv, "Failed to allocate NIC resources\n");
        return -ENOMEM;
 }
 
@@ -883,7 +871,7 @@ void mlx4_en_destroy_netdev(struct net_device *dev)
        struct mlx4_en_priv *priv = netdev_priv(dev);
        struct mlx4_en_dev *mdev = priv->mdev;
 
-       mlx4_dbg(DRV, priv, "Destroying netdev on port:%d\n", priv->port);
+       en_dbg(DRV, priv, "Destroying netdev on port:%d\n", priv->port);
 
        /* Unregister device - this will close the port if it was up */
        if (priv->registered)
@@ -912,11 +900,11 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu)
        struct mlx4_en_dev *mdev = priv->mdev;
        int err = 0;
 
-       mlx4_dbg(DRV, priv, "Change MTU called - current:%d new:%d\n",
+       en_dbg(DRV, priv, "Change MTU called - current:%d new:%d\n",
                 dev->mtu, new_mtu);
 
        if ((new_mtu < MLX4_EN_MIN_MTU) || (new_mtu > priv->max_mtu)) {
-               mlx4_err(mdev, "Bad MTU size:%d.\n", new_mtu);
+               en_err(priv, "Bad MTU size:%d.\n", new_mtu);
                return -EPERM;
        }
        dev->mtu = new_mtu;
@@ -926,13 +914,13 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu)
                if (!mdev->device_up) {
                        /* NIC is probably restarting - let watchdog task reset
                         * the port */
-                       mlx4_dbg(DRV, priv, "Change MTU called with card down!?\n");
+                       en_dbg(DRV, priv, "Change MTU called with card down!?\n");
                } else {
                        mlx4_en_stop_port(dev);
                        mlx4_en_set_default_moderation(priv);
                        err = mlx4_en_start_port(dev);
                        if (err) {
-                               mlx4_err(mdev, "Failed restarting port:%d\n",
+                               en_err(priv, "Failed restarting port:%d\n",
                                         priv->port);
                                queue_work(mdev->workqueue, &priv->watchdog_task);
                        }
@@ -946,6 +934,7 @@ static const struct net_device_ops mlx4_netdev_ops = {
        .ndo_open               = mlx4_en_open,
        .ndo_stop               = mlx4_en_close,
        .ndo_start_xmit         = mlx4_en_xmit,
+       .ndo_select_queue       = mlx4_en_select_queue,
        .ndo_get_stats          = mlx4_en_get_stats,
        .ndo_set_multicast_list = mlx4_en_set_multicast,
        .ndo_set_mac_address    = mlx4_en_set_mac,
@@ -968,7 +957,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        int i;
        int err;
 
-       dev = alloc_etherdev(sizeof(struct mlx4_en_priv));
+       dev = alloc_etherdev_mq(sizeof(struct mlx4_en_priv), prof->tx_ring_num);
        if (dev == NULL) {
                mlx4_err(mdev, "Net device allocation failed\n");
                return -ENOMEM;
@@ -1006,7 +995,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port];
        priv->mac = mdev->dev->caps.def_mac[priv->port];
        if (ILLEGAL_MAC(priv->mac)) {
-               mlx4_err(mdev, "Port: %d, invalid mac burned: 0x%llx, quiting\n",
+               en_err(priv, "Port: %d, invalid mac burned: 0x%llx, quiting\n",
                         priv->port, priv->mac);
                err = -EINVAL;
                goto out;
@@ -1025,19 +1014,17 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        err = mlx4_alloc_hwq_res(mdev->dev, &priv->res,
                                MLX4_EN_PAGE_SIZE, MLX4_EN_PAGE_SIZE);
        if (err) {
-               mlx4_err(mdev, "Failed to allocate page for rx qps\n");
+               en_err(priv, "Failed to allocate page for rx qps\n");
                goto out;
        }
        priv->allocated = 1;
 
-       /* Populate Tx priority mappings */
-       mlx4_en_set_prio_map(priv, priv->tx_prio_map, prof->tx_ring_num);
-
        /*
         * Initialize netdev entry points
         */
        dev->netdev_ops = &mlx4_netdev_ops;
        dev->watchdog_timeo = MLX4_EN_WATCHDOG_TIMEOUT;
+       dev->real_num_tx_queues = MLX4_EN_NUM_TX_RINGS;
 
        SET_ETHTOOL_OPS(dev, &mlx4_en_ethtool_ops);
 
@@ -1051,7 +1038,9 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
         * Set driver features
         */
        dev->features |= NETIF_F_SG;
+       dev->vlan_features |= NETIF_F_SG;
        dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+       dev->vlan_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
        dev->features |= NETIF_F_HIGHDMA;
        dev->features |= NETIF_F_HW_VLAN_TX |
                         NETIF_F_HW_VLAN_RX |
@@ -1061,6 +1050,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        if (mdev->LSO_support) {
                dev->features |= NETIF_F_TSO;
                dev->features |= NETIF_F_TSO6;
+               dev->vlan_features |= NETIF_F_TSO;
+               dev->vlan_features |= NETIF_F_TSO6;
        }
 
        mdev->pndev[port] = dev;
@@ -1068,9 +1059,13 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        netif_carrier_off(dev);
        err = register_netdev(dev);
        if (err) {
-               mlx4_err(mdev, "Netdev registration failed\n");
+               en_err(priv, "Netdev registration failed for port %d\n", port);
                goto out;
        }
+
+       en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num);
+       en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num);
+
        priv->registered = 1;
        queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY);
        return 0;
index 6bfab6e..5a14899 100644 (file)
@@ -114,8 +114,8 @@ static int mlx4_en_init_allocator(struct mlx4_en_priv *priv,
                        goto out;
 
                page_alloc->offset = priv->frag_info[i].frag_align;
-               mlx4_dbg(DRV, priv, "Initialized allocator:%d with page:%p\n",
-                        i, page_alloc->page);
+               en_dbg(DRV, priv, "Initialized allocator:%d with page:%p\n",
+                      i, page_alloc->page);
        }
        return 0;
 
@@ -136,8 +136,8 @@ static void mlx4_en_destroy_allocator(struct mlx4_en_priv *priv,
 
        for (i = 0; i < priv->num_frags; i++) {
                page_alloc = &ring->page_alloc[i];
-               mlx4_dbg(DRV, priv, "Freeing allocator:%d count:%d\n",
-                        i, page_count(page_alloc->page));
+               en_dbg(DRV, priv, "Freeing allocator:%d count:%d\n",
+                      i, page_count(page_alloc->page));
 
                put_page(page_alloc->page);
                page_alloc->page = NULL;
@@ -214,10 +214,10 @@ static void mlx4_en_free_rx_desc(struct mlx4_en_priv *priv,
 
        skb_frags = ring->rx_info + (index << priv->log_rx_info);
        for (nr = 0; nr < priv->num_frags; nr++) {
-               mlx4_dbg(DRV, priv, "Freeing fragment:%d\n", nr);
+               en_dbg(DRV, priv, "Freeing fragment:%d\n", nr);
                dma = be64_to_cpu(rx_desc->data[nr].addr);
 
-               mlx4_dbg(DRV, priv, "Unmaping buffer at dma:0x%llx\n", (u64) dma);
+               en_dbg(DRV, priv, "Unmaping buffer at dma:0x%llx\n", (u64) dma);
                pci_unmap_single(mdev->pdev, dma, skb_frags[nr].size,
                                 PCI_DMA_FROMDEVICE);
                put_page(skb_frags[nr].page);
@@ -226,7 +226,6 @@ static void mlx4_en_free_rx_desc(struct mlx4_en_priv *priv,
 
 static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv)
 {
-       struct mlx4_en_dev *mdev = priv->mdev;
        struct mlx4_en_rx_ring *ring;
        int ring_ind;
        int buf_ind;
@@ -239,14 +238,14 @@ static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv)
                        if (mlx4_en_prepare_rx_desc(priv, ring,
                                                    ring->actual_size)) {
                                if (ring->actual_size < MLX4_EN_MIN_RX_SIZE) {
-                                       mlx4_err(mdev, "Failed to allocate "
-                                                      "enough rx buffers\n");
+                                       en_err(priv, "Failed to allocate "
+                                                    "enough rx buffers\n");
                                        return -ENOMEM;
                                } else {
                                        new_size = rounddown_pow_of_two(ring->actual_size);
-                                       mlx4_warn(mdev, "Only %d buffers allocated "
-                                                       "reducing ring size to %d",
-                                                 ring->actual_size, new_size);
+                                       en_warn(priv, "Only %d buffers allocated "
+                                                     "reducing ring size to %d",
+                                               ring->actual_size, new_size);
                                        goto reduce_rings;
                                }
                        }
@@ -282,8 +281,7 @@ static int mlx4_en_fill_rx_buf(struct net_device *dev,
                                              ring->size_mask);
                if (err) {
                        if (netif_msg_rx_err(priv))
-                               mlx4_warn(priv->mdev,
-                                         "Failed preparing rx descriptor\n");
+                               en_warn(priv, "Failed preparing rx descriptor\n");
                        priv->port_stats.rx_alloc_failed++;
                        break;
                }
@@ -301,14 +299,14 @@ static void mlx4_en_free_rx_buf(struct mlx4_en_priv *priv,
 {
        int index;
 
-       mlx4_dbg(DRV, priv, "Freeing Rx buf - cons:%d prod:%d\n",
-                       ring->cons, ring->prod);
+       en_dbg(DRV, priv, "Freeing Rx buf - cons:%d prod:%d\n",
+              ring->cons, ring->prod);
 
        /* Unmap and free Rx buffers */
        BUG_ON((u32) (ring->prod - ring->cons) > ring->actual_size);
        while (ring->cons != ring->prod) {
                index = ring->cons & ring->size_mask;
-               mlx4_dbg(DRV, priv, "Processing descriptor:%d\n", index);
+               en_dbg(DRV, priv, "Processing descriptor:%d\n", index);
                mlx4_en_free_rx_desc(priv, ring, index);
                ++ring->cons;
        }
@@ -373,10 +371,10 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
                                        sizeof(struct skb_frag_struct));
        ring->rx_info = vmalloc(tmp);
        if (!ring->rx_info) {
-               mlx4_err(mdev, "Failed allocating rx_info ring\n");
+               en_err(priv, "Failed allocating rx_info ring\n");
                return -ENOMEM;
        }
-       mlx4_dbg(DRV, priv, "Allocated rx_info ring at addr:%p size:%d\n",
+       en_dbg(DRV, priv, "Allocated rx_info ring at addr:%p size:%d\n",
                 ring->rx_info, tmp);
 
        err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres,
@@ -386,7 +384,7 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
 
        err = mlx4_en_map_buffer(&ring->wqres.buf);
        if (err) {
-               mlx4_err(mdev, "Failed to map RX buffer\n");
+               en_err(priv, "Failed to map RX buffer\n");
                goto err_hwq;
        }
        ring->buf = ring->wqres.buf.direct.buf;
@@ -404,7 +402,7 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
                                    sizeof(struct net_lro_desc),
                                    GFP_KERNEL);
        if (!ring->lro.lro_arr) {
-               mlx4_err(mdev, "Failed to allocate lro array\n");
+               en_err(priv, "Failed to allocate lro array\n");
                goto err_map;
        }
        ring->lro.get_frag_header = mlx4_en_get_frag_header;
@@ -455,7 +453,7 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv)
                /* Initialize page allocators */
                err = mlx4_en_init_allocator(priv, ring);
                if (err) {
-                       mlx4_err(mdev, "Failed initializing ring allocator\n");
+                       en_err(priv, "Failed initializing ring allocator\n");
                        ring_ind--;
                        goto err_allocator;
                }
@@ -486,7 +484,7 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv)
                err = mlx4_srq_alloc(mdev->dev, mdev->priv_pdn, &ring->wqres.mtt,
                                     ring->wqres.db.dma, &ring->srq);
                if (err){
-                       mlx4_err(mdev, "Failed to allocate srq\n");
+                       en_err(priv, "Failed to allocate srq\n");
                        ring_ind--;
                        goto err_srq;
                }
@@ -601,7 +599,7 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv,
 
        skb = dev_alloc_skb(SMALL_PACKET_SIZE + NET_IP_ALIGN);
        if (!skb) {
-               mlx4_dbg(RX_ERR, priv, "Failed allocating skb\n");
+               en_dbg(RX_ERR, priv, "Failed allocating skb\n");
                return NULL;
        }
        skb->dev = priv->dev;
@@ -680,7 +678,6 @@ static void mlx4_en_copy_desc(struct mlx4_en_priv *priv,
 int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
-       struct mlx4_en_dev *mdev = priv->mdev;
        struct mlx4_cqe *cqe;
        struct mlx4_en_rx_ring *ring = &priv->rx_ring[cq->ring];
        struct skb_frag_struct *skb_frags;
@@ -717,14 +714,14 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
                /* Drop packet on bad receive or bad checksum */
                if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) ==
                                                MLX4_CQE_OPCODE_ERROR)) {
-                       mlx4_err(mdev, "CQE completed in error - vendor "
+                       en_err(priv, "CQE completed in error - vendor "
                                  "syndrom:%d syndrom:%d\n",
                                  ((struct mlx4_err_cqe *) cqe)->vendor_err_syndrome,
                                  ((struct mlx4_err_cqe *) cqe)->syndrome);
                        goto next;
                }
                if (unlikely(cqe->badfcs_enc & MLX4_CQE_BAD_FCS)) {
-                       mlx4_dbg(RX_ERR, priv, "Accepted frame with bad FCS\n");
+                       en_dbg(RX_ERR, priv, "Accepted frame with bad FCS\n");
                        goto next;
                }
 
@@ -874,7 +871,7 @@ static int mlx4_en_last_alloc_offset(struct mlx4_en_priv *priv, u16 stride, u16
        u16 res = MLX4_EN_ALLOC_SIZE % stride;
        u16 offset = MLX4_EN_ALLOC_SIZE - stride - res + align;
 
-       mlx4_dbg(DRV, priv, "Calculated last offset for stride:%d align:%d "
+       en_dbg(DRV, priv, "Calculated last offset for stride:%d align:%d "
                            "res:%d offset:%d\n", stride, align, res, offset);
        return offset;
 }
@@ -919,10 +916,10 @@ void mlx4_en_calc_rx_buf(struct net_device *dev)
        priv->rx_skb_size = eff_mtu;
        priv->log_rx_info = ROUNDUP_LOG2(i * sizeof(struct skb_frag_struct));
 
-       mlx4_dbg(DRV, priv, "Rx buffer scatter-list (effective-mtu:%d "
+       en_dbg(DRV, priv, "Rx buffer scatter-list (effective-mtu:%d "
                  "num_frags:%d):\n", eff_mtu, priv->num_frags);
        for (i = 0; i < priv->num_frags; i++) {
-               mlx4_dbg(DRV, priv, "  frag:%d - size:%d prefix:%d align:%d "
+               en_dbg(DRV, priv, "  frag:%d - size:%d prefix:%d align:%d "
                                "stride:%d last_offset:%d\n", i,
                                priv->frag_info[i].frag_size,
                                priv->frag_info[i].frag_prefix_size,
@@ -942,12 +939,12 @@ void mlx4_en_set_default_rss_map(struct mlx4_en_priv *priv,
        int i;
 
        rss_map->size = roundup_pow_of_two(num_entries);
-       mlx4_dbg(DRV, priv, "Setting default RSS map of %d entires\n",
-                rss_map->size);
+       en_dbg(DRV, priv, "Setting default RSS map of %d entires\n",
+              rss_map->size);
 
        for (i = 0; i < rss_map->size; i++) {
                rss_map->map[i] = i % num_rings;
-               mlx4_dbg(DRV, priv, "Entry %d ---> ring %d\n", i, rss_map->map[i]);
+               en_dbg(DRV, priv, "Entry %d ---> ring %d\n", i, rss_map->map[i]);
        }
 }
 
@@ -962,13 +959,13 @@ static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv,
 
        context = kmalloc(sizeof *context , GFP_KERNEL);
        if (!context) {
-               mlx4_err(mdev, "Failed to allocate qp context\n");
+               en_err(priv, "Failed to allocate qp context\n");
                return -ENOMEM;
        }
 
        err = mlx4_qp_alloc(mdev->dev, qpn, qp);
        if (err) {
-               mlx4_err(mdev, "Failed to allocate qp #%d\n", qpn);
+               en_err(priv, "Failed to allocate qp #%x\n", qpn);
                goto out;
        }
        qp->event = mlx4_en_sqp_event;
@@ -1000,12 +997,11 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv)
        int err = 0;
        int good_qps = 0;
 
-       mlx4_dbg(DRV, priv, "Configuring rss steering for port %u\n", priv->port);
+       en_dbg(DRV, priv, "Configuring rss steering\n");
        err = mlx4_qp_reserve_range(mdev->dev, rss_map->size,
                                    rss_map->size, &rss_map->base_qpn);
        if (err) {
-               mlx4_err(mdev, "Failed reserving %d qps for port %u\n",
-                        rss_map->size, priv->port);
+               en_err(priv, "Failed reserving %d qps\n", rss_map->size);
                return err;
        }
 
@@ -1025,13 +1021,13 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv)
        /* Configure RSS indirection qp */
        err = mlx4_qp_reserve_range(mdev->dev, 1, 1, &priv->base_qpn);
        if (err) {
-               mlx4_err(mdev, "Failed to reserve range for RSS "
-                              "indirection qp\n");
+               en_err(priv, "Failed to reserve range for RSS "
+                            "indirection qp\n");
                goto rss_err;
        }
        err = mlx4_qp_alloc(mdev->dev, priv->base_qpn, &rss_map->indir_qp);
        if (err) {
-               mlx4_err(mdev, "Failed to allocate RSS indirection QP\n");
+               en_err(priv, "Failed to allocate RSS indirection QP\n");
                goto reserve_err;
        }
        rss_map->indir_qp.event = mlx4_en_sqp_event;
index ac6fc49..5dc7466 100644 (file)
@@ -68,15 +68,15 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
        tmp = size * sizeof(struct mlx4_en_tx_info);
        ring->tx_info = vmalloc(tmp);
        if (!ring->tx_info) {
-               mlx4_err(mdev, "Failed allocating tx_info ring\n");
+               en_err(priv, "Failed allocating tx_info ring\n");
                return -ENOMEM;
        }
-       mlx4_dbg(DRV, priv, "Allocated tx_info ring at addr:%p size:%d\n",
+       en_dbg(DRV, priv, "Allocated tx_info ring at addr:%p size:%d\n",
                 ring->tx_info, tmp);
 
        ring->bounce_buf = kmalloc(MAX_DESC_SIZE, GFP_KERNEL);
        if (!ring->bounce_buf) {
-               mlx4_err(mdev, "Failed allocating bounce buffer\n");
+               en_err(priv, "Failed allocating bounce buffer\n");
                err = -ENOMEM;
                goto err_tx;
        }
@@ -85,31 +85,31 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
        err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres, ring->buf_size,
                                 2 * PAGE_SIZE);
        if (err) {
-               mlx4_err(mdev, "Failed allocating hwq resources\n");
+               en_err(priv, "Failed allocating hwq resources\n");
                goto err_bounce;
        }
 
        err = mlx4_en_map_buffer(&ring->wqres.buf);
        if (err) {
-               mlx4_err(mdev, "Failed to map TX buffer\n");
+               en_err(priv, "Failed to map TX buffer\n");
                goto err_hwq_res;
        }
 
        ring->buf = ring->wqres.buf.direct.buf;
 
-       mlx4_dbg(DRV, priv, "Allocated TX ring (addr:%p) - buf:%p size:%d "
-                "buf_size:%d dma:%llx\n", ring, ring->buf, ring->size,
-                ring->buf_size, (unsigned long long) ring->wqres.buf.direct.map);
+       en_dbg(DRV, priv, "Allocated TX ring (addr:%p) - buf:%p size:%d "
+              "buf_size:%d dma:%llx\n", ring, ring->buf, ring->size,
+              ring->buf_size, (unsigned long long) ring->wqres.buf.direct.map);
 
        err = mlx4_qp_reserve_range(mdev->dev, 1, 1, &ring->qpn);
        if (err) {
-               mlx4_err(mdev, "Failed reserving qp for tx ring.\n");
+               en_err(priv, "Failed reserving qp for tx ring.\n");
                goto err_map;
        }
 
        err = mlx4_qp_alloc(mdev->dev, ring->qpn, &ring->qp);
        if (err) {
-               mlx4_err(mdev, "Failed allocating qp %d\n", ring->qpn);
+               en_err(priv, "Failed allocating qp %d\n", ring->qpn);
                goto err_reserve;
        }
        ring->qp.event = mlx4_en_sqp_event;
@@ -135,7 +135,7 @@ void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv,
                             struct mlx4_en_tx_ring *ring)
 {
        struct mlx4_en_dev *mdev = priv->mdev;
-       mlx4_dbg(DRV, priv, "Destroying tx ring, qpn: %d\n", ring->qpn);
+       en_dbg(DRV, priv, "Destroying tx ring, qpn: %d\n", ring->qpn);
 
        mlx4_qp_remove(mdev->dev, &ring->qp);
        mlx4_qp_free(mdev->dev, &ring->qp);
@@ -274,12 +274,12 @@ int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring)
 
        /* Skip last polled descriptor */
        ring->cons += ring->last_nr_txbb;
-       mlx4_dbg(DRV, priv, "Freeing Tx buf - cons:0x%x prod:0x%x\n",
+       en_dbg(DRV, priv, "Freeing Tx buf - cons:0x%x prod:0x%x\n",
                 ring->cons, ring->prod);
 
        if ((u32) (ring->prod - ring->cons) > ring->size) {
                if (netif_msg_tx_err(priv))
-                       mlx4_warn(priv->mdev, "Tx consumer passed producer!\n");
+                       en_warn(priv, "Tx consumer passed producer!\n");
                return 0;
        }
 
@@ -292,39 +292,11 @@ int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring)
        }
 
        if (cnt)
-               mlx4_dbg(DRV, priv, "Freed %d uncompleted tx descriptors\n", cnt);
+               en_dbg(DRV, priv, "Freed %d uncompleted tx descriptors\n", cnt);
 
        return cnt;
 }
 
-void mlx4_en_set_prio_map(struct mlx4_en_priv *priv, u16 *prio_map, u32 ring_num)
-{
-       int block = 8 / ring_num;
-       int extra = 8 - (block * ring_num);
-       int num = 0;
-       u16 ring = 1;
-       int prio;
-
-       if (ring_num == 1) {
-               for (prio = 0; prio < 8; prio++)
-                       prio_map[prio] = 0;
-               return;
-       }
-
-       for (prio = 0; prio < 8; prio++) {
-               if (extra && (num == block + 1)) {
-                       ring++;
-                       num = 0;
-                       extra--;
-               } else if (!extra && (num == block)) {
-                       ring++;
-                       num = 0;
-               }
-               prio_map[prio] = ring;
-               mlx4_dbg(DRV, priv, " prio:%d --> ring:%d\n", prio, ring);
-               num++;
-       }
-}
 
 static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
 {
@@ -386,18 +358,8 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
        if (unlikely(ring->blocked)) {
                if ((u32) (ring->prod - ring->cons) <=
                     ring->size - HEADROOM - MAX_DESC_TXBBS) {
-
-                       /* TODO: support multiqueue netdevs. Currently, we block
-                        * when *any* ring is full. Note that:
-                        * - 2 Tx rings can unblock at the same time and call
-                        *   netif_wake_queue(), which is OK since this
-                        *   operation is idempotent.
-                        * - We might wake the queue just after another ring
-                        *   stopped it. This is no big deal because the next
-                        *   transmission on that ring would stop the queue.
-                        */
                        ring->blocked = 0;
-                       netif_wake_queue(dev);
+                       netif_tx_wake_queue(netdev_get_tx_queue(dev, cq->ring));
                        priv->port_stats.wake_queue++;
                }
        }
@@ -426,7 +388,7 @@ void mlx4_en_poll_tx_cq(unsigned long data)
 
        INC_PERF_COUNTER(priv->pstats.tx_poll);
 
-       if (!spin_trylock(&ring->comp_lock)) {
+       if (!spin_trylock_irq(&ring->comp_lock)) {
                mod_timer(&cq->timer, jiffies + MLX4_EN_TX_POLL_TIMEOUT);
                return;
        }
@@ -439,7 +401,7 @@ void mlx4_en_poll_tx_cq(unsigned long data)
        if (inflight && priv->port_up)
                mod_timer(&cq->timer, jiffies + MLX4_EN_TX_POLL_TIMEOUT);
 
-       spin_unlock(&ring->comp_lock);
+       spin_unlock_irq(&ring->comp_lock);
 }
 
 static struct mlx4_en_tx_desc *mlx4_en_bounce_to_desc(struct mlx4_en_priv *priv,
@@ -482,9 +444,9 @@ static inline void mlx4_en_xmit_poll(struct mlx4_en_priv *priv, int tx_ind)
 
        /* Poll the CQ every mlx4_en_TX_MODER_POLL packets */
        if ((++ring->poll_cnt & (MLX4_EN_TX_POLL_MODER - 1)) == 0)
-               if (spin_trylock(&ring->comp_lock)) {
+               if (spin_trylock_irq(&ring->comp_lock)) {
                        mlx4_en_process_tx_cq(priv->dev, cq);
-                       spin_unlock(&ring->comp_lock);
+                       spin_unlock_irq(&ring->comp_lock);
                }
 }
 
@@ -539,7 +501,6 @@ static int get_real_size(struct sk_buff *skb, struct net_device *dev,
                         int *lso_header_size)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
-       struct mlx4_en_dev *mdev = priv->mdev;
        int real_size;
 
        if (skb_is_gso(skb)) {
@@ -553,14 +514,14 @@ static int get_real_size(struct sk_buff *skb, struct net_device *dev,
                                real_size += DS_SIZE;
                        else {
                                if (netif_msg_tx_err(priv))
-                                       mlx4_warn(mdev, "Non-linear headers\n");
+                                       en_warn(priv, "Non-linear headers\n");
                                dev_kfree_skb_any(skb);
                                return 0;
                        }
                }
                if (unlikely(*lso_header_size > MAX_LSO_HDR_SIZE)) {
                        if (netif_msg_tx_err(priv))
-                               mlx4_warn(mdev, "LSO header size too big\n");
+                               en_warn(priv, "LSO header size too big\n");
                        dev_kfree_skb_any(skb);
                        return 0;
                }
@@ -617,21 +578,20 @@ static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct sk_buff *sk
        tx_desc->ctrl.fence_size = (real_size / 16) & 0x3f;
 }
 
-static int get_vlan_info(struct mlx4_en_priv *priv, struct sk_buff *skb,
-                        u16 *vlan_tag)
+u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb)
 {
-       int tx_ind;
+       struct mlx4_en_priv *priv = netdev_priv(dev);
+       u16 vlan_tag = 0;
 
-       /* Obtain VLAN information if present */
-       if (priv->vlgrp && vlan_tx_tag_present(skb)) {
-               *vlan_tag = vlan_tx_tag_get(skb);
-               /* Set the Tx ring to use according to vlan priority */
-               tx_ind = priv->tx_prio_map[*vlan_tag >> 13];
-       } else {
-               *vlan_tag = 0;
-               tx_ind = 0;
+       /* If we support per priority flow control and the packet contains
+        * a vlan tag, send the packet to the TX ring assigned to that priority
+        */
+       if (priv->prof->rx_ppp && priv->vlgrp && vlan_tx_tag_present(skb)) {
+               vlan_tag = vlan_tx_tag_get(skb);
+               return MLX4_EN_NUM_TX_RINGS + (vlan_tag >> 13);
        }
-       return tx_ind;
+
+       return skb_tx_hash(dev, skb);
 }
 
 int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -651,7 +611,7 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
        dma_addr_t dma;
        u32 index;
        __be32 op_own;
-       u16 vlan_tag;
+       u16 vlan_tag = 0;
        int i;
        int lso_header_size;
        void *fragptr;
@@ -669,20 +629,21 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
        nr_txbb = desc_size / TXBB_SIZE;
        if (unlikely(nr_txbb > MAX_DESC_TXBBS)) {
                if (netif_msg_tx_err(priv))
-                       mlx4_warn(mdev, "Oversized header or SG list\n");
+                       en_warn(priv, "Oversized header or SG list\n");
                dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
-       tx_ind = get_vlan_info(priv, skb, &vlan_tag);
+       tx_ind = skb->queue_mapping;
        ring = &priv->tx_ring[tx_ind];
+       if (priv->vlgrp && vlan_tx_tag_present(skb))
+               vlan_tag = vlan_tx_tag_get(skb);
 
        /* Check available TXBBs And 2K spare for prefetch */
        if (unlikely(((int)(ring->prod - ring->cons)) >
                     ring->size - HEADROOM - MAX_DESC_TXBBS)) {
-               /* every full Tx ring stops queue.
-                * TODO: implement multi-queue support (per-queue stop) */
-               netif_stop_queue(dev);
+               /* every full Tx ring stops queue */
+               netif_tx_stop_queue(netdev_get_tx_queue(dev, tx_ind));
                ring->blocked = 1;
                priv->port_stats.queue_stopped++;
 
@@ -695,7 +656,7 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Now that we know what Tx ring to use */
        if (unlikely(!priv->port_up)) {
                if (netif_msg_tx_err(priv))
-                       mlx4_warn(mdev, "xmit: port down!\n");
+                       en_warn(priv, "xmit: port down!\n");
                dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
@@ -819,7 +780,6 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Ring doorbell! */
        wmb();
        writel(ring->doorbell_qpn, mdev->uar_map + MLX4_SEND_DOORBELL);
-       dev->trans_start = jiffies;
 
        /* Poll CQ here */
        mlx4_en_xmit_poll(priv, tx_ind);
index 8830dcb..dee1887 100644 (file)
@@ -623,8 +623,10 @@ int mlx4_init_eq_table(struct mlx4_dev *dev)
                err = mlx4_create_eq(dev, dev->caps.num_cqs + MLX4_NUM_SPARE_EQE,
                                     (dev->flags & MLX4_FLAG_MSI_X) ? i : 0,
                                     &priv->eq_table.eq[i]);
-               if (err)
+               if (err) {
+                       --i;
                        goto err_out_unmap;
+               }
        }
 
        err = mlx4_create_eq(dev, MLX4_NUM_ASYNC_EQE + MLX4_NUM_SPARE_EQE,
index ef840ab..d43a9e4 100644 (file)
 #include "en_port.h"
 
 #define DRV_NAME       "mlx4_en"
-#define DRV_VERSION    "1.4.0"
-#define DRV_RELDATE    "Sep 2008"
+#define DRV_VERSION    "1.4.1.1"
+#define DRV_RELDATE    "June 2009"
 
 
 #define MLX4_EN_MSG_LEVEL      (NETIF_MSG_LINK | NETIF_MSG_IFDOWN)
 
-#define mlx4_dbg(mlevel, priv, format, arg...) \
-       if (NETIF_MSG_##mlevel & priv->msg_enable) \
-       printk(KERN_DEBUG "%s %s: " format , DRV_NAME ,\
-               (dev_name(&priv->mdev->pdev->dev)) , ## arg)
+#define en_print(level, priv, format, arg...)                  \
+       {                                                       \
+       if ((priv)->registered)                                 \
+               printk(level "%s: %s: " format, DRV_NAME,       \
+                       (priv->dev)->name, ## arg);             \
+       else                                                    \
+               printk(level "%s: %s: Port %d: " format,        \
+                       DRV_NAME, dev_name(&priv->mdev->pdev->dev), \
+                       (priv)->port, ## arg);                  \
+       }
+
+#define en_dbg(mlevel, priv, format, arg...)                   \
+       {                                                       \
+       if (NETIF_MSG_##mlevel & priv->msg_enable)              \
+               en_print(KERN_DEBUG, priv, format, ## arg)      \
+       }
+#define en_warn(priv, format, arg...)                          \
+       en_print(KERN_WARNING, priv, format, ## arg)
+#define en_err(priv, format, arg...)                           \
+       en_print(KERN_ERR, priv, format, ## arg)
 
 #define mlx4_err(mdev, format, arg...) \
        printk(KERN_ERR "%s %s: " format , DRV_NAME ,\
-               (dev_name(&mdev->pdev->dev)) , ## arg)
+               dev_name(&mdev->pdev->dev) , ## arg)
 #define mlx4_info(mdev, format, arg...) \
        printk(KERN_INFO "%s %s: " format , DRV_NAME ,\
-               (dev_name(&mdev->pdev->dev)) , ## arg)
+               dev_name(&mdev->pdev->dev) , ## arg)
 #define mlx4_warn(mdev, format, arg...) \
        printk(KERN_WARNING "%s %s: " format , DRV_NAME ,\
-               (dev_name(&mdev->pdev->dev)) , ## arg)
+               dev_name(&mdev->pdev->dev) , ## arg)
 
 /*
  * Device constants
@@ -123,12 +139,14 @@ enum {
 #define MLX4_EN_MIN_RX_SIZE    (MLX4_EN_ALLOC_SIZE / SMP_CACHE_BYTES)
 #define MLX4_EN_MIN_TX_SIZE    (4096 / TXBB_SIZE)
 
-#define MLX4_EN_TX_RING_NUM            9
-#define MLX4_EN_DEF_TX_RING_SIZE       1024
+#define MLX4_EN_SMALL_PKT_SIZE         64
+#define MLX4_EN_NUM_TX_RINGS           8
+#define MLX4_EN_NUM_PPP_RINGS          8
+#define MLX4_EN_DEF_TX_RING_SIZE       512
 #define MLX4_EN_DEF_RX_RING_SIZE       1024
 
-/* Target number of bytes to coalesce with interrupt moderation */
-#define MLX4_EN_RX_COAL_TARGET 0x20000
+/* Target number of packets to coalesce with interrupt moderation */
+#define MLX4_EN_RX_COAL_TARGET 44
 #define MLX4_EN_RX_COAL_TIME   0x10
 
 #define MLX4_EN_TX_COAL_PKTS   5
@@ -462,7 +480,6 @@ struct mlx4_en_priv {
        int base_qpn;
 
        struct mlx4_en_rss_map rss_map;
-       u16 tx_prio_map[8];
        u32 flags;
 #define MLX4_EN_FLAG_PROMISC   0x1
        u32 tx_ring_num;
@@ -500,8 +517,6 @@ void mlx4_en_stop_port(struct net_device *dev);
 void mlx4_en_free_resources(struct mlx4_en_priv *priv);
 int mlx4_en_alloc_resources(struct mlx4_en_priv *priv);
 
-int mlx4_en_get_profile(struct mlx4_en_dev *mdev);
-
 int mlx4_en_create_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
                      int entries, int ring, enum cq_type mode);
 void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq);
@@ -512,6 +527,7 @@ int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq);
 
 void mlx4_en_poll_tx_cq(unsigned long data);
 void mlx4_en_tx_irq(struct mlx4_cq *mcq);
+u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb);
 int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev);
 
 int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring,
@@ -546,7 +562,6 @@ void mlx4_en_calc_rx_buf(struct net_device *dev);
 void mlx4_en_set_default_rss_map(struct mlx4_en_priv *priv,
                                 struct mlx4_en_rss_map *rss_map,
                                 int num_entries, int num_rings);
-void mlx4_en_set_prio_map(struct mlx4_en_priv *priv, u16 *prio_map, u32 ring_num);
 int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv);
 void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv);
 int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring);
index 0caf74c..0a46778 100644 (file)
@@ -402,7 +402,8 @@ static int mlx4_write_mtt_chunk(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
        for (i = 0; i < npages; ++i)
                mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT);
 
-       dma_sync_single(&dev->pdev->dev, dma_handle, npages * sizeof (u64), DMA_TO_DEVICE);
+       dma_sync_single_for_cpu(&dev->pdev->dev, dma_handle,
+                               npages * sizeof (u64), DMA_TO_DEVICE);
 
        return 0;
 }
@@ -549,8 +550,8 @@ int mlx4_map_phys_fmr(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u64 *page_list
        for (i = 0; i < npages; ++i)
                fmr->mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT);
 
-       dma_sync_single(&dev->pdev->dev, fmr->dma_handle,
-                       npages * sizeof(u64), DMA_TO_DEVICE);
+       dma_sync_single_for_cpu(&dev->pdev->dev, fmr->dma_handle,
+                               npages * sizeof(u64), DMA_TO_DEVICE);
 
        fmr->mpt->key    = cpu_to_be32(key);
        fmr->mpt->lkey   = cpu_to_be32(key);
index 1361ddc..b4e18a5 100644 (file)
@@ -55,6 +55,7 @@
 #include <linux/types.h>
 #include <linux/inet_lro.h>
 #include <asm/system.h>
+#include <linux/list.h>
 
 static char mv643xx_eth_driver_name[] = "mv643xx_eth";
 static char mv643xx_eth_driver_version[] = "1.4";
@@ -1721,20 +1722,20 @@ static void uc_addr_set(struct mv643xx_eth_private *mp, unsigned char *addr)
 
 static u32 uc_addr_filter_mask(struct net_device *dev)
 {
-       struct dev_addr_list *uc_ptr;
+       struct netdev_hw_addr *ha;
        u32 nibbles;
 
        if (dev->flags & IFF_PROMISC)
                return 0;
 
        nibbles = 1 << (dev->dev_addr[5] & 0x0f);
-       for (uc_ptr = dev->uc_list; uc_ptr != NULL; uc_ptr = uc_ptr->next) {
-               if (memcmp(dev->dev_addr, uc_ptr->da_addr, 5))
+       list_for_each_entry(ha, &dev->uc_list, list) {
+               if (memcmp(dev->dev_addr, ha->addr, 5))
                        return 0;
-               if ((dev->dev_addr[5] ^ uc_ptr->da_addr[5]) & 0xf0)
+               if ((dev->dev_addr[5] ^ ha->addr[5]) & 0xf0)
                        return 0;
 
-               nibbles |= 1 << (uc_ptr->da_addr[5] & 0x0f);
+               nibbles |= 1 << (ha->addr[5] & 0x0f);
        }
 
        return nibbles;
index 7e28b46..c9a30d3 100644 (file)
@@ -2892,7 +2892,6 @@ again:
                tx->stop_queue++;
                netif_tx_stop_queue(netdev_queue);
        }
-       dev->trans_start = jiffies;
        return 0;
 
 abort_linearize:
index 4a51c31..6f77ad5 100644 (file)
@@ -178,10 +178,8 @@ void netxen_free_sw_resources(struct netxen_adapter *adapter)
 
        for (ring = 0; ring < adapter->max_rds_rings; ring++) {
                rds_ring = &recv_ctx->rds_rings[ring];
-               if (rds_ring->rx_buf_arr) {
-                       vfree(rds_ring->rx_buf_arr);
-                       rds_ring->rx_buf_arr = NULL;
-               }
+               vfree(rds_ring->rx_buf_arr);
+               rds_ring->rx_buf_arr = NULL;
        }
        kfree(recv_ctx->rds_rings);
 
@@ -190,8 +188,7 @@ skip_rds:
                return;
 
        tx_ring = adapter->tx_ring;
-       if (tx_ring->cmd_buf_arr)
-               vfree(tx_ring->cmd_buf_arr);
+       vfree(tx_ring->cmd_buf_arr);
 }
 
 int netxen_alloc_sw_resources(struct netxen_adapter *adapter)
index 50477f5..98737ef 100644 (file)
@@ -1496,7 +1496,6 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        netxen_nic_update_cmd_producer(adapter, tx_ring, producer);
 
        adapter->stats.xmitcalled++;
-       netdev->trans_start = jiffies;
 
        return NETDEV_TX_OK;
 
index 0d9de5a..fa61a12 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/log2.h>
 #include <linux/jiffies.h>
 #include <linux/crc32.h>
+#include <linux/list.h>
 
 #include <linux/io.h>
 
@@ -6362,6 +6363,7 @@ static void niu_set_rx_mode(struct net_device *dev)
        struct niu *np = netdev_priv(dev);
        int i, alt_cnt, err;
        struct dev_addr_list *addr;
+       struct netdev_hw_addr *ha;
        unsigned long flags;
        u16 hash[16] = { 0, };
 
@@ -6383,9 +6385,8 @@ static void niu_set_rx_mode(struct net_device *dev)
        if (alt_cnt) {
                int index = 0;
 
-               for (addr = dev->uc_list; addr; addr = addr->next) {
-                       err = niu_set_alt_mac(np, index,
-                                             addr->da_addr);
+               list_for_each_entry(ha, &dev->uc_list, list) {
+                       err = niu_set_alt_mac(np, index, ha->addr);
                        if (err)
                                printk(KERN_WARNING PFX "%s: Error %d "
                                       "adding alt mac %d\n",
@@ -6777,8 +6778,6 @@ static int niu_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        netif_tx_wake_queue(txq);
        }
 
-       dev->trans_start = jiffies;
-
 out:
        return NETDEV_TX_OK;
 
index d531614..940962a 100644 (file)
@@ -1204,9 +1204,7 @@ again:
        if (stopped && (dev->tx_done_idx != tx_done_idx) && start_tx_okay(dev))
                netif_start_queue(ndev);
 
-       /* set the transmit start time to catch transmit timeouts */
-       ndev->trans_start = jiffies;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void ns83820_update_stats(struct ns83820 *dev)
@@ -1626,7 +1624,7 @@ static void ns83820_tx_watch(unsigned long data)
                );
 #endif
 
-       if (time_after(jiffies, ndev->trans_start + 1*HZ) &&
+       if (time_after(jiffies, dev_trans_start(ndev) + 1*HZ) &&
            dev->tx_done_idx != dev->tx_free_idx) {
                printk(KERN_DEBUG "%s: ns83820_tx_watch: %u %u %d\n",
                        ndev->name,
index 7a3ec9d..dd6f54d 100644 (file)
@@ -243,6 +243,7 @@ static int m88e1111_config_init(struct phy_device *phydev)
 
                temp &= ~(MII_M1111_HWCFG_MODE_MASK);
                temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK;
+               temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO;
 
                err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
                if (err < 0)
index 5981deb..e7935d0 100644 (file)
@@ -433,8 +433,7 @@ static void pppol2tp_recv_dequeue_skb(struct pppol2tp_session *session, struct s
                 *   to the inner packet either
                 */
                secpath_reset(skb);
-               dst_release(skb->dst);
-               skb->dst = NULL;
+               skb_dst_drop(skb);
                nf_reset(skb);
 
                po = pppox_sk(session_sock);
@@ -976,7 +975,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh
        /* Calculate UDP checksum if configured to do so */
        if (sk_tun->sk_no_check == UDP_CSUM_NOXMIT)
                skb->ip_summed = CHECKSUM_NONE;
-       else if (!(skb->dst->dev->features & NETIF_F_V4_CSUM)) {
+       else if (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM)) {
                skb->ip_summed = CHECKSUM_COMPLETE;
                csum = skb_checksum(skb, 0, udp_len, 0);
                uh->check = csum_tcpudp_magic(inet->saddr, inet->daddr,
@@ -1172,14 +1171,14 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
        nf_reset(skb);
 
        /* Get routing info from the tunnel socket */
-       dst_release(skb->dst);
-       skb->dst = dst_clone(__sk_dst_get(sk_tun));
+       skb_dst_drop(skb);
+       skb_dst_set(skb, dst_clone(__sk_dst_get(sk_tun)));
        pppol2tp_skb_set_owner_w(skb, sk_tun);
 
        /* Calculate UDP checksum if configured to do so */
        if (sk_tun->sk_no_check == UDP_CSUM_NOXMIT)
                skb->ip_summed = CHECKSUM_NONE;
-       else if (!(skb->dst->dev->features & NETIF_F_V4_CSUM)) {
+       else if (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM)) {
                skb->ip_summed = CHECKSUM_COMPLETE;
                csum = skb_checksum(skb, 0, udp_len, 0);
                uh->check = csum_tcpudp_magic(inet->saddr, inet->daddr,
index cadc32c..8a823ec 100644 (file)
@@ -2617,7 +2617,6 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
                            &port_regs->CommonRegs.reqQProducerIndex,
                            qdev->req_producer_index);
 
-       ndev->trans_start = jiffies;
        if (netif_msg_tx_queued(qdev))
                printk(KERN_DEBUG PFX "%s: tx queued, slot %d, len %d\n",
                       ndev->name, qdev->req_producer_index, skb->len);
index fcb159e..156e02e 100644 (file)
@@ -27,6 +27,8 @@
                           "%s: " fmt, __func__, ##args);  \
        } while (0)
 
+#define WQ_ADDR_ALIGN  0x3     /* 4 byte alignment */
+
 #define QLGE_VENDOR_ID    0x1077
 #define QLGE_DEVICE_ID_8012    0x8012
 #define QLGE_DEVICE_ID_8000    0x8000
 
 #define NUM_SMALL_BUFFERS   512
 #define NUM_LARGE_BUFFERS   512
+#define DB_PAGE_SIZE 4096
+
+/* Calculate the number of (4k) pages required to
+ * contain a buffer queue of the given length.
+ */
+#define MAX_DB_PAGES_PER_BQ(x) \
+               (((x * sizeof(u64)) / DB_PAGE_SIZE) + \
+               (((x * sizeof(u64)) % DB_PAGE_SIZE) ? 1 : 0))
 
+#define RX_RING_SHADOW_SPACE   (sizeof(u64) + \
+               MAX_DB_PAGES_PER_BQ(NUM_SMALL_BUFFERS) * sizeof(u64) + \
+               MAX_DB_PAGES_PER_BQ(NUM_LARGE_BUFFERS) * sizeof(u64))
 #define SMALL_BUFFER_SIZE 256
 #define LARGE_BUFFER_SIZE      PAGE_SIZE
 #define MAX_SPLIT_SIZE 1023
@@ -50,7 +63,7 @@
 #define MAX_INTER_FRAME_WAIT 10        /* 10 usec max interframe-wait for coalescing */
 #define DFLT_INTER_FRAME_WAIT (MAX_INTER_FRAME_WAIT/2)
 #define UDELAY_COUNT 3
-#define UDELAY_DELAY 10
+#define UDELAY_DELAY 100
 
 
 #define TX_DESC_PER_IOCB 8
 #define TX_DESC_PER_OAL 0
 #endif
 
-#define DB_PAGE_SIZE 4096
+/* MPI test register definitions. This register
+ * is used for determining alternate NIC function's
+ * PCI->func number.
+ */
+enum {
+       MPI_TEST_FUNC_PORT_CFG = 0x1002,
+       MPI_TEST_NIC1_FUNC_SHIFT = 1,
+       MPI_TEST_NIC2_FUNC_SHIFT = 5,
+       MPI_TEST_NIC_FUNC_MASK = 0x00000007,
+};
 
 /*
  * Processor Address Register (PROC_ADDR) bit definitions.
@@ -1430,7 +1452,10 @@ struct ql_adapter {
 
        /* Hardware information */
        u32 chip_rev_id;
+       u32 fw_rev_id;
        u32 func;               /* PCI function for this adapter */
+       u32 alt_func;           /* PCI function for alternate adapter */
+       u32 port;               /* Port number this adapter */
 
        spinlock_t adapter_lock;
        spinlock_t hw_lock;
@@ -1580,6 +1605,8 @@ void ql_mpi_idc_work(struct work_struct *work);
 void ql_mpi_port_cfg_work(struct work_struct *work);
 int ql_mb_get_fw_state(struct ql_adapter *qdev);
 int ql_cam_route_initialize(struct ql_adapter *qdev);
+int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data);
+int ql_mb_about_fw(struct ql_adapter *qdev);
 
 #if 1
 #define QL_ALL_DUMP
index 913b2a5..37c99fe 100644 (file)
@@ -293,7 +293,10 @@ static void ql_get_drvinfo(struct net_device *ndev,
        struct ql_adapter *qdev = netdev_priv(ndev);
        strncpy(drvinfo->driver, qlge_driver_name, 32);
        strncpy(drvinfo->version, qlge_driver_version, 32);
-       strncpy(drvinfo->fw_version, "N/A", 32);
+       snprintf(drvinfo->fw_version, 32, "v%d.%d.%d",
+                (qdev->fw_rev_id & 0x00ff0000) >> 16,
+                (qdev->fw_rev_id & 0x0000ff00) >> 8,
+                (qdev->fw_rev_id & 0x000000ff));
        strncpy(drvinfo->bus_info, pci_name(qdev->pdev), 32);
        drvinfo->n_stats = 0;
        drvinfo->testinfo_len = 0;
@@ -401,6 +404,7 @@ const struct ethtool_ops qlge_ethtool_ops = {
        .get_rx_csum = ql_get_rx_csum,
        .set_rx_csum = ql_set_rx_csum,
        .get_tx_csum = ethtool_op_get_tx_csum,
+       .set_tx_csum = ethtool_op_set_tx_csum,
        .get_sg = ethtool_op_get_sg,
        .set_sg = ethtool_op_set_sg,
        .get_tso = ethtool_op_get_tso,
index c92ced2..b9a5f59 100644 (file)
@@ -675,11 +675,12 @@ static int ql_get_8000_flash_params(struct ql_adapter *qdev)
        int status;
        __le32 *p = (__le32 *)&qdev->flash;
        u32 offset;
+       u8 mac_addr[6];
 
        /* Get flash offset for function and adjust
         * for dword access.
         */
-       if (!qdev->func)
+       if (!qdev->port)
                offset = FUNC0_FLASH_OFFSET / sizeof(u32);
        else
                offset = FUNC1_FLASH_OFFSET / sizeof(u32);
@@ -705,14 +706,26 @@ static int ql_get_8000_flash_params(struct ql_adapter *qdev)
                goto exit;
        }
 
-       if (!is_valid_ether_addr(qdev->flash.flash_params_8000.mac_addr)) {
+       /* Extract either manufacturer or BOFM modified
+        * MAC address.
+        */
+       if (qdev->flash.flash_params_8000.data_type1 == 2)
+               memcpy(mac_addr,
+                       qdev->flash.flash_params_8000.mac_addr1,
+                       qdev->ndev->addr_len);
+       else
+               memcpy(mac_addr,
+                       qdev->flash.flash_params_8000.mac_addr,
+                       qdev->ndev->addr_len);
+
+       if (!is_valid_ether_addr(mac_addr)) {
                QPRINTK(qdev, IFUP, ERR, "Invalid MAC address.\n");
                status = -EINVAL;
                goto exit;
        }
 
        memcpy(qdev->ndev->dev_addr,
-               qdev->flash.flash_params_8000.mac_addr,
+               mac_addr,
                qdev->ndev->addr_len);
 
 exit:
@@ -731,7 +744,7 @@ static int ql_get_8012_flash_params(struct ql_adapter *qdev)
        /* Second function's parameters follow the first
         * function's.
         */
-       if (qdev->func)
+       if (qdev->port)
                offset = size;
 
        if (ql_sem_spinlock(qdev, SEM_FLASH_MASK))
@@ -837,6 +850,13 @@ exit:
 static int ql_8000_port_initialize(struct ql_adapter *qdev)
 {
        int status;
+       /*
+        * Get MPI firmware version for driver banner
+        * and ethool info.
+        */
+       status = ql_mb_about_fw(qdev);
+       if (status)
+               goto exit;
        status = ql_mb_get_fw_state(qdev);
        if (status)
                goto exit;
@@ -1518,6 +1538,22 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev,
                return;
        }
 
+       /* Frame error, so drop the packet. */
+       if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) {
+               QPRINTK(qdev, DRV, ERR, "Receive error, flags2 = 0x%x\n",
+                                       ib_mac_rsp->flags2);
+               dev_kfree_skb_any(skb);
+               return;
+       }
+
+       /* The max framesize filter on this chip is set higher than
+        * MTU since FCoE uses 2k frames.
+        */
+       if (skb->len > ndev->mtu + ETH_HLEN) {
+               dev_kfree_skb_any(skb);
+               return;
+       }
+
        prefetch(skb->data);
        skb->dev = ndev;
        if (ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_M_MASK) {
@@ -1540,7 +1576,6 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev,
         * csum or frame errors.
         */
        if (qdev->rx_csum &&
-               !(ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) &&
                !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) {
                /* TCP frame. */
                if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) {
@@ -2108,7 +2143,6 @@ static int qlge_send(struct sk_buff *skb, struct net_device *ndev)
        wmb();
 
        ql_write_db_reg(tx_ring->prod_idx, tx_ring->prod_idx_db_reg);
-       ndev->trans_start = jiffies;
        QPRINTK(qdev, TX_QUEUED, DEBUG, "tx queued, slot %d, len %d\n",
                tx_ring->prod_idx, skb->len);
 
@@ -2203,7 +2237,7 @@ static int ql_alloc_tx_resources(struct ql_adapter *qdev,
                                 &tx_ring->wq_base_dma);
 
        if ((tx_ring->wq_base == NULL)
-           || tx_ring->wq_base_dma & (tx_ring->wq_size - 1)) {
+               || tx_ring->wq_base_dma & WQ_ADDR_ALIGN) {
                QPRINTK(qdev, IFUP, ERR, "tx_ring alloc failed.\n");
                return -ENOMEM;
        }
@@ -2518,14 +2552,16 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring)
 {
        struct cqicb *cqicb = &rx_ring->cqicb;
        void *shadow_reg = qdev->rx_ring_shadow_reg_area +
-           (rx_ring->cq_id * sizeof(u64) * 4);
+               (rx_ring->cq_id * RX_RING_SHADOW_SPACE);
        u64 shadow_reg_dma = qdev->rx_ring_shadow_reg_dma +
-           (rx_ring->cq_id * sizeof(u64) * 4);
+               (rx_ring->cq_id * RX_RING_SHADOW_SPACE);
        void __iomem *doorbell_area =
            qdev->doorbell_area + (DB_PAGE_SIZE * (128 + rx_ring->cq_id));
        int err = 0;
        u16 bq_len;
        u64 tmp;
+       __le64 *base_indirect_ptr;
+       int page_entries;
 
        /* Set up the shadow registers for this ring. */
        rx_ring->prod_idx_sh_reg = shadow_reg;
@@ -2534,8 +2570,8 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring)
        shadow_reg_dma += sizeof(u64);
        rx_ring->lbq_base_indirect = shadow_reg;
        rx_ring->lbq_base_indirect_dma = shadow_reg_dma;
-       shadow_reg += sizeof(u64);
-       shadow_reg_dma += sizeof(u64);
+       shadow_reg += (sizeof(u64) * MAX_DB_PAGES_PER_BQ(rx_ring->lbq_len));
+       shadow_reg_dma += (sizeof(u64) * MAX_DB_PAGES_PER_BQ(rx_ring->lbq_len));
        rx_ring->sbq_base_indirect = shadow_reg;
        rx_ring->sbq_base_indirect_dma = shadow_reg_dma;
 
@@ -2572,7 +2608,14 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring)
        if (rx_ring->lbq_len) {
                cqicb->flags |= FLAGS_LL;       /* Load lbq values */
                tmp = (u64)rx_ring->lbq_base_dma;;
-               *((__le64 *) rx_ring->lbq_base_indirect) = cpu_to_le64(tmp);
+               base_indirect_ptr = (__le64 *) rx_ring->lbq_base_indirect;
+               page_entries = 0;
+               do {
+                       *base_indirect_ptr = cpu_to_le64(tmp);
+                       tmp += DB_PAGE_SIZE;
+                       base_indirect_ptr++;
+                       page_entries++;
+               } while (page_entries < MAX_DB_PAGES_PER_BQ(rx_ring->lbq_len));
                cqicb->lbq_addr =
                    cpu_to_le64(rx_ring->lbq_base_indirect_dma);
                bq_len = (rx_ring->lbq_buf_size == 65536) ? 0 :
@@ -2589,7 +2632,14 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring)
        if (rx_ring->sbq_len) {
                cqicb->flags |= FLAGS_LS;       /* Load sbq values */
                tmp = (u64)rx_ring->sbq_base_dma;;
-               *((__le64 *) rx_ring->sbq_base_indirect) = cpu_to_le64(tmp);
+               base_indirect_ptr = (__le64 *) rx_ring->sbq_base_indirect;
+               page_entries = 0;
+               do {
+                       *base_indirect_ptr = cpu_to_le64(tmp);
+                       tmp += DB_PAGE_SIZE;
+                       base_indirect_ptr++;
+                       page_entries++;
+               } while (page_entries < MAX_DB_PAGES_PER_BQ(rx_ring->sbq_len));
                cqicb->sbq_addr =
                    cpu_to_le64(rx_ring->sbq_base_indirect_dma);
                cqicb->sbq_buf_size =
@@ -3186,9 +3236,10 @@ static void ql_display_dev_info(struct net_device *ndev)
        struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev);
 
        QPRINTK(qdev, PROBE, INFO,
-               "Function #%d, NIC Roll %d, NIC Rev = %d, "
+               "Function #%d, Port %d, NIC Roll %d, NIC Rev = %d, "
                "XG Roll = %d, XG Rev = %d.\n",
                qdev->func,
+               qdev->port,
                qdev->chip_rev_id & 0x0000000f,
                qdev->chip_rev_id >> 4 & 0x0000000f,
                qdev->chip_rev_id >> 8 & 0x0000000f,
@@ -3264,7 +3315,6 @@ static int ql_adapter_up(struct ql_adapter *qdev)
        err = ql_adapter_initialize(qdev);
        if (err) {
                QPRINTK(qdev, IFUP, INFO, "Unable to initialize adapter.\n");
-               spin_unlock(&qdev->hw_lock);
                goto err_init;
        }
        set_bit(QL_ADAPTER_UP, &qdev->flags);
@@ -3361,7 +3411,6 @@ static int ql_configure_rings(struct ql_adapter *qdev)
         * completion handler rx_rings.
         */
        qdev->rx_ring_count = qdev->tx_ring_count + qdev->rss_ring_count + 1;
-       netif_set_gso_max_size(qdev->ndev, 65536);
 
        for (i = 0; i < qdev->tx_ring_count; i++) {
                tx_ring = &qdev->tx_ring[i];
@@ -3644,12 +3693,53 @@ static struct nic_operations qla8000_nic_ops = {
        .port_initialize        = ql_8000_port_initialize,
 };
 
+/* Find the pcie function number for the other NIC
+ * on this chip.  Since both NIC functions share a
+ * common firmware we have the lowest enabled function
+ * do any common work.  Examples would be resetting
+ * after a fatal firmware error, or doing a firmware
+ * coredump.
+ */
+static int ql_get_alt_pcie_func(struct ql_adapter *qdev)
+{
+       int status = 0;
+       u32 temp;
+       u32 nic_func1, nic_func2;
+
+       status = ql_read_mpi_reg(qdev, MPI_TEST_FUNC_PORT_CFG,
+                       &temp);
+       if (status)
+               return status;
+
+       nic_func1 = ((temp >> MPI_TEST_NIC1_FUNC_SHIFT) &
+                       MPI_TEST_NIC_FUNC_MASK);
+       nic_func2 = ((temp >> MPI_TEST_NIC2_FUNC_SHIFT) &
+                       MPI_TEST_NIC_FUNC_MASK);
+
+       if (qdev->func == nic_func1)
+               qdev->alt_func = nic_func2;
+       else if (qdev->func == nic_func2)
+               qdev->alt_func = nic_func1;
+       else
+               status = -EIO;
+
+       return status;
+}
 
-static void ql_get_board_info(struct ql_adapter *qdev)
+static int ql_get_board_info(struct ql_adapter *qdev)
 {
+       int status;
        qdev->func =
            (ql_read32(qdev, STS) & STS_FUNC_ID_MASK) >> STS_FUNC_ID_SHIFT;
-       if (qdev->func) {
+       if (qdev->func > 3)
+               return -EIO;
+
+       status = ql_get_alt_pcie_func(qdev);
+       if (status)
+               return status;
+
+       qdev->port = (qdev->func < qdev->alt_func) ? 0 : 1;
+       if (qdev->port) {
                qdev->xg_sem_mask = SEM_XGMAC1_MASK;
                qdev->port_link_up = STS_PL1;
                qdev->port_init = STS_PI1;
@@ -3668,6 +3758,7 @@ static void ql_get_board_info(struct ql_adapter *qdev)
                qdev->nic_ops = &qla8012_nic_ops;
        else if (qdev->device_id == QLGE_DEVICE_ID_8000)
                qdev->nic_ops = &qla8000_nic_ops;
+       return status;
 }
 
 static void ql_release_all(struct pci_dev *pdev)
@@ -3762,7 +3853,12 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
 
        qdev->ndev = ndev;
        qdev->pdev = pdev;
-       ql_get_board_info(qdev);
+       err = ql_get_board_info(qdev);
+       if (err) {
+               dev_err(&pdev->dev, "Register access failed.\n");
+               err = -EIO;
+               goto err_out;
+       }
        qdev->msg_enable = netif_msg_init(debug, default_msg);
        spin_lock_init(&qdev->hw_lock);
        spin_lock_init(&qdev->stats_lock);
index 9f81b79..a67c14a 100644 (file)
@@ -90,14 +90,14 @@ static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp)
  */
 static int ql_wait_mbx_cmd_cmplt(struct ql_adapter *qdev)
 {
-       int count = 50; /* TODO: arbitrary for now. */
+       int count = 100;
        u32 value;
 
        do {
                value = ql_read32(qdev, STS);
                if (value & STS_PI)
                        return 0;
-               udelay(UDELAY_DELAY); /* 10us */
+               mdelay(UDELAY_DELAY); /* 100ms */
        } while (--count);
        return -ETIMEDOUT;
 }
@@ -453,6 +453,13 @@ static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp)
        }
 end:
        ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT);
+       /* Restore the original mailbox count to
+        * what the caller asked for.  This can get
+        * changed when a mailbox command is waiting
+        * for a response and an AEN arrives and
+        * is handled.
+        * */
+       mbcp->out_count = orig_count;
        return status;
 }
 
@@ -540,6 +547,40 @@ end:
        return status;
 }
 
+
+/* Get MPI firmware version. This will be used for
+ * driver banner and for ethtool info.
+ * Returns zero on success.
+ */
+int ql_mb_about_fw(struct ql_adapter *qdev)
+{
+       struct mbox_params mbc;
+       struct mbox_params *mbcp = &mbc;
+       int status = 0;
+
+       memset(mbcp, 0, sizeof(struct mbox_params));
+
+       mbcp->in_count = 1;
+       mbcp->out_count = 3;
+
+       mbcp->mbox_in[0] = MB_CMD_ABOUT_FW;
+
+       status = ql_mailbox_command(qdev, mbcp);
+       if (status)
+               return status;
+
+       if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
+               QPRINTK(qdev, DRV, ERR,
+                       "Failed about firmware command\n");
+               status = -EIO;
+       }
+
+       /* Store the firmware version */
+       qdev->fw_rev_id = mbcp->mbox_out[1];
+
+       return status;
+}
+
 /* Get functional state for MPI firmware.
  * Returns zero on success.
  */
@@ -754,7 +795,6 @@ void ql_mpi_port_cfg_work(struct work_struct *work)
 {
        struct ql_adapter *qdev =
            container_of(work, struct ql_adapter, mpi_port_cfg_work.work);
-       struct net_device *ndev = qdev->ndev;
        int status;
 
        status = ql_mb_get_port_cfg(qdev);
@@ -764,9 +804,7 @@ void ql_mpi_port_cfg_work(struct work_struct *work)
                goto err;
        }
 
-       if (ndev->mtu <= 2500)
-               goto end;
-       else if (qdev->link_config & CFG_JUMBO_FRAME_SIZE &&
+       if (qdev->link_config & CFG_JUMBO_FRAME_SIZE &&
                        qdev->max_frame_size ==
                        CFG_DEFAULT_MAX_FRAME_SIZE)
                goto end;
@@ -831,13 +869,19 @@ void ql_mpi_work(struct work_struct *work)
            container_of(work, struct ql_adapter, mpi_work.work);
        struct mbox_params mbc;
        struct mbox_params *mbcp = &mbc;
+       int err = 0;
 
        mutex_lock(&qdev->mpi_mutex);
 
        while (ql_read32(qdev, STS) & STS_PI) {
                memset(mbcp, 0, sizeof(struct mbox_params));
                mbcp->out_count = 1;
-               ql_mpi_handler(qdev, mbcp);
+               /* Don't continue if an async event
+                * did not complete properly.
+                */
+               err = ql_mpi_handler(qdev, mbcp);
+               if (err)
+                       break;
        }
 
        mutex_unlock(&qdev->mpi_mutex);
index 1508b12..ed63d23 100644 (file)
@@ -401,6 +401,9 @@ static void r6040_init_mac_regs(struct net_device *dev)
         * we may got called by r6040_tx_timeout which has left
         * some unsent tx buffers */
        iowrite16(0x01, ioaddr + MTPR);
+
+       /* Check media */
+       mii_check_media(&lp->mii_if, 1, 1);
 }
 
 static void r6040_tx_timeout(struct net_device *dev)
@@ -528,6 +531,8 @@ static int r6040_phy_mode_chk(struct net_device *dev)
                        phy_dat = 0x0000;
        }
 
+       mii_check_media(&lp->mii_if, 0, 1);
+
        return phy_dat;
 };
 
@@ -810,7 +815,6 @@ static void r6040_timer(unsigned long data)
                lp->phy_mode = phy_mode;
                lp->mcr0 = (lp->mcr0 & 0x7fff) | phy_mode;
                iowrite16(lp->mcr0, ioaddr);
-               printk(KERN_INFO "Link Change %x \n", ioread16(ioaddr));
        }
 
        /* Timer active again */
index 0ec0605..007c881 100644 (file)
@@ -3279,8 +3279,6 @@ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev)
        status = opts1 | len | (RingEnd * !((entry + 1) % NUM_TX_DESC));
        txd->opts1 = cpu_to_le32(status);
 
-       dev->trans_start = jiffies;
-
        tp->cur_tx += frags + 1;
 
        smp_wmb();
@@ -3381,7 +3379,7 @@ static void rtl8169_tx_interrupt(struct net_device *dev,
                rtl8169_unmap_tx_skb(tp->pci_dev, tx_skb, tp->TxDescArray + entry);
 
                if (status & LastFrag) {
-                       dev_kfree_skb_irq(tx_skb->skb);
+                       dev_kfree_skb(tx_skb->skb);
                        tx_skb->skb = NULL;
                }
                dirty_tx++;
@@ -3563,54 +3561,64 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
        int handled = 0;
        int status;
 
+       /* loop handling interrupts until we have no new ones or
+        * we hit a invalid/hotplug case.
+        */
        status = RTL_R16(IntrStatus);
+       while (status && status != 0xffff) {
+               handled = 1;
 
-       /* hotplug/major error/no more work/shared irq */
-       if ((status == 0xffff) || !status)
-               goto out;
-
-       handled = 1;
+               /* Handle all of the error cases first. These will reset
+                * the chip, so just exit the loop.
+                */
+               if (unlikely(!netif_running(dev))) {
+                       rtl8169_asic_down(ioaddr);
+                       break;
+               }
 
-       if (unlikely(!netif_running(dev))) {
-               rtl8169_asic_down(ioaddr);
-               goto out;
-       }
+               /* Work around for rx fifo overflow */
+               if (unlikely(status & RxFIFOOver) &&
+               (tp->mac_version == RTL_GIGA_MAC_VER_11)) {
+                       netif_stop_queue(dev);
+                       rtl8169_tx_timeout(dev);
+                       break;
+               }
 
-       status &= tp->intr_mask;
-       RTL_W16(IntrStatus,
-               (status & RxFIFOOver) ? (status | RxOverflow) : status);
+               if (unlikely(status & SYSErr)) {
+                       rtl8169_pcierr_interrupt(dev);
+                       break;
+               }
 
-       if (!(status & tp->intr_event))
-               goto out;
+               if (status & LinkChg)
+                       rtl8169_check_link_status(dev, tp, ioaddr);
 
-       /* Work around for rx fifo overflow */
-       if (unlikely(status & RxFIFOOver) &&
-           (tp->mac_version == RTL_GIGA_MAC_VER_11)) {
-               netif_stop_queue(dev);
-               rtl8169_tx_timeout(dev);
-               goto out;
-       }
+               /* We need to see the lastest version of tp->intr_mask to
+                * avoid ignoring an MSI interrupt and having to wait for
+                * another event which may never come.
+                */
+               smp_rmb();
+               if (status & tp->intr_mask & tp->napi_event) {
+                       RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
+                       tp->intr_mask = ~tp->napi_event;
+
+                       if (likely(napi_schedule_prep(&tp->napi)))
+                               __napi_schedule(&tp->napi);
+                       else if (netif_msg_intr(tp)) {
+                               printk(KERN_INFO "%s: interrupt %04x in poll\n",
+                               dev->name, status);
+                       }
+               }
 
-       if (unlikely(status & SYSErr)) {
-               rtl8169_pcierr_interrupt(dev);
-               goto out;
+               /* We only get a new MSI interrupt when all active irq
+                * sources on the chip have been acknowledged. So, ack
+                * everything we've seen and check if new sources have become
+                * active to avoid blocking all interrupts from the chip.
+                */
+               RTL_W16(IntrStatus,
+                       (status & RxFIFOOver) ? (status | RxOverflow) : status);
+               status = RTL_R16(IntrStatus);
        }
 
-       if (status & LinkChg)
-               rtl8169_check_link_status(dev, tp, ioaddr);
-
-       if (status & tp->napi_event) {
-               RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
-               tp->intr_mask = ~tp->napi_event;
-
-               if (likely(napi_schedule_prep(&tp->napi)))
-                       __napi_schedule(&tp->napi);
-               else if (netif_msg_intr(tp)) {
-                       printk(KERN_INFO "%s: interrupt %04x in poll\n",
-                              dev->name, status);
-               }
-       }
-out:
        return IRQ_RETVAL(handled);
 }
 
@@ -3626,13 +3634,15 @@ static int rtl8169_poll(struct napi_struct *napi, int budget)
 
        if (work_done < budget) {
                napi_complete(napi);
-               tp->intr_mask = 0xffff;
-               /*
-                * 20040426: the barrier is not strictly required but the
-                * behavior of the irq handler could be less predictable
-                * without it. Btw, the lack of flush for the posted pci
-                * write is safe - FR
+
+               /* We need for force the visibility of tp->intr_mask
+                * for other CPUs, as we can loose an MSI interrupt
+                * and potentially wait for a retransmit timeout if we don't.
+                * The posted write to IntrMask is safe, as it will
+                * eventually make it to the chip and we won't loose anything
+                * until it does.
                 */
+               tp->intr_mask = 0xffff;
                smp_wmb();
                RTL_W16(IntrMask, tp->intr_event);
        }
index 80562ea..458daa0 100644 (file)
@@ -1764,7 +1764,7 @@ static int init_nic(struct s2io_nic *nic)
                 * by then we return error.
                 */
                time = 0;
-               while (TRUE) {
+               while (true) {
                        val64 = readq(&bar0->rti_command_mem);
                        if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD))
                                break;
@@ -2137,7 +2137,7 @@ static int verify_pcc_quiescent(struct s2io_nic *sp, int flag)
 
        herc = (sp->device_type == XFRAME_II_DEVICE);
 
-       if (flag == FALSE) {
+       if (flag == false) {
                if ((!herc && (sp->pdev->revision >= 4)) || herc) {
                        if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE))
                                ret = 1;
@@ -3587,7 +3587,7 @@ static void s2io_reset(struct s2io_nic * sp)
                writeq(val64, &bar0->pcc_err_reg);
        }
 
-       sp->device_enabled_once = FALSE;
+       sp->device_enabled_once = false;
 }
 
 /**
@@ -4299,7 +4299,6 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
                s2io_stop_tx_queue(sp, fifo->fifo_no);
        }
        mac_control->stats_info->sw_stat.mem_allocated += skb->truesize;
-       dev->trans_start = jiffies;
        spin_unlock_irqrestore(&fifo->tx_lock, flags);
 
        if (sp->config.intr_type == MSI_X)
@@ -5573,10 +5572,10 @@ static void s2io_ethtool_getpause_data(struct net_device *dev,
 
        val64 = readq(&bar0->rmac_pause_cfg);
        if (val64 & RMAC_PAUSE_GEN_ENABLE)
-               ep->tx_pause = TRUE;
+               ep->tx_pause = true;
        if (val64 & RMAC_PAUSE_RX_ENABLE)
-               ep->rx_pause = TRUE;
-       ep->autoneg = FALSE;
+               ep->rx_pause = true;
+       ep->autoneg = false;
 }
 
 /**
@@ -6807,7 +6806,7 @@ static void s2io_set_link(struct work_struct *work)
                                        val64 |= ADAPTER_LED_ON;
                                        writeq(val64, &bar0->adapter_control);
                                }
-                               nic->device_enabled_once = TRUE;
+                               nic->device_enabled_once = true;
                        } else {
                                DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name);
                                DBG_PRINT(ERR_DBG, "device is not Quiescent\n");
@@ -7755,7 +7754,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
        struct s2io_nic *sp;
        struct net_device *dev;
        int i, j, ret;
-       int dma_flag = FALSE;
+       int dma_flag = false;
        u32 mac_up, mac_down;
        u64 val64 = 0, tmp64 = 0;
        struct XENA_dev_config __iomem *bar0 = NULL;
@@ -7778,7 +7777,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
 
        if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
                DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 64bit DMA\n");
-               dma_flag = TRUE;
+               dma_flag = true;
                if (pci_set_consistent_dma_mask
                    (pdev, DMA_BIT_MASK(64))) {
                        DBG_PRINT(ERR_DBG,
@@ -7819,7 +7818,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
        sp->dev = dev;
        sp->pdev = pdev;
        sp->high_dma_flag = dma_flag;
-       sp->device_enabled_once = FALSE;
+       sp->device_enabled_once = false;
        if (rx_ring_mode == 1)
                sp->rxd_mode = RXD_MODE_1;
        if (rx_ring_mode == 2)
@@ -7965,7 +7964,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
        dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
 
        dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
-       if (sp->high_dma_flag == TRUE)
+       if (sp->high_dma_flag == true)
                dev->features |= NETIF_F_HIGHDMA;
        dev->features |= NETIF_F_TSO;
        dev->features |= NETIF_F_TSO6;
index 55cb943..d5c5be6 100644 (file)
 #define vBIT(val, loc, sz)     (((u64)val) << (64-loc-sz))
 #define INV(d)  ((d&0xff)<<24) | (((d>>8)&0xff)<<16) | (((d>>16)&0xff)<<8)| ((d>>24)&0xff)
 
-#ifndef BOOL
-#define BOOL    int
-#endif
-
-#ifndef TRUE
-#define TRUE    1
-#define FALSE   0
-#endif
-
 #undef SUCCESS
 #define SUCCESS 0
 #define FAILURE -1
index 0437957..b67ccca 100644 (file)
@@ -438,6 +438,7 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue)
                        kfree_skb(skb);
                        return -EPIPE;
                }
+               efx->net_dev->trans_start = jiffies;
        }
 
        return 0;
index db723c5..f4d5090 100644 (file)
@@ -63,6 +63,7 @@
 
 /* extended status register */
 #define PMA_PMD_XSTATUS_REG    49153
+#define PMA_PMD_XSTAT_MDIX_LBN 14
 #define PMA_PMD_XSTAT_FLP_LBN   (12)
 
 /* LED control register */
@@ -741,9 +742,17 @@ tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
 
        mdio45_ethtool_gset_npage(&efx->mdio, ecmd, adv, lpa);
 
-       if (efx->phy_type != PHY_TYPE_SFX7101)
+       if (efx->phy_type != PHY_TYPE_SFX7101) {
                ecmd->supported |= (SUPPORTED_100baseT_Full |
                                    SUPPORTED_1000baseT_Full);
+               if (ecmd->speed != SPEED_10000) {
+                       ecmd->eth_tp_mdix =
+                               (efx_mdio_read(efx, MDIO_MMD_PMAPMD,
+                                              PMA_PMD_XSTATUS_REG) &
+                                (1 << PMA_PMD_XSTAT_MDIX_LBN))
+                               ? ETH_TP_MDI_X : ETH_TP_MDI;
+               }
+       }
 
        /* In loopback, the PHY automatically brings up the correct interface,
         * but doesn't advertise the correct speed. So override it */
index d6681ed..14a1478 100644 (file)
@@ -360,13 +360,6 @@ inline int efx_xmit(struct efx_nic *efx,
 
        /* Map fragments for DMA and add to TX queue */
        rc = efx_enqueue_skb(tx_queue, skb);
-       if (unlikely(rc != NETDEV_TX_OK))
-               goto out;
-
-       /* Update last TX timer */
-       efx->net_dev->trans_start = jiffies;
-
- out:
        return rc;
 }
 
index 55ccd51..e224766 100644 (file)
@@ -47,7 +47,7 @@
 #define PHY_ID_ANY             0x1f
 #define MII_REG_ANY            0x1f
 
-#define DRV_VERSION            "1.2"
+#define DRV_VERSION            "1.3"
 #define DRV_NAME               "sis190"
 #define SIS190_DRIVER_NAME     DRV_NAME " Gigabit Ethernet driver " DRV_VERSION
 #define PFX DRV_NAME ": "
@@ -317,6 +317,7 @@ static struct mii_chip_info {
         unsigned int type;
        u32 feature;
 } mii_chip_table[] = {
+       { "Atheros PHY",          { 0x004d, 0xd010 }, LAN, 0 },
        { "Atheros PHY AR8012",   { 0x004d, 0xd020 }, LAN, 0 },
        { "Broadcom PHY BCM5461", { 0x0020, 0x60c0 }, LAN, F_PHY_BCM5461 },
        { "Broadcom PHY AC131",   { 0x0143, 0xbc70 }, LAN, 0 },
@@ -347,7 +348,7 @@ static struct {
        u32 msg_enable;
 } debug = { -1 };
 
-MODULE_DESCRIPTION("SiS sis190 Gigabit Ethernet driver");
+MODULE_DESCRIPTION("SiS sis190/191 Gigabit Ethernet driver");
 module_param(rx_copybreak, int, 0);
 MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames");
 module_param_named(debug, debug.msg_enable, int, 0);
@@ -539,8 +540,8 @@ static bool sis190_try_rx_copy(struct sis190_private *tp,
        if (!skb)
                goto out;
 
-       pci_dma_sync_single_for_device(tp->pci_dev, addr, pkt_size,
-                                      PCI_DMA_FROMDEVICE);
+       pci_dma_sync_single_for_cpu(tp->pci_dev, addr, tp->rx_buf_sz,
+                               PCI_DMA_FROMDEVICE);
        skb_reserve(skb, 2);
        skb_copy_to_linear_data(skb, sk_buff[0]->data, pkt_size);
        *sk_buff = skb;
@@ -942,9 +943,9 @@ static void sis190_phy_task(struct work_struct *work)
                        u32 ctl;
                        const char *msg;
                } reg31[] = {
-                       { LPA_1000XFULL | LPA_SLCT, 0x07000c00 | 0x00001000,
+                       { LPA_1000FULL, 0x07000c00 | 0x00001000,
                                "1000 Mbps Full Duplex" },
-                       { LPA_1000XHALF | LPA_SLCT, 0x07000c00,
+                       { LPA_1000HALF, 0x07000c00,
                                "1000 Mbps Half Duplex" },
                        { LPA_100FULL, 0x04000800 | 0x00001000,
                                "100 Mbps Full Duplex" },
@@ -955,22 +956,35 @@ static void sis190_phy_task(struct work_struct *work)
                        { LPA_10HALF, 0x04000400,
                                "10 Mbps Half Duplex" },
                        { 0, 0x04000400, "unknown" }
-               }, *p;
-               u16 adv;
+               }, *p = NULL;
+               u16 adv, autoexp, gigadv, gigrec;
 
                val = mdio_read(ioaddr, phy_id, 0x1f);
                net_link(tp, KERN_INFO "%s: mii ext = %04x.\n", dev->name, val);
 
                val = mdio_read(ioaddr, phy_id, MII_LPA);
                adv = mdio_read(ioaddr, phy_id, MII_ADVERTISE);
-               net_link(tp, KERN_INFO "%s: mii lpa = %04x adv = %04x.\n",
-                        dev->name, val, adv);
-
-               val &= adv;
+               autoexp = mdio_read(ioaddr, phy_id, MII_EXPANSION);
+               net_link(tp, KERN_INFO "%s: mii lpa=%04x adv=%04x exp=%04x.\n",
+                        dev->name, val, adv, autoexp);
+
+               if (val & LPA_NPAGE && autoexp & EXPANSION_NWAY) {
+                       /* check for gigabit speed */
+                       gigadv = mdio_read(ioaddr, phy_id, MII_CTRL1000);
+                       gigrec = mdio_read(ioaddr, phy_id, MII_STAT1000);
+                       val = (gigadv & (gigrec >> 2));
+                       if (val & ADVERTISE_1000FULL)
+                               p = reg31;
+                       else if (val & ADVERTISE_1000HALF)
+                               p = reg31 + 1;
+               }
+               if (!p) {
+                       val &= adv;
 
-               for (p = reg31; p->val; p++) {
-                       if ((val & p->val) == p->val)
-                               break;
+                       for (p = reg31; p->val; p++) {
+                               if ((val & p->val) == p->val)
+                                       break;
+                       }
                }
 
                p->ctl |= SIS_R32(StationControl) & ~0x0f001c00;
@@ -1204,8 +1218,6 @@ static int sis190_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        SIS_W32(TxControl, 0x1a00 | CmdReset | CmdTxEnb);
 
-       dev->trans_start = jiffies;
-
        dirty_tx = tp->dirty_tx;
        if ((tp->cur_tx - NUM_TX_DESC) == dirty_tx) {
                netif_stop_queue(dev);
@@ -1315,12 +1327,15 @@ static void sis190_init_phy(struct net_device *dev, struct sis190_private *tp,
                        ((mii_status & (BMSR_100FULL | BMSR_100HALF)) ?
                                LAN : HOME) : p->type;
                tp->features |= p->feature;
-       } else
+               net_probe(tp, KERN_INFO "%s: %s transceiver at address %d.\n",
+                       pci_name(tp->pci_dev), p->name, phy_id);
+       } else {
                phy->type = UNKNOWN;
-
-       net_probe(tp, KERN_INFO "%s: %s transceiver at address %d.\n",
-                 pci_name(tp->pci_dev),
-                 (phy->type == UNKNOWN) ? "Unknown PHY" : p->name, phy_id);
+               net_probe(tp, KERN_INFO
+                       "%s: unknown PHY 0x%x:0x%x transceiver at address %d\n",
+                       pci_name(tp->pci_dev),
+                       phy->id[0], (phy->id[1] & 0xfff0), phy_id);
+       }
 }
 
 static void sis190_mii_probe_88e1111_fixup(struct sis190_private *tp)
index c11cdd0..60d502e 100644 (file)
@@ -2837,8 +2837,6 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
                netif_stop_queue(dev);
        }
 
-       dev->trans_start = jiffies;
-
        return NETDEV_TX_OK;
 }
 
index a2ff9cb..6b5946f 100644 (file)
@@ -1690,7 +1690,6 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
 
        sky2_put_idx(hw, txqaddr[sky2->port], sky2->tx_prod);
 
-       dev->trans_start = jiffies;
        return NETDEV_TX_OK;
 
 mapping_unwind:
index 3cff840..b60639b 100644 (file)
@@ -2155,7 +2155,7 @@ static int smsc911x_resume(struct platform_device *pdev)
 
 static struct platform_driver smsc911x_driver = {
        .probe = smsc911x_drv_probe,
-       .remove = smsc911x_drv_remove,
+       .remove = __devexit_p(smsc911x_drv_remove),
        .driver = {
                .name = SMSC_CHIPNAME,
        },
index c399b19..545f81b 100644 (file)
@@ -369,7 +369,6 @@ struct netdev_private {
        struct sk_buff* tx_skbuff[TX_RING_SIZE];
         dma_addr_t tx_ring_dma;
         dma_addr_t rx_ring_dma;
-       struct net_device_stats stats;
        struct timer_list timer;                /* Media monitoring timer. */
        /* Frequently used values: keep some adjacent for cache effect. */
        spinlock_t lock;
@@ -975,7 +974,7 @@ static void tx_timeout(struct net_device *dev)
        dev->if_port = 0;
 
        dev->trans_start = jiffies;
-       np->stats.tx_errors++;
+       dev->stats.tx_errors++;
        if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
                netif_wake_queue(dev);
        }
@@ -1123,7 +1122,7 @@ reset_tx (struct net_device *dev)
                        else
                                dev_kfree_skb (skb);
                        np->tx_skbuff[i] = NULL;
-                       np->stats.tx_dropped++;
+                       dev->stats.tx_dropped++;
                }
        }
        np->cur_tx = np->dirty_tx = 0;
@@ -1181,15 +1180,15 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
                                        if (netif_msg_tx_err(np))
                                                printk("%s: Transmit error status %4.4x.\n",
                                                           dev->name, tx_status);
-                                       np->stats.tx_errors++;
+                                       dev->stats.tx_errors++;
                                        if (tx_status & 0x10)
-                                               np->stats.tx_fifo_errors++;
+                                               dev->stats.tx_fifo_errors++;
                                        if (tx_status & 0x08)
-                                               np->stats.collisions++;
+                                               dev->stats.collisions++;
                                        if (tx_status & 0x04)
-                                               np->stats.tx_fifo_errors++;
+                                               dev->stats.tx_fifo_errors++;
                                        if (tx_status & 0x02)
-                                               np->stats.tx_window_errors++;
+                                               dev->stats.tx_window_errors++;
 
                                        /*
                                        ** This reset has been verified on
@@ -1313,11 +1312,15 @@ static void rx_poll(unsigned long data)
                        if (netif_msg_rx_err(np))
                                printk(KERN_DEBUG "  netdev_rx() Rx error was %8.8x.\n",
                                           frame_status);
-                       np->stats.rx_errors++;
-                       if (frame_status & 0x00100000) np->stats.rx_length_errors++;
-                       if (frame_status & 0x00010000) np->stats.rx_fifo_errors++;
-                       if (frame_status & 0x00060000) np->stats.rx_frame_errors++;
-                       if (frame_status & 0x00080000) np->stats.rx_crc_errors++;
+                       dev->stats.rx_errors++;
+                       if (frame_status & 0x00100000)
+                               dev->stats.rx_length_errors++;
+                       if (frame_status & 0x00010000)
+                               dev->stats.rx_fifo_errors++;
+                       if (frame_status & 0x00060000)
+                               dev->stats.rx_frame_errors++;
+                       if (frame_status & 0x00080000)
+                               dev->stats.rx_crc_errors++;
                        if (frame_status & 0x00100000) {
                                printk(KERN_WARNING "%s: Oversized Ethernet frame,"
                                           " status %8.8x.\n",
@@ -1485,22 +1488,22 @@ static struct net_device_stats *get_stats(struct net_device *dev)
           the vulnerability window is very small and statistics are
           non-critical. */
        /* The chip only need report frame silently dropped. */
-       np->stats.rx_missed_errors      += ioread8(ioaddr + RxMissed);
-       np->stats.tx_packets += ioread16(ioaddr + TxFramesOK);
-       np->stats.rx_packets += ioread16(ioaddr + RxFramesOK);
-       np->stats.collisions += ioread8(ioaddr + StatsLateColl);
-       np->stats.collisions += ioread8(ioaddr + StatsMultiColl);
-       np->stats.collisions += ioread8(ioaddr + StatsOneColl);
-       np->stats.tx_carrier_errors += ioread8(ioaddr + StatsCarrierError);
+       dev->stats.rx_missed_errors     += ioread8(ioaddr + RxMissed);
+       dev->stats.tx_packets += ioread16(ioaddr + TxFramesOK);
+       dev->stats.rx_packets += ioread16(ioaddr + RxFramesOK);
+       dev->stats.collisions += ioread8(ioaddr + StatsLateColl);
+       dev->stats.collisions += ioread8(ioaddr + StatsMultiColl);
+       dev->stats.collisions += ioread8(ioaddr + StatsOneColl);
+       dev->stats.tx_carrier_errors += ioread8(ioaddr + StatsCarrierError);
        ioread8(ioaddr + StatsTxDefer);
        for (i = StatsTxDefer; i <= StatsMcastRx; i++)
                ioread8(ioaddr + i);
-       np->stats.tx_bytes += ioread16(ioaddr + TxOctetsLow);
-       np->stats.tx_bytes += ioread16(ioaddr + TxOctetsHigh) << 16;
-       np->stats.rx_bytes += ioread16(ioaddr + RxOctetsLow);
-       np->stats.rx_bytes += ioread16(ioaddr + RxOctetsHigh) << 16;
+       dev->stats.tx_bytes += ioread16(ioaddr + TxOctetsLow);
+       dev->stats.tx_bytes += ioread16(ioaddr + TxOctetsHigh) << 16;
+       dev->stats.rx_bytes += ioread16(ioaddr + RxOctetsLow);
+       dev->stats.rx_bytes += ioread16(ioaddr + RxOctetsHigh) << 16;
 
-       return &np->stats;
+       return &dev->stats;
 }
 
 static void set_rx_mode(struct net_device *dev)
index 7f4a968..3c2679c 100644 (file)
@@ -948,8 +948,7 @@ static void print_rxfd(struct rxf_desc *rxfd);
 
 static void bdx_rxdb_destroy(struct rxdb *db)
 {
-       if (db)
-               vfree(db);
+       vfree(db);
 }
 
 static struct rxdb *bdx_rxdb_create(int nelem)
@@ -1482,10 +1481,8 @@ static void bdx_tx_db_close(struct txdb *d)
 {
        BDX_ASSERT(d == NULL);
 
-       if (d->start) {
-               vfree(d->start);
-               d->start = NULL;
-       }
+       vfree(d->start);
+       d->start = NULL;
 }
 
 /*************************************************************************
@@ -1718,8 +1715,9 @@ static int bdx_tx_transmit(struct sk_buff *skb, struct net_device *ndev)
        WRITE_REG(priv, f->m.reg_WPTR, f->m.wptr & TXF_WPTR_WR_PTR);
 
 #endif
-       ndev->trans_start = jiffies;
-
+#ifdef BDX_LLTX
+       ndev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */
+#endif
        priv->net_stats.tx_packets++;
        priv->net_stats.tx_bytes += skb->len;
 
index eb65e25..46a3f86 100644 (file)
@@ -5021,7 +5021,7 @@ static int tigon3_dma_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb,
                /* New SKB is guaranteed to be linear. */
                entry = *start;
                ret = skb_dma_map(&tp->pdev->dev, new_skb, DMA_TO_DEVICE);
-               new_addr = skb_shinfo(new_skb)->dma_maps[0];
+               new_addr = skb_shinfo(new_skb)->dma_head;
 
                /* Make sure new skb does not cross any 4G boundaries.
                 * Drop the packet if it does.
@@ -5155,7 +5155,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        sp = skb_shinfo(skb);
 
-       mapping = sp->dma_maps[0];
+       mapping = sp->dma_head;
 
        tp->tx_buffers[entry].skb = skb;
 
@@ -5173,7 +5173,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
 
                        len = frag->size;
-                       mapping = sp->dma_maps[i + 1];
+                       mapping = sp->dma_maps[i];
                        tp->tx_buffers[entry].skb = NULL;
 
                        tg3_set_txd(tp, entry, mapping, len,
@@ -5194,9 +5194,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
 out_unlock:
-       mmiowb();
-
-       dev->trans_start = jiffies;
+       mmiowb();
 
        return NETDEV_TX_OK;
 }
@@ -5333,7 +5331,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
 
        sp = skb_shinfo(skb);
 
-       mapping = sp->dma_maps[0];
+       mapping = sp->dma_head;
 
        tp->tx_buffers[entry].skb = skb;
 
@@ -5358,7 +5356,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
                        skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
 
                        len = frag->size;
-                       mapping = sp->dma_maps[i + 1];
+                       mapping = sp->dma_maps[i];
 
                        tp->tx_buffers[entry].skb = NULL;
 
@@ -5407,9 +5405,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
        }
 
 out_unlock:
-       mmiowb();
-
-       dev->trans_start = jiffies;
+       mmiowb();
 
        return NETDEV_TX_OK;
 }
index d913405..1cc8cf4 100644 (file)
@@ -27,6 +27,18 @@ config DE2104X
          To compile this driver as a module, choose M here. The module will
          be called de2104x.
 
+config DE2104X_DSL
+       int "Descriptor Skip Length in 32 bit longwords"
+       depends on DE2104X
+       range 0 31
+       default 0
+       help
+         Setting this value allows to align ring buffer descriptors into their
+         own cache lines. Value of 4 corresponds to the typical 32 byte line
+         (the descriptor is 16 bytes). This is necessary on systems that lack
+         cache coherence, an example is PowerMac 5500. Otherwise 0 is safe.
+         Default is 0, and range is 0 to 31.
+
 config TULIP
        tristate "DECchip Tulip (dc2114x) PCI support"
        depends on PCI
index d4c5ecc..e7609a0 100644 (file)
@@ -82,6 +82,13 @@ MODULE_PARM_DESC (rx_copybreak, "de2104x Breakpoint at which Rx packets are copi
                                 NETIF_MSG_RX_ERR       | \
                                 NETIF_MSG_TX_ERR)
 
+/* Descriptor skip length in 32 bit longwords. */
+#ifndef CONFIG_DE2104X_DSL
+#define DSL                    0
+#else
+#define DSL                    CONFIG_DE2104X_DSL
+#endif
+
 #define DE_RX_RING_SIZE                64
 #define DE_TX_RING_SIZE                64
 #define DE_RING_BYTES          \
@@ -153,6 +160,7 @@ enum {
        CmdReset                = (1 << 0),
        CacheAlign16            = 0x00008000,
        BurstLen4               = 0x00000400,
+       DescSkipLen             = (DSL << 2),
 
        /* Rx/TxPoll bits */
        NormalTxPoll            = (1 << 0),
@@ -246,7 +254,7 @@ static const u32 de_intr_mask =
  * Set the programmable burst length to 4 longwords for all:
  * DMA errors result without these values. Cache align 16 long.
  */
-static const u32 de_bus_mode = CacheAlign16 | BurstLen4;
+static const u32 de_bus_mode = CacheAlign16 | BurstLen4 | DescSkipLen;
 
 struct de_srom_media_block {
        u8                      opts;
@@ -266,6 +274,9 @@ struct de_desc {
        __le32                  opts2;
        __le32                  addr1;
        __le32                  addr2;
+#if DSL
+       __le32                  skip[DSL];
+#endif
 };
 
 struct media_info {
index 4cda69b..811d351 100644 (file)
@@ -565,9 +565,13 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun,
                if (memcpy_fromiovecend((void *)&gso, iv, offset, sizeof(gso)))
                        return -EFAULT;
 
+               if ((gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
+                   gso.csum_start + gso.csum_offset + 2 > gso.hdr_len)
+                       gso.hdr_len = gso.csum_start + gso.csum_offset + 2;
+
                if (gso.hdr_len > len)
                        return -EINVAL;
-               offset += sizeof(pi);
+               offset += sizeof(gso);
        }
 
        if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) {
@@ -844,12 +848,12 @@ static void tun_sock_write_space(struct sock *sk)
        if (!sock_writeable(sk))
                return;
 
-       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-               wake_up_interruptible_sync(sk->sk_sleep);
-
        if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags))
                return;
 
+       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
+               wake_up_interruptible_sync(sk->sk_sleep);
+
        tun = container_of(sk, struct tun_sock, sk)->tun;
        kill_fasync(&tun->fasync, SIGIO, POLL_OUT);
 }
@@ -1318,21 +1322,22 @@ static int tun_chr_open(struct inode *inode, struct file * file)
 static int tun_chr_close(struct inode *inode, struct file *file)
 {
        struct tun_file *tfile = file->private_data;
-       struct tun_struct *tun = __tun_get(tfile);
+       struct tun_struct *tun;
 
 
+       rtnl_lock();
+       tun = __tun_get(tfile);
        if (tun) {
                DBG(KERN_INFO "%s: tun_chr_close\n", tun->dev->name);
 
-               rtnl_lock();
                __tun_detach(tun);
 
                /* If desireable, unregister the netdevice. */
                if (!(tun->flags & TUN_PERSIST))
                        unregister_netdevice(tun->dev);
 
-               rtnl_unlock();
        }
+       rtnl_unlock();
 
        tun = tfile->tun;
        if (tun)
index 0cf22c4..fd6140b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2007 Freescale Semicondutor, Inc. All rights reserved.
+ * Copyright (C) 2006-2009 Freescale Semicondutor, Inc. All rights reserved.
  *
  * Author: Shlomi Gridish <gridish@freescale.com>
  *        Li Yang <leoli@freescale.com>
@@ -65,6 +65,8 @@
 
 static DEFINE_SPINLOCK(ugeth_lock);
 
+static void uec_configure_serdes(struct net_device *dev);
+
 static struct {
        u32 msg_enable;
 } debug = { -1 };
@@ -1410,6 +1412,9 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
            (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
                upsmr |= UCC_GETH_UPSMR_TBIM;
        }
+       if ((ugeth->phy_interface == PHY_INTERFACE_MODE_SGMII))
+               upsmr |= UCC_GETH_UPSMR_SGMM;
+
        out_be32(&uf_regs->upsmr, upsmr);
 
        /* Disable autonegotiation in tbi mode, because by default it
@@ -1554,6 +1559,9 @@ static int init_phy(struct net_device *dev)
                return -ENODEV;
        }
 
+       if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII)
+               uec_configure_serdes(dev);
+
        phydev->supported &= (ADVERTISED_10baseT_Half |
                                 ADVERTISED_10baseT_Full |
                                 ADVERTISED_100baseT_Half |
@@ -1569,7 +1577,41 @@ static int init_phy(struct net_device *dev)
        return 0;
 }
 
+/* Initialize TBI PHY interface for communicating with the
+ * SERDES lynx PHY on the chip.  We communicate with this PHY
+ * through the MDIO bus on each controller, treating it as a
+ * "normal" PHY at the address found in the UTBIPA register.  We assume
+ * that the UTBIPA register is valid.  Either the MDIO bus code will set
+ * it to a value that doesn't conflict with other PHYs on the bus, or the
+ * value doesn't matter, as there are no other PHYs on the bus.
+ */
+static void uec_configure_serdes(struct net_device *dev)
+{
+       struct ucc_geth_private *ugeth = netdev_priv(dev);
+
+       if (!ugeth->tbiphy) {
+               printk(KERN_WARNING "SGMII mode requires that the device "
+                       "tree specify a tbi-handle\n");
+       return;
+       }
+
+       /*
+        * If the link is already up, we must already be ok, and don't need to
+        * configure and reset the TBI<->SerDes link.  Maybe U-Boot configured
+        * everything for us?  Resetting it takes the link down and requires
+        * several seconds for it to come back.
+        */
+       if (phy_read(ugeth->tbiphy, ENET_TBI_MII_SR) & TBISR_LSTATUS)
+               return;
+
+       /* Single clk mode, mii mode off(for serdes communication) */
+       phy_write(ugeth->tbiphy, ENET_TBI_MII_ANA, TBIANA_SETTINGS);
 
+       phy_write(ugeth->tbiphy, ENET_TBI_MII_TBICON, TBICON_CLK_SELECT);
+
+       phy_write(ugeth->tbiphy, ENET_TBI_MII_CR, TBICR_SETTINGS);
+
+}
 
 static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth)
 {
@@ -3523,6 +3565,8 @@ static phy_interface_t to_phy_interface(const char *phy_connection_type)
                return PHY_INTERFACE_MODE_RGMII_RXID;
        if (strcasecmp(phy_connection_type, "rtbi") == 0)
                return PHY_INTERFACE_MODE_RTBI;
+       if (strcasecmp(phy_connection_type, "sgmii") == 0)
+               return PHY_INTERFACE_MODE_SGMII;
 
        return PHY_INTERFACE_MODE_MII;
 }
@@ -3567,6 +3611,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
                PHY_INTERFACE_MODE_RMII, PHY_INTERFACE_MODE_RGMII,
                PHY_INTERFACE_MODE_GMII, PHY_INTERFACE_MODE_RGMII,
                PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_RTBI,
+               PHY_INTERFACE_MODE_SGMII,
        };
 
        ugeth_vdbg("%s: IN", __func__);
@@ -3682,6 +3727,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
                case PHY_INTERFACE_MODE_RGMII_TXID:
                case PHY_INTERFACE_MODE_TBI:
                case PHY_INTERFACE_MODE_RTBI:
+               case PHY_INTERFACE_MODE_SGMII:
                        max_speed = SPEED_1000;
                        break;
                default:
@@ -3756,6 +3802,37 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
        ugeth->ndev = dev;
        ugeth->node = np;
 
+       /* Find the TBI PHY.  If it's not there, we don't support SGMII */
+       ph = of_get_property(np, "tbi-handle", NULL);
+       if (ph) {
+               struct device_node *tbi = of_find_node_by_phandle(*ph);
+               struct of_device *ofdev;
+               struct mii_bus *bus;
+               const unsigned int *id;
+
+               if (!tbi)
+                       return 0;
+
+               mdio = of_get_parent(tbi);
+               if (!mdio)
+                       return 0;
+
+               ofdev = of_find_device_by_node(mdio);
+
+               of_node_put(mdio);
+
+               id = of_get_property(tbi, "reg", NULL);
+               if (!id)
+                       return 0;
+               of_node_put(tbi);
+
+               bus = dev_get_drvdata(&ofdev->dev);
+               if (!bus)
+                       return 0;
+
+               ugeth->tbiphy = bus->phy_map[*id];
+       }
+
        return 0;
 }
 
index dca628a..deb962b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
+ * Copyright (C) Freescale Semicondutor, Inc. 2006-2009. All rights reserved.
  *
  * Author: Shlomi Gridish <gridish@freescale.com>
  *
@@ -193,6 +193,31 @@ struct ucc_geth {
 #define        ENET_TBI_MII_JD         0x10    /* Jitter diagnostics */
 #define        ENET_TBI_MII_TBICON     0x11    /* TBI control */
 
+/* TBI MDIO register bit fields*/
+#define TBISR_LSTATUS          0x0004
+#define TBICON_CLK_SELECT       0x0020
+#define TBIANA_ASYMMETRIC_PAUSE 0x0100
+#define TBIANA_SYMMETRIC_PAUSE  0x0080
+#define TBIANA_HALF_DUPLEX      0x0040
+#define TBIANA_FULL_DUPLEX      0x0020
+#define TBICR_PHY_RESET         0x8000
+#define TBICR_ANEG_ENABLE       0x1000
+#define TBICR_RESTART_ANEG      0x0200
+#define TBICR_FULL_DUPLEX       0x0100
+#define TBICR_SPEED1_SET        0x0040
+
+#define TBIANA_SETTINGS ( \
+               TBIANA_ASYMMETRIC_PAUSE \
+               | TBIANA_SYMMETRIC_PAUSE \
+               | TBIANA_FULL_DUPLEX \
+               )
+#define TBICR_SETTINGS ( \
+               TBICR_PHY_RESET \
+               | TBICR_ANEG_ENABLE \
+               | TBICR_FULL_DUPLEX \
+               | TBICR_SPEED1_SET \
+               )
+
 /* UCC GETH MACCFG1 (MAC Configuration 1 Register) */
 #define MACCFG1_FLOW_RX                         0x00000020     /* Flow Control
                                                                   Rx */
@@ -1188,6 +1213,7 @@ struct ucc_geth_private {
 
        struct ugeth_mii_info *mii_info;
        struct phy_device *phydev;
+       struct phy_device *tbiphy;
        phy_interface_t phy_interface;
        int max_speed;
        uint32_t msg_enable;
index 837135f..e3580f4 100644 (file)
@@ -899,15 +899,14 @@ static void packetizeRx(struct hso_net *odev, unsigned char *ip_pkt,
                                        continue;
                                }
                                /* Allocate an sk_buff */
-                               odev->skb_rx_buf = dev_alloc_skb(frame_len);
+                               odev->skb_rx_buf = netdev_alloc_skb(odev->net,
+                                                                   frame_len);
                                if (!odev->skb_rx_buf) {
                                        /* We got no receive buffer. */
                                        D1("could not allocate memory");
                                        odev->rx_parse_state = WAIT_SYNC;
                                        return;
                                }
-                               /* Here's where it came from */
-                               odev->skb_rx_buf->dev = odev->net;
 
                                /* Copy what we got so far. make room for iphdr
                                 * after tail. */
@@ -2481,10 +2480,10 @@ static int add_net_device(struct hso_device *hso_dev)
        return 0;
 }
 
-static int hso_radio_toggle(void *data, enum rfkill_state state)
+static int hso_rfkill_set_block(void *data, bool blocked)
 {
        struct hso_device *hso_dev = data;
-       int enabled = (state == RFKILL_STATE_UNBLOCKED);
+       int enabled = !blocked;
        int rv;
 
        mutex_lock(&hso_dev->mutex);
@@ -2498,6 +2497,10 @@ static int hso_radio_toggle(void *data, enum rfkill_state state)
        return rv;
 }
 
+static const struct rfkill_ops hso_rfkill_ops = {
+       .set_block = hso_rfkill_set_block,
+};
+
 /* Creates and sets up everything for rfkill */
 static void hso_create_rfkill(struct hso_device *hso_dev,
                             struct usb_interface *interface)
@@ -2506,29 +2509,25 @@ static void hso_create_rfkill(struct hso_device *hso_dev,
        struct device *dev = &hso_net->net->dev;
        char *rfkn;
 
-       hso_net->rfkill = rfkill_allocate(&interface_to_usbdev(interface)->dev,
-                                RFKILL_TYPE_WWAN);
-       if (!hso_net->rfkill) {
-               dev_err(dev, "%s - Out of memory\n", __func__);
-               return;
-       }
        rfkn = kzalloc(20, GFP_KERNEL);
-       if (!rfkn) {
-               rfkill_free(hso_net->rfkill);
-               hso_net->rfkill = NULL;
+       if (!rfkn)
                dev_err(dev, "%s - Out of memory\n", __func__);
-               return;
-       }
+
        snprintf(rfkn, 20, "hso-%d",
                 interface->altsetting->desc.bInterfaceNumber);
-       hso_net->rfkill->name = rfkn;
-       hso_net->rfkill->state = RFKILL_STATE_UNBLOCKED;
-       hso_net->rfkill->data = hso_dev;
-       hso_net->rfkill->toggle_radio = hso_radio_toggle;
+
+       hso_net->rfkill = rfkill_alloc(rfkn,
+                                      &interface_to_usbdev(interface)->dev,
+                                      RFKILL_TYPE_WWAN,
+                                      &hso_rfkill_ops, hso_dev);
+       if (!hso_net->rfkill) {
+               dev_err(dev, "%s - Out of memory\n", __func__);
+               kfree(rfkn);
+               return;
+       }
        if (rfkill_register(hso_net->rfkill) < 0) {
+               rfkill_destroy(hso_net->rfkill);
                kfree(rfkn);
-               hso_net->rfkill->name = NULL;
-               rfkill_free(hso_net->rfkill);
                hso_net->rfkill = NULL;
                dev_err(dev, "%s - Failed to register rfkill\n", __func__);
                return;
@@ -3165,8 +3164,10 @@ static void hso_free_interface(struct usb_interface *interface)
                        hso_stop_net_device(network_table[i]);
                        cancel_work_sync(&network_table[i]->async_put_intf);
                        cancel_work_sync(&network_table[i]->async_get_intf);
-                       if (rfk)
+                       if (rfk) {
                                rfkill_unregister(rfk);
+                               rfkill_destroy(rfk);
+                       }
                        hso_free_net_device(network_table[i]);
                }
        }
index f9fb454..fcc6fa0 100644 (file)
@@ -221,7 +221,8 @@ static void ctrl_callback(struct urb *urb)
        case -ENOENT:
                break;
        default:
-               dev_warn(&urb->dev->dev, "ctrl urb status %d\n", status);
+               if (printk_ratelimit())
+                       dev_warn(&urb->dev->dev, "ctrl urb status %d\n", status);
        }
        dev = urb->context;
        clear_bit(RX_REG_SET, &dev->flags);
@@ -442,10 +443,12 @@ static void read_bulk_callback(struct urb *urb)
        case -ENOENT:
                return; /* the urb is in unlink state */
        case -ETIME:
-               dev_warn(&urb->dev->dev, "may be reset is needed?..\n");
+               if (printk_ratelimit())
+                       dev_warn(&urb->dev->dev, "may be reset is needed?..\n");
                goto goon;
        default:
-               dev_warn(&urb->dev->dev, "Rx status %d\n", status);
+               if (printk_ratelimit())
+                       dev_warn(&urb->dev->dev, "Rx status %d\n", status);
                goto goon;
        }
 
index 8e56fcf..87197dd 100644 (file)
@@ -176,8 +176,6 @@ static int veth_xmit(struct sk_buff *skb, struct net_device *dev)
        if (dev->features & NETIF_F_NO_CSUM)
                skb->ip_summed = rcv_priv->ip_summed;
 
-       dst_release(skb->dst);
-       skb->dst = NULL;
        skb->mark = 0;
        secpath_reset(skb);
        nf_reset(skb);
index 45daba7..d3489a3 100644 (file)
@@ -388,7 +388,6 @@ struct rhine_private {
        long pioaddr;
        struct net_device *dev;
        struct napi_struct napi;
-       struct net_device_stats stats;
        spinlock_t lock;
 
        /* Frequently used values: keep some adjacent for cache effect. */
@@ -1209,7 +1208,7 @@ static void rhine_tx_timeout(struct net_device *dev)
        enable_irq(rp->pdev->irq);
 
        dev->trans_start = jiffies;
-       rp->stats.tx_errors++;
+       dev->stats.tx_errors++;
        netif_wake_queue(dev);
 }
 
@@ -1237,7 +1236,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
                        /* packet too long, drop it */
                        dev_kfree_skb(skb);
                        rp->tx_skbuff[entry] = NULL;
-                       rp->stats.tx_dropped++;
+                       dev->stats.tx_dropped++;
                        return 0;
                }
 
@@ -1378,29 +1377,33 @@ static void rhine_tx(struct net_device *dev)
                                printk(KERN_DEBUG "%s: Transmit error, "
                                       "Tx status %8.8x.\n",
                                       dev->name, txstatus);
-                       rp->stats.tx_errors++;
-                       if (txstatus & 0x0400) rp->stats.tx_carrier_errors++;
-                       if (txstatus & 0x0200) rp->stats.tx_window_errors++;
-                       if (txstatus & 0x0100) rp->stats.tx_aborted_errors++;
-                       if (txstatus & 0x0080) rp->stats.tx_heartbeat_errors++;
+                       dev->stats.tx_errors++;
+                       if (txstatus & 0x0400)
+                               dev->stats.tx_carrier_errors++;
+                       if (txstatus & 0x0200)
+                               dev->stats.tx_window_errors++;
+                       if (txstatus & 0x0100)
+                               dev->stats.tx_aborted_errors++;
+                       if (txstatus & 0x0080)
+                               dev->stats.tx_heartbeat_errors++;
                        if (((rp->quirks & rqRhineI) && txstatus & 0x0002) ||
                            (txstatus & 0x0800) || (txstatus & 0x1000)) {
-                               rp->stats.tx_fifo_errors++;
+                               dev->stats.tx_fifo_errors++;
                                rp->tx_ring[entry].tx_status = cpu_to_le32(DescOwn);
                                break; /* Keep the skb - we try again */
                        }
                        /* Transmitter restarted in 'abnormal' handler. */
                } else {
                        if (rp->quirks & rqRhineI)
-                               rp->stats.collisions += (txstatus >> 3) & 0x0F;
+                               dev->stats.collisions += (txstatus >> 3) & 0x0F;
                        else
-                               rp->stats.collisions += txstatus & 0x0F;
+                               dev->stats.collisions += txstatus & 0x0F;
                        if (debug > 6)
                                printk(KERN_DEBUG "collisions: %1.1x:%1.1x\n",
                                       (txstatus >> 3) & 0xF,
                                       txstatus & 0xF);
-                       rp->stats.tx_bytes += rp->tx_skbuff[entry]->len;
-                       rp->stats.tx_packets++;
+                       dev->stats.tx_bytes += rp->tx_skbuff[entry]->len;
+                       dev->stats.tx_packets++;
                }
                /* Free the original skb. */
                if (rp->tx_skbuff_dma[entry]) {
@@ -1455,21 +1458,24 @@ static int rhine_rx(struct net_device *dev, int limit)
                                printk(KERN_WARNING "%s: Oversized Ethernet "
                                       "frame %p vs %p.\n", dev->name,
                                       rp->rx_head_desc, &rp->rx_ring[entry]);
-                               rp->stats.rx_length_errors++;
+                               dev->stats.rx_length_errors++;
                        } else if (desc_status & RxErr) {
                                /* There was a error. */
                                if (debug > 2)
                                        printk(KERN_DEBUG "rhine_rx() Rx "
                                               "error was %8.8x.\n",
                                               desc_status);
-                               rp->stats.rx_errors++;
-                               if (desc_status & 0x0030) rp->stats.rx_length_errors++;
-                               if (desc_status & 0x0048) rp->stats.rx_fifo_errors++;
-                               if (desc_status & 0x0004) rp->stats.rx_frame_errors++;
+                               dev->stats.rx_errors++;
+                               if (desc_status & 0x0030)
+                                       dev->stats.rx_length_errors++;
+                               if (desc_status & 0x0048)
+                                       dev->stats.rx_fifo_errors++;
+                               if (desc_status & 0x0004)
+                                       dev->stats.rx_frame_errors++;
                                if (desc_status & 0x0002) {
                                        /* this can also be updated outside the interrupt handler */
                                        spin_lock(&rp->lock);
-                                       rp->stats.rx_crc_errors++;
+                                       dev->stats.rx_crc_errors++;
                                        spin_unlock(&rp->lock);
                                }
                        }
@@ -1513,8 +1519,8 @@ static int rhine_rx(struct net_device *dev, int limit)
                        }
                        skb->protocol = eth_type_trans(skb, dev);
                        netif_receive_skb(skb);
-                       rp->stats.rx_bytes += pkt_len;
-                       rp->stats.rx_packets++;
+                       dev->stats.rx_bytes += pkt_len;
+                       dev->stats.rx_packets++;
                }
                entry = (++rp->cur_rx) % RX_RING_SIZE;
                rp->rx_head_desc = &rp->rx_ring[entry];
@@ -1599,8 +1605,8 @@ static void rhine_error(struct net_device *dev, int intr_status)
        if (intr_status & IntrLinkChange)
                rhine_check_media(dev, 0);
        if (intr_status & IntrStatsMax) {
-               rp->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs);
-               rp->stats.rx_missed_errors += ioread16(ioaddr + RxMissed);
+               dev->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs);
+               dev->stats.rx_missed_errors += ioread16(ioaddr + RxMissed);
                clear_tally_counters(ioaddr);
        }
        if (intr_status & IntrTxAborted) {
@@ -1654,12 +1660,12 @@ static struct net_device_stats *rhine_get_stats(struct net_device *dev)
        unsigned long flags;
 
        spin_lock_irqsave(&rp->lock, flags);
-       rp->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs);
-       rp->stats.rx_missed_errors += ioread16(ioaddr + RxMissed);
+       dev->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs);
+       dev->stats.rx_missed_errors += ioread16(ioaddr + RxMissed);
        clear_tally_counters(ioaddr);
        spin_unlock_irqrestore(&rp->lock, flags);
 
-       return &rp->stats;
+       return &dev->stats;
 }
 
 static void rhine_set_rx_mode(struct net_device *dev)
index 754a4b1..e2a7725 100644 (file)
@@ -1385,7 +1385,7 @@ static void velocity_free_td_ring(struct velocity_info *vptr)
 
 static int velocity_rx_srv(struct velocity_info *vptr, int status)
 {
-       struct net_device_stats *stats = &vptr->stats;
+       struct net_device_stats *stats = &vptr->dev->stats;
        int rd_curr = vptr->rx.curr;
        int works = 0;
 
@@ -1519,7 +1519,7 @@ static inline void velocity_iph_realign(struct velocity_info *vptr,
 static int velocity_receive_frame(struct velocity_info *vptr, int idx)
 {
        void (*pci_action)(struct pci_dev *, dma_addr_t, size_t, int);
-       struct net_device_stats *stats = &vptr->stats;
+       struct net_device_stats *stats = &vptr->dev->stats;
        struct velocity_rd_info *rd_info = &(vptr->rx.info[idx]);
        struct rx_desc *rd = &(vptr->rx.ring[idx]);
        int pkt_len = le16_to_cpu(rd->rdesc0.len) & 0x3fff;
@@ -1532,7 +1532,7 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
        }
 
        if (rd->rdesc0.RSR & RSR_MAR)
-               vptr->stats.multicast++;
+               stats->multicast++;
 
        skb = rd_info->skb;
 
@@ -1634,7 +1634,7 @@ static int velocity_tx_srv(struct velocity_info *vptr, u32 status)
        int idx;
        int works = 0;
        struct velocity_td_info *tdinfo;
-       struct net_device_stats *stats = &vptr->stats;
+       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;
@@ -2324,22 +2324,22 @@ static struct net_device_stats *velocity_get_stats(struct net_device *dev)
 
        /* If the hardware is down, don't touch MII */
        if(!netif_running(dev))
-               return &vptr->stats;
+               return &dev->stats;
 
        spin_lock_irq(&vptr->lock);
        velocity_update_hw_mibs(vptr);
        spin_unlock_irq(&vptr->lock);
 
-       vptr->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts];
-       vptr->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts];
-       vptr->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors];
+       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    */
-       vptr->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions];
+       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  */
-       vptr->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE];
+       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   */
@@ -2347,7 +2347,7 @@ static struct net_device_stats *velocity_get_stats(struct net_device *dev)
        /* detailed tx_errors */
 //  unsigned long   tx_fifo_errors;
 
-       return &vptr->stats;
+       return &dev->stats;
 }
 
 
index ea43e18..4cd3f6c 100644 (file)
@@ -1503,7 +1503,6 @@ struct velocity_info {
 
        struct pci_dev *pdev;
        struct net_device *dev;
-       struct net_device_stats stats;
 
        struct vlan_group    *vlgrp;
        u8 ip_addr[4];
index 6cc5bcd..09bd441 100644 (file)
@@ -470,7 +470,7 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
        }
 
        if (skb_is_gso(skb)) {
-               hdr->hdr_len = skb_transport_header(skb) - skb->data;
+               hdr->hdr_len = skb_headlen(skb);
                hdr->gso_size = skb_shinfo(skb)->gso_size;
                if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
                        hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
@@ -680,6 +680,7 @@ static void virtnet_set_rx_mode(struct net_device *dev)
        u8 promisc, allmulti;
        struct virtio_net_ctrl_mac *mac_data;
        struct dev_addr_list *addr;
+       struct netdev_hw_addr *ha;
        void *buf;
        int i;
 
@@ -718,9 +719,9 @@ static void virtnet_set_rx_mode(struct net_device *dev)
 
        /* Store the unicast list and count in the front of the buffer */
        mac_data->entries = dev->uc_count;
-       addr = dev->uc_list;
-       for (i = 0; i < dev->uc_count; i++, addr = addr->next)
-               memcpy(&mac_data->macs[i][0], addr->da_addr, ETH_ALEN);
+       i = 0;
+       list_for_each_entry(ha, &dev->uc_list, list)
+               memcpy(&mac_data->macs[i++][0], ha->addr, ETH_ALEN);
 
        sg_set_buf(&sg[0], mac_data,
                   sizeof(mac_data->entries) + (dev->uc_count * ETH_ALEN));
index 6b41c88..26cde57 100644 (file)
@@ -1884,17 +1884,13 @@ void __vxge_hw_mempool_destroy(struct vxge_hw_mempool *mempool)
                                mempool->memblock_size, dma_object);
        }
 
-       if (mempool->items_arr)
-               vfree(mempool->items_arr);
+       vfree(mempool->items_arr);
 
-       if (mempool->memblocks_dma_arr)
-               vfree(mempool->memblocks_dma_arr);
+       vfree(mempool->memblocks_dma_arr);
 
-       if (mempool->memblocks_priv_arr)
-               vfree(mempool->memblocks_priv_arr);
+       vfree(mempool->memblocks_priv_arr);
 
-       if (mempool->memblocks_arr)
-               vfree(mempool->memblocks_arr);
+       vfree(mempool->memblocks_arr);
 
        vfree(mempool);
 }
index b7f08f3..6c838b3 100644 (file)
@@ -677,7 +677,7 @@ vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr,
        return VXGE_HW_OK;
 }
 
-/* select a vpath to trasmit the packet */
+/* select a vpath to transmit the packet */
 static u32 vxge_get_vpath_no(struct vxgedev *vdev, struct sk_buff *skb,
        int *do_lock)
 {
@@ -992,7 +992,9 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
                                        VXGE_HW_FIFO_TXD_TX_CKO_UDP_EN);
 
        vxge_hw_fifo_txdl_post(fifo_hw, dtr);
-       dev->trans_start = jiffies;
+#ifdef NETIF_F_LLTX
+       dev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */
+#endif
        spin_unlock_irqrestore(&fifo->tx_lock, flags);
 
        VXGE_COMPLETE_VPATH_TX(fifo);
index 765a7f5..08b1a28 100644 (file)
@@ -731,8 +731,8 @@ static int hss_hdlc_poll(struct napi_struct *napi, int budget)
                dma_unmap_single(&dev->dev, desc->data,
                                 RX_SIZE, DMA_FROM_DEVICE);
 #else
-               dma_sync_single(&dev->dev, desc->data,
-                               RX_SIZE, DMA_FROM_DEVICE);
+               dma_sync_single_for_cpu(&dev->dev, desc->data,
+                                       RX_SIZE, DMA_FROM_DEVICE);
                memcpy_swab32((u32 *)skb->data, (u32 *)port->rx_buff_tab[n],
                              ALIGN(desc->pkt_len, 4) / 4);
 #endif
index b3cadb6..bd193ae 100644 (file)
@@ -292,8 +292,6 @@ void i2400m_report_tlv_system_state(struct i2400m *i2400m,
 
        d_fnstart(3, dev, "(i2400m %p ss %p [%u])\n", i2400m, ss, i2400m_state);
 
-       if (unlikely(i2400m->ready == 0))       /* act if up */
-               goto out;
        if (i2400m->state != i2400m_state) {
                i2400m->state = i2400m_state;
                wake_up_all(&i2400m->state_wq);
@@ -341,7 +339,6 @@ void i2400m_report_tlv_system_state(struct i2400m *i2400m,
                i2400m->bus_reset(i2400m, I2400M_RT_WARM);
                break;
        };
-out:
        d_fnend(3, dev, "(i2400m %p ss %p [%u]) = void\n",
                i2400m, ss, i2400m_state);
 }
@@ -372,8 +369,6 @@ void i2400m_report_tlv_media_status(struct i2400m *i2400m,
 
        d_fnstart(3, dev, "(i2400m %p ms %p [%u])\n", i2400m, ms, status);
 
-       if (unlikely(i2400m->ready == 0))       /* act if up */
-               goto out;
        switch (status) {
        case I2400M_MEDIA_STATUS_LINK_UP:
                netif_carrier_on(net_dev);
@@ -393,14 +388,59 @@ void i2400m_report_tlv_media_status(struct i2400m *i2400m,
                dev_err(dev, "HW BUG? unknown media status %u\n",
                        status);
        };
-out:
        d_fnend(3, dev, "(i2400m %p ms %p [%u]) = void\n",
                i2400m, ms, status);
 }
 
 
 /*
- * Parse a 'state report' and extract carrier on/off information
+ * Process a TLV from a 'state report'
+ *
+ * @i2400m: device descriptor
+ * @tlv: pointer to the TLV header; it has been already validated for
+ *     consistent size.
+ * @tag: for error messages
+ *
+ * Act on the TLVs from a 'state report'.
+ */
+static
+void i2400m_report_state_parse_tlv(struct i2400m *i2400m,
+                                  const struct i2400m_tlv_hdr *tlv,
+                                  const char *tag)
+{
+       struct device *dev = i2400m_dev(i2400m);
+       const struct i2400m_tlv_media_status *ms;
+       const struct i2400m_tlv_system_state *ss;
+       const struct i2400m_tlv_rf_switches_status *rfss;
+
+       if (0 == i2400m_tlv_match(tlv, I2400M_TLV_SYSTEM_STATE, sizeof(*ss))) {
+               ss = container_of(tlv, typeof(*ss), hdr);
+               d_printf(2, dev, "%s: system state TLV "
+                        "found (0x%04x), state 0x%08x\n",
+                        tag, I2400M_TLV_SYSTEM_STATE,
+                        le32_to_cpu(ss->state));
+               i2400m_report_tlv_system_state(i2400m, ss);
+       }
+       if (0 == i2400m_tlv_match(tlv, I2400M_TLV_RF_STATUS, sizeof(*rfss))) {
+               rfss = container_of(tlv, typeof(*rfss), hdr);
+               d_printf(2, dev, "%s: RF status TLV "
+                        "found (0x%04x), sw 0x%02x hw 0x%02x\n",
+                        tag, I2400M_TLV_RF_STATUS,
+                        le32_to_cpu(rfss->sw_rf_switch),
+                        le32_to_cpu(rfss->hw_rf_switch));
+               i2400m_report_tlv_rf_switches_status(i2400m, rfss);
+       }
+       if (0 == i2400m_tlv_match(tlv, I2400M_TLV_MEDIA_STATUS, sizeof(*ms))) {
+               ms = container_of(tlv, typeof(*ms), hdr);
+               d_printf(2, dev, "%s: Media Status TLV: %u\n",
+                        tag, le32_to_cpu(ms->media_status));
+               i2400m_report_tlv_media_status(i2400m, ms);
+       }
+}
+
+
+/*
+ * Parse a 'state report' and extract information
  *
  * @i2400m: device descriptor
  * @l3l4_hdr: pointer to message; it has been already validated for
@@ -409,13 +449,7 @@ out:
  *        declaration is assumed to be congruent with @size (as in
  *        sizeof(*l3l4_hdr) + l3l4_hdr->length == size)
  *
- * Extract from the report state the system state TLV and infer from
- * there if we have a carrier or not. Update our local state and tell
- * netdev.
- *
- * When setting the carrier, it's fine to set OFF twice (for example),
- * as netif_carrier_off() will not generate two OFF events (just on
- * the transitions).
+ * Walk over the TLVs in a report state and act on them.
  */
 static
 void i2400m_report_state_hook(struct i2400m *i2400m,
@@ -424,9 +458,6 @@ void i2400m_report_state_hook(struct i2400m *i2400m,
 {
        struct device *dev = i2400m_dev(i2400m);
        const struct i2400m_tlv_hdr *tlv;
-       const struct i2400m_tlv_system_state *ss;
-       const struct i2400m_tlv_rf_switches_status *rfss;
-       const struct i2400m_tlv_media_status *ms;
        size_t tlv_size = le16_to_cpu(l3l4_hdr->length);
 
        d_fnstart(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s)\n",
@@ -434,34 +465,8 @@ void i2400m_report_state_hook(struct i2400m *i2400m,
        tlv = NULL;
 
        while ((tlv = i2400m_tlv_buffer_walk(i2400m, &l3l4_hdr->pl,
-                                            tlv_size, tlv))) {
-               if (0 == i2400m_tlv_match(tlv, I2400M_TLV_SYSTEM_STATE,
-                                         sizeof(*ss))) {
-                       ss = container_of(tlv, typeof(*ss), hdr);
-                       d_printf(2, dev, "%s: system state TLV "
-                                "found (0x%04x), state 0x%08x\n",
-                                tag, I2400M_TLV_SYSTEM_STATE,
-                                le32_to_cpu(ss->state));
-                       i2400m_report_tlv_system_state(i2400m, ss);
-               }
-               if (0 == i2400m_tlv_match(tlv, I2400M_TLV_RF_STATUS,
-                                         sizeof(*rfss))) {
-                       rfss = container_of(tlv, typeof(*rfss), hdr);
-                       d_printf(2, dev, "%s: RF status TLV "
-                                "found (0x%04x), sw 0x%02x hw 0x%02x\n",
-                                tag, I2400M_TLV_RF_STATUS,
-                                le32_to_cpu(rfss->sw_rf_switch),
-                                le32_to_cpu(rfss->hw_rf_switch));
-                       i2400m_report_tlv_rf_switches_status(i2400m, rfss);
-               }
-               if (0 == i2400m_tlv_match(tlv, I2400M_TLV_MEDIA_STATUS,
-                                         sizeof(*ms))) {
-                       ms = container_of(tlv, typeof(*ms), hdr);
-                       d_printf(2, dev, "%s: Media Status TLV: %u\n",
-                                tag, le32_to_cpu(ms->media_status));
-                       i2400m_report_tlv_media_status(i2400m, ms);
-               }
-       }
+                                            tlv_size, tlv)))
+               i2400m_report_state_parse_tlv(i2400m, tlv, tag);
        d_fnend(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s) = void\n",
                i2400m, l3l4_hdr, size, tag);
 }
@@ -721,6 +726,8 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m,
                ack_timeout = HZ;
        };
 
+       if (unlikely(i2400m->trace_msg_from_user))
+               wimax_msg(&i2400m->wimax_dev, "echo", buf, buf_len, GFP_KERNEL);
        /* The RX path in rx.c will put any response for this message
         * in i2400m->ack_skb and wake us up. If we cancel the wait,
         * we need to change the value of i2400m->ack_skb to something
@@ -755,6 +762,9 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m,
        ack_l3l4_hdr = wimax_msg_data_len(ack_skb, &ack_len);
 
        /* Check the ack and deliver it if it is ok */
+       if (unlikely(i2400m->trace_msg_from_user))
+               wimax_msg(&i2400m->wimax_dev, "echo",
+                         ack_l3l4_hdr, ack_len, GFP_KERNEL);
        result = i2400m_msg_size_check(i2400m, ack_l3l4_hdr, ack_len);
        if (result < 0) {
                dev_err(dev, "HW BUG? reply to message 0x%04x: %d\n",
index 07a54ba..ef16c57 100644 (file)
@@ -62,6 +62,7 @@
  *   unregister_netdev()
  */
 #include "i2400m.h"
+#include <linux/etherdevice.h>
 #include <linux/wimax/i2400m.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -234,9 +235,6 @@ int i2400m_op_msg_from_user(struct wimax_dev *wimax_dev,
        result = PTR_ERR(ack_skb);
        if (IS_ERR(ack_skb))
                goto error_msg_to_dev;
-       if (unlikely(i2400m->trace_msg_from_user))
-               wimax_msg(&i2400m->wimax_dev, "trace",
-                         msg_buf, msg_len, GFP_KERNEL);
        result = wimax_msg_send(&i2400m->wimax_dev, ack_skb);
 error_msg_to_dev:
        d_fnend(4, dev, "(wimax_dev %p [i2400m %p] msg_buf %p msg_len %zu "
@@ -650,6 +648,7 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags)
        result = i2400m_read_mac_addr(i2400m);
        if (result < 0)
                goto error_read_mac_addr;
+       random_ether_addr(i2400m->src_mac_addr);
 
        result = register_netdev(net_dev);      /* Okey dokey, bring it up */
        if (result < 0) {
index 3ae2df3..434ba31 100644 (file)
@@ -323,6 +323,10 @@ struct i2400m_roq;
  *     delivered. Then the driver can release them to the host. See
  *     drivers/net/i2400m/rx.c for details.
  *
+ * @src_mac_addr: MAC address used to make ethernet packets be coming
+ *     from. This is generated at i2400m_setup() time and used during
+ *     the life cycle of the instance. See i2400m_fake_eth_header().
+ *
  * @init_mutex: Mutex used for serializing the device bringup
  *     sequence; this way if the device reboots in the middle, we
  *     don't try to do a bringup again while we are tearing down the
@@ -421,6 +425,7 @@ struct i2400m {
        unsigned rx_pl_num, rx_pl_max, rx_pl_min,
                rx_num, rx_size_acc, rx_size_min, rx_size_max;
        struct i2400m_roq *rx_roq;      /* not under rx_lock! */
+       u8 src_mac_addr[ETH_HLEN];
 
        struct mutex msg_mutex;         /* serialize command execution */
        struct completion msg_completion;
index 6b1fe7a..9653f47 100644 (file)
@@ -404,10 +404,12 @@ static
 void i2400m_rx_fake_eth_header(struct net_device *net_dev,
                               void *_eth_hdr, __be16 protocol)
 {
+       struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
        struct ethhdr *eth_hdr = _eth_hdr;
 
        memcpy(eth_hdr->h_dest, net_dev->dev_addr, sizeof(eth_hdr->h_dest));
-       memset(eth_hdr->h_source, 0, sizeof(eth_hdr->h_dest));
+       memcpy(eth_hdr->h_source, i2400m->src_mac_addr,
+              sizeof(eth_hdr->h_source));
        eth_hdr->h_proto = protocol;
 }
 
index f9fc389..7643850 100644 (file)
@@ -177,7 +177,8 @@ void i2400m_report_hook_work(struct work_struct *ws)
        struct i2400m_work *iw =
                container_of(ws, struct i2400m_work, ws);
        struct i2400m_report_hook_args *args = (void *) iw->pl;
-       i2400m_report_hook(iw->i2400m, args->l3l4_hdr, args->size);
+       if (iw->i2400m->ready)
+               i2400m_report_hook(iw->i2400m, args->l3l4_hdr, args->size);
        kfree_skb(args->skb_rx);
        i2400m_put(iw->i2400m);
        kfree(iw);
@@ -309,6 +310,9 @@ void i2400m_rx_ctl(struct i2400m *i2400m, struct sk_buff *skb_rx,
                skb_get(skb_rx);
                i2400m_queue_work(i2400m, i2400m_report_hook_work,
                                  GFP_KERNEL, &args, sizeof(args));
+               if (unlikely(i2400m->trace_msg_from_user))
+                       wimax_msg(&i2400m->wimax_dev, "echo",
+                                 l3l4_hdr, size, GFP_KERNEL);
                result = wimax_msg(&i2400m->wimax_dev, NULL, l3l4_hdr, size,
                                   GFP_KERNEL);
                if (result < 0)
index 5ac5e76..777c981 100644 (file)
@@ -409,19 +409,19 @@ int i2400ms_probe(struct sdio_func *func,
        i2400m->bus_fw_names = i2400ms_bus_fw_names;
        i2400m->bus_bm_mac_addr_impaired = 1;
 
-       result = i2400ms_enable_function(i2400ms->func);
-       if (result < 0) {
-               dev_err(dev, "Cannot enable SDIO function: %d\n", result);
-               goto error_func_enable;
-       }
-
        sdio_claim_host(func);
        result = sdio_set_block_size(func, I2400MS_BLK_SIZE);
+       sdio_release_host(func);
        if (result < 0) {
                dev_err(dev, "Failed to set block size: %d\n", result);
                goto error_set_blk_size;
        }
-       sdio_release_host(func);
+
+       result = i2400ms_enable_function(i2400ms->func);
+       if (result < 0) {
+               dev_err(dev, "Cannot enable SDIO function: %d\n", result);
+               goto error_func_enable;
+       }
 
        result = i2400m_setup(i2400m, I2400M_BRI_NO_REBOOT);
        if (result < 0) {
@@ -440,12 +440,12 @@ int i2400ms_probe(struct sdio_func *func,
 error_debugfs_add:
        i2400m_release(i2400m);
 error_setup:
-       sdio_set_drvdata(func, NULL);
        sdio_claim_host(func);
-error_set_blk_size:
        sdio_disable_func(func);
        sdio_release_host(func);
 error_func_enable:
+error_set_blk_size:
+       sdio_set_drvdata(func, NULL);
        free_netdev(net_dev);
 error_alloc_netdev:
        return result;
index ca4151a..1785132 100644 (file)
@@ -505,27 +505,52 @@ int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg)
 #ifdef CONFIG_PM
        struct usb_device *usb_dev = i2400mu->usb_dev;
 #endif
+       unsigned is_autosuspend = 0;
        struct i2400m *i2400m = &i2400mu->i2400m;
 
+#ifdef CONFIG_PM
+       if (usb_dev->auto_pm > 0)
+               is_autosuspend = 1;
+#endif
+
        d_fnstart(3, dev, "(iface %p pm_msg %u)\n", iface, pm_msg.event);
        if (i2400m->updown == 0)
                goto no_firmware;
-       d_printf(1, dev, "fw up, requesting standby\n");
+       if (i2400m->state == I2400M_SS_DATA_PATH_CONNECTED && is_autosuspend) {
+               /* ugh -- the device is connected and this suspend
+                * request is an autosuspend one (not a system standby
+                * / hibernate).
+                *
+                * The only way the device can go to standby is if the
+                * link with the base station is in IDLE mode; that
+                * were the case, we'd be in status
+                * I2400M_SS_CONNECTED_IDLE. But we are not.
+                *
+                * If we *tell* him to go power save now, it'll reset
+                * as a precautionary measure, so if this is an
+                * autosuspend thing, say no and it'll come back
+                * later, when the link is IDLE
+                */
+               result = -EBADF;
+               d_printf(1, dev, "fw up, link up, not-idle, autosuspend: "
+                        "not entering powersave\n");
+               goto error_not_now;
+       }
+       d_printf(1, dev, "fw up: entering powersave\n");
        atomic_dec(&i2400mu->do_autopm);
        result = i2400m_cmd_enter_powersave(i2400m);
        atomic_inc(&i2400mu->do_autopm);
-#ifdef CONFIG_PM
-       if (result < 0 && usb_dev->auto_pm == 0) {
+       if (result < 0 && !is_autosuspend) {
                /* System suspend, can't fail */
                dev_err(dev, "failed to suspend, will reset on resume\n");
                result = 0;
        }
-#endif
        if (result < 0)
                goto error_enter_powersave;
        i2400mu_notification_release(i2400mu);
-       d_printf(1, dev, "fw up, got standby\n");
+       d_printf(1, dev, "powersave requested\n");
 error_enter_powersave:
+error_not_now:
 no_firmware:
        d_fnend(3, dev, "(iface %p pm_msg %u) = %d\n",
                iface, pm_msg.event, result);
index a67d292..fb7541c 100644 (file)
@@ -153,7 +153,7 @@ config LIBERTAS_SDIO
 
 config LIBERTAS_SPI
        tristate "Marvell Libertas 8686 SPI 802.11b/g cards"
-       depends on LIBERTAS && SPI && GENERIC_GPIO
+       depends on LIBERTAS && SPI
        ---help---
          A driver for Marvell Libertas 8686 SPI devices.
 
@@ -333,11 +333,11 @@ config USB_ZD1201
 config USB_NET_RNDIS_WLAN
        tristate "Wireless RNDIS USB support"
        depends on USB && WLAN_80211 && EXPERIMENTAL
+       depends on CFG80211
        select USB_USBNET
        select USB_NET_CDCETHER
        select USB_NET_RNDIS_HOST
        select WIRELESS_EXT
-       select CFG80211
        ---help---
          This is a driver for wireless RNDIS devices.
          These are USB based adapters found in devices such as:
@@ -431,6 +431,7 @@ config RTL8187
          ASUS P5B Deluxe
          Toshiba Satellite Pro series of laptops
          Asus Wireless Link
+         Linksys WUSB54GC-EU
 
          Thanks to Realtek for their support!
 
index cea7f14..4efbdbe 100644 (file)
@@ -1873,18 +1873,18 @@ static void at76_dwork_hw_scan(struct work_struct *work)
        if (ret != CMD_STATUS_COMPLETE) {
                queue_delayed_work(priv->hw->workqueue, &priv->dwork_hw_scan,
                                   SCAN_POLL_INTERVAL);
-               goto exit;
+               mutex_unlock(&priv->mtx);
+               return;
        }
 
-       ieee80211_scan_completed(priv->hw, false);
-
        if (is_valid_ether_addr(priv->bssid))
                at76_join(priv);
 
-       ieee80211_wake_queues(priv->hw);
-
-exit:
        mutex_unlock(&priv->mtx);
+
+       ieee80211_scan_completed(priv->hw, false);
+
+       ieee80211_wake_queues(priv->hw);
 }
 
 static int at76_hw_scan(struct ieee80211_hw *hw,
index 17bd3ea..bb97981 100644 (file)
@@ -91,6 +91,7 @@ struct ar9170_led {
        struct led_classdev l;
        char name[32];
        unsigned int toggled;
+       bool last_state;
        bool registered;
 };
 
@@ -101,7 +102,6 @@ enum ar9170_device_state {
        AR9170_STOPPED,
        AR9170_IDLE,
        AR9170_STARTED,
-       AR9170_ASSOCIATED,
 };
 
 struct ar9170_rxstream_mpdu_merge {
@@ -109,6 +109,11 @@ struct ar9170_rxstream_mpdu_merge {
        bool has_plcp;
 };
 
+#define AR9170_QUEUE_TIMEOUT           64
+#define AR9170_TX_TIMEOUT              8
+#define AR9170_JANITOR_DELAY           128
+#define AR9170_TX_INVALID_RATE         0xffffffff
+
 struct ar9170 {
        struct ieee80211_hw *hw;
        struct mutex mutex;
@@ -117,10 +122,11 @@ struct ar9170 {
 
        int (*open)(struct ar9170 *);
        void (*stop)(struct ar9170 *);
-       int (*tx)(struct ar9170 *, struct sk_buff *, bool, unsigned int);
+       int (*tx)(struct ar9170 *, struct sk_buff *);
        int (*exec_cmd)(struct ar9170 *, enum ar9170_cmd, u32 ,
                        void *, u32 , void *);
        void (*callback_cmd)(struct ar9170 *, u32 , void *);
+       int (*flush)(struct ar9170 *);
 
        /* interface mode settings */
        struct ieee80211_vif *vif;
@@ -140,7 +146,7 @@ struct ar9170 {
        struct work_struct filter_config_work;
        u64 cur_mc_hash, want_mc_hash;
        u32 cur_filter, want_filter;
-       unsigned int filter_changed;
+       unsigned long filter_changed;
        unsigned int filter_state;
        bool sniffer_enabled;
 
@@ -177,10 +183,10 @@ struct ar9170 {
        struct ar9170_eeprom eeprom;
        struct ath_regulatory regulatory;
 
-       /* global tx status for unregistered Stations. */
-       struct sk_buff_head global_tx_status;
-       struct sk_buff_head global_tx_status_waste;
-       struct delayed_work tx_status_janitor;
+       /* tx queues - as seen by hw - */
+       struct sk_buff_head tx_pending[__AR9170_NUM_TXQ];
+       struct sk_buff_head tx_status[__AR9170_NUM_TXQ];
+       struct delayed_work tx_janitor;
 
        /* rxstream mpdu merge */
        struct ar9170_rxstream_mpdu_merge rx_mpdu;
@@ -189,13 +195,21 @@ struct ar9170 {
 };
 
 struct ar9170_sta_info {
-       struct sk_buff_head tx_status[__AR9170_NUM_TXQ];
 };
 
-#define IS_STARTED(a)          (a->state >= AR9170_STARTED)
-#define IS_ACCEPTING_CMD(a)    (a->state >= AR9170_IDLE)
+#define AR9170_TX_FLAG_WAIT_FOR_ACK    BIT(0)
+#define AR9170_TX_FLAG_NO_ACK          BIT(1)
+#define AR9170_TX_FLAG_BLOCK_ACK       BIT(2)
+
+struct ar9170_tx_info {
+       unsigned long timeout;
+       unsigned int flags;
+};
+
+#define IS_STARTED(a)          (((struct ar9170 *)a)->state >= AR9170_STARTED)
+#define IS_ACCEPTING_CMD(a)    (((struct ar9170 *)a)->state >= AR9170_IDLE)
 
-#define AR9170_FILTER_CHANGED_PROMISC          BIT(0)
+#define AR9170_FILTER_CHANGED_MODE             BIT(0)
 #define AR9170_FILTER_CHANGED_MULTICAST                BIT(1)
 #define AR9170_FILTER_CHANGED_FRAMEFILTER      BIT(2)
 
@@ -204,8 +218,9 @@ void *ar9170_alloc(size_t priv_size);
 int ar9170_register(struct ar9170 *ar, struct device *pdev);
 void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb);
 void ar9170_unregister(struct ar9170 *ar);
-void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb,
-                            bool update_statistics, u16 tx_status);
+void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb);
+void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len);
+int ar9170_nag_limiter(struct ar9170 *ar);
 
 /* MAC */
 int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -215,6 +230,9 @@ int ar9170_update_multicast(struct ar9170 *ar);
 int ar9170_update_frame_filter(struct ar9170 *ar);
 int ar9170_set_operating_mode(struct ar9170 *ar);
 int ar9170_set_beacon_timers(struct ar9170 *ar);
+int ar9170_set_dyn_sifs_ack(struct ar9170 *ar);
+int ar9170_set_slot_time(struct ar9170 *ar);
+int ar9170_set_basic_rates(struct ar9170 *ar);
 int ar9170_set_hwretry_limit(struct ar9170 *ar, u32 max_retry);
 int ar9170_update_beacon(struct ar9170 *ar);
 void ar9170_new_beacon(struct work_struct *work);
index 3293e0f..6cbfb2f 100644 (file)
@@ -207,7 +207,8 @@ enum ar9170_cmd {
 #define AR9170_MAC_REG_AC1_AC0_TXOP            (AR9170_MAC_REG_BASE + 0xB44)
 #define AR9170_MAC_REG_AC3_AC2_TXOP            (AR9170_MAC_REG_BASE + 0xB48)
 
-#define AR9170_MAC_REG_AMPDU_SET               (AR9170_MAC_REG_BASE + 0xba0)
+#define AR9170_MAC_REG_AMPDU_FACTOR            (AR9170_MAC_REG_BASE + 0xB9C)
+#define AR9170_MAC_REG_AMPDU_DENSITY           (AR9170_MAC_REG_BASE + 0xBA0)
 
 #define AR9170_MAC_REG_ACK_TABLE               (AR9170_MAC_REG_BASE + 0xC00)
 #define AR9170_MAC_REG_AMPDU_RX_THRESH         (AR9170_MAC_REG_BASE + 0xC50)
@@ -376,7 +377,6 @@ static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_macstatus *t)
 #define AR9170_RX_ERROR_FATAL                  0x80
 
 struct ar9170_cmd_tx_status {
-       __le16 unkn;
        u8 dst[ETH_ALEN];
        __le32 rate;
        __le16 status;
@@ -394,6 +394,7 @@ struct ar9170_cmd_ba_failed_count {
 struct ar9170_cmd_response {
        u8 flag;
        u8 type;
+       __le16 padding;
 
        union {
                struct ar9170_cmd_tx_status             tx_status;
@@ -419,4 +420,7 @@ enum ar9170_txq {
        __AR9170_NUM_TXQ,
 };
 
+#define AR9170_TXQ_DEPTH       32
+#define AR9170_TX_MAX_PENDING  128
+
 #endif /* __AR9170_HW_H */
index 341cead..63fda6c 100644 (file)
@@ -74,7 +74,7 @@ static void ar9170_update_leds(struct work_struct *work)
 
        mutex_lock(&ar->mutex);
        for (i = 0; i < AR9170_NUM_LEDS; i++)
-               if (ar->leds[i].toggled) {
+               if (ar->leds[i].registered && ar->leds[i].toggled) {
                        led_val |= 1 << i;
 
                        tmp = 70 + 200 / (ar->leds[i].toggled);
@@ -101,9 +101,15 @@ static void ar9170_led_brightness_set(struct led_classdev *led,
        struct ar9170_led *arl = container_of(led, struct ar9170_led, l);
        struct ar9170 *ar = arl->ar;
 
-       arl->toggled++;
+       if (unlikely(!arl->registered))
+               return ;
+
+       if (arl->last_state != !!brightness) {
+               arl->toggled++;
+               arl->last_state = !!brightness;
+       }
 
-       if (likely(IS_ACCEPTING_CMD(ar) && brightness))
+       if (likely(IS_ACCEPTING_CMD(ar) && arl->toggled))
                queue_delayed_work(ar->hw->workqueue, &ar->led_work, HZ/10);
 }
 
@@ -136,13 +142,14 @@ void ar9170_unregister_leds(struct ar9170 *ar)
 {
        int i;
 
-       cancel_delayed_work_sync(&ar->led_work);
-
        for (i = 0; i < AR9170_NUM_LEDS; i++)
                if (ar->leds[i].registered) {
                        led_classdev_unregister(&ar->leds[i].l);
                        ar->leds[i].registered = false;
+                       ar->leds[i].toggled = 0;
                }
+
+       cancel_delayed_work_sync(&ar->led_work);
 }
 
 int ar9170_register_leds(struct ar9170 *ar)
index 43aeb69..d9f1f46 100644 (file)
 #include "ar9170.h"
 #include "cmd.h"
 
+int ar9170_set_dyn_sifs_ack(struct ar9170 *ar)
+{
+       u32 val;
+
+       if (conf_is_ht40(&ar->hw->conf))
+               val = 0x010a;
+       else {
+               if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ)
+                       val = 0x105;
+               else
+                       val = 0x104;
+       }
+
+       return ar9170_write_reg(ar, AR9170_MAC_REG_DYNAMIC_SIFS_ACK, val);
+}
+
+int ar9170_set_slot_time(struct ar9170 *ar)
+{
+       u32 slottime = 20;
+
+       if (!ar->vif)
+               return 0;
+
+       if ((ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) ||
+           ar->vif->bss_conf.use_short_slot)
+               slottime = 9;
+
+       return ar9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME, slottime << 10);
+}
+
+int ar9170_set_basic_rates(struct ar9170 *ar)
+{
+       u8 cck, ofdm;
+
+       if (!ar->vif)
+               return 0;
+
+       ofdm = ar->vif->bss_conf.basic_rates >> 4;
+
+       /* FIXME: is still necessary? */
+       if (ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ)
+               cck = 0;
+       else
+               cck = ar->vif->bss_conf.basic_rates & 0xf;
+
+       return ar9170_write_reg(ar, AR9170_MAC_REG_BASIC_RATE,
+                               ofdm << 8 | cck);
+}
+
 int ar9170_set_qos(struct ar9170 *ar)
 {
        ar9170_regwrite_begin(ar);
@@ -84,7 +133,7 @@ static int ar9170_set_ampdu_density(struct ar9170 *ar, u8 mpdudensity)
        val = 0x140a00 | (mpdudensity ? (mpdudensity + 1) : 0);
 
        ar9170_regwrite_begin(ar);
-       ar9170_regwrite(AR9170_MAC_REG_AMPDU_SET, val);
+       ar9170_regwrite(AR9170_MAC_REG_AMPDU_DENSITY, val);
        ar9170_regwrite_finish();
 
        return ar9170_regwrite_result();
@@ -398,10 +447,10 @@ int ar9170_update_beacon(struct ar9170 *ar)
        /* XXX: use skb->cb info */
        if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ)
                ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP,
-                               ((skb->len + 4) << (3+16)) + 0x0400);
+                               ((skb->len + 4) << (3 + 16)) + 0x0400);
        else
                ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP,
-                               ((skb->len + 4) << (3+16)) + 0x0400);
+                               ((skb->len + 4) << 16) + 0x001b);
 
        ar9170_regwrite(AR9170_MAC_REG_BCN_LENGTH, skb->len + 4);
        ar9170_regwrite(AR9170_MAC_REG_BCN_ADDR, AR9170_BEACON_BUFFER_ADDRESS);
index 99df9dd..9d38cf6 100644 (file)
@@ -146,7 +146,6 @@ static struct ieee80211_channel ar9170_5ghz_chantable[] = {
 {                                                                      \
        .ht_supported   = true,                                         \
        .cap            = IEEE80211_HT_CAP_MAX_AMSDU |                  \
-                         IEEE80211_HT_CAP_SM_PS |                      \
                          IEEE80211_HT_CAP_SUP_WIDTH_20_40 |            \
                          IEEE80211_HT_CAP_SGI_40 |                     \
                          IEEE80211_HT_CAP_DSSSCCK40 |                  \
@@ -174,59 +173,122 @@ static struct ieee80211_supported_band ar9170_band_5GHz = {
        .ht_cap         = AR9170_HT_CAP,
 };
 
-#ifdef AR9170_QUEUE_DEBUG
-/*
- * In case some wants works with AR9170's crazy tx_status queueing techniques.
- * He might need this rather useful probing function.
- *
- * NOTE: caller must hold the queue's spinlock!
- */
+static void ar9170_tx(struct ar9170 *ar);
 
+#ifdef AR9170_QUEUE_DEBUG
 static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
 {
        struct ar9170_tx_control *txc = (void *) skb->data;
-       struct ieee80211_hdr *hdr = (void *)txc->frame_data;
+       struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(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, queue:%d, DA:[%pM] "
-                         "mac_control:%04x, phy_control:%08x]\n",
+       printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x "
+                         "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), le16_to_cpu(txc->mac_control),
-              le32_to_cpu(txc->phy_control));
+              ieee80211_get_DA(hdr), arinfo->flags,
+              le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control),
+              jiffies_to_msecs(arinfo->timeout - jiffies));
 }
 
-static void ar9170_dump_station_tx_status_queue(struct ar9170 *ar,
-                                               struct sk_buff_head *queue)
+static void __ar9170_dump_txqueue(struct ar9170 *ar,
+                               struct sk_buff_head *queue)
 {
        struct sk_buff *skb;
        int i = 0;
 
        printk(KERN_DEBUG "---[ cut here ]---\n");
-       printk(KERN_DEBUG "%s: %d entries in tx_status queue.\n",
+       printk(KERN_DEBUG "%s: %d entries in queue.\n",
               wiphy_name(ar->hw->wiphy), skb_queue_len(queue));
 
        skb_queue_walk(queue, skb) {
-               struct ar9170_tx_control *txc = (void *) skb->data;
-               struct ieee80211_hdr *hdr = (void *)txc->frame_data;
-
-               printk(KERN_DEBUG "index:%d => \n", i);
+               printk(KERN_DEBUG "index:%d => \n", i++);
                ar9170_print_txheader(ar, skb);
        }
+       if (i != skb_queue_len(queue))
+               printk(KERN_DEBUG "WARNING: queue frame counter "
+                      "mismatch %d != %d\n", skb_queue_len(queue), i);
        printk(KERN_DEBUG "---[ end ]---\n");
 }
-#endif /* AR9170_QUEUE_DEBUG */
 
-void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb,
-                            bool valid_status, u16 tx_status)
+static void ar9170_dump_txqueue(struct ar9170 *ar,
+                               struct sk_buff_head *queue)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&queue->lock, flags);
+       __ar9170_dump_txqueue(ar, queue);
+       spin_unlock_irqrestore(&queue->lock, flags);
+}
+
+static void __ar9170_dump_txstats(struct ar9170 *ar)
+{
+       int i;
+
+       printk(KERN_DEBUG "%s: QoS queue stats\n",
+              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]));
+}
+
+static void ar9170_dump_txstats(struct ar9170 *ar)
 {
-       struct ieee80211_tx_info *txinfo;
-       unsigned int retries = 0, queue = skb_get_queue_mapping(skb);
        unsigned long flags;
 
        spin_lock_irqsave(&ar->tx_stats_lock, flags);
-       ar->tx_stats[queue].len--;
-       if (ieee80211_queue_stopped(ar->hw, queue))
-               ieee80211_wake_queue(ar->hw, queue);
+       __ar9170_dump_txstats(ar);
        spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
+}
+#endif /* AR9170_QUEUE_DEBUG */
+
+/* caller must guarantee exclusive access for _bin_ queue. */
+static void ar9170_recycle_expired(struct ar9170 *ar,
+                                  struct sk_buff_head *queue,
+                                  struct sk_buff_head *bin)
+{
+       struct sk_buff *skb, *old = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&queue->lock, flags);
+       while ((skb = skb_peek(queue))) {
+               struct ieee80211_tx_info *txinfo;
+               struct ar9170_tx_info *arinfo;
+
+               txinfo = IEEE80211_SKB_CB(skb);
+               arinfo = (void *) txinfo->rate_driver_data;
+
+               if (time_is_before_jiffies(arinfo->timeout)) {
+#ifdef AR9170_QUEUE_DEBUG
+                       printk(KERN_DEBUG "%s: [%ld > %ld] frame expired => "
+                              "recycle \n", wiphy_name(ar->hw->wiphy),
+                              jiffies, arinfo->timeout);
+                       ar9170_print_txheader(ar, skb);
+#endif /* AR9170_QUEUE_DEBUG */
+                       __skb_unlink(skb, queue);
+                       __skb_queue_tail(bin, skb);
+               } else {
+                       break;
+               }
+
+               if (unlikely(old == skb)) {
+                       /* bail out - queue is shot. */
+
+                       WARN_ON(1);
+                       break;
+               }
+               old = skb;
+       }
+       spin_unlock_irqrestore(&queue->lock, flags);
+}
+
+static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb,
+                                   u16 tx_status)
+{
+       struct ieee80211_tx_info *txinfo;
+       unsigned int retries = 0;
 
        txinfo = IEEE80211_SKB_CB(skb);
        ieee80211_tx_info_clear_status(txinfo);
@@ -248,45 +310,61 @@ void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb,
                break;
        }
 
-       if (valid_status)
-               txinfo->status.rates[0].count = retries + 1;
-
+       txinfo->status.rates[0].count = retries + 1;
        skb_pull(skb, sizeof(struct ar9170_tx_control));
        ieee80211_tx_status_irqsafe(ar->hw, skb);
 }
 
-static struct sk_buff *ar9170_find_skb_in_queue(struct ar9170 *ar,
-                                               const u8 *mac,
-                                               const u32 queue,
-                                               struct sk_buff_head *q)
+void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
 {
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ar9170_tx_info *arinfo = (void *) info->rate_driver_data;
+       unsigned int queue = skb_get_queue_mapping(skb);
        unsigned long flags;
-       struct sk_buff *skb;
 
-       spin_lock_irqsave(&q->lock, flags);
-       skb_queue_walk(q, skb) {
-               struct ar9170_tx_control *txc = (void *) skb->data;
-               struct ieee80211_hdr *hdr = (void *) txc->frame_data;
-               u32 txc_queue = (le32_to_cpu(txc->phy_control) &
-                               AR9170_TX_PHY_QOS_MASK) >>
-                               AR9170_TX_PHY_QOS_SHIFT;
+       spin_lock_irqsave(&ar->tx_stats_lock, flags);
+       ar->tx_stats[queue].len--;
 
-               if  ((queue != txc_queue) ||
-                    (compare_ether_addr(ieee80211_get_DA(hdr), mac)))
-                       continue;
+       if (skb_queue_empty(&ar->tx_pending[queue])) {
+#ifdef AR9170_QUEUE_STOP_DEBUG
+               printk(KERN_DEBUG "%s: wake queue %d\n",
+                      wiphy_name(ar->hw->wiphy), queue);
+               __ar9170_dump_txstats(ar);
+#endif /* AR9170_QUEUE_STOP_DEBUG */
+               ieee80211_wake_queue(ar->hw, queue);
+       }
+       spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
 
-               __skb_unlink(skb, q);
-               spin_unlock_irqrestore(&q->lock, flags);
-               return skb;
+       if (arinfo->flags & AR9170_TX_FLAG_BLOCK_ACK) {
+               dev_kfree_skb_any(skb);
+       } else if (arinfo->flags & AR9170_TX_FLAG_WAIT_FOR_ACK) {
+               arinfo->timeout = jiffies +
+                                 msecs_to_jiffies(AR9170_TX_TIMEOUT);
+
+               skb_queue_tail(&ar->tx_status[queue], skb);
+       } else if (arinfo->flags & AR9170_TX_FLAG_NO_ACK) {
+               ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED);
+       } else {
+#ifdef AR9170_QUEUE_DEBUG
+               printk(KERN_DEBUG "%s: unsupported frame flags!\n",
+                      wiphy_name(ar->hw->wiphy));
+               ar9170_print_txheader(ar, skb);
+#endif /* AR9170_QUEUE_DEBUG */
+               dev_kfree_skb_any(skb);
+       }
+
+       if (!ar->tx_stats[queue].len &&
+           !skb_queue_empty(&ar->tx_pending[queue])) {
+               ar9170_tx(ar);
        }
-       spin_unlock_irqrestore(&q->lock, flags);
-       return NULL;
 }
 
-static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac,
-                                             const u32 queue)
+static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar,
+                                            const u8 *mac,
+                                            struct sk_buff_head *queue,
+                                            const u32 rate)
 {
-       struct ieee80211_sta *sta;
+       unsigned long flags;
        struct sk_buff *skb;
 
        /*
@@ -297,85 +375,94 @@ static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac,
         * the firmware provided (-> destination MAC, and phy_control) -
         * and hope that we picked the right one...
         */
-       rcu_read_lock();
-       sta = ieee80211_find_sta(ar->hw, mac);
-
-       if (likely(sta)) {
-               struct ar9170_sta_info *sta_priv = (void *) sta->drv_priv;
-               skb = skb_dequeue(&sta_priv->tx_status[queue]);
-               rcu_read_unlock();
-               if (likely(skb))
-                       return skb;
-       } else
-               rcu_read_unlock();
-
-       /* scan the waste queue for candidates */
-       skb = ar9170_find_skb_in_queue(ar, mac, queue,
-                                      &ar->global_tx_status_waste);
-       if (!skb) {
-               /* so it still _must_ be in the global list. */
-               skb = ar9170_find_skb_in_queue(ar, mac, queue,
-                                              &ar->global_tx_status);
-       }
 
+       spin_lock_irqsave(&queue->lock, flags);
+       skb_queue_walk(queue, skb) {
+               struct ar9170_tx_control *txc = (void *) skb->data;
+               struct ieee80211_hdr *hdr = (void *) txc->frame_data;
+               u32 r;
+
+               if (mac && compare_ether_addr(ieee80211_get_DA(hdr), mac)) {
+#ifdef AR9170_QUEUE_DEBUG
+                       printk(KERN_DEBUG "%s: skip frame => DA %pM != %pM\n",
+                              wiphy_name(ar->hw->wiphy), mac,
+                              ieee80211_get_DA(hdr));
+                       ar9170_print_txheader(ar, skb);
+#endif /* AR9170_QUEUE_DEBUG */
+                       continue;
+               }
+
+               r = (le32_to_cpu(txc->phy_control) & AR9170_TX_PHY_MCS_MASK) >>
+                   AR9170_TX_PHY_MCS_SHIFT;
+
+               if ((rate != AR9170_TX_INVALID_RATE) && (r != rate)) {
 #ifdef AR9170_QUEUE_DEBUG
-       if (unlikely((!skb) && net_ratelimit())) {
-               printk(KERN_ERR "%s: ESS:[%pM] does not have any "
-                               "outstanding frames in this queue (%d).\n",
-                               wiphy_name(ar->hw->wiphy), mac, queue);
+                       printk(KERN_DEBUG "%s: skip frame => rate %d != %d\n",
+                              wiphy_name(ar->hw->wiphy), rate, r);
+                       ar9170_print_txheader(ar, skb);
+#endif /* AR9170_QUEUE_DEBUG */
+                       continue;
+               }
+
+               __skb_unlink(skb, queue);
+               spin_unlock_irqrestore(&queue->lock, flags);
+               return skb;
        }
+
+#ifdef AR9170_QUEUE_DEBUG
+       printk(KERN_ERR "%s: ESS:[%pM] does not have any "
+                       "outstanding frames in queue.\n",
+                       wiphy_name(ar->hw->wiphy), mac);
+       __ar9170_dump_txqueue(ar, queue);
 #endif /* AR9170_QUEUE_DEBUG */
-       return skb;
+       spin_unlock_irqrestore(&queue->lock, flags);
+
+       return NULL;
 }
 
 /*
- * This worker tries to keep the global tx_status queue empty.
- * So we can guarantee that incoming tx_status reports for
- * unregistered stations are always synced with the actual
- * frame - which we think - belongs to.
+ * This worker tries to keeps an maintain tx_status queues.
+ * So we can guarantee that incoming tx_status reports are
+ * actually for a pending frame.
  */
 
-static void ar9170_tx_status_janitor(struct work_struct *work)
+static void ar9170_tx_janitor(struct work_struct *work)
 {
        struct ar9170 *ar = container_of(work, struct ar9170,
-                                        tx_status_janitor.work);
-       struct sk_buff *skb;
+                                        tx_janitor.work);
+       struct sk_buff_head waste;
+       unsigned int i;
+       bool resched = false;
 
        if (unlikely(!IS_STARTED(ar)))
                return ;
 
-       mutex_lock(&ar->mutex);
-       /* recycle the garbage back to mac80211... one by one. */
-       while ((skb = skb_dequeue(&ar->global_tx_status_waste))) {
+       skb_queue_head_init(&waste);
+
+       for (i = 0; i < __AR9170_NUM_TXQ; i++) {
 #ifdef AR9170_QUEUE_DEBUG
-               printk(KERN_DEBUG "%s: dispose queued frame =>\n",
-                      wiphy_name(ar->hw->wiphy));
-               ar9170_print_txheader(ar, skb);
+               printk(KERN_DEBUG "%s: garbage collector scans queue:%d\n",
+                      wiphy_name(ar->hw->wiphy), i);
+               ar9170_dump_txqueue(ar, &ar->tx_pending[i]);
+               ar9170_dump_txqueue(ar, &ar->tx_status[i]);
 #endif /* AR9170_QUEUE_DEBUG */
-               ar9170_handle_tx_status(ar, skb, false,
-                                       AR9170_TX_STATUS_FAILED);
-       }
 
-       while ((skb = skb_dequeue(&ar->global_tx_status))) {
-#ifdef AR9170_QUEUE_DEBUG
-               printk(KERN_DEBUG "%s: moving frame into waste queue =>\n",
-                      wiphy_name(ar->hw->wiphy));
+               ar9170_recycle_expired(ar, &ar->tx_status[i], &waste);
+               ar9170_recycle_expired(ar, &ar->tx_pending[i], &waste);
+               skb_queue_purge(&waste);
 
-               ar9170_print_txheader(ar, skb);
-#endif /* AR9170_QUEUE_DEBUG */
-               skb_queue_tail(&ar->global_tx_status_waste, skb);
+               if (!skb_queue_empty(&ar->tx_status[i]) ||
+                   !skb_queue_empty(&ar->tx_pending[i]))
+                       resched = true;
        }
 
-       /* recall the janitor in 100ms - if there's garbage in the can. */
-       if (skb_queue_len(&ar->global_tx_status_waste) > 0)
-               queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor,
-                                  msecs_to_jiffies(100));
-
-       mutex_unlock(&ar->mutex);
+       if (resched)
+               queue_delayed_work(ar->hw->workqueue,
+                                  &ar->tx_janitor,
+                                  msecs_to_jiffies(AR9170_JANITOR_DELAY));
 }
 
-static void ar9170_handle_command_response(struct ar9170 *ar,
-                                          void *buf, u32 len)
+void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
 {
        struct ar9170_cmd_response *cmd = (void *) buf;
 
@@ -399,15 +486,21 @@ static void ar9170_handle_command_response(struct ar9170 *ar,
                 */
 
                struct sk_buff *skb;
-               u32 queue = (le32_to_cpu(cmd->tx_status.rate) &
-                           AR9170_TX_PHY_QOS_MASK) >> AR9170_TX_PHY_QOS_SHIFT;
+               u32 phy = le32_to_cpu(cmd->tx_status.rate);
+               u32 q = (phy & AR9170_TX_PHY_QOS_MASK) >>
+                       AR9170_TX_PHY_QOS_SHIFT;
+#ifdef AR9170_QUEUE_DEBUG
+               printk(KERN_DEBUG "%s: recv tx_status for %pM, p:%08x, q:%d\n",
+                      wiphy_name(ar->hw->wiphy), cmd->tx_status.dst, phy, q);
+#endif /* AR9170_QUEUE_DEBUG */
 
-               skb = ar9170_find_queued_skb(ar, cmd->tx_status.dst, queue);
+               skb = ar9170_get_queued_skb(ar, cmd->tx_status.dst,
+                                           &ar->tx_status[q],
+                                           AR9170_TX_INVALID_RATE);
                if (unlikely(!skb))
                        return ;
 
-               ar9170_handle_tx_status(ar, skb, true,
-                                       le16_to_cpu(cmd->tx_status.status));
+               ar9170_tx_status(ar, skb, le16_to_cpu(cmd->tx_status.status));
                break;
                }
 
@@ -447,6 +540,38 @@ static void ar9170_handle_command_response(struct ar9170 *ar,
                /* retransmission issue / SIFS/EIFS collision ?! */
                break;
 
+       /* firmware debug */
+       case 0xca:
+               printk(KERN_DEBUG "ar9170 FW: %.*s\n", len - 4, (char *)buf + 4);
+               break;
+       case 0xcb:
+               len -= 4;
+
+               switch (len) {
+               case 1:
+                       printk(KERN_DEBUG "ar9170 FW: u8: %#.2x\n",
+                               *((char *)buf + 4));
+                       break;
+               case 2:
+                       printk(KERN_DEBUG "ar9170 FW: u8: %#.4x\n",
+                               le16_to_cpup((__le16 *)((char *)buf + 4)));
+                       break;
+               case 4:
+                       printk(KERN_DEBUG "ar9170 FW: u8: %#.8x\n",
+                               le32_to_cpup((__le32 *)((char *)buf + 4)));
+                       break;
+               case 8:
+                       printk(KERN_DEBUG "ar9170 FW: u8: %#.16lx\n",
+                               (unsigned long)le64_to_cpup(
+                                               (__le64 *)((char *)buf + 4)));
+                       break;
+               }
+               break;
+       case 0xcc:
+               print_hex_dump_bytes("ar9170 FW:", DUMP_PREFIX_NONE,
+                                    (char *)buf + 4, len - 4);
+               break;
+
        default:
                printk(KERN_INFO "received unhandled event %x\n", cmd->type);
                print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len);
@@ -460,7 +585,7 @@ static void ar9170_rx_reset_rx_mpdu(struct ar9170 *ar)
        ar->rx_mpdu.has_plcp = false;
 }
 
-static int ar9170_nag_limiter(struct ar9170 *ar)
+int ar9170_nag_limiter(struct ar9170 *ar)
 {
        bool print_message;
 
@@ -957,10 +1082,12 @@ static int ar9170_op_start(struct ieee80211_hw *hw)
 
        mutex_lock(&ar->mutex);
 
+       ar->filter_changed = 0;
+
        /* reinitialize queues statistics */
        memset(&ar->tx_stats, 0, sizeof(ar->tx_stats));
-       for (i = 0; i < ARRAY_SIZE(ar->tx_stats); i++)
-               ar->tx_stats[i].limit = 8;
+       for (i = 0; i < __AR9170_NUM_TXQ; i++)
+               ar->tx_stats[i].limit = AR9170_TXQ_DEPTH;
 
        /* reset QoS defaults */
        AR9170_FILL_QUEUE(ar->edcf[0], 3, 15, 1023,  0); /* BEST EFFORT*/
@@ -1006,18 +1133,17 @@ out:
 static void ar9170_op_stop(struct ieee80211_hw *hw)
 {
        struct ar9170 *ar = hw->priv;
+       unsigned int i;
 
        if (IS_STARTED(ar))
                ar->state = AR9170_IDLE;
 
        flush_workqueue(ar->hw->workqueue);
 
-       mutex_lock(&ar->mutex);
-       cancel_delayed_work_sync(&ar->tx_status_janitor);
+       cancel_delayed_work_sync(&ar->tx_janitor);
        cancel_work_sync(&ar->filter_config_work);
        cancel_work_sync(&ar->beacon_work);
-       skb_queue_purge(&ar->global_tx_status_waste);
-       skb_queue_purge(&ar->global_tx_status);
+       mutex_lock(&ar->mutex);
 
        if (IS_ACCEPTING_CMD(ar)) {
                ar9170_set_leds_state(ar, 0);
@@ -1027,51 +1153,32 @@ static void ar9170_op_stop(struct ieee80211_hw *hw)
                ar->stop(ar);
        }
 
+       for (i = 0; i < __AR9170_NUM_TXQ; i++) {
+               skb_queue_purge(&ar->tx_pending[i]);
+               skb_queue_purge(&ar->tx_status[i]);
+       }
        mutex_unlock(&ar->mutex);
 }
 
-int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
 {
-       struct ar9170 *ar = hw->priv;
        struct ieee80211_hdr *hdr;
        struct ar9170_tx_control *txc;
        struct ieee80211_tx_info *info;
-       struct ieee80211_rate *rate = NULL;
        struct ieee80211_tx_rate *txrate;
+       struct ar9170_tx_info *arinfo;
        unsigned int queue = skb_get_queue_mapping(skb);
-       unsigned long flags = 0;
-       struct ar9170_sta_info *sta_info = NULL;
-       u32 power, chains;
        u16 keytype = 0;
        u16 len, icv = 0;
-       int err;
-       bool tx_status;
 
-       if (unlikely(!IS_STARTED(ar)))
-               goto err_free;
+       BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data));
 
        hdr = (void *)skb->data;
        info = IEEE80211_SKB_CB(skb);
        len = skb->len;
 
-       spin_lock_irqsave(&ar->tx_stats_lock, flags);
-       if (ar->tx_stats[queue].limit < ar->tx_stats[queue].len) {
-               spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
-               return NETDEV_TX_OK;
-       }
-
-       ar->tx_stats[queue].len++;
-       ar->tx_stats[queue].count++;
-       if (ar->tx_stats[queue].limit == ar->tx_stats[queue].len)
-               ieee80211_stop_queue(hw, queue);
-
-       spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
-
        txc = (void *)skb_push(skb, sizeof(*txc));
 
-       tx_status = (((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) != 0) ||
-                   ((info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) != 0));
-
        if (info->control.hw_key) {
                icv = info->control.hw_key->icv_len;
 
@@ -1087,7 +1194,7 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
                        break;
                default:
                        WARN_ON(1);
-                       goto err_dequeue;
+                       goto err_out;
                }
        }
 
@@ -1104,16 +1211,65 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
        if (info->flags & IEEE80211_TX_CTL_NO_ACK)
                txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_NO_ACK);
 
-       if (info->flags & IEEE80211_TX_CTL_AMPDU)
-               txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR);
-
        txrate = &info->control.rates[0];
-
        if (txrate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
                txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS);
        else if (txrate->flags & IEEE80211_TX_RC_USE_RTS_CTS)
                txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS);
 
+       arinfo = (void *)info->rate_driver_data;
+       arinfo->timeout = jiffies + msecs_to_jiffies(AR9170_QUEUE_TIMEOUT);
+
+       if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+            (is_valid_ether_addr(ieee80211_get_DA(hdr)))) {
+               if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+                       if (unlikely(!info->control.sta))
+                               goto err_out;
+
+                       txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR);
+                       arinfo->flags = AR9170_TX_FLAG_BLOCK_ACK;
+                       goto out;
+               }
+
+               txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE);
+               /*
+                * WARNING:
+                * Putting the QoS queue bits into an unexplored territory is
+                * certainly not elegant.
+                *
+                * In my defense: This idea provides a reasonable way to
+                * smuggle valuable information to the tx_status callback.
+                * Also, the idea behind this bit-abuse came straight from
+                * the original driver code.
+                */
+
+               txc->phy_control |=
+                       cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT);
+               arinfo->flags = AR9170_TX_FLAG_WAIT_FOR_ACK;
+       } else {
+               arinfo->flags = AR9170_TX_FLAG_NO_ACK;
+       }
+
+out:
+       return 0;
+
+err_out:
+       skb_pull(skb, sizeof(*txc));
+       return -EINVAL;
+}
+
+static void ar9170_tx_prepare_phy(struct ar9170 *ar, struct sk_buff *skb)
+{
+       struct ar9170_tx_control *txc;
+       struct ieee80211_tx_info *info;
+       struct ieee80211_rate *rate = NULL;
+       struct ieee80211_tx_rate *txrate;
+       u32 power, chains;
+
+       txc = (void *) skb->data;
+       info = IEEE80211_SKB_CB(skb);
+       txrate = &info->control.rates[0];
+
        if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD)
                txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_GREENFIELD);
 
@@ -1133,9 +1289,12 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
                u32 r = txrate->idx;
                u8 *txpower;
 
+               /* heavy clip control */
+               txc->phy_control |= cpu_to_le32((r & 0x7) << 7);
+
                r <<= AR9170_TX_PHY_MCS_SHIFT;
-               if (WARN_ON(r & ~AR9170_TX_PHY_MCS_MASK))
-                       goto err_dequeue;
+               BUG_ON(r & ~AR9170_TX_PHY_MCS_MASK);
+
                txc->phy_control |= cpu_to_le32(r & AR9170_TX_PHY_MCS_MASK);
                txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_MOD_HT);
 
@@ -1197,53 +1356,154 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
                        chains = AR9170_TX_PHY_TXCHAIN_1;
        }
        txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT);
+}
 
-       if (tx_status) {
-               txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE);
-               /*
-                * WARNING:
-                * Putting the QoS queue bits into an unexplored territory is
-                * certainly not elegant.
-                *
-                * In my defense: This idea provides a reasonable way to
-                * smuggle valuable information to the tx_status callback.
-                * Also, the idea behind this bit-abuse came straight from
-                * the original driver code.
-                */
+static void ar9170_tx(struct ar9170 *ar)
+{
+       struct sk_buff *skb;
+       unsigned long flags;
+       struct ieee80211_tx_info *info;
+       struct ar9170_tx_info *arinfo;
+       unsigned int i, frames, frames_failed, remaining_space;
+       int err;
+       bool schedule_garbagecollector = false;
 
-               txc->phy_control |=
-                       cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT);
+       BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data));
 
-               if (info->control.sta) {
-                       sta_info = (void *) info->control.sta->drv_priv;
-                       skb_queue_tail(&sta_info->tx_status[queue], skb);
-               } else {
-                       skb_queue_tail(&ar->global_tx_status, skb);
+       if (unlikely(!IS_STARTED(ar)))
+               return ;
+
+       remaining_space = AR9170_TX_MAX_PENDING;
+
+       for (i = 0; i < __AR9170_NUM_TXQ; i++) {
+               spin_lock_irqsave(&ar->tx_stats_lock, flags);
+               if (ar->tx_stats[i].len >= ar->tx_stats[i].limit) {
+#ifdef AR9170_QUEUE_DEBUG
+                       printk(KERN_DEBUG "%s: queue %d full\n",
+                              wiphy_name(ar->hw->wiphy), i);
 
-                       queue_delayed_work(ar->hw->workqueue,
-                                          &ar->tx_status_janitor,
-                                          msecs_to_jiffies(100));
+                       __ar9170_dump_txstats(ar);
+                       printk(KERN_DEBUG "stuck frames: ===> \n");
+                       ar9170_dump_txqueue(ar, &ar->tx_pending[i]);
+                       ar9170_dump_txqueue(ar, &ar->tx_status[i]);
+#endif /* AR9170_QUEUE_DEBUG */
+                       ieee80211_stop_queue(ar->hw, i);
+                       spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
+                       continue;
+               }
+
+               frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len,
+                            skb_queue_len(&ar->tx_pending[i]));
+
+               if (remaining_space < frames) {
+#ifdef AR9170_QUEUE_DEBUG
+                       printk(KERN_DEBUG "%s: tx quota reached queue:%d, "
+                              "remaining slots:%d, needed:%d\n",
+                              wiphy_name(ar->hw->wiphy), i, remaining_space,
+                              frames);
+
+                       ar9170_dump_txstats(ar);
+#endif /* AR9170_QUEUE_DEBUG */
+                       frames = remaining_space;
+               }
+
+               ar->tx_stats[i].len += frames;
+               ar->tx_stats[i].count += frames;
+               spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
+
+               if (!frames)
+                       continue;
+
+               frames_failed = 0;
+               while (frames) {
+                       skb = skb_dequeue(&ar->tx_pending[i]);
+                       if (unlikely(!skb)) {
+                               frames_failed += frames;
+                               frames = 0;
+                               break;
+                       }
+
+                       info = IEEE80211_SKB_CB(skb);
+                       arinfo = (void *) info->rate_driver_data;
+
+                       /* TODO: cancel stuck frames */
+                       arinfo->timeout = jiffies +
+                                         msecs_to_jiffies(AR9170_TX_TIMEOUT);
+
+#ifdef AR9170_QUEUE_DEBUG
+                       printk(KERN_DEBUG "%s: send frame q:%d =>\n",
+                              wiphy_name(ar->hw->wiphy), i);
+                       ar9170_print_txheader(ar, skb);
+#endif /* AR9170_QUEUE_DEBUG */
+
+                       err = ar->tx(ar, skb);
+                       if (unlikely(err)) {
+                               frames_failed++;
+                               dev_kfree_skb_any(skb);
+                       } else {
+                               remaining_space--;
+                               schedule_garbagecollector = true;
+                       }
+
+                       frames--;
+               }
+
+#ifdef AR9170_QUEUE_DEBUG
+               printk(KERN_DEBUG "%s: ar9170_tx report for queue %d\n",
+                      wiphy_name(ar->hw->wiphy), i);
+
+               printk(KERN_DEBUG "%s: unprocessed pending frames left:\n",
+                      wiphy_name(ar->hw->wiphy));
+               ar9170_dump_txqueue(ar, &ar->tx_pending[i]);
+#endif /* AR9170_QUEUE_DEBUG */
+
+               if (unlikely(frames_failed)) {
+#ifdef AR9170_QUEUE_DEBUG
+                       printk(KERN_DEBUG "%s: frames failed =>\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;
+                       ieee80211_wake_queue(ar->hw, i);
+                       spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
                }
        }
 
-       err = ar->tx(ar, skb, tx_status, 0);
-       if (unlikely(tx_status && err)) {
-               if (info->control.sta)
-                       skb_unlink(skb, &sta_info->tx_status[queue]);
-               else
-                       skb_unlink(skb, &ar->global_tx_status);
+       if (schedule_garbagecollector)
+               queue_delayed_work(ar->hw->workqueue,
+                                  &ar->tx_janitor,
+                                  msecs_to_jiffies(AR9170_JANITOR_DELAY));
+}
+
+int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+       struct ar9170 *ar = hw->priv;
+       struct ieee80211_tx_info *info;
+
+       if (unlikely(!IS_STARTED(ar)))
+               goto err_free;
+
+       if (unlikely(ar9170_tx_prepare(ar, skb)))
+               goto err_free;
+
+       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;
+       } else {
+               unsigned int queue = skb_get_queue_mapping(skb);
+
+               ar9170_tx_prepare_phy(ar, skb);
+               skb_queue_tail(&ar->tx_pending[queue], skb);
        }
 
+       ar9170_tx(ar);
        return NETDEV_TX_OK;
 
-err_dequeue:
-       spin_lock_irqsave(&ar->tx_stats_lock, flags);
-       ar->tx_stats[queue].len--;
-       ar->tx_stats[queue].count--;
-       spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
-
 err_free:
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
        return NETDEV_TX_OK;
 }
 
@@ -1306,11 +1566,6 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed)
 
        mutex_lock(&ar->mutex);
 
-       if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) {
-               /* TODO */
-               err = 0;
-       }
-
        if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {
                /* TODO */
                err = 0;
@@ -1344,15 +1599,21 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed)
        }
 
        if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+
+               /* adjust slot time for 5 GHz */
+               err = ar9170_set_slot_time(ar);
+               if (err)
+                       goto out;
+
+               err = ar9170_set_dyn_sifs_ack(ar);
+               if (err)
+                       goto out;
+
                err = ar9170_set_channel(ar, hw->conf.channel,
                                AR9170_RFI_NONE,
                                nl80211_to_ar9170(hw->conf.channel_type));
                if (err)
                        goto out;
-               /* adjust slot time for 5 GHz */
-               if (hw->conf.channel->band == IEEE80211_BAND_5GHZ)
-                       err = ar9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME,
-                                              9 << 10);
        }
 
 out:
@@ -1370,20 +1631,26 @@ static void ar9170_set_filters(struct work_struct *work)
                return ;
 
        mutex_lock(&ar->mutex);
-       if (ar->filter_changed & AR9170_FILTER_CHANGED_PROMISC) {
+       if (test_and_clear_bit(AR9170_FILTER_CHANGED_MODE,
+                              &ar->filter_changed)) {
                err = ar9170_set_operating_mode(ar);
                if (err)
                        goto unlock;
        }
 
-       if (ar->filter_changed & AR9170_FILTER_CHANGED_MULTICAST) {
+       if (test_and_clear_bit(AR9170_FILTER_CHANGED_MULTICAST,
+                              &ar->filter_changed)) {
                err = ar9170_update_multicast(ar);
                if (err)
                        goto unlock;
        }
 
-       if (ar->filter_changed & AR9170_FILTER_CHANGED_FRAMEFILTER)
+       if (test_and_clear_bit(AR9170_FILTER_CHANGED_FRAMEFILTER,
+                              &ar->filter_changed)) {
                err = ar9170_update_frame_filter(ar);
+               if (err)
+                       goto unlock;
+       }
 
 unlock:
        mutex_unlock(&ar->mutex);
@@ -1413,7 +1680,7 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
                        int i;
 
                        /* always get broadcast frames */
-                       mchash = 1ULL << (0xff>>2);
+                       mchash = 1ULL << (0xff >> 2);
 
                        for (i = 0; i < mc_count; i++) {
                                if (WARN_ON(!mclist))
@@ -1423,7 +1690,7 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
                        }
                ar->want_mc_hash = mchash;
                }
-               ar->filter_changed |= AR9170_FILTER_CHANGED_MULTICAST;
+               set_bit(AR9170_FILTER_CHANGED_MULTICAST, &ar->filter_changed);
        }
 
        if (changed_flags & FIF_CONTROL) {
@@ -1439,12 +1706,14 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
                else
                        ar->want_filter = ar->cur_filter & ~filter;
 
-               ar->filter_changed |= AR9170_FILTER_CHANGED_FRAMEFILTER;
+               set_bit(AR9170_FILTER_CHANGED_FRAMEFILTER,
+                       &ar->filter_changed);
        }
 
        if (changed_flags & FIF_PROMISC_IN_BSS) {
                ar->sniffer_enabled = ((*new_flags) & FIF_PROMISC_IN_BSS) != 0;
-               ar->filter_changed |= AR9170_FILTER_CHANGED_PROMISC;
+               set_bit(AR9170_FILTER_CHANGED_MODE,
+                       &ar->filter_changed);
        }
 
        if (likely(IS_STARTED(ar)))
@@ -1464,27 +1733,32 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw,
        if (changed & BSS_CHANGED_BSSID) {
                memcpy(ar->bssid, bss_conf->bssid, ETH_ALEN);
                err = ar9170_set_operating_mode(ar);
+               if (err)
+                       goto out;
        }
 
        if (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) {
                err = ar9170_update_beacon(ar);
-               if (!err)
-                       ar9170_set_beacon_timers(ar);
-       }
+               if (err)
+                       goto out;
 
-       ar9170_regwrite_begin(ar);
+               err = ar9170_set_beacon_timers(ar);
+               if (err)
+                       goto out;
+       }
 
        if (changed & BSS_CHANGED_ASSOC) {
-               ar->state = bss_conf->assoc ? AR9170_ASSOCIATED : ar->state;
-
 #ifndef CONFIG_AR9170_LEDS
                /* enable assoc LED. */
                err = ar9170_set_leds_state(ar, bss_conf->assoc ? 2 : 0);
 #endif /* CONFIG_AR9170_LEDS */
        }
 
-       if (changed & BSS_CHANGED_BEACON_INT)
+       if (changed & BSS_CHANGED_BEACON_INT) {
                err = ar9170_set_beacon_timers(ar);
+               if (err)
+                       goto out;
+       }
 
        if (changed & BSS_CHANGED_HT) {
                /* TODO */
@@ -1492,31 +1766,18 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw,
        }
 
        if (changed & BSS_CHANGED_ERP_SLOT) {
-               u32 slottime = 20;
-
-               if (bss_conf->use_short_slot)
-                       slottime = 9;
-
-               ar9170_regwrite(AR9170_MAC_REG_SLOT_TIME, slottime << 10);
+               err = ar9170_set_slot_time(ar);
+               if (err)
+                       goto out;
        }
 
        if (changed & BSS_CHANGED_BASIC_RATES) {
-               u32 cck, ofdm;
-
-               if (hw->conf.channel->band == IEEE80211_BAND_5GHZ) {
-                       ofdm = bss_conf->basic_rates;
-                       cck = 0;
-               } else {
-                       /* four cck rates */
-                       cck = bss_conf->basic_rates & 0xf;
-                       ofdm = bss_conf->basic_rates >> 4;
-               }
-               ar9170_regwrite(AR9170_MAC_REG_BASIC_RATE,
-                               ofdm << 8 | cck);
+               err = ar9170_set_basic_rates(ar);
+               if (err)
+                       goto out;
        }
 
-       ar9170_regwrite_finish();
-       err = ar9170_regwrite_result();
+out:
        mutex_unlock(&ar->mutex);
 }
 
@@ -1668,43 +1929,6 @@ 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 *info = (void *) sta->drv_priv;
-       struct sk_buff *skb;
-       unsigned int i;
-
-       switch (cmd) {
-       case STA_NOTIFY_ADD:
-               for (i = 0; i < ar->hw->queues; i++)
-                       skb_queue_head_init(&info->tx_status[i]);
-               break;
-
-       case STA_NOTIFY_REMOVE:
-
-               /*
-                * transfer all outstanding frames that need a tx_status
-                * reports to the global tx_status queue
-                */
-
-               for (i = 0; i < ar->hw->queues; i++) {
-                       while ((skb = skb_dequeue(&info->tx_status[i]))) {
-#ifdef AR9170_QUEUE_DEBUG
-                               printk(KERN_DEBUG "%s: queueing frame in "
-                                         "global tx_status queue =>\n",
-                                      wiphy_name(ar->hw->wiphy));
-
-                               ar9170_print_txheader(ar, skb);
-#endif /* AR9170_QUEUE_DEBUG */
-                               skb_queue_tail(&ar->global_tx_status, skb);
-                       }
-               }
-               queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor,
-                                  msecs_to_jiffies(100));
-               break;
-
-       default:
-               break;
-       }
 }
 
 static int ar9170_get_stats(struct ieee80211_hw *hw,
@@ -1743,7 +1967,7 @@ static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue,
        int ret;
 
        mutex_lock(&ar->mutex);
-       if ((param) && !(queue > ar->hw->queues)) {
+       if ((param) && !(queue > __AR9170_NUM_TXQ)) {
                memcpy(&ar->edcf[ar9170_qos_hwmap[queue]],
                       param, sizeof(*param));
 
@@ -1819,12 +2043,14 @@ void *ar9170_alloc(size_t priv_size)
        mutex_init(&ar->mutex);
        spin_lock_init(&ar->cmdlock);
        spin_lock_init(&ar->tx_stats_lock);
-       skb_queue_head_init(&ar->global_tx_status);
-       skb_queue_head_init(&ar->global_tx_status_waste);
+       for (i = 0; i < __AR9170_NUM_TXQ; i++) {
+               skb_queue_head_init(&ar->tx_status[i]);
+               skb_queue_head_init(&ar->tx_pending[i]);
+       }
        ar9170_rx_reset_rx_mpdu(ar);
        INIT_WORK(&ar->filter_config_work, ar9170_set_filters);
        INIT_WORK(&ar->beacon_work, ar9170_new_beacon);
-       INIT_DELAYED_WORK(&ar->tx_status_janitor, ar9170_tx_status_janitor);
+       INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor);
 
        /* all hw supports 2.4 GHz, so set channel to 1 by default */
        ar->channel = &ar9170_2ghz_chantable[0];
index 6ce2075..df86f70 100644 (file)
@@ -401,7 +401,7 @@ int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band)
        int i, err;
        u32 val;
        bool is_2ghz = band == IEEE80211_BAND_2GHZ;
-       bool is_40mhz = false; /* XXX: for now */
+       bool is_40mhz = conf_is_ht40(&ar->hw->conf);
 
        ar9170_regwrite_begin(ar);
 
@@ -1200,7 +1200,7 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
                return -ENOSYS;
        }
 
-       if (0 /* 2 streams capable */)
+       if (ar->eeprom.tx_mask != 1)
                tmp |= 0x100;
 
        err = ar9170_write_reg(ar, 0x1c5804, tmp);
@@ -1214,7 +1214,7 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
        freqpar = ar9170_get_hw_dyn_params(channel, bw);
 
        vals[0] = cpu_to_le32(channel->center_freq * 1000);
-       vals[1] = cpu_to_le32(bw == AR9170_BW_20 ? 0 : 1);
+       vals[1] = cpu_to_le32(conf_is_ht40(&ar->hw->conf));
        vals[2] = cpu_to_le32(offs << 2 | 1);
        vals[3] = cpu_to_le32(freqpar->coeff_exp);
        vals[4] = cpu_to_le32(freqpar->coeff_man);
index d7c13c0..754b1f8 100644 (file)
@@ -51,9 +51,14 @@ MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
 MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Atheros AR9170 802.11n USB wireless");
+MODULE_FIRMWARE("ar9170.fw");
 MODULE_FIRMWARE("ar9170-1.fw");
 MODULE_FIRMWARE("ar9170-2.fw");
 
+enum ar9170_requirements {
+       AR9170_REQ_FW1_ONLY = 1,
+};
+
 static struct usb_device_id ar9170_usb_ids[] = {
        /* Atheros 9170 */
        { USB_DEVICE(0x0cf3, 0x9170) },
@@ -81,25 +86,74 @@ static struct usb_device_id ar9170_usb_ids[] = {
        { USB_DEVICE(0x2019, 0x5304) },
        /* IO-Data WNGDNUS2 */
        { USB_DEVICE(0x04bb, 0x093f) },
+       /* AVM FRITZ!WLAN USB Stick N */
+       { USB_DEVICE(0x057C, 0x8401) },
+       /* AVM FRITZ!WLAN USB Stick N 2.4 */
+       { USB_DEVICE(0x057C, 0x8402), .driver_info = AR9170_REQ_FW1_ONLY },
 
        /* terminate */
        {}
 };
 MODULE_DEVICE_TABLE(usb, ar9170_usb_ids);
 
-static void ar9170_usb_tx_urb_complete_free(struct urb *urb)
+static void ar9170_usb_submit_urb(struct ar9170_usb *aru)
+{
+       struct urb *urb;
+       unsigned long flags;
+       int err;
+
+       if (unlikely(!IS_STARTED(&aru->common)))
+               return ;
+
+       spin_lock_irqsave(&aru->tx_urb_lock, flags);
+       if (aru->tx_submitted_urbs >= AR9170_NUM_TX_URBS) {
+               spin_unlock_irqrestore(&aru->tx_urb_lock, flags);
+               return ;
+       }
+       aru->tx_submitted_urbs++;
+
+       urb = usb_get_from_anchor(&aru->tx_pending);
+       if (!urb) {
+               aru->tx_submitted_urbs--;
+               spin_unlock_irqrestore(&aru->tx_urb_lock, flags);
+
+               return ;
+       }
+       spin_unlock_irqrestore(&aru->tx_urb_lock, flags);
+
+       aru->tx_pending_urbs--;
+       usb_anchor_urb(urb, &aru->tx_submitted);
+
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (unlikely(err)) {
+               if (ar9170_nag_limiter(&aru->common))
+                       dev_err(&aru->udev->dev, "submit_urb failed (%d).\n",
+                               err);
+
+               usb_unanchor_urb(urb);
+               aru->tx_submitted_urbs--;
+               ar9170_tx_callback(&aru->common, urb->context);
+       }
+
+       usb_free_urb(urb);
+}
+
+static void ar9170_usb_tx_urb_complete_frame(struct urb *urb)
 {
        struct sk_buff *skb = urb->context;
        struct ar9170_usb *aru = (struct ar9170_usb *)
              usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
 
-       if (!aru) {
+       if (unlikely(!aru)) {
                dev_kfree_skb_irq(skb);
                return ;
        }
 
-       ar9170_handle_tx_status(&aru->common, skb, false,
-                               AR9170_TX_STATUS_COMPLETE);
+       aru->tx_submitted_urbs--;
+
+       ar9170_tx_callback(&aru->common, skb);
+
+       ar9170_usb_submit_urb(aru);
 }
 
 static void ar9170_usb_tx_urb_complete(struct urb *urb)
@@ -126,8 +180,8 @@ static void ar9170_usb_irq_completed(struct urb *urb)
                goto resubmit;
        }
 
-       print_hex_dump_bytes("ar9170 irq: ", DUMP_PREFIX_OFFSET,
-                            urb->transfer_buffer, urb->actual_length);
+       ar9170_handle_command_response(&aru->common, urb->transfer_buffer,
+                                      urb->actual_length);
 
 resubmit:
        usb_anchor_urb(urb, &aru->rx_submitted);
@@ -177,16 +231,15 @@ resubmit:
 
        usb_anchor_urb(urb, &aru->rx_submitted);
        err = usb_submit_urb(urb, GFP_ATOMIC);
-       if (err) {
+       if (unlikely(err)) {
                usb_unanchor_urb(urb);
-               dev_kfree_skb_irq(skb);
+               goto free;
        }
 
        return ;
 
 free:
        dev_kfree_skb_irq(skb);
-       return;
 }
 
 static int ar9170_usb_prep_rx_urb(struct ar9170_usb *aru,
@@ -282,21 +335,47 @@ err_out:
        return err;
 }
 
-static void ar9170_usb_cancel_urbs(struct ar9170_usb *aru)
+static int ar9170_usb_flush(struct ar9170 *ar)
 {
-       int ret;
+       struct ar9170_usb *aru = (void *) ar;
+       struct urb *urb;
+       int ret, err = 0;
 
-       aru->common.state = AR9170_UNKNOWN_STATE;
+       if (IS_STARTED(ar))
+               aru->common.state = AR9170_IDLE;
 
-       usb_unlink_anchored_urbs(&aru->tx_submitted);
+       usb_wait_anchor_empty_timeout(&aru->tx_pending,
+                                           msecs_to_jiffies(800));
+       while ((urb = usb_get_from_anchor(&aru->tx_pending))) {
+               ar9170_tx_callback(&aru->common, (void *) urb->context);
+               usb_free_urb(urb);
+       }
 
-       /* give the LED OFF command and the deauth frame a chance to air. */
+       /* lets wait a while until the tx - queues are dried out */
        ret = usb_wait_anchor_empty_timeout(&aru->tx_submitted,
                                            msecs_to_jiffies(100));
        if (ret == 0)
-               dev_err(&aru->udev->dev, "kill pending tx urbs.\n");
-       usb_poison_anchored_urbs(&aru->tx_submitted);
+               err = -ETIMEDOUT;
+
+       usb_kill_anchored_urbs(&aru->tx_submitted);
+
+       if (IS_ACCEPTING_CMD(ar))
+               aru->common.state = AR9170_STARTED;
 
+       return err;
+}
+
+static void ar9170_usb_cancel_urbs(struct ar9170_usb *aru)
+{
+       int err;
+
+       aru->common.state = AR9170_UNKNOWN_STATE;
+
+       err = ar9170_usb_flush(&aru->common);
+       if (err)
+               dev_err(&aru->udev->dev, "stuck tx urbs!\n");
+
+       usb_poison_anchored_urbs(&aru->tx_submitted);
        usb_poison_anchored_urbs(&aru->rx_submitted);
 }
 
@@ -337,7 +416,7 @@ static int ar9170_usb_exec_cmd(struct ar9170 *ar, enum ar9170_cmd cmd,
 
        usb_anchor_urb(urb, &aru->tx_submitted);
        err = usb_submit_urb(urb, GFP_ATOMIC);
-       if (err) {
+       if (unlikely(err)) {
                usb_unanchor_urb(urb);
                usb_free_urb(urb);
                goto err_unbuf;
@@ -380,12 +459,10 @@ err_free:
        return err;
 }
 
-static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb,
-                        bool txstatus_needed, unsigned int extra_len)
+static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb)
 {
        struct ar9170_usb *aru = (struct ar9170_usb *) ar;
        struct urb *urb;
-       int err;
 
        if (unlikely(!IS_STARTED(ar))) {
                /* Seriously, what were you drink... err... thinking!? */
@@ -398,18 +475,17 @@ static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb,
 
        usb_fill_bulk_urb(urb, aru->udev,
                          usb_sndbulkpipe(aru->udev, AR9170_EP_TX),
-                         skb->data, skb->len + extra_len, (txstatus_needed ?
-                         ar9170_usb_tx_urb_complete :
-                         ar9170_usb_tx_urb_complete_free), skb);
+                         skb->data, skb->len,
+                         ar9170_usb_tx_urb_complete_frame, skb);
        urb->transfer_flags |= URB_ZERO_PACKET;
 
-       usb_anchor_urb(urb, &aru->tx_submitted);
-       err = usb_submit_urb(urb, GFP_ATOMIC);
-       if (unlikely(err))
-               usb_unanchor_urb(urb);
+       usb_anchor_urb(urb, &aru->tx_pending);
+       aru->tx_pending_urbs++;
 
        usb_free_urb(urb);
-       return err;
+
+       ar9170_usb_submit_urb(aru);
+       return 0;
 }
 
 static void ar9170_usb_callback_cmd(struct ar9170 *ar, u32 len , void *buffer)
@@ -418,7 +494,7 @@ static void ar9170_usb_callback_cmd(struct ar9170 *ar, u32 len , void *buffer)
        unsigned long flags;
        u32 in, out;
 
-       if (!buffer)
+       if (unlikely(!buffer))
                return ;
 
        in = le32_to_cpup((__le32 *)buffer);
@@ -504,17 +580,29 @@ static int ar9170_usb_request_firmware(struct ar9170_usb *aru)
 {
        int err = 0;
 
-       err = request_firmware(&aru->init_values, "ar9170-1.fw",
+       err = request_firmware(&aru->firmware, "ar9170.fw",
                               &aru->udev->dev);
-       if (err) {
-               dev_err(&aru->udev->dev, "file with init values not found.\n");
-               return err;
+       if (!err) {
+               aru->init_values = NULL;
+               return 0;
+       }
+
+       if (aru->req_one_stage_fw) {
+               dev_err(&aru->udev->dev, "ar9170.fw firmware file "
+                       "not found and is required for this device\n");
+               return -EINVAL;
        }
 
+       dev_err(&aru->udev->dev, "ar9170.fw firmware file "
+               "not found, trying old firmware...\n");
+
+       err = request_firmware(&aru->init_values, "ar9170-1.fw",
+                              &aru->udev->dev);
+
        err = request_firmware(&aru->firmware, "ar9170-2.fw", &aru->udev->dev);
        if (err) {
                release_firmware(aru->init_values);
-               dev_err(&aru->udev->dev, "firmware file not found.\n");
+               dev_err(&aru->udev->dev, "file with init values not found.\n");
                return err;
        }
 
@@ -548,6 +636,9 @@ static int ar9170_usb_upload_firmware(struct ar9170_usb *aru)
 {
        int err;
 
+       if (!aru->init_values)
+               goto upload_fw_start;
+
        /* First, upload initial values to device RAM */
        err = ar9170_usb_upload(aru, aru->init_values->data,
                                aru->init_values->size, 0x102800, false);
@@ -557,6 +648,8 @@ static int ar9170_usb_upload_firmware(struct ar9170_usb *aru)
                return err;
        }
 
+upload_fw_start:
+
        /* Then, upload the firmware itself and start it */
        return ar9170_usb_upload(aru, aru->firmware->data, aru->firmware->size,
                                0x200000, true);
@@ -592,10 +685,8 @@ static void ar9170_usb_stop(struct ar9170 *ar)
        if (IS_ACCEPTING_CMD(ar))
                aru->common.state = AR9170_STOPPED;
 
-       /* lets wait a while until the tx - queues are dried out */
-       ret = usb_wait_anchor_empty_timeout(&aru->tx_submitted,
-                                           msecs_to_jiffies(1000));
-       if (ret == 0)
+       ret = ar9170_usb_flush(ar);
+       if (ret)
                dev_err(&aru->udev->dev, "kill pending tx urbs.\n");
 
        usb_poison_anchored_urbs(&aru->tx_submitted);
@@ -656,6 +747,15 @@ err_out:
        return err;
 }
 
+static bool ar9170_requires_one_stage(const struct usb_device_id *id)
+{
+       if (!id->driver_info)
+               return false;
+       if (id->driver_info == AR9170_REQ_FW1_ONLY)
+               return true;
+       return false;
+}
+
 static int ar9170_usb_probe(struct usb_interface *intf,
                        const struct usb_device_id *id)
 {
@@ -676,14 +776,22 @@ static int ar9170_usb_probe(struct usb_interface *intf,
        aru->intf = intf;
        ar = &aru->common;
 
+       aru->req_one_stage_fw = ar9170_requires_one_stage(id);
+
        usb_set_intfdata(intf, aru);
        SET_IEEE80211_DEV(ar->hw, &udev->dev);
 
        init_usb_anchor(&aru->rx_submitted);
+       init_usb_anchor(&aru->tx_pending);
        init_usb_anchor(&aru->tx_submitted);
        init_completion(&aru->cmd_wait);
+       spin_lock_init(&aru->tx_urb_lock);
+
+       aru->tx_pending_urbs = 0;
+       aru->tx_submitted_urbs = 0;
 
        aru->common.stop = ar9170_usb_stop;
+       aru->common.flush = ar9170_usb_flush;
        aru->common.open = ar9170_usb_open;
        aru->common.tx = ar9170_usb_tx;
        aru->common.exec_cmd = ar9170_usb_exec_cmd;
@@ -691,7 +799,7 @@ static int ar9170_usb_probe(struct usb_interface *intf,
 
 #ifdef CONFIG_PM
        udev->reset_resume = 1;
-#endif
+#endif /* CONFIG_PM */
        err = ar9170_usb_reset(aru);
        if (err)
                goto err_freehw;
@@ -776,11 +884,6 @@ static int ar9170_resume(struct usb_interface *intf)
        usb_unpoison_anchored_urbs(&aru->rx_submitted);
        usb_unpoison_anchored_urbs(&aru->tx_submitted);
 
-       /*
-        * FIXME: firmware upload will fail on resume.
-        * but this is better than a hang!
-        */
-
        err = ar9170_usb_init_device(aru);
        if (err)
                goto err_unrx;
index ac42586..d098f4d 100644 (file)
@@ -51,6 +51,7 @@
 #include "ar9170.h"
 
 #define AR9170_NUM_RX_URBS                     16
+#define AR9170_NUM_TX_URBS                     8
 
 struct firmware;
 
@@ -60,9 +61,15 @@ struct ar9170_usb {
        struct usb_interface *intf;
 
        struct usb_anchor rx_submitted;
+       struct usb_anchor tx_pending;
        struct usb_anchor tx_submitted;
 
-       spinlock_t cmdlock;
+       bool req_one_stage_fw;
+
+       spinlock_t tx_urb_lock;
+       unsigned int tx_submitted_urbs;
+       unsigned int tx_pending_urbs;
+
        struct completion cmd_wait;
        int readlen;
        u8 *readbuf;
index 84a74c5..090dc6d 100644 (file)
@@ -11,5 +11,6 @@ ath5k-y                               += reset.o
 ath5k-y                                += attach.o
 ath5k-y                                += base.o
 ath5k-y                                += led.o
+ath5k-y                                += rfkill.o
 ath5k-$(CONFIG_ATH5K_DEBUG)    += debug.o
 obj-$(CONFIG_ATH5K)            += ath5k.o
index 8137182..6358233 100644 (file)
@@ -1256,6 +1256,10 @@ extern u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio);
 extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val);
 extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level);
 
+/* rfkill Functions */
+extern void ath5k_rfkill_hw_start(struct ath5k_hw *ah);
+extern void ath5k_rfkill_hw_stop(struct ath5k_hw *ah);
+
 /* Misc functions */
 int ath5k_hw_set_capabilities(struct ath5k_hw *ah);
 extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result);
index fb51937..55f7de0 100644 (file)
@@ -2070,6 +2070,13 @@ 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
@@ -2353,6 +2360,8 @@ ath5k_init(struct ath5k_softc *sc)
        if (ret)
                goto done;
 
+       ath5k_rfkill_hw_start(ah);
+
        /*
         * Reset the key cache since some parts do not reset the
         * contents on initial power up or resume from suspend.
@@ -2461,6 +2470,8 @@ ath5k_stop_hw(struct ath5k_softc *sc)
        tasklet_kill(&sc->restq);
        tasklet_kill(&sc->beacontq);
 
+       ath5k_rfkill_hw_stop(sc->ah);
+
        return ret;
 }
 
@@ -2519,6 +2530,9 @@ ath5k_intr(int irq, void *dev_id)
                                 */
                                ath5k_hw_update_mib_counters(ah, &sc->ll_stats);
                        }
+                       if (status & AR5K_INT_GPIO)
+                               tasklet_schedule(&sc->rf_kill.toggleq);
+
                }
        } while (ath5k_hw_is_intr_pending(ah) && --counter > 0);
 
@@ -2757,6 +2771,7 @@ 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);
@@ -2775,11 +2790,9 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed)
 
        mutex_lock(&sc->lock);
 
-       sc->bintval = conf->beacon_int;
-
        ret = ath5k_chan_set(sc, conf->channel);
        if (ret < 0)
-               return ret;
+               goto unlock;
 
        if ((changed & IEEE80211_CONF_CHANGE_POWER) &&
        (sc->power_level != conf->power_level)) {
@@ -2808,8 +2821,9 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed)
         */
        ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT);
 
+unlock:
        mutex_unlock(&sc->lock);
-       return 0;
+       return ret;
 }
 
 #define SUPPORTED_FIF_FLAGS \
@@ -3061,7 +3075,14 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        int ret;
        struct ath5k_softc *sc = hw->priv;
-       struct sk_buff *skb = ieee80211_beacon_get(hw, vif);
+       struct sk_buff *skb;
+
+       if (WARN_ON(!vif)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       skb = ieee80211_beacon_get(hw, vif);
 
        if (!skb) {
                ret = -ENOMEM;
index 852b2c1..f9b7f2f 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/wireless.h>
 #include <linux/if_ether.h>
 #include <linux/leds.h>
+#include <linux/rfkill.h>
 
 #include "ath5k.h"
 #include "debug.h"
@@ -91,6 +92,15 @@ struct ath5k_led
        struct led_classdev led_dev;            /* led classdev */
 };
 
+/* Rfkill */
+struct ath5k_rfkill {
+       /* GPIO PIN for rfkill */
+       u16 gpio;
+       /* polarity of rfkill GPIO PIN */
+       bool polarity;
+       /* RFKILL toggle tasklet */
+       struct tasklet_struct toggleq;
+};
 
 #if CHAN_DEBUG
 #define ATH_CHAN_MAX   (26+26+26+200+200)
@@ -167,6 +177,8 @@ struct ath5k_softc {
        struct tasklet_struct   txtq;           /* tx intr tasklet */
        struct ath5k_led        tx_led;         /* tx led */
 
+       struct ath5k_rfkill     rf_kill;
+
        spinlock_t              block;          /* protects beacon */
        struct tasklet_struct   beacontq;       /* beacon intr tasklet */
        struct ath5k_buf        *bbuf;          /* beacon buffer */
index 6606773..bd0a97a 100644 (file)
@@ -1304,23 +1304,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
        if (ah->ah_version != AR5K_AR5210)
                ath5k_hw_set_imr(ah, ah->ah_imr);
 
-       /*
-        * Setup RFKill interrupt if rfkill flag is set on eeprom.
-        * TODO: Use gpio pin and polarity infos from eeprom
-        * TODO: Handle this in ath5k_intr because it'll result
-        *       a nasty interrupt storm.
-        */
-#if 0
-       if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) {
-               ath5k_hw_set_gpio_input(ah, 0);
-               ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, 0);
-               if (ah->ah_gpio[0] == 0)
-                       ath5k_hw_set_gpio_intr(ah, 0, 1);
-               else
-                       ath5k_hw_set_gpio_intr(ah, 0, 0);
-       }
-#endif
-
        /* Enable 32KHz clock function for AR5212+ chips
         * Set clocks to 32KHz operation and use an
         * external 32KHz crystal when sleeping if one
diff --git a/drivers/net/wireless/ath/ath5k/rfkill.c b/drivers/net/wireless/ath/ath5k/rfkill.c
new file mode 100644 (file)
index 0000000..41a877b
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * RFKILL support for ath5k
+ *
+ * Copyright (c) 2009 Tobias Doerffel <tobias.doerffel@gmail.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include "base.h"
+
+
+static inline void ath5k_rfkill_disable(struct ath5k_softc *sc)
+{
+       ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "rfkill disable (gpio:%d polarity:%d)\n",
+               sc->rf_kill.gpio, sc->rf_kill.polarity);
+       ath5k_hw_set_gpio_output(sc->ah, sc->rf_kill.gpio);
+       ath5k_hw_set_gpio(sc->ah, sc->rf_kill.gpio, !sc->rf_kill.polarity);
+}
+
+
+static inline void ath5k_rfkill_enable(struct ath5k_softc *sc)
+{
+       ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "rfkill enable (gpio:%d polarity:%d)\n",
+               sc->rf_kill.gpio, sc->rf_kill.polarity);
+       ath5k_hw_set_gpio_output(sc->ah, sc->rf_kill.gpio);
+       ath5k_hw_set_gpio(sc->ah, sc->rf_kill.gpio, sc->rf_kill.polarity);
+}
+
+static inline void ath5k_rfkill_set_intr(struct ath5k_softc *sc, bool enable)
+{
+       struct ath5k_hw *ah = sc->ah;
+       u32 curval;
+
+       ath5k_hw_set_gpio_input(ah, sc->rf_kill.gpio);
+       curval = ath5k_hw_get_gpio(ah, sc->rf_kill.gpio);
+       ath5k_hw_set_gpio_intr(ah, sc->rf_kill.gpio, enable ?
+                                       !!curval : !curval);
+}
+
+static bool
+ath5k_is_rfkill_set(struct ath5k_softc *sc)
+{
+       /* configuring GPIO for input for some reason disables rfkill */
+       /*ath5k_hw_set_gpio_input(sc->ah, sc->rf_kill.gpio);*/
+       return ath5k_hw_get_gpio(sc->ah, sc->rf_kill.gpio) ==
+                                                       sc->rf_kill.polarity;
+}
+
+static void
+ath5k_tasklet_rfkill_toggle(unsigned long data)
+{
+       struct ath5k_softc *sc = (void *)data;
+       bool blocked;
+
+       blocked = ath5k_is_rfkill_set(sc);
+       wiphy_rfkill_set_hw_state(sc->hw->wiphy, blocked);
+}
+
+
+void
+ath5k_rfkill_hw_start(struct ath5k_hw *ah)
+{
+       struct ath5k_softc *sc = ah->ah_sc;
+
+       /* read rfkill GPIO configuration from EEPROM header */
+       sc->rf_kill.gpio = ah->ah_capabilities.cap_eeprom.ee_rfkill_pin;
+       sc->rf_kill.polarity = ah->ah_capabilities.cap_eeprom.ee_rfkill_pol;
+
+       tasklet_init(&sc->rf_kill.toggleq, ath5k_tasklet_rfkill_toggle,
+               (unsigned long)sc);
+
+       ath5k_rfkill_disable(sc);
+
+       /* enable interrupt for rfkill switch */
+       if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header))
+               ath5k_rfkill_set_intr(sc, true);
+}
+
+
+void
+ath5k_rfkill_hw_stop(struct ath5k_hw *ah)
+{
+       struct ath5k_softc *sc = ah->ah_sc;
+
+       /* disable interrupt for rfkill switch */
+       if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header))
+               ath5k_rfkill_set_intr(sc, false);
+
+       tasklet_kill(&sc->rf_kill.toggleq);
+
+       /* enable RFKILL when stopping HW so Wifi LED is turned off */
+       ath5k_rfkill_enable(sc);
+}
+
index 796a3ad..515880a 100644 (file)
@@ -460,12 +460,9 @@ struct ath_led {
        bool registered;
 };
 
-/* Rfkill */
-#define ATH_RFKILL_POLL_INTERVAL       2000 /* msecs */
-
 struct ath_rfkill {
        struct rfkill *rfkill;
-       struct delayed_work rfkill_poll;
+       struct rfkill_ops ops;
        char rfkill_name[32];
 };
 
@@ -509,8 +506,6 @@ struct ath_rfkill {
 #define SC_OP_RXFLUSH           BIT(7)
 #define SC_OP_LED_ASSOCIATED    BIT(8)
 #define SC_OP_RFKILL_REGISTERED BIT(9)
-#define SC_OP_RFKILL_SW_BLOCKED BIT(10)
-#define SC_OP_RFKILL_HW_BLOCKED BIT(11)
 #define SC_OP_WAIT_FOR_BEACON   BIT(12)
 #define SC_OP_LED_ON            BIT(13)
 #define SC_OP_SCANNING          BIT(14)
index a21b213..3639a2e 100644 (file)
@@ -411,6 +411,7 @@ void ath_beacon_tasklet(unsigned long data)
                } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
                        DPRINTF(sc, ATH_DBG_BEACON,
                                "beacon is officially stuck\n");
+                       sc->sc_flags |= SC_OP_TSF_RESET;
                        ath_reset(sc, false);
                }
 
@@ -673,6 +674,14 @@ 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 */
 
        nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp);
index 97df20c..6d20725 100644 (file)
@@ -44,6 +44,44 @@ static int ath9k_debugfs_open(struct inode *inode, struct file *file)
        return 0;
 }
 
+static ssize_t read_file_debug(struct file *file, char __user *user_buf,
+                            size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       char buf[32];
+       unsigned int len;
+
+       len = snprintf(buf, sizeof(buf), "0x%08x\n", sc->debug.debug_mask);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_debug(struct file *file, const char __user *user_buf,
+                            size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       unsigned long mask;
+       char buf[32];
+       ssize_t len;
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len))
+               return -EINVAL;
+
+       buf[len] = '\0';
+       if (strict_strtoul(buf, 0, &mask))
+               return -EINVAL;
+
+       sc->debug.debug_mask = mask;
+       return count;
+}
+
+static const struct file_operations fops_debug = {
+       .read = read_file_debug,
+       .write = write_file_debug,
+       .open = ath9k_debugfs_open,
+       .owner = THIS_MODULE
+};
+
 static ssize_t read_file_dma(struct file *file, char __user *user_buf,
                             size_t count, loff_t *ppos)
 {
@@ -224,111 +262,66 @@ static const struct file_operations fops_interrupt = {
        .owner = THIS_MODULE
 };
 
-static void ath_debug_stat_11n_rc(struct ath_softc *sc, struct sk_buff *skb)
-{
-       struct ath_tx_info_priv *tx_info_priv = NULL;
-       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-       struct ieee80211_tx_rate *rates = tx_info->status.rates;
-       int final_ts_idx, idx;
-
-       tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
-       final_ts_idx = tx_info_priv->tx.ts_rateindex;
-       idx = sc->cur_rate_table->info[rates[final_ts_idx].idx].dot11rate;
-
-       sc->debug.stats.n_rcstats[idx].success++;
-}
-
-static void ath_debug_stat_legacy_rc(struct ath_softc *sc, struct sk_buff *skb)
+void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb)
 {
        struct ath_tx_info_priv *tx_info_priv = NULL;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        struct ieee80211_tx_rate *rates = tx_info->status.rates;
        int final_ts_idx, idx;
+       struct ath_rc_stats *stats;
 
        tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
        final_ts_idx = tx_info_priv->tx.ts_rateindex;
        idx = rates[final_ts_idx].idx;
-
-       sc->debug.stats.legacy_rcstats[idx].success++;
-}
-
-void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb)
-{
-       if (conf_is_ht(&sc->hw->conf))
-               ath_debug_stat_11n_rc(sc, skb);
-       else
-               ath_debug_stat_legacy_rc(sc, skb);
+       stats = &sc->debug.stats.rcstats[idx];
+       stats->success++;
 }
 
-/* FIXME: legacy rates, later on .. */
 void ath_debug_stat_retries(struct ath_softc *sc, int rix,
                            int xretries, int retries, u8 per)
 {
-       if (conf_is_ht(&sc->hw->conf)) {
-               int idx = sc->cur_rate_table->info[rix].dot11rate;
+       struct ath_rc_stats *stats = &sc->debug.stats.rcstats[rix];
 
-               sc->debug.stats.n_rcstats[idx].xretries += xretries;
-               sc->debug.stats.n_rcstats[idx].retries += retries;
-               sc->debug.stats.n_rcstats[idx].per = per;
-       }
+       stats->xretries += xretries;
+       stats->retries += retries;
+       stats->per = per;
 }
 
-static ssize_t ath_read_file_stat_11n_rc(struct file *file,
-                                        char __user *user_buf,
-                                        size_t count, loff_t *ppos)
+static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
+                               size_t count, loff_t *ppos)
 {
        struct ath_softc *sc = file->private_data;
-       char buf[1024];
-       unsigned int len = 0;
+       char *buf;
+       unsigned int len = 0, max;
        int i = 0;
+       ssize_t retval;
 
-       len += sprintf(buf, "%7s %13s %8s %8s %6s\n\n", "Rate", "Success",
-                      "Retries", "XRetries", "PER");
-
-       for (i = 0; i <= 15; i++) {
-               len += snprintf(buf + len, sizeof(buf) - len,
-                               "%5s%3d: %8u %8u %8u %8u\n", "MCS", i,
-                               sc->debug.stats.n_rcstats[i].success,
-                               sc->debug.stats.n_rcstats[i].retries,
-                               sc->debug.stats.n_rcstats[i].xretries,
-                               sc->debug.stats.n_rcstats[i].per);
-       }
-
-       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
+       if (sc->cur_rate_table == NULL)
+               return 0;
 
-static ssize_t ath_read_file_stat_legacy_rc(struct file *file,
-                                           char __user *user_buf,
-                                           size_t count, loff_t *ppos)
-{
-       struct ath_softc *sc = file->private_data;
-       char buf[512];
-       unsigned int len = 0;
-       int i = 0;
+       max = 80 + sc->cur_rate_table->rate_cnt * 64;
+       buf = kmalloc(max + 1, GFP_KERNEL);
+       if (buf == NULL)
+               return 0;
+       buf[max] = 0;
 
-       len += sprintf(buf, "%7s %13s\n\n", "Rate", "Success");
+       len += sprintf(buf, "%5s %15s %8s %9s %3s\n\n", "Rate", "Success",
+                      "Retries", "XRetries", "PER");
 
        for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) {
-               len += snprintf(buf + len, sizeof(buf) - len, "%5u: %12u\n",
-                               sc->cur_rate_table->info[i].ratekbps / 1000,
-                               sc->debug.stats.legacy_rcstats[i].success);
+               u32 ratekbps = sc->cur_rate_table->info[i].ratekbps;
+               struct ath_rc_stats *stats = &sc->debug.stats.rcstats[i];
+
+               len += snprintf(buf + len, max - len,
+                       "%3u.%d: %8u %8u %8u %8u\n", ratekbps / 1000,
+                       (ratekbps % 1000) / 100, stats->success,
+                       stats->retries, stats->xretries,
+                       stats->per);
        }
 
-       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
-
-static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
-                               size_t count, loff_t *ppos)
-{
-       struct ath_softc *sc = file->private_data;
-
-       if (sc->cur_rate_table == NULL)
-               return 0;
-
-       if (conf_is_ht(&sc->hw->conf))
-               return ath_read_file_stat_11n_rc(file, user_buf, count, ppos);
-       else
-               return ath_read_file_stat_legacy_rc(file, user_buf, count ,ppos);
+       retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+       kfree(buf);
+       return retval;
 }
 
 static const struct file_operations fops_rcstat = {
@@ -506,6 +499,11 @@ int ath9k_init_debug(struct ath_softc *sc)
        if (!sc->debug.debugfs_phy)
                goto err;
 
+       sc->debug.debugfs_debug = debugfs_create_file("debug",
+               S_IRUGO | 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_phy, sc, &fops_dma);
        if (!sc->debug.debugfs_dma)
@@ -543,6 +541,7 @@ void ath9k_exit_debug(struct ath_softc *sc)
        debugfs_remove(sc->debug.debugfs_rcstat);
        debugfs_remove(sc->debug.debugfs_interrupt);
        debugfs_remove(sc->debug.debugfs_dma);
+       debugfs_remove(sc->debug.debugfs_debug);
        debugfs_remove(sc->debug.debugfs_phy);
 }
 
index db845cf..edda15b 100644 (file)
@@ -80,11 +80,7 @@ struct ath_interrupt_stats {
        u32 dtim;
 };
 
-struct ath_legacy_rc_stats {
-       u32 success;
-};
-
-struct ath_11n_rc_stats {
+struct ath_rc_stats {
        u32 success;
        u32 retries;
        u32 xretries;
@@ -93,13 +89,13 @@ struct ath_11n_rc_stats {
 
 struct ath_stats {
        struct ath_interrupt_stats istats;
-       struct ath_legacy_rc_stats legacy_rcstats[12];  /* max(11a,11b,11g) */
-       struct ath_11n_rc_stats n_rcstats[16];          /* 0..15 MCS rates */
+       struct ath_rc_stats rcstats[RATE_TABLE_SIZE];
 };
 
 struct ath9k_debug {
        int debug_mask;
        struct dentry *debugfs_phy;
+       struct dentry *debugfs_debug;
        struct dentry *debugfs_dma;
        struct dentry *debugfs_interrupt;
        struct dentry *debugfs_rcstat;
index 61da08a..f7baa40 100644 (file)
@@ -1192,120 +1192,69 @@ static bool ath_is_rfkill_set(struct ath_softc *sc)
                                  ah->rfkill_polarity;
 }
 
-/* h/w rfkill poll function */
-static void ath_rfkill_poll(struct work_struct *work)
+/* s/w rfkill handlers */
+static int ath_rfkill_set_block(void *data, bool blocked)
 {
-       struct ath_softc *sc = container_of(work, struct ath_softc,
-                                           rf_kill.rfkill_poll.work);
-       bool radio_on;
-
-       if (sc->sc_flags & SC_OP_INVALID)
-               return;
-
-       radio_on = !ath_is_rfkill_set(sc);
-
-       /*
-        * enable/disable radio only when there is a
-        * state change in RF switch
-        */
-       if (radio_on == !!(sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED)) {
-               enum rfkill_state state;
-
-               if (sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED) {
-                       state = radio_on ? RFKILL_STATE_SOFT_BLOCKED
-                               : RFKILL_STATE_HARD_BLOCKED;
-               } else if (radio_on) {
-                       ath_radio_enable(sc);
-                       state = RFKILL_STATE_UNBLOCKED;
-               } else {
-                       ath_radio_disable(sc);
-                       state = RFKILL_STATE_HARD_BLOCKED;
-               }
-
-               if (state == RFKILL_STATE_HARD_BLOCKED)
-                       sc->sc_flags |= SC_OP_RFKILL_HW_BLOCKED;
-               else
-                       sc->sc_flags &= ~SC_OP_RFKILL_HW_BLOCKED;
+       struct ath_softc *sc = data;
 
-               rfkill_force_state(sc->rf_kill.rfkill, state);
-       }
+       if (blocked)
+               ath_radio_disable(sc);
+       else
+               ath_radio_enable(sc);
 
-       queue_delayed_work(sc->hw->workqueue, &sc->rf_kill.rfkill_poll,
-                          msecs_to_jiffies(ATH_RFKILL_POLL_INTERVAL));
+       return 0;
 }
 
-/* s/w rfkill handler */
-static int ath_sw_toggle_radio(void *data, enum rfkill_state state)
+static void ath_rfkill_poll_state(struct rfkill *rfkill, void *data)
 {
        struct ath_softc *sc = data;
+       bool blocked = !!ath_is_rfkill_set(sc);
 
-       switch (state) {
-       case RFKILL_STATE_SOFT_BLOCKED:
-               if (!(sc->sc_flags & (SC_OP_RFKILL_HW_BLOCKED |
-                   SC_OP_RFKILL_SW_BLOCKED)))
-                       ath_radio_disable(sc);
-               sc->sc_flags |= SC_OP_RFKILL_SW_BLOCKED;
-               return 0;
-       case RFKILL_STATE_UNBLOCKED:
-               if ((sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED)) {
-                       sc->sc_flags &= ~SC_OP_RFKILL_SW_BLOCKED;
-                       if (sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED) {
-                               DPRINTF(sc, ATH_DBG_FATAL, "Can't turn on the"
-                                       "radio as it is disabled by h/w\n");
-                               return -EPERM;
-                       }
-                       ath_radio_enable(sc);
-               }
-               return 0;
-       default:
-               return -EINVAL;
-       }
+       if (rfkill_set_hw_state(rfkill, blocked))
+               ath_radio_disable(sc);
+       else
+               ath_radio_enable(sc);
 }
 
 /* Init s/w rfkill */
 static int ath_init_sw_rfkill(struct ath_softc *sc)
 {
-       sc->rf_kill.rfkill = rfkill_allocate(wiphy_dev(sc->hw->wiphy),
-                                            RFKILL_TYPE_WLAN);
+       sc->rf_kill.ops.set_block = ath_rfkill_set_block;
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+               sc->rf_kill.ops.poll = ath_rfkill_poll_state;
+
+       snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name),
+               "ath9k-%s::rfkill", wiphy_name(sc->hw->wiphy));
+
+       sc->rf_kill.rfkill = rfkill_alloc(sc->rf_kill.rfkill_name,
+                                         wiphy_dev(sc->hw->wiphy),
+                                         RFKILL_TYPE_WLAN,
+                                         &sc->rf_kill.ops, sc);
        if (!sc->rf_kill.rfkill) {
                DPRINTF(sc, ATH_DBG_FATAL, "Failed to allocate rfkill\n");
                return -ENOMEM;
        }
 
-       snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name),
-               "ath9k-%s::rfkill", wiphy_name(sc->hw->wiphy));
-       sc->rf_kill.rfkill->name = sc->rf_kill.rfkill_name;
-       sc->rf_kill.rfkill->data = sc;
-       sc->rf_kill.rfkill->toggle_radio = ath_sw_toggle_radio;
-       sc->rf_kill.rfkill->state = RFKILL_STATE_UNBLOCKED;
-
        return 0;
 }
 
 /* Deinitialize rfkill */
 static void ath_deinit_rfkill(struct ath_softc *sc)
 {
-       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
-               cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
-
        if (sc->sc_flags & SC_OP_RFKILL_REGISTERED) {
                rfkill_unregister(sc->rf_kill.rfkill);
+               rfkill_destroy(sc->rf_kill.rfkill);
                sc->sc_flags &= ~SC_OP_RFKILL_REGISTERED;
-               sc->rf_kill.rfkill = NULL;
        }
 }
 
 static int ath_start_rfkill_poll(struct ath_softc *sc)
 {
-       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
-               queue_delayed_work(sc->hw->workqueue,
-                                  &sc->rf_kill.rfkill_poll, 0);
-
        if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) {
                if (rfkill_register(sc->rf_kill.rfkill)) {
                        DPRINTF(sc, ATH_DBG_FATAL,
                                "Unable to register rfkill\n");
-                       rfkill_free(sc->rf_kill.rfkill);
+                       rfkill_destroy(sc->rf_kill.rfkill);
 
                        /* Deinitialize the device */
                        ath_cleanup(sc);
@@ -1678,10 +1627,6 @@ int ath_attach(u16 devid, struct ath_softc *sc)
                goto error_attach;
 
 #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
-       /* Initialze h/w Rfkill */
-       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
-               INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll);
-
        /* Initialize s/w rfkill */
        error = ath_init_sw_rfkill(sc);
        if (error)
@@ -2214,10 +2159,8 @@ static void ath9k_stop(struct ieee80211_hw *hw)
        } else
                sc->rx.rxlink = NULL;
 
-#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
-       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
-               cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
-#endif
+       rfkill_pause_polling(sc->rf_kill.rfkill);
+
        /* disable HAL and put h/w to sleep */
        ath9k_hw_disable(sc->sc_ah);
        ath9k_hw_configpcipowersave(sc->sc_ah, 1);
index 168411d..ccdf20a 100644 (file)
@@ -227,11 +227,6 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 
        ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
 
-#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
-       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
-               cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
-#endif
-
        pci_save_state(pdev);
        pci_disable_device(pdev);
        pci_set_power_state(pdev, PCI_D3hot);
@@ -256,16 +251,6 @@ static int ath_pci_resume(struct pci_dev *pdev)
                            AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
        ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
 
-#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
-       /*
-        * check the h/w rfkill state on resume
-        * and start the rfkill poll timer
-        */
-       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
-               queue_delayed_work(sc->hw->workqueue,
-                                  &sc->rf_kill.rfkill_poll, 0);
-#endif
-
        return 0;
 }
 
index a8def4f..b61a071 100644 (file)
@@ -711,6 +711,7 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
                return 0;
 
        if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
+               txtid->state &= ~AGGR_ADDBA_PROGRESS;
                txtid->addba_exchangeattempts = 0;
                return 0;
        }
index 7a89f9f..eef370b 100644 (file)
@@ -366,11 +366,17 @@ static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg)
        if (rd & COUNTRY_ERD_FLAG) {
                /* EEPROM value is a country code */
                u16 cc = rd & ~COUNTRY_ERD_FLAG;
+               printk(KERN_DEBUG
+                      "ath: EEPROM indicates we should expect "
+                       "a country code\n");
                for (i = 0; i < ARRAY_SIZE(allCountries); i++)
                        if (allCountries[i].countryCode == cc)
                                return true;
        } else {
                /* EEPROM value is a regpair value */
+               if (rd != CTRY_DEFAULT)
+                       printk(KERN_DEBUG "ath: EEPROM indicates we "
+                              "should expect a direct regpair map\n");
                for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
                        if (regDomainPairs[i].regDmnEnum == rd)
                                return true;
@@ -477,6 +483,11 @@ ath_regd_init(struct ath_regulatory *reg,
        struct country_code_to_enum_rd *country = NULL;
        u16 regdmn;
 
+       if (!reg)
+               return -EINVAL;
+
+       printk(KERN_DEBUG "ath: EEPROM regdomain: 0x%0x\n", reg->current_rd);
+
        if (!ath_regd_is_eeprom_valid(reg)) {
                printk(KERN_ERR "ath: Invalid EEPROM contents\n");
                return -EINVAL;
@@ -486,20 +497,30 @@ ath_regd_init(struct ath_regulatory *reg,
        reg->country_code = ath_regd_get_default_country(regdmn);
 
        if (reg->country_code == CTRY_DEFAULT &&
-           regdmn == CTRY_DEFAULT)
+           regdmn == CTRY_DEFAULT) {
+               printk(KERN_DEBUG "ath: EEPROM indicates default "
+                      "country code should be used\n");
                reg->country_code = CTRY_UNITED_STATES;
+       }
 
        if (reg->country_code == CTRY_DEFAULT) {
                country = NULL;
        } else {
+               printk(KERN_DEBUG "ath: doing EEPROM country->regdmn "
+                      "map search\n");
                country = ath_regd_find_country(reg->country_code);
                if (country == NULL) {
                        printk(KERN_DEBUG
-                               "ath: Country is NULL!!!!, cc= %d\n",
+                               "ath: no valid country maps found for "
+                               "country code: 0x%0x\n",
                                reg->country_code);
                        return -EINVAL;
-               } else
+               } else {
                        regdmn = country->regDmnEnum;
+                       printk(KERN_DEBUG "ath: country maps to "
+                              "regdmn code: 0x%0x\n",
+                              regdmn);
+               }
        }
 
        reg->regpair = ath_get_regpair(regdmn);
@@ -523,7 +544,7 @@ ath_regd_init(struct ath_regulatory *reg,
 
        printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n",
                reg->alpha2[0], reg->alpha2[1]);
-       printk(KERN_DEBUG "ath: Regpair detected: 0x%0x\n",
+       printk(KERN_DEBUG "ath: Regpair used: 0x%0x\n",
                reg->regpair->regDmnEnum);
 
        ath_regd_init_wiphy(reg, wiphy, reg_notifier);
index 21572e4..67f564e 100644 (file)
@@ -98,13 +98,6 @@ config B43_LEDS
        depends on B43 && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = B43)
        default y
 
-# This config option automatically enables b43 RFKILL support,
-# if it's possible.
-config B43_RFKILL
-       bool
-       depends on B43 && (RFKILL = y || RFKILL = B43) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43)
-       default y
-
 # This config option automatically enables b43 HW-RNG support,
 # if the HW-RNG core is enabled.
 config B43_HWRNG
index 281ef83..da379f4 100644 (file)
@@ -13,7 +13,7 @@ b43-y                         += lo.o
 b43-y                          += wa.o
 b43-y                          += dma.o
 b43-$(CONFIG_B43_PIO)          += pio.o
-b43-$(CONFIG_B43_RFKILL)       += rfkill.o
+b43-y                          += rfkill.o
 b43-$(CONFIG_B43_LEDS)         += leds.o
 b43-$(CONFIG_B43_PCMCIA)       += pcmcia.o
 b43-$(CONFIG_B43_DEBUG)                += debugfs.o
index 4e8ad84..f580c28 100644 (file)
@@ -163,6 +163,7 @@ enum {
 #define B43_SHM_SH_WLCOREREV           0x0016  /* 802.11 core revision */
 #define B43_SHM_SH_PCTLWDPOS           0x0008
 #define B43_SHM_SH_RXPADOFF            0x0034  /* RX Padding data offset (PIO only) */
+#define B43_SHM_SH_FWCAPA              0x0042  /* Firmware capabilities (Opensource firmware only) */
 #define B43_SHM_SH_PHYVER              0x0050  /* PHY version */
 #define B43_SHM_SH_PHYTYPE             0x0052  /* PHY type */
 #define B43_SHM_SH_ANTSWAP             0x005C  /* Antenna swap threshold */
@@ -297,6 +298,10 @@ enum {
 #define B43_HF_MLADVW          0x001000000000ULL /* N PHY ML ADV workaround (rev >= 13 only) */
 #define B43_HF_PR45960W                0x080000000000ULL /* PR 45960 workaround (rev >= 13 only) */
 
+/* Firmware capabilities field in SHM (Opensource firmware only) */
+#define B43_FWCAPA_HWCRYPTO    0x0001
+#define B43_FWCAPA_QOS         0x0002
+
 /* MacFilter offsets. */
 #define B43_MACFILTER_SELF             0x0000
 #define B43_MACFILTER_BSSID            0x0003
@@ -596,6 +601,13 @@ struct b43_wl {
        /* Pointer to the ieee80211 hardware data structure */
        struct ieee80211_hw *hw;
 
+       /* The number of queues that were registered with the mac80211 subsystem
+        * initially. This is a backup copy of hw->queues in case hw->queues has
+        * to be dynamically lowered at runtime (Firmware does not support QoS).
+        * hw->queues has to be restored to the original value before unregistering
+        * from the mac80211 subsystem. */
+       u16 mac80211_initially_registered_queues;
+
        struct mutex mutex;
        spinlock_t irq_lock;
        /* R/W lock for data transmission.
@@ -631,9 +643,6 @@ struct b43_wl {
        char rng_name[30 + 1];
 #endif /* CONFIG_B43_HWRNG */
 
-       /* The RF-kill button */
-       struct b43_rfkill rfkill;
-
        /* List of all wireless devices on this chip */
        struct list_head devlist;
        u8 nr_devs;
@@ -752,6 +761,8 @@ struct b43_wldev {
        bool dfq_valid;         /* Directed frame queue valid (IBSS PS mode, ATIM) */
        bool radio_hw_enable;   /* saved state of radio hardware enabled state */
        bool suspend_in_progress;       /* TRUE, if we are in a suspend/resume cycle */
+       bool qos_enabled;               /* TRUE, if QoS is used. */
+       bool hwcrypto_enabled;          /* TRUE, if HW crypto acceleration is enabled. */
 
        /* PHY/Radio device. */
        struct b43_phy phy;
index eae680b..7964cc3 100644 (file)
@@ -1285,7 +1285,7 @@ static struct b43_dmaring *select_ring_by_priority(struct b43_wldev *dev,
 {
        struct b43_dmaring *ring;
 
-       if (b43_modparam_qos) {
+       if (dev->qos_enabled) {
                /* 0 = highest priority */
                switch (queue_prio) {
                default:
index 76f4c7b..c8b3170 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "b43.h"
 #include "leds.h"
+#include "rfkill.h"
 
 
 static void b43_led_turn_on(struct b43_wldev *dev, u8 led_index,
@@ -87,7 +88,7 @@ static void b43_led_brightness_set(struct led_classdev *led_dev,
 }
 
 static int b43_register_led(struct b43_wldev *dev, struct b43_led *led,
-                           const char *name, char *default_trigger,
+                           const char *name, const char *default_trigger,
                            u8 led_index, bool activelow)
 {
        int err;
@@ -164,10 +165,10 @@ static void b43_map_led(struct b43_wldev *dev,
                snprintf(name, sizeof(name),
                         "b43-%s::radio", wiphy_name(hw->wiphy));
                b43_register_led(dev, &dev->led_radio, name,
-                                b43_rfkill_led_name(dev),
+                                ieee80211_get_radio_led_name(hw),
                                 led_index, activelow);
-               /* Sync the RF-kill LED state with the switch state. */
-               if (dev->radio_hw_enable)
+               /* Sync the RF-kill LED state with radio and switch states. */
+               if (dev->phy.radio_on && b43_is_hw_radio_enabled(dev))
                        b43_led_turn_on(dev, led_index, activelow);
                break;
        case B43_LED_WEIRD:
index cb4a871..6456afe 100644 (file)
@@ -80,8 +80,8 @@ static int modparam_nohwcrypt;
 module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
 MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
 
-int b43_modparam_qos = 1;
-module_param_named(qos, b43_modparam_qos, int, 0444);
+static int modparam_qos = 1;
+module_param_named(qos, modparam_qos, int, 0444);
 MODULE_PARM_DESC(qos, "Enable QOS support (default on)");
 
 static int modparam_btcoex = 1;
@@ -538,6 +538,13 @@ void b43_hf_write(struct b43_wldev *dev, u64 value)
        b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI, hi);
 }
 
+/* Read the firmware capabilities bitmask (Opensource firmware only) */
+static u16 b43_fwcapa_read(struct b43_wldev *dev)
+{
+       B43_WARN_ON(!dev->fw.opensource);
+       return b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_FWCAPA);
+}
+
 void b43_tsf_read(struct b43_wldev *dev, u64 *tsf)
 {
        u32 low, high;
@@ -2307,12 +2314,34 @@ static int b43_upload_microcode(struct b43_wldev *dev)
        dev->fw.patch = fwpatch;
        dev->fw.opensource = (fwdate == 0xFFFF);
 
+       /* Default to use-all-queues. */
+       dev->wl->hw->queues = dev->wl->mac80211_initially_registered_queues;
+       dev->qos_enabled = !!modparam_qos;
+       /* Default to firmware/hardware crypto acceleration. */
+       dev->hwcrypto_enabled = 1;
+
        if (dev->fw.opensource) {
+               u16 fwcapa;
+
                /* Patchlevel info is encoded in the "time" field. */
                dev->fw.patch = fwtime;
-               b43info(dev->wl, "Loading OpenSource firmware version %u.%u%s\n",
-                       dev->fw.rev, dev->fw.patch,
-                       dev->fw.pcm_request_failed ? " (Hardware crypto not supported)" : "");
+               b43info(dev->wl, "Loading OpenSource firmware version %u.%u\n",
+                       dev->fw.rev, dev->fw.patch);
+
+               fwcapa = b43_fwcapa_read(dev);
+               if (!(fwcapa & B43_FWCAPA_HWCRYPTO) || dev->fw.pcm_request_failed) {
+                       b43info(dev->wl, "Hardware crypto acceleration not supported by firmware\n");
+                       /* Disable hardware crypto and fall back to software crypto. */
+                       dev->hwcrypto_enabled = 0;
+               }
+               if (!(fwcapa & B43_FWCAPA_QOS)) {
+                       b43info(dev->wl, "QoS not supported by firmware\n");
+                       /* Disable QoS. Tweak hw->queues to 1. It will be restored before
+                        * ieee80211_unregister to make sure the networking core can
+                        * properly free possible resources. */
+                       dev->wl->hw->queues = 1;
+                       dev->qos_enabled = 0;
+               }
        } else {
                b43info(dev->wl, "Loading firmware version %u.%u "
                        "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
@@ -3470,7 +3499,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
 
        if (!!conf->radio_enabled != phy->radio_on) {
                if (conf->radio_enabled) {
-                       b43_software_rfkill(dev, RFKILL_STATE_UNBLOCKED);
+                       b43_software_rfkill(dev, false);
                        b43info(dev->wl, "Radio turned on by software\n");
                        if (!dev->radio_hw_enable) {
                                b43info(dev->wl, "The hardware RF-kill button "
@@ -3478,7 +3507,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
                                        "Press the button to turn it on.\n");
                        }
                } else {
-                       b43_software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED);
+                       b43_software_rfkill(dev, true);
                        b43info(dev->wl, "Radio turned off by software\n");
                }
        }
@@ -3627,7 +3656,7 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        if (!dev || b43_status(dev) < B43_STAT_INITIALIZED)
                goto out_unlock;
 
-       if (dev->fw.pcm_request_failed) {
+       if (dev->fw.pcm_request_failed || !dev->hwcrypto_enabled) {
                /* We don't have firmware for the crypto engine.
                 * Must use software-crypto. */
                err = -EOPNOTSUPP;
@@ -4298,7 +4327,6 @@ static int b43_op_start(struct ieee80211_hw *hw)
        struct b43_wldev *dev = wl->current_dev;
        int did_init = 0;
        int err = 0;
-       bool do_rfkill_exit = 0;
 
        /* Kill all old instance specific information to make sure
         * the card won't use it in the short timeframe between start
@@ -4312,18 +4340,12 @@ static int b43_op_start(struct ieee80211_hw *hw)
        wl->beacon1_uploaded = 0;
        wl->beacon_templates_virgin = 1;
 
-       /* First register RFkill.
-        * LEDs that are registered later depend on it. */
-       b43_rfkill_init(dev);
-
        mutex_lock(&wl->mutex);
 
        if (b43_status(dev) < B43_STAT_INITIALIZED) {
                err = b43_wireless_core_init(dev);
-               if (err) {
-                       do_rfkill_exit = 1;
+               if (err)
                        goto out_mutex_unlock;
-               }
                did_init = 1;
        }
 
@@ -4332,17 +4354,16 @@ static int b43_op_start(struct ieee80211_hw *hw)
                if (err) {
                        if (did_init)
                                b43_wireless_core_exit(dev);
-                       do_rfkill_exit = 1;
                        goto out_mutex_unlock;
                }
        }
 
+       /* XXX: only do if device doesn't support rfkill irq */
+       wiphy_rfkill_start_polling(hw->wiphy);
+
  out_mutex_unlock:
        mutex_unlock(&wl->mutex);
 
-       if (do_rfkill_exit)
-               b43_rfkill_exit(dev);
-
        return err;
 }
 
@@ -4351,7 +4372,6 @@ static void b43_op_stop(struct ieee80211_hw *hw)
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev = wl->current_dev;
 
-       b43_rfkill_exit(dev);
        cancel_work_sync(&(wl->beacon_update_trigger));
 
        mutex_lock(&wl->mutex);
@@ -4433,6 +4453,7 @@ static const struct ieee80211_ops b43_hw_ops = {
        .sta_notify             = b43_op_sta_notify,
        .sw_scan_start          = b43_op_sw_scan_start_notifier,
        .sw_scan_complete       = b43_op_sw_scan_complete_notifier,
+       .rfkill_poll            = b43_rfkill_poll,
 };
 
 /* Hard-reset the chip. Do not call this directly.
@@ -4735,6 +4756,7 @@ static int b43_wireless_init(struct ssb_device *dev)
                b43err(NULL, "Could not allocate ieee80211 device\n");
                goto out;
        }
+       wl = hw_to_b43_wl(hw);
 
        /* fill hw info */
        hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
@@ -4748,7 +4770,8 @@ static int b43_wireless_init(struct ssb_device *dev)
                BIT(NL80211_IFTYPE_WDS) |
                BIT(NL80211_IFTYPE_ADHOC);
 
-       hw->queues = b43_modparam_qos ? 4 : 1;
+       hw->queues = modparam_qos ? 4 : 1;
+       wl->mac80211_initially_registered_queues = hw->queues;
        hw->max_rates = 2;
        SET_IEEE80211_DEV(hw, dev->dev);
        if (is_valid_ether_addr(sprom->et1mac))
@@ -4756,9 +4779,7 @@ static int b43_wireless_init(struct ssb_device *dev)
        else
                SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac);
 
-       /* Get and initialize struct b43_wl */
-       wl = hw_to_b43_wl(hw);
-       memset(wl, 0, sizeof(*wl));
+       /* Initialize struct b43_wl */
        wl->hw = hw;
        spin_lock_init(&wl->irq_lock);
        rwlock_init(&wl->tx_lock);
@@ -4824,8 +4845,13 @@ static void b43_remove(struct ssb_device *dev)
        cancel_work_sync(&wldev->restart_work);
 
        B43_WARN_ON(!wl);
-       if (wl->current_dev == wldev)
+       if (wl->current_dev == wldev) {
+               /* Restore the queues count before unregistering, because firmware detect
+                * might have modified it. Restoring is important, so the networking
+                * stack can properly free resources. */
+               wl->hw->queues = wl->mac80211_initially_registered_queues;
                ieee80211_unregister_hw(wl->hw);
+       }
 
        b43_one_core_detach(dev);
 
@@ -4920,7 +4946,7 @@ static struct ssb_driver b43_ssb_driver = {
 static void b43_print_driverinfo(void)
 {
        const char *feat_pci = "", *feat_pcmcia = "", *feat_nphy = "",
-                  *feat_leds = "", *feat_rfkill = "";
+                  *feat_leds = "";
 
 #ifdef CONFIG_B43_PCI_AUTOSELECT
        feat_pci = "P";
@@ -4934,14 +4960,11 @@ static void b43_print_driverinfo(void)
 #ifdef CONFIG_B43_LEDS
        feat_leds = "L";
 #endif
-#ifdef CONFIG_B43_RFKILL
-       feat_rfkill = "R";
-#endif
        printk(KERN_INFO "Broadcom 43xx driver loaded "
-              "[ Features: %s%s%s%s%s, Firmware-ID: "
+              "[ Features: %s%s%s%s, Firmware-ID: "
               B43_SUPPORTED_FIRMWARE_ID " ]\n",
               feat_pci, feat_pcmcia, feat_nphy,
-              feat_leds, feat_rfkill);
+              feat_leds);
 }
 
 static int __init b43_init(void)
index 40abcf5..950fb1b 100644 (file)
@@ -39,7 +39,6 @@
 #define PAD_BYTES(nr_bytes)            P4D_BYTES( __LINE__ , (nr_bytes))
 
 
-extern int b43_modparam_qos;
 extern int b43_modparam_verbose;
 
 /* Logmessage verbosity levels. Update the b43_modparam_verbose helptext, if
index c836c07..816e028 100644 (file)
@@ -480,11 +480,11 @@ static bool b43_aphy_op_supports_hwpctl(struct b43_wldev *dev)
 }
 
 static void b43_aphy_op_software_rfkill(struct b43_wldev *dev,
-                                       enum rfkill_state state)
+                                       bool blocked)
 {
        struct b43_phy *phy = &dev->phy;
 
-       if (state == RFKILL_STATE_UNBLOCKED) {
+       if (!blocked) {
                if (phy->radio_on)
                        return;
                b43_radio_write16(dev, 0x0004, 0x00C0);
index e176b6e..6d24162 100644 (file)
@@ -84,7 +84,7 @@ int b43_phy_init(struct b43_wldev *dev)
 
        phy->channel = ops->get_default_chan(dev);
 
-       ops->software_rfkill(dev, RFKILL_STATE_UNBLOCKED);
+       ops->software_rfkill(dev, false);
        err = ops->init(dev);
        if (err) {
                b43err(dev->wl, "PHY init failed\n");
@@ -104,7 +104,7 @@ err_phy_exit:
        if (ops->exit)
                ops->exit(dev);
 err_block_rf:
-       ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED);
+       ops->software_rfkill(dev, true);
 
        return err;
 }
@@ -113,7 +113,7 @@ void b43_phy_exit(struct b43_wldev *dev)
 {
        const struct b43_phy_operations *ops = dev->phy.ops;
 
-       ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED);
+       ops->software_rfkill(dev, true);
        if (ops->exit)
                ops->exit(dev);
 }
@@ -295,18 +295,13 @@ err_restore_cookie:
        return err;
 }
 
-void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state)
+void b43_software_rfkill(struct b43_wldev *dev, bool blocked)
 {
        struct b43_phy *phy = &dev->phy;
 
-       if (state == RFKILL_STATE_HARD_BLOCKED) {
-               /* We cannot hardware-block the device */
-               state = RFKILL_STATE_SOFT_BLOCKED;
-       }
-
        b43_mac_suspend(dev);
-       phy->ops->software_rfkill(dev, state);
-       phy->radio_on = (state == RFKILL_STATE_UNBLOCKED);
+       phy->ops->software_rfkill(dev, blocked);
+       phy->radio_on = !blocked;
        b43_mac_enable(dev);
 }
 
index b2d9910..44cc918 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef LINUX_B43_PHY_COMMON_H_
 #define LINUX_B43_PHY_COMMON_H_
 
-#include <linux/rfkill.h>
+#include <linux/types.h>
 
 struct b43_wldev;
 
@@ -159,7 +159,7 @@ struct b43_phy_operations {
 
        /* Radio */
        bool (*supports_hwpctl)(struct b43_wldev *dev);
-       void (*software_rfkill)(struct b43_wldev *dev, enum rfkill_state state);
+       void (*software_rfkill)(struct b43_wldev *dev, bool blocked);
        void (*switch_analog)(struct b43_wldev *dev, bool on);
        int (*switch_channel)(struct b43_wldev *dev, unsigned int new_channel);
        unsigned int (*get_default_chan)(struct b43_wldev *dev);
@@ -364,7 +364,7 @@ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel);
 /**
  * b43_software_rfkill - Turn the radio ON or OFF in software.
  */
-void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state);
+void b43_software_rfkill(struct b43_wldev *dev, bool blocked);
 
 /**
  * b43_phy_txpower_check - Check TX power output.
index e7b98f0..5300232 100644 (file)
@@ -2592,7 +2592,7 @@ static bool b43_gphy_op_supports_hwpctl(struct b43_wldev *dev)
 }
 
 static void b43_gphy_op_software_rfkill(struct b43_wldev *dev,
-                                       enum rfkill_state state)
+                                       bool blocked)
 {
        struct b43_phy *phy = &dev->phy;
        struct b43_phy_g *gphy = phy->g;
@@ -2600,7 +2600,7 @@ static void b43_gphy_op_software_rfkill(struct b43_wldev *dev,
 
        might_sleep();
 
-       if (state == RFKILL_STATE_UNBLOCKED) {
+       if (!blocked) {
                /* Turn radio ON */
                if (phy->radio_on)
                        return;
index 58e319d..ea0d3a3 100644 (file)
@@ -488,7 +488,7 @@ static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
 }
 
 static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev,
-                                        enum rfkill_state state)
+                                        bool blocked)
 {
        //TODO
 }
index 8bcfda5..be7b560 100644 (file)
@@ -579,7 +579,7 @@ static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
 }
 
 static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
-                                       enum rfkill_state state)
+                                       bool blocked)
 {//TODO
 }
 
index 8cd9776..69138e8 100644 (file)
@@ -313,7 +313,7 @@ static struct b43_pio_txqueue *select_queue_by_priority(struct b43_wldev *dev,
 {
        struct b43_pio_txqueue *q;
 
-       if (b43_modparam_qos) {
+       if (dev->qos_enabled) {
                /* 0 = highest priority */
                switch (queue_prio) {
                default:
index 9e1d00b..31e5599 100644 (file)
 
 */
 
-#include "rfkill.h"
 #include "b43.h"
-#include "phy_common.h"
-
-#include <linux/kmod.h>
 
 
 /* Returns TRUE, if the radio is enabled in hardware. */
-static bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
+bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
 {
        if (dev->phy.rev >= 3) {
                if (!(b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI)
@@ -45,165 +41,39 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
 }
 
 /* The poll callback for the hardware button. */
-static void b43_rfkill_poll(struct input_polled_dev *poll_dev)
+void b43_rfkill_poll(struct ieee80211_hw *hw)
 {
-       struct b43_wldev *dev = poll_dev->private;
-       struct b43_wl *wl = dev->wl;
+       struct b43_wl *wl = hw_to_b43_wl(hw);
+       struct b43_wldev *dev = wl->current_dev;
+       struct ssb_bus *bus = dev->dev->bus;
        bool enabled;
-       bool report_change = 0;
+       bool brought_up = false;
 
        mutex_lock(&wl->mutex);
        if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED)) {
-               mutex_unlock(&wl->mutex);
-               return;
+               if (ssb_bus_powerup(bus, 0)) {
+                       mutex_unlock(&wl->mutex);
+                       return;
+               }
+               ssb_device_enable(dev->dev, 0);
+               brought_up = true;
        }
+
        enabled = b43_is_hw_radio_enabled(dev);
+
        if (unlikely(enabled != dev->radio_hw_enable)) {
                dev->radio_hw_enable = enabled;
-               report_change = 1;
                b43info(wl, "Radio hardware status changed to %s\n",
                        enabled ? "ENABLED" : "DISABLED");
+               wiphy_rfkill_set_hw_state(hw->wiphy, !enabled);
+               if (enabled != dev->phy.radio_on)
+                       b43_software_rfkill(dev, !enabled);
        }
-       mutex_unlock(&wl->mutex);
 
-       /* send the radio switch event to the system - note both a key press
-        * and a release are required */
-       if (unlikely(report_change)) {
-               input_report_key(poll_dev->input, KEY_WLAN, 1);
-               input_report_key(poll_dev->input, KEY_WLAN, 0);
+       if (brought_up) {
+               ssb_device_disable(dev->dev, 0);
+               ssb_bus_may_powerdown(bus);
        }
-}
-
-/* Called when the RFKILL toggled in software. */
-static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state)
-{
-       struct b43_wldev *dev = data;
-       struct b43_wl *wl = dev->wl;
-       int err = -EBUSY;
 
-       if (!wl->rfkill.registered)
-               return 0;
-
-       mutex_lock(&wl->mutex);
-       if (b43_status(dev) < B43_STAT_INITIALIZED)
-               goto out_unlock;
-       err = 0;
-       switch (state) {
-       case RFKILL_STATE_UNBLOCKED:
-               if (!dev->radio_hw_enable) {
-                       /* No luck. We can't toggle the hardware RF-kill
-                        * button from software. */
-                       err = -EBUSY;
-                       goto out_unlock;
-               }
-               if (!dev->phy.radio_on)
-                       b43_software_rfkill(dev, state);
-               break;
-       case RFKILL_STATE_SOFT_BLOCKED:
-               if (dev->phy.radio_on)
-                       b43_software_rfkill(dev, state);
-               break;
-       default:
-               b43warn(wl, "Received unexpected rfkill state %d.\n", state);
-               break;
-       }
-out_unlock:
        mutex_unlock(&wl->mutex);
-
-       return err;
-}
-
-char *b43_rfkill_led_name(struct b43_wldev *dev)
-{
-       struct b43_rfkill *rfk = &(dev->wl->rfkill);
-
-       if (!rfk->registered)
-               return NULL;
-       return rfkill_get_led_name(rfk->rfkill);
-}
-
-void b43_rfkill_init(struct b43_wldev *dev)
-{
-       struct b43_wl *wl = dev->wl;
-       struct b43_rfkill *rfk = &(wl->rfkill);
-       int err;
-
-       rfk->registered = 0;
-
-       rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
-       if (!rfk->rfkill)
-               goto out_error;
-       snprintf(rfk->name, sizeof(rfk->name),
-                "b43-%s", wiphy_name(wl->hw->wiphy));
-       rfk->rfkill->name = rfk->name;
-       rfk->rfkill->state = RFKILL_STATE_UNBLOCKED;
-       rfk->rfkill->data = dev;
-       rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle;
-
-       rfk->poll_dev = input_allocate_polled_device();
-       if (!rfk->poll_dev) {
-               rfkill_free(rfk->rfkill);
-               goto err_freed_rfk;
-       }
-
-       rfk->poll_dev->private = dev;
-       rfk->poll_dev->poll = b43_rfkill_poll;
-       rfk->poll_dev->poll_interval = 1000; /* msecs */
-
-       rfk->poll_dev->input->name = rfk->name;
-       rfk->poll_dev->input->id.bustype = BUS_HOST;
-       rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor;
-       rfk->poll_dev->input->evbit[0] = BIT(EV_KEY);
-       set_bit(KEY_WLAN, rfk->poll_dev->input->keybit);
-
-       err = rfkill_register(rfk->rfkill);
-       if (err)
-               goto err_free_polldev;
-
-#ifdef CONFIG_RFKILL_INPUT_MODULE
-       /* B43 RF-kill isn't useful without the rfkill-input subsystem.
-        * Try to load the module. */
-       err = request_module("rfkill-input");
-       if (err)
-               b43warn(wl, "Failed to load the rfkill-input module. "
-                       "The built-in radio LED will not work.\n");
-#endif /* CONFIG_RFKILL_INPUT */
-
-#if !defined(CONFIG_RFKILL_INPUT) && !defined(CONFIG_RFKILL_INPUT_MODULE)
-       b43warn(wl, "The rfkill-input subsystem is not available. "
-               "The built-in radio LED will not work.\n");
-#endif
-
-       err = input_register_polled_device(rfk->poll_dev);
-       if (err)
-               goto err_unreg_rfk;
-
-       rfk->registered = 1;
-
-       return;
-err_unreg_rfk:
-       rfkill_unregister(rfk->rfkill);
-err_free_polldev:
-       input_free_polled_device(rfk->poll_dev);
-       rfk->poll_dev = NULL;
-err_freed_rfk:
-       rfk->rfkill = NULL;
-out_error:
-       rfk->registered = 0;
-       b43warn(wl, "RF-kill button init failed\n");
-}
-
-void b43_rfkill_exit(struct b43_wldev *dev)
-{
-       struct b43_rfkill *rfk = &(dev->wl->rfkill);
-
-       if (!rfk->registered)
-               return;
-       rfk->registered = 0;
-
-       input_unregister_polled_device(rfk->poll_dev);
-       rfkill_unregister(rfk->rfkill);
-       input_free_polled_device(rfk->poll_dev);
-       rfk->poll_dev = NULL;
-       rfk->rfkill = NULL;
 }
index adacf93..f046c3c 100644 (file)
@@ -1,52 +1,11 @@
 #ifndef B43_RFKILL_H_
 #define B43_RFKILL_H_
 
+struct ieee80211_hw;
 struct b43_wldev;
 
+void b43_rfkill_poll(struct ieee80211_hw *hw);
 
-#ifdef CONFIG_B43_RFKILL
-
-#include <linux/rfkill.h>
-#include <linux/input-polldev.h>
-
-
-struct b43_rfkill {
-       /* The RFKILL subsystem data structure */
-       struct rfkill *rfkill;
-       /* The poll device for the RFKILL input button */
-       struct input_polled_dev *poll_dev;
-       /* Did initialization succeed? Used for freeing. */
-       bool registered;
-       /* The unique name of this rfkill switch */
-       char name[sizeof("b43-phy4294967295")];
-};
-
-/* The init function returns void, because we are not interested
- * in failing the b43 init process when rfkill init failed. */
-void b43_rfkill_init(struct b43_wldev *dev);
-void b43_rfkill_exit(struct b43_wldev *dev);
-
-char * b43_rfkill_led_name(struct b43_wldev *dev);
-
-
-#else /* CONFIG_B43_RFKILL */
-/* No RFKILL support. */
-
-struct b43_rfkill {
-       /* empty */
-};
-
-static inline void b43_rfkill_init(struct b43_wldev *dev)
-{
-}
-static inline void b43_rfkill_exit(struct b43_wldev *dev)
-{
-}
-static inline char * b43_rfkill_led_name(struct b43_wldev *dev)
-{
-       return NULL;
-}
-
-#endif /* CONFIG_B43_RFKILL */
+bool b43_is_hw_radio_enabled(struct b43_wldev *dev);
 
 #endif /* B43_RFKILL_H_ */
index a63d888..55f36a7 100644 (file)
@@ -118,7 +118,6 @@ u8 b43_plcp_get_ratecode_ofdm(const u8 bitrate)
 void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp,
                           const u16 octets, const u8 bitrate)
 {
-       __le32 *data = &(plcp->data);
        __u8 *raw = plcp->raw;
 
        if (b43_is_ofdm_rate(bitrate)) {
@@ -127,7 +126,7 @@ void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp,
                d = b43_plcp_get_ratecode_ofdm(bitrate);
                B43_WARN_ON(octets & 0xF000);
                d |= (octets << 5);
-               *data = cpu_to_le32(d);
+               plcp->data = cpu_to_le32(d);
        } else {
                u32 plen;
 
@@ -141,7 +140,7 @@ void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp,
                                raw[1] = 0x04;
                } else
                        raw[1] = 0x04;
-               *data |= cpu_to_le32(plen << 16);
+               plcp->data |= cpu_to_le32(plen << 16);
                raw[0] = b43_plcp_get_ratecode_cck(bitrate);
        }
 }
index d4f628a..94a4634 100644 (file)
@@ -42,14 +42,6 @@ config B43LEGACY_LEDS
        depends on B43LEGACY && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = B43LEGACY)
        default y
 
-# RFKILL support
-# This config option automatically enables b43legacy RFKILL support,
-# if it's possible.
-config B43LEGACY_RFKILL
-       bool
-       depends on B43LEGACY && (RFKILL = y || RFKILL = B43LEGACY) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43LEGACY)
-       default y
-
 # This config option automatically enables b43 HW-RNG support,
 # if the HW-RNG core is enabled.
 config B43LEGACY_HWRNG
index 80cdb73..227a77e 100644 (file)
@@ -6,7 +6,7 @@ b43legacy-y                             += radio.o
 b43legacy-y                            += sysfs.o
 b43legacy-y                            += xmit.o
 # b43 RFKILL button support
-b43legacy-$(CONFIG_B43LEGACY_RFKILL)   += rfkill.o
+b43legacy-y                            += rfkill.o
 # b43legacy LED support
 b43legacy-$(CONFIG_B43LEGACY_LEDS)     += leds.o
 # b43legacy debugging
index 19a4b0b..77fda14 100644 (file)
@@ -602,9 +602,6 @@ struct b43legacy_wl {
        char rng_name[30 + 1];
 #endif
 
-       /* The RF-kill button */
-       struct b43legacy_rfkill rfkill;
-
        /* List of all wireless devices on this chip */
        struct list_head devlist;
        u8 nr_devs;
index 3ea55b1..37e9be8 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "b43legacy.h"
 #include "leds.h"
+#include "rfkill.h"
 
 
 static void b43legacy_led_turn_on(struct b43legacy_wldev *dev, u8 led_index,
@@ -86,7 +87,8 @@ static void b43legacy_led_brightness_set(struct led_classdev *led_dev,
 
 static int b43legacy_register_led(struct b43legacy_wldev *dev,
                                  struct b43legacy_led *led,
-                                 const char *name, char *default_trigger,
+                                 const char *name,
+                                 const char *default_trigger,
                                  u8 led_index, bool activelow)
 {
        int err;
@@ -163,10 +165,10 @@ static void b43legacy_map_led(struct b43legacy_wldev *dev,
                snprintf(name, sizeof(name),
                         "b43legacy-%s::radio", wiphy_name(hw->wiphy));
                b43legacy_register_led(dev, &dev->led_radio, name,
-                                b43legacy_rfkill_led_name(dev),
+                                ieee80211_get_radio_led_name(hw),
                                 led_index, activelow);
-               /* Sync the RF-kill LED state with the switch state. */
-               if (dev->radio_hw_enable)
+               /* Sync the RF-kill LED state with radio and switch states. */
+               if (dev->phy.radio_on && b43legacy_is_hw_radio_enabled(dev))
                        b43legacy_led_turn_on(dev, led_index, activelow);
                break;
        case B43legacy_LED_WEIRD:
index f6f3fbf..e5136fb 100644 (file)
@@ -3431,11 +3431,6 @@ static int b43legacy_op_start(struct ieee80211_hw *hw)
        struct b43legacy_wldev *dev = wl->current_dev;
        int did_init = 0;
        int err = 0;
-       bool do_rfkill_exit = 0;
-
-       /* First register RFkill.
-        * LEDs that are registered later depend on it. */
-       b43legacy_rfkill_init(dev);
 
        /* Kill all old instance specific information to make sure
         * the card won't use it in the short timeframe between start
@@ -3451,10 +3446,8 @@ static int b43legacy_op_start(struct ieee80211_hw *hw)
 
        if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
                err = b43legacy_wireless_core_init(dev);
-               if (err) {
-                       do_rfkill_exit = 1;
+               if (err)
                        goto out_mutex_unlock;
-               }
                did_init = 1;
        }
 
@@ -3463,17 +3456,15 @@ static int b43legacy_op_start(struct ieee80211_hw *hw)
                if (err) {
                        if (did_init)
                                b43legacy_wireless_core_exit(dev);
-                       do_rfkill_exit = 1;
                        goto out_mutex_unlock;
                }
        }
 
+       wiphy_rfkill_start_polling(hw->wiphy);
+
 out_mutex_unlock:
        mutex_unlock(&wl->mutex);
 
-       if (do_rfkill_exit)
-               b43legacy_rfkill_exit(dev);
-
        return err;
 }
 
@@ -3482,7 +3473,6 @@ static void b43legacy_op_stop(struct ieee80211_hw *hw)
        struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
        struct b43legacy_wldev *dev = wl->current_dev;
 
-       b43legacy_rfkill_exit(dev);
        cancel_work_sync(&(wl->beacon_update_trigger));
 
        mutex_lock(&wl->mutex);
@@ -3518,6 +3508,7 @@ static const struct ieee80211_ops b43legacy_hw_ops = {
        .start                  = b43legacy_op_start,
        .stop                   = b43legacy_op_stop,
        .set_tim                = b43legacy_op_beacon_set_tim,
+       .rfkill_poll            = b43legacy_rfkill_poll,
 };
 
 /* Hard-reset the chip. Do not call this directly.
index 4b0c7d2..8783022 100644 (file)
 
 */
 
-#include "rfkill.h"
 #include "radio.h"
 #include "b43legacy.h"
 
-#include <linux/kmod.h>
-
 
 /* Returns TRUE, if the radio is enabled in hardware. */
-static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev)
+bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev)
 {
        if (dev->phy.rev >= 3) {
                if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI)
@@ -45,164 +42,43 @@ static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev)
 }
 
 /* The poll callback for the hardware button. */
-static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev)
+void b43legacy_rfkill_poll(struct ieee80211_hw *hw)
 {
-       struct b43legacy_wldev *dev = poll_dev->private;
-       struct b43legacy_wl *wl = dev->wl;
+       struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+       struct b43legacy_wldev *dev = wl->current_dev;
+       struct ssb_bus *bus = dev->dev->bus;
        bool enabled;
-       bool report_change = 0;
+       bool brought_up = false;
 
        mutex_lock(&wl->mutex);
        if (unlikely(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)) {
-               mutex_unlock(&wl->mutex);
-               return;
+               if (ssb_bus_powerup(bus, 0)) {
+                       mutex_unlock(&wl->mutex);
+                       return;
+               }
+               ssb_device_enable(dev->dev, 0);
+               brought_up = true;
        }
+
        enabled = b43legacy_is_hw_radio_enabled(dev);
+
        if (unlikely(enabled != dev->radio_hw_enable)) {
                dev->radio_hw_enable = enabled;
-               report_change = 1;
                b43legacyinfo(wl, "Radio hardware status changed to %s\n",
                        enabled ? "ENABLED" : "DISABLED");
-       }
-       mutex_unlock(&wl->mutex);
-
-       /* send the radio switch event to the system - note both a key press
-        * and a release are required */
-       if (unlikely(report_change)) {
-               input_report_key(poll_dev->input, KEY_WLAN, 1);
-               input_report_key(poll_dev->input, KEY_WLAN, 0);
-       }
-}
-
-/* Called when the RFKILL toggled in software.
- * This is called without locking. */
-static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state)
-{
-       struct b43legacy_wldev *dev = data;
-       struct b43legacy_wl *wl = dev->wl;
-       int err = -EBUSY;
-
-       if (!wl->rfkill.registered)
-               return 0;
-
-       mutex_lock(&wl->mutex);
-       if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)
-               goto out_unlock;
-       err = 0;
-       switch (state) {
-       case RFKILL_STATE_UNBLOCKED:
-               if (!dev->radio_hw_enable) {
-                       /* No luck. We can't toggle the hardware RF-kill
-                        * button from software. */
-                       err = -EBUSY;
-                       goto out_unlock;
+               wiphy_rfkill_set_hw_state(hw->wiphy, !enabled);
+               if (enabled != dev->phy.radio_on) {
+                       if (enabled)
+                               b43legacy_radio_turn_on(dev);
+                       else
+                               b43legacy_radio_turn_off(dev, 0);
                }
-               if (!dev->phy.radio_on)
-                       b43legacy_radio_turn_on(dev);
-               break;
-       case RFKILL_STATE_SOFT_BLOCKED:
-               if (dev->phy.radio_on)
-                       b43legacy_radio_turn_off(dev, 0);
-               break;
-       default:
-               b43legacywarn(wl, "Received unexpected rfkill state %d.\n",
-                             state);
-               break;
        }
 
-out_unlock:
-       mutex_unlock(&wl->mutex);
-
-       return err;
-}
-
-char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev)
-{
-       struct b43legacy_rfkill *rfk = &(dev->wl->rfkill);
-
-       if (!rfk->registered)
-               return NULL;
-       return rfkill_get_led_name(rfk->rfkill);
-}
-
-void b43legacy_rfkill_init(struct b43legacy_wldev *dev)
-{
-       struct b43legacy_wl *wl = dev->wl;
-       struct b43legacy_rfkill *rfk = &(wl->rfkill);
-       int err;
-
-       rfk->registered = 0;
-
-       rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
-       if (!rfk->rfkill)
-               goto out_error;
-       snprintf(rfk->name, sizeof(rfk->name),
-                "b43legacy-%s", wiphy_name(wl->hw->wiphy));
-       rfk->rfkill->name = rfk->name;
-       rfk->rfkill->state = RFKILL_STATE_UNBLOCKED;
-       rfk->rfkill->data = dev;
-       rfk->rfkill->toggle_radio = b43legacy_rfkill_soft_toggle;
-
-       rfk->poll_dev = input_allocate_polled_device();
-       if (!rfk->poll_dev) {
-               rfkill_free(rfk->rfkill);
-               goto err_freed_rfk;
+       if (brought_up) {
+               ssb_device_disable(dev->dev, 0);
+               ssb_bus_may_powerdown(bus);
        }
 
-       rfk->poll_dev->private = dev;
-       rfk->poll_dev->poll = b43legacy_rfkill_poll;
-       rfk->poll_dev->poll_interval = 1000; /* msecs */
-
-       rfk->poll_dev->input->name = rfk->name;
-       rfk->poll_dev->input->id.bustype = BUS_HOST;
-       rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor;
-       rfk->poll_dev->input->evbit[0] = BIT(EV_KEY);
-       set_bit(KEY_WLAN, rfk->poll_dev->input->keybit);
-
-       err = rfkill_register(rfk->rfkill);
-       if (err)
-               goto err_free_polldev;
-
-#ifdef CONFIG_RFKILL_INPUT_MODULE
-       /* B43legacy RF-kill isn't useful without the rfkill-input subsystem.
-        * Try to load the module. */
-       err = request_module("rfkill-input");
-       if (err)
-               b43legacywarn(wl, "Failed to load the rfkill-input module."
-                       "The built-in radio LED will not work.\n");
-#endif /* CONFIG_RFKILL_INPUT */
-
-       err = input_register_polled_device(rfk->poll_dev);
-       if (err)
-               goto err_unreg_rfk;
-
-       rfk->registered = 1;
-
-       return;
-err_unreg_rfk:
-       rfkill_unregister(rfk->rfkill);
-err_free_polldev:
-       input_free_polled_device(rfk->poll_dev);
-       rfk->poll_dev = NULL;
-err_freed_rfk:
-       rfk->rfkill = NULL;
-out_error:
-       rfk->registered = 0;
-       b43legacywarn(wl, "RF-kill button init failed\n");
-}
-
-void b43legacy_rfkill_exit(struct b43legacy_wldev *dev)
-{
-       struct b43legacy_rfkill *rfk = &(dev->wl->rfkill);
-
-       if (!rfk->registered)
-               return;
-       rfk->registered = 0;
-
-       input_unregister_polled_device(rfk->poll_dev);
-       rfkill_unregister(rfk->rfkill);
-       input_free_polled_device(rfk->poll_dev);
-       rfk->poll_dev = NULL;
-       rfk->rfkill = NULL;
+       mutex_unlock(&wl->mutex);
 }
-
index 11150a8..7558557 100644 (file)
@@ -1,59 +1,11 @@
 #ifndef B43legacy_RFKILL_H_
 #define B43legacy_RFKILL_H_
 
+struct ieee80211_hw;
 struct b43legacy_wldev;
 
-#ifdef CONFIG_B43LEGACY_RFKILL
+void b43legacy_rfkill_poll(struct ieee80211_hw *hw);
 
-#include <linux/rfkill.h>
-#include <linux/workqueue.h>
-#include <linux/input-polldev.h>
-
-
-
-struct b43legacy_rfkill {
-       /* The RFKILL subsystem data structure */
-       struct rfkill *rfkill;
-       /* The poll device for the RFKILL input button */
-       struct input_polled_dev *poll_dev;
-       /* Did initialization succeed? Used for freeing. */
-       bool registered;
-       /* The unique name of this rfkill switch */
-       char name[sizeof("b43legacy-phy4294967295")];
-};
-
-/* The init function returns void, because we are not interested
- * in failing the b43 init process when rfkill init failed. */
-void b43legacy_rfkill_init(struct b43legacy_wldev *dev);
-void b43legacy_rfkill_exit(struct b43legacy_wldev *dev);
-
-char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev);
-
-
-#else /* CONFIG_B43LEGACY_RFKILL */
-/* No RFKILL support. */
-
-struct b43legacy_rfkill {
-       /* empty */
-};
-
-static inline void b43legacy_rfkill_alloc(struct b43legacy_wldev *dev)
-{
-}
-static inline void b43legacy_rfkill_free(struct b43legacy_wldev *dev)
-{
-}
-static inline void b43legacy_rfkill_init(struct b43legacy_wldev *dev)
-{
-}
-static inline void b43legacy_rfkill_exit(struct b43legacy_wldev *dev)
-{
-}
-static inline char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev)
-{
-       return NULL;
-}
-
-#endif /* CONFIG_B43LEGACY_RFKILL */
+bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev);
 
 #endif /* B43legacy_RFKILL_H_ */
index 8304f64..029ccb6 100644 (file)
@@ -5,16 +5,11 @@ config IWLWIFI
        select FW_LOADER
        select MAC80211_LEDS if IWLWIFI_LEDS
        select LEDS_CLASS if IWLWIFI_LEDS
-       select RFKILL if IWLWIFI_RFKILL
 
 config IWLWIFI_LEDS
        bool "Enable LED support in iwlagn and iwl3945 drivers"
        depends on IWLWIFI
 
-config IWLWIFI_RFKILL
-       bool "Enable RF kill support in iwlagn and iwl3945 drivers"
-       depends on IWLWIFI
-
 config IWLWIFI_SPECTRUM_MEASUREMENT
        bool "Enable Spectrum Measurement in iwlagn driver"
        depends on IWLWIFI
index d79d97a..1d4e0a2 100644 (file)
@@ -4,7 +4,6 @@ iwlcore-objs            += iwl-rx.o iwl-tx.o iwl-sta.o iwl-calib.o
 iwlcore-objs           += iwl-scan.o
 iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
 iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o
-iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o
 iwlcore-$(CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT) += iwl-spectrum.o
 
 obj-$(CONFIG_IWLAGN)   += iwlagn.o
index bd7e520..225e5f8 100644 (file)
@@ -167,10 +167,6 @@ static int iwl3945_led_disassociate(struct iwl_priv *priv, int led_id)
        IWL_DEBUG_LED(priv, "Disassociated\n");
 
        priv->allow_blinking = 0;
-       if (iwl_is_rfkill(priv))
-               iwl3945_led_off(priv, led_id);
-       else
-               iwl3945_led_on(priv, led_id);
 
        return 0;
 }
index 814afaf..5eb538d 100644 (file)
@@ -38,6 +38,7 @@
 
 #include "iwl-commands.h"
 #include "iwl-3945.h"
+#include "iwl-sta.h"
 
 #define RS_NAME "iwl-3945-rs"
 
@@ -714,13 +715,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
 
        if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
            !rs_sta->ibss_sta_added) {
-               u8 sta_id = iwl3945_hw_find_station(priv, hdr->addr1);
+               u8 sta_id = iwl_find_station(priv, hdr->addr1);
 
                if (sta_id == IWL_INVALID_STATION) {
                        IWL_DEBUG_RATE(priv, "LQ: ADD station %pm\n",
                                       hdr->addr1);
-                       sta_id = iwl3945_add_station(priv,
-                                   hdr->addr1, 0, CMD_ASYNC, NULL);
+                       sta_id = iwl_add_station(priv, hdr->addr1, false,
+                               CMD_ASYNC, NULL);
                }
                if (sta_id != IWL_INVALID_STATION)
                        rs_sta->ibss_sta_added = 1;
@@ -975,7 +976,7 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
 
        rcu_read_lock();
 
-       sta = ieee80211_find_sta(hw, priv->stations_39[sta_id].sta.sta.addr);
+       sta = ieee80211_find_sta(hw, priv->stations[sta_id].sta.sta.addr);
        if (!sta) {
                rcu_read_unlock();
                return;
index fd65e1c..46288e7 100644 (file)
@@ -769,35 +769,6 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
        return ;
 }
 
-u8 iwl3945_hw_find_station(struct iwl_priv *priv, const u8 *addr)
-{
-       int i, start = IWL_AP_ID;
-       int ret = IWL_INVALID_STATION;
-       unsigned long flags;
-
-       if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) ||
-           (priv->iw_mode == NL80211_IFTYPE_AP))
-               start = IWL_STA_ID;
-
-       if (is_broadcast_ether_addr(addr))
-               return priv->hw_params.bcast_sta_id;
-
-       spin_lock_irqsave(&priv->sta_lock, flags);
-       for (i = start; i < priv->hw_params.max_stations; i++)
-               if ((priv->stations_39[i].used) &&
-                   (!compare_ether_addr
-                    (priv->stations_39[i].sta.sta.addr, addr))) {
-                       ret = i;
-                       goto out;
-               }
-
-       IWL_DEBUG_INFO(priv, "can not find STA %pM (total %d)\n",
-                      addr, priv->num_stations);
- out:
-       spin_unlock_irqrestore(&priv->sta_lock, flags);
-       return ret;
-}
-
 /**
  * iwl3945_hw_build_tx_cmd_rate - Add rate portion to TX_CMD:
  *
@@ -875,13 +846,13 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd,
 u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags)
 {
        unsigned long flags_spin;
-       struct iwl3945_station_entry *station;
+       struct iwl_station_entry *station;
 
        if (sta_id == IWL_INVALID_STATION)
                return IWL_INVALID_STATION;
 
        spin_lock_irqsave(&priv->sta_lock, flags_spin);
-       station = &priv->stations_39[sta_id];
+       station = &priv->stations[sta_id];
 
        station->sta.sta.modify_mask = STA_MODIFY_TX_RATE_MSK;
        station->sta.rate_n_flags = cpu_to_le16(tx_rate);
@@ -889,8 +860,7 @@ u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags)
 
        spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
 
-       iwl_send_add_sta(priv,
-                        (struct iwl_addsta_cmd *)&station->sta, flags);
+       iwl_send_add_sta(priv, &station->sta, flags);
        IWL_DEBUG_RATE(priv, "SCALE sync station %d to rate %d\n",
                        sta_id, tx_rate);
        return sta_id;
@@ -2029,7 +1999,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
 
        memcpy(active_rxon, staging_rxon, sizeof(*active_rxon));
 
-       priv->cfg->ops->smgmt->clear_station_table(priv);
+       iwl_clear_stations_table(priv);
 
        /* If we issue a new RXON command which required a tune then we must
         * send a new TXPOWER command or we won't be able to Tx any frames */
@@ -2040,7 +2010,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
        }
 
        /* Add the broadcast address so we can send broadcast frames */
-       if (priv->cfg->ops->smgmt->add_station(priv, iwl_bcast_addr, 0, 0, NULL) ==
+       if (iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL) ==
            IWL_INVALID_STATION) {
                IWL_ERR(priv, "Error adding BROADCAST address for transmit.\n");
                return -EIO;
@@ -2050,9 +2020,8 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
         * add the IWL_AP_ID to the station rate table */
        if (iwl_is_associated(priv) &&
            (priv->iw_mode == NL80211_IFTYPE_STATION))
-               if (priv->cfg->ops->smgmt->add_station(priv,
-                                       priv->active_rxon.bssid_addr, 1, 0, NULL)
-                   == IWL_INVALID_STATION) {
+               if (iwl_add_station(priv, priv->active_rxon.bssid_addr,
+                               true, CMD_SYNC, NULL) == IWL_INVALID_STATION) {
                        IWL_ERR(priv, "Error adding AP address for transmit\n");
                        return -EIO;
                }
@@ -2466,13 +2435,25 @@ static u16 iwl3945_get_hcmd_size(u8 cmd_id, u16 len)
        }
 }
 
+
 static u16 iwl3945_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
 {
-       u16 size = (u16)sizeof(struct iwl3945_addsta_cmd);
-       memcpy(data, cmd, size);
-       return size;
+       struct iwl3945_addsta_cmd *addsta = (struct iwl3945_addsta_cmd *)data;
+       addsta->mode = cmd->mode;
+       memcpy(&addsta->sta, &cmd->sta, sizeof(struct sta_id_modify));
+       memcpy(&addsta->key, &cmd->key, sizeof(struct iwl4965_keyinfo));
+       addsta->station_flags = cmd->station_flags;
+       addsta->station_flags_msk = cmd->station_flags_msk;
+       addsta->tid_disable_tx = cpu_to_le16(0);
+       addsta->rate_n_flags = cmd->rate_n_flags;
+       addsta->add_immediate_ba_tid = cmd->add_immediate_ba_tid;
+       addsta->remove_immediate_ba_tid = cmd->remove_immediate_ba_tid;
+       addsta->add_immediate_ba_ssn = cmd->add_immediate_ba_ssn;
+
+       return (u16)sizeof(struct iwl3945_addsta_cmd);
 }
 
+
 /**
  * iwl3945_init_hw_rate_table - Initialize the hardware rate fallback table
  */
@@ -2842,15 +2823,6 @@ static struct iwl_lib_ops iwl3945_lib = {
        .config_ap = iwl3945_config_ap,
 };
 
-static struct iwl_station_mgmt_ops iwl3945_station_mgmt = {
-       .add_station = iwl3945_add_station,
-#if 0
-       .remove_station = iwl3945_remove_station,
-#endif
-       .find_station = iwl3945_hw_find_station,
-       .clear_station_table = iwl3945_clear_stations_table,
-};
-
 static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
        .get_hcmd_size = iwl3945_get_hcmd_size,
        .build_addsta_hcmd = iwl3945_build_addsta_hcmd,
@@ -2860,7 +2832,6 @@ static struct iwl_ops iwl3945_ops = {
        .lib = &iwl3945_lib,
        .hcmd = &iwl3945_hcmd,
        .utils = &iwl3945_hcmd_utils,
-       .smgmt = &iwl3945_station_mgmt,
 };
 
 static struct iwl_cfg iwl3945_bg_cfg = {
index da87528..fbb3a57 100644 (file)
 #include <linux/kernel.h>
 #include <net/ieee80211_radiotap.h>
 
-/*used for rfkill*/
-#include <linux/rfkill.h>
-#include <linux/input.h>
-
 /* Hardware specific file defines the PCI IDs table for that hardware module */
 extern struct pci_device_id iwl3945_hw_card_ids[];
 
@@ -155,7 +151,6 @@ struct iwl3945_frame {
 #define STATUS_HCMD_SYNC_ACTIVE        1       /* sync host command in progress */
 #define STATUS_INT_ENABLED     2
 #define STATUS_RF_KILL_HW      3
-#define STATUS_RF_KILL_SW      4
 #define STATUS_INIT            5
 #define STATUS_ALIVE           6
 #define STATUS_READY           7
@@ -202,12 +197,6 @@ struct iwl3945_ibss_seq {
  * for use by iwl-*.c
  *
  *****************************************************************************/
-struct iwl3945_addsta_cmd;
-extern int iwl3945_send_add_station(struct iwl_priv *priv,
-                               struct iwl3945_addsta_cmd *sta, u8 flags);
-extern u8 iwl3945_add_station(struct iwl_priv *priv, const u8 *bssid,
-                         int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info);
-extern void iwl3945_clear_stations_table(struct iwl_priv *priv);
 extern int iwl3945_power_init_handle(struct iwl_priv *priv);
 extern int iwl3945_eeprom_init(struct iwl_priv *priv);
 extern int iwl3945_calc_db_from_ratio(int sig_ratio);
index a0b2941..8f3d4bc 100644 (file)
@@ -2221,13 +2221,6 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv)
        cancel_work_sync(&priv->txpower_work);
 }
 
-static struct iwl_station_mgmt_ops iwl4965_station_mgmt = {
-       .add_station = iwl_add_station_flags,
-       .remove_station = iwl_remove_station,
-       .find_station = iwl_find_station,
-       .clear_station_table = iwl_clear_stations_table,
-};
-
 static struct iwl_hcmd_ops iwl4965_hcmd = {
        .rxon_assoc = iwl4965_send_rxon_assoc,
        .commit_rxon = iwl_commit_rxon,
@@ -2297,7 +2290,6 @@ static struct iwl_ops iwl4965_ops = {
        .lib = &iwl4965_lib,
        .hcmd = &iwl4965_hcmd,
        .utils = &iwl4965_hcmd_utils,
-       .smgmt = &iwl4965_station_mgmt,
 };
 
 struct iwl_cfg iwl4965_agn_cfg = {
index ab29aab..b3c648c 100644 (file)
@@ -651,7 +651,7 @@ static void iwl5000_init_alive_start(struct iwl_priv *priv)
                goto restart;
        }
 
-       priv->cfg->ops->smgmt->clear_station_table(priv);
+       iwl_clear_stations_table(priv);
        ret = priv->cfg->ops->lib->alive_notify(priv);
        if (ret) {
                IWL_WARN(priv,
@@ -1049,7 +1049,10 @@ static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
 u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
 {
        u16 size = (u16)sizeof(struct iwl_addsta_cmd);
-       memcpy(data, cmd, size);
+       struct iwl_addsta_cmd *addsta = (struct iwl_addsta_cmd *)data;
+       memcpy(addsta, cmd, size);
+       /* resrved in 5000 */
+       addsta->rate_n_flags = cpu_to_le16(0);
        return size;
 }
 
@@ -1423,13 +1426,6 @@ int iwl5000_calc_rssi(struct iwl_priv *priv,
        return max_rssi - agc - IWL49_RSSI_OFFSET;
 }
 
-struct iwl_station_mgmt_ops iwl5000_station_mgmt = {
-       .add_station = iwl_add_station_flags,
-       .remove_station = iwl_remove_station,
-       .find_station = iwl_find_station,
-       .clear_station_table = iwl_clear_stations_table,
-};
-
 struct iwl_hcmd_ops iwl5000_hcmd = {
        .rxon_assoc = iwl5000_send_rxon_assoc,
        .commit_rxon = iwl_commit_rxon,
@@ -1549,14 +1545,12 @@ struct iwl_ops iwl5000_ops = {
        .lib = &iwl5000_lib,
        .hcmd = &iwl5000_hcmd,
        .utils = &iwl5000_hcmd_utils,
-       .smgmt = &iwl5000_station_mgmt,
 };
 
 static struct iwl_ops iwl5150_ops = {
        .lib = &iwl5150_lib,
        .hcmd = &iwl5000_hcmd,
        .utils = &iwl5000_hcmd_utils,
-       .smgmt = &iwl5000_station_mgmt,
 };
 
 struct iwl_mod_params iwl50_mod_params = {
index 7236382..bd438d8 100644 (file)
@@ -72,7 +72,6 @@ static struct iwl_ops iwl6000_ops = {
        .lib = &iwl5000_lib,
        .hcmd = &iwl5000_hcmd,
        .utils = &iwl6000_hcmd_utils,
-       .smgmt = &iwl5000_station_mgmt,
 };
 
 struct iwl_cfg iwl6000_2ag_cfg = {
index 23a58b0..ff20e50 100644 (file)
@@ -2502,15 +2502,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
 
        if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
            !lq_sta->ibss_sta_added) {
-               u8 sta_id = priv->cfg->ops->smgmt->find_station(priv,
-                                                  hdr->addr1);
+               u8 sta_id = iwl_find_station(priv, hdr->addr1);
 
                if (sta_id == IWL_INVALID_STATION) {
                        IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n",
                                       hdr->addr1);
-                       sta_id = priv->cfg->ops->smgmt->add_station(priv,
-                                               hdr->addr1, 0,
-                                               CMD_ASYNC, NULL);
+                       sta_id = iwl_add_station(priv, hdr->addr1,
+                                               false, CMD_ASYNC, NULL);
                }
                if ((sta_id != IWL_INVALID_STATION)) {
                        lq_sta->lq.sta_id = sta_id;
@@ -2598,7 +2596,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
 
        lq_sta->ibss_sta_added = 0;
        if (priv->iw_mode == NL80211_IFTYPE_AP) {
-               u8 sta_id = priv->cfg->ops->smgmt->find_station(priv,
+               u8 sta_id = iwl_find_station(priv,
                                                                sta->addr);
 
                /* for IBSS the call are from tasklet */
@@ -2606,9 +2604,8 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
 
                if (sta_id == IWL_INVALID_STATION) {
                        IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr);
-                       sta_id = priv->cfg->ops->smgmt->add_station(priv,
-                                                       sta->addr, 0,
-                                                       CMD_ASYNC, NULL);
+                       sta_id = iwl_add_station(priv, sta->addr, false,
+                                               CMD_ASYNC, NULL);
                }
                if ((sta_id != IWL_INVALID_STATION)) {
                        lq_sta->lq.sta_id = sta_id;
@@ -2790,9 +2787,10 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv,
                repeat_rate--;
        }
 
-       lq_cmd->agg_params.agg_frame_cnt_limit = 64;
-       lq_cmd->agg_params.agg_dis_start_th = 3;
-       lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000);
+       lq_cmd->agg_params.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_MAX;
+       lq_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
+       lq_cmd->agg_params.agg_time_limit =
+               cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
 }
 
 static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
index 0a5507c..a5637c4 100644 (file)
@@ -188,7 +188,7 @@ int iwl_commit_rxon(struct iwl_priv *priv)
                memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
        }
 
-       priv->cfg->ops->smgmt->clear_station_table(priv);
+       iwl_clear_stations_table(priv);
 
        priv->start_calib = 0;
 
@@ -737,19 +737,13 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
                clear_bit(STATUS_RF_KILL_HW, &priv->status);
 
 
-       if (flags & SW_CARD_DISABLED)
-               set_bit(STATUS_RF_KILL_SW, &priv->status);
-       else
-               clear_bit(STATUS_RF_KILL_SW, &priv->status);
-
        if (!(flags & RXON_CARD_DISABLED))
                iwl_scan_cancel(priv);
 
        if ((test_bit(STATUS_RF_KILL_HW, &status) !=
-            test_bit(STATUS_RF_KILL_HW, &priv->status)) ||
-           (test_bit(STATUS_RF_KILL_SW, &status) !=
-            test_bit(STATUS_RF_KILL_SW, &priv->status)))
-               queue_work(priv->workqueue, &priv->rf_kill);
+            test_bit(STATUS_RF_KILL_HW, &priv->status)))
+               wiphy_rfkill_set_hw_state(priv->hw->wiphy,
+                       test_bit(STATUS_RF_KILL_HW, &priv->status));
        else
                wake_up_interruptible(&priv->wait_command_queue);
 }
@@ -1045,7 +1039,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
                                set_bit(STATUS_RF_KILL_HW, &priv->status);
                        else
                                clear_bit(STATUS_RF_KILL_HW, &priv->status);
-                       queue_work(priv->workqueue, &priv->rf_kill);
+                       wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rf_kill);
                }
 
                handled |= CSR_INT_BIT_RF_KILL;
@@ -1218,7 +1212,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
                                set_bit(STATUS_RF_KILL_HW, &priv->status);
                        else
                                clear_bit(STATUS_RF_KILL_HW, &priv->status);
-                       queue_work(priv->workqueue, &priv->rf_kill);
+                       wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rf_kill);
                }
 
                handled |= CSR_INT_BIT_RF_KILL;
@@ -1617,7 +1611,7 @@ static void iwl_alive_start(struct iwl_priv *priv)
                goto restart;
        }
 
-       priv->cfg->ops->smgmt->clear_station_table(priv);
+       iwl_clear_stations_table(priv);
        ret = priv->cfg->ops->lib->alive_notify(priv);
        if (ret) {
                IWL_WARN(priv,
@@ -1703,7 +1697,7 @@ static void __iwl_down(struct iwl_priv *priv)
 
        iwl_leds_unregister(priv);
 
-       priv->cfg->ops->smgmt->clear_station_table(priv);
+       iwl_clear_stations_table(priv);
 
        /* Unblock any waiting calls */
        wake_up_interruptible_all(&priv->wait_command_queue);
@@ -1726,12 +1720,10 @@ static void __iwl_down(struct iwl_priv *priv)
                ieee80211_stop_queues(priv->hw);
 
        /* If we have not previously called iwl_init() then
-        * clear all bits but the RF Kill bits and return */
+        * clear all bits but the RF Kill bit and return */
        if (!iwl_is_init(priv)) {
                priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) <<
                                        STATUS_RF_KILL_HW |
-                              test_bit(STATUS_RF_KILL_SW, &priv->status) <<
-                                       STATUS_RF_KILL_SW |
                               test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
                                        STATUS_GEO_CONFIGURED |
                               test_bit(STATUS_EXIT_PENDING, &priv->status) <<
@@ -1740,11 +1732,9 @@ static void __iwl_down(struct iwl_priv *priv)
        }
 
        /* ...otherwise clear out all the status bits but the RF Kill
-        * bits and continue taking the NIC down. */
+        * bit and continue taking the NIC down. */
        priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) <<
                                STATUS_RF_KILL_HW |
-                       test_bit(STATUS_RF_KILL_SW, &priv->status) <<
-                               STATUS_RF_KILL_SW |
                        test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
                                STATUS_GEO_CONFIGURED |
                        test_bit(STATUS_FW_ERROR, &priv->status) <<
@@ -1866,9 +1856,10 @@ static int __iwl_up(struct iwl_priv *priv)
                set_bit(STATUS_RF_KILL_HW, &priv->status);
 
        if (iwl_is_rfkill(priv)) {
+               wiphy_rfkill_set_hw_state(priv->hw->wiphy, true);
+
                iwl_enable_interrupts(priv);
-               IWL_WARN(priv, "Radio disabled by %s RF Kill switch\n",
-                   test_bit(STATUS_RF_KILL_HW, &priv->status) ? "HW" : "SW");
+               IWL_WARN(priv, "Radio disabled by HW RF Kill switch\n");
                return 0;
        }
 
@@ -1887,8 +1878,6 @@ static int __iwl_up(struct iwl_priv *priv)
 
        /* clear (again), then enable host interrupts */
        iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
-       /* enable dram interrupt */
-       iwl_reset_ict(priv);
        iwl_enable_interrupts(priv);
 
        /* really make sure rfkill handshake bits are cleared */
@@ -1903,7 +1892,7 @@ static int __iwl_up(struct iwl_priv *priv)
 
        for (i = 0; i < MAX_HW_RESTARTS; i++) {
 
-               priv->cfg->ops->smgmt->clear_station_table(priv);
+               iwl_clear_stations_table(priv);
 
                /* load bootstrap state machine,
                 * load bootstrap program into processor's memory,
@@ -1962,6 +1951,9 @@ static void iwl_bg_alive_start(struct work_struct *data)
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
+       /* enable dram interrupt */
+       iwl_reset_ict(priv);
+
        mutex_lock(&priv->mutex);
        iwl_alive_start(priv);
        mutex_unlock(&priv->mutex);
@@ -2000,7 +1992,6 @@ static void iwl_bg_up(struct work_struct *data)
        mutex_lock(&priv->mutex);
        __iwl_up(priv);
        mutex_unlock(&priv->mutex);
-       iwl_rfkill_set_hw_state(priv);
 }
 
 static void iwl_bg_restart(struct work_struct *data)
@@ -2178,8 +2169,6 @@ static int iwl_mac_start(struct ieee80211_hw *hw)
 
        mutex_unlock(&priv->mutex);
 
-       iwl_rfkill_set_hw_state(priv);
-
        if (ret)
                return ret;
 
@@ -2348,7 +2337,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                return -EOPNOTSUPP;
        }
        addr = sta ? sta->addr : iwl_bcast_addr;
-       sta_id = priv->cfg->ops->smgmt->find_station(priv, addr);
+       sta_id = iwl_find_station(priv, addr);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
                                   addr);
@@ -2774,7 +2763,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
        INIT_WORK(&priv->up, iwl_bg_up);
        INIT_WORK(&priv->restart, iwl_bg_restart);
        INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish);
-       INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill);
        INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
        INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
        INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
@@ -3045,12 +3033,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        else
                set_bit(STATUS_RF_KILL_HW, &priv->status);
 
-       err = iwl_rfkill_init(priv);
-       if (err)
-               IWL_ERR(priv, "Unable to initialize RFKILL system. "
-                                 "Ignoring error: %d\n", err);
-       else
-               iwl_rfkill_set_hw_state(priv);
+       wiphy_rfkill_set_hw_state(priv->hw->wiphy,
+               test_bit(STATUS_RF_KILL_HW, &priv->status));
 
        iwl_power_initialize(priv);
        return 0;
@@ -3114,14 +3098,13 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
 
        iwl_synchronize_irq(priv);
 
-       iwl_rfkill_unregister(priv);
        iwl_dealloc_ucode_pci(priv);
 
        if (priv->rxq.bd)
                iwl_rx_queue_free(priv, &priv->rxq);
        iwl_hw_txq_ctx_free(priv);
 
-       priv->cfg->ops->smgmt->clear_station_table(priv);
+       iwl_clear_stations_table(priv);
        iwl_eeprom_free(priv);
 
 
index e581dc3..c87033b 100644 (file)
@@ -1067,7 +1067,7 @@ struct iwl_addsta_cmd {
         * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */
        __le16 tid_disable_tx;
 
-       __le16  reserved1;
+       __le16  rate_n_flags;           /* 3945 only */
 
        /* TID for which to add block-ack support.
         * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
@@ -1913,6 +1913,18 @@ struct iwl_link_qual_general_params {
        u8 start_rate_index[LINK_QUAL_AC_NUM];
 } __attribute__ ((packed));
 
+#define LINK_QUAL_AGG_TIME_LIMIT_DEF   (4000) /* 4 milliseconds */
+#define LINK_QUAL_AGG_TIME_LIMIT_MAX   (65535)
+#define LINK_QUAL_AGG_TIME_LIMIT_MIN   (0)
+
+#define LINK_QUAL_AGG_DISABLE_START_DEF        (3)
+#define LINK_QUAL_AGG_DISABLE_START_MAX        (255)
+#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_MIN  (0)
+
 /**
  * struct iwl_link_qual_agg_params
  *
index e93ddb7..f9d16ca 100644 (file)
@@ -36,7 +36,6 @@
 #include "iwl-debug.h"
 #include "iwl-core.h"
 #include "iwl-io.h"
-#include "iwl-rfkill.h"
 #include "iwl-power.h"
 #include "iwl-sta.h"
 #include "iwl-helpers.h"
@@ -1389,7 +1388,7 @@ int iwl_init_drv(struct iwl_priv *priv)
        mutex_init(&priv->mutex);
 
        /* Clear the driver's (not device's) station table */
-       priv->cfg->ops->smgmt->clear_station_table(priv);
+       iwl_clear_stations_table(priv);
 
        priv->data_retry_limit = -1;
        priv->ieee_channels = NULL;
@@ -1704,8 +1703,9 @@ static irqreturn_t iwl_isr(int irq, void *data)
 {
        struct iwl_priv *priv = data;
        u32 inta, inta_mask;
+#ifdef CONFIG_IWLWIFI_DEBUG
        u32 inta_fh;
-
+#endif
        if (!priv)
                return IRQ_NONE;
 
@@ -2210,126 +2210,6 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
 }
 EXPORT_SYMBOL(iwl_send_card_state);
 
-void iwl_radio_kill_sw_disable_radio(struct iwl_priv *priv)
-{
-       unsigned long flags;
-
-       if (test_bit(STATUS_RF_KILL_SW, &priv->status))
-               return;
-
-       IWL_DEBUG_RF_KILL(priv, "Manual SW RF KILL set to: RADIO OFF\n");
-
-       iwl_scan_cancel(priv);
-       /* FIXME: This is a workaround for AP */
-       if (priv->iw_mode != NL80211_IFTYPE_AP) {
-               spin_lock_irqsave(&priv->lock, flags);
-               iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
-                           CSR_UCODE_SW_BIT_RFKILL);
-               spin_unlock_irqrestore(&priv->lock, flags);
-               /* call the host command only if no hw rf-kill set */
-               if (!test_bit(STATUS_RF_KILL_HW, &priv->status) &&
-                   iwl_is_ready(priv))
-                       iwl_send_card_state(priv,
-                               CARD_STATE_CMD_DISABLE, 0);
-               set_bit(STATUS_RF_KILL_SW, &priv->status);
-                       /* make sure mac80211 stop sending Tx frame */
-               if (priv->mac80211_registered)
-                       ieee80211_stop_queues(priv->hw);
-       }
-}
-EXPORT_SYMBOL(iwl_radio_kill_sw_disable_radio);
-
-int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv)
-{
-       unsigned long flags;
-
-       if (!test_bit(STATUS_RF_KILL_SW, &priv->status))
-               return 0;
-
-       IWL_DEBUG_RF_KILL(priv, "Manual SW RF KILL set to: RADIO ON\n");
-
-       spin_lock_irqsave(&priv->lock, flags);
-       iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-
-       /* If the driver is up it will receive CARD_STATE_NOTIFICATION
-        * notification where it will clear SW rfkill status.
-        * Setting it here would break the handler. Only if the
-        * interface is down we can set here since we don't
-        * receive any further notification.
-        */
-       if (!priv->is_open)
-               clear_bit(STATUS_RF_KILL_SW, &priv->status);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       /* wake up ucode */
-       msleep(10);
-
-       iwl_read32(priv, CSR_UCODE_DRV_GP1);
-       spin_lock_irqsave(&priv->reg_lock, flags);
-       if (!iwl_grab_nic_access(priv))
-               iwl_release_nic_access(priv);
-       spin_unlock_irqrestore(&priv->reg_lock, flags);
-
-       if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
-               IWL_DEBUG_RF_KILL(priv, "Can not turn radio back on - "
-                                 "disabled by HW switch\n");
-               return 0;
-       }
-
-       /* when driver is up while rfkill is on, it wont receive
-        * any CARD_STATE_NOTIFICATION notifications so we have to
-        * restart it in here
-        */
-       if (priv->is_open && !test_bit(STATUS_ALIVE, &priv->status)) {
-               clear_bit(STATUS_RF_KILL_SW, &priv->status);
-               if (!iwl_is_rfkill(priv))
-                       queue_work(priv->workqueue, &priv->up);
-       }
-
-       /* If the driver is already loaded, it will receive
-        * CARD_STATE_NOTIFICATION notifications and the handler will
-        * call restart to reload the driver.
-        */
-       return 1;
-}
-EXPORT_SYMBOL(iwl_radio_kill_sw_enable_radio);
-
-void iwl_bg_rf_kill(struct work_struct *work)
-{
-       struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill);
-
-       wake_up_interruptible(&priv->wait_command_queue);
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       mutex_lock(&priv->mutex);
-
-       if (!iwl_is_rfkill(priv)) {
-               IWL_DEBUG_RF_KILL(priv,
-                         "HW and/or SW RF Kill no longer active, restarting "
-                         "device\n");
-               if (!test_bit(STATUS_EXIT_PENDING, &priv->status) &&
-                   priv->is_open)
-                       queue_work(priv->workqueue, &priv->restart);
-       } else {
-               /* make sure mac80211 stop sending Tx frame */
-               if (priv->mac80211_registered)
-                       ieee80211_stop_queues(priv->hw);
-
-               if (!test_bit(STATUS_RF_KILL_HW, &priv->status))
-                       IWL_DEBUG_RF_KILL(priv, "Can not turn radio back on - "
-                                         "disabled by SW switch\n");
-               else
-                       IWL_WARN(priv, "Radio Frequency Kill Switch is On:\n"
-                                   "Kill switch must be turned off for "
-                                   "wireless networking to work.\n");
-       }
-       mutex_unlock(&priv->mutex);
-       iwl_rfkill_set_hw_state(priv);
-}
-EXPORT_SYMBOL(iwl_bg_rf_kill);
-
 void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
                           struct iwl_rx_mem_buffer *rxb)
 {
@@ -2679,19 +2559,12 @@ int iwl_set_mode(struct iwl_priv *priv, int mode)
 
        memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
 
-       priv->cfg->ops->smgmt->clear_station_table(priv);
+       iwl_clear_stations_table(priv);
 
        /* dont commit rxon if rf-kill is on*/
        if (!iwl_is_ready_rf(priv))
                return -EAGAIN;
 
-       cancel_delayed_work(&priv->scan_check);
-       if (iwl_scan_cancel_timeout(priv, 100)) {
-               IWL_WARN(priv, "Aborted scan still in progress after 100ms\n");
-               IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n");
-               return -EAGAIN;
-       }
-
        iwlcore_commit_rxon(priv);
 
        return 0;
@@ -2855,23 +2728,6 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
        if (priv->cfg->ops->hcmd->set_rxon_chain)
                priv->cfg->ops->hcmd->set_rxon_chain(priv);
 
-       if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) {
-               if (conf->radio_enabled &&
-                       iwl_radio_kill_sw_enable_radio(priv)) {
-                       IWL_DEBUG_MAC80211(priv, "leave - RF-KILL - "
-                                               "waiting for uCode\n");
-                       goto out;
-               }
-
-               if (!conf->radio_enabled)
-                       iwl_radio_kill_sw_disable_radio(priv);
-       }
-
-       if (!conf->radio_enabled) {
-               IWL_DEBUG_MAC80211(priv, "leave - radio disabled\n");
-               goto out;
-       }
-
        if (!iwl_is_ready(priv)) {
                IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
                goto out;
index 87df1b7..dabf663 100644 (file)
@@ -83,15 +83,6 @@ struct iwl_cmd;
 #define IWL_SKU_A       0x2
 #define IWL_SKU_N       0x8
 
-struct iwl_station_mgmt_ops {
-       u8 (*add_station)(struct iwl_priv *priv, const u8 *addr,
-                       int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info);
-       int (*remove_station)(struct iwl_priv *priv, const u8 *addr,
-                       int is_ap);
-       u8 (*find_station)(struct iwl_priv *priv, const u8 *addr);
-       void (*clear_station_table)(struct iwl_priv *priv);
-};
-
 struct iwl_hcmd_ops {
        int (*rxon_assoc)(struct iwl_priv *priv);
        int (*commit_rxon)(struct iwl_priv *priv);
@@ -183,7 +174,6 @@ struct iwl_ops {
        const struct iwl_lib_ops *lib;
        const struct iwl_hcmd_ops *hcmd;
        const struct iwl_hcmd_utils_ops *utils;
-       const struct iwl_station_mgmt_ops *smgmt;
 };
 
 struct iwl_mod_params {
@@ -192,7 +182,7 @@ struct iwl_mod_params {
        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 */
-       int disable_11n;        /* def: 0 = disable 11n capabilities */
+       int disable_11n;        /* def: 0 = 11n capabilities enabled */
        int amsdu_size_8K;      /* def: 1 = enable 8K amsdu size */
        int antenna;            /* def: 0 = both antennas (use diversity) */
        int restart_fw;         /* def: 1 = restart firmware */
@@ -358,14 +348,6 @@ int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id);
  ****************************************************/
 int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force);
 
-/*****************************************************
- * RF -Kill - here and not in iwl-rfkill.h to be available when
- * RF-kill subsystem is not compiled.
- ****************************************************/
-void iwl_bg_rf_kill(struct work_struct *work);
-void iwl_radio_kill_sw_disable_radio(struct iwl_priv *priv);
-int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv);
-
 /*******************************************************************************
  * Rate
  ******************************************************************************/
@@ -508,7 +490,6 @@ void iwlcore_free_geos(struct iwl_priv *priv);
 #define STATUS_HCMD_SYNC_ACTIVE        1       /* sync host command in progress */
 #define STATUS_INT_ENABLED     2
 #define STATUS_RF_KILL_HW      3
-#define STATUS_RF_KILL_SW      4
 #define STATUS_INIT            5
 #define STATUS_ALIVE           6
 #define STATUS_READY           7
@@ -543,11 +524,6 @@ static inline int iwl_is_init(struct iwl_priv *priv)
        return test_bit(STATUS_INIT, &priv->status);
 }
 
-static inline int iwl_is_rfkill_sw(struct iwl_priv *priv)
-{
-       return test_bit(STATUS_RF_KILL_SW, &priv->status);
-}
-
 static inline int iwl_is_rfkill_hw(struct iwl_priv *priv)
 {
        return test_bit(STATUS_RF_KILL_HW, &priv->status);
@@ -555,7 +531,7 @@ static inline int iwl_is_rfkill_hw(struct iwl_priv *priv)
 
 static inline int iwl_is_rfkill(struct iwl_priv *priv)
 {
-       return iwl_is_rfkill_hw(priv) || iwl_is_rfkill_sw(priv);
+       return iwl_is_rfkill_hw(priv);
 }
 
 static inline int iwl_is_ready_rf(struct iwl_priv *priv)
index af70229..11e08c0 100644 (file)
@@ -449,8 +449,6 @@ static ssize_t iwl_dbgfs_status_read(struct file *file,
                test_bit(STATUS_INT_ENABLED, &priv->status));
        pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n",
                test_bit(STATUS_RF_KILL_HW, &priv->status));
-       pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_SW:\t %d\n",
-               test_bit(STATUS_RF_KILL_SW, &priv->status));
        pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INIT:\t\t %d\n",
                test_bit(STATUS_INIT, &priv->status));
        pos += scnprintf(buf + pos, bufsz - pos, "STATUS_ALIVE:\t\t %d\n",
index 2dafc26..e2d620f 100644 (file)
@@ -41,7 +41,6 @@
 #include "iwl-prph.h"
 #include "iwl-fh.h"
 #include "iwl-debug.h"
-#include "iwl-rfkill.h"
 #include "iwl-4965-hw.h"
 #include "iwl-3945-hw.h"
 #include "iwl-3945-led.h"
@@ -70,7 +69,6 @@ extern struct iwl_ops iwl5000_ops;
 extern struct iwl_lib_ops iwl5000_lib;
 extern struct iwl_hcmd_ops iwl5000_hcmd;
 extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils;
-extern struct iwl_station_mgmt_ops iwl5000_station_mgmt;
 
 /* shared functions from iwl-5000.c */
 extern u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len);
@@ -290,11 +288,11 @@ struct iwl_frame {
 #define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
 
 enum {
-       /* CMD_SIZE_NORMAL = 0, */
+       CMD_SYNC = 0,
+       CMD_SIZE_NORMAL = 0,
+       CMD_NO_SKB = 0,
        CMD_SIZE_HUGE = (1 << 0),
-       /* CMD_SYNC = 0, */
        CMD_ASYNC = (1 << 1),
-       /* CMD_NO_SKB = 0, */
        CMD_WANT_SKB = (1 << 2),
 };
 
@@ -937,9 +935,6 @@ struct iwl_priv {
         * 4965's initialize alive response contains some calibration data. */
        struct iwl_init_alive_resp card_alive_init;
        struct iwl_alive_resp card_alive;
-#if defined(CONFIG_IWLWIFI_RFKILL)
-       struct rfkill *rfkill;
-#endif
 
 #ifdef CONFIG_IWLWIFI_LEDS
        unsigned long last_blink_time;
@@ -1073,7 +1068,6 @@ struct iwl_priv {
        struct work_struct calibrated_work;
        struct work_struct scan_completed;
        struct work_struct rx_replenish;
-       struct work_struct rf_kill;
        struct work_struct abort_scan;
        struct work_struct update_link_led;
        struct work_struct auth_work;
@@ -1119,8 +1113,6 @@ struct iwl_priv {
 
        struct iwl3945_notif_statistics statistics_39;
 
-       struct iwl3945_station_entry stations_39[IWL_STATION_COUNT];
-
        u32 sta_supp_rates;
 }; /*iwl_priv */
 
index cefa501..7d7554a 100644 (file)
@@ -240,13 +240,11 @@ static int iwl_init_otp_access(struct iwl_priv *priv)
        if (ret < 0)
                IWL_ERR(priv, "Time out access OTP\n");
        else {
-               if (!ret) {
-                       iwl_set_bits_prph(priv, APMG_PS_CTRL_REG,
-                                         APMG_PS_CTRL_VAL_RESET_REQ);
-                       udelay(5);
-                       iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG,
-                                           APMG_PS_CTRL_VAL_RESET_REQ);
-               }
+               iwl_set_bits_prph(priv, APMG_PS_CTRL_REG,
+                                 APMG_PS_CTRL_VAL_RESET_REQ);
+               udelay(5);
+               iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG,
+                                   APMG_PS_CTRL_VAL_RESET_REQ);
        }
        return ret;
 }
index 19680f7..5e64252 100644 (file)
@@ -176,10 +176,6 @@ static int iwl_led_associate(struct iwl_priv *priv, int led_id)
 static int iwl_led_disassociate(struct iwl_priv *priv, int led_id)
 {
        priv->allow_blinking = 0;
-       if (iwl_is_rfkill(priv))
-               iwl4965_led_off_reg(priv, led_id);
-       else
-               iwl4965_led_on_reg(priv, led_id);
 
        return 0;
 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c
deleted file mode 100644 (file)
index 65605ad..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2009 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *****************************************************************************/
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <net/mac80211.h>
-
-#include "iwl-eeprom.h"
-#include "iwl-dev.h"
-#include "iwl-core.h"
-
-/* software rf-kill from user */
-static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state)
-{
-       struct iwl_priv *priv = data;
-       int err = 0;
-
-       if (!priv->rfkill)
-               return 0;
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return 0;
-
-       IWL_DEBUG_RF_KILL(priv, "we received soft RFKILL set to state %d\n", state);
-       mutex_lock(&priv->mutex);
-
-       switch (state) {
-       case RFKILL_STATE_UNBLOCKED:
-               if (iwl_is_rfkill_hw(priv)) {
-                       err = -EBUSY;
-                       goto out_unlock;
-               }
-               iwl_radio_kill_sw_enable_radio(priv);
-               break;
-       case RFKILL_STATE_SOFT_BLOCKED:
-               iwl_radio_kill_sw_disable_radio(priv);
-               break;
-       default:
-               IWL_WARN(priv, "we received unexpected RFKILL state %d\n",
-                       state);
-               break;
-       }
-out_unlock:
-       mutex_unlock(&priv->mutex);
-
-       return err;
-}
-
-int iwl_rfkill_init(struct iwl_priv *priv)
-{
-       struct device *device = wiphy_dev(priv->hw->wiphy);
-       int ret = 0;
-
-       BUG_ON(device == NULL);
-
-       IWL_DEBUG_RF_KILL(priv, "Initializing RFKILL.\n");
-       priv->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN);
-       if (!priv->rfkill) {
-               IWL_ERR(priv, "Unable to allocate RFKILL device.\n");
-               ret = -ENOMEM;
-               goto error;
-       }
-
-       priv->rfkill->name = priv->cfg->name;
-       priv->rfkill->data = priv;
-       priv->rfkill->state = RFKILL_STATE_UNBLOCKED;
-       priv->rfkill->toggle_radio = iwl_rfkill_soft_rf_kill;
-
-       priv->rfkill->dev.class->suspend = NULL;
-       priv->rfkill->dev.class->resume = NULL;
-
-       ret = rfkill_register(priv->rfkill);
-       if (ret) {
-               IWL_ERR(priv, "Unable to register RFKILL: %d\n", ret);
-               goto free_rfkill;
-       }
-
-       IWL_DEBUG_RF_KILL(priv, "RFKILL initialization complete.\n");
-       return ret;
-
-free_rfkill:
-       if (priv->rfkill != NULL)
-               rfkill_free(priv->rfkill);
-       priv->rfkill = NULL;
-
-error:
-       IWL_DEBUG_RF_KILL(priv, "RFKILL initialization complete.\n");
-       return ret;
-}
-EXPORT_SYMBOL(iwl_rfkill_init);
-
-void iwl_rfkill_unregister(struct iwl_priv *priv)
-{
-
-       if (priv->rfkill)
-               rfkill_unregister(priv->rfkill);
-
-       priv->rfkill = NULL;
-}
-EXPORT_SYMBOL(iwl_rfkill_unregister);
-
-/* set RFKILL to the right state. */
-void iwl_rfkill_set_hw_state(struct iwl_priv *priv)
-{
-       if (!priv->rfkill)
-               return;
-
-       if (iwl_is_rfkill_hw(priv)) {
-               rfkill_force_state(priv->rfkill, RFKILL_STATE_HARD_BLOCKED);
-               return;
-       }
-
-       if (!iwl_is_rfkill_sw(priv))
-               rfkill_force_state(priv->rfkill, RFKILL_STATE_UNBLOCKED);
-       else
-               rfkill_force_state(priv->rfkill, RFKILL_STATE_SOFT_BLOCKED);
-}
-EXPORT_SYMBOL(iwl_rfkill_set_hw_state);
diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.h b/drivers/net/wireless/iwlwifi/iwl-rfkill.h
deleted file mode 100644 (file)
index 633dafb..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *****************************************************************************/
-#ifndef __iwl_rf_kill_h__
-#define __iwl_rf_kill_h__
-
-struct iwl_priv;
-
-#include <linux/rfkill.h>
-
-#ifdef CONFIG_IWLWIFI_RFKILL
-
-void iwl_rfkill_set_hw_state(struct iwl_priv *priv);
-void iwl_rfkill_unregister(struct iwl_priv *priv);
-int iwl_rfkill_init(struct iwl_priv *priv);
-#else
-static inline void iwl_rfkill_set_hw_state(struct iwl_priv *priv) {}
-static inline void iwl_rfkill_unregister(struct iwl_priv *priv) {}
-static inline int iwl_rfkill_init(struct iwl_priv *priv) { return 0; }
-#endif
-
-
-
-#endif  /* __iwl_rf_kill_h__ */
index 0eb939c..2addf73 100644 (file)
@@ -75,7 +75,7 @@ int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
                return IWL_AP_ID;
        } else {
                u8 *da = ieee80211_get_DA(hdr);
-               return priv->cfg->ops->smgmt->find_station(priv, da);
+               return iwl_find_station(priv, da);
        }
 }
 EXPORT_SYMBOL(iwl_get_ra_sta_id);
@@ -86,8 +86,7 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
 
        spin_lock_irqsave(&priv->sta_lock, flags);
 
-       if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) &&
-           !(priv->stations_39[sta_id].used & IWL_STA_DRIVER_ACTIVE))
+       if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE))
                IWL_ERR(priv, "ACTIVATE a non DRIVER active station %d\n",
                        sta_id);
 
@@ -228,15 +227,16 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
 }
 
 /**
- * iwl_add_station_flags - Add station to tables in driver and device
+ * iwl_add_station - Add station to tables in driver and device
  */
-u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap,
-                        u8 flags, struct ieee80211_sta_ht_cap *ht_info)
+u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags,
+               struct ieee80211_sta_ht_cap *ht_info)
 {
-       int i;
-       int sta_id = IWL_INVALID_STATION;
        struct iwl_station_entry *station;
        unsigned long flags_spin;
+       int i;
+       int sta_id = IWL_INVALID_STATION;
+       u16 rate;
 
        spin_lock_irqsave(&priv->sta_lock, flags_spin);
        if (is_ap)
@@ -288,6 +288,12 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap,
            priv->iw_mode != NL80211_IFTYPE_ADHOC)
                iwl_set_ht_add_station(priv, sta_id, ht_info);
 
+       /* 3945 only */
+       rate = (priv->band == IEEE80211_BAND_5GHZ) ?
+               IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP;
+       /* Turn on both antennas for the station... */
+       station->sta.rate_n_flags = cpu_to_le16(rate | RATE_MCS_ANT_AB_MSK);
+
        spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
 
        /* Add station to device's station table */
@@ -295,12 +301,12 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap,
        return sta_id;
 
 }
-EXPORT_SYMBOL(iwl_add_station_flags);
+EXPORT_SYMBOL(iwl_add_station);
 
 static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
 {
        unsigned long flags;
-       u8 sta_id = priv->cfg->ops->smgmt->find_station(priv, addr);
+       u8 sta_id = iwl_find_station(priv, addr);
 
        BUG_ON(sta_id == IWL_INVALID_STATION);
 
@@ -408,7 +414,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
 /**
  * iwl_remove_station - Remove driver's knowledge of station.
  */
-int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
+int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap)
 {
        int sta_id = IWL_INVALID_STATION;
        int i, ret = -EINVAL;
@@ -767,7 +773,7 @@ void iwl_update_tkip_key(struct iwl_priv *priv,
        unsigned long flags;
        int i;
 
-       sta_id = priv->cfg->ops->smgmt->find_station(priv, addr);
+       sta_id = iwl_find_station(priv, addr);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
                                   addr);
@@ -946,7 +952,7 @@ EXPORT_SYMBOL(iwl_send_lq_cmd);
  *       calling this function (which runs REPLY_TX_LINK_QUALITY_CMD,
  *       which requires station table entry to exist).
  */
-static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap)
+static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, bool is_ap)
 {
        int i, r;
        struct iwl_link_quality_cmd link_cmd = {
@@ -979,8 +985,9 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap)
        link_cmd.general_params.single_stream_ant_msk =
                                first_antenna(priv->hw_params.valid_tx_ant);
        link_cmd.general_params.dual_stream_ant_msk = 3;
-       link_cmd.agg_params.agg_dis_start_th = 3;
-       link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000);
+       link_cmd.agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
+       link_cmd.agg_params.agg_time_limit =
+               cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
 
        /* Update the rate scaling for control frame Tx to AP */
        link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id;
@@ -995,7 +1002,7 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap)
  * there is only one AP station with id= IWL_AP_ID
  * NOTE: mutex must be held before calling this function
  */
-int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
+int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap)
 {
        struct ieee80211_sta *sta;
        struct ieee80211_sta_ht_cap ht_config;
@@ -1020,8 +1027,7 @@ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
                rcu_read_unlock();
        }
 
-       sta_id = priv->cfg->ops->smgmt->add_station(priv, addr, is_ap,
-                                      0, cur_ht_config);
+       sta_id = iwl_add_station(priv, addr, is_ap, CMD_SYNC, cur_ht_config);
 
        /* Set up default rate scaling table in device's station table */
        iwl_sta_init_lq(priv, addr, is_ap);
@@ -1054,7 +1060,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
 
        /* If we are an AP, then find the station, or use BCAST */
        case NL80211_IFTYPE_AP:
-               sta_id = priv->cfg->ops->smgmt->find_station(priv, hdr->addr1);
+               sta_id = iwl_find_station(priv, hdr->addr1);
                if (sta_id != IWL_INVALID_STATION)
                        return sta_id;
                return priv->hw_params.bcast_sta_id;
@@ -1062,13 +1068,13 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
        /* If this frame is going out to an IBSS network, find the station,
         * or create a new station table entry */
        case NL80211_IFTYPE_ADHOC:
-               sta_id = priv->cfg->ops->smgmt->find_station(priv, hdr->addr1);
+               sta_id = iwl_find_station(priv, hdr->addr1);
                if (sta_id != IWL_INVALID_STATION)
                        return sta_id;
 
                /* Create new station table entry */
-               sta_id = priv->cfg->ops->smgmt->add_station(priv, hdr->addr1,
-                                                  0, CMD_ASYNC, NULL);
+               sta_id = iwl_add_station(priv, hdr->addr1, false,
+                                       CMD_ASYNC, NULL);
 
                if (sta_id != IWL_INVALID_STATION)
                        return sta_id;
@@ -1111,7 +1117,7 @@ int iwl_sta_rx_agg_start(struct iwl_priv *priv,
        unsigned long flags;
        int sta_id;
 
-       sta_id = priv->cfg->ops->smgmt->find_station(priv, addr);
+       sta_id = iwl_find_station(priv, addr);
        if (sta_id == IWL_INVALID_STATION)
                return -ENXIO;
 
@@ -1133,7 +1139,7 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid)
        unsigned long flags;
        int sta_id;
 
-       sta_id = priv->cfg->ops->smgmt->find_station(priv, addr);
+       sta_id = iwl_find_station(priv, addr);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid);
                return -ENXIO;
@@ -1168,7 +1174,7 @@ static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
 void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
 {
        /* FIXME: need locking over ps_status ??? */
-       u8 sta_id = priv->cfg->ops->smgmt->find_station(priv, addr);
+       u8 sta_id = iwl_find_station(priv, addr);
 
        if (sta_id != IWL_INVALID_STATION) {
                u8 sta_awake = priv->stations[sta_id].
index 59a586b..6deebad 100644 (file)
@@ -51,16 +51,15 @@ void iwl_update_tkip_key(struct iwl_priv *priv,
                        struct ieee80211_key_conf *keyconf,
                        const u8 *addr, u32 iv32, u16 *phase1key);
 
-int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap);
-int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap);
+int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap);
+int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap);
 void iwl_clear_stations_table(struct iwl_priv *priv);
 int iwl_get_free_ucode_key_index(struct iwl_priv *priv);
 int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
 int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
 int iwl_send_add_sta(struct iwl_priv *priv,
                     struct iwl_addsta_cmd *sta, u8 flags);
-u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr,
-                       int is_ap, u8 flags,
+u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags,
                        struct ieee80211_sta_ht_cap *ht_info);
 void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid);
 int iwl_sta_rx_agg_start(struct iwl_priv *priv,
index 5c10b87..83d3160 100644 (file)
@@ -95,144 +95,6 @@ struct iwl_mod_params iwl3945_mod_params = {
        /* the rest are 0 by default */
 };
 
-/*************** STATION TABLE MANAGEMENT ****
- * mac80211 should be examined to determine if sta_info is duplicating
- * the functionality provided here
- */
-
-/**************************************************************/
-#if 0 /* temporary disable till we add real remove station */
-/**
- * iwl3945_remove_station - Remove driver's knowledge of station.
- *
- * NOTE:  This does not remove station from device's station table.
- */
-static u8 iwl3945_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
-{
-       int index = IWL_INVALID_STATION;
-       int i;
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->sta_lock, flags);
-
-       if (is_ap)
-               index = IWL_AP_ID;
-       else if (is_broadcast_ether_addr(addr))
-               index = priv->hw_params.bcast_sta_id;
-       else
-               for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++)
-                       if (priv->stations_39[i].used &&
-                           !compare_ether_addr(priv->stations_39[i].sta.sta.addr,
-                                               addr)) {
-                               index = i;
-                               break;
-                       }
-
-       if (unlikely(index == IWL_INVALID_STATION))
-               goto out;
-
-       if (priv->stations_39[index].used) {
-               priv->stations_39[index].used = 0;
-               priv->num_stations--;
-       }
-
-       BUG_ON(priv->num_stations < 0);
-
-out:
-       spin_unlock_irqrestore(&priv->sta_lock, flags);
-       return 0;
-}
-#endif
-
-/**
- * iwl3945_clear_stations_table - Clear the driver's station table
- *
- * NOTE:  This does not clear or otherwise alter the device's station table.
- */
-void iwl3945_clear_stations_table(struct iwl_priv *priv)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->sta_lock, flags);
-
-       priv->num_stations = 0;
-       memset(priv->stations_39, 0, sizeof(priv->stations_39));
-
-       spin_unlock_irqrestore(&priv->sta_lock, flags);
-}
-
-/**
- * iwl3945_add_station - Add station to station tables in driver and device
- */
-u8 iwl3945_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info)
-{
-       int i;
-       int index = IWL_INVALID_STATION;
-       struct iwl3945_station_entry *station;
-       unsigned long flags_spin;
-       u8 rate;
-
-       spin_lock_irqsave(&priv->sta_lock, flags_spin);
-       if (is_ap)
-               index = IWL_AP_ID;
-       else if (is_broadcast_ether_addr(addr))
-               index = priv->hw_params.bcast_sta_id;
-       else
-               for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) {
-                       if (!compare_ether_addr(priv->stations_39[i].sta.sta.addr,
-                                               addr)) {
-                               index = i;
-                               break;
-                       }
-
-                       if (!priv->stations_39[i].used &&
-                           index == IWL_INVALID_STATION)
-                               index = i;
-               }
-
-       /* These two conditions has the same outcome but keep them separate
-         since they have different meaning */
-       if (unlikely(index == IWL_INVALID_STATION)) {
-               spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
-               return index;
-       }
-
-       if (priv->stations_39[index].used &&
-          !compare_ether_addr(priv->stations_39[index].sta.sta.addr, addr)) {
-               spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
-               return index;
-       }
-
-       IWL_DEBUG_ASSOC(priv, "Add STA ID %d: %pM\n", index, addr);
-       station = &priv->stations_39[index];
-       station->used = 1;
-       priv->num_stations++;
-
-       /* Set up the REPLY_ADD_STA command to send to device */
-       memset(&station->sta, 0, sizeof(struct iwl3945_addsta_cmd));
-       memcpy(station->sta.sta.addr, addr, ETH_ALEN);
-       station->sta.mode = 0;
-       station->sta.sta.sta_id = index;
-       station->sta.station_flags = 0;
-
-       if (priv->band == IEEE80211_BAND_5GHZ)
-               rate = IWL_RATE_6M_PLCP;
-       else
-               rate =  IWL_RATE_1M_PLCP;
-
-       /* Turn on both antennas for the station... */
-       station->sta.rate_n_flags =
-                       iwl3945_hw_set_rate_n_flags(rate, RATE_MCS_ANT_AB_MSK);
-
-       spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
-
-       /* Add station to device's station table */
-       iwl_send_add_sta(priv,
-                        (struct iwl_addsta_cmd *)&station->sta, flags);
-       return index;
-
-}
-
 /**
  * iwl3945_get_antenna_flags - Get antenna flags for RXON command
  * @priv: eeprom and antenna fields are used to determine antenna flags
@@ -289,32 +151,31 @@ static int iwl3945_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
        key_flags &= ~STA_KEY_FLG_INVALID;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
-       priv->stations_39[sta_id].keyinfo.alg = keyconf->alg;
-       priv->stations_39[sta_id].keyinfo.keylen = keyconf->keylen;
-       memcpy(priv->stations_39[sta_id].keyinfo.key, keyconf->key,
+       priv->stations[sta_id].keyinfo.alg = keyconf->alg;
+       priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
+       memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
               keyconf->keylen);
 
-       memcpy(priv->stations_39[sta_id].sta.key.key, keyconf->key,
+       memcpy(priv->stations[sta_id].sta.key.key, keyconf->key,
               keyconf->keylen);
 
-       if ((priv->stations_39[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
+       if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
                        == STA_KEY_FLG_NO_ENC)
-               priv->stations_39[sta_id].sta.key.key_offset =
+               priv->stations[sta_id].sta.key.key_offset =
                                 iwl_get_free_ucode_key_index(priv);
        /* else, we are overriding an existing key => no need to allocated room
        * in uCode. */
 
-       WARN(priv->stations_39[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET,
+       WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET,
                "no space for a new key");
 
-       priv->stations_39[sta_id].sta.key.key_flags = key_flags;
-       priv->stations_39[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
-       priv->stations_39[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+       priv->stations[sta_id].sta.key.key_flags = key_flags;
+       priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+       priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
 
        IWL_DEBUG_INFO(priv, "hwcrypto: modify ucode station key info\n");
 
-       ret = iwl_send_add_sta(priv,
-               (struct iwl_addsta_cmd *)&priv->stations_39[sta_id].sta, CMD_ASYNC);
+       ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
 
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 
@@ -340,17 +201,16 @@ static int iwl3945_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
        unsigned long flags;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
-       memset(&priv->stations_39[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key));
-       memset(&priv->stations_39[sta_id].sta.key, 0,
+       memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key));
+       memset(&priv->stations[sta_id].sta.key, 0,
                sizeof(struct iwl4965_keyinfo));
-       priv->stations_39[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
-       priv->stations_39[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
-       priv->stations_39[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+       priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
+       priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+       priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 
        IWL_DEBUG_INFO(priv, "hwcrypto: clear ucode station key info\n");
-       iwl_send_add_sta(priv,
-               (struct iwl_addsta_cmd *)&priv->stations_39[sta_id].sta, 0);
+       iwl_send_add_sta(priv, &priv->stations[sta_id].sta, 0);
        return 0;
 }
 
@@ -578,7 +438,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
                                      int sta_id)
 {
        struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
-       struct iwl_hw_key *keyinfo = &priv->stations_39[sta_id].keyinfo;
+       struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo;
 
        switch (keyinfo->alg) {
        case ALG_CCMP:
@@ -753,7 +613,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        if (ieee80211_is_data_qos(fc)) {
                qc = ieee80211_get_qos_ctl(hdr);
                tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
-               seq_number = priv->stations_39[sta_id].tid[tid].seq_number &
+               seq_number = priv->stations[sta_id].tid[tid].seq_number &
                                IEEE80211_SCTL_SEQ;
                hdr->seq_ctrl = cpu_to_le16(seq_number) |
                        (hdr->seq_ctrl &
@@ -813,7 +673,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        if (!ieee80211_has_morefrags(hdr->frame_control)) {
                txq->need_update = 1;
                if (qc)
-                       priv->stations_39[sta_id].tid[tid].seq_number = seq_number;
+                       priv->stations[sta_id].tid[tid].seq_number = seq_number;
        } else {
                wait_write_ptr = 1;
                txq->need_update = 0;
@@ -1149,18 +1009,12 @@ static void iwl3945_rx_card_state_notif(struct iwl_priv *priv,
                clear_bit(STATUS_RF_KILL_HW, &priv->status);
 
 
-       if (flags & SW_CARD_DISABLED)
-               set_bit(STATUS_RF_KILL_SW, &priv->status);
-       else
-               clear_bit(STATUS_RF_KILL_SW, &priv->status);
-
        iwl_scan_cancel(priv);
 
        if ((test_bit(STATUS_RF_KILL_HW, &status) !=
-            test_bit(STATUS_RF_KILL_HW, &priv->status)) ||
-           (test_bit(STATUS_RF_KILL_SW, &status) !=
-            test_bit(STATUS_RF_KILL_SW, &priv->status)))
-               queue_work(priv->workqueue, &priv->rf_kill);
+            test_bit(STATUS_RF_KILL_HW, &priv->status)))
+               wiphy_rfkill_set_hw_state(priv->hw->wiphy,
+                               test_bit(STATUS_RF_KILL_HW, &priv->status));
        else
                wake_up_interruptible(&priv->wait_command_queue);
 }
@@ -1316,7 +1170,7 @@ static int iwl3945_rx_queue_restock(struct iwl_priv *priv)
 
        /* If we've added more space for the firmware to place data, tell it.
         * Increment device's write pointer in multiples of 8. */
-       if ((write != (rxq->write & ~0x7))
+       if ((rxq->write_actual != (rxq->write & ~0x7))
            || (abs(rxq->write - rxq->read) > 7)) {
                spin_lock_irqsave(&rxq->lock, flags);
                rxq->need_update = 1;
@@ -1337,7 +1191,7 @@ static int iwl3945_rx_queue_restock(struct iwl_priv *priv)
  * Also restock the Rx queue via iwl3945_rx_queue_restock.
  * This is called as a scheduled work item (except for during initialization)
  */
-static void iwl3945_rx_allocate(struct iwl_priv *priv)
+static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority)
 {
        struct iwl_rx_queue *rxq = &priv->rxq;
        struct list_head *element;
@@ -1360,7 +1214,7 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv)
                /* Alloc a new receive buffer */
                rxb->skb =
                    alloc_skb(priv->hw_params.rx_buf_size,
-                               GFP_KERNEL);
+                               priority);
                if (!rxb->skb) {
                        if (net_ratelimit())
                                IWL_CRIT(priv, ": Can not allocate SKB buffers\n");
@@ -1419,6 +1273,7 @@ void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
         * not restocked the Rx queue with fresh buffers */
        rxq->read = rxq->write = 0;
        rxq->free_count = 0;
+       rxq->write_actual = 0;
        spin_unlock_irqrestore(&rxq->lock, flags);
 }
 
@@ -1427,13 +1282,21 @@ void iwl3945_rx_replenish(void *data)
        struct iwl_priv *priv = data;
        unsigned long flags;
 
-       iwl3945_rx_allocate(priv);
+       iwl3945_rx_allocate(priv, GFP_KERNEL);
 
        spin_lock_irqsave(&priv->lock, flags);
        iwl3945_rx_queue_restock(priv);
        spin_unlock_irqrestore(&priv->lock, flags);
 }
 
+static void iwl3945_rx_replenish_now(struct iwl_priv *priv)
+{
+       iwl3945_rx_allocate(priv, GFP_ATOMIC);
+
+       iwl3945_rx_queue_restock(priv);
+}
+
+
 /* Assumes that the skb field of the buffers in 'pool' is kept accurate.
  * If an SKB has been detached, the POOL needs to have its SKB set to NULL
  * This free routine walks the list of POOL entries and if SKB is set to
@@ -1556,13 +1419,19 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
        unsigned long flags;
        u8 fill_rx = 0;
        u32 count = 8;
+       int total_empty = 0;
 
        /* uCode's read index (stored in shared DRAM) indicates the last Rx
         * buffer that the driver may process (last buffer filled by ucode). */
        r = le16_to_cpu(rxq->rb_stts->closed_rb_num) &  0x0FFF;
        i = rxq->read;
 
-       if (iwl_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2))
+       /* calculate total frames need to be restock after handling RX */
+       total_empty = r - priv->rxq.write_actual;
+       if (total_empty < 0)
+               total_empty += RX_QUEUE_SIZE;
+
+       if (total_empty > (RX_QUEUE_SIZE / 2))
                fill_rx = 1;
        /* Rx interrupt, but nothing sent from uCode */
        if (i == r)
@@ -1639,7 +1508,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
                        count++;
                        if (count >= 8) {
                                priv->rxq.read = i;
-                               iwl3945_rx_queue_restock(priv);
+                               iwl3945_rx_replenish_now(priv);
                                count = 0;
                        }
                }
@@ -1647,7 +1516,10 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
 
        /* Backtrack one entry */
        priv->rxq.read = i;
-       iwl3945_rx_queue_restock(priv);
+       if (fill_rx)
+               iwl3945_rx_replenish_now(priv);
+       else
+               iwl3945_rx_queue_restock(priv);
 }
 
 /* call this function to flush any scheduled tasklet */
@@ -2589,7 +2461,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
                goto restart;
        }
 
-       priv->cfg->ops->smgmt->clear_station_table(priv);
+       iwl_clear_stations_table(priv);
 
        rfkill = iwl_read_prph(priv, APMG_RFKILL_REG);
        IWL_DEBUG_INFO(priv, "RFKILL status: 0x%x\n", rfkill);
@@ -2681,7 +2553,7 @@ static void __iwl3945_down(struct iwl_priv *priv)
                set_bit(STATUS_EXIT_PENDING, &priv->status);
 
        iwl3945_led_unregister(priv);
-       priv->cfg->ops->smgmt->clear_station_table(priv);
+       iwl_clear_stations_table(priv);
 
        /* Unblock any waiting calls */
        wake_up_interruptible_all(&priv->wait_command_queue);
@@ -2708,8 +2580,6 @@ static void __iwl3945_down(struct iwl_priv *priv)
        if (!iwl_is_init(priv)) {
                priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) <<
                                        STATUS_RF_KILL_HW |
-                              test_bit(STATUS_RF_KILL_SW, &priv->status) <<
-                                       STATUS_RF_KILL_SW |
                               test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
                                        STATUS_GEO_CONFIGURED |
                                test_bit(STATUS_EXIT_PENDING, &priv->status) <<
@@ -2718,11 +2588,9 @@ static void __iwl3945_down(struct iwl_priv *priv)
        }
 
        /* ...otherwise clear out all the status bits but the RF Kill
-        * bits and continue taking the NIC down. */
+        * bit and continue taking the NIC down. */
        priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) <<
                                STATUS_RF_KILL_HW |
-                       test_bit(STATUS_RF_KILL_SW, &priv->status) <<
-                               STATUS_RF_KILL_SW |
                        test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
                                STATUS_GEO_CONFIGURED |
                        test_bit(STATUS_FW_ERROR, &priv->status) <<
@@ -2779,12 +2647,6 @@ static int __iwl3945_up(struct iwl_priv *priv)
                return -EIO;
        }
 
-       if (test_bit(STATUS_RF_KILL_SW, &priv->status)) {
-               IWL_WARN(priv, "Radio disabled by SW RF kill (module "
-                           "parameter)\n");
-               return -ENODEV;
-       }
-
        if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) {
                IWL_ERR(priv, "ucode not available for device bring up\n");
                return -EIO;
@@ -2833,7 +2695,7 @@ static int __iwl3945_up(struct iwl_priv *priv)
 
        for (i = 0; i < MAX_HW_RESTARTS; i++) {
 
-               priv->cfg->ops->smgmt->clear_station_table(priv);
+               iwl_clear_stations_table(priv);
 
                /* load bootstrap state machine,
                 * load bootstrap program into processor's memory,
@@ -2901,15 +2763,14 @@ static void iwl3945_rfkill_poll(struct work_struct *data)
 {
        struct iwl_priv *priv =
            container_of(data, struct iwl_priv, rfkill_poll.work);
-       unsigned long status = priv->status;
 
        if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
                clear_bit(STATUS_RF_KILL_HW, &priv->status);
        else
                set_bit(STATUS_RF_KILL_HW, &priv->status);
 
-       if (test_bit(STATUS_RF_KILL_HW, &status) != test_bit(STATUS_RF_KILL_HW, &priv->status))
-               queue_work(priv->workqueue, &priv->rf_kill);
+       wiphy_rfkill_set_hw_state(priv->hw->wiphy,
+                       test_bit(STATUS_RF_KILL_HW, &priv->status));
 
        queue_delayed_work(priv->workqueue, &priv->rfkill_poll,
                           round_jiffies_relative(2 * HZ));
@@ -3141,7 +3002,6 @@ static void iwl3945_bg_up(struct work_struct *data)
        mutex_lock(&priv->mutex);
        __iwl3945_up(priv);
        mutex_unlock(&priv->mutex);
-       iwl_rfkill_set_hw_state(priv);
 }
 
 static void iwl3945_bg_restart(struct work_struct *data)
@@ -3247,7 +3107,7 @@ void iwl3945_post_associate(struct iwl_priv *priv)
        case NL80211_IFTYPE_ADHOC:
 
                priv->assoc_id = 1;
-               priv->cfg->ops->smgmt->add_station(priv, priv->bssid, 0, 0, NULL);
+               iwl_add_station(priv, priv->bssid, 0, CMD_SYNC, NULL);
                iwl3945_sync_sta(priv, IWL_STA_ID,
                                 (priv->band == IEEE80211_BAND_5GHZ) ?
                                 IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP,
@@ -3304,8 +3164,6 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw)
 
        mutex_unlock(&priv->mutex);
 
-       iwl_rfkill_set_hw_state(priv);
-
        if (ret)
                goto out_release_irq;
 
@@ -3438,7 +3296,7 @@ void iwl3945_config_ap(struct iwl_priv *priv)
                /* restore RXON assoc */
                priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
                iwlcore_commit_rxon(priv);
-               priv->cfg->ops->smgmt->add_station(priv, iwl_bcast_addr, 0, 0, NULL);
+               iwl_add_station(priv, iwl_bcast_addr, 0, CMD_SYNC, NULL);
        }
        iwl3945_send_beacon_cmd(priv);
 
@@ -3469,7 +3327,7 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        static_key = !iwl_is_associated(priv);
 
        if (!static_key) {
-               sta_id = priv->cfg->ops->smgmt->find_station(priv, addr);
+               sta_id = iwl_find_station(priv, addr);
                if (sta_id == IWL_INVALID_STATION) {
                        IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
                                            addr);
@@ -3958,7 +3816,6 @@ static void iwl3945_setup_deferred_work(struct iwl_priv *priv)
        INIT_WORK(&priv->up, iwl3945_bg_up);
        INIT_WORK(&priv->restart, iwl3945_bg_restart);
        INIT_WORK(&priv->rx_replenish, iwl3945_bg_rx_replenish);
-       INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill);
        INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update);
        INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start);
        INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start);
@@ -4044,7 +3901,7 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
        mutex_init(&priv->mutex);
 
        /* Clear the driver's (not device's) station table */
-       priv->cfg->ops->smgmt->clear_station_table(priv);
+       iwl_clear_stations_table(priv);
 
        priv->data_retry_limit = -1;
        priv->ieee_channels = NULL;
@@ -4325,13 +4182,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        if (err)
                IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err);
 
-       err = iwl_rfkill_init(priv);
-       if (err)
-               IWL_ERR(priv, "Unable to initialize RFKILL system. "
-                                 "Ignoring error: %d\n", err);
-       else
-               iwl_rfkill_set_hw_state(priv);
-
        /* Start monitoring the killswitch */
        queue_delayed_work(priv->workqueue, &priv->rfkill_poll,
                           2 * HZ);
@@ -4397,7 +4247,6 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
 
        sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
 
-       iwl_rfkill_unregister(priv);
        cancel_delayed_work_sync(&priv->rfkill_poll);
 
        iwl3945_dealloc_ucode_pci(priv);
@@ -4407,7 +4256,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
        iwl3945_hw_txq_ctx_free(priv);
 
        iwl3945_unset_hw_params(priv);
-       priv->cfg->ops->smgmt->clear_station_table(priv);
+       iwl_clear_stations_table(priv);
 
        /*netif_stop_queue(dev); */
        flush_workqueue(priv->workqueue);
index 41bd4b2..1eccb6d 100644 (file)
@@ -1,10 +1,9 @@
 config IWM
        tristate "Intel Wireless Multicomm 3200 WiFi driver"
        depends on MMC && WLAN_80211 && EXPERIMENTAL
+       depends on CFG80211
        select WIRELESS_EXT
-       select CFG80211
        select FW_LOADER
-       select RFKILL
 
 config IWM_DEBUG
        bool "Enable full debugging output in iwmc3200wifi"
index 7cb415e..927f022 100644 (file)
@@ -1,5 +1,5 @@
 obj-$(CONFIG_IWM) := iwmc3200wifi.o
 iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o
-iwmc3200wifi-objs += commands.o wext.o cfg80211.o eeprom.o rfkill.o
+iwmc3200wifi-objs += commands.o wext.o cfg80211.o eeprom.o
 
 iwmc3200wifi-$(CONFIG_IWM_DEBUG) += debugfs.o
index 3256ad2..96f714e 100644 (file)
@@ -268,7 +268,7 @@ static int iwm_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
 
                iwm->conf.frag_threshold = wiphy->frag_threshold;
 
-               ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+               ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_FA_CFG_FIX,
                                             CFG_FRAG_THRESHOLD,
                                             iwm->conf.frag_threshold);
                if (ret < 0)
index db4ba08..ec1a15a 100644 (file)
@@ -72,7 +72,7 @@ static int iwm_fw_op_offset(struct iwm_priv *iwm, const struct firmware *fw,
        }
 
        if (fw->size < IWM_HDR_LEN) {
-               IWM_ERR(iwm, "FW is too small (%d)\n", fw->size);
+               IWM_ERR(iwm, "FW is too small (%zu)\n", fw->size);
                return -EINVAL;
        }
 
index 3b29681..635c16e 100644 (file)
@@ -343,8 +343,4 @@ int iwm_rx_handle_resp(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size,
                       struct iwm_wifi_cmd *cmd);
 void iwm_rx_free(struct iwm_priv *iwm);
 
-/* RF Kill API */
-int iwm_rfkill_init(struct iwm_priv *iwm);
-void iwm_rfkill_exit(struct iwm_priv *iwm);
-
 #endif
index eec7201..68e2c3b 100644 (file)
@@ -136,17 +136,8 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
 
        wdev->netdev = ndev;
 
-       ret = iwm_rfkill_init(iwm);
-       if (ret) {
-               dev_err(dev, "Failed to init rfkill\n");
-               goto out_rfkill;
-       }
-
        return iwm;
 
- out_rfkill:
-       unregister_netdev(ndev);
-
  out_ndev:
        free_netdev(ndev);
 
@@ -162,7 +153,6 @@ void iwm_if_free(struct iwm_priv *iwm)
        if (!iwm_to_ndev(iwm))
                return;
 
-       iwm_rfkill_exit(iwm);
        unregister_netdev(iwm_to_ndev(iwm));
        free_netdev(iwm_to_ndev(iwm));
        iwm_wdev_free(iwm);
diff --git a/drivers/net/wireless/iwmc3200wifi/rfkill.c b/drivers/net/wireless/iwmc3200wifi/rfkill.c
deleted file mode 100644 (file)
index 4ca8b49..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Intel Wireless Multicomm 3200 WiFi driver
- *
- * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
- * Samuel Ortiz <samuel.ortiz@intel.com>
- * Zhu Yi <yi.zhu@intel.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 Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- */
-
-#include <linux/rfkill.h>
-
-#include "iwm.h"
-
-static int iwm_rfkill_soft_toggle(void *data, enum rfkill_state state)
-{
-       struct iwm_priv *iwm = data;
-
-       switch (state) {
-       case RFKILL_STATE_UNBLOCKED:
-               if (test_bit(IWM_RADIO_RFKILL_HW, &iwm->radio))
-                       return -EBUSY;
-
-               if (test_and_clear_bit(IWM_RADIO_RFKILL_SW, &iwm->radio) &&
-                   (iwm_to_ndev(iwm)->flags & IFF_UP))
-                       iwm_up(iwm);
-
-               break;
-       case RFKILL_STATE_SOFT_BLOCKED:
-               if (!test_and_set_bit(IWM_RADIO_RFKILL_SW, &iwm->radio))
-                       iwm_down(iwm);
-
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-int iwm_rfkill_init(struct iwm_priv *iwm)
-{
-       int ret;
-
-       iwm->rfkill = rfkill_allocate(iwm_to_dev(iwm), RFKILL_TYPE_WLAN);
-       if (!iwm->rfkill) {
-               IWM_ERR(iwm, "Unable to allocate rfkill device\n");
-               return -ENOMEM;
-       }
-
-       iwm->rfkill->name = KBUILD_MODNAME;
-       iwm->rfkill->data = iwm;
-       iwm->rfkill->state = RFKILL_STATE_UNBLOCKED;
-       iwm->rfkill->toggle_radio = iwm_rfkill_soft_toggle;
-
-       ret = rfkill_register(iwm->rfkill);
-       if (ret) {
-               IWM_ERR(iwm, "Failed to register rfkill device\n");
-               goto fail;
-       }
-
-       return 0;
- fail:
-       rfkill_free(iwm->rfkill);
-       return ret;
-}
-
-void iwm_rfkill_exit(struct iwm_priv *iwm)
-{
-       if (iwm->rfkill)
-               rfkill_unregister(iwm->rfkill);
-
-       rfkill_free(iwm->rfkill);
-       iwm->rfkill = NULL;
-}
index edc0a00..b54da67 100644 (file)
@@ -395,7 +395,7 @@ static struct iwm_if_ops if_sdio_ops = {
        .debugfs_init = if_sdio_debugfs_init,
        .debugfs_exit = if_sdio_debugfs_exit,
        .umac_name = "iwmc3200wifi-umac-sdio.bin",
-       .calib_lmac_name = "iwmc3200wifi-lmac-calib-sdio.bin",
+       .calib_lmac_name = "iwmc3200wifi-calib-sdio.bin",
        .lmac_name = "iwmc3200wifi-lmac-sdio.bin",
 };
 
index 4bc46a6..9a5408e 100644 (file)
@@ -207,7 +207,7 @@ static int generate_domain_info_11d(struct parsed_region_chan_11d
        lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband);
        lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo,
                COUNTRY_CODE_LEN + 1 +
-               sizeof(struct ieeetypes_subbandset) * nr_subband);
+               sizeof(struct ieee_subbandset) * nr_subband);
        return 0;
 }
 
@@ -302,11 +302,9 @@ done:
  *  @param parsed_region_chan   pointer to parsed_region_chan_11d
  *  @return                    0
 */
-static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
-                                countryinfo,
+static int parse_domain_info_11d(struct ieee_ie_country_info_full_set *countryinfo,
                                 u8 band,
-                                struct parsed_region_chan_11d *
-                                parsed_region_chan)
+                                struct parsed_region_chan_11d *parsed_region_chan)
 {
        u8 nr_subband, nrchan;
        u8 lastchan, firstchan;
@@ -331,7 +329,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
        lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30);
 
        if ((*(countryinfo->countrycode)) == 0
-           || (countryinfo->len <= COUNTRY_CODE_LEN)) {
+           || (countryinfo->header.len <= COUNTRY_CODE_LEN)) {
                /* No region Info or Wrong region info: treat as No 11D info */
                goto done;
        }
@@ -349,8 +347,8 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
        memcpy(parsed_region_chan->countrycode, countryinfo->countrycode,
               COUNTRY_CODE_LEN);
 
-       nr_subband = (countryinfo->len - COUNTRY_CODE_LEN) /
-           sizeof(struct ieeetypes_subbandset);
+       nr_subband = (countryinfo->header.len - COUNTRY_CODE_LEN) /
+           sizeof(struct ieee_subbandset);
 
        for (j = 0, lastchan = 0; j < nr_subband; j++) {
 
@@ -502,7 +500,7 @@ int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
 {
        struct cmd_ds_802_11d_domain_info *pdomaininfo =
            &cmd->params.domaininfo;
-       struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain;
+       struct mrvl_ie_domain_param_set *domain = &pdomaininfo->domain;
        u8 nr_subband = priv->domainreg.nr_subband;
 
        lbs_deb_enter(LBS_DEB_11D);
@@ -524,16 +522,16 @@ int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
               sizeof(domain->countrycode));
 
        domain->header.len =
-           cpu_to_le16(nr_subband * sizeof(struct ieeetypes_subbandset) +
+           cpu_to_le16(nr_subband * sizeof(struct ieee_subbandset) +
                             sizeof(domain->countrycode));
 
        if (nr_subband) {
                memcpy(domain->subband, priv->domainreg.subband,
-                      nr_subband * sizeof(struct ieeetypes_subbandset));
+                      nr_subband * sizeof(struct ieee_subbandset));
 
                cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
                                             le16_to_cpu(domain->header.len) +
-                                            sizeof(struct mrvlietypesheader) +
+                                            sizeof(struct mrvl_ie_header) +
                                             S_DS_GEN);
        } else {
                cmd->size =
@@ -556,7 +554,7 @@ done:
 int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp)
 {
        struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp;
-       struct mrvlietypes_domainparamset *domain = &domaininfo->domain;
+       struct mrvl_ie_domain_param_set *domain = &domaininfo->domain;
        u16 action = le16_to_cpu(domaininfo->action);
        s16 ret = 0;
        u8 nr_subband = 0;
@@ -567,7 +565,7 @@ int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp)
                (int)le16_to_cpu(resp->size));
 
        nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
-                     sizeof(struct ieeetypes_subbandset);
+                     sizeof(struct ieee_subbandset);
 
        lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband);
 
index 4f4f47f..fb75d3e 100644 (file)
 struct cmd_ds_command;
 
 /** Data structure for Country IE*/
-struct ieeetypes_subbandset {
+struct ieee_subbandset {
        u8 firstchan;
        u8 nrchan;
        u8 maxtxpwr;
 } __attribute__ ((packed));
 
-struct ieeetypes_countryinfoset {
-       u8 element_id;
-       u8 len;
+struct ieee_ie_country_info_set {
+       struct ieee_ie_header header;
+
        u8 countrycode[COUNTRY_CODE_LEN];
-       struct ieeetypes_subbandset subband[1];
+       struct ieee_subbandset subband[1];
 };
 
-struct ieeetypes_countryinfofullset {
-       u8 element_id;
-       u8 len;
+struct ieee_ie_country_info_full_set {
+       struct ieee_ie_header header;
+
        u8 countrycode[COUNTRY_CODE_LEN];
-       struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
+       struct ieee_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
 } __attribute__ ((packed));
 
-struct mrvlietypes_domainparamset {
-       struct mrvlietypesheader header;
+struct mrvl_ie_domain_param_set {
+       struct mrvl_ie_header header;
+
        u8 countrycode[COUNTRY_CODE_LEN];
-       struct ieeetypes_subbandset subband[1];
+       struct ieee_subbandset subband[1];
 } __attribute__ ((packed));
 
 struct cmd_ds_802_11d_domain_info {
        __le16 action;
-       struct mrvlietypes_domainparamset domain;
+       struct mrvl_ie_domain_param_set domain;
 } __attribute__ ((packed));
 
 /** domain regulatory information */
@@ -57,7 +58,7 @@ struct lbs_802_11d_domain_reg {
        u8 countrycode[COUNTRY_CODE_LEN];
        /** No. of subband*/
        u8 nr_subband;
-       struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
+       struct ieee_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
 };
 
 struct chan_power_11d {
index a0e440c..b9b3741 100644 (file)
 #include "scan.h"
 #include "cmd.h"
 
-static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp);
-
 static const u8 bssid_any[ETH_ALEN]  __attribute__ ((aligned (2))) =
        { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
 static const u8 bssid_off[ETH_ALEN]  __attribute__ ((aligned (2))) =
        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 
-/* The firmware needs certain bits masked out of the beacon-derviced capability
- * field when associating/joining to BSSs.
+/* The firmware needs the following bits masked out of the beacon-derived
+ * capability field when associating/joining to a BSS:
+ *  9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused)
  */
 #define CAPINFO_MASK   (~(0xda00))
 
@@ -102,6 +101,295 @@ static void lbs_set_basic_rate_flags(u8 *rates, size_t len)
 }
 
 
+static u8 iw_auth_to_ieee_auth(u8 auth)
+{
+       if (auth == IW_AUTH_ALG_OPEN_SYSTEM)
+               return 0x00;
+       else if (auth == IW_AUTH_ALG_SHARED_KEY)
+               return 0x01;
+       else if (auth == IW_AUTH_ALG_LEAP)
+               return 0x80;
+
+       lbs_deb_join("%s: invalid auth alg 0x%X\n", __func__, auth);
+       return 0;
+}
+
+/**
+ *  @brief This function prepares the authenticate command.  AUTHENTICATE only
+ *  sets the authentication suite for future associations, as the firmware
+ *  handles authentication internally during the ASSOCIATE command.
+ *
+ *  @param priv      A pointer to struct lbs_private structure
+ *  @param bssid     The peer BSSID with which to authenticate
+ *  @param auth      The authentication mode to use (from wireless.h)
+ *
+ *  @return         0 or -1
+ */
+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);
+
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+       memcpy(cmd.bssid, bssid, ETH_ALEN);
+
+       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);
+
+       ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd);
+
+       lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
+       return ret;
+}
+
+
+static int lbs_assoc_post(struct lbs_private *priv,
+                         struct cmd_ds_802_11_associate_response *resp)
+{
+       int ret = 0;
+       union iwreq_data wrqu;
+       struct bss_descriptor *bss;
+       u16 status_code;
+
+       lbs_deb_enter(LBS_DEB_ASSOC);
+
+       if (!priv->in_progress_assoc_req) {
+               lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n");
+               ret = -1;
+               goto done;
+       }
+       bss = &priv->in_progress_assoc_req->bss;
+
+       /*
+        * Older FW versions map the IEEE 802.11 Status Code in the association
+        * response to the following values returned in resp->statuscode:
+        *
+        *    IEEE Status Code                Marvell Status Code
+        *    0                       ->      0x0000 ASSOC_RESULT_SUCCESS
+        *    13                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
+        *    14                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
+        *    15                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
+        *    16                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
+        *    others                  ->      0x0003 ASSOC_RESULT_REFUSED
+        *
+        * Other response codes:
+        *    0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
+        *    0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
+        *                                    association response from the AP)
+        */
+
+       status_code = le16_to_cpu(resp->statuscode);
+       if (priv->fwrelease < 0x09000000) {
+               switch (status_code) {
+               case 0x00:
+                       break;
+               case 0x01:
+                       lbs_deb_assoc("ASSOC_RESP: invalid parameters\n");
+                       break;
+               case 0x02:
+                       lbs_deb_assoc("ASSOC_RESP: internal timer "
+                               "expired while waiting for the AP\n");
+                       break;
+               case 0x03:
+                       lbs_deb_assoc("ASSOC_RESP: association "
+                               "refused by AP\n");
+                       break;
+               case 0x04:
+                       lbs_deb_assoc("ASSOC_RESP: authentication "
+                               "refused by AP\n");
+                       break;
+               default:
+                       lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x "
+                               " unknown\n", status_code);
+                       break;
+               }
+       } else {
+               /* v9+ returns the AP's association response */
+               lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x\n", status_code);
+       }
+
+       if (status_code) {
+               lbs_mac_event_disconnected(priv);
+               ret = -1;
+               goto done;
+       }
+
+       lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP",
+                   (void *) (resp + sizeof (resp->hdr)),
+                   le16_to_cpu(resp->hdr.size) - sizeof (resp->hdr));
+
+       /* Send a Media Connected event, according to the Spec */
+       priv->connect_status = LBS_CONNECTED;
+
+       /* Update current SSID and BSSID */
+       memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
+       priv->curbssparams.ssid_len = bss->ssid_len;
+       memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
+
+       priv->SNR[TYPE_RXPD][TYPE_AVG] = 0;
+       priv->NF[TYPE_RXPD][TYPE_AVG] = 0;
+
+       memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
+       memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
+       priv->nextSNRNF = 0;
+       priv->numSNRNF = 0;
+
+       netif_carrier_on(priv->dev);
+       if (!priv->tx_pending_len)
+               netif_wake_queue(priv->dev);
+
+       memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
+       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+       wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+
+done:
+       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
+       return ret;
+}
+
+/**
+ *  @brief This function prepares an association-class command.
+ *
+ *  @param priv      A pointer to struct lbs_private structure
+ *  @param assoc_req The association request describing the BSS to associate
+ *                   or reassociate with
+ *  @param command   The actual command, either CMD_802_11_ASSOCIATE or
+ *                   CMD_802_11_REASSOCIATE
+ *
+ *  @return         0 or -1
+ */
+static int lbs_associate(struct lbs_private *priv,
+                        struct assoc_request *assoc_req,
+                        u16 command)
+{
+       struct cmd_ds_802_11_associate cmd;
+       int ret = 0;
+       struct bss_descriptor *bss = &assoc_req->bss;
+       u8 *pos = &(cmd.iebuf[0]);
+       u16 tmpcap, tmplen, tmpauth;
+       struct mrvl_ie_ssid_param_set *ssid;
+       struct mrvl_ie_ds_param_set *ds;
+       struct mrvl_ie_cf_param_set *cf;
+       struct mrvl_ie_rates_param_set *rates;
+       struct mrvl_ie_rsn_param_set *rsn;
+       struct mrvl_ie_auth_type *auth;
+
+       lbs_deb_enter(LBS_DEB_ASSOC);
+
+       BUG_ON((command != CMD_802_11_ASSOCIATE) &&
+               (command != CMD_802_11_REASSOCIATE));
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.hdr.command = cpu_to_le16(command);
+
+       /* Fill in static fields */
+       memcpy(cmd.bssid, bss->bssid, ETH_ALEN);
+       cmd.listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
+
+       /* Capability info */
+       tmpcap = (bss->capability & CAPINFO_MASK);
+       if (bss->mode == IW_MODE_INFRA)
+               tmpcap |= WLAN_CAPABILITY_ESS;
+       cmd.capability = cpu_to_le16(tmpcap);
+       lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap);
+
+       /* SSID */
+       ssid = (struct mrvl_ie_ssid_param_set *) pos;
+       ssid->header.type = cpu_to_le16(TLV_TYPE_SSID);
+       tmplen = bss->ssid_len;
+       ssid->header.len = cpu_to_le16(tmplen);
+       memcpy(ssid->ssid, bss->ssid, tmplen);
+       pos += sizeof(ssid->header) + tmplen;
+
+       ds = (struct mrvl_ie_ds_param_set *) pos;
+       ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
+       ds->header.len = cpu_to_le16(1);
+       ds->channel = bss->phy.ds.channel;
+       pos += sizeof(ds->header) + 1;
+
+       cf = (struct mrvl_ie_cf_param_set *) pos;
+       cf->header.type = cpu_to_le16(TLV_TYPE_CF);
+       tmplen = sizeof(*cf) - sizeof (cf->header);
+       cf->header.len = cpu_to_le16(tmplen);
+       /* IE payload should be zeroed, firmware fills it in for us */
+       pos += sizeof(*cf);
+
+       rates = (struct mrvl_ie_rates_param_set *) pos;
+       rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
+       memcpy(&rates->rates, &bss->rates, MAX_RATES);
+       tmplen = MAX_RATES;
+       if (get_common_rates(priv, rates->rates, &tmplen)) {
+               ret = -1;
+               goto done;
+       }
+       pos += sizeof(rates->header) + tmplen;
+       rates->header.len = cpu_to_le16(tmplen);
+       lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen);
+
+       /* Copy the infra. association rates into Current BSS state structure */
+       memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
+       memcpy(&priv->curbssparams.rates, &rates->rates, tmplen);
+
+       /* Set MSB on basic rates as the firmware requires, but _after_
+        * copying to current bss rates.
+        */
+       lbs_set_basic_rate_flags(rates->rates, tmplen);
+
+       /* 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);
+               tmpauth = iw_auth_to_ieee_auth(priv->secinfo.auth_mode);
+               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);
+       }
+
+       /* WPA/WPA2 IEs */
+       if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
+               rsn = (struct mrvl_ie_rsn_param_set *) pos;
+               /* WPA_IE or WPA2_IE */
+               rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]);
+               tmplen = (u16) assoc_req->wpa_ie[1];
+               rsn->header.len = cpu_to_le16(tmplen);
+               memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen);
+               lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: WPA/RSN IE", (u8 *) rsn,
+                       sizeof(rsn->header) + tmplen);
+               pos += sizeof(rsn->header) + tmplen;
+       }
+
+       cmd.hdr.size = cpu_to_le16((sizeof(cmd) - sizeof(cmd.iebuf)) +
+                                  (u16)(pos - (u8 *) &cmd.iebuf));
+
+       /* update curbssparams */
+       priv->curbssparams.channel = bss->phy.ds.channel;
+
+       if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
+               ret = -1;
+               goto done;
+       }
+
+       ret = lbs_cmd_with_response(priv, command, &cmd);
+       if (ret == 0) {
+               ret = lbs_assoc_post(priv,
+                       (struct cmd_ds_802_11_associate_response *) &cmd);
+       }
+
+done:
+       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
+       return ret;
+}
+
 /**
  *  @brief Associate to a specific BSS discovered in a scan
  *
@@ -110,7 +398,7 @@ static void lbs_set_basic_rate_flags(u8 *rates, size_t len)
  *
  *  @return          0-success, otherwise fail
  */
-static int lbs_associate(struct lbs_private *priv,
+static int lbs_try_associate(struct lbs_private *priv,
        struct assoc_request *assoc_req)
 {
        int ret;
@@ -118,11 +406,15 @@ static int lbs_associate(struct lbs_private *priv,
 
        lbs_deb_enter(LBS_DEB_ASSOC);
 
-       ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE,
-                                   0, CMD_OPTION_WAITFORRSP,
-                                   0, assoc_req->bss.bssid);
-       if (ret)
-               goto out;
+       /* FW v9 and higher indicate authentication suites as a TLV in the
+        * association command, not as a separate authentication command.
+        */
+       if (priv->fwrelease < 0x09000000) {
+               ret = lbs_set_authentication(priv, assoc_req->bss.bssid,
+                                            priv->secinfo.auth_mode);
+               if (ret)
+                       goto out;
+       }
 
        /* Use short preamble only when both the BSS and firmware support it */
        if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
@@ -133,14 +425,78 @@ static int lbs_associate(struct lbs_private *priv,
        if (ret)
                goto out;
 
-       ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE,
-                                   0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
+       ret = lbs_associate(priv, assoc_req, CMD_802_11_ASSOCIATE);
 
 out:
        lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
        return ret;
 }
 
+static int lbs_adhoc_post(struct lbs_private *priv,
+                         struct cmd_ds_802_11_ad_hoc_result *resp)
+{
+       int ret = 0;
+       u16 command = le16_to_cpu(resp->hdr.command);
+       u16 result = le16_to_cpu(resp->hdr.result);
+       union iwreq_data wrqu;
+       struct bss_descriptor *bss;
+       DECLARE_SSID_BUF(ssid);
+
+       lbs_deb_enter(LBS_DEB_JOIN);
+
+       if (!priv->in_progress_assoc_req) {
+               lbs_deb_join("ADHOC_RESP: no in-progress association "
+                       "request\n");
+               ret = -1;
+               goto done;
+       }
+       bss = &priv->in_progress_assoc_req->bss;
+
+       /*
+        * Join result code 0 --> SUCCESS
+        */
+       if (result) {
+               lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result);
+               if (priv->connect_status == LBS_CONNECTED)
+                       lbs_mac_event_disconnected(priv);
+               ret = -1;
+               goto done;
+       }
+
+       /* Send a Media Connected event, according to the Spec */
+       priv->connect_status = LBS_CONNECTED;
+
+       if (command == CMD_RET(CMD_802_11_AD_HOC_START)) {
+               /* Update the created network descriptor with the new BSSID */
+               memcpy(bss->bssid, resp->bssid, ETH_ALEN);
+       }
+
+       /* Set the BSSID from the joined/started descriptor */
+       memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
+
+       /* Set the new SSID to current SSID */
+       memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
+       priv->curbssparams.ssid_len = bss->ssid_len;
+
+       netif_carrier_on(priv->dev);
+       if (!priv->tx_pending_len)
+               netif_wake_queue(priv->dev);
+
+       memset(&wrqu, 0, sizeof(wrqu));
+       memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
+       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+       wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+
+       lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n",
+                    print_ssid(ssid, bss->ssid, bss->ssid_len),
+                    priv->curbssparams.bssid,
+                    priv->curbssparams.channel);
+
+done:
+       lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
+       return ret;
+}
+
 /**
  *  @brief Join an adhoc network found in a previous scan
  *
@@ -219,11 +575,10 @@ static int lbs_adhoc_join(struct lbs_private *priv,
        memcpy(&cmd.bss.bssid, &bss->bssid, ETH_ALEN);
        memcpy(&cmd.bss.ssid, &bss->ssid, bss->ssid_len);
 
-       memcpy(&cmd.bss.phyparamset, &bss->phyparamset,
-              sizeof(union ieeetypes_phyparamset));
+       memcpy(&cmd.bss.ds, &bss->phy.ds, sizeof(struct ieee_ie_ds_param_set));
 
-       memcpy(&cmd.bss.ssparamset, &bss->ssparamset,
-              sizeof(union IEEEtypes_ssparamset));
+       memcpy(&cmd.bss.ibss, &bss->ss.ibss,
+              sizeof(struct ieee_ie_ibss_param_set));
 
        cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
        lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
@@ -260,7 +615,7 @@ static int lbs_adhoc_join(struct lbs_private *priv,
         */
        lbs_set_basic_rate_flags(cmd.bss.rates, ratesize);
 
-       cmd.bss.ssparamset.ibssparamset.atimwindow = cpu_to_le16(bss->atimwindow);
+       cmd.bss.ibss.atimwindow = bss->atimwindow;
 
        if (assoc_req->secinfo.wep_enabled) {
                u16 tmp = le16_to_cpu(cmd.bss.capability);
@@ -287,8 +642,10 @@ static int lbs_adhoc_join(struct lbs_private *priv,
        }
 
        ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd);
-       if (ret == 0)
-               ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd);
+       if (ret == 0) {
+               ret = lbs_adhoc_post(priv,
+                                    (struct cmd_ds_802_11_ad_hoc_result *)&cmd);
+       }
 
 out:
        lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
@@ -343,22 +700,24 @@ static int lbs_adhoc_start(struct lbs_private *priv,
        WARN_ON(!assoc_req->channel);
 
        /* set Physical parameter set */
-       cmd.phyparamset.dsparamset.elementid = WLAN_EID_DS_PARAMS;
-       cmd.phyparamset.dsparamset.len = 1;
-       cmd.phyparamset.dsparamset.currentchan = assoc_req->channel;
+       cmd.ds.header.id = WLAN_EID_DS_PARAMS;
+       cmd.ds.header.len = 1;
+       cmd.ds.channel = assoc_req->channel;
 
        /* set IBSS parameter set */
-       cmd.ssparamset.ibssparamset.elementid = WLAN_EID_IBSS_PARAMS;
-       cmd.ssparamset.ibssparamset.len = 2;
-       cmd.ssparamset.ibssparamset.atimwindow = 0;
+       cmd.ibss.header.id = WLAN_EID_IBSS_PARAMS;
+       cmd.ibss.header.len = 2;
+       cmd.ibss.atimwindow = cpu_to_le16(0);
 
        /* set capability info */
        tmpcap = WLAN_CAPABILITY_IBSS;
-       if (assoc_req->secinfo.wep_enabled) {
-               lbs_deb_join("ADHOC_START: WEP enabled, setting privacy on\n");
+       if (assoc_req->secinfo.wep_enabled ||
+           assoc_req->secinfo.WPAenabled ||
+           assoc_req->secinfo.WPA2enabled) {
+               lbs_deb_join("ADHOC_START: WEP/WPA enabled, privacy on\n");
                tmpcap |= WLAN_CAPABILITY_PRIVACY;
        } else
-               lbs_deb_join("ADHOC_START: WEP disabled, setting privacy off\n");
+               lbs_deb_join("ADHOC_START: WEP disabled, privacy off\n");
 
        cmd.capability = cpu_to_le16(tmpcap);
 
@@ -395,7 +754,8 @@ static int lbs_adhoc_start(struct lbs_private *priv,
 
        ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd);
        if (ret == 0)
-               ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd);
+               ret = lbs_adhoc_post(priv,
+                                    (struct cmd_ds_802_11_ad_hoc_result *)&cmd);
 
 out:
        lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
@@ -720,7 +1080,7 @@ static int assoc_helper_essid(struct lbs_private *priv,
                                assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel);
                if (bss != NULL) {
                        memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
-                       ret = lbs_associate(priv, assoc_req);
+                       ret = lbs_try_associate(priv, assoc_req);
                } else {
                        lbs_deb_assoc("SSID not found; cannot associate\n");
                }
@@ -772,8 +1132,9 @@ static int assoc_helper_bssid(struct lbs_private *priv,
 
        memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
        if (assoc_req->mode == IW_MODE_INFRA) {
-               ret = lbs_associate(priv, assoc_req);
-               lbs_deb_assoc("ASSOC: lbs_associate(bssid) returned %d\n", ret);
+               ret = lbs_try_associate(priv, assoc_req);
+               lbs_deb_assoc("ASSOC: lbs_try_associate(bssid) returned %d\n",
+                             ret);
        } else if (assoc_req->mode == IW_MODE_ADHOC) {
                lbs_adhoc_join(priv, assoc_req);
        }
@@ -1467,57 +1828,6 @@ struct assoc_request *lbs_get_association_request(struct lbs_private *priv)
 
 
 /**
- *  @brief This function prepares command of authenticate.
- *
- *  @param priv      A pointer to struct lbs_private structure
- *  @param cmd       A pointer to cmd_ds_command structure
- *  @param pdata_buf Void cast of pointer to a BSSID to authenticate with
- *
- *  @return         0 or -1
- */
-int lbs_cmd_80211_authenticate(struct lbs_private *priv,
-                                struct cmd_ds_command *cmd,
-                                void *pdata_buf)
-{
-       struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth;
-       int ret = -1;
-       u8 *bssid = pdata_buf;
-
-       lbs_deb_enter(LBS_DEB_JOIN);
-
-       cmd->command = cpu_to_le16(CMD_802_11_AUTHENTICATE);
-       cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate)
-                       + S_DS_GEN);
-
-       /* translate auth mode to 802.11 defined wire value */
-       switch (priv->secinfo.auth_mode) {
-       case IW_AUTH_ALG_OPEN_SYSTEM:
-               pauthenticate->authtype = 0x00;
-               break;
-       case IW_AUTH_ALG_SHARED_KEY:
-               pauthenticate->authtype = 0x01;
-               break;
-       case IW_AUTH_ALG_LEAP:
-               pauthenticate->authtype = 0x80;
-               break;
-       default:
-               lbs_deb_join("AUTH_CMD: invalid auth alg 0x%X\n",
-                       priv->secinfo.auth_mode);
-               goto out;
-       }
-
-       memcpy(pauthenticate->macaddr, bssid, ETH_ALEN);
-
-       lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n",
-               bssid, pauthenticate->authtype);
-       ret = 0;
-
-out:
-       lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
-       return ret;
-}
-
-/**
  *  @brief Deauthenticate from a specific BSS
  *
  *  @param priv        A pointer to struct lbs_private structure
@@ -1550,285 +1860,3 @@ int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN],
        return ret;
 }
 
-int lbs_cmd_80211_associate(struct lbs_private *priv,
-                             struct cmd_ds_command *cmd, void *pdata_buf)
-{
-       struct cmd_ds_802_11_associate *passo = &cmd->params.associate;
-       int ret = 0;
-       struct assoc_request *assoc_req = pdata_buf;
-       struct bss_descriptor *bss = &assoc_req->bss;
-       u8 *pos;
-       u16 tmpcap, tmplen;
-       struct mrvlietypes_ssidparamset *ssid;
-       struct mrvlietypes_phyparamset *phy;
-       struct mrvlietypes_ssparamset *ss;
-       struct mrvlietypes_ratesparamset *rates;
-       struct mrvlietypes_rsnparamset *rsn;
-
-       lbs_deb_enter(LBS_DEB_ASSOC);
-
-       pos = (u8 *) passo;
-
-       if (!priv) {
-               ret = -1;
-               goto done;
-       }
-
-       cmd->command = cpu_to_le16(CMD_802_11_ASSOCIATE);
-
-       memcpy(passo->peerstaaddr, bss->bssid, sizeof(passo->peerstaaddr));
-       pos += sizeof(passo->peerstaaddr);
-
-       /* set the listen interval */
-       passo->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
-
-       pos += sizeof(passo->capability);
-       pos += sizeof(passo->listeninterval);
-       pos += sizeof(passo->bcnperiod);
-       pos += sizeof(passo->dtimperiod);
-
-       ssid = (struct mrvlietypes_ssidparamset *) pos;
-       ssid->header.type = cpu_to_le16(TLV_TYPE_SSID);
-       tmplen = bss->ssid_len;
-       ssid->header.len = cpu_to_le16(tmplen);
-       memcpy(ssid->ssid, bss->ssid, tmplen);
-       pos += sizeof(ssid->header) + tmplen;
-
-       phy = (struct mrvlietypes_phyparamset *) pos;
-       phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
-       tmplen = sizeof(phy->fh_ds.dsparamset);
-       phy->header.len = cpu_to_le16(tmplen);
-       memcpy(&phy->fh_ds.dsparamset,
-              &bss->phyparamset.dsparamset.currentchan,
-              tmplen);
-       pos += sizeof(phy->header) + tmplen;
-
-       ss = (struct mrvlietypes_ssparamset *) pos;
-       ss->header.type = cpu_to_le16(TLV_TYPE_CF);
-       tmplen = sizeof(ss->cf_ibss.cfparamset);
-       ss->header.len = cpu_to_le16(tmplen);
-       pos += sizeof(ss->header) + tmplen;
-
-       rates = (struct mrvlietypes_ratesparamset *) pos;
-       rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
-       memcpy(&rates->rates, &bss->rates, MAX_RATES);
-       tmplen = MAX_RATES;
-       if (get_common_rates(priv, rates->rates, &tmplen)) {
-               ret = -1;
-               goto done;
-       }
-       pos += sizeof(rates->header) + tmplen;
-       rates->header.len = cpu_to_le16(tmplen);
-       lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen);
-
-       /* Copy the infra. association rates into Current BSS state structure */
-       memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
-       memcpy(&priv->curbssparams.rates, &rates->rates, tmplen);
-
-       /* Set MSB on basic rates as the firmware requires, but _after_
-        * copying to current bss rates.
-        */
-       lbs_set_basic_rate_flags(rates->rates, tmplen);
-
-       if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
-               rsn = (struct mrvlietypes_rsnparamset *) pos;
-               /* WPA_IE or WPA2_IE */
-               rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]);
-               tmplen = (u16) assoc_req->wpa_ie[1];
-               rsn->header.len = cpu_to_le16(tmplen);
-               memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen);
-               lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: RSN IE", (u8 *) rsn,
-                       sizeof(rsn->header) + tmplen);
-               pos += sizeof(rsn->header) + tmplen;
-       }
-
-       /* update curbssparams */
-       priv->curbssparams.channel = bss->phyparamset.dsparamset.currentchan;
-
-       if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
-               ret = -1;
-               goto done;
-       }
-
-       cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN);
-
-       /* set the capability info */
-       tmpcap = (bss->capability & CAPINFO_MASK);
-       if (bss->mode == IW_MODE_INFRA)
-               tmpcap |= WLAN_CAPABILITY_ESS;
-       passo->capability = cpu_to_le16(tmpcap);
-       lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap);
-
-done:
-       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-       return ret;
-}
-
-int lbs_ret_80211_associate(struct lbs_private *priv,
-                             struct cmd_ds_command *resp)
-{
-       int ret = 0;
-       union iwreq_data wrqu;
-       struct ieeetypes_assocrsp *passocrsp;
-       struct bss_descriptor *bss;
-       u16 status_code;
-
-       lbs_deb_enter(LBS_DEB_ASSOC);
-
-       if (!priv->in_progress_assoc_req) {
-               lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n");
-               ret = -1;
-               goto done;
-       }
-       bss = &priv->in_progress_assoc_req->bss;
-
-       passocrsp = (struct ieeetypes_assocrsp *) &resp->params;
-
-       /*
-        * Older FW versions map the IEEE 802.11 Status Code in the association
-        * response to the following values returned in passocrsp->statuscode:
-        *
-        *    IEEE Status Code                Marvell Status Code
-        *    0                       ->      0x0000 ASSOC_RESULT_SUCCESS
-        *    13                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
-        *    14                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
-        *    15                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
-        *    16                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
-        *    others                  ->      0x0003 ASSOC_RESULT_REFUSED
-        *
-        * Other response codes:
-        *    0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
-        *    0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
-        *                                    association response from the AP)
-        */
-
-       status_code = le16_to_cpu(passocrsp->statuscode);
-       switch (status_code) {
-       case 0x00:
-               break;
-       case 0x01:
-               lbs_deb_assoc("ASSOC_RESP: invalid parameters\n");
-               break;
-       case 0x02:
-               lbs_deb_assoc("ASSOC_RESP: internal timer "
-                       "expired while waiting for the AP\n");
-               break;
-       case 0x03:
-               lbs_deb_assoc("ASSOC_RESP: association "
-                       "refused by AP\n");
-               break;
-       case 0x04:
-               lbs_deb_assoc("ASSOC_RESP: authentication "
-                       "refused by AP\n");
-               break;
-       default:
-               lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x "
-                       " unknown\n", status_code);
-               break;
-       }
-
-       if (status_code) {
-               lbs_mac_event_disconnected(priv);
-               ret = -1;
-               goto done;
-       }
-
-       lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP", (void *)&resp->params,
-               le16_to_cpu(resp->size) - S_DS_GEN);
-
-       /* Send a Media Connected event, according to the Spec */
-       priv->connect_status = LBS_CONNECTED;
-
-       /* Update current SSID and BSSID */
-       memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
-       priv->curbssparams.ssid_len = bss->ssid_len;
-       memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
-
-       priv->SNR[TYPE_RXPD][TYPE_AVG] = 0;
-       priv->NF[TYPE_RXPD][TYPE_AVG] = 0;
-
-       memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
-       memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
-       priv->nextSNRNF = 0;
-       priv->numSNRNF = 0;
-
-       netif_carrier_on(priv->dev);
-       if (!priv->tx_pending_len)
-               netif_wake_queue(priv->dev);
-
-       memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
-       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-       wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
-
-done:
-       lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
-       return ret;
-}
-
-static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp)
-{
-       int ret = 0;
-       u16 command = le16_to_cpu(resp->command);
-       u16 result = le16_to_cpu(resp->result);
-       struct cmd_ds_802_11_ad_hoc_result *adhoc_resp;
-       union iwreq_data wrqu;
-       struct bss_descriptor *bss;
-       DECLARE_SSID_BUF(ssid);
-
-       lbs_deb_enter(LBS_DEB_JOIN);
-
-       adhoc_resp = (struct cmd_ds_802_11_ad_hoc_result *) resp;
-
-       if (!priv->in_progress_assoc_req) {
-               lbs_deb_join("ADHOC_RESP: no in-progress association "
-                       "request\n");
-               ret = -1;
-               goto done;
-       }
-       bss = &priv->in_progress_assoc_req->bss;
-
-       /*
-        * Join result code 0 --> SUCCESS
-        */
-       if (result) {
-               lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result);
-               if (priv->connect_status == LBS_CONNECTED)
-                       lbs_mac_event_disconnected(priv);
-               ret = -1;
-               goto done;
-       }
-
-       /* Send a Media Connected event, according to the Spec */
-       priv->connect_status = LBS_CONNECTED;
-
-       if (command == CMD_RET(CMD_802_11_AD_HOC_START)) {
-               /* Update the created network descriptor with the new BSSID */
-               memcpy(bss->bssid, adhoc_resp->bssid, ETH_ALEN);
-       }
-
-       /* Set the BSSID from the joined/started descriptor */
-       memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
-
-       /* Set the new SSID to current SSID */
-       memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
-       priv->curbssparams.ssid_len = bss->ssid_len;
-
-       netif_carrier_on(priv->dev);
-       if (!priv->tx_pending_len)
-               netif_wake_queue(priv->dev);
-
-       memset(&wrqu, 0, sizeof(wrqu));
-       memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
-       wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-       wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
-
-       lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n",
-                    print_ssid(ssid, bss->ssid, bss->ssid_len),
-                    priv->curbssparams.bssid,
-                    priv->curbssparams.channel);
-
-done:
-       lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
-       return ret;
-}
-
index 8b7336d..6e765e9 100644 (file)
@@ -8,22 +8,9 @@
 void lbs_association_worker(struct work_struct *work);
 struct assoc_request *lbs_get_association_request(struct lbs_private *priv);
 
-struct cmd_ds_command;
-int lbs_cmd_80211_authenticate(struct lbs_private *priv,
-                                       struct cmd_ds_command *cmd,
-                                       void *pdata_buf);
-
 int lbs_adhoc_stop(struct lbs_private *priv);
 
 int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
                                 u8 bssid[ETH_ALEN], u16 reason);
-int lbs_cmd_80211_associate(struct lbs_private *priv,
-                                    struct cmd_ds_command *cmd,
-                                    void *pdata_buf);
-
-int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv,
-                                       struct cmd_ds_command *resp);
-int lbs_ret_80211_associate(struct lbs_private *priv,
-                                    struct cmd_ds_command *resp);
 
 #endif /* _LBS_ASSOC_H */
index c455b9a..01db705 100644 (file)
@@ -1220,8 +1220,7 @@ static void lbs_submit_command(struct lbs_private *priv,
        command = le16_to_cpu(cmd->command);
 
        /* These commands take longer */
-       if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE ||
-           command == CMD_802_11_AUTHENTICATE)
+       if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE)
                timeo = 5 * HZ;
 
        lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n",
@@ -1415,15 +1414,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
                ret = lbs_cmd_802_11_ps_mode(cmdptr, cmd_action);
                break;
 
-       case CMD_802_11_ASSOCIATE:
-       case CMD_802_11_REASSOCIATE:
-               ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf);
-               break;
-
-       case CMD_802_11_AUTHENTICATE:
-               ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
-               break;
-
        case CMD_MAC_REG_ACCESS:
        case CMD_BBP_REG_ACCESS:
        case CMD_RF_REG_ACCESS:
@@ -1470,8 +1460,8 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
                break;
        case CMD_802_11_LED_GPIO_CTRL:
                {
-                       struct mrvlietypes_ledgpio *gpio =
-                           (struct mrvlietypes_ledgpio*)
+                       struct mrvl_ie_ledgpio *gpio =
+                           (struct mrvl_ie_ledgpio*)
                            cmdptr->params.ledgpio.data;
 
                        memmove(&cmdptr->params.ledgpio,
index bcf2a97..c42d3fa 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/delay.h>
 #include <linux/if_arp.h>
 #include <linux/netdevice.h>
-
+#include <asm/unaligned.h>
 #include <net/iw_handler.h>
 
 #include "host.h"
@@ -154,11 +154,11 @@ static int lbs_ret_802_11_rssi(struct lbs_private *priv,
        lbs_deb_enter(LBS_DEB_CMD);
 
        /* store the non average value */
-       priv->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR);
-       priv->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor);
+       priv->SNR[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->SNR);
+       priv->NF[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->noisefloor);
 
-       priv->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR);
-       priv->NF[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgnoisefloor);
+       priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR);
+       priv->NF[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgnoisefloor);
 
        priv->RSSI[TYPE_BEACON][TYPE_NOAVG] =
            CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
@@ -210,12 +210,6 @@ static inline int handle_cmd_response(struct lbs_private *priv,
                ret = lbs_ret_reg_access(priv, respcmd, resp);
                break;
 
-       case CMD_RET_802_11_ASSOCIATE:
-       case CMD_RET(CMD_802_11_ASSOCIATE):
-       case CMD_RET(CMD_802_11_REASSOCIATE):
-               ret = lbs_ret_80211_associate(priv, resp);
-               break;
-
        case CMD_RET(CMD_802_11_SET_AFC):
        case CMD_RET(CMD_802_11_GET_AFC):
                spin_lock_irqsave(&priv->driver_lock, flags);
@@ -225,7 +219,6 @@ static inline int handle_cmd_response(struct lbs_private *priv,
 
                break;
 
-       case CMD_RET(CMD_802_11_AUTHENTICATE):
        case CMD_RET(CMD_802_11_BEACON_STOP):
                break;
 
index 50e28a0..811ffc3 100644 (file)
@@ -183,12 +183,12 @@ out_unlock:
  */
 static void *lbs_tlv_find(uint16_t tlv_type, const uint8_t *tlv, uint16_t size)
 {
-       struct mrvlietypesheader *tlv_h;
+       struct mrvl_ie_header *tlv_h;
        uint16_t length;
        ssize_t pos = 0;
 
        while (pos < size) {
-               tlv_h = (struct mrvlietypesheader *) tlv;
+               tlv_h = (struct mrvl_ie_header *) tlv;
                if (!tlv_h->len)
                        return NULL;
                if (tlv_h->type == cpu_to_le16(tlv_type))
@@ -206,7 +206,7 @@ static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask,
                                  size_t count, loff_t *ppos)
 {
        struct cmd_ds_802_11_subscribe_event *subscribed;
-       struct mrvlietypes_thresholds *got;
+       struct mrvl_ie_thresholds *got;
        struct lbs_private *priv = file->private_data;
        ssize_t ret = 0;
        size_t pos = 0;
@@ -259,7 +259,7 @@ static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask,
                                   loff_t *ppos)
 {
        struct cmd_ds_802_11_subscribe_event *events;
-       struct mrvlietypes_thresholds *tlv;
+       struct mrvl_ie_thresholds *tlv;
        struct lbs_private *priv = file->private_data;
        ssize_t buf_size;
        int value, freq, new_mask;
index a4455ec..f9ec69e 100644 (file)
@@ -321,8 +321,6 @@ struct lbs_private {
 
        u32 monitormode;
        u8 fw_ready;
-       u8 fn_init_required;
-       u8 fn_shutdown_required;
 };
 
 extern struct cmd_confirm_sleep confirm_sleep;
@@ -340,7 +338,7 @@ struct bss_descriptor {
        u32 rssi;
        u32 channel;
        u16 beaconperiod;
-       u32 atimwindow;
+       __le16 atimwindow;
 
        /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */
        u8 mode;
@@ -350,10 +348,10 @@ struct bss_descriptor {
 
        unsigned long last_scanned;
 
-       union ieeetypes_phyparamset phyparamset;
-       union IEEEtypes_ssparamset ssparamset;
+       union ieee_phy_param_set phy;
+       union ieee_ss_param_set ss;
 
-       struct ieeetypes_countryinfofullset countryinfo;
+       struct ieee_ie_country_info_full_set countryinfo;
 
        u8 wpa_ie[MAX_WPA_IE_LEN];
        size_t wpa_ie_len;
index 391c54a..0a2e291 100644 (file)
@@ -250,7 +250,9 @@ struct cmd_ds_gspi_bus_config {
 } __attribute__ ((packed));
 
 struct cmd_ds_802_11_authenticate {
-       u8 macaddr[ETH_ALEN];
+       struct cmd_header hdr;
+
+       u8 bssid[ETH_ALEN];
        u8 authtype;
        u8 reserved[10];
 } __attribute__ ((packed));
@@ -263,22 +265,23 @@ struct cmd_ds_802_11_deauthenticate {
 } __attribute__ ((packed));
 
 struct cmd_ds_802_11_associate {
-       u8 peerstaaddr[6];
+       struct cmd_header hdr;
+
+       u8 bssid[6];
        __le16 capability;
        __le16 listeninterval;
        __le16 bcnperiod;
        u8 dtimperiod;
-
-#if 0
-       mrvlietypes_ssidparamset_t ssidParamSet;
-       mrvlietypes_phyparamset_t phyparamset;
-       mrvlietypes_ssparamset_t ssparamset;
-       mrvlietypes_ratesparamset_t ratesParamSet;
-#endif
+       u8 iebuf[512];    /* Enough for required and most optional IEs */
 } __attribute__ ((packed));
 
-struct cmd_ds_802_11_associate_rsp {
-       struct ieeetypes_assocrsp assocRsp;
+struct cmd_ds_802_11_associate_response {
+       struct cmd_header hdr;
+
+       __le16 capability;
+       __le16 statuscode;
+       __le16 aid;
+       u8 iebuf[512];
 } __attribute__ ((packed));
 
 struct cmd_ds_802_11_set_wep {
@@ -535,9 +538,11 @@ struct cmd_ds_802_11_ad_hoc_start {
        u8 bsstype;
        __le16 beaconperiod;
        u8 dtimperiod;   /* Reserved on v9 and later */
-       union IEEEtypes_ssparamset ssparamset;
-       union ieeetypes_phyparamset phyparamset;
-       __le16 probedelay;
+       struct ieee_ie_ibss_param_set ibss;
+       u8 reserved1[4];
+       struct ieee_ie_ds_param_set ds;
+       u8 reserved2[4];
+       __le16 probedelay;  /* Reserved on v9 and later */
        __le16 capability;
        u8 rates[MAX_RATES];
        u8 tlv_memory_size_pad[100];
@@ -558,8 +563,10 @@ struct adhoc_bssdesc {
        u8 dtimperiod;
        __le64 timestamp;
        __le64 localtime;
-       union ieeetypes_phyparamset phyparamset;
-       union IEEEtypes_ssparamset ssparamset;
+       struct ieee_ie_ds_param_set ds;
+       u8 reserved1[4];
+       struct ieee_ie_ibss_param_set ibss;
+       u8 reserved2[4];
        __le16 capability;
        u8 rates[MAX_RATES];
 
@@ -765,8 +772,6 @@ struct cmd_ds_command {
        /* command Body */
        union {
                struct cmd_ds_802_11_ps_mode psmode;
-               struct cmd_ds_802_11_associate associate;
-               struct cmd_ds_802_11_authenticate auth;
                struct cmd_ds_802_11_get_stat gstat;
                struct cmd_ds_802_3_get_stat gstat_8023;
                struct cmd_ds_802_11_rf_antenna rant;
index a7e3fc1..8cdb88c 100644 (file)
 #include "decl.h"
 #include "defs.h"
 #include "dev.h"
+#include "cmd.h"
 #include "if_sdio.h"
 
+/* The if_sdio_remove() callback function is called when
+ * user removes this module from kernel space or ejects
+ * the card from the slot. The driver handles these 2 cases
+ * differently for SD8688 combo chip.
+ * If the user is removing the module, the FUNC_SHUTDOWN
+ * command for SD8688 is sent to the firmware.
+ * If the card is removed, there is no need to send this command.
+ *
+ * The variable 'user_rmmod' is used to distinguish these two
+ * scenarios. This flag is initialized as FALSE in case the card
+ * is removed, and will be set to TRUE for module removal when
+ * module_exit function is called.
+ */
+static u8 user_rmmod;
+
 static char *lbs_helper_name = NULL;
 module_param_named(helper_name, lbs_helper_name, charp, 0644);
 
@@ -61,7 +77,6 @@ struct if_sdio_model {
        int model;
        const char *helper;
        const char *firmware;
-       struct if_sdio_card *card;
 };
 
 static struct if_sdio_model if_sdio_models[] = {
@@ -70,21 +85,18 @@ static struct if_sdio_model if_sdio_models[] = {
                .model = IF_SDIO_MODEL_8385,
                .helper = "sd8385_helper.bin",
                .firmware = "sd8385.bin",
-               .card = NULL,
        },
        {
                /* 8686 */
                .model = IF_SDIO_MODEL_8686,
                .helper = "sd8686_helper.bin",
                .firmware = "sd8686.bin",
-               .card = NULL,
        },
        {
                /* 8688 */
                .model = IF_SDIO_MODEL_8688,
                .helper = "sd8688_helper.bin",
                .firmware = "sd8688.bin",
-               .card = NULL,
        },
 };
 
@@ -927,8 +939,6 @@ static int if_sdio_probe(struct sdio_func *func,
                goto free;
        }
 
-       if_sdio_models[i].card = card;
-
        card->helper = if_sdio_models[i].helper;
        card->firmware = if_sdio_models[i].firmware;
 
@@ -1014,8 +1024,16 @@ static int if_sdio_probe(struct sdio_func *func,
        /*
         * FUNC_INIT is required for SD8688 WLAN/BT multiple functions
         */
-       priv->fn_init_required =
-               (card->model == IF_SDIO_MODEL_8688) ? 1 : 0;
+       if (card->model == IF_SDIO_MODEL_8688) {
+               struct cmd_header cmd;
+
+               memset(&cmd, 0, sizeof(cmd));
+
+               lbs_deb_sdio("send function INIT command\n");
+               if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
+                               lbs_cmd_copyback, (unsigned long) &cmd))
+                       lbs_pr_alert("CMD_FUNC_INIT cmd failed\n");
+       }
 
        ret = lbs_start_card(priv);
        if (ret)
@@ -1057,30 +1075,39 @@ static void if_sdio_remove(struct sdio_func *func)
 {
        struct if_sdio_card *card;
        struct if_sdio_packet *packet;
-       int ret;
 
        lbs_deb_enter(LBS_DEB_SDIO);
 
        card = sdio_get_drvdata(func);
 
-       lbs_stop_card(card->priv);
+       if (user_rmmod && (card->model == IF_SDIO_MODEL_8688)) {
+               /*
+                * FUNC_SHUTDOWN is required for SD8688 WLAN/BT
+                * multiple functions
+                */
+               struct cmd_header cmd;
+
+               memset(&cmd, 0, sizeof(cmd));
+
+               lbs_deb_sdio("send function SHUTDOWN command\n");
+               if (__lbs_cmd(card->priv, CMD_FUNC_SHUTDOWN,
+                               &cmd, sizeof(cmd), lbs_cmd_copyback,
+                               (unsigned long) &cmd))
+                       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);
 
        flush_workqueue(card->workqueue);
        destroy_workqueue(card->workqueue);
 
        sdio_claim_host(func);
-
-       /* Disable interrupts */
-       sdio_writeb(func, 0x00, IF_SDIO_H_INT_MASK, &ret);
-
        sdio_release_irq(func);
        sdio_disable_func(func);
-
        sdio_release_host(func);
 
        while (card->packets) {
@@ -1116,6 +1143,9 @@ static int __init if_sdio_init_module(void)
 
        ret = sdio_register_driver(&if_sdio_driver);
 
+       /* Clear the flag in case user removes the card. */
+       user_rmmod = 0;
+
        lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
 
        return ret;
@@ -1123,22 +1153,10 @@ static int __init if_sdio_init_module(void)
 
 static void __exit if_sdio_exit_module(void)
 {
-       int i;
-       struct if_sdio_card *card;
-
        lbs_deb_enter(LBS_DEB_SDIO);
 
-       for (i = 0; i < ARRAY_SIZE(if_sdio_models); i++) {
-               card = if_sdio_models[i].card;
-
-               /*
-                * FUNC_SHUTDOWN is required for SD8688 WLAN/BT
-                * multiple functions
-                */
-               if (card && card->priv)
-                       card->priv->fn_shutdown_required =
-                               (card->model == IF_SDIO_MODEL_8688) ? 1 : 0;
-       }
+       /* Set the flag as user is removing this module. */
+       user_rmmod = 1;
 
        sdio_unregister_driver(&if_sdio_driver);
 
index 5fa55fe..f8c2898 100644 (file)
@@ -19,7 +19,6 @@
 
 #include <linux/moduleparam.h>
 #include <linux/firmware.h>
-#include <linux/gpio.h>
 #include <linux/jiffies.h>
 #include <linux/kthread.h>
 #include <linux/list.h>
@@ -51,13 +50,6 @@ struct if_spi_card {
        u16                             card_id;
        u8                              card_rev;
 
-       /* Pin number for our GPIO chip-select. */
-       /* TODO: Once the generic SPI layer has some additional features, we
-        * should take this out and use the normal chip select here.
-        * We need support for chip select delays, and not dropping chipselect
-        * after each word. */
-       int                             gpio_cs;
-
        /* The last time that we initiated an SPU operation */
        unsigned long                   prev_xfer_time;
 
@@ -119,9 +111,6 @@ static struct chip_ident chip_id_to_device_name[] = {
  * First we have to put a SPU register name on the bus. Then we can
  * either read from or write to that register.
  *
- * For 16-bit transactions, byte order on the bus is big-endian.
- * We don't have to worry about that here, though.
- * The translation takes place in the SPI routines.
  */
 
 static void spu_transaction_init(struct if_spi_card *card)
@@ -133,12 +122,10 @@ static void spu_transaction_init(struct if_spi_card *card)
                 * If not, we have to busy-wait to be on the safe side. */
                ndelay(400);
        }
-       gpio_set_value(card->gpio_cs, 0); /* assert CS */
 }
 
 static void spu_transaction_finish(struct if_spi_card *card)
 {
-       gpio_set_value(card->gpio_cs, 1); /* drop CS */
        card->prev_xfer_time = jiffies;
 }
 
@@ -147,7 +134,14 @@ static void spu_transaction_finish(struct if_spi_card *card)
 static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len)
 {
        int err = 0;
-       u16 reg_out = reg | IF_SPI_WRITE_OPERATION_MASK;
+       u16 reg_out = cpu_to_le16(reg | IF_SPI_WRITE_OPERATION_MASK);
+       struct spi_message m;
+       struct spi_transfer reg_trans;
+       struct spi_transfer data_trans;
+
+       spi_message_init(&m);
+       memset(&reg_trans, 0, sizeof(reg_trans));
+       memset(&data_trans, 0, sizeof(data_trans));
 
        /* You must give an even number of bytes to the SPU, even if it
         * doesn't care about the last one.  */
@@ -156,29 +150,26 @@ static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len)
        spu_transaction_init(card);
 
        /* write SPU register index */
-       err = spi_write(card->spi, (u8 *)&reg_out, sizeof(u16));
-       if (err)
-               goto out;
+       reg_trans.tx_buf = &reg_out;
+       reg_trans.len = sizeof(reg_out);
 
-       err = spi_write(card->spi, buf, len);
+       data_trans.tx_buf = buf;
+       data_trans.len = len;
 
-out:
+       spi_message_add_tail(&reg_trans, &m);
+       spi_message_add_tail(&data_trans, &m);
+
+       err = spi_sync(card->spi, &m);
        spu_transaction_finish(card);
        return err;
 }
 
 static inline int spu_write_u16(struct if_spi_card *card, u16 reg, u16 val)
 {
-       return spu_write(card, reg, (u8 *)&val, sizeof(u16));
-}
+       u16 buff;
 
-static inline int spu_write_u32(struct if_spi_card *card, u16 reg, u32 val)
-{
-       /* The lower 16 bits are written first. */
-       u16 out[2];
-       out[0] = val & 0xffff;
-       out[1] = (val & 0xffff0000) >> 16;
-       return spu_write(card, reg, (u8 *)&out, sizeof(u32));
+       buff = cpu_to_le16(val);
+       return spu_write(card, reg, (u8 *)&buff, sizeof(u16));
 }
 
 static inline int spu_reg_is_port_reg(u16 reg)
@@ -195,10 +186,13 @@ static inline int spu_reg_is_port_reg(u16 reg)
 
 static int spu_read(struct if_spi_card *card, u16 reg, u8 *buf, int len)
 {
-       unsigned int i, delay;
+       unsigned int delay;
        int err = 0;
-       u16 zero = 0;
-       u16 reg_out = reg | IF_SPI_READ_OPERATION_MASK;
+       u16 reg_out = cpu_to_le16(reg | IF_SPI_READ_OPERATION_MASK);
+       struct spi_message m;
+       struct spi_transfer reg_trans;
+       struct spi_transfer dummy_trans;
+       struct spi_transfer data_trans;
 
        /* You must take an even number of bytes from the SPU, even if you
         * don't care about the last one.  */
@@ -206,29 +200,34 @@ static int spu_read(struct if_spi_card *card, u16 reg, u8 *buf, int len)
 
        spu_transaction_init(card);
 
+       spi_message_init(&m);
+       memset(&reg_trans, 0, sizeof(reg_trans));
+       memset(&dummy_trans, 0, sizeof(dummy_trans));
+       memset(&data_trans, 0, sizeof(data_trans));
+
        /* write SPU register index */
-       err = spi_write(card->spi, (u8 *)&reg_out, sizeof(u16));
-       if (err)
-               goto out;
+       reg_trans.tx_buf = &reg_out;
+       reg_trans.len = sizeof(reg_out);
+       spi_message_add_tail(&reg_trans, &m);
 
        delay = spu_reg_is_port_reg(reg) ? card->spu_port_delay :
                                                card->spu_reg_delay;
        if (card->use_dummy_writes) {
                /* Clock in dummy cycles while the SPU fills the FIFO */
-               for (i = 0; i < delay / 16; ++i) {
-                       err = spi_write(card->spi, (u8 *)&zero, sizeof(u16));
-                       if (err)
-                               return err;
-               }
+               dummy_trans.len = delay / 8;
+               spi_message_add_tail(&dummy_trans, &m);
        } else {
                /* Busy-wait while the SPU fills the FIFO */
-               ndelay(100 + (delay * 10));
+               reg_trans.delay_usecs =
+                       DIV_ROUND_UP((100 + (delay * 10)), 1000);
        }
 
        /* read in data */
-       err = spi_read(card->spi, buf, len);
+       data_trans.rx_buf = buf;
+       data_trans.len = len;
+       spi_message_add_tail(&data_trans, &m);
 
-out:
+       err = spi_sync(card->spi, &m);
        spu_transaction_finish(card);
        return err;
 }
@@ -236,18 +235,25 @@ out:
 /* Read 16 bits from an SPI register */
 static inline int spu_read_u16(struct if_spi_card *card, u16 reg, u16 *val)
 {
-       return spu_read(card, reg, (u8 *)val, sizeof(u16));
+       u16 buf;
+       int ret;
+
+       ret = spu_read(card, reg, (u8 *)&buf, sizeof(buf));
+       if (ret == 0)
+               *val = le16_to_cpup(&buf);
+       return ret;
 }
 
 /* Read 32 bits from an SPI register.
  * The low 16 bits are read first. */
 static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val)
 {
-       u16 buf[2];
+       u32 buf;
        int err;
-       err = spu_read(card, reg, (u8 *)buf, sizeof(u32));
+
+       err = spu_read(card, reg, (u8 *)&buf, sizeof(buf));
        if (!err)
-               *val = buf[0] | (buf[1] << 16);
+               *val = le32_to_cpup(&buf);
        return err;
 }
 
@@ -1051,7 +1057,6 @@ static int __devinit if_spi_probe(struct spi_device *spi)
        spi_set_drvdata(spi, card);
        card->pdata = pdata;
        card->spi = spi;
-       card->gpio_cs = pdata->gpio_cs;
        card->prev_xfer_time = jiffies;
 
        sema_init(&card->spi_ready, 0);
@@ -1060,26 +1065,18 @@ static int __devinit if_spi_probe(struct spi_device *spi)
        INIT_LIST_HEAD(&card->data_packet_list);
        spin_lock_init(&card->buffer_lock);
 
-       /* set up GPIO CS line. TODO: use  regular CS line */
-       err = gpio_request(card->gpio_cs, "if_spi_gpio_chip_select");
-       if (err)
-               goto free_card;
-       err = gpio_direction_output(card->gpio_cs, 1);
-       if (err)
-               goto free_gpio;
-
        /* Initialize the SPI Interface Unit */
        err = spu_init(card, pdata->use_dummy_writes);
        if (err)
-               goto free_gpio;
+               goto free_card;
        err = spu_get_chip_revision(card, &card->card_id, &card->card_rev);
        if (err)
-               goto free_gpio;
+               goto free_card;
 
        /* Firmware load */
        err = spu_read_u32(card, IF_SPI_SCRATCH_4_REG, &scratch);
        if (err)
-               goto free_gpio;
+               goto free_card;
        if (scratch == SUCCESSFUL_FW_DOWNLOAD_MAGIC)
                lbs_deb_spi("Firmware is already loaded for "
                            "Marvell WLAN 802.11 adapter\n");
@@ -1087,7 +1084,7 @@ static int __devinit if_spi_probe(struct spi_device *spi)
                err = if_spi_calculate_fw_names(card->card_id,
                                card->helper_fw_name, card->main_fw_name);
                if (err)
-                       goto free_gpio;
+                       goto free_card;
 
                lbs_deb_spi("Initializing FW for Marvell WLAN 802.11 adapter "
                                "(chip_id = 0x%04x, chip_rev = 0x%02x) "
@@ -1098,23 +1095,23 @@ static int __devinit if_spi_probe(struct spi_device *spi)
                                spi->max_speed_hz);
                err = if_spi_prog_helper_firmware(card);
                if (err)
-                       goto free_gpio;
+                       goto free_card;
                err = if_spi_prog_main_firmware(card);
                if (err)
-                       goto free_gpio;
+                       goto free_card;
                lbs_deb_spi("loaded FW for Marvell WLAN 802.11 adapter\n");
        }
 
        err = spu_set_interrupt_mode(card, 0, 1);
        if (err)
-               goto free_gpio;
+               goto free_card;
 
        /* Register our card with libertas.
         * This will call alloc_etherdev */
        priv = lbs_add_card(card, &spi->dev);
        if (!priv) {
                err = -ENOMEM;
-               goto free_gpio;
+               goto free_card;
        }
        card->priv = priv;
        priv->card = card;
@@ -1159,8 +1156,6 @@ terminate_thread:
        if_spi_terminate_spi_thread(card);
 remove_card:
        lbs_remove_card(priv); /* will call free_netdev */
-free_gpio:
-       gpio_free(card->gpio_cs);
 free_card:
        free_if_spi_card(card);
 out:
@@ -1181,7 +1176,6 @@ static int __devexit libertas_spi_remove(struct spi_device *spi)
        free_irq(spi->irq, card);
        if_spi_terminate_spi_thread(card);
        lbs_remove_card(priv); /* will call free_netdev */
-       gpio_free(card->gpio_cs);
        if (card->pdata->teardown)
                card->pdata->teardown(spi);
        free_if_spi_card(card);
index a58a123..89575e4 100644 (file)
@@ -1002,17 +1002,9 @@ static int lbs_setup_firmware(struct lbs_private *priv)
 {
        int ret = -1;
        s16 curlevel = 0, minlevel = 0, maxlevel = 0;
-       struct cmd_header cmd;
 
        lbs_deb_enter(LBS_DEB_FW);
 
-       if (priv->fn_init_required) {
-               memset(&cmd, 0, sizeof(cmd));
-               if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
-                               lbs_cmd_copyback, (unsigned long) &cmd))
-                       lbs_pr_alert("CMD_FUNC_INIT command failed\n");
-       }
-
        /* Read MAC address from firmware */
        memset(priv->current_addr, 0xff, ETH_ALEN);
        ret = lbs_update_hw_spec(priv);
@@ -1200,9 +1192,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
        priv->mesh_open = 0;
        priv->infra_open = 0;
 
-       priv->fn_init_required = 0;
-       priv->fn_shutdown_required = 0;
-
        /* Setup the OS Interface to our functions */
        dev->netdev_ops = &lbs_netdev_ops;
        dev->watchdog_timeo = 5 * HZ;
@@ -1384,20 +1373,11 @@ void lbs_stop_card(struct lbs_private *priv)
        struct net_device *dev;
        struct cmd_ctrl_node *cmdnode;
        unsigned long flags;
-       struct cmd_header cmd;
 
        lbs_deb_enter(LBS_DEB_MAIN);
 
        if (!priv)
                goto out;
-
-       if (priv->fn_shutdown_required) {
-               memset(&cmd, 0, sizeof(cmd));
-               if (__lbs_cmd(priv, CMD_FUNC_SHUTDOWN, &cmd, sizeof(cmd),
-                               lbs_cmd_copyback, (unsigned long) &cmd))
-                       lbs_pr_alert("CMD_FUNC_SHUTDOWN command failed\n");
-       }
-
        dev = priv->dev;
 
        netif_stop_queue(dev);
index 8124db3..601b542 100644 (file)
                              + 40)     /* 40 for WPAIE */
 
 //! Memory needed to store a max sized channel List TLV for a firmware scan
-#define CHAN_TLV_MAX_SIZE  (sizeof(struct mrvlietypesheader)    \
+#define CHAN_TLV_MAX_SIZE  (sizeof(struct mrvl_ie_header)    \
                             + (MRVDRV_MAX_CHANNELS_PER_SCAN     \
                                * sizeof(struct chanscanparamset)))
 
 //! Memory needed to store a max number/size SSID TLV for a firmware scan
-#define SSID_TLV_MAX_SIZE  (1 * sizeof(struct mrvlietypes_ssidparamset))
+#define SSID_TLV_MAX_SIZE  (1 * sizeof(struct mrvl_ie_ssid_param_set))
 
 //! Maximum memory needed for a cmd_ds_802_11_scan with all TLVs at max
 #define MAX_SCAN_CFG_ALLOC (sizeof(struct cmd_ds_802_11_scan)  \
@@ -211,7 +211,7 @@ static int lbs_scan_create_channel_list(struct lbs_private *priv,
  */
 static int lbs_scan_add_ssid_tlv(struct lbs_private *priv, u8 *tlv)
 {
-       struct mrvlietypes_ssidparamset *ssid_tlv = (void *)tlv;
+       struct mrvl_ie_ssid_param_set *ssid_tlv = (void *)tlv;
 
        ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
        ssid_tlv->header.len = cpu_to_le16(priv->scan_ssid_len);
@@ -249,7 +249,7 @@ static int lbs_scan_add_chanlist_tlv(uint8_t *tlv,
                                     int chan_count)
 {
        size_t size = sizeof(struct chanscanparamset) *chan_count;
-       struct mrvlietypes_chanlistparamset *chan_tlv = (void *)tlv;
+       struct mrvl_ie_chanlist_param_set *chan_tlv = (void *)tlv;
 
        chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
        memcpy(chan_tlv->chanscanparam, chan_list, size);
@@ -270,7 +270,7 @@ static int lbs_scan_add_chanlist_tlv(uint8_t *tlv,
 static int lbs_scan_add_rates_tlv(uint8_t *tlv)
 {
        int i;
-       struct mrvlietypes_ratesparamset *rate_tlv = (void *)tlv;
+       struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv;
 
        rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
        tlv += sizeof(rate_tlv->header);
@@ -513,12 +513,12 @@ void lbs_scan_worker(struct work_struct *work)
 static int lbs_process_bss(struct bss_descriptor *bss,
                           uint8_t **pbeaconinfo, int *bytesleft)
 {
-       struct ieeetypes_fhparamset *pFH;
-       struct ieeetypes_dsparamset *pDS;
-       struct ieeetypes_cfparamset *pCF;
-       struct ieeetypes_ibssparamset *pibss;
+       struct ieee_ie_fh_param_set *fh;
+       struct ieee_ie_ds_param_set *ds;
+       struct ieee_ie_cf_param_set *cf;
+       struct ieee_ie_ibss_param_set *ibss;
        DECLARE_SSID_BUF(ssid);
-       struct ieeetypes_countryinfoset *pcountryinfo;
+       struct ieee_ie_country_info_set *pcountryinfo;
        uint8_t *pos, *end, *p;
        uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;
        uint16_t beaconsize = 0;
@@ -616,50 +616,49 @@ static int lbs_process_bss(struct bss_descriptor *bss,
                        break;
 
                case WLAN_EID_FH_PARAMS:
-                       pFH = (struct ieeetypes_fhparamset *) pos;
-                       memmove(&bss->phyparamset.fhparamset, pFH,
-                               sizeof(struct ieeetypes_fhparamset));
+                       fh = (struct ieee_ie_fh_param_set *) pos;
+                       memcpy(&bss->phy.fh, fh, sizeof(*fh));
                        lbs_deb_scan("got FH IE\n");
                        break;
 
                case WLAN_EID_DS_PARAMS:
-                       pDS = (struct ieeetypes_dsparamset *) pos;
-                       bss->channel = pDS->currentchan;
-                       memcpy(&bss->phyparamset.dsparamset, pDS,
-                              sizeof(struct ieeetypes_dsparamset));
+                       ds = (struct ieee_ie_ds_param_set *) pos;
+                       bss->channel = ds->channel;
+                       memcpy(&bss->phy.ds, ds, sizeof(*ds));
                        lbs_deb_scan("got DS IE, channel %d\n", bss->channel);
                        break;
 
                case WLAN_EID_CF_PARAMS:
-                       pCF = (struct ieeetypes_cfparamset *) pos;
-                       memcpy(&bss->ssparamset.cfparamset, pCF,
-                              sizeof(struct ieeetypes_cfparamset));
+                       cf = (struct ieee_ie_cf_param_set *) pos;
+                       memcpy(&bss->ss.cf, cf, sizeof(*cf));
                        lbs_deb_scan("got CF IE\n");
                        break;
 
                case WLAN_EID_IBSS_PARAMS:
-                       pibss = (struct ieeetypes_ibssparamset *) pos;
-                       bss->atimwindow = le16_to_cpu(pibss->atimwindow);
-                       memmove(&bss->ssparamset.ibssparamset, pibss,
-                               sizeof(struct ieeetypes_ibssparamset));
+                       ibss = (struct ieee_ie_ibss_param_set *) pos;
+                       bss->atimwindow = ibss->atimwindow;
+                       memcpy(&bss->ss.ibss, ibss, sizeof(*ibss));
                        lbs_deb_scan("got IBSS IE\n");
                        break;
 
                case WLAN_EID_COUNTRY:
-                       pcountryinfo = (struct ieeetypes_countryinfoset *) pos;
+                       pcountryinfo = (struct ieee_ie_country_info_set *) pos;
                        lbs_deb_scan("got COUNTRY IE\n");
-                       if (pcountryinfo->len < sizeof(pcountryinfo->countrycode)
-                           || pcountryinfo->len > 254) {
-                               lbs_deb_scan("process_bss: 11D- Err CountryInfo len %d, min %zd, max 254\n",
-                                            pcountryinfo->len, sizeof(pcountryinfo->countrycode));
+                       if (pcountryinfo->header.len < sizeof(pcountryinfo->countrycode)
+                           || pcountryinfo->header.len > 254) {
+                               lbs_deb_scan("%s: 11D- Err CountryInfo len %d, min %zd, max 254\n",
+                                            __func__,
+                                            pcountryinfo->header.len,
+                                            sizeof(pcountryinfo->countrycode));
                                ret = -1;
                                goto done;
                        }
 
-                       memcpy(&bss->countryinfo, pcountryinfo, pcountryinfo->len + 2);
+                       memcpy(&bss->countryinfo, pcountryinfo,
+                               pcountryinfo->header.len + 2);
                        lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo",
                                    (uint8_t *) pcountryinfo,
-                                   (int) (pcountryinfo->len + 2));
+                                   (int) (pcountryinfo->header.len + 2));
                        break;
 
                case WLAN_EID_EXT_SUPP_RATES:
@@ -1130,7 +1129,7 @@ static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,
                goto done;
        }
 
-       bytesleft = le16_to_cpu(scanresp->bssdescriptsize);
+       bytesleft = get_unaligned_le16(&scanresp->bssdescriptsize);
        lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft);
 
        scanrespsize = le16_to_cpu(resp->size);
index de03b9c..99905df 100644 (file)
@@ -8,9 +8,14 @@
 #include <asm/byteorder.h>
 #include <linux/wireless.h>
 
-struct ieeetypes_cfparamset {
-       u8 elementid;
+struct ieee_ie_header {
+       u8 id;
        u8 len;
+} __attribute__ ((packed));
+
+struct ieee_ie_cf_param_set {
+       struct ieee_ie_header header;
+
        u8 cfpcnt;
        u8 cfpperiod;
        __le16 cfpmaxduration;
@@ -18,42 +23,35 @@ struct ieeetypes_cfparamset {
 } __attribute__ ((packed));
 
 
-struct ieeetypes_ibssparamset {
-       u8 elementid;
-       u8 len;
+struct ieee_ie_ibss_param_set {
+       struct ieee_ie_header header;
+
        __le16 atimwindow;
 } __attribute__ ((packed));
 
-union IEEEtypes_ssparamset {
-       struct ieeetypes_cfparamset cfparamset;
-       struct ieeetypes_ibssparamset ibssparamset;
+union ieee_ss_param_set {
+       struct ieee_ie_cf_param_set cf;
+       struct ieee_ie_ibss_param_set ibss;
 } __attribute__ ((packed));
 
-struct ieeetypes_fhparamset {
-       u8 elementid;
-       u8 len;
+struct ieee_ie_fh_param_set {
+       struct ieee_ie_header header;
+
        __le16 dwelltime;
        u8 hopset;
        u8 hoppattern;
        u8 hopindex;
 } __attribute__ ((packed));
 
-struct ieeetypes_dsparamset {
-       u8 elementid;
-       u8 len;
-       u8 currentchan;
-} __attribute__ ((packed));
+struct ieee_ie_ds_param_set {
+       struct ieee_ie_header header;
 
-union ieeetypes_phyparamset {
-       struct ieeetypes_fhparamset fhparamset;
-       struct ieeetypes_dsparamset dsparamset;
+       u8 channel;
 } __attribute__ ((packed));
 
-struct ieeetypes_assocrsp {
-       __le16 capability;
-       __le16 statuscode;
-       __le16 aid;
-       u8 iebuffer[1];
+union ieee_phy_param_set {
+       struct ieee_ie_fh_param_set fh;
+       struct ieee_ie_ds_param_set ds;
 } __attribute__ ((packed));
 
 /** TLV  type ID definition */
@@ -94,32 +92,33 @@ struct ieeetypes_assocrsp {
 #define TLV_TYPE_TSFTIMESTAMP      (PROPRIETARY_TLV_BASE_ID + 19)
 #define TLV_TYPE_RSSI_HIGH          (PROPRIETARY_TLV_BASE_ID + 22)
 #define TLV_TYPE_SNR_HIGH           (PROPRIETARY_TLV_BASE_ID + 23)
+#define TLV_TYPE_AUTH_TYPE          (PROPRIETARY_TLV_BASE_ID + 31)
 #define TLV_TYPE_MESH_ID            (PROPRIETARY_TLV_BASE_ID + 37)
 #define TLV_TYPE_OLD_MESH_ID        (PROPRIETARY_TLV_BASE_ID + 291)
 
 /** TLV related data structures*/
-struct mrvlietypesheader {
+struct mrvl_ie_header {
        __le16 type;
        __le16 len;
 } __attribute__ ((packed));
 
-struct mrvlietypes_data {
-       struct mrvlietypesheader header;
+struct mrvl_ie_data {
+       struct mrvl_ie_header header;
        u8 Data[1];
 } __attribute__ ((packed));
 
-struct mrvlietypes_ratesparamset {
-       struct mrvlietypesheader header;
+struct mrvl_ie_rates_param_set {
+       struct mrvl_ie_header header;
        u8 rates[1];
 } __attribute__ ((packed));
 
-struct mrvlietypes_ssidparamset {
-       struct mrvlietypesheader header;
+struct mrvl_ie_ssid_param_set {
+       struct mrvl_ie_header header;
        u8 ssid[1];
 } __attribute__ ((packed));
 
-struct mrvlietypes_wildcardssidparamset {
-       struct mrvlietypesheader header;
+struct mrvl_ie_wildcard_ssid_param_set {
+       struct mrvl_ie_header header;
        u8 MaxSsidlength;
        u8 ssid[1];
 } __attribute__ ((packed));
@@ -144,91 +143,72 @@ struct chanscanparamset {
        __le16 maxscantime;
 } __attribute__ ((packed));
 
-struct mrvlietypes_chanlistparamset {
-       struct mrvlietypesheader header;
+struct mrvl_ie_chanlist_param_set {
+       struct mrvl_ie_header header;
        struct chanscanparamset chanscanparam[1];
 } __attribute__ ((packed));
 
-struct cfparamset {
+struct mrvl_ie_cf_param_set {
+       struct mrvl_ie_header header;
        u8 cfpcnt;
        u8 cfpperiod;
        __le16 cfpmaxduration;
        __le16 cfpdurationremaining;
 } __attribute__ ((packed));
 
-struct ibssparamset {
-       __le16 atimwindow;
-} __attribute__ ((packed));
-
-struct mrvlietypes_ssparamset {
-       struct mrvlietypesheader header;
-       union {
-               struct cfparamset cfparamset[1];
-               struct ibssparamset ibssparamset[1];
-       } cf_ibss;
+struct mrvl_ie_ds_param_set {
+       struct mrvl_ie_header header;
+       u8 channel;
 } __attribute__ ((packed));
 
-struct fhparamset {
-       __le16 dwelltime;
-       u8 hopset;
-       u8 hoppattern;
-       u8 hopindex;
-} __attribute__ ((packed));
-
-struct dsparamset {
-       u8 currentchan;
-} __attribute__ ((packed));
-
-struct mrvlietypes_phyparamset {
-       struct mrvlietypesheader header;
-       union {
-               struct fhparamset fhparamset[1];
-               struct dsparamset dsparamset[1];
-       } fh_ds;
-} __attribute__ ((packed));
-
-struct mrvlietypes_rsnparamset {
-       struct mrvlietypesheader header;
+struct mrvl_ie_rsn_param_set {
+       struct mrvl_ie_header header;
        u8 rsnie[1];
 } __attribute__ ((packed));
 
-struct mrvlietypes_tsftimestamp {
-       struct mrvlietypesheader header;
+struct mrvl_ie_tsf_timestamp {
+       struct mrvl_ie_header header;
        __le64 tsftable[1];
 } __attribute__ ((packed));
 
+/* v9 and later firmware only */
+struct mrvl_ie_auth_type {
+       struct mrvl_ie_header header;
+       __le16 auth;
+} __attribute__ ((packed));
+
 /**  Local Power capability */
-struct mrvlietypes_powercapability {
-       struct mrvlietypesheader header;
+struct mrvl_ie_power_capability {
+       struct mrvl_ie_header header;
        s8 minpower;
        s8 maxpower;
 } __attribute__ ((packed));
 
 /* used in CMD_802_11_SUBSCRIBE_EVENT for SNR, RSSI and Failure */
-struct mrvlietypes_thresholds {
-       struct mrvlietypesheader header;
+struct mrvl_ie_thresholds {
+       struct mrvl_ie_header header;
        u8 value;
        u8 freq;
 } __attribute__ ((packed));
 
-struct mrvlietypes_beaconsmissed {
-       struct mrvlietypesheader header;
+struct mrvl_ie_beacons_missed {
+       struct mrvl_ie_header header;
        u8 beaconmissed;
        u8 reserved;
 } __attribute__ ((packed));
 
-struct mrvlietypes_numprobes {
-       struct mrvlietypesheader header;
+struct mrvl_ie_num_probes {
+       struct mrvl_ie_header header;
        __le16 numprobes;
 } __attribute__ ((packed));
 
-struct mrvlietypes_bcastprobe {
-       struct mrvlietypesheader header;
+struct mrvl_ie_bcast_probe {
+       struct mrvl_ie_header header;
        __le16 bcastprobe;
 } __attribute__ ((packed));
 
-struct mrvlietypes_numssidprobe {
-       struct mrvlietypesheader header;
+struct mrvl_ie_num_ssid_probe {
+       struct mrvl_ie_header header;
        __le16 numssidprobe;
 } __attribute__ ((packed));
 
@@ -237,8 +217,8 @@ struct led_pin {
        u8 pin;
 } __attribute__ ((packed));
 
-struct mrvlietypes_ledgpio {
-       struct mrvlietypesheader header;
+struct mrvl_ie_ledgpio {
+       struct mrvl_ie_header header;
        struct led_pin ledpin[1];
 } __attribute__ ((packed));
 
@@ -250,8 +230,8 @@ struct led_bhv {
 } __attribute__ ((packed));
 
 
-struct mrvlietypes_ledbhv {
-       struct mrvlietypesheader header;
+struct mrvl_ie_ledbhv {
+       struct mrvl_ie_header header;
        struct led_bhv ledbhv[1];
 } __attribute__ ((packed));
 
index 574b8bb..e789c6e 100644 (file)
@@ -280,7 +280,6 @@ struct mac80211_hwsim_data {
        struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)];
 
        struct ieee80211_channel *channel;
-       int radio_enabled;
        unsigned long beacon_int; /* in jiffies unit */
        unsigned int rx_filter;
        int started;
@@ -418,8 +417,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
                if (data == data2)
                        continue;
 
-               if (!data2->started || !data2->radio_enabled ||
-                   !hwsim_ps_rx_ok(data2, skb) ||
+               if (!data2->started || !hwsim_ps_rx_ok(data2, skb) ||
                    data->channel->center_freq != data2->channel->center_freq ||
                    !(data->group & data2->group))
                        continue;
@@ -441,7 +439,6 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
 
 static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
-       struct mac80211_hwsim_data *data = hw->priv;
        bool ack;
        struct ieee80211_tx_info *txi;
 
@@ -453,13 +450,6 @@ static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
                return NETDEV_TX_OK;
        }
 
-       if (!data->radio_enabled) {
-               printk(KERN_DEBUG "%s: dropped TX frame since radio "
-                      "disabled\n", wiphy_name(hw->wiphy));
-               dev_kfree_skb(skb);
-               return NETDEV_TX_OK;
-       }
-
        ack = mac80211_hwsim_tx_frame(hw, skb);
 
        txi = IEEE80211_SKB_CB(skb);
@@ -546,7 +536,7 @@ static void mac80211_hwsim_beacon(unsigned long arg)
        struct ieee80211_hw *hw = (struct ieee80211_hw *) arg;
        struct mac80211_hwsim_data *data = hw->priv;
 
-       if (!data->started || !data->radio_enabled)
+       if (!data->started)
                return;
 
        ieee80211_iterate_active_interfaces_atomic(
@@ -562,15 +552,14 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
        struct mac80211_hwsim_data *data = hw->priv;
        struct ieee80211_conf *conf = &hw->conf;
 
-       printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d idle=%d ps=%d)\n",
+       printk(KERN_DEBUG "%s:%s (freq=%d idle=%d ps=%d)\n",
               wiphy_name(hw->wiphy), __func__,
-              conf->channel->center_freq, conf->radio_enabled,
+              conf->channel->center_freq,
               !!(conf->flags & IEEE80211_CONF_IDLE),
               !!(conf->flags & IEEE80211_CONF_PS));
 
        data->channel = conf->channel;
-       data->radio_enabled = conf->radio_enabled;
-       if (!data->started || !data->radio_enabled || !data->beacon_int)
+       if (!data->started || !data->beacon_int)
                del_timer(&data->beacon_timer);
        else
                mod_timer(&data->beacon_timer, jiffies + data->beacon_int);
@@ -787,8 +776,7 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
        pspoll->aid = cpu_to_le16(0xc000 | vp->aid);
        memcpy(pspoll->bssid, vp->bssid, ETH_ALEN);
        memcpy(pspoll->ta, mac, ETH_ALEN);
-       if (data->radio_enabled &&
-           !mac80211_hwsim_tx_frame(data->hw, skb))
+       if (!mac80211_hwsim_tx_frame(data->hw, skb))
                printk(KERN_DEBUG "%s: PS-Poll frame not ack'ed\n", __func__);
        dev_kfree_skb(skb);
 }
@@ -819,8 +807,7 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
        memcpy(hdr->addr1, vp->bssid, ETH_ALEN);
        memcpy(hdr->addr2, mac, ETH_ALEN);
        memcpy(hdr->addr3, vp->bssid, ETH_ALEN);
-       if (data->radio_enabled &&
-           !mac80211_hwsim_tx_frame(data->hw, skb))
+       if (!mac80211_hwsim_tx_frame(data->hw, skb))
                printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__);
        dev_kfree_skb(skb);
 }
index 48d81d9..b618bd1 100644 (file)
@@ -823,30 +823,30 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
        struct p54_tx_info *range;
        unsigned long flags;
 
-       if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue)))
+       if (unlikely(!skb || !dev || skb_queue_empty(&priv->tx_queue)))
                return;
 
-       /*
-        * don't try to free an already unlinked skb
+       /* There used to be a check here to see if the SKB was on the
+        * TX queue or not.  This can never happen because all SKBs we
+        * see here successfully went through p54_assign_address()
+        * which means the SKB is on the ->tx_queue.
         */
-       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) {
+       if (!skb_queue_is_first(&priv->tx_queue, skb)) {
                struct ieee80211_tx_info *ni;
                struct p54_tx_info *mr;
 
-               ni = IEEE80211_SKB_CB(skb->prev);
+               ni = IEEE80211_SKB_CB(skb_queue_prev(&priv->tx_queue, skb));
                mr = (struct p54_tx_info *)ni->rate_driver_data;
        }
-       if (skb->next != (struct sk_buff *)&priv->tx_queue) {
+       if (!skb_queue_is_last(&priv->tx_queue, skb)) {
                struct ieee80211_tx_info *ni;
                struct p54_tx_info *mr;
 
-               ni = IEEE80211_SKB_CB(skb->next);
+               ni = IEEE80211_SKB_CB(skb_queue_next(&priv->tx_queue, skb));
                mr = (struct p54_tx_info *)ni->rate_driver_data;
        }
        __skb_unlink(skb, &priv->tx_queue);
@@ -864,15 +864,13 @@ static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev,
        unsigned long flags;
 
        spin_lock_irqsave(&priv->tx_queue.lock, flags);
-       entry = priv->tx_queue.next;
-       while (entry != (struct sk_buff *)&priv->tx_queue) {
+       skb_queue_walk(&priv->tx_queue, entry) {
                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;
@@ -890,24 +888,22 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
        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) {
+       skb_queue_walk(&priv->tx_queue, entry) {
                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;
+               if (range->start_addr != addr)
                        continue;
-               }
 
-               if (entry->next != (struct sk_buff *)&priv->tx_queue) {
+               if (!skb_queue_is_last(&priv->tx_queue, entry)) {
                        struct ieee80211_tx_info *ni;
                        struct p54_tx_info *mr;
 
-                       ni = IEEE80211_SKB_CB(entry->next);
+                       ni = IEEE80211_SKB_CB(skb_queue_next(&priv->tx_queue,
+                                                            entry));
                        mr = (struct p54_tx_info *)ni->rate_driver_data;
                }
 
@@ -1168,23 +1164,21 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
                }
        }
 
-       entry = priv->tx_queue.next;
-       while (left--) {
+       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;
+                       target_skb = skb_queue_prev(&priv->tx_queue, entry);
                        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;
+               target_skb = skb_peek_tail(&priv->tx_queue);
                largest_hole = max(largest_hole, priv->rx_end - last_addr - len);
                if (!skb_queue_empty(&priv->tx_queue)) {
                        info = IEEE80211_SKB_CB(target_skb);
@@ -2090,7 +2084,6 @@ out:
 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;
@@ -2105,8 +2098,7 @@ static void p54_stop(struct ieee80211_hw *dev)
                p54_tx_cancel(dev, priv->cached_beacon);
 
        priv->stop(dev);
-       while ((skb = skb_dequeue(&priv->tx_queue)))
-               kfree_skb(skb);
+       skb_queue_purge(&priv->tx_queue);
        priv->cached_beacon = NULL;
        priv->tsf_high32 = priv->tsf_low32 = 0;
        mutex_unlock(&priv->conf_mutex);
index f40c0f4..0e877a1 100644 (file)
@@ -84,8 +84,8 @@ MODULE_DEVICE_TABLE(usb, p54u_table);
 static const struct {
        u32 intf;
        enum p54u_hw_type type;
-       char fw[FIRMWARE_NAME_MAX];
-       char fw_legacy[FIRMWARE_NAME_MAX];
+       const char *fw;
+       const char *fw_legacy;
        char hw[20];
 } p54u_fwlist[__NUM_P54U_HWTYPES] = {
        {
index c254fdf..7441d55 100644 (file)
@@ -157,55 +157,55 @@ MODULE_PARM_DESC(workaround_interval,
 #define NDIS_802_11_LENGTH_RATES_EX 16
 
 enum ndis_80211_net_type {
-       ndis_80211_type_freq_hop,
-       ndis_80211_type_direct_seq,
-       ndis_80211_type_ofdm_a,
-       ndis_80211_type_ofdm_g
+       NDIS_80211_TYPE_FREQ_HOP,
+       NDIS_80211_TYPE_DIRECT_SEQ,
+       NDIS_80211_TYPE_OFDM_A,
+       NDIS_80211_TYPE_OFDM_G
 };
 
 enum ndis_80211_net_infra {
-       ndis_80211_infra_adhoc,
-       ndis_80211_infra_infra,
-       ndis_80211_infra_auto_unknown
+       NDIS_80211_INFRA_ADHOC,
+       NDIS_80211_INFRA_INFRA,
+       NDIS_80211_INFRA_AUTO_UNKNOWN
 };
 
 enum ndis_80211_auth_mode {
-       ndis_80211_auth_open,
-       ndis_80211_auth_shared,
-       ndis_80211_auth_auto_switch,
-       ndis_80211_auth_wpa,
-       ndis_80211_auth_wpa_psk,
-       ndis_80211_auth_wpa_none,
-       ndis_80211_auth_wpa2,
-       ndis_80211_auth_wpa2_psk
+       NDIS_80211_AUTH_OPEN,
+       NDIS_80211_AUTH_SHARED,
+       NDIS_80211_AUTH_AUTO_SWITCH,
+       NDIS_80211_AUTH_WPA,
+       NDIS_80211_AUTH_WPA_PSK,
+       NDIS_80211_AUTH_WPA_NONE,
+       NDIS_80211_AUTH_WPA2,
+       NDIS_80211_AUTH_WPA2_PSK
 };
 
 enum ndis_80211_encr_status {
-       ndis_80211_encr_wep_enabled,
-       ndis_80211_encr_disabled,
-       ndis_80211_encr_wep_key_absent,
-       ndis_80211_encr_not_supported,
-       ndis_80211_encr_tkip_enabled,
-       ndis_80211_encr_tkip_key_absent,
-       ndis_80211_encr_ccmp_enabled,
-       ndis_80211_encr_ccmp_key_absent
+       NDIS_80211_ENCR_WEP_ENABLED,
+       NDIS_80211_ENCR_DISABLED,
+       NDIS_80211_ENCR_WEP_KEY_ABSENT,
+       NDIS_80211_ENCR_NOT_SUPPORTED,
+       NDIS_80211_ENCR_TKIP_ENABLED,
+       NDIS_80211_ENCR_TKIP_KEY_ABSENT,
+       NDIS_80211_ENCR_CCMP_ENABLED,
+       NDIS_80211_ENCR_CCMP_KEY_ABSENT
 };
 
 enum ndis_80211_priv_filter {
-       ndis_80211_priv_accept_all,
-       ndis_80211_priv_8021x_wep
+       NDIS_80211_PRIV_ACCEPT_ALL,
+       NDIS_80211_PRIV_8021X_WEP
 };
 
 enum ndis_80211_addkey_bits {
-       ndis_80211_addkey_8021x_auth = cpu_to_le32(1 << 28),
-       ndis_80211_addkey_set_init_recv_seq = cpu_to_le32(1 << 29),
-       ndis_80211_addkey_pairwise_key = cpu_to_le32(1 << 30),
-       ndis_80211_addkey_transmit_key = cpu_to_le32(1 << 31),
+       NDIS_80211_ADDKEY_8021X_AUTH = cpu_to_le32(1 << 28),
+       NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ = cpu_to_le32(1 << 29),
+       NDIS_80211_ADDKEY_PAIRWISE_KEY = cpu_to_le32(1 << 30),
+       NDIS_80211_ADDKEY_TRANSMIT_KEY = cpu_to_le32(1 << 31)
 };
 
 enum ndis_80211_addwep_bits {
-       ndis_80211_addwep_perclient_key = cpu_to_le32(1 << 30),
-       ndis_80211_addwep_transmit_key = cpu_to_le32(1 << 31),
+       NDIS_80211_ADDWEP_PERCLIENT_KEY = cpu_to_le32(1 << 30),
+       NDIS_80211_ADDWEP_TRANSMIT_KEY = cpu_to_le32(1 << 31)
 };
 
 struct ndis_80211_ssid {
@@ -361,7 +361,7 @@ static const struct ieee80211_rate rndis_rates[] = {
 };
 
 /* RNDIS device private data */
-struct rndis_wext_private {
+struct rndis_wlan_private {
        struct usbnet *usbdev;
 
        struct wireless_dev wdev;
@@ -441,13 +441,13 @@ static const unsigned char ffff_bssid[ETH_ALEN] = { 0xff, 0xff, 0xff,
                                                        0xff, 0xff, 0xff };
 
 
-static struct rndis_wext_private *get_rndis_wext_priv(struct usbnet *dev)
+static struct rndis_wlan_private *get_rndis_wlan_priv(struct usbnet *dev)
 {
-       return (struct rndis_wext_private *)dev->driver_priv;
+       return (struct rndis_wlan_private *)dev->driver_priv;
 }
 
 
-static u32 get_bcm4320_power(struct rndis_wext_private *priv)
+static u32 get_bcm4320_power(struct rndis_wlan_private *priv)
 {
        return BCM4320_DEFAULT_TXPOWER *
                bcm4320_power_output[priv->param_power_output] / 100;
@@ -480,7 +480,7 @@ static int rndis_error_status(__le32 rndis_status)
 
 static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len)
 {
-       struct rndis_wext_private *priv = get_rndis_wext_priv(dev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev);
        union {
                void                    *buf;
                struct rndis_msg_hdr    *header;
@@ -526,7 +526,7 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len)
 
 static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len)
 {
-       struct rndis_wext_private *priv = get_rndis_wext_priv(dev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev);
        union {
                void                    *buf;
                struct rndis_msg_hdr    *header;
@@ -747,7 +747,7 @@ static int get_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid)
 
 static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid)
 {
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        int ret;
 
        ret = rndis_set_oid(usbdev, OID_802_11_SSID, ssid, sizeof(*ssid));
@@ -794,7 +794,7 @@ static int is_associated(struct usbnet *usbdev)
 
 static int disassociate(struct usbnet *usbdev, int reset_ssid)
 {
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        struct ndis_80211_ssid ssid;
        int i, ret = 0;
 
@@ -826,7 +826,7 @@ static int disassociate(struct usbnet *usbdev, int reset_ssid)
 
 static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg)
 {
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        __le32 tmp;
        int auth_mode, ret;
 
@@ -835,23 +835,23 @@ static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg)
 
        if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) {
                if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X)
-                       auth_mode = ndis_80211_auth_wpa2;
+                       auth_mode = NDIS_80211_AUTH_WPA2;
                else
-                       auth_mode = ndis_80211_auth_wpa2_psk;
+                       auth_mode = NDIS_80211_AUTH_WPA2_PSK;
        } else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) {
                if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_802_1X)
-                       auth_mode = ndis_80211_auth_wpa;
+                       auth_mode = NDIS_80211_AUTH_WPA;
                else if (priv->wpa_keymgmt & IW_AUTH_KEY_MGMT_PSK)
-                       auth_mode = ndis_80211_auth_wpa_psk;
+                       auth_mode = NDIS_80211_AUTH_WPA_PSK;
                else
-                       auth_mode = ndis_80211_auth_wpa_none;
+                       auth_mode = NDIS_80211_AUTH_WPA_NONE;
        } else if (authalg & IW_AUTH_ALG_SHARED_KEY) {
                if (authalg & IW_AUTH_ALG_OPEN_SYSTEM)
-                       auth_mode = ndis_80211_auth_auto_switch;
+                       auth_mode = NDIS_80211_AUTH_AUTO_SWITCH;
                else
-                       auth_mode = ndis_80211_auth_shared;
+                       auth_mode = NDIS_80211_AUTH_SHARED;
        } else
-               auth_mode = ndis_80211_auth_open;
+               auth_mode = NDIS_80211_AUTH_OPEN;
 
        tmp = cpu_to_le32(auth_mode);
        ret = rndis_set_oid(usbdev, OID_802_11_AUTHENTICATION_MODE, &tmp,
@@ -869,16 +869,16 @@ static int set_auth_mode(struct usbnet *usbdev, int wpa_version, int authalg)
 
 static int set_priv_filter(struct usbnet *usbdev)
 {
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        __le32 tmp;
 
        devdbg(usbdev, "set_priv_filter: wpa_version=0x%x", priv->wpa_version);
 
        if (priv->wpa_version & IW_AUTH_WPA_VERSION_WPA2 ||
            priv->wpa_version & IW_AUTH_WPA_VERSION_WPA)
-               tmp = cpu_to_le32(ndis_80211_priv_8021x_wep);
+               tmp = cpu_to_le32(NDIS_80211_PRIV_8021X_WEP);
        else
-               tmp = cpu_to_le32(ndis_80211_priv_accept_all);
+               tmp = cpu_to_le32(NDIS_80211_PRIV_ACCEPT_ALL);
 
        return rndis_set_oid(usbdev, OID_802_11_PRIVACY_FILTER, &tmp,
                                                                sizeof(tmp));
@@ -887,7 +887,7 @@ static int set_priv_filter(struct usbnet *usbdev)
 
 static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise)
 {
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        __le32 tmp;
        int encr_mode, ret;
 
@@ -896,18 +896,18 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise)
                groupwise);
 
        if (pairwise & IW_AUTH_CIPHER_CCMP)
-               encr_mode = ndis_80211_encr_ccmp_enabled;
+               encr_mode = NDIS_80211_ENCR_CCMP_ENABLED;
        else if (pairwise & IW_AUTH_CIPHER_TKIP)
-               encr_mode = ndis_80211_encr_tkip_enabled;
+               encr_mode = NDIS_80211_ENCR_TKIP_ENABLED;
        else if (pairwise &
                 (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104))
-               encr_mode = ndis_80211_encr_wep_enabled;
+               encr_mode = NDIS_80211_ENCR_WEP_ENABLED;
        else if (groupwise & IW_AUTH_CIPHER_CCMP)
-               encr_mode = ndis_80211_encr_ccmp_enabled;
+               encr_mode = NDIS_80211_ENCR_CCMP_ENABLED;
        else if (groupwise & IW_AUTH_CIPHER_TKIP)
-               encr_mode = ndis_80211_encr_tkip_enabled;
+               encr_mode = NDIS_80211_ENCR_TKIP_ENABLED;
        else
-               encr_mode = ndis_80211_encr_disabled;
+               encr_mode = NDIS_80211_ENCR_DISABLED;
 
        tmp = cpu_to_le32(encr_mode);
        ret = rndis_set_oid(usbdev, OID_802_11_ENCRYPTION_STATUS, &tmp,
@@ -925,7 +925,7 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise)
 
 static int set_assoc_params(struct usbnet *usbdev)
 {
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
 
        set_auth_mode(usbdev, priv->wpa_version, priv->wpa_authalg);
        set_priv_filter(usbdev);
@@ -937,7 +937,7 @@ static int set_assoc_params(struct usbnet *usbdev)
 
 static int set_infra_mode(struct usbnet *usbdev, int mode)
 {
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        __le32 tmp;
        int ret, i;
 
@@ -970,12 +970,12 @@ static int set_infra_mode(struct usbnet *usbdev, int mode)
 
 static void set_default_iw_params(struct usbnet *usbdev)
 {
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
 
        priv->wpa_keymgmt = 0;
        priv->wpa_version = 0;
 
-       set_infra_mode(usbdev, ndis_80211_infra_infra);
+       set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA);
        set_auth_mode(usbdev, IW_AUTH_WPA_VERSION_DISABLED,
                                IW_AUTH_ALG_OPEN_SYSTEM);
        set_priv_filter(usbdev);
@@ -996,7 +996,7 @@ static int deauthenticate(struct usbnet *usbdev)
 /* index must be 0 - N, as per NDIS  */
 static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index)
 {
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        struct ndis_80211_wep_key ndis_key;
        int ret;
 
@@ -1011,7 +1011,7 @@ static int add_wep_key(struct usbnet *usbdev, char *key, int key_len, int index)
        memcpy(&ndis_key.material, key, key_len);
 
        if (index == priv->encr_tx_key_index) {
-               ndis_key.index |= ndis_80211_addwep_transmit_key;
+               ndis_key.index |= NDIS_80211_ADDWEP_TRANSMIT_KEY;
                ret = set_encr_mode(usbdev, IW_AUTH_CIPHER_WEP104,
                                                IW_AUTH_CIPHER_NONE);
                if (ret)
@@ -1039,7 +1039,7 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
                        int index, const struct sockaddr *addr,
                        const u8 *rx_seq, int alg, int flags)
 {
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        struct ndis_80211_key ndis_key;
        int ret;
 
@@ -1047,15 +1047,15 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
                return -EINVAL;
        if (key_len > sizeof(ndis_key.material) || key_len < 0)
                return -EINVAL;
-       if ((flags & ndis_80211_addkey_set_init_recv_seq) && !rx_seq)
+       if ((flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) && !rx_seq)
                return -EINVAL;
-       if ((flags & ndis_80211_addkey_pairwise_key) && !addr)
+       if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !addr)
                return -EINVAL;
 
        devdbg(usbdev, "add_wpa_key(%i): flags:%i%i%i", index,
-                       !!(flags & ndis_80211_addkey_transmit_key),
-                       !!(flags & ndis_80211_addkey_pairwise_key),
-                       !!(flags & ndis_80211_addkey_set_init_recv_seq));
+                       !!(flags & NDIS_80211_ADDKEY_TRANSMIT_KEY),
+                       !!(flags & NDIS_80211_ADDKEY_PAIRWISE_KEY),
+                       !!(flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ));
 
        memset(&ndis_key, 0, sizeof(ndis_key));
 
@@ -1073,15 +1073,15 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
        } else
                memcpy(ndis_key.material, key, key_len);
 
-       if (flags & ndis_80211_addkey_set_init_recv_seq)
+       if (flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ)
                memcpy(ndis_key.rsc, rx_seq, 6);
 
-       if (flags & ndis_80211_addkey_pairwise_key) {
+       if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) {
                /* pairwise key */
                memcpy(ndis_key.bssid, addr->sa_data, ETH_ALEN);
        } else {
                /* group key */
-               if (priv->infra_mode == ndis_80211_infra_adhoc)
+               if (priv->infra_mode == NDIS_80211_INFRA_ADHOC)
                        memset(ndis_key.bssid, 0xff, ETH_ALEN);
                else
                        get_bssid(usbdev, ndis_key.bssid);
@@ -1096,7 +1096,7 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
        priv->encr_key_len[index] = key_len;
        priv->encr_key_wpa[index] = 1;
 
-       if (flags & ndis_80211_addkey_transmit_key)
+       if (flags & NDIS_80211_ADDKEY_TRANSMIT_KEY)
                priv->encr_tx_key_index = index;
 
        return 0;
@@ -1106,7 +1106,7 @@ static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
 /* remove_key is for both wep and wpa */
 static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN])
 {
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        struct ndis_80211_remove_key remove_key;
        __le32 keyindex;
        int ret;
@@ -1128,7 +1128,7 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN])
                        /* pairwise key */
                        if (memcmp(bssid, ffff_bssid, ETH_ALEN) != 0)
                                remove_key.index |=
-                                       ndis_80211_addkey_pairwise_key;
+                                       NDIS_80211_ADDKEY_PAIRWISE_KEY;
                        memcpy(remove_key.bssid, bssid,
                                        sizeof(remove_key.bssid));
                } else
@@ -1161,7 +1161,7 @@ static int remove_key(struct usbnet *usbdev, int index, u8 bssid[ETH_ALEN])
 
 static void set_multicast_list(struct usbnet *usbdev)
 {
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        struct dev_mc_list *mclist;
        __le32 filter;
        int ret, i, size;
@@ -1238,10 +1238,10 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex,
 
        switch (type) {
        case NL80211_IFTYPE_ADHOC:
-               mode = ndis_80211_infra_adhoc;
+               mode = NDIS_80211_INFRA_ADHOC;
                break;
        case NL80211_IFTYPE_STATION:
-               mode = ndis_80211_infra_infra;
+               mode = NDIS_80211_INFRA_INFRA;
                break;
        default:
                return -EINVAL;
@@ -1256,7 +1256,7 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
                        struct cfg80211_scan_request *request)
 {
        struct usbnet *usbdev = netdev_priv(dev);
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        int ret;
        __le32 tmp;
 
@@ -1286,7 +1286,7 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
 static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev,
                                        struct ndis_80211_bssid_ex *bssid)
 {
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        struct ieee80211_channel *channel;
        s32 signal;
        u64 timestamp;
@@ -1371,8 +1371,8 @@ out:
 
 static void rndis_get_scan_results(struct work_struct *work)
 {
-       struct rndis_wext_private *priv =
-               container_of(work, struct rndis_wext_private, scan_work.work);
+       struct rndis_wlan_private *priv =
+               container_of(work, struct rndis_wlan_private, scan_work.work);
        struct usbnet *usbdev = priv->usbdev;
        int ret;
 
@@ -1497,7 +1497,7 @@ static int rndis_iw_set_auth(struct net_device *dev,
 {
        struct iw_param *p = &wrqu->param;
        struct usbnet *usbdev = netdev_priv(dev);
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        int ret = -ENOTSUPP;
 
        switch (p->flags & IW_AUTH_INDEX) {
@@ -1578,7 +1578,7 @@ static int rndis_iw_get_auth(struct net_device *dev,
 {
        struct iw_param *p = &wrqu->param;
        struct usbnet *usbdev = netdev_priv(dev);
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
 
        switch (p->flags & IW_AUTH_INDEX) {
        case IW_AUTH_WPA_VERSION:
@@ -1609,7 +1609,7 @@ static int rndis_iw_set_encode(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
        struct usbnet *usbdev = netdev_priv(dev);
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        int ret, index, key_len;
        u8 *key;
 
@@ -1672,7 +1672,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev,
 {
        struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
        struct usbnet *usbdev = netdev_priv(dev);
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        int keyidx, flags;
 
        keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX;
@@ -1698,11 +1698,11 @@ static int rndis_iw_set_encode_ext(struct net_device *dev,
 
        flags = 0;
        if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
-               flags |= ndis_80211_addkey_set_init_recv_seq;
+               flags |= NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ;
        if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY))
-               flags |= ndis_80211_addkey_pairwise_key;
+               flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY;
        if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
-               flags |= ndis_80211_addkey_transmit_key;
+               flags |= NDIS_80211_ADDKEY_TRANSMIT_KEY;
 
        return add_wpa_key(usbdev, ext->key, ext->key_len, keyidx, &ext->addr,
                                ext->rx_seq, ext->alg, flags);
@@ -1713,7 +1713,7 @@ static int rndis_iw_set_genie(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
        struct usbnet *usbdev = netdev_priv(dev);
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        int ret = 0;
 
 #ifdef DEBUG
@@ -1747,7 +1747,7 @@ static int rndis_iw_get_genie(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
        struct usbnet *usbdev = netdev_priv(dev);
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
 
        devdbg(usbdev, "SIOCGIWGENIE");
 
@@ -1886,7 +1886,7 @@ 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_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        __le32 tx_power;
 
        if (priv->radio_on) {
@@ -1912,7 +1912,7 @@ 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_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        __le32 tx_power = 0;
 
        if (!wrqu->txpower.disabled) {
@@ -1969,7 +1969,7 @@ static int rndis_iw_set_mlme(struct net_device *dev,
     struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
 {
        struct usbnet *usbdev = netdev_priv(dev);
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        struct iw_mlme *mlme = (struct iw_mlme *)extra;
        unsigned char bssid[ETH_ALEN];
 
@@ -1994,7 +1994,7 @@ static int rndis_iw_set_mlme(struct net_device *dev,
 static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev)
 {
        struct usbnet *usbdev = netdev_priv(dev);
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        unsigned long flags;
 
        spin_lock_irqsave(&priv->stats_lock, flags);
@@ -2037,28 +2037,28 @@ static const iw_handler rndis_iw_handler[] =
        IW_IOCTL(SIOCSIWMLME)      = rndis_iw_set_mlme,
 };
 
-static const iw_handler rndis_wext_private_handler[] = {
+static const iw_handler rndis_wlan_private_handler[] = {
 };
 
-static const struct iw_priv_args rndis_wext_private_args[] = {
+static const struct iw_priv_args rndis_wlan_private_args[] = {
 };
 
 
 static const struct iw_handler_def rndis_iw_handlers = {
        .num_standard = ARRAY_SIZE(rndis_iw_handler),
-       .num_private  = ARRAY_SIZE(rndis_wext_private_handler),
-       .num_private_args = ARRAY_SIZE(rndis_wext_private_args),
+       .num_private  = ARRAY_SIZE(rndis_wlan_private_handler),
+       .num_private_args = ARRAY_SIZE(rndis_wlan_private_args),
        .standard = (iw_handler *)rndis_iw_handler,
-       .private  = (iw_handler *)rndis_wext_private_handler,
-       .private_args = (struct iw_priv_args *)rndis_wext_private_args,
+       .private  = (iw_handler *)rndis_wlan_private_handler,
+       .private_args = (struct iw_priv_args *)rndis_wlan_private_args,
        .get_wireless_stats = rndis_get_wireless_stats,
 };
 
 
-static void rndis_wext_worker(struct work_struct *work)
+static void rndis_wlan_worker(struct work_struct *work)
 {
-       struct rndis_wext_private *priv =
-               container_of(work, struct rndis_wext_private, work);
+       struct rndis_wlan_private *priv =
+               container_of(work, struct rndis_wlan_private, work);
        struct usbnet *usbdev = priv->usbdev;
        union iwreq_data evt;
        unsigned char bssid[ETH_ALEN];
@@ -2119,10 +2119,10 @@ get_bssid:
                set_multicast_list(usbdev);
 }
 
-static void rndis_wext_set_multicast_list(struct net_device *dev)
+static void rndis_wlan_set_multicast_list(struct net_device *dev)
 {
        struct usbnet *usbdev = netdev_priv(dev);
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
 
        if (test_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending))
                return;
@@ -2131,9 +2131,9 @@ static void rndis_wext_set_multicast_list(struct net_device *dev)
        queue_work(priv->workqueue, &priv->work);
 }
 
-static void rndis_wext_link_change(struct usbnet *usbdev, int state)
+static void rndis_wlan_link_change(struct usbnet *usbdev, int state)
 {
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
 
        /* queue work to avoid recursive calls into rndis_command */
        set_bit(state ? WORK_LINK_UP : WORK_LINK_DOWN, &priv->work_pending);
@@ -2141,14 +2141,14 @@ static void rndis_wext_link_change(struct usbnet *usbdev, int state)
 }
 
 
-static int rndis_wext_get_caps(struct usbnet *usbdev)
+static int rndis_wlan_get_caps(struct usbnet *usbdev)
 {
        struct {
                __le32  num_items;
                __le32  items[8];
        } networks_supported;
        int len, retval, i, n;
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
 
        /* determine supported modes */
        len = sizeof(networks_supported);
@@ -2160,14 +2160,14 @@ static int rndis_wext_get_caps(struct usbnet *usbdev)
                        n = 8;
                for (i = 0; i < n; i++) {
                        switch (le32_to_cpu(networks_supported.items[i])) {
-                       case ndis_80211_type_freq_hop:
-                       case ndis_80211_type_direct_seq:
+                       case NDIS_80211_TYPE_FREQ_HOP:
+                       case NDIS_80211_TYPE_DIRECT_SEQ:
                                priv->caps |= CAP_MODE_80211B;
                                break;
-                       case ndis_80211_type_ofdm_a:
+                       case NDIS_80211_TYPE_OFDM_A:
                                priv->caps |= CAP_MODE_80211A;
                                break;
-                       case ndis_80211_type_ofdm_g:
+                       case NDIS_80211_TYPE_OFDM_G:
                                priv->caps |= CAP_MODE_80211G;
                                break;
                        }
@@ -2181,8 +2181,8 @@ static int rndis_wext_get_caps(struct usbnet *usbdev)
 #define STATS_UPDATE_JIFFIES (HZ)
 static void rndis_update_wireless_stats(struct work_struct *work)
 {
-       struct rndis_wext_private *priv =
-               container_of(work, struct rndis_wext_private, stats_work.work);
+       struct rndis_wlan_private *priv =
+               container_of(work, struct rndis_wlan_private, stats_work.work);
        struct usbnet *usbdev = priv->usbdev;
        struct iw_statistics iwstats;
        __le32 rssi, tmp;
@@ -2297,7 +2297,7 @@ static int bcm4320a_early_init(struct usbnet *usbdev)
 
 static int bcm4320b_early_init(struct usbnet *usbdev)
 {
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        char buf[8];
 
        /* Early initialization settings, setting these won't have effect
@@ -2363,21 +2363,21 @@ static int bcm4320b_early_init(struct usbnet *usbdev)
 }
 
 /* same as rndis_netdev_ops but with local multicast handler */
-static const struct net_device_ops rndis_wext_netdev_ops = {
+static const struct net_device_ops rndis_wlan_netdev_ops = {
        .ndo_open               = usbnet_open,
        .ndo_stop               = usbnet_stop,
        .ndo_start_xmit         = usbnet_start_xmit,
        .ndo_tx_timeout         = usbnet_tx_timeout,
        .ndo_set_mac_address    = eth_mac_addr,
        .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_multicast_list = rndis_wext_set_multicast_list,
+       .ndo_set_multicast_list = rndis_wlan_set_multicast_list,
 };
 
 
-static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf)
+static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf)
 {
        struct wiphy *wiphy;
-       struct rndis_wext_private *priv;
+       struct rndis_wlan_private *priv;
        int retval, len;
        __le32 tmp;
 
@@ -2385,7 +2385,7 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf)
         * NOTE: We only support a single virtual interface, so wiphy
         * and wireless_dev are somewhat synonymous for this device.
         */
-       wiphy = wiphy_new(&rndis_config_ops, sizeof(struct rndis_wext_private));
+       wiphy = wiphy_new(&rndis_config_ops, sizeof(struct rndis_wlan_private));
        if (!wiphy)
                return -ENOMEM;
 
@@ -2395,7 +2395,7 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf)
        priv->wdev.iftype = NL80211_IFTYPE_STATION;
 
        /* These have to be initialized before calling generic_rndis_bind().
-        * Otherwise we'll be in big trouble in rndis_wext_early_init().
+        * Otherwise we'll be in big trouble in rndis_wlan_early_init().
         */
        usbdev->driver_priv = priv;
        usbdev->net->wireless_handlers = &rndis_iw_handlers;
@@ -2406,7 +2406,7 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf)
 
        /* because rndis_command() sleeps we need to use workqueue */
        priv->workqueue = create_singlethread_workqueue("rndis_wlan");
-       INIT_WORK(&priv->work, rndis_wext_worker);
+       INIT_WORK(&priv->work, rndis_wlan_worker);
        INIT_DELAYED_WORK(&priv->stats_work, rndis_update_wireless_stats);
        INIT_DELAYED_WORK(&priv->scan_work, rndis_get_scan_results);
 
@@ -2420,9 +2420,9 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf)
         * picks up rssi to closest station instead of to access point).
         *
         * rndis_host wants to avoid all OID as much as possible
-        * so do promisc/multicast handling in rndis_wext.
+        * so do promisc/multicast handling in rndis_wlan.
         */
-       usbdev->net->netdev_ops = &rndis_wext_netdev_ops;
+       usbdev->net->netdev_ops = &rndis_wlan_netdev_ops;
 
        tmp = RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_BROADCAST;
        retval = rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &tmp,
@@ -2455,7 +2455,7 @@ static int rndis_wext_bind(struct usbnet *usbdev, struct usb_interface *intf)
        wiphy->max_scan_ssids = 1;
 
        /* TODO: fill-out band information based on priv->caps */
-       rndis_wext_get_caps(usbdev);
+       rndis_wlan_get_caps(usbdev);
 
        memcpy(priv->channels, rndis_channels, sizeof(rndis_channels));
        memcpy(priv->rates, rndis_rates, sizeof(rndis_rates));
@@ -2497,9 +2497,9 @@ fail:
 }
 
 
-static void rndis_wext_unbind(struct usbnet *usbdev, struct usb_interface *intf)
+static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf)
 {
-       struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
 
        /* turn radio off */
        disassociate(usbdev, 0);
@@ -2520,7 +2520,7 @@ static void rndis_wext_unbind(struct usbnet *usbdev, struct usb_interface *intf)
 }
 
 
-static int rndis_wext_reset(struct usbnet *usbdev)
+static int rndis_wlan_reset(struct usbnet *usbdev)
 {
        return deauthenticate(usbdev);
 }
@@ -2529,40 +2529,40 @@ static int rndis_wext_reset(struct usbnet *usbdev)
 static const struct driver_info        bcm4320b_info = {
        .description =  "Wireless RNDIS device, BCM4320b based",
        .flags =        FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
-       .bind =         rndis_wext_bind,
-       .unbind =       rndis_wext_unbind,
+       .bind =         rndis_wlan_bind,
+       .unbind =       rndis_wlan_unbind,
        .status =       rndis_status,
        .rx_fixup =     rndis_rx_fixup,
        .tx_fixup =     rndis_tx_fixup,
-       .reset =        rndis_wext_reset,
+       .reset =        rndis_wlan_reset,
        .early_init =   bcm4320b_early_init,
-       .link_change =  rndis_wext_link_change,
+       .link_change =  rndis_wlan_link_change,
 };
 
 static const struct driver_info        bcm4320a_info = {
        .description =  "Wireless RNDIS device, BCM4320a based",
        .flags =        FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
-       .bind =         rndis_wext_bind,
-       .unbind =       rndis_wext_unbind,
+       .bind =         rndis_wlan_bind,
+       .unbind =       rndis_wlan_unbind,
        .status =       rndis_status,
        .rx_fixup =     rndis_rx_fixup,
        .tx_fixup =     rndis_tx_fixup,
-       .reset =        rndis_wext_reset,
+       .reset =        rndis_wlan_reset,
        .early_init =   bcm4320a_early_init,
-       .link_change =  rndis_wext_link_change,
+       .link_change =  rndis_wlan_link_change,
 };
 
-static const struct driver_info rndis_wext_info = {
+static const struct driver_info rndis_wlan_info = {
        .description =  "Wireless RNDIS device",
        .flags =        FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
-       .bind =         rndis_wext_bind,
-       .unbind =       rndis_wext_unbind,
+       .bind =         rndis_wlan_bind,
+       .unbind =       rndis_wlan_unbind,
        .status =       rndis_status,
        .rx_fixup =     rndis_rx_fixup,
        .tx_fixup =     rndis_tx_fixup,
-       .reset =        rndis_wext_reset,
+       .reset =        rndis_wlan_reset,
        .early_init =   bcm4320a_early_init,
-       .link_change =  rndis_wext_link_change,
+       .link_change =  rndis_wlan_link_change,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -2672,11 +2672,11 @@ static const struct usb_device_id products [] = {
 {
        /* RNDIS is MSFT's un-official variant of CDC ACM */
        USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
-       .driver_info = (unsigned long) &rndis_wext_info,
+       .driver_info = (unsigned long) &rndis_wlan_info,
 }, {
        /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */
        USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1),
-       .driver_info = (unsigned long) &rndis_wext_info,
+       .driver_info = (unsigned long) &rndis_wlan_info,
 },
        { },            // END
 };
index 0197531..435f945 100644 (file)
@@ -520,7 +520,7 @@ static void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev,
        if (state == STATE_SLEEP) {
                rt2x00pci_register_read(rt2x00dev, CSR20, &reg);
                rt2x00_set_field32(&reg, CSR20_DELAY_AFTER_TBCN,
-                                  (libconf->conf->beacon_int - 20) * 16);
+                                  (rt2x00dev->beacon_int - 20) * 16);
                rt2x00_set_field32(&reg, CSR20_TBCN_BEFORE_WAKEUP,
                                   libconf->conf->listen_interval - 1);
 
index f95cb64..08b30d0 100644 (file)
@@ -569,7 +569,7 @@ static void rt2500pci_config_ps(struct rt2x00_dev *rt2x00dev,
        if (state == STATE_SLEEP) {
                rt2x00pci_register_read(rt2x00dev, CSR20, &reg);
                rt2x00_set_field32(&reg, CSR20_DELAY_AFTER_TBCN,
-                                  (libconf->conf->beacon_int - 20) * 16);
+                                  (rt2x00dev->beacon_int - 20) * 16);
                rt2x00_set_field32(&reg, CSR20_TBCN_BEFORE_WAKEUP,
                                   libconf->conf->listen_interval - 1);
 
index 69f966f..66daf68 100644 (file)
@@ -647,7 +647,7 @@ static void rt2500usb_config_ps(struct rt2x00_dev *rt2x00dev,
        if (state == STATE_SLEEP) {
                rt2500usb_register_read(rt2x00dev, MAC_CSR18, &reg);
                rt2x00_set_field16(&reg, MAC_CSR18_DELAY_AFTER_BEACON,
-                                  libconf->conf->beacon_int - 20);
+                                  rt2x00dev->beacon_int - 20);
                rt2x00_set_field16(&reg, MAC_CSR18_BEACONS_BEFORE_WAKEUP,
                                   libconf->conf->listen_interval - 1);
 
index 142ad34..3756166 100644 (file)
@@ -2927,12 +2927,17 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x07d1, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x07d1, 0x3c0a), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x07d1, 0x3c0d), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x07d1, 0x3c0e), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x07d1, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Edimax */
        { USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) },
+       /* Encore */
+       { USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* EnGenius */
        { USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -2951,6 +2956,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) },
+       /* I-O DATA */
+       { USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* LevelOne */
        { USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -2970,6 +2977,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
        /* Pegatron */
        { USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Philips */
        { USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Planex */
@@ -2981,6 +2989,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
        /* Quanta */
        { USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Ralink */
+       { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -3005,6 +3014,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* SMC */
        { USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -3029,6 +3039,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
        /* Zinwell */
        { USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Zyxel */
        { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0586, 0x341a), USB_DEVICE_DATA(&rt2800usb_ops) },
index 2b64a61..a498dde 100644 (file)
@@ -802,6 +802,11 @@ struct rt2x00_dev {
        u8 calibration[2];
 
        /*
+        * Beacon interval.
+        */
+       u16 beacon_int;
+
+       /*
         * Low level statistics which will have
         * to be kept up to date while device is running.
         */
index c5bbf0b..3e019a1 100644 (file)
@@ -108,6 +108,9 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
        erp.basic_rates = bss_conf->basic_rates;
        erp.beacon_int = bss_conf->beacon_int;
 
+       /* Update global beacon interval time, this is needed for PS support */
+       rt2x00dev->beacon_int = bss_conf->beacon_int;
+
        rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp);
 }
 
index a8bf5c4..49b29ff 100644 (file)
@@ -956,7 +956,7 @@ static void rt61pci_config_ps(struct rt2x00_dev *rt2x00dev,
        if (state == STATE_SLEEP) {
                rt2x00pci_register_read(rt2x00dev, MAC_CSR11, &reg);
                rt2x00_set_field32(&reg, MAC_CSR11_DELAY_AFTER_TBCN,
-                                  libconf->conf->beacon_int - 10);
+                                  rt2x00dev->beacon_int - 10);
                rt2x00_set_field32(&reg, MAC_CSR11_TBCN_BEFORE_WAKEUP,
                                   libconf->conf->listen_interval - 1);
                rt2x00_set_field32(&reg, MAC_CSR11_WAKEUP_LATENCY, 5);
index 211a3d6..c188488 100644 (file)
@@ -852,7 +852,7 @@ static void rt73usb_config_ps(struct rt2x00_dev *rt2x00dev,
        if (state == STATE_SLEEP) {
                rt2x00usb_register_read(rt2x00dev, MAC_CSR11, &reg);
                rt2x00_set_field32(&reg, MAC_CSR11_DELAY_AFTER_TBCN,
-                                  libconf->conf->beacon_int - 10);
+                                  rt2x00dev->beacon_int - 10);
                rt2x00_set_field32(&reg, MAC_CSR11_TBCN_BEFORE_WAKEUP,
                                   libconf->conf->listen_interval - 1);
                rt2x00_set_field32(&reg, MAC_CSR11_WAKEUP_LATENCY, 5);
index 6499ccc..294250e 100644 (file)
@@ -74,6 +74,8 @@ static struct usb_device_id rtl8187_table[] __devinitdata = {
        {USB_DEVICE(0x18E8, 0x6232), .driver_info = DEVICE_RTL8187},
        /* AirLive */
        {USB_DEVICE(0x1b75, 0x8187), .driver_info = DEVICE_RTL8187},
+       /* Linksys */
+       {USB_DEVICE(0x1737, 0x0073), .driver_info = DEVICE_RTL8187B},
        {}
 };
 
@@ -321,12 +323,7 @@ static void rtl8187_rx_cb(struct urb *urb)
        unsigned long f;
 
        spin_lock_irqsave(&priv->rx_queue.lock, f);
-       if (skb->next)
-               __skb_unlink(skb, &priv->rx_queue);
-       else {
-               spin_unlock_irqrestore(&priv->rx_queue.lock, f);
-               return;
-       }
+       __skb_unlink(skb, &priv->rx_queue);
        spin_unlock_irqrestore(&priv->rx_queue.lock, f);
        skb_put(skb, urb->actual_length);
 
index 3ab3eb9..25d27b6 100644 (file)
@@ -2869,10 +2869,6 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev)
                if (lp->tx_n_in_use == (NTXBLOCKS - 1))
                        return 1;
        }
-#ifdef DEBUG_TX_ERROR
-       if (skb->next)
-               printk(KERN_INFO "skb has next\n");
-#endif
 
        /* Do we need some padding? */
        /* Note : on wireless the propagation time is in the order of 1us,
index e55b339..1a90d69 100644 (file)
@@ -3107,11 +3107,6 @@ wavelan_packet_xmit(struct sk_buff *     skb,
        * so the Tx buffer is now free */
     }
 
-#ifdef DEBUG_TX_ERROR
-       if (skb->next)
-               printk(KERN_INFO "skb has next\n");
-#endif
-
        /* Check if we need some padding */
        /* Note : on wireless the propagation time is in the order of 1us,
         * and we don't have the Ethernet specific requirement of beeing
index 7477ffd..3c7a505 100644 (file)
@@ -717,7 +717,7 @@ static void yellowfin_tx_timeout(struct net_device *dev)
        if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE)
                netif_wake_queue (dev);         /* Typical path */
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        dev->stats.tx_errors++;
 }
 
@@ -876,7 +876,6 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev)
                netif_start_queue (dev);                /* Typical path */
        else
                yp->tx_full = 1;
-       dev->trans_start = jiffies;
 
        if (yellowfin_debug > 4) {
                printk(KERN_DEBUG "%s: Yellowfin transmit frame #%d queued in slot %d.\n",
index 284ebac..c682ac5 100644 (file)
@@ -21,7 +21,7 @@ config ACER_WMI
        depends on NEW_LEDS
        depends on BACKLIGHT_CLASS_DEVICE
        depends on SERIO_I8042
-       depends on RFKILL
+       depends on RFKILL || RFKILL = n
        select ACPI_WMI
        ---help---
          This is a driver for newer Acer (and Wistron) laptops. It adds
@@ -60,7 +60,7 @@ config DELL_LAPTOP
        depends on DCDBAS
        depends on EXPERIMENTAL
        depends on BACKLIGHT_CLASS_DEVICE
-       depends on RFKILL
+       depends on RFKILL || RFKILL = n
        depends on POWER_SUPPLY
        default n
        ---help---
@@ -117,7 +117,7 @@ config HP_WMI
        tristate "HP WMI extras"
        depends on ACPI_WMI
        depends on INPUT
-       depends on RFKILL
+       depends on RFKILL || RFKILL = n
        help
         Say Y here if you want to support WMI-based hotkeys on HP laptops and
         to read data from WMI such as docking or ambient light sensor state.
@@ -196,14 +196,13 @@ config THINKPAD_ACPI
        tristate "ThinkPad ACPI Laptop Extras"
        depends on ACPI
        depends on INPUT
+       depends on RFKILL || RFKILL = n
        select BACKLIGHT_LCD_SUPPORT
        select BACKLIGHT_CLASS_DEVICE
        select HWMON
        select NVRAM
        select NEW_LEDS
        select LEDS_CLASS
-       select NET
-       select RFKILL
        ---help---
          This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
          support for Fn-Fx key combinations, Bluetooth control, video
@@ -338,9 +337,9 @@ config EEEPC_LAPTOP
        depends on ACPI
        depends on INPUT
        depends on EXPERIMENTAL
+       depends on RFKILL || RFKILL = n
        select BACKLIGHT_CLASS_DEVICE
        select HWMON
-       select RFKILL
        ---help---
          This driver supports the Fn-Fx keys on Eee PC laptops.
          It also adds the ability to switch camera/wlan on/off.
@@ -405,9 +404,8 @@ config ACPI_TOSHIBA
        tristate "Toshiba Laptop Extras"
        depends on ACPI
        depends on INPUT
+       depends on RFKILL || RFKILL = n
        select INPUT_POLLDEV
-       select NET
-       select RFKILL
        select BACKLIGHT_CLASS_DEVICE
        ---help---
          This driver adds support for access to certain system settings
index 62d02b3..09a503e 100644 (file)
@@ -958,58 +958,47 @@ static void acer_rfkill_update(struct work_struct *ignored)
 
        status = get_u32(&state, ACER_CAP_WIRELESS);
        if (ACPI_SUCCESS(status))
-               rfkill_force_state(wireless_rfkill, state ?
-                       RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED);
+               rfkill_set_sw_state(wireless_rfkill, !!state);
 
        if (has_cap(ACER_CAP_BLUETOOTH)) {
                status = get_u32(&state, ACER_CAP_BLUETOOTH);
                if (ACPI_SUCCESS(status))
-                       rfkill_force_state(bluetooth_rfkill, state ?
-                               RFKILL_STATE_UNBLOCKED :
-                               RFKILL_STATE_SOFT_BLOCKED);
+                       rfkill_set_sw_state(bluetooth_rfkill, !!state);
        }
 
        schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
 }
 
-static int acer_rfkill_set(void *data, enum rfkill_state state)
+static int acer_rfkill_set(void *data, bool blocked)
 {
        acpi_status status;
-       u32 *cap = data;
-       status = set_u32((u32) (state == RFKILL_STATE_UNBLOCKED), *cap);
+       u32 cap = (unsigned long)data;
+       status = set_u32(!!blocked, cap);
        if (ACPI_FAILURE(status))
                return -ENODEV;
        return 0;
 }
 
-static struct rfkill * acer_rfkill_register(struct device *dev,
-enum rfkill_type type, char *name, u32 cap)
+static const struct rfkill_ops acer_rfkill_ops = {
+       .set_block = acer_rfkill_set,
+};
+
+static struct rfkill *acer_rfkill_register(struct device *dev,
+                                          enum rfkill_type type,
+                                          char *name, u32 cap)
 {
        int err;
-       u32 state;
-       u32 *data;
        struct rfkill *rfkill_dev;
 
-       rfkill_dev = rfkill_allocate(dev, type);
+       rfkill_dev = rfkill_alloc(name, dev, type,
+                                 &acer_rfkill_ops,
+                                 (void *)(unsigned long)cap);
        if (!rfkill_dev)
                return ERR_PTR(-ENOMEM);
-       rfkill_dev->name = name;
-       get_u32(&state, cap);
-       rfkill_dev->state = state ? RFKILL_STATE_UNBLOCKED :
-               RFKILL_STATE_SOFT_BLOCKED;
-       data = kzalloc(sizeof(u32), GFP_KERNEL);
-       if (!data) {
-               rfkill_free(rfkill_dev);
-               return ERR_PTR(-ENOMEM);
-       }
-       *data = cap;
-       rfkill_dev->data = data;
-       rfkill_dev->toggle_radio = acer_rfkill_set;
 
        err = rfkill_register(rfkill_dev);
        if (err) {
-               kfree(rfkill_dev->data);
-               rfkill_free(rfkill_dev);
+               rfkill_destroy(rfkill_dev);
                return ERR_PTR(err);
        }
        return rfkill_dev;
@@ -1027,8 +1016,8 @@ static int acer_rfkill_init(struct device *dev)
                        RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
                        ACER_CAP_BLUETOOTH);
                if (IS_ERR(bluetooth_rfkill)) {
-                       kfree(wireless_rfkill->data);
                        rfkill_unregister(wireless_rfkill);
+                       rfkill_destroy(wireless_rfkill);
                        return PTR_ERR(bluetooth_rfkill);
                }
        }
@@ -1041,11 +1030,13 @@ static int acer_rfkill_init(struct device *dev)
 static void acer_rfkill_exit(void)
 {
        cancel_delayed_work_sync(&acer_rfkill_work);
-       kfree(wireless_rfkill->data);
+
        rfkill_unregister(wireless_rfkill);
+       rfkill_destroy(wireless_rfkill);
+
        if (has_cap(ACER_CAP_BLUETOOTH)) {
-               kfree(bluetooth_rfkill->data);
                rfkill_unregister(bluetooth_rfkill);
+               rfkill_destroy(bluetooth_rfkill);
        }
        return;
 }
index af9f430..2faf0e1 100644 (file)
@@ -174,10 +174,11 @@ dell_send_request(struct calling_interface_buffer *buffer, int class,
    result[3]: NVRAM format version number
 */
 
-static int dell_rfkill_set(int radio, enum rfkill_state state)
+static int dell_rfkill_set(void *data, bool blocked)
 {
        struct calling_interface_buffer buffer;
-       int disable = (state == RFKILL_STATE_UNBLOCKED) ? 0 : 1;
+       int disable = blocked ? 0 : 1;
+       unsigned long radio = (unsigned long)data;
 
        memset(&buffer, 0, sizeof(struct calling_interface_buffer));
        buffer.input[0] = (1 | (radio<<8) | (disable << 16));
@@ -186,56 +187,24 @@ static int dell_rfkill_set(int radio, enum rfkill_state state)
        return 0;
 }
 
-static int dell_wifi_set(void *data, enum rfkill_state state)
-{
-       return dell_rfkill_set(1, state);
-}
-
-static int dell_bluetooth_set(void *data, enum rfkill_state state)
-{
-       return dell_rfkill_set(2, state);
-}
-
-static int dell_wwan_set(void *data, enum rfkill_state state)
-{
-       return dell_rfkill_set(3, state);
-}
-
-static int dell_rfkill_get(int bit, enum rfkill_state *state)
+static void dell_rfkill_query(struct rfkill *rfkill, void *data)
 {
        struct calling_interface_buffer buffer;
        int status;
-       int new_state = RFKILL_STATE_HARD_BLOCKED;
+       int bit = (unsigned long)data + 16;
 
        memset(&buffer, 0, sizeof(struct calling_interface_buffer));
        dell_send_request(&buffer, 17, 11);
        status = buffer.output[1];
 
-       if (status & (1<<16))
-               new_state = RFKILL_STATE_SOFT_BLOCKED;
-
-       if (status & (1<<bit))
-               *state = new_state;
-       else
-               *state = RFKILL_STATE_UNBLOCKED;
-
-       return 0;
-}
-
-static int dell_wifi_get(void *data, enum rfkill_state *state)
-{
-       return dell_rfkill_get(17, state);
-}
-
-static int dell_bluetooth_get(void *data, enum rfkill_state *state)
-{
-       return dell_rfkill_get(18, state);
+       if (status & BIT(bit))
+               rfkill_set_hw_state(rfkill, !!(status & BIT(16)));
 }
 
-static int dell_wwan_get(void *data, enum rfkill_state *state)
-{
-       return dell_rfkill_get(19, state);
-}
+static const struct rfkill_ops dell_rfkill_ops = {
+       .set_block = dell_rfkill_set,
+       .query = dell_rfkill_query,
+};
 
 static int dell_setup_rfkill(void)
 {
@@ -248,36 +217,37 @@ static int dell_setup_rfkill(void)
        status = buffer.output[1];
 
        if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) {
-               wifi_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WLAN);
-               if (!wifi_rfkill)
+               wifi_rfkill = rfkill_alloc("dell-wifi", NULL, RFKILL_TYPE_WLAN,
+                                          &dell_rfkill_ops, (void *) 1);
+               if (!wifi_rfkill) {
+                       ret = -ENOMEM;
                        goto err_wifi;
-               wifi_rfkill->name = "dell-wifi";
-               wifi_rfkill->toggle_radio = dell_wifi_set;
-               wifi_rfkill->get_state = dell_wifi_get;
+               }
                ret = rfkill_register(wifi_rfkill);
                if (ret)
                        goto err_wifi;
        }
 
        if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) {
-               bluetooth_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_BLUETOOTH);
-               if (!bluetooth_rfkill)
+               bluetooth_rfkill = rfkill_alloc("dell-bluetooth", NULL,
+                                               RFKILL_TYPE_BLUETOOTH,
+                                               &dell_rfkill_ops, (void *) 2);
+               if (!bluetooth_rfkill) {
+                       ret = -ENOMEM;
                        goto err_bluetooth;
-               bluetooth_rfkill->name = "dell-bluetooth";
-               bluetooth_rfkill->toggle_radio = dell_bluetooth_set;
-               bluetooth_rfkill->get_state = dell_bluetooth_get;
+               }
                ret = rfkill_register(bluetooth_rfkill);
                if (ret)
                        goto err_bluetooth;
        }
 
        if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) {
-               wwan_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WWAN);
-               if (!wwan_rfkill)
+               wwan_rfkill = rfkill_alloc("dell-wwan", NULL, RFKILL_TYPE_WWAN,
+                                          &dell_rfkill_ops, (void *) 3);
+               if (!wwan_rfkill) {
+                       ret = -ENOMEM;
                        goto err_wwan;
-               wwan_rfkill->name = "dell-wwan";
-               wwan_rfkill->toggle_radio = dell_wwan_set;
-               wwan_rfkill->get_state = dell_wwan_get;
+               }
                ret = rfkill_register(wwan_rfkill);
                if (ret)
                        goto err_wwan;
@@ -285,22 +255,15 @@ static int dell_setup_rfkill(void)
 
        return 0;
 err_wwan:
-       if (wwan_rfkill)
-               rfkill_free(wwan_rfkill);
-       if (bluetooth_rfkill) {
+       rfkill_destroy(wwan_rfkill);
+       if (bluetooth_rfkill)
                rfkill_unregister(bluetooth_rfkill);
-               bluetooth_rfkill = NULL;
-       }
 err_bluetooth:
-       if (bluetooth_rfkill)
-               rfkill_free(bluetooth_rfkill);
-       if (wifi_rfkill) {
+       rfkill_destroy(bluetooth_rfkill);
+       if (wifi_rfkill)
                rfkill_unregister(wifi_rfkill);
-               wifi_rfkill = NULL;
-       }
 err_wifi:
-       if (wifi_rfkill)
-               rfkill_free(wifi_rfkill);
+       rfkill_destroy(wifi_rfkill);
 
        return ret;
 }
index 353a898..03bf522 100644 (file)
@@ -299,39 +299,22 @@ static int update_bl_status(struct backlight_device *bd)
  * Rfkill helpers
  */
 
-static int eeepc_wlan_rfkill_set(void *data, enum rfkill_state state)
-{
-       if (state == RFKILL_STATE_SOFT_BLOCKED)
-               return set_acpi(CM_ASL_WLAN, 0);
-       else
-               return set_acpi(CM_ASL_WLAN, 1);
-}
-
-static int eeepc_wlan_rfkill_state(void *data, enum rfkill_state *state)
+static bool eeepc_wlan_rfkill_blocked(void)
 {
        if (get_acpi(CM_ASL_WLAN) == 1)
-               *state = RFKILL_STATE_UNBLOCKED;
-       else
-               *state = RFKILL_STATE_SOFT_BLOCKED;
-       return 0;
+               return false;
+       return true;
 }
 
-static int eeepc_bluetooth_rfkill_set(void *data, enum rfkill_state state)
+static int eeepc_rfkill_set(void *data, bool blocked)
 {
-       if (state == RFKILL_STATE_SOFT_BLOCKED)
-               return set_acpi(CM_ASL_BLUETOOTH, 0);
-       else
-               return set_acpi(CM_ASL_BLUETOOTH, 1);
+       unsigned long asl = (unsigned long)data;
+       return set_acpi(asl, !blocked);
 }
 
-static int eeepc_bluetooth_rfkill_state(void *data, enum rfkill_state *state)
-{
-       if (get_acpi(CM_ASL_BLUETOOTH) == 1)
-               *state = RFKILL_STATE_UNBLOCKED;
-       else
-               *state = RFKILL_STATE_SOFT_BLOCKED;
-       return 0;
-}
+static const struct rfkill_ops eeepc_rfkill_ops = {
+       .set_block = eeepc_rfkill_set,
+};
 
 /*
  * Sys helpers
@@ -531,9 +514,9 @@ static int notify_brn(void)
 
 static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
 {
-       enum rfkill_state state;
        struct pci_dev *dev;
        struct pci_bus *bus = pci_find_bus(0, 1);
+       bool blocked;
 
        if (event != ACPI_NOTIFY_BUS_CHECK)
                return;
@@ -543,9 +526,8 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
                return;
        }
 
-       eeepc_wlan_rfkill_state(ehotk->eeepc_wlan_rfkill, &state);
-
-       if (state == RFKILL_STATE_UNBLOCKED) {
+       blocked = eeepc_wlan_rfkill_blocked();
+       if (!blocked) {
                dev = pci_get_slot(bus, 0);
                if (dev) {
                        /* Device already present */
@@ -566,7 +548,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
                }
        }
 
-       rfkill_force_state(ehotk->eeepc_wlan_rfkill, state);
+       rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, blocked);
 }
 
 static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
@@ -684,26 +666,17 @@ static int eeepc_hotk_add(struct acpi_device *device)
        eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
 
        if (get_acpi(CM_ASL_WLAN) != -1) {
-               ehotk->eeepc_wlan_rfkill = rfkill_allocate(&device->dev,
-                                                          RFKILL_TYPE_WLAN);
+               ehotk->eeepc_wlan_rfkill = rfkill_alloc("eeepc-wlan",
+                                                       &device->dev,
+                                                       RFKILL_TYPE_WLAN,
+                                                       &eeepc_rfkill_ops,
+                                                       (void *)CM_ASL_WLAN);
 
                if (!ehotk->eeepc_wlan_rfkill)
                        goto wlan_fail;
 
-               ehotk->eeepc_wlan_rfkill->name = "eeepc-wlan";
-               ehotk->eeepc_wlan_rfkill->toggle_radio = eeepc_wlan_rfkill_set;
-               ehotk->eeepc_wlan_rfkill->get_state = eeepc_wlan_rfkill_state;
-               if (get_acpi(CM_ASL_WLAN) == 1) {
-                       ehotk->eeepc_wlan_rfkill->state =
-                               RFKILL_STATE_UNBLOCKED;
-                       rfkill_set_default(RFKILL_TYPE_WLAN,
-                                          RFKILL_STATE_UNBLOCKED);
-               } else {
-                       ehotk->eeepc_wlan_rfkill->state =
-                               RFKILL_STATE_SOFT_BLOCKED;
-                       rfkill_set_default(RFKILL_TYPE_WLAN,
-                                          RFKILL_STATE_SOFT_BLOCKED);
-               }
+               rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill,
+                                   get_acpi(CM_ASL_WLAN) != 1);
                result = rfkill_register(ehotk->eeepc_wlan_rfkill);
                if (result)
                        goto wlan_fail;
@@ -711,28 +684,17 @@ static int eeepc_hotk_add(struct acpi_device *device)
 
        if (get_acpi(CM_ASL_BLUETOOTH) != -1) {
                ehotk->eeepc_bluetooth_rfkill =
-                       rfkill_allocate(&device->dev, RFKILL_TYPE_BLUETOOTH);
+                       rfkill_alloc("eeepc-bluetooth",
+                                    &device->dev,
+                                    RFKILL_TYPE_BLUETOOTH,
+                                    &eeepc_rfkill_ops,
+                                    (void *)CM_ASL_BLUETOOTH);
 
                if (!ehotk->eeepc_bluetooth_rfkill)
                        goto bluetooth_fail;
 
-               ehotk->eeepc_bluetooth_rfkill->name = "eeepc-bluetooth";
-               ehotk->eeepc_bluetooth_rfkill->toggle_radio =
-                       eeepc_bluetooth_rfkill_set;
-               ehotk->eeepc_bluetooth_rfkill->get_state =
-                       eeepc_bluetooth_rfkill_state;
-               if (get_acpi(CM_ASL_BLUETOOTH) == 1) {
-                       ehotk->eeepc_bluetooth_rfkill->state =
-                               RFKILL_STATE_UNBLOCKED;
-                       rfkill_set_default(RFKILL_TYPE_BLUETOOTH,
-                                          RFKILL_STATE_UNBLOCKED);
-               } else {
-                       ehotk->eeepc_bluetooth_rfkill->state =
-                               RFKILL_STATE_SOFT_BLOCKED;
-                       rfkill_set_default(RFKILL_TYPE_BLUETOOTH,
-                                          RFKILL_STATE_SOFT_BLOCKED);
-               }
-
+               rfkill_set_sw_state(ehotk->eeepc_bluetooth_rfkill,
+                                   get_acpi(CM_ASL_BLUETOOTH) != 1);
                result = rfkill_register(ehotk->eeepc_bluetooth_rfkill);
                if (result)
                        goto bluetooth_fail;
@@ -741,13 +703,10 @@ static int eeepc_hotk_add(struct acpi_device *device)
        return 0;
 
  bluetooth_fail:
-       if (ehotk->eeepc_bluetooth_rfkill)
-               rfkill_free(ehotk->eeepc_bluetooth_rfkill);
+       rfkill_destroy(ehotk->eeepc_bluetooth_rfkill);
        rfkill_unregister(ehotk->eeepc_wlan_rfkill);
-       ehotk->eeepc_wlan_rfkill = NULL;
  wlan_fail:
-       if (ehotk->eeepc_wlan_rfkill)
-               rfkill_free(ehotk->eeepc_wlan_rfkill);
+       rfkill_destroy(ehotk->eeepc_wlan_rfkill);
        eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
        eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
  ehotk_fail:
index fe171fa..16fffe4 100644 (file)
@@ -154,58 +154,46 @@ static int hp_wmi_dock_state(void)
        return hp_wmi_perform_query(HPWMI_DOCK_QUERY, 0, 0);
 }
 
-static int hp_wmi_wifi_set(void *data, enum rfkill_state state)
+static int hp_wmi_set_block(void *data, bool blocked)
 {
-       if (state)
-               return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x101);
-       else
-               return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x100);
-}
+       unsigned long b = (unsigned long) data;
+       int query = BIT(b + 8) | ((!!blocked) << b);
 
-static int hp_wmi_bluetooth_set(void *data, enum rfkill_state state)
-{
-       if (state)
-               return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x202);
-       else
-               return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x200);
+       return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query);
 }
 
-static int hp_wmi_wwan_set(void *data, enum rfkill_state state)
-{
-       if (state)
-               return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x404);
-       else
-               return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x400);
-}
+static const struct rfkill_ops hp_wmi_rfkill_ops = {
+       .set_block = hp_wmi_set_block,
+};
 
-static int hp_wmi_wifi_state(void)
+static bool hp_wmi_wifi_state(void)
 {
        int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
 
        if (wireless & 0x100)
-               return RFKILL_STATE_UNBLOCKED;
+               return false;
        else
-               return RFKILL_STATE_SOFT_BLOCKED;
+               return true;
 }
 
-static int hp_wmi_bluetooth_state(void)
+static bool hp_wmi_bluetooth_state(void)
 {
        int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
 
        if (wireless & 0x10000)
-               return RFKILL_STATE_UNBLOCKED;
+               return false;
        else
-               return RFKILL_STATE_SOFT_BLOCKED;
+               return true;
 }
 
-static int hp_wmi_wwan_state(void)
+static bool hp_wmi_wwan_state(void)
 {
        int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
 
        if (wireless & 0x1000000)
-               return RFKILL_STATE_UNBLOCKED;
+               return false;
        else
-               return RFKILL_STATE_SOFT_BLOCKED;
+               return true;
 }
 
 static ssize_t show_display(struct device *dev, struct device_attribute *attr,
@@ -347,14 +335,14 @@ static void hp_wmi_notify(u32 value, void *context)
                        }
                } else if (eventcode == 0x5) {
                        if (wifi_rfkill)
-                               rfkill_force_state(wifi_rfkill,
-                                                  hp_wmi_wifi_state());
+                               rfkill_set_sw_state(wifi_rfkill,
+                                                   hp_wmi_wifi_state());
                        if (bluetooth_rfkill)
-                               rfkill_force_state(bluetooth_rfkill,
-                                                  hp_wmi_bluetooth_state());
+                               rfkill_set_sw_state(bluetooth_rfkill,
+                                                   hp_wmi_bluetooth_state());
                        if (wwan_rfkill)
-                               rfkill_force_state(wwan_rfkill,
-                                                  hp_wmi_wwan_state());
+                               rfkill_set_sw_state(wwan_rfkill,
+                                                   hp_wmi_wwan_state());
                } else
                        printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n",
                               eventcode);
@@ -430,31 +418,30 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
                goto add_sysfs_error;
 
        if (wireless & 0x1) {
-               wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN);
-               wifi_rfkill->name = "hp-wifi";
-               wifi_rfkill->state = hp_wmi_wifi_state();
-               wifi_rfkill->toggle_radio = hp_wmi_wifi_set;
+               wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
+                                          RFKILL_TYPE_WLAN,
+                                          &hp_wmi_rfkill_ops,
+                                          (void *) 0);
                err = rfkill_register(wifi_rfkill);
                if (err)
-                       goto add_sysfs_error;
+                       goto register_wifi_error;
        }
 
        if (wireless & 0x2) {
-               bluetooth_rfkill = rfkill_allocate(&device->dev,
-                                                  RFKILL_TYPE_BLUETOOTH);
-               bluetooth_rfkill->name = "hp-bluetooth";
-               bluetooth_rfkill->state = hp_wmi_bluetooth_state();
-               bluetooth_rfkill->toggle_radio = hp_wmi_bluetooth_set;
+               bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev,
+                                               RFKILL_TYPE_BLUETOOTH,
+                                               &hp_wmi_rfkill_ops,
+                                               (void *) 1);
                err = rfkill_register(bluetooth_rfkill);
                if (err)
                        goto register_bluetooth_error;
        }
 
        if (wireless & 0x4) {
-               wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN);
-               wwan_rfkill->name = "hp-wwan";
-               wwan_rfkill->state = hp_wmi_wwan_state();
-               wwan_rfkill->toggle_radio = hp_wmi_wwan_set;
+               wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev,
+                                          RFKILL_TYPE_WWAN,
+                                          &hp_wmi_rfkill_ops,
+                                          (void *) 2);
                err = rfkill_register(wwan_rfkill);
                if (err)
                        goto register_wwan_err;
@@ -462,11 +449,15 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
 
        return 0;
 register_wwan_err:
+       rfkill_destroy(wwan_rfkill);
        if (bluetooth_rfkill)
                rfkill_unregister(bluetooth_rfkill);
 register_bluetooth_error:
+       rfkill_destroy(bluetooth_rfkill);
        if (wifi_rfkill)
                rfkill_unregister(wifi_rfkill);
+register_wifi_error:
+       rfkill_destroy(wifi_rfkill);
 add_sysfs_error:
        cleanup_sysfs(device);
        return err;
@@ -476,12 +467,18 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device)
 {
        cleanup_sysfs(device);
 
-       if (wifi_rfkill)
+       if (wifi_rfkill) {
                rfkill_unregister(wifi_rfkill);
-       if (bluetooth_rfkill)
+               rfkill_destroy(wifi_rfkill);
+       }
+       if (bluetooth_rfkill) {
                rfkill_unregister(bluetooth_rfkill);
-       if (wwan_rfkill)
+               rfkill_destroy(wifi_rfkill);
+       }
+       if (wwan_rfkill) {
                rfkill_unregister(wwan_rfkill);
+               rfkill_destroy(wwan_rfkill);
+       }
 
        return 0;
 }
index f1963b0..e48d9a4 100644 (file)
@@ -128,11 +128,11 @@ enum sony_nc_rfkill {
        SONY_BLUETOOTH,
        SONY_WWAN,
        SONY_WIMAX,
-       SONY_RFKILL_MAX,
+       N_SONY_RFKILL,
 };
 
-static struct rfkill *sony_rfkill_devices[SONY_RFKILL_MAX];
-static int sony_rfkill_address[SONY_RFKILL_MAX] = {0x300, 0x500, 0x700, 0x900};
+static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL];
+static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900};
 static void sony_nc_rfkill_update(void);
 
 /*********** Input Devices ***********/
@@ -1051,147 +1051,96 @@ static void sony_nc_rfkill_cleanup(void)
 {
        int i;
 
-       for (i = 0; i < SONY_RFKILL_MAX; i++) {
-               if (sony_rfkill_devices[i])
+       for (i = 0; i < N_SONY_RFKILL; i++) {
+               if (sony_rfkill_devices[i]) {
                        rfkill_unregister(sony_rfkill_devices[i]);
+                       rfkill_destroy(sony_rfkill_devices[i]);
+               }
        }
 }
 
-static int sony_nc_rfkill_get(void *data, enum rfkill_state *state)
-{
-       int result;
-       int argument = sony_rfkill_address[(long) data];
-
-       sony_call_snc_handle(0x124, 0x200, &result);
-       if (result & 0x1) {
-               sony_call_snc_handle(0x124, argument, &result);
-               if (result & 0xf)
-                       *state = RFKILL_STATE_UNBLOCKED;
-               else
-                       *state = RFKILL_STATE_SOFT_BLOCKED;
-       } else {
-               *state = RFKILL_STATE_HARD_BLOCKED;
-       }
-
-       return 0;
-}
-
-static int sony_nc_rfkill_set(void *data, enum rfkill_state state)
+static int sony_nc_rfkill_set(void *data, bool blocked)
 {
        int result;
        int argument = sony_rfkill_address[(long) data] + 0x100;
 
-       if (state == RFKILL_STATE_UNBLOCKED)
+       if (!blocked)
                argument |= 0xff0000;
 
        return sony_call_snc_handle(0x124, argument, &result);
 }
 
-static int sony_nc_setup_wifi_rfkill(struct acpi_device *device)
-{
-       int err = 0;
-       struct rfkill *sony_wifi_rfkill;
-
-       sony_wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN);
-       if (!sony_wifi_rfkill)
-               return -1;
-       sony_wifi_rfkill->name = "sony-wifi";
-       sony_wifi_rfkill->toggle_radio = sony_nc_rfkill_set;
-       sony_wifi_rfkill->get_state = sony_nc_rfkill_get;
-       sony_wifi_rfkill->data = (void *)SONY_WIFI;
-       err = rfkill_register(sony_wifi_rfkill);
-       if (err)
-               rfkill_free(sony_wifi_rfkill);
-       else {
-               sony_rfkill_devices[SONY_WIFI] = sony_wifi_rfkill;
-               sony_nc_rfkill_set(sony_wifi_rfkill->data,
-                               RFKILL_STATE_UNBLOCKED);
-       }
-       return err;
-}
+static const struct rfkill_ops sony_rfkill_ops = {
+       .set_block = sony_nc_rfkill_set,
+};
 
-static int sony_nc_setup_bluetooth_rfkill(struct acpi_device *device)
+static int sony_nc_setup_rfkill(struct acpi_device *device,
+                               enum sony_nc_rfkill nc_type)
 {
        int err = 0;
-       struct rfkill *sony_bluetooth_rfkill;
-
-       sony_bluetooth_rfkill = rfkill_allocate(&device->dev,
-                                               RFKILL_TYPE_BLUETOOTH);
-       if (!sony_bluetooth_rfkill)
-               return -1;
-       sony_bluetooth_rfkill->name = "sony-bluetooth";
-       sony_bluetooth_rfkill->toggle_radio = sony_nc_rfkill_set;
-       sony_bluetooth_rfkill->get_state = sony_nc_rfkill_get;
-       sony_bluetooth_rfkill->data = (void *)SONY_BLUETOOTH;
-       err = rfkill_register(sony_bluetooth_rfkill);
-       if (err)
-               rfkill_free(sony_bluetooth_rfkill);
-       else {
-               sony_rfkill_devices[SONY_BLUETOOTH] = sony_bluetooth_rfkill;
-               sony_nc_rfkill_set(sony_bluetooth_rfkill->data,
-                               RFKILL_STATE_UNBLOCKED);
+       struct rfkill *rfk;
+       enum rfkill_type type;
+       const char *name;
+
+       switch (nc_type) {
+       case SONY_WIFI:
+               type = RFKILL_TYPE_WLAN;
+               name = "sony-wifi";
+               break;
+       case SONY_BLUETOOTH:
+               type = RFKILL_TYPE_BLUETOOTH;
+               name = "sony-bluetooth";
+               break;
+       case SONY_WWAN:
+               type = RFKILL_TYPE_WWAN;
+               name = "sony-wwan";
+               break;
+       case SONY_WIMAX:
+               type = RFKILL_TYPE_WIMAX;
+               name = "sony-wimax";
+               break;
+       default:
+               return -EINVAL;
        }
-       return err;
-}
 
-static int sony_nc_setup_wwan_rfkill(struct acpi_device *device)
-{
-       int err = 0;
-       struct rfkill *sony_wwan_rfkill;
+       rfk = rfkill_alloc(name, &device->dev, type,
+                          &sony_rfkill_ops, (void *)nc_type);
+       if (!rfk)
+               return -ENOMEM;
 
-       sony_wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN);
-       if (!sony_wwan_rfkill)
-               return -1;
-       sony_wwan_rfkill->name = "sony-wwan";
-       sony_wwan_rfkill->toggle_radio = sony_nc_rfkill_set;
-       sony_wwan_rfkill->get_state = sony_nc_rfkill_get;
-       sony_wwan_rfkill->data = (void *)SONY_WWAN;
-       err = rfkill_register(sony_wwan_rfkill);
-       if (err)
-               rfkill_free(sony_wwan_rfkill);
-       else {
-               sony_rfkill_devices[SONY_WWAN] = sony_wwan_rfkill;
-               sony_nc_rfkill_set(sony_wwan_rfkill->data,
-                               RFKILL_STATE_UNBLOCKED);
+       err = rfkill_register(rfk);
+       if (err) {
+               rfkill_destroy(rfk);
+               return err;
        }
+       sony_rfkill_devices[nc_type] = rfk;
        return err;
 }
 
-static int sony_nc_setup_wimax_rfkill(struct acpi_device *device)
+static void sony_nc_rfkill_update()
 {
-       int err = 0;
-       struct rfkill *sony_wimax_rfkill;
+       enum sony_nc_rfkill i;
+       int result;
+       bool hwblock;
 
-       sony_wimax_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WIMAX);
-       if (!sony_wimax_rfkill)
-               return -1;
-       sony_wimax_rfkill->name = "sony-wimax";
-       sony_wimax_rfkill->toggle_radio = sony_nc_rfkill_set;
-       sony_wimax_rfkill->get_state = sony_nc_rfkill_get;
-       sony_wimax_rfkill->data = (void *)SONY_WIMAX;
-       err = rfkill_register(sony_wimax_rfkill);
-       if (err)
-               rfkill_free(sony_wimax_rfkill);
-       else {
-               sony_rfkill_devices[SONY_WIMAX] = sony_wimax_rfkill;
-               sony_nc_rfkill_set(sony_wimax_rfkill->data,
-                               RFKILL_STATE_UNBLOCKED);
-       }
-       return err;
-}
+       sony_call_snc_handle(0x124, 0x200, &result);
+       hwblock = !(result & 0x1);
 
-static void sony_nc_rfkill_update()
-{
-       int i;
-       enum rfkill_state state;
+       for (i = 0; i < N_SONY_RFKILL; i++) {
+               int argument = sony_rfkill_address[i];
 
-       for (i = 0; i < SONY_RFKILL_MAX; i++) {
-               if (sony_rfkill_devices[i]) {
-                       sony_rfkill_devices[i]->
-                               get_state(sony_rfkill_devices[i]->data,
-                                         &state);
-                       rfkill_force_state(sony_rfkill_devices[i], state);
+               if (!sony_rfkill_devices[i])
+                       continue;
+
+               if (hwblock) {
+                       if (rfkill_set_hw_state(sony_rfkill_devices[i], true))
+                               sony_nc_rfkill_set((void *)i, true);
+                       continue;
                }
+
+               sony_call_snc_handle(0x124, argument, &result);
+               rfkill_set_states(sony_rfkill_devices[i],
+                                 !(result & 0xf), false);
        }
 }
 
@@ -1210,13 +1159,13 @@ static int sony_nc_rfkill_setup(struct acpi_device *device)
        }
 
        if (result & 0x1)
-               sony_nc_setup_wifi_rfkill(device);
+               sony_nc_setup_rfkill(device, SONY_WIFI);
        if (result & 0x2)
-               sony_nc_setup_bluetooth_rfkill(device);
+               sony_nc_setup_rfkill(device, SONY_BLUETOOTH);
        if (result & 0x1c)
-               sony_nc_setup_wwan_rfkill(device);
+               sony_nc_setup_rfkill(device, SONY_WWAN);
        if (result & 0x20)
-               sony_nc_setup_wimax_rfkill(device);
+               sony_nc_setup_rfkill(device, SONY_WIMAX);
 
        return 0;
 }
index 912be65..86e9585 100644 (file)
@@ -166,13 +166,6 @@ enum {
 
 #define TPACPI_MAX_ACPI_ARGS 3
 
-/* rfkill switches */
-enum {
-       TPACPI_RFK_BLUETOOTH_SW_ID = 0,
-       TPACPI_RFK_WWAN_SW_ID,
-       TPACPI_RFK_UWB_SW_ID,
-};
-
 /* printk headers */
 #define TPACPI_LOG TPACPI_FILE ": "
 #define TPACPI_EMERG   KERN_EMERG      TPACPI_LOG
@@ -1005,67 +998,234 @@ static int __init tpacpi_check_std_acpi_brightness_support(void)
        return 0;
 }
 
-static int __init tpacpi_new_rfkill(const unsigned int id,
-                       struct rfkill **rfk,
+static void printk_deprecated_attribute(const char * const what,
+                                       const char * const details)
+{
+       tpacpi_log_usertask("deprecated sysfs attribute");
+       printk(TPACPI_WARN "WARNING: sysfs attribute %s is deprecated and "
+               "will be removed. %s\n",
+               what, details);
+}
+
+/*************************************************************************
+ * rfkill and radio control support helpers
+ */
+
+/*
+ * ThinkPad-ACPI firmware handling model:
+ *
+ * WLSW (master wireless switch) is event-driven, and is common to all
+ * firmware-controlled radios.  It cannot be controlled, just monitored,
+ * as expected.  It overrides all radio state in firmware
+ *
+ * The kernel, a masked-off hotkey, and WLSW can change the radio state
+ * (TODO: verify how WLSW interacts with the returned radio state).
+ *
+ * The only time there are shadow radio state changes, is when
+ * masked-off hotkeys are used.
+ */
+
+/*
+ * Internal driver API for radio state:
+ *
+ * int: < 0 = error, otherwise enum tpacpi_rfkill_state
+ * bool: true means radio blocked (off)
+ */
+enum tpacpi_rfkill_state {
+       TPACPI_RFK_RADIO_OFF = 0,
+       TPACPI_RFK_RADIO_ON
+};
+
+/* rfkill switches */
+enum tpacpi_rfk_id {
+       TPACPI_RFK_BLUETOOTH_SW_ID = 0,
+       TPACPI_RFK_WWAN_SW_ID,
+       TPACPI_RFK_UWB_SW_ID,
+       TPACPI_RFK_SW_MAX
+};
+
+static const char *tpacpi_rfkill_names[] = {
+       [TPACPI_RFK_BLUETOOTH_SW_ID] = "bluetooth",
+       [TPACPI_RFK_WWAN_SW_ID] = "wwan",
+       [TPACPI_RFK_UWB_SW_ID] = "uwb",
+       [TPACPI_RFK_SW_MAX] = NULL
+};
+
+/* ThinkPad-ACPI rfkill subdriver */
+struct tpacpi_rfk {
+       struct rfkill *rfkill;
+       enum tpacpi_rfk_id id;
+       const struct tpacpi_rfk_ops *ops;
+};
+
+struct tpacpi_rfk_ops {
+       /* firmware interface */
+       int (*get_status)(void);
+       int (*set_status)(const enum tpacpi_rfkill_state);
+};
+
+static struct tpacpi_rfk *tpacpi_rfkill_switches[TPACPI_RFK_SW_MAX];
+
+/* Query FW and update rfkill sw state for a given rfkill switch */
+static int tpacpi_rfk_update_swstate(const struct tpacpi_rfk *tp_rfk)
+{
+       int status;
+
+       if (!tp_rfk)
+               return -ENODEV;
+
+       status = (tp_rfk->ops->get_status)();
+       if (status < 0)
+               return status;
+
+       rfkill_set_sw_state(tp_rfk->rfkill,
+                           (status == TPACPI_RFK_RADIO_OFF));
+
+       return status;
+}
+
+/* Query FW and update rfkill sw state for all rfkill switches */
+static void tpacpi_rfk_update_swstate_all(void)
+{
+       unsigned int i;
+
+       for (i = 0; i < TPACPI_RFK_SW_MAX; i++)
+               tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[i]);
+}
+
+/*
+ * Sync the HW-blocking state of all rfkill switches,
+ * do notice it causes the rfkill core to schedule uevents
+ */
+static void tpacpi_rfk_update_hwblock_state(bool blocked)
+{
+       unsigned int i;
+       struct tpacpi_rfk *tp_rfk;
+
+       for (i = 0; i < TPACPI_RFK_SW_MAX; i++) {
+               tp_rfk = tpacpi_rfkill_switches[i];
+               if (tp_rfk) {
+                       if (rfkill_set_hw_state(tp_rfk->rfkill,
+                                               blocked)) {
+                               /* ignore -- we track sw block */
+                       }
+               }
+       }
+}
+
+/* Call to get the WLSW state from the firmware */
+static int hotkey_get_wlsw(void);
+
+/* Call to query WLSW state and update all rfkill switches */
+static bool tpacpi_rfk_check_hwblock_state(void)
+{
+       int res = hotkey_get_wlsw();
+       int hw_blocked;
+
+       /* When unknown or unsupported, we have to assume it is unblocked */
+       if (res < 0)
+               return false;
+
+       hw_blocked = (res == TPACPI_RFK_RADIO_OFF);
+       tpacpi_rfk_update_hwblock_state(hw_blocked);
+
+       return hw_blocked;
+}
+
+static int tpacpi_rfk_hook_set_block(void *data, bool blocked)
+{
+       struct tpacpi_rfk *tp_rfk = data;
+       int res;
+
+       dbg_printk(TPACPI_DBG_RFKILL,
+                  "request to change radio state to %s\n",
+                  blocked ? "blocked" : "unblocked");
+
+       /* try to set radio state */
+       res = (tp_rfk->ops->set_status)(blocked ?
+                               TPACPI_RFK_RADIO_OFF : TPACPI_RFK_RADIO_ON);
+
+       /* and update the rfkill core with whatever the FW really did */
+       tpacpi_rfk_update_swstate(tp_rfk);
+
+       return (res < 0) ? res : 0;
+}
+
+static const struct rfkill_ops tpacpi_rfk_rfkill_ops = {
+       .set_block = tpacpi_rfk_hook_set_block,
+};
+
+static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id,
+                       const struct tpacpi_rfk_ops *tp_rfkops,
                        const enum rfkill_type rfktype,
                        const char *name,
-                       const bool set_default,
-                       int (*toggle_radio)(void *, enum rfkill_state),
-                       int (*get_state)(void *, enum rfkill_state *))
+                       const bool set_default)
 {
+       struct tpacpi_rfk *atp_rfk;
        int res;
-       enum rfkill_state initial_state = RFKILL_STATE_SOFT_BLOCKED;
-
-       res = get_state(NULL, &initial_state);
-       if (res < 0) {
-               printk(TPACPI_ERR
-                       "failed to read initial state for %s, error %d; "
-                       "will turn radio off\n", name, res);
-       } else if (set_default) {
-               /* try to set the initial state as the default for the rfkill
-                * type, since we ask the firmware to preserve it across S5 in
-                * NVRAM */
-               if (rfkill_set_default(rfktype,
-                               (initial_state == RFKILL_STATE_UNBLOCKED) ?
-                                       RFKILL_STATE_UNBLOCKED :
-                                       RFKILL_STATE_SOFT_BLOCKED) == -EPERM)
-                       vdbg_printk(TPACPI_DBG_RFKILL,
-                                   "Default state for %s cannot be changed\n",
-                                   name);
-       }
-
-       *rfk = rfkill_allocate(&tpacpi_pdev->dev, rfktype);
-       if (!*rfk) {
+       bool initial_sw_state = false;
+       int initial_sw_status;
+
+       BUG_ON(id >= TPACPI_RFK_SW_MAX || tpacpi_rfkill_switches[id]);
+
+       atp_rfk = kzalloc(sizeof(struct tpacpi_rfk), GFP_KERNEL);
+       if (atp_rfk)
+               atp_rfk->rfkill = rfkill_alloc(name,
+                                               &tpacpi_pdev->dev,
+                                               rfktype,
+                                               &tpacpi_rfk_rfkill_ops,
+                                               atp_rfk);
+       if (!atp_rfk || !atp_rfk->rfkill) {
                printk(TPACPI_ERR
                        "failed to allocate memory for rfkill class\n");
+               kfree(atp_rfk);
                return -ENOMEM;
        }
 
-       (*rfk)->name = name;
-       (*rfk)->get_state = get_state;
-       (*rfk)->toggle_radio = toggle_radio;
-       (*rfk)->state = initial_state;
+       atp_rfk->id = id;
+       atp_rfk->ops = tp_rfkops;
+
+       initial_sw_status = (tp_rfkops->get_status)();
+       if (initial_sw_status < 0) {
+               printk(TPACPI_ERR
+                       "failed to read initial state for %s, error %d\n",
+                       name, initial_sw_status);
+       } else {
+               initial_sw_state = (initial_sw_status == TPACPI_RFK_RADIO_OFF);
+               if (set_default) {
+                       /* try to keep the initial state, since we ask the
+                        * firmware to preserve it across S5 in NVRAM */
+                       rfkill_set_sw_state(atp_rfk->rfkill, initial_sw_state);
+               }
+       }
+       rfkill_set_hw_state(atp_rfk->rfkill, tpacpi_rfk_check_hwblock_state());
 
-       res = rfkill_register(*rfk);
+       res = rfkill_register(atp_rfk->rfkill);
        if (res < 0) {
                printk(TPACPI_ERR
                        "failed to register %s rfkill switch: %d\n",
                        name, res);
-               rfkill_free(*rfk);
-               *rfk = NULL;
+               rfkill_destroy(atp_rfk->rfkill);
+               kfree(atp_rfk);
                return res;
        }
 
+       tpacpi_rfkill_switches[id] = atp_rfk;
        return 0;
 }
 
-static void printk_deprecated_attribute(const char * const what,
-                                       const char * const details)
+static void tpacpi_destroy_rfkill(const enum tpacpi_rfk_id id)
 {
-       tpacpi_log_usertask("deprecated sysfs attribute");
-       printk(TPACPI_WARN "WARNING: sysfs attribute %s is deprecated and "
-               "will be removed. %s\n",
-               what, details);
+       struct tpacpi_rfk *tp_rfk;
+
+       BUG_ON(id >= TPACPI_RFK_SW_MAX);
+
+       tp_rfk = tpacpi_rfkill_switches[id];
+       if (tp_rfk) {
+               rfkill_unregister(tp_rfk->rfkill);
+               tpacpi_rfkill_switches[id] = NULL;
+               kfree(tp_rfk);
+       }
 }
 
 static void printk_deprecated_rfkill_attribute(const char * const what)
@@ -1074,6 +1234,112 @@ static void printk_deprecated_rfkill_attribute(const char * const what)
                        "Please switch to generic rfkill before year 2010");
 }
 
+/* sysfs <radio> enable ------------------------------------------------ */
+static ssize_t tpacpi_rfk_sysfs_enable_show(const enum tpacpi_rfk_id id,
+                                           struct device_attribute *attr,
+                                           char *buf)
+{
+       int status;
+
+       printk_deprecated_rfkill_attribute(attr->attr.name);
+
+       /* This is in the ABI... */
+       if (tpacpi_rfk_check_hwblock_state()) {
+               status = TPACPI_RFK_RADIO_OFF;
+       } else {
+               status = tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[id]);
+               if (status < 0)
+                       return status;
+       }
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+                       (status == TPACPI_RFK_RADIO_ON) ? 1 : 0);
+}
+
+static ssize_t tpacpi_rfk_sysfs_enable_store(const enum tpacpi_rfk_id id,
+                           struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       unsigned long t;
+       int res;
+
+       printk_deprecated_rfkill_attribute(attr->attr.name);
+
+       if (parse_strtoul(buf, 1, &t))
+               return -EINVAL;
+
+       tpacpi_disclose_usertask(attr->attr.name, "set to %ld\n", t);
+
+       /* This is in the ABI... */
+       if (tpacpi_rfk_check_hwblock_state() && !!t)
+               return -EPERM;
+
+       res = tpacpi_rfkill_switches[id]->ops->set_status((!!t) ?
+                               TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF);
+       tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[id]);
+
+       return (res < 0) ? res : count;
+}
+
+/* procfs -------------------------------------------------------------- */
+static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, char *p)
+{
+       int len = 0;
+
+       if (id >= TPACPI_RFK_SW_MAX)
+               len += sprintf(p + len, "status:\t\tnot supported\n");
+       else {
+               int status;
+
+               /* This is in the ABI... */
+               if (tpacpi_rfk_check_hwblock_state()) {
+                       status = TPACPI_RFK_RADIO_OFF;
+               } else {
+                       status = tpacpi_rfk_update_swstate(
+                                               tpacpi_rfkill_switches[id]);
+                       if (status < 0)
+                               return status;
+               }
+
+               len += sprintf(p + len, "status:\t\t%s\n",
+                               (status == TPACPI_RFK_RADIO_ON) ?
+                                       "enabled" : "disabled");
+               len += sprintf(p + len, "commands:\tenable, disable\n");
+       }
+
+       return len;
+}
+
+static int tpacpi_rfk_procfs_write(const enum tpacpi_rfk_id id, char *buf)
+{
+       char *cmd;
+       int status = -1;
+       int res = 0;
+
+       if (id >= TPACPI_RFK_SW_MAX)
+               return -ENODEV;
+
+       while ((cmd = next_cmd(&buf))) {
+               if (strlencmp(cmd, "enable") == 0)
+                       status = TPACPI_RFK_RADIO_ON;
+               else if (strlencmp(cmd, "disable") == 0)
+                       status = TPACPI_RFK_RADIO_OFF;
+               else
+                       return -EINVAL;
+       }
+
+       if (status != -1) {
+               tpacpi_disclose_usertask("procfs", "attempt to %s %s\n",
+                               (status == TPACPI_RFK_RADIO_ON) ?
+                                               "enable" : "disable",
+                               tpacpi_rfkill_names[id]);
+               res = (tpacpi_rfkill_switches[id]->ops->set_status)(status);
+               tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[id]);
+       }
+
+       return res;
+}
+
 /*************************************************************************
  * thinkpad-acpi driver attributes
  */
@@ -1127,8 +1393,6 @@ static DRIVER_ATTR(version, S_IRUGO,
 
 #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
 
-static void tpacpi_send_radiosw_update(void);
-
 /* wlsw_emulstate ------------------------------------------------------ */
 static ssize_t tpacpi_driver_wlsw_emulstate_show(struct device_driver *drv,
                                                char *buf)
@@ -1144,11 +1408,10 @@ static ssize_t tpacpi_driver_wlsw_emulstate_store(struct device_driver *drv,
        if (parse_strtoul(buf, 1, &t))
                return -EINVAL;
 
-       if (tpacpi_wlsw_emulstate != t) {
-               tpacpi_wlsw_emulstate = !!t;
-               tpacpi_send_radiosw_update();
-       } else
+       if (tpacpi_wlsw_emulstate != !!t) {
                tpacpi_wlsw_emulstate = !!t;
+               tpacpi_rfk_update_hwblock_state(!t);    /* negative logic */
+       }
 
        return count;
 }
@@ -1463,17 +1726,23 @@ static struct attribute_set *hotkey_dev_attributes;
 /* HKEY.MHKG() return bits */
 #define TP_HOTKEY_TABLET_MASK (1 << 3)
 
-static int hotkey_get_wlsw(int *status)
+static int hotkey_get_wlsw(void)
 {
+       int status;
+
+       if (!tp_features.hotkey_wlsw)
+               return -ENODEV;
+
 #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
-       if (dbg_wlswemul) {
-               *status = !!tpacpi_wlsw_emulstate;
-               return 0;
-       }
+       if (dbg_wlswemul)
+               return (tpacpi_wlsw_emulstate) ?
+                               TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF;
 #endif
-       if (!acpi_evalf(hkey_handle, status, "WLSW", "d"))
+
+       if (!acpi_evalf(hkey_handle, &status, "WLSW", "d"))
                return -EIO;
-       return 0;
+
+       return (status) ? TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF;
 }
 
 static int hotkey_get_tablet_mode(int *status)
@@ -2107,12 +2376,16 @@ static ssize_t hotkey_radio_sw_show(struct device *dev,
                           struct device_attribute *attr,
                           char *buf)
 {
-       int res, s;
-       res = hotkey_get_wlsw(&s);
+       int res;
+       res = hotkey_get_wlsw();
        if (res < 0)
                return res;
 
-       return snprintf(buf, PAGE_SIZE, "%d\n", !!s);
+       /* Opportunistic update */
+       tpacpi_rfk_update_hwblock_state((res == TPACPI_RFK_RADIO_OFF));
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+                       (res == TPACPI_RFK_RADIO_OFF) ? 0 : 1);
 }
 
 static struct device_attribute dev_attr_hotkey_radio_sw =
@@ -2223,30 +2496,52 @@ static struct attribute *hotkey_mask_attributes[] __initdata = {
        &dev_attr_hotkey_wakeup_hotunplug_complete.attr,
 };
 
-static void bluetooth_update_rfk(void);
-static void wan_update_rfk(void);
-static void uwb_update_rfk(void);
+/*
+ * Sync both the hw and sw blocking state of all switches
+ */
 static void tpacpi_send_radiosw_update(void)
 {
        int wlsw;
 
-       /* Sync these BEFORE sending any rfkill events */
-       if (tp_features.bluetooth)
-               bluetooth_update_rfk();
-       if (tp_features.wan)
-               wan_update_rfk();
-       if (tp_features.uwb)
-               uwb_update_rfk();
+       /*
+        * We must sync all rfkill controllers *before* issuing any
+        * rfkill input events, or we will race the rfkill core input
+        * handler.
+        *
+        * tpacpi_inputdev_send_mutex works as a syncronization point
+        * for the above.
+        *
+        * We optimize to avoid numerous calls to hotkey_get_wlsw.
+        */
+
+       wlsw = hotkey_get_wlsw();
+
+       /* Sync hw blocking state first if it is hw-blocked */
+       if (wlsw == TPACPI_RFK_RADIO_OFF)
+               tpacpi_rfk_update_hwblock_state(true);
 
-       if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
+       /* Sync sw blocking state */
+       tpacpi_rfk_update_swstate_all();
+
+       /* Sync hw blocking state last if it is hw-unblocked */
+       if (wlsw == TPACPI_RFK_RADIO_ON)
+               tpacpi_rfk_update_hwblock_state(false);
+
+       /* Issue rfkill input event for WLSW switch */
+       if (!(wlsw < 0)) {
                mutex_lock(&tpacpi_inputdev_send_mutex);
 
                input_report_switch(tpacpi_inputdev,
-                                   SW_RFKILL_ALL, !!wlsw);
+                                   SW_RFKILL_ALL, (wlsw > 0));
                input_sync(tpacpi_inputdev);
 
                mutex_unlock(&tpacpi_inputdev_send_mutex);
        }
+
+       /*
+        * this can be unconditional, as we will poll state again
+        * if userspace uses the notify to read data
+        */
        hotkey_radio_sw_notify_change();
 }
 
@@ -3056,8 +3351,6 @@ enum {
 
 #define TPACPI_RFK_BLUETOOTH_SW_NAME   "tpacpi_bluetooth_sw"
 
-static struct rfkill *tpacpi_bluetooth_rfkill;
-
 static void bluetooth_suspend(pm_message_t state)
 {
        /* Try to make sure radio will resume powered off */
@@ -3067,83 +3360,47 @@ static void bluetooth_suspend(pm_message_t state)
                        "bluetooth power down on resume request failed\n");
 }
 
-static int bluetooth_get_radiosw(void)
+static int bluetooth_get_status(void)
 {
        int status;
 
-       if (!tp_features.bluetooth)
-               return -ENODEV;
-
-       /* WLSW overrides bluetooth in firmware/hardware, reflect that */
-       if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status)
-               return RFKILL_STATE_HARD_BLOCKED;
-
 #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
        if (dbg_bluetoothemul)
                return (tpacpi_bluetooth_emulstate) ?
-                       RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
+                      TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF;
 #endif
 
        if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
                return -EIO;
 
        return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0) ?
-               RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
-}
-
-static void bluetooth_update_rfk(void)
-{
-       int status;
-
-       if (!tpacpi_bluetooth_rfkill)
-               return;
-
-       status = bluetooth_get_radiosw();
-       if (status < 0)
-               return;
-       rfkill_force_state(tpacpi_bluetooth_rfkill, status);
-
-       vdbg_printk(TPACPI_DBG_RFKILL,
-               "forced rfkill state to %d\n",
-               status);
+                       TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF;
 }
 
-static int bluetooth_set_radiosw(int radio_on, int update_rfk)
+static int bluetooth_set_status(enum tpacpi_rfkill_state state)
 {
        int status;
 
-       if (!tp_features.bluetooth)
-               return -ENODEV;
-
-       /* WLSW overrides bluetooth in firmware/hardware, but there is no
-        * reason to risk weird behaviour. */
-       if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status
-           && radio_on)
-               return -EPERM;
-
        vdbg_printk(TPACPI_DBG_RFKILL,
-               "will %s bluetooth\n", radio_on ? "enable" : "disable");
+               "will attempt to %s bluetooth\n",
+               (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable");
 
 #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
        if (dbg_bluetoothemul) {
-               tpacpi_bluetooth_emulstate = !!radio_on;
-               if (update_rfk)
-                       bluetooth_update_rfk();
+               tpacpi_bluetooth_emulstate = (state == TPACPI_RFK_RADIO_ON);
                return 0;
        }
 #endif
 
        /* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */
-       if (radio_on)
+       if (state == TPACPI_RFK_RADIO_ON)
                status = TP_ACPI_BLUETOOTH_RADIOSSW;
        else
                status = 0;
+
        if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
                return -EIO;
 
-       if (update_rfk)
-               bluetooth_update_rfk();
-
        return 0;
 }
 
@@ -3152,35 +3409,16 @@ static ssize_t bluetooth_enable_show(struct device *dev,
                           struct device_attribute *attr,
                           char *buf)
 {
-       int status;
-
-       printk_deprecated_rfkill_attribute("bluetooth_enable");
-
-       status = bluetooth_get_radiosw();
-       if (status < 0)
-               return status;
-
-       return snprintf(buf, PAGE_SIZE, "%d\n",
-                       (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0);
+       return tpacpi_rfk_sysfs_enable_show(TPACPI_RFK_BLUETOOTH_SW_ID,
+                       attr, buf);
 }
 
 static ssize_t bluetooth_enable_store(struct device *dev,
                            struct device_attribute *attr,
                            const char *buf, size_t count)
 {
-       unsigned long t;
-       int res;
-
-       printk_deprecated_rfkill_attribute("bluetooth_enable");
-
-       if (parse_strtoul(buf, 1, &t))
-               return -EINVAL;
-
-       tpacpi_disclose_usertask("bluetooth_enable", "set to %ld\n", t);
-
-       res = bluetooth_set_radiosw(t, 1);
-
-       return (res) ? res : count;
+       return tpacpi_rfk_sysfs_enable_store(TPACPI_RFK_BLUETOOTH_SW_ID,
+                               attr, buf, count);
 }
 
 static struct device_attribute dev_attr_bluetooth_enable =
@@ -3198,23 +3436,10 @@ static const struct attribute_group bluetooth_attr_group = {
        .attrs = bluetooth_attributes,
 };
 
-static int tpacpi_bluetooth_rfk_get(void *data, enum rfkill_state *state)
-{
-       int bts = bluetooth_get_radiosw();
-
-       if (bts < 0)
-               return bts;
-
-       *state = bts;
-       return 0;
-}
-
-static int tpacpi_bluetooth_rfk_set(void *data, enum rfkill_state state)
-{
-       dbg_printk(TPACPI_DBG_RFKILL,
-                  "request to change radio state to %d\n", state);
-       return bluetooth_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0);
-}
+static const struct tpacpi_rfk_ops bluetooth_tprfk_ops = {
+       .get_status = bluetooth_get_status,
+       .set_status = bluetooth_set_status,
+};
 
 static void bluetooth_shutdown(void)
 {
@@ -3230,13 +3455,12 @@ static void bluetooth_shutdown(void)
 
 static void bluetooth_exit(void)
 {
-       bluetooth_shutdown();
-
-       if (tpacpi_bluetooth_rfkill)
-               rfkill_unregister(tpacpi_bluetooth_rfkill);
-
        sysfs_remove_group(&tpacpi_pdev->dev.kobj,
                        &bluetooth_attr_group);
+
+       tpacpi_destroy_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID);
+
+       bluetooth_shutdown();
 }
 
 static int __init bluetooth_init(struct ibm_init_struct *iibm)
@@ -3277,20 +3501,18 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
        if (!tp_features.bluetooth)
                return 1;
 
-       res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
-                               &bluetooth_attr_group);
-       if (res)
-               return res;
-
        res = tpacpi_new_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID,
-                               &tpacpi_bluetooth_rfkill,
+                               &bluetooth_tprfk_ops,
                                RFKILL_TYPE_BLUETOOTH,
                                TPACPI_RFK_BLUETOOTH_SW_NAME,
-                               true,
-                               tpacpi_bluetooth_rfk_set,
-                               tpacpi_bluetooth_rfk_get);
+                               true);
+       if (res)
+               return res;
+
+       res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+                               &bluetooth_attr_group);
        if (res) {
-               bluetooth_exit();
+               tpacpi_destroy_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID);
                return res;
        }
 
@@ -3300,46 +3522,12 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
 /* procfs -------------------------------------------------------------- */
 static int bluetooth_read(char *p)
 {
-       int len = 0;
-       int status = bluetooth_get_radiosw();
-
-       if (!tp_features.bluetooth)
-               len += sprintf(p + len, "status:\t\tnot supported\n");
-       else {
-               len += sprintf(p + len, "status:\t\t%s\n",
-                               (status == RFKILL_STATE_UNBLOCKED) ?
-                                       "enabled" : "disabled");
-               len += sprintf(p + len, "commands:\tenable, disable\n");
-       }
-
-       return len;
+       return tpacpi_rfk_procfs_read(TPACPI_RFK_BLUETOOTH_SW_ID, p);
 }
 
 static int bluetooth_write(char *buf)
 {
-       char *cmd;
-       int state = -1;
-
-       if (!tp_features.bluetooth)
-               return -ENODEV;
-
-       while ((cmd = next_cmd(&buf))) {
-               if (strlencmp(cmd, "enable") == 0) {
-                       state = 1;
-               } else if (strlencmp(cmd, "disable") == 0) {
-                       state = 0;
-               } else
-                       return -EINVAL;
-       }
-
-       if (state != -1) {
-               tpacpi_disclose_usertask("procfs bluetooth",
-                       "attempt to %s\n",
-                       state ? "enable" : "disable");
-               bluetooth_set_radiosw(state, 1);
-       }
-
-       return 0;
+       return tpacpi_rfk_procfs_write(TPACPI_RFK_BLUETOOTH_SW_ID, buf);
 }
 
 static struct ibm_struct bluetooth_driver_data = {
@@ -3365,8 +3553,6 @@ enum {
 
 #define TPACPI_RFK_WWAN_SW_NAME                "tpacpi_wwan_sw"
 
-static struct rfkill *tpacpi_wan_rfkill;
-
 static void wan_suspend(pm_message_t state)
 {
        /* Try to make sure radio will resume powered off */
@@ -3376,83 +3562,47 @@ static void wan_suspend(pm_message_t state)
                        "WWAN power down on resume request failed\n");
 }
 
-static int wan_get_radiosw(void)
+static int wan_get_status(void)
 {
        int status;
 
-       if (!tp_features.wan)
-               return -ENODEV;
-
-       /* WLSW overrides WWAN in firmware/hardware, reflect that */
-       if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status)
-               return RFKILL_STATE_HARD_BLOCKED;
-
 #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
        if (dbg_wwanemul)
                return (tpacpi_wwan_emulstate) ?
-                       RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
+                      TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF;
 #endif
 
        if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
                return -EIO;
 
        return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0) ?
-               RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
-}
-
-static void wan_update_rfk(void)
-{
-       int status;
-
-       if (!tpacpi_wan_rfkill)
-               return;
-
-       status = wan_get_radiosw();
-       if (status < 0)
-               return;
-       rfkill_force_state(tpacpi_wan_rfkill, status);
-
-       vdbg_printk(TPACPI_DBG_RFKILL,
-               "forced rfkill state to %d\n",
-               status);
+                       TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF;
 }
 
-static int wan_set_radiosw(int radio_on, int update_rfk)
+static int wan_set_status(enum tpacpi_rfkill_state state)
 {
        int status;
 
-       if (!tp_features.wan)
-               return -ENODEV;
-
-       /* WLSW overrides bluetooth in firmware/hardware, but there is no
-        * reason to risk weird behaviour. */
-       if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status
-           && radio_on)
-               return -EPERM;
-
        vdbg_printk(TPACPI_DBG_RFKILL,
-               "will %s WWAN\n", radio_on ? "enable" : "disable");
+               "will attempt to %s wwan\n",
+               (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable");
 
 #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
        if (dbg_wwanemul) {
-               tpacpi_wwan_emulstate = !!radio_on;
-               if (update_rfk)
-                       wan_update_rfk();
+               tpacpi_wwan_emulstate = (state == TPACPI_RFK_RADIO_ON);
                return 0;
        }
 #endif
 
        /* We make sure to keep TP_ACPI_WANCARD_RESUMECTRL off */
-       if (radio_on)
+       if (state == TPACPI_RFK_RADIO_ON)
                status = TP_ACPI_WANCARD_RADIOSSW;
        else
                status = 0;
+
        if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
                return -EIO;
 
-       if (update_rfk)
-               wan_update_rfk();
-
        return 0;
 }
 
@@ -3461,35 +3611,16 @@ static ssize_t wan_enable_show(struct device *dev,
                           struct device_attribute *attr,
                           char *buf)
 {
-       int status;
-
-       printk_deprecated_rfkill_attribute("wwan_enable");
-
-       status = wan_get_radiosw();
-       if (status < 0)
-               return status;
-
-       return snprintf(buf, PAGE_SIZE, "%d\n",
-                       (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0);
+       return tpacpi_rfk_sysfs_enable_show(TPACPI_RFK_WWAN_SW_ID,
+                       attr, buf);
 }
 
 static ssize_t wan_enable_store(struct device *dev,
                            struct device_attribute *attr,
                            const char *buf, size_t count)
 {
-       unsigned long t;
-       int res;
-
-       printk_deprecated_rfkill_attribute("wwan_enable");
-
-       if (parse_strtoul(buf, 1, &t))
-               return -EINVAL;
-
-       tpacpi_disclose_usertask("wwan_enable", "set to %ld\n", t);
-
-       res = wan_set_radiosw(t, 1);
-
-       return (res) ? res : count;
+       return tpacpi_rfk_sysfs_enable_store(TPACPI_RFK_WWAN_SW_ID,
+                       attr, buf, count);
 }
 
 static struct device_attribute dev_attr_wan_enable =
@@ -3507,23 +3638,10 @@ static const struct attribute_group wan_attr_group = {
        .attrs = wan_attributes,
 };
 
-static int tpacpi_wan_rfk_get(void *data, enum rfkill_state *state)
-{
-       int wans = wan_get_radiosw();
-
-       if (wans < 0)
-               return wans;
-
-       *state = wans;
-       return 0;
-}
-
-static int tpacpi_wan_rfk_set(void *data, enum rfkill_state state)
-{
-       dbg_printk(TPACPI_DBG_RFKILL,
-                  "request to change radio state to %d\n", state);
-       return wan_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0);
-}
+static const struct tpacpi_rfk_ops wan_tprfk_ops = {
+       .get_status = wan_get_status,
+       .set_status = wan_set_status,
+};
 
 static void wan_shutdown(void)
 {
@@ -3539,13 +3657,12 @@ static void wan_shutdown(void)
 
 static void wan_exit(void)
 {
-       wan_shutdown();
-
-       if (tpacpi_wan_rfkill)
-               rfkill_unregister(tpacpi_wan_rfkill);
-
        sysfs_remove_group(&tpacpi_pdev->dev.kobj,
                &wan_attr_group);
+
+       tpacpi_destroy_rfkill(TPACPI_RFK_WWAN_SW_ID);
+
+       wan_shutdown();
 }
 
 static int __init wan_init(struct ibm_init_struct *iibm)
@@ -3584,20 +3701,19 @@ static int __init wan_init(struct ibm_init_struct *iibm)
        if (!tp_features.wan)
                return 1;
 
-       res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
-                               &wan_attr_group);
-       if (res)
-               return res;
-
        res = tpacpi_new_rfkill(TPACPI_RFK_WWAN_SW_ID,
-                               &tpacpi_wan_rfkill,
+                               &wan_tprfk_ops,
                                RFKILL_TYPE_WWAN,
                                TPACPI_RFK_WWAN_SW_NAME,
-                               true,
-                               tpacpi_wan_rfk_set,
-                               tpacpi_wan_rfk_get);
+                               true);
+       if (res)
+               return res;
+
+       res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+                               &wan_attr_group);
+
        if (res) {
-               wan_exit();
+               tpacpi_destroy_rfkill(TPACPI_RFK_WWAN_SW_ID);
                return res;
        }
 
@@ -3607,48 +3723,12 @@ static int __init wan_init(struct ibm_init_struct *iibm)
 /* procfs -------------------------------------------------------------- */
 static int wan_read(char *p)
 {
-       int len = 0;
-       int status = wan_get_radiosw();
-
-       tpacpi_disclose_usertask("procfs wan", "read");
-
-       if (!tp_features.wan)
-               len += sprintf(p + len, "status:\t\tnot supported\n");
-       else {
-               len += sprintf(p + len, "status:\t\t%s\n",
-                               (status == RFKILL_STATE_UNBLOCKED) ?
-                                       "enabled" : "disabled");
-               len += sprintf(p + len, "commands:\tenable, disable\n");
-       }
-
-       return len;
+       return tpacpi_rfk_procfs_read(TPACPI_RFK_WWAN_SW_ID, p);
 }
 
 static int wan_write(char *buf)
 {
-       char *cmd;
-       int state = -1;
-
-       if (!tp_features.wan)
-               return -ENODEV;
-
-       while ((cmd = next_cmd(&buf))) {
-               if (strlencmp(cmd, "enable") == 0) {
-                       state = 1;
-               } else if (strlencmp(cmd, "disable") == 0) {
-                       state = 0;
-               } else
-                       return -EINVAL;
-       }
-
-       if (state != -1) {
-               tpacpi_disclose_usertask("procfs wan",
-                       "attempt to %s\n",
-                       state ? "enable" : "disable");
-               wan_set_radiosw(state, 1);
-       }
-
-       return 0;
+       return tpacpi_rfk_procfs_write(TPACPI_RFK_WWAN_SW_ID, buf);
 }
 
 static struct ibm_struct wan_driver_data = {
@@ -3672,108 +3752,59 @@ enum {
 
 #define TPACPI_RFK_UWB_SW_NAME "tpacpi_uwb_sw"
 
-static struct rfkill *tpacpi_uwb_rfkill;
-
-static int uwb_get_radiosw(void)
+static int uwb_get_status(void)
 {
        int status;
 
-       if (!tp_features.uwb)
-               return -ENODEV;
-
-       /* WLSW overrides UWB in firmware/hardware, reflect that */
-       if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status)
-               return RFKILL_STATE_HARD_BLOCKED;
-
 #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
        if (dbg_uwbemul)
                return (tpacpi_uwb_emulstate) ?
-                       RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
+                      TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF;
 #endif
 
        if (!acpi_evalf(hkey_handle, &status, "GUWB", "d"))
                return -EIO;
 
        return ((status & TP_ACPI_UWB_RADIOSSW) != 0) ?
-               RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
+                       TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF;
 }
 
-static void uwb_update_rfk(void)
+static int uwb_set_status(enum tpacpi_rfkill_state state)
 {
        int status;
 
-       if (!tpacpi_uwb_rfkill)
-               return;
-
-       status = uwb_get_radiosw();
-       if (status < 0)
-               return;
-       rfkill_force_state(tpacpi_uwb_rfkill, status);
-
        vdbg_printk(TPACPI_DBG_RFKILL,
-               "forced rfkill state to %d\n",
-               status);
-}
-
-static int uwb_set_radiosw(int radio_on, int update_rfk)
-{
-       int status;
-
-       if (!tp_features.uwb)
-               return -ENODEV;
-
-       /* WLSW overrides UWB in firmware/hardware, but there is no
-        * reason to risk weird behaviour. */
-       if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status
-           && radio_on)
-               return -EPERM;
-
-       vdbg_printk(TPACPI_DBG_RFKILL,
-                       "will %s UWB\n", radio_on ? "enable" : "disable");
+               "will attempt to %s UWB\n",
+               (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable");
 
 #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
        if (dbg_uwbemul) {
-               tpacpi_uwb_emulstate = !!radio_on;
-               if (update_rfk)
-                       uwb_update_rfk();
+               tpacpi_uwb_emulstate = (state == TPACPI_RFK_RADIO_ON);
                return 0;
        }
 #endif
 
-       status = (radio_on) ? TP_ACPI_UWB_RADIOSSW : 0;
+       if (state == TPACPI_RFK_RADIO_ON)
+               status = TP_ACPI_UWB_RADIOSSW;
+       else
+               status = 0;
+
        if (!acpi_evalf(hkey_handle, NULL, "SUWB", "vd", status))
                return -EIO;
 
-       if (update_rfk)
-               uwb_update_rfk();
-
        return 0;
 }
 
 /* --------------------------------------------------------------------- */
 
-static int tpacpi_uwb_rfk_get(void *data, enum rfkill_state *state)
-{
-       int uwbs = uwb_get_radiosw();
-
-       if (uwbs < 0)
-               return uwbs;
-
-       *state = uwbs;
-       return 0;
-}
-
-static int tpacpi_uwb_rfk_set(void *data, enum rfkill_state state)
-{
-       dbg_printk(TPACPI_DBG_RFKILL,
-                  "request to change radio state to %d\n", state);
-       return uwb_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0);
-}
+static const struct tpacpi_rfk_ops uwb_tprfk_ops = {
+       .get_status = uwb_get_status,
+       .set_status = uwb_set_status,
+};
 
 static void uwb_exit(void)
 {
-       if (tpacpi_uwb_rfkill)
-               rfkill_unregister(tpacpi_uwb_rfkill);
+       tpacpi_destroy_rfkill(TPACPI_RFK_UWB_SW_ID);
 }
 
 static int __init uwb_init(struct ibm_init_struct *iibm)
@@ -3813,13 +3844,10 @@ static int __init uwb_init(struct ibm_init_struct *iibm)
                return 1;
 
        res = tpacpi_new_rfkill(TPACPI_RFK_UWB_SW_ID,
-                               &tpacpi_uwb_rfkill,
+                               &uwb_tprfk_ops,
                                RFKILL_TYPE_UWB,
                                TPACPI_RFK_UWB_SW_NAME,
-                               false,
-                               tpacpi_uwb_rfk_set,
-                               tpacpi_uwb_rfk_get);
-
+                               false);
        return res;
 }
 
index 4345089..81d31ea 100644 (file)
@@ -45,7 +45,6 @@
 #include <linux/backlight.h>
 #include <linux/platform_device.h>
 #include <linux/rfkill.h>
-#include <linux/input-polldev.h>
 
 #include <asm/uaccess.h>
 
@@ -250,21 +249,15 @@ static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 *result)
 
 struct toshiba_acpi_dev {
        struct platform_device *p_dev;
-       struct rfkill *rfk_dev;
-       struct input_polled_dev *poll_dev;
+       struct rfkill *bt_rfk;
 
        const char *bt_name;
-       const char *rfk_name;
-
-       bool last_rfk_state;
 
        struct mutex mutex;
 };
 
 static struct toshiba_acpi_dev toshiba_acpi = {
        .bt_name = "Toshiba Bluetooth",
-       .rfk_name = "Toshiba RFKill Switch",
-       .last_rfk_state = false,
 };
 
 /* Bluetooth rfkill handlers */
@@ -283,21 +276,6 @@ static u32 hci_get_bt_present(bool *present)
        return hci_result;
 }
 
-static u32 hci_get_bt_on(bool *on)
-{
-       u32 hci_result;
-       u32 value, value2;
-
-       value = 0;
-       value2 = 0x0001;
-       hci_read2(HCI_WIRELESS, &value, &value2, &hci_result);
-       if (hci_result == HCI_SUCCESS)
-               *on = (value & HCI_WIRELESS_BT_POWER) &&
-                     (value & HCI_WIRELESS_BT_ATTACH);
-
-       return hci_result;
-}
-
 static u32 hci_get_radio_state(bool *radio_state)
 {
        u32 hci_result;
@@ -311,70 +289,67 @@ static u32 hci_get_radio_state(bool *radio_state)
        return hci_result;
 }
 
-static int bt_rfkill_toggle_radio(void *data, enum rfkill_state state)
+static int bt_rfkill_set_block(void *data, bool blocked)
 {
+       struct toshiba_acpi_dev *dev = data;
        u32 result1, result2;
        u32 value;
+       int err;
        bool radio_state;
-       struct toshiba_acpi_dev *dev = data;
 
-       value = (state == RFKILL_STATE_UNBLOCKED);
+       value = (blocked == false);
 
-       if (hci_get_radio_state(&radio_state) != HCI_SUCCESS)
-               return -EFAULT;
+       mutex_lock(&dev->mutex);
+       if (hci_get_radio_state(&radio_state) != HCI_SUCCESS) {
+               err = -EBUSY;
+               goto out;
+       }
 
-       switch (state) {
-       case RFKILL_STATE_UNBLOCKED:
-               if (!radio_state)
-                       return -EPERM;
-               break;
-       case RFKILL_STATE_SOFT_BLOCKED:
-               break;
-       default:
-               return -EINVAL;
+       if (!radio_state) {
+               err = 0;
+               goto out;
        }
 
-       mutex_lock(&dev->mutex);
        hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1);
        hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2);
-       mutex_unlock(&dev->mutex);
 
        if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS)
-               return -EFAULT;
-
-       return 0;
+               err = -EBUSY;
+       else
+               err = 0;
+ out:
+       mutex_unlock(&dev->mutex);
+       return err;
 }
 
-static void bt_poll_rfkill(struct input_polled_dev *poll_dev)
+static void bt_rfkill_poll(struct rfkill *rfkill, void *data)
 {
-       bool state_changed;
        bool new_rfk_state;
        bool value;
        u32 hci_result;
-       struct toshiba_acpi_dev *dev = poll_dev->private;
+       struct toshiba_acpi_dev *dev = data;
+
+       mutex_lock(&dev->mutex);
 
        hci_result = hci_get_radio_state(&value);
-       if (hci_result != HCI_SUCCESS)
-               return; /* Can't do anything useful */
+       if (hci_result != HCI_SUCCESS) {
+               /* Can't do anything useful */
+               mutex_unlock(&dev->mutex);
+       }
 
        new_rfk_state = value;
 
-       mutex_lock(&dev->mutex);
-       state_changed = new_rfk_state != dev->last_rfk_state;
-       dev->last_rfk_state = new_rfk_state;
        mutex_unlock(&dev->mutex);
 
-       if (unlikely(state_changed)) {
-               rfkill_force_state(dev->rfk_dev,
-                                  new_rfk_state ?
-                                  RFKILL_STATE_SOFT_BLOCKED :
-                                  RFKILL_STATE_HARD_BLOCKED);
-               input_report_switch(poll_dev->input, SW_RFKILL_ALL,
-                                   new_rfk_state);
-               input_sync(poll_dev->input);
-       }
+       if (rfkill_set_hw_state(rfkill, !new_rfk_state))
+               bt_rfkill_set_block(data, true);
 }
 
+static const struct rfkill_ops toshiba_rfk_ops = {
+       .set_block = bt_rfkill_set_block,
+       .poll = bt_rfkill_poll,
+};
+
 static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
 static struct backlight_device *toshiba_backlight_device;
 static int force_fan;
@@ -702,14 +677,11 @@ static struct backlight_ops toshiba_backlight_data = {
 
 static void toshiba_acpi_exit(void)
 {
-       if (toshiba_acpi.poll_dev) {
-               input_unregister_polled_device(toshiba_acpi.poll_dev);
-               input_free_polled_device(toshiba_acpi.poll_dev);
+       if (toshiba_acpi.bt_rfk) {
+               rfkill_unregister(toshiba_acpi.bt_rfk);
+               rfkill_destroy(toshiba_acpi.bt_rfk);
        }
 
-       if (toshiba_acpi.rfk_dev)
-               rfkill_unregister(toshiba_acpi.rfk_dev);
-
        if (toshiba_backlight_device)
                backlight_device_unregister(toshiba_backlight_device);
 
@@ -728,8 +700,6 @@ static int __init toshiba_acpi_init(void)
        acpi_status status = AE_OK;
        u32 hci_result;
        bool bt_present;
-       bool bt_on;
-       bool radio_on;
        int ret = 0;
 
        if (acpi_disabled)
@@ -793,60 +763,21 @@ static int __init toshiba_acpi_init(void)
 
        /* Register rfkill switch for Bluetooth */
        if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) {
-               toshiba_acpi.rfk_dev = rfkill_allocate(&toshiba_acpi.p_dev->dev,
-                                                       RFKILL_TYPE_BLUETOOTH);
-               if (!toshiba_acpi.rfk_dev) {
+               toshiba_acpi.bt_rfk = rfkill_alloc(toshiba_acpi.bt_name,
+                                                  &toshiba_acpi.p_dev->dev,
+                                                  RFKILL_TYPE_BLUETOOTH,
+                                                  &toshiba_rfk_ops,
+                                                  &toshiba_acpi);
+               if (!toshiba_acpi.bt_rfk) {
                        printk(MY_ERR "unable to allocate rfkill device\n");
                        toshiba_acpi_exit();
                        return -ENOMEM;
                }
 
-               toshiba_acpi.rfk_dev->name = toshiba_acpi.bt_name;
-               toshiba_acpi.rfk_dev->toggle_radio = bt_rfkill_toggle_radio;
-               toshiba_acpi.rfk_dev->data = &toshiba_acpi;
-
-               if (hci_get_bt_on(&bt_on) == HCI_SUCCESS && bt_on) {
-                       toshiba_acpi.rfk_dev->state = RFKILL_STATE_UNBLOCKED;
-               } else if (hci_get_radio_state(&radio_on) == HCI_SUCCESS &&
-                          radio_on) {
-                       toshiba_acpi.rfk_dev->state = RFKILL_STATE_SOFT_BLOCKED;
-               } else {
-                       toshiba_acpi.rfk_dev->state = RFKILL_STATE_HARD_BLOCKED;
-               }
-
-               ret = rfkill_register(toshiba_acpi.rfk_dev);
+               ret = rfkill_register(toshiba_acpi.bt_rfk);
                if (ret) {
                        printk(MY_ERR "unable to register rfkill device\n");
-                       toshiba_acpi_exit();
-                       return -ENOMEM;
-               }
-
-               /* Register input device for kill switch */
-               toshiba_acpi.poll_dev = input_allocate_polled_device();
-               if (!toshiba_acpi.poll_dev) {
-                       printk(MY_ERR
-                              "unable to allocate kill-switch input device\n");
-                       toshiba_acpi_exit();
-                       return -ENOMEM;
-               }
-               toshiba_acpi.poll_dev->private = &toshiba_acpi;
-               toshiba_acpi.poll_dev->poll = bt_poll_rfkill;
-               toshiba_acpi.poll_dev->poll_interval = 1000; /* msecs */
-
-               toshiba_acpi.poll_dev->input->name = toshiba_acpi.rfk_name;
-               toshiba_acpi.poll_dev->input->id.bustype = BUS_HOST;
-               /* Toshiba USB ID */
-               toshiba_acpi.poll_dev->input->id.vendor = 0x0930;
-               set_bit(EV_SW, toshiba_acpi.poll_dev->input->evbit);
-               set_bit(SW_RFKILL_ALL, toshiba_acpi.poll_dev->input->swbit);
-               input_report_switch(toshiba_acpi.poll_dev->input,
-                                   SW_RFKILL_ALL, TRUE);
-               input_sync(toshiba_acpi.poll_dev->input);
-
-               ret = input_register_polled_device(toshiba_acpi.poll_dev);
-               if (ret) {
-                       printk(MY_ERR
-                              "unable to register kill-switch input device\n");
+                       rfkill_destroy(toshiba_acpi.bt_rfk);
                        toshiba_acpi_exit();
                        return ret;
                }
index 2994aa1..74c49d9 100644 (file)
@@ -2937,8 +2937,8 @@ int qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
        if (card->info.type == QETH_CARD_TYPE_OSN)
                return cast_type;
 
-       if (skb->dst && skb->dst->neighbour) {
-               cast_type = skb->dst->neighbour->type;
+       if (skb_dst(skb) && skb_dst(skb)->neighbour) {
+               cast_type = skb_dst(skb)->neighbour->type;
                if ((cast_type == RTN_BROADCAST) ||
                    (cast_type == RTN_MULTICAST) ||
                    (cast_type == RTN_ANYCAST))
index 9ca6bab..ecd3d06 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/etherdevice.h>
 #include <linux/mii.h>
 #include <linux/ip.h>
+#include <linux/list.h>
 
 #include "qeth_core.h"
 
@@ -640,6 +641,7 @@ static void qeth_l2_set_multicast_list(struct net_device *dev)
 {
        struct qeth_card *card = dev->ml_priv;
        struct dev_addr_list *dm;
+       struct netdev_hw_addr *ha;
 
        if (card->info.type == QETH_CARD_TYPE_OSN)
                return ;
@@ -653,8 +655,8 @@ static void qeth_l2_set_multicast_list(struct net_device *dev)
        for (dm = dev->mc_list; dm; dm = dm->next)
                qeth_l2_add_mc(card, dm->da_addr, 0);
 
-       for (dm = dev->uc_list; dm; dm = dm->next)
-               qeth_l2_add_mc(card, dm->da_addr, 1);
+       list_for_each_entry(ha, &dev->uc_list, list)
+               qeth_l2_add_mc(card, ha->addr, 1);
 
        spin_unlock_bh(&card->mclock);
        if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE))
index b36b5cd..6f2386e 100644 (file)
@@ -2549,9 +2549,9 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
                /* IPv4 */
                hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags4(cast_type);
                memset(hdr->hdr.l3.dest_addr, 0, 12);
-               if ((skb->dst) && (skb->dst->neighbour)) {
+               if ((skb_dst(skb)) && (skb_dst(skb)->neighbour)) {
                        *((u32 *) (&hdr->hdr.l3.dest_addr[12])) =
-                           *((u32 *) skb->dst->neighbour->primary_key);
+                           *((u32 *) skb_dst(skb)->neighbour->primary_key);
                } else {
                        /* fill in destination address used in ip header */
                        *((u32 *) (&hdr->hdr.l3.dest_addr[12])) =
@@ -2562,9 +2562,9 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
                hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags6(cast_type);
                if (card->info.type == QETH_CARD_TYPE_IQD)
                        hdr->hdr.l3.flags &= ~QETH_HDR_PASSTHRU;
-               if ((skb->dst) && (skb->dst->neighbour)) {
+               if ((skb_dst(skb)) && (skb_dst(skb)->neighbour)) {
                        memcpy(hdr->hdr.l3.dest_addr,
-                              skb->dst->neighbour->primary_key, 16);
+                              skb_dst(skb)->neighbour->primary_key, 16);
                } else {
                        /* fill in destination address used in ip header */
                        memcpy(hdr->hdr.l3.dest_addr,
@@ -3012,6 +3012,7 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
        card->dev->features |=  NETIF_F_HW_VLAN_TX |
                                NETIF_F_HW_VLAN_RX |
                                NETIF_F_HW_VLAN_FILTER;
+       card->dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
 
        SET_NETDEV_DEV(card->dev, &card->gdev->dev);
        return register_netdev(card->dev);
index ce33f10..f791348 100644 (file)
@@ -182,8 +182,8 @@ static void fcoe_update_src_mac(struct fcoe_ctlr *fip, u8 *old, u8 *new)
        fc = fcoe_from_ctlr(fip);
        rtnl_lock();
        if (!is_zero_ether_addr(old))
-               dev_unicast_delete(fc->real_dev, old, ETH_ALEN);
-       dev_unicast_add(fc->real_dev, new, ETH_ALEN);
+               dev_unicast_delete(fc->real_dev, old);
+       dev_unicast_add(fc->real_dev, new);
        rtnl_unlock();
 }
 
@@ -233,13 +233,11 @@ void fcoe_netdev_cleanup(struct fcoe_softc *fc)
        /* Delete secondary MAC addresses */
        rtnl_lock();
        memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN);
-       dev_unicast_delete(fc->real_dev, flogi_maddr, ETH_ALEN);
+       dev_unicast_delete(fc->real_dev, flogi_maddr);
        if (!is_zero_ether_addr(fc->ctlr.data_src_addr))
-               dev_unicast_delete(fc->real_dev,
-                                  fc->ctlr.data_src_addr, ETH_ALEN);
+               dev_unicast_delete(fc->real_dev, fc->ctlr.data_src_addr);
        if (fc->ctlr.spma)
-               dev_unicast_delete(fc->real_dev,
-                                  fc->ctlr.ctl_src_addr, ETH_ALEN);
+               dev_unicast_delete(fc->real_dev, fc->ctlr.ctl_src_addr);
        dev_mc_delete(fc->real_dev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0);
        rtnl_unlock();
 }
@@ -347,9 +345,9 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)
         */
        rtnl_lock();
        memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN);
-       dev_unicast_add(fc->real_dev, flogi_maddr, ETH_ALEN);
+       dev_unicast_add(fc->real_dev, flogi_maddr);
        if (fc->ctlr.spma)
-               dev_unicast_add(fc->real_dev, fc->ctlr.ctl_src_addr, ETH_ALEN);
+               dev_unicast_add(fc->real_dev, fc->ctlr.ctl_src_addr);
        dev_mc_add(fc->real_dev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0);
        rtnl_unlock();
 
index c1abeb8..96fb118 100644 (file)
@@ -188,8 +188,7 @@ static struct usb_descriptor_header *hs_pn_function[] = {
 
 static int pn_net_open(struct net_device *dev)
 {
-       if (netif_carrier_ok(dev))
-               netif_wake_queue(dev);
+       netif_wake_queue(dev);
        return 0;
 }
 
@@ -219,8 +218,7 @@ static void pn_tx_complete(struct usb_ep *ep, struct usb_request *req)
        }
 
        dev_kfree_skb_any(skb);
-       if (netif_carrier_ok(dev))
-               netif_wake_queue(dev);
+       netif_wake_queue(dev);
 }
 
 static int pn_net_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -255,7 +253,7 @@ out_unlock:
        spin_unlock_irqrestore(&port->lock, flags);
 out:
        if (unlikely(skb)) {
-               dev_kfree_skb_any(skb);
+               dev_kfree_skb(skb);
                dev->stats.tx_dropped++;
        }
        return 0;
@@ -383,7 +381,6 @@ static void __pn_reset(struct usb_function *f)
        struct phonet_port *port = netdev_priv(dev);
 
        netif_carrier_off(dev);
-       netif_stop_queue(dev);
        port->usb = NULL;
 
        usb_ep_disable(fp->out_ep);
@@ -427,8 +424,6 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
                        fp->in_ep->driver_data = fp;
 
                        netif_carrier_on(dev);
-                       if (netif_running(dev))
-                               netif_wake_queue(dev);
                        for (i = 0; i < phonet_rxq_size; i++)
                                pn_rx_submit(fp, fp->out_reqv[i], GFP_ATOMIC);
                }
@@ -574,9 +569,10 @@ static struct net_device *dev;
 int __init phonet_bind_config(struct usb_configuration *c)
 {
        struct f_phonet *fp;
-       int err;
+       int err, size;
 
-       fp = kzalloc(sizeof(*fp), GFP_KERNEL);
+       size = sizeof(*fp) + (phonet_rxq_size * sizeof(struct usb_request *));
+       fp = kzalloc(size, GFP_KERNEL);
        if (!fp)
                return -ENOMEM;
 
@@ -601,16 +597,13 @@ int __init gphonet_setup(struct usb_gadget *gadget)
 
        /* Create net device */
        BUG_ON(dev);
-       dev = alloc_netdev(sizeof(*port)
-               + (phonet_rxq_size * sizeof(struct usb_request *)),
-                               "upnlink%d", pn_net_setup);
+       dev = alloc_netdev(sizeof(*port), "upnlink%d", pn_net_setup);
        if (!dev)
                return -ENOMEM;
 
        port = netdev_priv(dev);
        spin_lock_init(&port->lock);
        netif_carrier_off(dev);
-       netif_stop_queue(dev);
        SET_NETDEV_DEV(dev, &gadget->dev);
 
        err = register_netdev(dev);
index 96c3dd8..621de8e 100644 (file)
@@ -41,7 +41,7 @@ fw-shipped-$(CONFIG_CASSINI) += sun/cassini.bin
 fw-shipped-$(CONFIG_COMPUTONE) += intelliport2.bin
 fw-shipped-$(CONFIG_CHELSIO_T3) += cxgb3/t3b_psram-1.1.0.bin \
                                   cxgb3/t3c_psram-1.1.0.bin \
-                                  cxgb3/t3fw-7.1.0.bin
+                                  cxgb3/t3fw-7.4.0.bin
 fw-shipped-$(CONFIG_DVB_AV7110) += av7110/bootcode.bin
 fw-shipped-$(CONFIG_DVB_TTUSB_BUDGET) += ttusb-budget/dspbootcode.bin
 fw-shipped-$(CONFIG_E100) += e100/d101m_ucode.bin e100/d101s_ucode.bin \
index bb8fda8..0f5649a 100644 (file)
@@ -412,7 +412,7 @@ Driver: cxgb3 - Chelsio Terminator 3 1G/10G Ethernet adapter
 
 File: cxgb3/t3b_psram-1.1.0.bin.ihex
 File: cxgb3/t3c_psram-1.1.0.bin.ihex
-file: cxgb3/t3fw-7.1.0.bin.ihex
+file: cxgb3/t3fw-7.4.0.bin.ihex
 
 License: GPLv2 or OpenIB.org BSD license, no source visible
 
diff --git a/firmware/cis/.gitignore b/firmware/cis/.gitignore
new file mode 100644 (file)
index 0000000..1de3984
--- /dev/null
@@ -0,0 +1 @@
+*.cis
diff --git a/firmware/cxgb3/t3fw-7.1.0.bin.ihex b/firmware/cxgb3/t3fw-7.1.0.bin.ihex
deleted file mode 100644 (file)
index 1042f75..0000000
+++ /dev/null
@@ -1,1885 +0,0 @@
-:1000000060007400200380002003700000001000D6
-:1000100000002000E100028400070000E1000288E7
-:1000200000010000E0000000E00000A0010000006E
-:1000300044444440E3000183200200002001E0002A
-:100040002001FF101FFFD0001FFFC000E300043C91
-:1000500002000000200069881FFFC290200069D0C4
-:100060001FFFC29420006A101FFFC29820006A84FC
-:100070001FFFC29C200003C0C00000E43100EA3131
-:1000800000A13100A03103020002ED306E2A05000C
-:10009000ED3100020002160012FFDBC03014FFDA5F
-:1000A000D30FD30FD30F03431F244C107249F0D347
-:1000B0000FD30FD30F12FFD5230A00240A00D30F4A
-:1000C000D30FD30F03431F244C107249F0D30FD327
-:1000D0000FD30F14FFCE03421F14FFCB03421F1296
-:1000E000FFCCC0302D37302D37342D37382D373CED
-:1000F000233D017233ED00020012FFC4C0302F37E0
-:10010000002F37102F37202F3730233D017233ED6A
-:1001100000020012FFBEC0302737002737102737F4
-:1001200020273730233D017233ED03020012FFB95F
-:1001300013FFBA0C0200932012FFB913FFB90C028F
-:1001400000932012FFB8C0319320822012FFB71312
-:10015000FFB7932012FFB715FFB316FFB6C030D715
-:100160002005660160001B00000000000000000088
-:10017000043605000200D30FD30F05330C6E3B1479
-:100180000747140704437631E604360505330C6F40
-:100190003BED00020012FFA615FFA3230A00D720A3
-:1001A000070443043E0505330C0747146F3BF00377
-:1001B000020012FFA1C03014FFA1D30FD30FD30F41
-:1001C0009340B4447249F2D30FD30FD30F14FF9B63
-:1001D000834014FF9B834012FF9B230A0014FF9A65
-:1001E000D30FD30FD30F9340B4447249F2D30FD33C
-:1001F0000FD30F14FF95834012FF95C92F832084DE
-:10020000218522BC22743B0F8650B4559630B433FE
-:100210007433F463FFE60000653FE1655FDE12FFC3
-:100220007C230A0028374028374428374828374C91
-:10023000233D017233ED03020000020012FF7AC079
-:1002400032032E0503020012FF7813FF819320C0B2
-:1002500011014931004831010200C00014FF7E0441
-:10026000D23115FF7D945014FF7D04D33115FF7CEE
-:10027000945014FF7C04D43115FF7C24560014FFE5
-:100280007B04D53115FF7B24560010FF7A03000054
-:10029000000000000000000000000000000000005E
-:1002A000000000000000000000000000000000004E
-:1002B000000000000000000000000000000000003E
-:1002C000000000000000000000000000000000002E
-:1002D000000000000000000000000000000000001E
-:1002E000000000000000000000000000000000000E
-:1002F00000000000000000000000000000000000FE
-:1003000000000000000000000000000000000000ED
-:1003100000000000000000000000000000000000DD
-:1003200000000000000000000000000000000000CD
-:1003300000000000000000000000000000000000BD
-:1003400000000000000000000000000000000000AD
-:10035000000000000000000000000000000000009D
-:10036000000000000000000000000000000000008D
-:10037000000000000000000000000000000000007D
-:10038000000000000000000000000000000000006D
-:10039000000000000000000000000000000000005D
-:1003A000000000000000000000000000000000004D
-:1003B000000000000000000000000000000000003D
-:1003C000000000000000000000000000000000002D
-:1003D000000000000000000000000000000000001D
-:1003E000000000000000000000000000000000000D
-:1003F00000000000000000000000000000000000FD
-:1004000000000000000000000000000000000000EC
-:1004100000000000000000000000000000000000DC
-:1004200063FFFC000000000000000000000000006E
-:100430000000000000000000000000001FFC0000A1
-:100440001FFC0000E30005C81FFC00001FFC0000AB
-:10045000E30005C81FFC00001FFC0000E30005C806
-:100460001FFFC0001FFFC000E30005C81FFFC00042
-:100470001FFFC018E30005C81FFFC0181FFFC018EA
-:10048000E30005E01FFFC0181FFFC28CE30005E07A
-:100490001FFFC28C1FFFC28CE30008541FFFC290D5
-:1004A0001FFFC58CE3000854200000002000016AF3
-:1004B000E3000B502000018020000180E3000CBC11
-:1004C0002000020020000203E3000CBC2000021CFC
-:1004D00020000220E3000CC02000022020000226A1
-:1004E000E3000CC42000023C20000240E3000CCCDE
-:1004F0002000024020000249E3000CD02000024C02
-:1005000020000250E3000CDC2000025020000259C1
-:10051000E3000CE02000025C20000260E3000CEC31
-:100520002000026020000269E3000CF02000026C51
-:1005300020000270E3000CFC200002702000027911
-:10054000E3000D002000028C2000028CE3000D0C63
-:100550002000029020000293E3000D0C200002AC6A
-:10056000200002B0E3000D10200002D0200002F2B3
-:10057000E3000D14200003B0200003B0E3000D38A9
-:10058000200003B0200003B0E3000D38200003B0CA
-:10059000200003B0E3000D38200003B0200003B0BA
-:1005A000E3000D38200003B020006BA8E3000D38F5
-:1005B00020006BA820006BA8E3007530000000004D
-:1005C00000000000000000001FFC00001FFC0000F5
-:1005D0001FFFC5901FFFC67020006BA820006BA8EE
-:1005E000DEFFFE000000080CDEADBEEF1FFFC2A064
-:1005F0001FFCFE001FFFC0941FFFC5C0300000009D
-:10060000003FFFFF8040000010000000080FFFFFC8
-:100610001FFFC26D000FFFFF804FFFFF8000000033
-:1006200000000880B000000560500000600000007D
-:1006300040000011350000004100000010000001E2
-:1006400020000000000010007FFFFFFF40000000BE
-:1006500005000000800000190400000000000800F0
-:1006600010000005806000007000000020000009FC
-:10067000001FF8008000001EA0000000F80000002D
-:1006800007FFFFFF080000001800000001008001C4
-:10069000420000001FFFC21D1FFFC0DC00010080E0
-:1006A000604000001A0000000C0000000000300054
-:1006B000600008008000001C000100008000001A9B
-:1006C00080000018FC0000008000000100004000D5
-:1006D000030000008000040050000003FFFFBFFF84
-:1006E0001FFFC3D400000FFFFFFFF000000016D073
-:1006F0000000FFF7A50000001FFFC4B01FFFC4618A
-:100700000001000800000B20202FFF801FFFC455B0
-:1007100000002C00FFFEFFF800FFFFFF1FFFC57861
-:1007200000002000FFFFDFFF0000FFEF01001100CD
-:100730001FFFC3D21FFFC590FFFFEFFF0000FFFBAD
-:100740001FFFC6301FFFBEA0FFFFF7FF1FFFC064E3
-:100750000000FFFD1FFFC6200001FBD01FFFC5B03A
-:100760001FFFC6601FFFC591E0FFFE001FFFC5A071
-:10077000000080001FFFC53C1FFFC5B41FFFC068FD
-:100780001FFFC4D01FFCFFD800010081E10006005C
-:10079000000027101FFCFE301FFCFE70E10002006D
-:1007A0001FFFC5381FFFC5500003D0901FFFC56451
-:1007B0002B5063802B5079802B5090802B50A6803B
-:1007C0001FFFC4690100110F202FFE0020300080A0
-:1007D000202FFF000000FFFF0001FFF82B50B200A8
-:1007E0002B50B208000100102B50B1802B50B2806A
-:1007F0002B50BA00000100112B50BD282B50BC809B
-:100800002B50BDA020300000DFFFFE005000000292
-:1008100000C0000002000000FFFFF7F41FFFC06CE3
-:10082000000FF80004400000001000000C40000021
-:100830001C400000E00000A01FFFC5401FFD000895
-:100840001FFFC5541FFFC5681FFFC57CE100069050
-:10085000E10006EC000000000000000000000000C5
-:100860000000000001000000000000000000000087
-:100870000000000020100040201000402010004028
-:1008800020140080200C0000200C0000200C000030
-:1008900020100040201400802014008020140080CC
-:1008A000201800C0201C0100201C0100201C010099
-:1008B00020200140201800C0201800C0201800C0CF
-:1008C000201C0100201800C0201800C0201800C003
-:1008D000201C010020200140202001402020014058
-:1008E00020200940202009402020094020200940E4
-:1008F00020240980FFFFFFFFFFFFFFFFFFFFFFFF37
-:1009000000000000000000000000000000000000E7
-:1009100000000000200052FC200051CC200052FCBE
-:10092000200052FC200051082000510820005108EE
-:1009300020004F4820004F4820004F4020004EAC80
-:1009400020004D5420004B342000490800000000D6
-:1009500000000000200052CC200051982000523CA2
-:100960002000523C20004FF020004FF020004FF0BC
-:1009700020004FF020004FF020004F3820004FF0B3
-:1009800020004C7420004AE4200048B4000000001D
-:100990000000000020000BE0200038BC200004C054
-:1009A000200044A820000BD820003FB4200003F012
-:1009B000200044682000489020003CC420003BE018
-:1009C00020003838200036C42000343420002F9412
-:1009D00020003A3C20002BF4200028282000653419
-:1009E000200023B4200020942000204020001D2C53
-:1009F000200018402000157020000DEC20000C2471
-:100A00002000113420001320200041AC20003C784D
-:100A100020000BE8200004C00000000000000000DF
-:100A200000000000000000000000000000000000C6
-:100A300000000000000000000000000000000000B6
-:100A400000000000000000000000000000000000A6
-:100A50000000000000000000000000000000000096
-:100A60000000000000000000000000000000000086
-:100A70000000000000000000000000000000000076
-:100A80000000000000000000000000000000000066
-:100A900000000000000000003264000000000000C0
-:100AA0003264000064006400640064006400640058
-:100AB000640064000000000000000000000000006E
-:100AC0000000000000000000000000000000000026
-:100AD0000000000000000000000000000000000016
-:100AE0000000000000000000000000000000000006
-:100AF00000000000000000000000000000001000E6
-:100B000000000000000000000000000000000000E5
-:100B100000000000000010000000000000000000C5
-:100B200000000000000000000043238000000000DF
-:100B300000000000000000000000000000000000B5
-:100B400000000000000000000000000000000000A5
-:100B5000005C94015D94025E94035F940043000086
-:100B60000000000000000000000000000000000085
-:100B70000000000000000000000000000000000075
-:100B80000000000000000000000000000000000065
-:100B9000005C90015D90025E90035F900053000046
-:100BA0000000000000000000000000000000000045
-:100BB0000000000000000000000000000000000035
-:100BC0000000000000000000000000000000000025
-:100BD000009C94001D90019D94029E94039F940498
-:100BE0000894050994060A94070B9400430000003A
-:100BF00000000000000000000000000000000000F5
-:100C000000000000000000000000000000000000E4
-:100C1000009C90019D90029E90071D90039F900460
-:100C20007890057990067A90077B90005300000039
-:100C300000000000000000000000000000000000B4
-:100C400000000000000000000000000000000000A4
-:100C500000DC94001D9001DD9402DE9403DF940417
-:100C60000494050594060694070794080894090956
-:100C7000940A0A940B0B940043000000000000004B
-:100C80000000000000000000000000000000000064
-:100C900000DC9001DD9002DE900B1D9003DF9004DC
-:100CA000B49005B59006B69007B79008B89009B90A
-:100CB000900ABA900BBB90005300000063FFFC0049
-:100CC0002000696410FFFF0A00000000200069880E
-:100CD00000D23110FFFE0A0000000000200069D0A1
-:100CE00000D33110FFFE0A000000000020006A104F
-:100CF00000D43110FFFE0A000000000020006A84CA
-:100D000000D53110FFFE0A000000000063FFFC0068
-:100D1000E00000A012FFF78220028257C82163FF83
-:100D2000FC12FFF303E83004EE3005C0309320944A
-:100D300021952263FFFC00001FFFD000000400206B
-:100D40001FFFC5901FFFC670200A0011FFFB13FF95
-:100D5000FB03E63101020016FFFA17FFFAD30F7703
-:100D60006B069060B4667763F85415505419E60F1B
-:100D7000140063FFF90000006C1004C020D10F00C4
-:100D80006C1004C0C71AEF06D830BC2BD720857270
-:100D90000D4211837105450B957202330C237601C8
-:100DA0007B3B04233D089371A32D12EEFE19EEFE4A
-:100DB000A2767D632C2E0A00088202280A01038E87
-:100DC000380E0E42C8EE29A67E6D4A050020880026
-:100DD000308C8271D10FC0F0028F387FC0EA63FF80
-:100DE000E400C0F1C050037E0CA2EE0E3D1208825A
-:100DF0000203F538050542CB5729A67E2FDC100FDC
-:100E00004F366DFA0500208800308CBC75C0300864
-:100E1000E208280A01058338030342C93E29A67E59
-:100E20000D480CD30F6D8A0500208800B08C8271AC
-:100E3000D10FC05008F53875C0C163FFBBC0600258
-:100E4000863876C0DA63FFD46C101216EED8C1F87B
-:100E5000C1E72B221E2C221DC0D07BC12F292006CA
-:100E6000D7B0299CFACC57282070288CFF282470F2
-:100E700064915C2AB0000EA80C6481670FA90C6411
-:100E800092B3C1E97EA13969AC2F600036292006F2
-:100E9000D7D0299CFACC57282070288CFF282470A2
-:100EA0006491352AD0000EA80C6481640FA90C64EB
-:100EB000931BC1E97EA10968AC09C020D10F0000D5
-:100EC000002D25028A32C0900A6F5065F5AD2924A5
-:100ED000670908476585A92F200C18EEB50CFE118F
-:100EE000A8EE28E286B44978930260057A19EEB13B
-:100EF00009F90A2992A3689007882009880C65855A
-:100F00006627E28564756065558E7BC104D9B06043
-:100F10000001C0908B941CEEA80B88148CC40B0BA2
-:100F200047A8CC18EEA609BB1008CC029C7018EE9E
-:100F3000A41CEEA508A8010B88020C4C021BEEA114
-:100F40009C710B880298722C90232B902204C8105D
-:100F500006BB100C4C1208BB0228902107CC100CC9
-:100F600088100C88020B88021CEE998B330CBB0195
-:100F70008C340B880298739C999C748B958C399B4C
-:100F80007588968B38987688979C799B7898771C8B
-:100F9000EE9028E2850CFC082DC4CF08480B28E60B
-:100FA0008565550B2B221E2D221D7BD9022B0A0095
-:100FB00064BF062CB00728B000DA2006880A288211
-:100FC0004CC0D10B8000DBA065AFE763FEEB0000F7
-:100FD000292070659E9C6004E42A207065AEC36081
-:100FE00004DB00002EB0032C2067D4E065C1058A25
-:100FF000328C330AFF500C4554BC5564F4E619EEAC
-:1010000075882A09A90109880C64821BC0926000B6
-:10101000DD2ED0032A2067D4E065A0D88A328B3336
-:101020000AFC500B4554BC5564C4B919EE6A882AB1
-:1010300009A9017989D50BEA5064A4DD0CEE11C031
-:10104000F02F16132E16168AE78CE82A16128EE950
-:10105000DFC0AAEA7EAB01B1CF0BA85065834288FE
-:1010600037DBC0AE89991E789B022BCC012B161B57
-:1010700029120E2B0A0029161A7FC3077FC9027E88
-:10108000AB01C0B165B4988B352F0A002A0A007AEB
-:10109000C30564C3C72F0A0165F4842B12162B16EF
-:1010A00019005104C0C100CC1A2CCCFF2C16170C0F
-:1010B000FC132C16182B121A2A121BDC505818FA83
-:1010C000C0D0C0902E5CF42C12172812182F121BBF
-:1010D0002A121A08FF010CAA018834074C0AAB8BAC
-:1010E0002812192BC6162F86082A86092E74102955
-:1010F00024672E70038975B1EA2A7403B0990949EF
-:101100000C659DB52B20672D250265B3F42B221E9F
-:101110002C221D7BC901C0B064BD9E2CB00728B035
-:1011200000DA2006880A28824CC0D10B8000DBA0A0
-:1011300065AFE763FD8389BAB19965909788341CE0
-:10114000EE2698BA8F331EEE1F0F4F542FB42C8DFE
-:101150002A8A320EDD020CAC017DC9660A49516F44
-:1011600092608A3375A65B2CB0130AED510DCD0148
-:101170000D0D410C0C417DC9492EB012B0EE65E356
-:10118000C2C0D08E378CB88A368FB97CA3077AC993
-:10119000027EFB01C0D1CED988350AAD020E8E0881
-:1011A00078EB022DAC0189B7DAC0AF9B79BB01B1F6
-:1011B000CADCB0C0B07DA3077AD9027CEB01C0B114
-:1011C00064B15DC091292467C020D10F00008ADA84
-:1011D000B1AA64A0BC2E20672D250265E30B1FED8C
-:1011E000F98A3218EDFE0FAF0108FF0C65F2860A8E
-:1011F00048516F820260027DC090292467090A4726
-:1012000065A2F27BC901C0B064BCAE2CB00728B0A7
-:1012100000DA2006880A28824CC0D10B8000DBA0AF
-:1012200065AFE763FC9300000CE9506492EB0CEFB0
-:1012300011C080281611AFBF2F16198EF88BF7DA60
-:10124000E08FF92B1610ABFB7FBB01B1EA0CA85065
-:101250006580D68837DCE0AF89991C789B022CEC3E
-:10126000012C161B29120C2C0A0029161A7AE307E6
-:101270007AE9027FBB01C0C165C2A48B352C0A008C
-:101280002A0A007AE30564E1CA2C0A0164CE1160DF
-:10129000028D88341BEDD198DA8F331EEDCA0F4FC3
-:1012A000542FD42C8C2A8A320ECC020BAB010CBBEF
-:1012B0000C65BF0E0A49516E920263FF058A330A1C
-:1012C000AB5064BEFD2CD0130AEE510ECE010E0EB3
-:1012D000410C0C410ECC0C65CEE82FD012B0FF654E
-:1012E000F26EC0B08E378CD88A362FD2097CA30715
-:1012F0007AC9027EFB01C0B165BEC78835DBA0AEEE
-:101300008E78EB01B1AB89D7DAC0AF9D79DB01B143
-:10131000CAC0C07BA3077AB9027DEB01C0C165CE0C
-:10132000A1C090292467C020D10F88378C3698142B
-:101330000CE90C29161408F80C981D78FB072812E4
-:1013400014B088281614891D9F159B16C0F02B1207
-:101350001429161A2B161B8B147AE30B7AE90688CC
-:10136000158E1678EB01C0F165F1B929121A2F120A
-:10137000118A352E121B9A1AAFEE2F1210C0A0AF91
-:101380009F79FB01B1EE9F11881AC0F098107AE3A3
-:101390000A7EA9052A12017A8B01C0F164F08160EE
-:1013A000018289368B3799170BE80C981F09C90CF5
-:1013B00029161578EB07281215B088281615D9C0FC
-:1013C0009A199E188A1F2E12152A161A2E161BDA23
-:1013D000C0C0E08C177F930B7FA90688188F1978FF
-:1013E000FB01C0E165E13D29121A2F12138A352E47
-:1013F000121B9A1BAFEE2F1212C0A0AF9F79FB01F8
-:10140000B1EE9F13881BC0F098127AE30A7EA905FB
-:101410002A12037A8B01C0F165F1092E12162E16DD
-:10142000192A121B005104C0E100EE1AB0EE2E166C
-:10143000170EFF132F16180FCC01ACAA2F121A0E7D
-:10144000BC01ACFC7FCB01B1AA2A161B2C161A6377
-:10145000FC6200007FB30263FE3163FE2B7EB302A9
-:1014600063FC3463FC2E00006450C0DA20DBF058CB
-:1014700015DEC020D10FC09163FD7E00C09163FADC
-:101480004CDA20DB70C0D12E0A80C09A2924682C47
-:1014900070075814CED2A0D10F034C0B18ED51DBBE
-:1014A000C0A82878C3022BCDF8D9B063FA65000034
-:1014B0002A2C74DB40580E5063FAE80000002D25FA
-:1014C000027BC901C0B064B0172CB00728B000DAA5
-:1014D0002006880A28824CC0D10B8000DBA065AFB3
-:1014E000E7C020D10FC09163FC04022A02580250C9
-:1014F0000AA202060000022A0258024D0AA20206AF
-:101500000000DB70DA20C0D12E0A80C09E2924683A
-:101510002C70075814AEC020D10FC09463FBCF00CD
-:10152000C09663FBC9C09663FBC400002A2C74DB21
-:1015300030DC405BFE13DBA0C2A02AB4002F200CDD
-:1015400063FF27008D358CB77DCB0263FDD263FC32
-:10155000718F358ED77FEB0263FDC563FC6400009D
-:101560006C1004C020D10F006C1004C020D10F00FB
-:101570006C10042B221E28221DC0A0C09429240612
-:101580002A25027B8901DBA0C9B913ED08DA2028DE
-:10159000B0002CB00703880A28824CC0D10B800011
-:1015A000DBA065AFE7C020D10F0000006C1004295C
-:1015B00020062A2102689805289CF965811A0A0AE2
-:1015C0004C65A0F016ECFB2B629E1AECF86FB8028B
-:1015D0006000F12AA22668A0078B200ABB0C65B028
-:1015E000E32A629D64A0DD2B200C0CBC11A6CC2D3F
-:1015F000C2866FD9026000D71DECEF0DBD0A2DD257
-:10160000A368D0078E200DEE0C65E0C327C285C00D
-:10161000E06470BB1DECF468434D1CECF38A2B0CAA
-:10162000AA029A7089200899110D99029971882A45
-:1016300098748F329F75282104088811987718ECC8
-:10164000E40CBF11A6FF2DF285A8B82E84CF2DDCA7
-:10165000282DF685C85A2A2C74DB40580DE7D2A0F5
-:10166000D10FC020D10F00002C9CF964C08D2C201C
-:10167000668931B1CC0C0C472C24666FC669709E0C
-:101680006618ECDA89308F2B0989400B991009FF15
-:101690000208FF029F708C2008CC110DCC029C71B7
-:1016A0008A339A7389329972882A98748F349F7515
-:1016B00063FF820000CC57DA20DB30DC405814B8DE
-:1016C000C020D10F00DA20C0B658154763FFE500EF
-:1016D000DA2058154563FFDC00DA20DB30DC40DD22
-:1016E000505815C7D2A0D10F2B21045813DA1DEC86
-:1016F000BD2B200CC0E02E246663FF842F2123C065
-:10170000C87FC30263FF792C20662B2104B1CC0C67
-:101710000C472C24665813CF1DECB32B200CC0E0D3
-:101720002E246663FF5A00006C1004C0B7C0A116D7
-:10173000ECB015ECA2D720D840B822C04005350245
-:101740009671957002A438040442C94B1AEC95199D
-:10175000EC9629A67EC140D30F6D4A050080880013
-:10176000208C220A88A272D10FC05008A53875B00B
-:10177000E363FFD76C100893149412292006655276
-:1017800088C0716898052A9CF965A29816EC892989
-:1017900021028A1409094C6590C78AA00A6A512A55
-:1017A000ACFD65A0BCCC5FDB30DA208C1258147C19
-:1017B000C0519A14C7BF9BA98E142EE20968E0603D
-:1017C0002F629E1DEC7A6FF8026000812DD2266890
-:1017D000D0052F22007DF9752C629DC79064C06DE5
-:1017E0009C118A142B200C2AA0200CBD11A6DD0A06
-:1017F0004F14BFA809880129D286AF88288C09799F
-:101800008B551FEC6C0FBF0A2FF2A368F00528223E
-:10181000007F894329D285D49065907760003D0090
-:10182000002B200C1FEC640CBD11A6DD29D2860F05
-:10183000BF0A6E96102FF2A368F00488207F8905F6
-:1018400029D285659165DA205814E7600013DA2003
-:10185000C0B65814E5600009C09063FFB9DA20589B
-:1018600014E28914899109FE506551E48C128D149B
-:10187000DA20DBD08DD09E100D6D515813549A1480
-:1018800064A208C75F8FA195A9C0510F0F479F128F
-:1018900063FEFB00C091C0F12820062C2066288C36
-:1018A000F9A7CC0C0C472C24666FC6088D148DD17B
-:1018B00070DE01C090DD90648159C9D32A12012BDA
-:1018C00021045813648A14C0B02B24668EA92AA060
-:1018D000200E28141CEC438D1415EC37C1700A77C8
-:1018E0003685562DDC28AC2C9C13DED0A8557CD335
-:1018F000022EDDF8D3E0DA40055B02DC305BFF8AC4
-:10190000D4A028200CB455C0D02B0A882F0A800CF4
-:101910008C11A6CC29C285AF3FAB9929C6851CEC9A
-:101920002CDEF0AC882D84CF28120329120478F322
-:10193000022EFDF8289020D3E007880CC17008081B
-:1019400047289420087736657FAB891413EC2A89E1
-:1019500090C0F47797491BEC28C1CA28210485144C
-:10196000099E4006EE11875304881185520E8802A5
-:101970000C88029BA09FA18F2B9DA598A497A7954B
-:10198000A603FF029FA22C200C1EEC11AECE0CCCA5
-:101990001106CC082BC2852DE4CF2BBC202BC6858D
-:1019A0002A2C748B12580D14D2A0D10F28203DC0C0
-:1019B000E07C877F2E24670E0A4765A07B1AEC0F18
-:1019C00088201EEBFD8F148EE48FF40888110A889E
-:1019D000020F8F14AFEE1FEC0A98910FEE029E904B
-:1019E0001EEC09C0801AEBFA2CD285AABAB8CC2812
-:1019F000A4CF2CD6852C21022F20700ECC02B1FF53
-:101A00002F24702C2502C020D10F87148770070760
-:101A10004763FD6E282123C099798B0263FE9ADD0E
-:101A2000F063FE9500DA20DB308C12DD505814F4A0
-:101A3000D2A0D10FC0E163FF7A8B148C12DD50C0AD
-:101A4000AA2E0A802A2468DA20581360D2A0D10F67
-:101A5000007096552B629E6EB8531DEBD42DD22686
-:101A600068D0048E207DE9452A629DCBAF2B2104EE
-:101A70002C20665812F8C090292466821418EBE2D4
-:101A80008F2108FF019F21C020D10F008B10C9B802
-:101A90008CA00C6C51CCCC8E241FEBD08DE19E140D
-:101AA0000FDD029DE18810658FA9C020D10FDA20DB
-:101AB000C0B658144DC020D10F0000006C1006298C
-:101AC0002102C0D07597102A32047FA70A8B357F78
-:101AD000BF052D25020DD902090C4C65C18216EBFC
-:101AE000B41EEBB228629EC0FA78F3026001882926
-:101AF000E2266890078A2009AA0C65A17A2A629DCD
-:101B0000DFA064A1772B200C0CBC11A6CC29C286C7
-:101B1000C08C79830260015719EBA709B90A299291
-:101B2000A3689007882009880C65814327C2851C1B
-:101B3000EBA964713A8931098B140CBB016FB11D9B
-:101B40002C20669F10B1CC0C0C472C24666EC6026C
-:101B500060014009FF5065F13A8A102AAC188934B7
-:101B6000C0C47F973C18EBAA1BEBA98F359C719BD7
-:101B7000708B209D7408BB029B72C08298751BEB12
-:101B8000A50F08409B730F881198777FF70B2F21C3
-:101B900002284A0008FF022F2502C0B4600004009A
-:101BA0000000C0B07E97048F362F25227D970488D1
-:101BB000372825217C9736C0F1C0900AF9382F3C90
-:101BC0002009094264908619EB7618EB7728967EF7
-:101BD00000F08800A08C00F08800A08C00F0880045
-:101BE000A08C2A629D2DE4A22AAC182A669D893019
-:101BF0007797388F338A3218EB8007BE0B2C21047D
-:101C0000B4BB04CC1198E0C08498E1882B9DE59A80
-:101C1000E69FE71AEB78099F4006FF110FCC020AF6
-:101C2000880298E2C1FC0FCC022CE604C9B82C2033
-:101C30000C1EEB670CCA11AECC06AA0829A2852D92
-:101C4000C4CF09B90B29A685CF5CC020D10FC081B4
-:101C5000C0900F8938C08779880263FF7263FF667E
-:101C600000CC57DA20DB30DC4058134DC020D10FB8
-:101C7000DA205813DD63FFE8C0A063FE82DA20C0DB
-:101C8000B65813D963FFD900DB402A2C74580C5A7C
-:101C9000D2A0D10F8A102B210458126E1EEB44C023
-:101CA000D02D246663FEB1006C1006D62019EB3FE0
-:101CB0001EEB4128610217EB3E08084C65805F8AE5
-:101CC000300A6A5169A3572B729E6EB83F2A92263A
-:101CD00068A0048C607AC9342A729D2C4CFECAAB71
-:101CE0002B600CB64F0CBD11A7DD28D2860EBE0AA4
-:101CF00078FB269C112EE2A32C160068E0052F62CB
-:101D0000007EF91522D285CF2560000D00DA60C073
-:101D1000B65813B5C85A60010F00DA605813B2659F
-:101D20005106DC40DB308D30DA600D6D51581227E2
-:101D3000D3A064A0F384A1C05104044763FF6D00E5
-:101D4000C0B02C60668931B1CC0C0C472C64666F36
-:101D5000C60270960A2B610458123EC0B02B64660E
-:101D60006550B42A3C10C0E7DC20C0D1C0F002DFCF
-:101D7000380F0F4264F09019EB0A18EB0B28967E8F
-:101D80008D106DDA0500A08800C08CC0A089301DC0
-:101D9000EB1A77975388328C108F3302CE0BC02406
-:101DA00092E12261049DE00422118D6B9BE59FE787
-:101DB00098E61FEB100998400688110822020FDDF3
-:101DC00002C18D9DE208220292E4B4C22E600C1F73
-:101DD000EB000CE811A7882C8285AFEE0C220B2BB0
-:101DE000E4CF228685D2A0D10F28600CD2A08C111E
-:101DF00019EAF80C8D11A988A7DD2ED2852B84CF86
-:101E00000ECC0B2CD685D10FC0F00ADF387FE8024C
-:101E100063FF6C63FF6000002A6C74C0B2DC20DDDD
-:101E20004058121CC0B063FF63C020D10F000000F7
-:101E30006C10042C221D2A221EC049D320293006F2
-:101E4000243468C0407AC105DDA060000200C0D023
-:101E50006E9738C08F2E0A802B3014C09629340616
-:101E60000EBB022E31022B34147E8004243502DE98
-:101E7000407AC10EC8ABDBD0DA302C0A00580A76A3
-:101E80002E31020E0F4CC8FEC020D10F6895F828E5
-:101E9000310208084C658FEF1AEAC61CEAC42BA26F
-:101EA0009EC09A7B9B462BC22668B0048D307BD99E
-:101EB0003B29A29DC0E3CB9394901BEAD72D31041C
-:101EC0009B9608DD110EDD029D979D9112EAD4C00C
-:101ED000E524C4A22E34062F310228A29D02FF025F
-:101EE000288C3028A69D2F3502C020D10FDA30C0B3
-:101EF000B658133DC020D10F6C10062920066898F3
-:101F000005289CF965825D29210209094C6592101A
-:101F1000CD51DB30DA20044C025812A1C051D3A0BD
-:101F2000C7AF2A360AC0E019EAA31DEAA91FEAA230
-:101F30008A3A16EA9FB1AC64C13528629E6F880266
-:101F40006001F129DC332992266890078B2009BBB8
-:101F50000C65B1E027629DC08E6471D82B200C0CFB
-:101F6000BC11A6CC29C2867983026001D219EA91FC
-:101F700009B90A2992A397106890082822000988B5
-:101F80000C6581BB27C2856471B5292006299CF99F
-:101F90006491EC2C20668931B1CC0C0C472C246662
-:101FA0006EC6026001A109F85065819B883689F4EC
-:101FB000088C14AC991CEA810C99022C21049970AC
-:101FC00019EA980808479971892A0988100899021E
-:101FD00018EA95089902997228301329301204885A
-:101FE0001006991008990228302C9A740C88100851
-:101FF000C802098802987389379975883898768A53
-:1020000039C0819A771AEA888935987B9978098945
-:10201000140A9902997A8A30893277A73618EA76B3
-:102020008F33987CC084987D882B2E761129761268
-:102030002F761319EA700A9F4006FF1104CA11098E
-:1020400088020FAA02987EC1F90FAA022A7610C050
-:10205000AA600001C0A6ADBF0CBC11A6CC29C285E8
-:102060002EF4CF09A90B29C685655107C020D10FD1
-:102070002B200C0CBC1106CC0828C28609B90A6FAB
-:10208000890260012E2992A36890082A220009AAD9
-:102090000C65A11F2AC28564A11928203D0828408B
-:1020A00064808C843504841464408485F574537F83
-:1020B0008436048414644077745374293013C08CBC
-:1020C00079886CC0902924670908476580ED8820CD
-:1020D00089F484351FEA4B048414A4940F440294B9
-:1020E000A014EA4608881104880298A1843698A3AF
-:1020F000048414A4990F990299A219EA42ADB42854
-:10210000C2852E44CF288C1028C6852821022F2076
-:1021100070098802B2FF2F2470282502C020D10F39
-:1021200000CC57DA20DB30DC4058121DC020D10F24
-:10213000C09163FF8FDA20C0B65812AB63FFE10095
-:10214000DA205812A963FFD88A102B2104581141B4
-:102150001DEA201FEA192B200CC0E02E24668A3AC3
-:1021600063FE480000DA20DB30DC40DD50581324E9
-:10217000D2A0D10F2A2C74DB40580B1FD2A0D10F54
-:10218000292123C08879830263FE202A12002C2093
-:10219000662B21042CCC010C0C472C246658112DE5
-:1021A0001DEA0C1FEA052B200CC0E02E24668A3A9B
-:1021B00063FDF800DA2058128C63FF64DA205BFFBD
-:1021C0001CD2A0D10F0000006C10089515C061C191
-:1021D000B0D9402A203DC0400BAA010A64382A2009
-:1021E0000629160668A8052CACF965C33B1DE9F263
-:1021F0006440052F120564F29C2621021EE9EE06BA
-:10220000064C6562E315E9EA6440D98A3529300352
-:102210009A140A990C6490CC2C200C8B149C110CF1
-:10222000CC11A5CC9C122CC286B4BB7CB30260023C
-:10223000D38F110EFE0A2EE2A368E0098620D30F89
-:102240000E660C6562BE88122882856482B6891487
-:1022500064905EDA80D9308C201EE9E81FE9E91D20
-:10226000E9D68B148DD4D4B07FB718B88A293C1026
-:10227000853608C6110E66029681058514A5D50F10
-:10228000550295800418146D8927889608CB11088B
-:1022900088140EBB02A8D8299C200F88029BA19805
-:1022A000A088929BA3088814A8D80F880298A22A15
-:1022B000AC1019E9D4C0C08F141EE9C586128D1167
-:1022C000286285AEDD08FF0B2CD4CF2821022F66B3
-:1022D000858B352A2070098802ABAA2825022A247A
-:1022E00070C020D10F29529E18E9B16F9802600288
-:1022F0000828822668800829220008990C6591F92F
-:102300002A529DC1CA9A1364A1EF2B200C262006E5
-:102310000CB811A5882D82860EBE0A7DC30260020C
-:10232000022EE2A368E0082F22000EFF0C65F1F3F5
-:10233000288285DE806481FF9810266CF96461FF35
-:102340002C20668831B1CC0C0C472C24666EC6025A
-:102350006001BC08FD5065D1B617E9B419E9981AB7
-:10236000E99F2C21048B2D2830102F211D0C881063
-:102370000BFB090C88020A880209BB0264415289DE
-:1023800010C04D9B90979198928D35D9E064D06C98
-:10239000D730DBD0D8307FD713273C10BCE92632AA
-:1023A000168C3996E69CE78A37B4389AE80B1314F2
-:1023B0006430492A821686799A9696978C778A7D18
-:1023C0009C982B82172C7C209A9A2A9C189B998681
-:1023D0007BB03BB8896DB9218BC996A52692162A88
-:1023E000AC18B8999BA196A08BC786CD9BA22B92C7
-:1023F0001596A49BA386CB2CCC2026A605C0346BB7
-:10240000D4200D3B0C0DD8090E880A7FB705C0906B
-:102410009988BC88C0900B1A126DAA069988998B6E
-:10242000288C18C0D01BE9831CE98216E978B1FF1B
-:102430002A211C23E6130F0F4F26E6122F251D7F9E
-:10244000A906C0F0C08028251D05F6111AE9718F74
-:10245000202BE6152CE6162DE61726E6180AFA02BA
-:102460002AE614292006299CF96490FF29200C8D66
-:1024700015C0801AE9570C9C11AA99A5CCDA202B1B
-:10248000C2852894CF0B4B0B2BC685C0B08C165839
-:102490001114D2A0D10F8A356FA548D8308BD56DD5
-:1024A000A90C8A860A8A14CBA97AB337288C10C063
-:1024B00080282467080B4765B112DA20DB302C1224
-:1024C00006581137D3A0C0C1C0D02DA4039C1563FA
-:1024D000FD26863664610C8910C04D9B90979198BB
-:1024E0009263FEA4C08163FFC78A15CCA7DA20DB04
-:1024F000308C1658112BC020D10FDA20C0B65811DD
-:10250000BA63FFE400DA208B115811B763FFD900DA
-:102510009E178A132B210458104F8E17C0B02B24FE
-:102520006663FE34C08063FE09DA20DB308C16DD82
-:1025300050581233D2A0D10FDA205811AB63FFA844
-:102540002D2123C0C87DC30263FE0D8A132B2104F5
-:102550002C20669817B1CC0C0C472C246658103DE3
-:102560008E17C0D02D246663FDEE0000262123B017
-:102570006606064F262523656EF128206A7F8705AB
-:102580000829416490A5C0D01BE91C19E92B26201D
-:102590000723E61BB16609FA022BE61A28200A2D4A
-:1025A000E61D2AE61E09880228E61C88260606473C
-:1025B00028E6202B220826E53E2BE6212D24072C99
-:1025C00020062A206468C347B44463FE9EDB30DAE9
-:1025D000208D15C0CE2E0A802C24688C1658107BB6
-:1025E000D2A0D10F8E102A321616E8F30A2A1486CA
-:1025F000662BE61297E127E61328E614AA66096619
-:102600000296E02EEC4869ED50C14663FD7A000069
-:1026100064AFB419E8E928201689920A880C009161
-:102620000400881AA8B8982963FF9C002B21046E27
-:10263000B81E2C2066B8CC0C0C472C2466C9C09E52
-:10264000178A135810048E17C0348F20C0D02D2441
-:1026500066C06826240663FF2C008D35C08064D0D8
-:102660004AD9E0DC30DBE0DF301AE8F4B188B4FFAF
-:1026700017E8F486C9249DFF8DC82CCC102D463058
-:102680000767012D46320A66011DE8EE264631AD88
-:102690006D2D463326F21597B796B684C3BCBB940E
-:1026A000B58D35299C107D83C22F211DC14663FD48
-:1026B0004B0000006C1006292006289CF86582C398
-:1026C0002921022B200C09094C6590E116E8B90C70
-:1026D000BA11A6AA2DA2862C0A127DC3026002900E
-:1026E00019E8B509B90A2992A36890078C2009CC8A
-:1026F0000C65C27C29A2856492762D629E1AE8AB95
-:102700006FD8026002722AA22629160168A0082B3F
-:1027100022000ABB0C65B26029629DC18C6492588C
-:102720002A21200A806099102C203CC7EF000F3E20
-:10273000010B3EB1BD0FDB390BBB098F260DBD115F
-:102740002DDC1C0D0D410EDD038E27B1DD0D0D417D
-:102750000FEE0C0DBB0B2BBC1C0BB7027EC71C2C49
-:1027600021257BCB162D1AFC0CBA0C0DA16000099B
-:102770003E01073EB1780987390B770A77EB026093
-:10278000020A2C2123282121B1CC0C0C4F2C25230B
-:102790007C8B29B0CD2D2523C855DA20DB30580F8E
-:1027A000FA292102CC96C0E80E9E022E2502CC57B3
-:1027B000DA20DB30DC4058107AC020D10F2C2066A4
-:1027C0008931B1CC0C0C472C24666EC6026001D353
-:1027D00009FD5065D1CD2F0A012E30112922146434
-:1027E000E01128221B090C4400C10400FA1A0A88CF
-:1027F0000228261B2E3010C0A0C0B088301CE86E06
-:1028000094129513C04125203C2CC022088D1477CA
-:1028100087052F0A010CFA38C0F2C0840858010F4E
-:102820005F010F4B3805354007BB10C0F0084F382B
-:1028300008FF100FBB0228ECFEC0F0084F38842BB5
-:102840000BA8100AFF102A21200F88020B8802080B
-:10285000440218E87D8F110844022821250A2A1411
-:102860000828140488110A88022A210494F08B2075
-:1028700004E41008BB1104BB02C04A04BB029BF174
-:10288000842A08AB110BEB0294F40A54110B440296
-:102890000555100D1B4094F707BB100B550208554A
-:1028A00002C08195F68433C05094F3B1948B329575
-:1028B000F898F99BF2C080C1BC24261498FB9BF5C4
-:1028C00099FA853895FC843A94FD8B3B9BFE8839B8
-:1028D00098FF853525F6108436851324F6118B373D
-:1028E00084122BF612C0B064C08189307797468D70
-:1028F0003288332E30108F111CE840099940069918
-:10290000112CF614C0C42CF6158C2B2DF61A28F6B3
-:102910001B2BF61904A81109880208EE0219E835E4
-:10292000C18008EE0209C90229F6162EF618C09ECB
-:10293000600004000000C09A2F200C18E8250CFE4F
-:1029400011A8FFA6EE2DE2852BF4CF0D9D0B2DE6F1
-:1029500085C87F8A268929A7AA9A260A990C090977
-:102960004829252565504CC020D10F00C09A63FF2F
-:10297000C6DA2058109D63FE34DA20C0B658109A8B
-:1029800063FE2A00689738C020D10F0000DA20DBF0
-:1029900070581057C0B0C0C10ACA390ACB3865BDDB
-:1029A000E063FE098A102B2104580F2AC0B02B24A3
-:1029B0006663FE21DB402A2C7458090FD2A0D10F88
-:1029C000DA20580F2F63FCF76C1004C020D10F00E1
-:1029D0006C1004290A801EE81D1FE81D1CE7F50C79
-:1029E0002B11ACBB2C2CFC2DB2850FCC029ED19CA4
-:1029F000D0C051C07013E81914E81818E8162AB2AC
-:102A000085A82804240A234691A986B8AA2AB6854F
-:102A1000A98827849F25649FD10F00006C100AD6D7
-:102A200030283010292006288CF964829B68980B86
-:102A30002A9CF965A1B2022A02580F1189371BE7B7
-:102A4000DEC89164520E2A21020A0C4C65C2588DD0
-:102A50003019E7D774D7052E212365E29E2F929E69
-:102A60001AE7D36FF8026002532AA22668A0082C46
-:102A700022000ACC0C65C2442A929D64A23E9A159B
-:102A80001FE7CD8D67C1E664D00E2B620618E7CA3A
-:102A900064B0052880217B8B422B200C18E7C50CE5
-:102AA000BC11A8CC29C28679EB450FBE0A2EE2A341
-:102AB00068E0048F207EF9372CC2859C1864C233ED
-:102AC0002B212F87660B7B360B790C6F9D266ED2E0
-:102AD000462C203D7BC740CE5560001E2A200CC1ED
-:102AE000B28C205810759A1864A2458D6763FFCF89
-:102AF000C0C063FFC5D7B063FFD300C0E060000271
-:102B00002E60030EDB0C6EB20EDC700CEA11AA6AAA
-:102B10002AAC20580199D7A0DA20DB70C1C82D213A
-:102B20002058101B8C268B279A160CBB0C7AB334BA
-:102B30008F18896399F3886298F28E659EF82D60EC
-:102B4000108A189D1768D729C0D09DA92C22182B50
-:102B500022139CAB9BAA97A58E667E73026000979A
-:102B6000CF5860001FDA208B16580FE165A138633B
-:102B7000FFBDC081C0908F18C0A29AF999FB98FA46
-:102B800097F563FFD2DB30DA20DC40580F85C05167
-:102B9000D6A0C0C02BA0102CA4039B172C12080297
-:102BA0002A02066B02DF702D60038E179D149E10A3
-:102BB0000CDD11C0E0AD6D2DDC205801188C148B9C
-:102BC00016ACAC2C64038A268929ABAA0A990C9A04
-:102BD00026886609094829252507880C98662F222A
-:102BE00018A7FF2F261863FE96DA20DB30DC40DDC5
-:102BF00050581083D2A0D10FC0302C20668961B10B
-:102C0000CC0C0C472C24666EC6026000D2C0300982
-:102C1000FD5065D0CA8E6764E069647066DB608CC5
-:102C200018DF70DA202D60038E170CDD119E10ADB9
-:102C30006D2DDC201EE7845800F9232618DA208B3E
-:102C400016DC402F2213DD50B1FF2F2613580F241E
-:102C5000D2A0D10F0028203D084840658DE76F9530
-:102C60003EDA308DB56D990C8CA80C8C14CACF7CD3
-:102C7000D32D2AAC10C090292467090D4764DDC507
-:102C8000600092002C1208066B022D6C20077F0258
-:102C90008E17DA209E101EE76B58007D63FF9A00A6
-:102CA000C09163FFD1000000655081DA20DB60DC59
-:102CB00040580F3BC020C0F02FA403D10FDA20C032
-:102CC000B6580FC963FFE000006F950263FD6CDA30
-:102CD00020DB30DC40DD50C4E0580EBCD2A0D10F68
-:102CE0008A152B2104580E5B232466286010981740
-:102CF00063FF2100DA20580FBC63FFABC858DB30FC
-:102D0000DA20580EA12A210265AF9CC09409A902BD
-:102D100029250263FF91DB30DC40DD50C0A32E0A81
-:102D2000802A2468DA20580EA9D2A0D10FC020D161
-:102D30000FDA202B200C580FC563FF6B6C10042892
-:102D40002006C062288CF8658125C050C7DF2B2281
-:102D50001BC0E12A206B29212300A104B099292559
-:102D600023B1AA00EC1A0BC4010A0A442A246B04FA
-:102D7000E4390DCC030CBB012B261B6440692920D0
-:102D80000C1BE70B0C9A110BAA082FA2861BE70954
-:102D90006FF9026000B60B9B0A2BB2A368B0082C37
-:102DA00022000BCC0C65C0A42BA2851DE72D64B0BE
-:102DB0009B8C2B2421040DCC029CB08820C0C5081C
-:102DC00088110C880298B1882A08441198B48F346D
-:102DD00094B79FB5C0401EE6FE2DA2850E9E082525
-:102DE000E4CF2DDC282DA68529210209094C689401
-:102DF0001A689820C9402A210265A00B2A221E2B9E
-:102E0000221D7AB10265A079C020D10F2C21236543
-:102E1000CFDE6000082E21212D21237EDBD52B2241
-:102E20001E2F221D2525027BF901C0B064BFC413EB
-:102E3000E6DF2CB00728B000DA2003880A28824C8D
-:102E4000C0D10B8000DBA065AFE763FFA62A2C741E
-:102E5000C0B02C0A02580D951CE7039CA08B2008DB
-:102E6000BB1106BB029BA1893499A263FF790000C4
-:102E7000262468DA20DB30DC40DD50580FE1D2A098
-:102E8000D10FDA202B200C580F58C020D10F000092
-:102E90006C1006073D14C080DC30DB40DA20C047F0
-:102EA000C02123BC30032838080842774001B1DD37
-:102EB00064815A1EE6BB19E6BC29E67ED30F6DDAA3
-:102EC0000500508800308CC0E0C02025A03C14E6EE
-:102ED000BAB6D38FC0C0D00F87142440220F8940C8
-:102EE000941077F704C081048238C0F10B2810C019
-:102EF00044C02204540104FD3802520102FE380885
-:102F0000DD10821C07EE100E6E020EDD02242CFE78
-:102F1000C0E004FE380AEE100E88020D88028DAB68
-:102F20001EE6AA08D8020E880298B0C0E80428104D
-:102F30000E5E0184A025A125084411084402052540
-:102F400014045511043402C0810E8E3994B18FAA35
-:102F500084109FB475660C26A11FC0F2062614606B
-:102F60000009000026A120C0F20626140565020F04
-:102F7000770107873905E6100778100866020655BD
-:102F80000295B625A1040AE611085811082802087E
-:102F9000660296B7C060644056649053067E11C0C6
-:102FA000F489C288C30B340B96459847994618E6B6
-:102FB000919F410459110E99021FE68F020E470896
-:102FC000D80298420E99029F40C1E00E990299449E
-:102FD0002FA00CB4380CF91114E67E1EE675A4FF80
-:102FE000AE992E928526F4CF0E880B289685D10FA8
-:102FF0002BA00C1FE66F1CE6760CBE11ACBBAFEE2F
-:103000002DE28526B4CF0D3D0B2DE685D10FC08076
-:1030100005283878480263FEA263FE966C1006C04D
-:10302000C06570F18830C030088714778712C0B04F
-:10303000C0A619E661299022C030CC97C03160004B
-:1030400003C0B0C0A6C0E0C091C0D4C08225203C5F
-:103050000B3F109712831CC0700858010D5D0108CA
-:103060009738C0800B9838077710048810086802DA
-:10307000087702C0800D98382D3CFE0888100D9E00
-:10308000388D2B0AEE1008EE0207EE020CB8100F76
-:10309000DD02053B400EDD029D408920043D100805
-:1030A00099110D99022D210409A90208DD119941F8
-:1030B000872A05B9100D3D020ABB110DBB02087726
-:1030C0000297442821258712082814048811071E16
-:1030D0004007EE100E990275660926211F06261478
-:1030E000600006002621200626140868029B470976
-:1030F0008802984629200CD2C0C0800C9E111BE685
-:10310000341FE62BAB99AFEE2DE2852894CF0DADA1
-:103110000B2DE685D10FDD40C0A6C0B08E51CAE0B0
-:10312000B2AAB1BB2DDC108F500E783698100877FC
-:103130000C9FD898D989538F52991199DB9FDA7EC9
-:103140008309B1CC255C10C97763FFCF88108D113E
-:1031500008E70C9751AD8DD7F078DB01B1F79D539F
-:1031600097528830C030088714088840648ED5652F
-:10317000BEC963FEBC0000006C1004D720B03A88C2
-:1031800020C0308221CAA0742B1E2972046D080F42
-:10319000C980C9918575B133A2527A3B0B742B0853
-:1031A00063FFE900649FECD10FD240D10F00000013
-:1031B0006C1008D630C0709515DA408E3914E5FED3
-:1031C0009A1464E0026451FC2920062A9CF865A246
-:1031D0005F2A21020A0B4C65B21F2C320015E5F460
-:1031E00074C7052D212365D3242E529E1AE5F06F56
-:1031F000E80260021B2AA22668A0082B22000ABB54
-:103200000C65B20C2E529D1DE5EB64E2038B386415
-:10321000B22D9E16C8BC8D691EE5E864D0052EE06F
-:10322000217BEB492E200C18E5E20CEF11A8FF29B9
-:10323000F286C186798B4A17E5DF07E70A2772A372
-:10324000687004882077893925F2856452A2272185
-:103250002E07B73607B90C6F9D01D7B089696E92FA
-:103260004228203D7B873C8A15CDAF600018C1B253
-:103270008C202A200C580E90D5A064A2AC8B6863D9
-:10328000FFCBC05063FFC3C0E06000022E60030E9E
-:103290009B0C6EB20EDC700CEA11AA6A2AAC285B99
-:1032A000FFB6D7A0DA20DB70C1C42D211F580E381D
-:1032B0008C268B27D4A00CBB0C7AB3258A63C090D4
-:1032C0009A538862995898528F659F598E679E5B72
-:1032D0008D6697559D5A8B687B7B748B15CEB3603A
-:1032E000000DDA20DB40580E0265A10D63FFCC0013
-:1032F000DA20DB308C14580DAAD6A0C0C0C0D19DF6
-:10330000152CA403DA20DB60DF70DC50C0E0256000
-:10331000039E101EE5C10C5D11AD6D2DDC285BFF19
-:103320003F8E66A5A88F67286403AF7F77FB01B146
-:10333000EE9E669F678D268C29A4DD0DCC0C9D2604
-:103340008B680C0C482C252507BB0C9B6863FEC3BF
-:103350002C20668961B1CC0C0C472C24666EC60209
-:103360006000B809FD5065D0B2CBBF8E69CBEBDBF6
-:1033700060DC50DF70DA201EE5BC2D6003C0809851
-:10338000100CDD11AD6D2DDC285BFF248B15C942BF
-:103390008A2629220904AA082A26060A990C09095C
-:1033A0004829252565B13CC020D10F00DB602D6C7C
-:1033B00028DF70DA20C0C01EE5AC9C10DC505BFE3C
-:1033C000B463FFC7002D203D0D4D4065DDF96FE56D
-:1033D00022DA308F456DE90C8EAA0E8E14C9E37E79
-:1033E000F3112AAC10C090292467090F4764FDD758
-:1033F00060014100C09163FFED00881565814CDAE2
-:1034000020DB608C14580D66C020C09029A403D125
-:103410000FDA20C0B6580DF463FFDE008A162B21A8
-:1034200004580C8CC0A02A24668B6863FF3A000005
-:10343000002B9CF965B0C5DA20580C9163FD910012
-:103440002B200C0CBA11A5AA2FA286C1C27FC302E1
-:103450006000FC0DB90A2992A36890078C2009CC62
-:103460000C65C0EB26A2856460E52C20668931B12D
-:10347000CC0C0C472C24666FC60270960ADAE02B3F
-:103480002104580C74272466893077974B18E55926
-:103490001DE55A8A328B33C0F42C2104099E400664
-:1034A000EE1104CC110ECC029F61C1E00ECC029D46
-:1034B000608F2B9A669B679C64976508FF029F62EA
-:1034C0002F200C18E5430CFE11A5EE2DE285A8FF78
-:1034D00027F4CF2DDC202DE6858F1565F091C020D7
-:1034E000D10F00002A2C748B14580643D2A0D10FA0
-:1034F00000DA20DBE0580DBC63FEFE0000DA20DBC2
-:10350000308C148D15580E3ED2A0D10F00008815B6
-:10351000C888DA20DB30580C9C2A210265AEDAC05C
-:103520009409A90229250263FECFDA202B200C582A
-:103530000DC763FEC4272468DA20DB302C12042D6B
-:1035400012052E0A80580CA163FC7C00C020D10F0C
-:10355000DA20580DA58A15CDA1DA20033B022C12E2
-:1035600004580D0F27A403C020D10F00C020D10F95
-:103570002A2C748B14580620D2A0D10F6C100C2862
-:103580002102941008084C6583621FE50929F29E08
-:103590006F98026003661DE50529D2266890082A07
-:1035A000220009AA0C65A3542CF29D64C34E2B2063
-:1035B0000C0CB611AF66286286C1EC78E30260039A
-:1035C0004619E4FC09B90A2992A36890078A2009E0
-:1035D000AA0C65A33224628564432CC0E12A310918
-:1035E000C07027246689359A11992A8836991298CD
-:1035F0002B89379813992C883899140858149815E2
-:10360000982D89392A25042E251D29251C28302886
-:10361000C09228243C2A30290808479816098901B5
-:103620002A243D2A311599170A094109A90C299C18
-:10363000EC29251F7E87192D2A000DA06000083E69
-:10364000010A3EB1AD08DA390EAA110A990C2925F2
-:103650001F2A211F18E5060A8160C1D0941A951B04
-:1036600001083E00053EB184054839843C259CFC98
-:103670000D883629201408AA1C8D3D2726182E26D1
-:10368000132E26142E261527261B2E246B2724677F
-:1036900027246808581C0909432924142932112AAF
-:1036A000252E28252F27252427252527252C2725A6
-:1036B000232525202425212D2522841A2D211C8512
-:1036C0001B6FD202600209C0A099186D080AB1AA46
-:1036D00000A10400E91A7D9B0263FFEE8918C080F7
-:1036E000C0E1C070C0D29B1D951B961C9C1E16E4A9
-:1036F000D12C203D15E4E00C0B400DCC010BE7383C
-:103700001DE4C30A77100CE8380B8810C0C49C4134
-:103710000877029D40B0A80988118B209C499D48DC
-:10372000954B9643087702861418E4D115E4B9083E
-:10373000770205BB029B4A9B429746881287110875
-:10374000DA149A4E0D88100D77110877021AE4AC3E
-:1037500006D8140D6610087702974FC78F984D98BA
-:103760004C9845871598440715140D55110A5502B4
-:10377000954715E4C18A262D46102D46182D462062
-:103780002C46112C46192C46212B46122B461A2862
-:1037900046142846152B46228816254624254626FB
-:1037A0008B170A0C48090D4885130EDD1105CC1145
-:1037B0000839400BEB390299101EE4B00DCC020D14
-:1037C0005511082D400655022E461316E47B0FDDD9
-:1037D00011254616080840851B0188100DBB02867E
-:1037E000671DE4A70988020CBB0219E4771CE4A555
-:1037F0002B46172D461BA7661BE4A4C0702C461C45
-:103800000988028C1E28461E2B4623C0908B1D293A
-:10381000461D29461F18E49D29462728462529319B
-:10382000162E200629246A243117962D2425238656
-:103830001CCCE1272407C0D7090E4064E0829A29F6
-:1038400009284164809164409B2D2406C098094951
-:1038500036280AA024628501C404A844282104242F
-:1038600066850888118E3F8A3E2D32100EA41800FE
-:10387000C4040EAE1800EE110ACA530EDD02C0E3F6
-:103880000E880298C11EE48209084E9EC08E2094C4
-:10389000C398C59DC418E44E1DE47F05EE110EAA21
-:1038A000020DAA02A8B82784CF9AC21EE44024F2CF
-:1038B0009D27E4A2244C1824F69D655052C020D1C7
-:1038C0000F2D2406C0A0C09809493604A93863FF0B
-:1038D0007FC0A063FE070000654F6DC098C0A82A96
-:1038E000240663FF6B2D2406C09063FF63CC57DA78
-:1038F00020DB308C10580C2AC020D10F00DA20C0F9
-:10390000B6580CB963FFE500DA20580CB763FFDC4A
-:103910002A2C748B10580538D2A0D10F6C100628B1
-:1039200020068A336F8202600161C05013E42029AF
-:10393000210216E41F699204252502D9502C201576
-:103940009A2814E41D8F2627200B0AFE0C04770901
-:103950002B711C64E1398E428D436FBC0260016F94
-:1039600000E104B0C800881A08A80808D8029827FF
-:103970002B200668B32ECE972B221E2C221D011160
-:10398000027BC901C0B064B0172CB00728B000DAC0
-:103990002003880A28824CC0D10B8000DBA065AFD1
-:1039A000E7C020D10F2D206464DFCA8B29C0F10B42
-:1039B000AB0C66BFC02B200C0CBC11A6CC28C28659
-:1039C0002E0A0878EB611EE3FB0EBE0A2EE2A36806
-:1039D000E0052822007E894F29C2851EE4076490F5
-:1039E000461FE4159E90C084989128200A95930F55
-:1039F000880298928E200FEE029E942F2007882630
-:103A00002F950A98969A972E200625240768E34357
-:103A10002921022AC2851DE3EE2AAC20ADBD25D4A2
-:103A2000CF2AC68563FF4E002E2065CBEDC08228CD
-:103A30002465C9F605E4310002002A62821BE3F71F
-:103A40002941020BAA022A668209E4312921026374
-:103A5000FF23000064DFB88F422E201600F1040D12
-:103A6000EE0C00EE1AAEAE9E2963FFA38A202B3225
-:103A700021B1AA9AB0293221283223B499293621BA
-:103A80007989A92B32222B362163FFA0C020D10FC8
-:103A90009F27252415ACB828751C2B2006C0C12EE5
-:103AA000BCFE64E0AB68B7772DBCFD65DEC72D209A
-:103AB00064C0F064D0868E290EAE0C66E089C0F139
-:103AC00028205A288CFE08CF3865FEE863FF58008E
-:103AD00000E0049310C0810AF30C038339C78F08F8
-:103AE000D80308A80108F80C080819A83303C80C63
-:103AF000A8B828751C030B472B24158310CBB700DF
-:103B0000E104B0BC00CC1AACAC0CDC029C27659E76
-:103B10005EC0B20B990209094F29250263FE5000CD
-:103B20002D206A0D2D4165DF7EDA20C0B0580C755E
-:103B300064AF18C0F163FEEF9F2763FFD02E221FF2
-:103B400065EE3263FF79000028221F658E2763FF30
-:103B50006E252406252502C09063FE196C100665AB
-:103B600071332B4C18C0C7293C18C0A1C08009A8CC
-:103B7000380808426481101CE38A1AE38B2AC67E47
-:103B80002A5CFDD30F6DAA0500B08800908C894097
-:103B9000C0A00988471FE3B4080B47094C50090D22
-:103BA0005304DD10B4CC04CC100D5D029D310CBB70
-:103BB000029B3088438E2098350FEE029E328D2670
-:103BC000D850A6DD9D268E40C0900E5E5064E097D2
-:103BD0001CE39A1EE389038B0BC0F49FB19EB02DAA
-:103BE000200A99B30CDD029DB28F200CFF029FB416
-:103BF0008E262D20079EB68C282DB50A9CB7292429
-:103C0000072F20062B206469F339CBB61DE36B2305
-:103C100020168DD20B330C00D10400331AB48DA3BF
-:103C2000C3932922200C13E36A1FE3610C2E11AF0A
-:103C3000EEA3222924CF2FE285D2A00FDD0B2DE6A3
-:103C400085D10F002E200CB48C0CEB111FE3611DED
-:103C5000E358AFEEADBB22B28529E4CF02C20B22FE
-:103C6000B685D2A0D10F00002E200C1CE3511FE31B
-:103C7000580CEB11AFEEACBB22B28529E4CF028227
-:103C80000B22B685D2A0D10FC0D00BAD387DC802B3
-:103C900063FEEC63FEE08E40272C747BEE12DA703C
-:103CA000C0B32C3C18DD50580A7B8940C08063FEAD
-:103CB000E3DE60DA20DB30DC40DD505800059A108E
-:103CC000DB50077A0258044C881063FEF8000000AD
-:103CD0006C100692121EE3428C40AE2D0C8C472EC7
-:103CE0003C1804CA0BD9A07DA30229ADF875C30204
-:103CF000600084C0B0C023C0A09D106D0844B89F70
-:103D00000EB80A8D900EB70BB8770D6D36ADAA9D23
-:103D1000800D660CD8F000808800708C879068B1A8
-:103D200024B22277D3278891C0D0CB879890279C44
-:103D30001000708800F08C9D91CB6FC08108BB0390
-:103D400075CB3663FFB4B1222EEC1863FFD4859295
-:103D50000D770C86939790A6D67D6B01B1559693FF
-:103D60009592600016B3CC2D9C188810D9D078D3CA
-:103D7000C729DDF863FFC100C0238A421BE3470067
-:103D8000CD322D44029B3092318942854379A10581
-:103D90001EE3430E550187121BE334897095350BE2
-:103DA0009902993288420A880C98428676A6A6968D
-:103DB000768F44AFAF9F44D10F0000006C10089382
-:103DC00011D6308830C091086351080847059838EB
-:103DD0009812282102293CFD08084C6581656591EF
-:103DE000628A630A2B5065B18B0A6F142E0AFF7C1E
-:103DF000A60A2C205ACCC42D0A022D245A7FE00298
-:103E0000600215892888261FE32609880C65820F21
-:103E10002E200B0FEE0B2DE0FE2EE0FF08DD110E25
-:103E2000DD021EE320AEDD1EE3201CE3200EDD01DB
-:103E30000DCC37C180084837B88DB4889810896098
-:103E40001AE2DE7B96218B622AA0219C147BA317A9
-:103E50009D132A200C8B108C20580B978C148D13DB
-:103E6000DBA0CEAC6001C4002E200C1BE2D10CEA1A
-:103E7000110BAA082BA2861FE2CF7BDB3B0FEF0AB8
-:103E80002FF2A368F0052822007F892C2BA28564DD
-:103E9000B0AA87628826DE700C7936097A0C6FAD7D
-:103EA0001C8F279B1508FF0C77F3197E7B729D13DF
-:103EB0009C149B15CF56600025C0B063FFD0D790EF
-:103EC00063FFDD00009D139C14DA20DB70580B08A3
-:103ED0008B158C148D1365A06A8E6263FFCC00DA9B
-:103EE000208B11DC40580AAED6A08B15C051DE7075
-:103EF000DA20DC60DD405BFF768D138C14D9A02EB8
-:103F0000200C1BE2AB1FE2B20CEA11AFEFC0E0AB3A
-:103F1000AA2BA2852EF4CF0B990B29A68563FF1D32
-:103F200000DA20DC60DD40DE708912282007DF50D7
-:103F3000A9882824075BFF09D2A0D10F00DBE0DAB3
-:103F400020580B296550EF2A20140A3A4065A0EB4F
-:103F5000DB60DC40DD30022A0258099CD6A064A058
-:103F6000D584A183A0040447030547951203635138
-:103F7000C05163FE5C2C2006D30F28CCFD6480A5C5
-:103F800068C704C0932924062C2006C0B18D641F85
-:103F9000E28A9D279D289D298FF29D2600F104002D
-:103FA000BB1A00F004B0BE0EDD01C0F0ADBB8D65E4
-:103FB0002F24070D0E5E01EE11AEBB2E0AFEB0BB24
-:103FC0000B0B190EBB36C0E20B0B470EBB372B2475
-:103FD0001618E2820A09450D0B422B240B29240AEC
-:103FE000B4BE2E240C7D88572920162FCCFDB09D01
-:103FF0000A5C520DCC362C246465FDEC0C0C476435
-:10400000CDE618E26D8E2888820C9F0C008104009A
-:10401000FF1AAFEE9E2963FDCF1CE29C63FE1300E6
-:104020001CE29363FE0C8D6563FFA500DA202B2054
-:104030000C580B06645F0FC020D10F00C020D10FB9
-:10404000C093292416C09363FFA000006C1004C025
-:104050006017E2561DE259C3812931012A3008292F
-:10406000240A78A108C3B27BA172D260D10FC0C16B
-:104070006550512625022AD0202F200B290AFB2B20
-:1040800020142E201526241509BB010DFF0928F147
-:104090001C2B2414A8EE2EF51C64A0B52B221E2880
-:1040A000221D0111027B8901DB6064B0172CB0076F
-:1040B00028B000DA2007880A28824CC0D10B800083
-:1040C000DBA065AFE7DB30DC40DD50DA205800D8FC
-:1040D000292102090B4CCAB2D2A0D10F00CC5A2C14
-:1040E00030087BC1372ED02064E02D022A02033B2A
-:1040F00002DC40DD505800CED2A0D10F2B2014B0EE
-:10410000BB2B24140B0F4164F0827CB7CAC0C10CD6
-:104110009C022C2502D2A0D10FC020D10F2E200648
-:1041200069E2C12F21020F0F4C69F1B8262406263F
-:1041300025022B221E28221D2A200B2920150DAA1C
-:10414000092CA11C262415AC9929A51C7B814A6049
-:104150000049B0BB2B24140B0D41CBD67CB7022CED
-:1041600025022B221E2E221D7BE9022B0A0064B0A1
-:10417000172CB00728B000DA2007880A28824CC024
-:10418000D10B8000DBA065AFE7C020D10F2624064D
-:10419000D2A0D10F26240663FFC7DB601DE20764AF
-:1041A000BF422CB00728B000DA2007880A28824CCA
-:1041B000C0D10B8000DBA065AFE71DE1FF63FF24EA
-:1041C0006C1004282006C0646F8564CA5B29201423
-:1041D0007D9726DA20DB30DC40055D025800192986
-:1041E0002102090A4CC8A3C020D10F00C0B10B9B0B
-:1041F000022B2502C020D10F0000022A02033B023D
-:104200002C0A015800CAC9AADA20DB30DC40580960
-:10421000E429A011D3A07E97082C0AFD0C9C012C48
-:10422000A411C0512D201406DD022D241463FFA219
-:10423000DA20DB30DC40DD50C0E0580964D2A0D188
-:104240000F0000006C100616E1DA1CE1DA65513B44
-:10425000C0E117E1D62821028B2008084C65807B3D
-:104260002932000969516993722A629E6EA8482A10
-:10427000722668A0027AB93F2A629DB44FCBA72B61
-:10428000200C0CBD1106DD0828D28678FB150CBF6A
-:104290000A2FF2A368F00488207F89072DD285D3E6
-:1042A0000F65D0602A210419E202D30F7A9B1DDA30
-:1042B00020580864600024002C21041BE1FD7CBB15
-:1042C00013DA20C0B658085FC9536000EFDA2058EF
-:1042D0000A46600006DA20C0B6580A436550DDDCA5
-:1042E00040DB308D30DA200D6D515808B8D3A06412
-:1042F000A0CA1CE1B0C05184A18EA00404470E0ED8
-:104300004763FF50002B2104C08C8931C070DF70DF
-:1043100009F950098F386EB8172C2066AECC0C0CFA
-:10432000472C24667CFB099D105808CA8D10272451
-:104330006694D11EE1B6B8DC9ED0655056C0D7B8A1
-:104340003AC0B1C0F00CBF380F0F42CBF119E19465
-:1043500018E19628967EB04BD30F6DBA0500A08861
-:1043600000C08C2C200CC0201DE19A0CCF11A6FFA0
-:104370002EF285ADCC27C4CF0E4E0B2EF685D10F75
-:10438000C0800AB83878D0CD63FFC1008E300E0EE1
-:104390004763FEBD2A2C742B0A01044D025808BD48
-:1043A0002F200C12E18B0CF911A699A2FF27F4CF54
-:1043B000289285D2A008480B289685D10FC020D11D
-:1043C0000F0000006C1004C060CB55DB30DC4005F2
-:1043D0005D02022A025BFF9B29210209084CC88268
-:1043E000D2A0D10F2B2014B0BB2B24140B0C41CB2B
-:1043F000C57DB7EBC0C10C9C022C2502D2A0D10F09
-:104400000000022A02033B02066C02C0D0C7F72E4E
-:10441000201428310126250228240A0FEE012E241B
-:104420001458010D63FFA300262406D2A0D10F006B
-:104430006C1006282102D62008084C65809D2B2090
-:104440000C12E15B0CB811A2882A8286B5497A93D6
-:104450000260009719E15809B90A2992A3689008E7
-:104460002A620009AA0C65A0822882851CE1636487
-:1044700080799C80B887B14B9B819B10655074C03C
-:10448000A7D970280A01C0D0078D380D0D42CBDEA8
-:104490001FE1441EE1452EF67ED830D30F6D4A054C
-:1044A00000808800908C2E3008C0A000EE322E7460
-:1044B0000028600C19E1470C8D11A2DDA988C020ED
-:1044C0002CD2852284CFD2A00CBC0B2CD685D10F48
-:1044D000C0F0038F387FA0C063FFB400CC582A6CB3
-:1044E00074DB30DC405807F1C020D10FDA60580986
-:1044F000BE63FFE7DD402A6C74C0B0DC705808650D
-:104500002E30088B1000EE322E740028600C19E15A
-:10451000300C8D11A2DDA988C0202CD2852284CF39
-:10452000D2A00CBC0B2CD685D10F00006C10042936
-:104530002014282006B199292414688124C0AF2CA6
-:104540000A012B21022C24067BA004C0D02D2502B9
-:10455000022A02033B02044C02C0D05800BFD2A082
-:10456000D10FC020D10F00006C1004293101C2B45A
-:1045700029240A2A3011C28378A16C7BA169645076
-:10458000472C2006C0686FC562CA572D20147CD7FF
-:1045900022DA20DB30DC40DD505BFFA52921020957
-:1045A0000E4CC8E2C020D10FC0F10F9F022F250290
-:1045B000C020D10FDA20DB30C0C05BFFDC28201424
-:1045C00006880228241463FFC72920151BE0FB2A54
-:1045D000200BC0C09C240BAA092BA11C2C2415ABBA
-:1045E0009929A51C63FF9900C020D10FDA20DB3088
-:1045F000DC40DD50C0E0580875D2A0D10F000000AB
-:104600006C1004CB5513E0F625221F0D46110655FC
-:104610000CA32326221E25261F06440B24261E73C8
-:104620004B1DC852D240D10F280A80C04024261FFB
-:10463000A82828261E28261DD240D10FC020D10F21
-:10464000244DF824261E63FFD80000006C100428B7
-:104650002006D6206E85026000DE17E0D51DE0DC66
-:1046600019E0D5C0C1C0202A8CFC64A1322B6102A4
-:10467000B44E0B0B4C65B0A82B600C2A62000CB832
-:10468000110788082F828609B90A7FE30260009F1C
-:104690002992A368900509AA0C65A09328828564D5
-:1046A000808DB8891BE0DA94819B8065514DC0B73D
-:1046B000B838C0A1C0E009AE380E0E4264E0481A16
-:1046C000E0B81FE0B92FA67EB04A6DAA0500808829
-:1046D00000908CC0A02E600C0CE811A7882F82855A
-:1046E000ADEE0F4F0B2F86852B600622E4CF68B10D
-:1046F0002A296015C0B2C99AD2A02D61022B640686
-:104700000CDD022D6502D10FC0E008AE387EB0B7D7
-:1047100063FFAB00226406D2A0D10F00D2A0D10F5C
-:1047200000CC57DA60DB30DC4058089DC020D10F48
-:10473000DA6058092D63FFE80028221E29221D781F
-:104740009902280A00C176C1C1C1D21BE0A5C124CB
-:10475000AB6B6480437891402A80000CAF0C64F00E
-:10476000AE0DAE0C64E0A802AF0C64F0A207AE0C74
-:1047700064E09C2FACE864F0962EACE764E0902FE8
-:10478000ACE664F08A2A800708A80B088A027B83BB
-:10479000022A8DF8D8A065AFBBC0906000730000FE
-:1047A0002B600C0CB811A7882E82866EE87909BAA6
-:1047B0000A2AA2A368A0048E607AE96B2A82856423
-:1047C000A0651FE08DC0E32E64069EA19FA01FE0A0
-:1047D000B92E600A92A30FEE029EA28E600FEE0227
-:1047E0009EA42F60147AFF4722A417ADBE2F8285A6
-:1047F00022E4CF2FFC182F868563FE702A6C74C0CC
-:10480000B1DC90DD405807A31DE072C0C163FEC457
-:10481000D9A0DA60DB30DC40DD50C2F0C1E009FE37
-:10482000395807EAD2A0D10FDA605808EF63FEF0DA
-:104830002CA4170DBE0829828522E4CF299C1829B3
-:10484000868564500C2A6C74044B0258016BD2A00C
-:10485000D10FC020D10F00006C10062B221E282281
-:104860001D93107B8901C0B0C0C9C03BC1F20406D2
-:10487000401DE05BC0E2C0740747010E4E01AD2D44
-:104880009E11C0402E0A1464B06E6D084428221D8B
-:104890007B81652AB0007EA13B7FA1477B51207CB4
-:1048A000A14968A91768AA1473A111C09F79A10C26
-:1048B000C18B78A107C1AE290A1E29B4007CA12BA7
-:1048C0002AB0070BAB0BDAB07DB3022ABDF8DBA030
-:1048D000CAA563FFB428B01089116987BB649FB86B
-:1048E00063FFDC00647FB463FFD50000646FD0C059
-:1048F00041C1AE2AB40063FFC62B2102CEBE2A22DC
-:104900001D2B221E7AB12A8C107CB1217AB901C0EC
-:10491000B0C9B913E026DA2028B0002CB00703880C
-:104920000A28824CC0D10B8000DBA065AFE7D240E3
-:10493000D10F8910659FD463FFF300006C1008C08D
-:10494000D0C8598C302921020C0C4760000C8E30E5
-:104950000E1E5065E19E292102C0C116E015090B0B
-:104960004C65B0908A300A6E5168E3026000852F72
-:10497000629E1BE00E6EF8532BB22668B0052E2205
-:10498000007BE94727629DB748CB7F97102B200C0F
-:10499000B04E0CBF11A6FF29F2869E12798B4117EB
-:1049A000E00507B70A2772A368700488207789306A
-:1049B00029F285DF90D7906590652A210419E03CA3
-:1049C0007A9B22DA2058069F600029002C21041BC4
-:1049D000E0387CBB18DA20C0B658069AC958600186
-:1049E0004CC09063FFCCDA2058087F600006DA20C4
-:1049F000C0B658087D655135DC40DB308D30DA209B
-:104A00000D6D515806F2C0D0D3A064A12029210217
-:104A1000C05184A18CA00404470C0C4763FF3E00E6
-:104A2000C09C8831DBD008F850089B3828210498B6
-:104A3000116E8823282066AC8C0C0C472C24667CD5
-:104A4000BB159F139E148A108B115807028E148F6A
-:104A500013C0D02D24668A30C092C1C81BDFEC7F02
-:104A6000A6099BF099F12CF40827FC106550A4B816
-:104A70003ADF70C051C08007583808084264806728
-:104A800018DFC819DFC929867E6A420AD30F6DE98B
-:104A90000500A08800F08CC0A08930B4E37F962880
-:104AA000C0F207E90B2C94089B909F912F200C12C9
-:104AB000DFC80CF811A688298285A2FF2DF4CFD279
-:104AC000A009330B238685D10F22200C891218DF11
-:104AD000C00C2B11A6BBA8222D24CF2CB285D2A0AE
-:104AE0000C990B29B685D10FC087C0900A59387927
-:104AF000809663FF8ADB30DA20C0C1C0D05BFF56EE
-:104B0000292102C0D02A9CFE65AE4D2D2502C09001
-:104B100063FE45009E142A2C74C0B1DC70DD405841
-:104B200006DD8E14C0D01BDFB9C1C863FF6AC02088
-:104B3000D10F00006C100628210216DF9D08084CDA
-:104B400065821929629E6F980260022019DF9829F8
-:104B500092266890078A2009AA0C65A20F27629DF9
-:104B6000C0CC6472072B21048E31C0A0DDA00EFEE4
-:104B7000500ECD386EB8102C2066B1CC0C0C472CE2
-:104B800024667CDB026001EFC0C12930081BDF8A8C
-:104B900064909C2F0AFFC0D3B09E64E10268921318
-:104BA0006450882A2C74044B025800930AA202060F
-:104BB000000000002B200C2721040CBC11A6CC29DE
-:104BC000C286280A087983026001B919DF7A09B917
-:104BD0000A2992A36890082E220009EE0C65E1A430
-:104BE0002EC28564E19E26200713DF836E7B026060
-:104BF000019A17DF7A1FDF8319DFB0C0D228200A9D
-:104C000093E09DE1A9690F880298E22F90802A9491
-:104C100080B1FF07FF029FE32EC2851FDF6D0EDE0E
-:104C20000BAFBF2AF4CF2EC685655F76C020D10FAB
-:104C30002830102930112E301300993200ED3264E3
-:104C400080EE2A30141FDF9D00AA3278EF050F9EF8
-:104C5000092DE47F1EDF9B66A0050F98092A84803A
-:104C6000B4A718DF98C76F009104AE9EDDE000AFD7
-:104C70001A00C31A6EE1052DB2000DED0C1EDF9275
-:104C800008D81C063303AE882A848B2EB02E2784C6
-:104C90008C03EE010FEE022EB42E58018F63FEFF3F
-:104CA0002931082925042830142E3109B088648060
-:104CB000A32E240AC0812E30162CB4232E240BB42C
-:104CC000EF2F240C8C378B36292504DEB0DFC00C87
-:104CD0008F390B8E390FEE0264EEC4089F1101C4A8
-:104CE000048D380CB81800C4040CBE1800EE110E68
-:104CF000DD02C0E30EFF021EDF669F719E701EDFA5
-:104D0000658F2098739D7405FF110BCD53C180985A
-:104D1000750FDD020EDD029D721EDF242A24662F30
-:104D2000629D2AE4A22FFC182F669D63FE7100008D
-:104D3000002F30121BDF6600FA3278FF050B980B4C
-:104D40002A847F66D0050B9A0B2DA4802A3011008F
-:104D5000AA3263FF442F240A9E2B63FF56CC57DAF6
-:104D600020DB30DC4058070EC020D10F00DA20C015
-:104D7000B658079D63FFE500DA70580636C0A02AD2
-:104D8000246663FE02DA2058079863FFCFB16928D2
-:104D9000200A8620090947991129240798107F8144
-:104DA0002693E027E50A9AE388109DE119DF428DFA
-:104DB00011096F029FE42DE416098802C0D398E21E
-:104DC0002A240763FE5100001DDF0B0868118F11B4
-:104DD000892B93E008FF02C08F9FE50D990299E2AD
-:104DE000047F11C0D49DE108FF029FE463FFD0005F
-:104DF0006C1004C020D10F006C100485210D3811F7
-:104E000014DEE98622A42408660C962205330B934F
-:104E100021743B13C862D230D10FC030BC29992114
-:104E200099209322D230D10F233DF8932163FFE3E1
-:104E30006C100AD620941817DEDED930B8389819CD
-:104E40009914655252C0E1D2E02E61021DDEDB0EE4
-:104E50000E4C65E1628F308E190F6F512FFCFD658E
-:104E6000F1558EE129D0230E8F5077E66B8F181EF7
-:104E7000DF18B0FF0FF4110F1F146590CE18DF1567
-:104E80008C60A8CCC0B119DEC928600B09CC0B0D11
-:104E9000880929811C28811A2A0A0009880C08BA65
-:104EA000381BDF0B0CA90A2992947B9B0260008CB3
-:104EB0002B600C94160CBD11A7DD29D286B8487959
-:104EC00083026000D219DEBB09B80A2882A39817B2
-:104ED0006880026000A36000A51ADEFF84180AEE55
-:104EE00001CA981BDEB28C192BB0008CC06EB313B4
-:104EF0001DDEAF0C1C520DCC0B2DC295C0A17EDB6C
-:104F0000AE6000380C0C5360000900000018DEF1A0
-:104F10008C60A8CCC0B119DEA528600B09CC0B0DA4
-:104F2000880929811C28811A2A0A0009880C08BAD4
-:104F3000380CA90A2992947E930263FF72DA60C04A
-:104F4000BA58072964507360026600001ADE988C14
-:104F5000192AA0008CC06EA31A18DE940C1C5208EB
-:104F6000CC0B18DEDB2BC295C0A178B30263FF3FE8
-:104F700063FFC9000C0C5363FF09896078991829F5
-:104F8000D285C9922B729E1DDE896EB8232DD22642
-:104F9000991369D00B60000DDA6058071360001791
-:104FA0000088607D890A9A1A29729D9C129915CFF2
-:104FB00095DA60C0B658070C6551F58D148C18DB76
-:104FC000D08DD0066A020D6D51580580D3A09A1479
-:104FD00064A1DD82A085A1B8AF9F19050547020233
-:104FE000479518C05163FE602B6104C08C8931C0A5
-:104FF000A009F950098A386EB81F2C6066A2CC0C43
-:105000000C472C64667CAB119F119E1B8A155805BA
-:10501000918E1B8F11C0A02A64669F1164F0E12954
-:1050200012032812096DF9172F810300908DAEFE2F
-:105030000080889F9200908C008088B89900908CA6
-:1050400065514E8A10851A8B301FDE6B88122960DD
-:105050000708580A2C82942D61040ECC0C2C8694DF
-:105060006FDB3C1CDE95AC9C29C0800B5D50A29987
-:1050700009094729C48065D0DA2E600CC0D01FDE34
-:10508000540CE811AFEEA7882282852DE4CF0242AE
-:105090000B228685D2A0D10F8E300E0E4763FDA65F
-:1050A000A29C0C0C472C64077AB6CD8B602E600A4C
-:1050B000280AFF08E80C64810E18DE7E831682132E
-:1050C000B33902330B2C34162D350AC02392319F8D
-:1050D00030C020923308B20208E80292349832C0FD
-:1050E000802864072B600CD2A01CDE390CBE11A7EF
-:1050F000EE2DE285ACBB28B4CF0D9D0B2DE685D1FE
-:105100000F8B1888138D30B88C0D8F470D4950B414
-:10511000990499100D0D5F04DD1009FF029F800DA9
-:10512000BB029B8165508D851AB83AC0F1C0800CD6
-:10513000F83808084264806B1BDE1A19DE1B29B69A
-:105140007E8D18B0DD6DDA0500A08800C08CC0A08F
-:1051500063FEF30082138B161DDE2B28600AC0E06D
-:105160002EC4800D880202B20B99239F20C0D298D2
-:10517000229D2122600CB2BB0C2D11A7DD28D28507
-:1051800008BB0B18DE132BD685A8222E24CFD2A065
-:10519000D10F9E1B851A2A6C748B185BFF178E1B10
-:1051A00063FEA300C087C0900AF93879809263FF3C
-:1051B00086C020D10F9E1B2A6C74C0B18D18580573
-:1051C000358E1B851A63FE7E886B8213891608BE96
-:1051D000110ECE0202920B9E25B4991EDE069F2070
-:1051E0000E88029822C0EF04D8110E88029824C0BD
-:1051F000E49E21C080D2A02B600C2864071CDDF443
-:105200000CBE11A7EE2DE285ACBB28B4CF0D9D0BD3
-:105210002DE685D10F0000006C1004C020D10F00D6
-:105220006C10048633C071C030600001B1330031AE
-:105230000400741A0462017460F1D10F6C1004024E
-:105240002A02033B025BFFF61CDDDC1BDE24C79F4A
-:1052500088B009A903098A019AB079801EC0F00FAD
-:10526000E4311DDDD30002002BD2821EDE1D2AC1D7
-:10527000020EBB022BD6820AE431D10F28C102C133
-:105280009009880208084F28C50208E431D10F00B0
-:105290006C1004C0C00CE43112DDC81ADDC5000278
-:1052A0000029A28218DE111BDE0F2621020B9901B4
-:1052B00008660129A68226250206E43114DE0C15B3
-:1052C000DE07236A902326128550242611252613F3
-:1052D000222C40D10F0000006C1008D6102B0A645D
-:1052E000291AB41ADDB20D23111CDDB30F2511B834
-:1052F0001898130E551118DDFEAC55A838AA332C9A
-:1053000080FF2A80FEA933288D0129800108AA1177
-:105310002880000CAA0208881109880208AA1C2803
-:105320008C0828160458084C14DDA40AA70224414E
-:10533000162A30802B120407AA28580847B1338B4D
-:1053400013B4559A6004AC28B4662C56277B69E0E8
-:1053500016DDDB9412C050C0D017DD979D15D370B9
-:10536000D4102F60802E60829F169E178816728937
-:105370001A8D128C402A607F0DCC282B3A200CAA63
-:1053800028580835C0B10ABE372E35408F1772F93C
-:105390001A8D128C402A60810DCC282B3A200CAA41
-:1053A0002858082DC0B10ABE372E3542B233B44456
-:1053B000B1556952B6B466C0508F15B877D370B284
-:1053C000FF9F156EF899D10F6C1004C021D10F000A
-:1053D0006C1004270A001CDD761FDD871EDD8A1D88
-:1053E000DD731ADDB51BDDC3C02824B0006D2A753E
-:1053F000AA48288080C09164806100410415DD6E58
-:10540000C03125502E00361A0655010595390C5627
-:10541000110C66082962966E974D0D590A2992243F
-:1054200068900812DDA702420872993B2362951228
-:10543000DD6BCB349F300282020E4402C092993160
-:1054400094329233AD52246295C090244C1024665D
-:105450009524B0002924A0AA42292480B177B14420
-:1054600004044224B400D10FD10FD10F6C10041AE0
-:10547000DD4F2AA00058021C5BFFD5022A02033B25
-:10548000025BFFD11BDD4DC9A12CB102C0D40DCCF4
-:10549000020C0C4F2CB5020CE431D10FC0A00AE471
-:1054A0003118DD430002002F828219DD562EB10231
-:1054B00009FF022F86820EE431D10F006C1004C068
-:1054C0002002E43114DD3D16DD3A00020022628242
-:1054D000234102732F0603E431C020D10F19DD8769
-:1054E0001ADD862841020A2A010988012A668228D3
-:1054F000450208E43115DD7D12DD8225461DD10F00
-:105500006C1004292006289CF96480A02A9CFD6563
-:10551000A0968A288D262F0A087AD9042B221FC824
-:10552000BD2C206464C0812E22090EAE0C66E0788A
-:105530002B200C1EDD1F0CBC11AECC28C28619DD41
-:105540001D78F3026000AD09B90A2992A36890089A
-:105550002E220009EE0C65E09B29C2851FDD276421
-:1055600090929F90C0E41FDD349E9128200AC0E0F5
-:105570009E930F8802989288200F880298942F207B
-:10558000079A979D962F950A2E24072820062920F2
-:105590006468833328C28512DD0E288C20A2B22EC7
-:1055A00024CF28C685C020D10FC020D10F2A206A61
-:1055B0000111020A2A4165AF52DA20C0B05805D164
-:1055C00064AFE5C021D10F00649FC81FDCFB2D2014
-:1055D000168FF209DD0C00F10400DD1AADAD9D2936
-:1055E00012DCFC28C285A2B22E24CF288C2028C62B
-:1055F00085C020D10FC021D10F0000006C100426FF
-:105600000A001BDD4015DCEC28206517DCE9288C3E
-:10561000FE6480940C4D110DBD082CD2F52BD2F4F4
-:105620002ED2F77CB13DB4BB2BD6F47BE9052BD24F
-:10563000F62BD6F47CB92C2AD2F62AD6F52AD6F443
-:1056400006E4310002002872822AFAFF0041042990
-:105650000A012F510200991A0A9903098801287634
-:10566000820FE4312624652BD2F48E5A2CD2F5B069
-:10567000EE9E5A7BCB1629D2F62FD2F70CB80C0926
-:10568000FF0C08FF0C0F2F14C8F96000320BCA0C76
-:105690000A2A14CEA92B5102C0C20CBB020B0B4F1D
-:1056A0002B55020BE431D10F00DB30DA205BFF9485
-:1056B0001BDD1564AF5D0C4D11ADBD63FFA800008F
-:1056C00006E4310002002F728218DCD42E51020849
-:1056D000FF022F76820EE431D10F00006C1004C05F
-:1056E0003003E43116DCB315DCB40002002462821E
-:1056F00074472118DD05875A084801286682CD7352
-:1057000019DD030C2A11AA9922928329928472919D
-:10571000038220CC292B51020BE431C020D10F0091
-:105720001FDCFC2E51020FEE012E55020EE431B0AB
-:105730002DB17C9C5A12DCF708DD112D5619D10FC2
-:105740006C10061BDC9A1EDC9C22B0001ADCF36F86
-:1057500023721DDCDAC04818DCF21FDCF0DC10D547
-:10576000C083F000808600508A6D4A4F0F35110DBE
-:1057700034092440800B560A296294B1330E55092E
-:105780002251400F44110C440A874009A80C02889A
-:105790003622514107883608770CA89929669497D4
-:1057A00040296295874109A80C0288360788360887
-:1057B000770CA8992966959741030342B1380808E8
-:1057C0004298F0D10F1CDCD713DCD827B00023326D
-:1057D000B5647057C091C0D016DCD615DCD4C0407B
-:1057E0002AC00003884328C4006D793C004104B1FD
-:1057F0004400971A7780148E502FB2952DB695AF2E
-:10580000EE2EED2006EE369E5060001877A009833C
-:10581000509D5023B69560000223B295223D20068C
-:10582000223622B695B455B8BBD10F000388432861
-:10583000C400D10F6C1004C04004E43115DCBE007C
-:105840000200885013DCBDCB815BFFBD1CDCBC0CAF
-:105850002D11ADCC2BC2822AC28394507BAB142E67
-:10586000C28429C2850ABD0C0E990C0D990C092918
-:10587000146000050BA90C092914993015DC4F2A76
-:1058800051020AE4312A2CFC58004B2B32000AA2A8
-:10589000022BBCFF9B30CCB6C8A4D2A0D10F000015
-:1058A00004E4311EDC430002002DE2822FBAFF2CFB
-:1058B00051020FDD012DE6820CE431D10F00000012
-:1058C0006C1004D10F0000006C1004C020D10F0038
-:1058D0006C100413DC9BC0D103230923318DC0A0BD
-:1058E0006F340260008D19DC321BDC3317DC940C42
-:1058F0002811A8772672832572822CFAFF765147E9
-:1059000088502E7285255C0425768275E9052572FE
-:10591000842576827659292E72842E76822E76837D
-:105920000AE4310002002392820021042FB1020018
-:10593000D61A0C66030633012396820FE4312672D1
-:105940008325728260000200D8A07659220AE431D1
-:1059500000020023928200210400D21A2FB1020C0F
-:1059600022030232012296820FE431D280D10F004D
-:10597000D280D10FC020D10F6C1004DB30862015EF
-:10598000DC0B280A00282502DA2028B0002CB007FA
-:1059900005880A28824C2D0A010B8000DBA065AF28
-:1059A000E61ADC040A4A0A29A2A3C7BF769101D1EC
-:1059B0000F2BA6A3D10F00006C1004C0D1C7CF1BC2
-:1059C000DBFE19DBFB17DBF90C2811A87786758540
-:1059D00074C0A076516288508E77B455957475E97D
-:1059E00003857695747659278F769F759F740AE4A0
-:1059F00031000200239282B42E2FB10200E1040094
-:105A0000D61A0C66030633012396820FE43186759D
-:105A100083747639280AE4310002002E9282B4227F
-:105A200000210424B10200DF1A0CFF030FEE012E47
-:105A3000968204E431D280D10FD8A07651D6D2809C
-:105A4000D10F00006C1004290A801EDC001FDC004E
-:105A50001CDBD80C2B11ACBB2C2CFC2DB2850FCC35
-:105A6000029ED19CD0C051C07013DBFC14DBFB182C
-:105A7000DBF92AB285A82804240A234691A986B80E
-:105A8000AA2AB685A98827849F25649FD10F000084
-:105A90006C100419DC2C0C2A11A9A98990C48479F2
-:105AA0008B761BDC1AABAC2AC2832CC2847AC16809
-:105AB0008AA02BBC30D3A064A05E0B2B0A2CB2A30F
-:105AC00019DBE568C0071DDC20D30F7DC94AA92971
-:105AD000299D0129901F68913270A603D3A0CA9E08
-:105AE000689210C7AF2AB6A32A2CFC5BFFB3D23052
-:105AF000D10F000013DBC503A3018C311DDBB60CF5
-:105B00008C140DCC012CB6A363FFDC00C020D10F98
-:105B1000DA205BFFCCC020D10FC020D10F000000E5
-:105B20006C1004DB30C0D019DBA1DA202830002251
-:105B3000300708481209880A28824CDC200B8000B4
-:105B40001BDB9C0C4A11ABAA29A28409290B29A6AC
-:105B500084D10F006C1004C04118DB9517DB970C43
-:105B60002611A727277030A866256286007104A336
-:105B70005500441A75414822628415DBB802320B85
-:105B8000C922882117DB940884140744017549054C
-:105B9000C834C020D10FD10F0809471DDBEBC0B2BC
-:105BA0008E201FDB820E0E43AFEC2BC4A00FEE0A3B
-:105BB0002DE6242A6284C0200A990B296684D10F1D
-:105BC000C020D10F6C1004DB30C0D018DB78DA2095
-:105BD00025300022300708580A28824CDC200B8030
-:105BE000008931709E121BDB720C4A11ABAA29A2EC
-:105BF0008409290B29A684D10F09C95268532600AC
-:105C0000910418DB6DC0A12F811200AA1A0AFF02AD
-:105C10002F85121EDB670C4D11AEDD2CD2840C2CAF
-:105C20000B2CD684D10FC0811FDB64B89A0A0A47B7
-:105C30002EF11200A10400881A08EE022EF5121DA2
-:105C4000DB5C0C4C11ADCC2BC2840B2B0B2BC68414
-:105C5000D10F00006C1004DB30C0D019DB54DA2007
-:105C600028300022300709880A28824CDC200B806B
-:105C7000001CDB4F0C4B11ACBB2AB2840A2A0B2A46
-:105C8000B684D10F6C1004C04118DB4916DB4B0CF5
-:105C90002711A626266030A872252286006104A35B
-:105CA0005500441A75410822228402320BD10F009C
-:105CB000C020D10F6C100415DBA502491429561120
-:105CC0002452120208430F8811C073008104003669
-:105CD0001A008104C78F00771A087703074401066A
-:105CE0004402245612D10F006C10066E230260008D
-:105CF000AC6420A7C0A0851013DB7E16DB94C040E7
-:105D0000A6AA2BA2AE0B194164906668915D6892B9
-:105D10005268933C2AA2AA283C7F288C7F0A0A4D0D
-:105D20002980012880002AACF208881109880275B0
-:105D300089462B3D0129B0002BB0010899110B9920
-:105D4000027A9934B8332A2A00B1447249B160000A
-:105D50004A7FBF0715DB7F63FFB90000253AE86380
-:105D6000FFB10000253AE863FFA90000250A64633B
-:105D7000FFA1C05A63FF9C0000705F082534FF0537
-:105D80008C142C34FE70AF0B0A8D142E3D012AE4C6
-:105D9000012DE400DA405BFD5063FFA7D10FD10F66
-:105DA0006C10041ADB0519DB021CDB6A1BDB6BC001
-:105DB00080C07160000D00000022A430B1AA299CAF
-:105DC000107B915F26928679C2156E6262C0206D4B
-:105DD000080AB12200210400741A764BDB63FFEE3F
-:105DE0002292850D6311032514645FCFD650032DD5
-:105DF000436DD9039820B4220644146D492298209B
-:105E000098219822982398249825982698279828AE
-:105E10009829982A982B982C982D982E982F222CD8
-:105E20004063FF971EDAE327E68027E681D10F0063
-:105E3000C02063FF830000006C1004C062C04112E8
-:105E4000DADE1ADADA13DB452AA00023322D19DB59
-:105E50003F2BACFE2992AE6EA30260008E090E406D
-:105E60002D1AC2C2CD0EDC392C251664B0895BFF19
-:105E70009E15DB3B1ADAE52B3AE80A3A015805761B
-:105E80002B21160ABB28D3A02B560058058D8B500A
-:105E90000ABB082A0A0058058C15DB322D21022C7A
-:105EA0003AE80C3C2804DD022D25029C505805845C
-:105EB0008B50AABBC0A15805841CDB2B2D21020CE2
-:105EC0003C2806DD0213DB292D25029C3058057C79
-:105ED0008B30AABBC0A258057C2A2102C0B40BAAF1
-:105EE000020A0A4F2A2502580590D10F242423C301
-:105EF000CC2C251663FF760018DB211CDB1D19DB7B
-:105F00001E1BDB1C17DAF085202E0AFD1FDB1D2D62
-:105F1000202E24F47A24F47E24F4820EDD0124F46D
-:105F2000862E0AF707552806DD02C0750EDD01052D
-:105F30000506AB5BA959C0E8AC5C24C4AB0EDD021E
-:105F400027C4AC2E0ADFA85527B4EC0EDD0124B41B
-:105F5000EBC2E027942C0EDD0224942B2E0A800D38
-:105F60000D4627546C24546B0EDD022D242E63FE47
-:105F7000FC0000006C10042A0A302B0A035BFF4D62
-:105F800012DAF3C390292616C3A1C0B3C08A28260B
-:105F9000175BFF48C03CC3B12B26161ADA872AA02C
-:105FA0002023261764A079C3A2C0B15BFF42C3A21D
-:105FB000C0B15BFF40C3C22C2616C2AFC0B12326BE
-:105FC000175BFF3CC28F282616C0FE2F2617C2E2A1
-:105FD0002E26162A0AA1C0B1C0D82D26175BFF3580
-:105FE0002A0AA12A2616C3A6C0B3C1922926175B86
-:105FF000FF31C3C62C2616C1B32A0AA22B2617C00E
-:10600000B35BFF2C290AA2292616C185282617C2B0
-:10601000FB2F2616C0E72E26171DDADA2D2610D103
-:106020000FC3A2C0B35BFF2363FF82006C10041C8C
-:10603000DAA41BDA9118DAD417DAD516DAD515DA1C
-:10604000D5C0E0C0D414DAA01FDA5CC0288FF06D90
-:106050002A36DAC0D9C07C5B020FC90C1CDA9A0C54
-:106060009C28A8C3A6C22A36802A2584A4C2A7CC0D
-:106070002D248C2B248A2B24872E248BB1BB2E36E7
-:106080009F2C369E2C369DB1AC1CDA7B1BDAC3C02C
-:10609000286D2A33DAC0D9C07C5B020FC90C1CDA28
-:1060A000890C9C28A8C3A6C22A36802B2584A4C2AA
-:1060B000B1BBA7CC2D248C2E248B2A248A2E369F6C
-:1060C0002C369E2C369DB1ACC07919DA791BDAB525
-:1060D00013DAB31ADAB318DAB414DA7A16DAB404C3
-:1060E000F42812DAB304660C040506A252A858AAD2
-:1060F0005AA3539B3029A50027848AC091C0A52AA2
-:10610000848C29848B17DAAC18DAABA75726361D96
-:1061100026361E2E361F16DAA913DAA9A655043321
-:106120000C2826C82E75002D54AC2E54AB2E54AA24
-:106130002326E62326E52E26E7D10F006C10061352
-:10614000DA8717DA8224723D2232937F2F0B6D0893
-:10615000052832937F8F0263FFF3C0C4C0B01ADA00
-:1061600016C051D94004593929A4206E44020BB5F8
-:1061700002C3281EDA11DDB025E422052D392DE4F5
-:1061800021C0501EDA9019DA8018DA8016DA821DE2
-:10619000DA8E94102A724517DA4C6DA94BD450B39D
-:1061A000557A5B17DF50756B071FDA038FF00F5FAF
-:1061B0000C12DA4402F228AE2222D681D54013DA3C
-:1061C00041746B0715D9FD855005450C035328B163
-:1061D00045A73FA832A93322369D22369E24368019
-:1061E0002B369F2BF48B2CF48C14DA5C24424DC09C
-:1061F00030041414C84C6D0806B133041414C8429A
-:1062000063FFF20015D9EAC4400031041AD9EBC08B
-:10621000D193A200DD1AC138B0DD9DA318DA502B4E
-:10622000824D29824E29A51C2882537A871E2C5420
-:10623000008E106FE45D12D9E02F211D23211C2F49
-:10624000251B04330C23251C23251AD10FC06218EB
-:10625000DA3F88807E87D989102654006F94191BF5
-:10626000D9D62AB11C0A1A1404AA0C2AB51C2AB5BC
-:106270001D2AB51A2AB51BD10F1BD9CF2AB11C0A6A
-:106280001A1403AA0C2AB51C2AB51D2AB51A2AB558
-:106290001BD10F001CD9C92BC11D2DC11C2BC51B27
-:1062A00003DD0C2DC51C2DC51AD10F006C1006196D
-:1062B000D9C214DA2612DA2915DA44C73FC0E02E13
-:1062C00056A82E56A92E56AA2E56AB23262918D9E3
-:1062D000EADB101CDA3EC0D42A42452D16019C1080
-:1062E00000B0890A880C2896005BFF942B22E318E3
-:1062F000D9B20B5B149B842A22E48B84B1AA0A5A7C
-:10630000140BAA0C9A852922E509591499862F2283
-:10631000CD0F5F149F875BFF455BFF1623463BC194
-:10632000B01DD9A51CDA032AD1022C463A0BAA02C9
-:106330000A0A4F2AD50258047C5BFEBF5BFE98C058
-:1063400050C0B016D99B14D9A317DA12C0C0C73EEB
-:1063500093122C262DC0306000430000007F9F0F59
-:10636000B155091914659FF4C0500AA9027FA7EF1F
-:1063700018D98FDA5008580A28822C2B0A000B8073
-:1063800000005104D2A0C091C7AF00991A0A990326
-:106390009912CE33642067D3202B200795138C12DB
-:1063A0002A62827CA85F18D98108580A28822CDAD0
-:1063B000500B8000D2A0643FDA8A310A8A1404AA02
-:1063C00001C8298B210B8B1404BB017BA945DDA0DF
-:1063D0007A7B081DD9792DD2000DAD0CDB3019D98F
-:1063E000731AD9B82812030ADA28088C021DD9F5C5
-:1063F00009880A28823C0DAA080B8000652F97D3D4
-:1064000020C0B063FF97CB53B1550050040A09195F
-:1064100063FF4900DAB07B7B071AD9678AA00ABA02
-:106420000C1BD9A88C310BAB280C8A141CD9E6ACF8
-:10643000BB1CD9E504AA012BC68163FF907FA7C7C7
-:1064400063FF62006C100427221EC08008E4311B29
-:10645000D9580002002AB28219D958003104C0610B
-:1064600000661A2991020A6A022AB68209E43115E5
-:10647000D9B30C3811A8532832822432842A8CFCD8
-:106480007841102921022A368297A009690229251C
-:1064900002D10F002B21022C32850B6B022CCCFC7D
-:1064A0002C368297C02B2502D10F00006C1004C03F
-:1064B000E71DD93B1CD93D0D4911D7208B228A20DD
-:1064C0000B4B0BD2A007A80C9B72288CF4C8346F1E
-:1064D0008E026000A21FD933A298AF7B78B334C973
-:1064E0003DC081C0F0028F380F0F42C9FA2CD67E12
-:1064F000D5206D4A0500308800508C8870089808B7
-:1065000078B16CD2A09870D10FC0F0038F387FE0C3
-:10651000DE63FFD8027B0CAFBB0B990C643046D80E
-:1065200030C0F1C05002F5380505426450792CD6D0
-:106530007E0B36122F6C100F4F366DFA05008088D7
-:1065400000208C06440CC081250A0003B208237C7D
-:106550000C0385380505426450592CD67E6D4A05DA
-:1065600000208800308CD2A0A798BC889870D10FEA
-:10657000D2A0BC799970D10FD2302BAD08C0F1C038
-:10658000500BF538050542CB552CD67E083F14C17B
-:10659000600F660C064636D30F6D6A050020880032
-:1065A000B08C827063FF2D00C05003F53875E08019
-:1065B00063FF7A00C06002863876E0A063FF9A002D
-:1065C000C05003F53875E0C363FFBD006C1004D6FE
-:1065D0002068520F695324DA20DB30DC405800F089
-:1065E000D2A0D10FDA20DB30DC405800ED9A242411
-:1065F000240EC02122640FC020D10F00B83BB04C44
-:106600002A2C7489242D200E2E200FA4DDB1EE2E0D
-:10661000240FB0DD2D240E2890072D9003A488B000
-:1066200088B1DD2D94032894075BFFA069511DC03C
-:10663000E082242A600F18D9662A240329600E8F6D
-:106640002029240708FF029F209E64D10FC020D17B
-:106650000F0000006C1004942319D95EC0B3083AEF
-:10666000110BAA02992019D8D29A2116D8D0C0505D
-:1066700028929D2564A2288C1828969DD10F000091
-:106680006C1004282066C038232406B788282466A6
-:10669000D10F00006C1006035A0C0D36110D5C1161
-:1066A000D8208B2282210CBB0C06550F9B82023214
-:1066B0000B928113D8BCD920A38F6450531CD8B837
-:1066C000C0D71BD8B9A256C0E1290A0004E938098D
-:1066D000094276F34A044302C99E2BC67E6DAA0581
-:1066E00000208800308C8981A95909FA0C64A079AE
-:1066F00099818A82C8ADD290D10FC06002E6387607
-:10670000D0DA63FFD4C020BC89998199809282D16C
-:106710000F7F2304292DF8998165BFD963FFE50018
-:10672000028F0CA3FF0F3312931003AA0CD340CB9C
-:106730009E2BC67E86106D6A0500208800308CBCBA
-:1067400082290A0004F308240A010349380909428E
-:10675000CA982BC67E6DAA0500208800308C0F5980
-:106760000CA989BC99998163FF87BC89998163FFD2
-:1067700080C06002E63876D0BA63FFB4C0700247CA
-:106780003877D0D063FFCA006C100414D895C1527A
-:10679000A424CA3028221D73811B292102CD952AE9
-:1067A000300075A912DA20033B022C30072D0A02B3
-:1067B0005801C2653FDDD10F2B300703BB0BDAB0A8
-:1067C00074B3022ABDF8D3A063FFC6006C1004297D
-:1067D0002006C0706E9741292102C08F2A2014C064
-:1067E000B62B240606AA022A241479800227250241
-:1067F0002A221E2C221D7AC10EC8ABDA20DB302CD7
-:106800000A00033D025BF8146450752D21020D0D42
-:106810004CC9D3C020D10F00002E9CFB64E0822F16
-:1068200021020F0F4C65F0911AD8621CD86029A282
-:106830009EC08A798B5D2BC22668B0048D207BD9DF
-:106840005229A29DC0F364904A97901DD8732E21BF
-:10685000049D9608EE110FEE029E979E9118D86F38
-:10686000C0E527C4A22E24062BA29D2F21022BBCFB
-:106870003008FF022F25022BA69DC020D10F00005B
-:10688000002F300068F938DA20DB30DC4058004453
-:1068900063FF7700022A022B0A065800D3220A005F
-:1068A000D10F655010283000688924022A02033B6A
-:1068B00002DC4058003BC020D10FD270D10F000045
-:1068C0002A2C74033B02044C025BFEF863FF3B007E
-:1068D000DB30DC402A2C745BFEF5C020D10F0000B9
-:1068E0006C1004C83F89268829A399992609880C29
-:1068F000080848282525CC52C020D10FDB402A2C7F
-:10690000745BF93DD2A0D10F6C1004D820D730822F
-:10691000220D451105220C928264207407420B134C
-:10692000D821D420A383732302242DF885807451A9
-:106930004CBC82C0906D081600408800708C77397E
-:1069400003D720C0918680743901D420746102631A
-:10695000FFE2CA98C097C0411BD8A0C0A00B8B0C07
-:106960000B4A380A0A42C9AA1DD80E1CD80F2CD6C9
-:106970007EC140D30F6D4A0500208800308C97807F
-:10698000D270D10FBC8FC0E00F4E387E90E263FF13
-:10699000D6BC8292819280C0209282D10F000000EA
-:1069A0006C1006C0D71CD7FE1BD8000D4911D7208C
-:1069B0002E221F28221D0E4E0BD280078A0C2E7607
-:1069C0001F2AAC80C8346FAE026000CB2F0A801A39
-:1069D000D804A29EAA7A7EA33FC93FC0E1C050025C
-:1069E000E538050542CA552BC67EDB20D30F6D4A1C
-:1069F0000500308800B08C2E721DAE9E0EA50C6472
-:106A00005086D2802E761DC091298403D10FC050AC
-:106A100003E53875D0D363FFCD15D7F1027E0CA501
-:106A2000EE643051C0A1250A0002A538033A0205E0
-:106A300005426450922BC67E0E35129510255C10CF
-:106A4000054536D30F6D5A0500A08800208CC0A1E3
-:106A5000A3E2C05023FA8003730C03A538AF73057B
-:106A600005426450722BC67E851005450C6D5A0593
-:106A700000208800308CD280C0A10E9B0CAB7BAF75
-:106A8000BB2B761D2A8403D10FD280C0C1AF7D2DD0
-:106A9000761D2C8403D10F00D2302E8D08C0F1C09A
-:106AA000500EF538050542CB592BC67E0A3F14C15E
-:106AB000600F660C064636D30F6D6A05002088000D
-:106AC000E08C22721D63FF03C061C05003653875FE
-:106AD000D80263FF6263FF5CC05002A53875D0879F
-:106AE00063FF8100C06003F63876D0BF63FFB90052
-:106AF0006C10042A201529201614D7AF0A990CCB44
-:106B00009D2E200B04ED092BD11C8F2809BC36AC1F
-:106B1000AA0CBB0C2BD51C0A0A472A2415CAAF8B1A
-:106B2000438942B0A800910400881AA8FF0FBB0255
-:106B30009B278F260FB80C783B1AC020D10F00007E
-:106B4000292102C0A20A9902292502C021D10F00E1
-:106B50008B2763FFDC2BD11C0CAA0C0A0A472A24C2
-:106B600015ACBB2BD51CC9AE8B438C288F42B0AD66
-:106B700000F10400DD1AADCC0CBB029B27DA20B774
-:106B8000EB580019C021D10F9F2763FFEF000000D1
-:106B90006C100428203C64304705306000073E013B
-:106BA000053EB156076539054928C77FA933030655
-:106BB00041076603B166060641A6337E871E222181
-:106BC00025291AFC732B1502380C09816000063E3A
-:106BD00001023EB12406423903220AD10FD230D13C
-:106BE0000FC05163FFC000006C100427221EC0803C
-:106BF00008E4311DD76F0002002CD2821BD76F0032
-:106C00003104C06100661A2BB1020C6C022CD682D2
-:106C10000BE43119D7F20C3A11AA932832829780EB
-:106C2000253282243284B45525368275410A2921C1
-:106C300002096902292502D10F2A21022B32830A77
-:106C40006A022B36822A2502D10F00006C1004192B
-:106C5000D76327221EC08009770208E4311DD7546C
-:106C60000002002CD2821BD754003104C0610066A0
-:106C70001A2BB1020C6C022CD6820BE43119D7D737
-:106C80000C3A11AA932832829780253282243284CA
-:106C9000B45525368275410B2A21020A6A022A253B
-:106CA00002D10F002B21022C32830B6B022C368277
-:106CB0002B2502D10F0000006C10041BD73D0C2ABD
-:106CC00011ABAA29A286B438798B221BD73A19D7DF
-:106CD000610B2B0A2BB2A309290868B00274B90D05
-:106CE000299D0129901F6E920822A285D10FC020F4
-:106CF000D10FC892C020D10FDA205BEF35C020D170
-:106D00000F0000006C100414D72A28429E19D727C0
-:106D10006F88026000BA2992266890078A2009AA23
-:106D20000C65A0AC2A429DC0DC64A0A42B200C19E9
-:106D3000D7210CBC11A4CC2EC28609B90A7ED3027D
-:106D400060009A2992A36890078D2009DD0C65D018
-:106D50008C25C2856450862D2104C0306ED80D2C40
-:106D60002066B8CC0C0C472C246665C07B1CD79CD5
-:106D700018D7281AD71E19D72F1DD724C0E49E5123
-:106D80009D508F209357935599539A569A5408FFC4
-:106D9000021AD73A9F5288269F5A9E599D58935E51
-:106DA0009C5D935C9A5B080848058811985FC0D881
-:106DB0001FD7080CB911A499289285AFBF23F4CF2F
-:106DC000288C402896858E262D24069E29C020D109
-:106DD0000FCA33DA20C0B65BFF84C72FD10FC93A80
-:106DE000DA205BFF81C72FD10FDBD05BFE1A232493
-:106DF000662B200C63FF7500C72FD10FC72FD10F53
-:106E00006C1004C85B29200668941C689607C02093
-:106E1000D10FC020D10FDA20DB30DC40DD502E0A4C
-:106E2000005BFE6AD2A0D10F2E200C18D6E10CEF29
-:106E300011A8FF29F286C088798B751AD6DE0AEA76
-:106E40000A2AA2A368A0048B207AB96423F285647D
-:106E5000305E1CD6E82A0A802D2068292067282168
-:106E6000040B991104881109880208DD02C09428D6
-:106E70004A1008DD0218D6E0993198308B2B9A37EA
-:106E80009D340CBB029B32C0C09C359C362A2C74AE
-:106E9000DB40C0D318D6CF29F285A8EE299C202C40
-:106EA000E4CF29F6852D2406DD405BFDFAD2A0D182
-:106EB0000FDA20DBE05BFF4CC020D10F6C100AD64C
-:106EC000302A2006941128ACF86583872B2122C034
-:106ED000F22A21246550082AAC010A0A4F2A2524E7
-:106EE0007ABB0260037F2C21020C0C4C65C3192E67
-:106EF00022158D32C0910EDD0C65D39088381ED6D8
-:106F0000AC64836B8C37C0B8C0960CB9399914B493
-:106F10009A9A120D991199138F6718D6A7C9FB2851
-:106F200080217F83168B142C22002A200C5BFF62A9
-:106F3000D4A064A3A88F6760002800002B200C89D0
-:106F4000120CBA11AEAA2CA2861DD69A7C9B3E0DBD
-:106F5000BD0A2DD2A368D00488207D893024A28563
-:106F600064436427212E07F73607F90C6F9D01D77C
-:106F7000F0DA20DB70C1C42D211F5BFF0589268854
-:106F800027DDA009880C7A8B179A10600006C04094
-:106F900063FFCC0000DA208B105BFED58D1065A25C
-:106FA00067C0E09E488C649C498B658A669B4A9AC0
-:106FB0004B97458F677F7302600120CD529D10DA99
-:106FC00020DB302C12015BFE768D10C051D6A08FD5
-:106FD000A7C0C08A68974D9A4C8869896A984E996B
-:106FE0004F8E6A8A69AE7E77EB01B1AA9E6A9A6972
-:106FF0008B60C0A00B8E1477B701C0A1C091C08474
-:1070000093159D179516C0D025203CC03008580117
-:10701000089338C082083310085B010535400B9D8A
-:107020003807DD100BAB100E19402A211F079910ED
-:1070300003DD020DBB020553100933020A55112965
-:1070400021250A2A140929140499110A99020933DD
-:10705000028A2B2921040BAA021BD6E208991109E6
-:1070600055020855020BAA029A40892088140899F3
-:107070001109880219D6631DD6DC09880298418B54
-:107080002A9346954783150DBB0285168D179B44A1
-:107090008A658966AACAA97C77CB01B1AA07FB0CCD
-:1070A0009C669A6588268E29AD87972607EE0C0E7A
-:1070B0000E482E25259B672B200C87131ED63D0CD2
-:1070C000B911AE99289285A78828968517D641C010
-:1070D00090A7BB29B4CF871863FE3C008C60C0E04A
-:1070E000C091C0F0C034C0B82A210428203C08AAAE
-:1070F000110B8B01038301039F380B9B39C03208AE
-:10710000FF10038801089E380C881407EE100FEE5C
-:107110000203880108983905BF1029211F0ABB11F5
-:1071200007881008FF020BAA0218D6350929140394
-:10713000AA022B212583200B2B1404BB1108331129
-:107140000FBB020B99028B148F2A0B3302083302F8
-:107150008B2B6470868868974D984C8769886A93F2
-:10716000419946974E984FC07077C701C0719A47B2
-:1071700018D69E0B7C100CEC0208F802984418D626
-:107180009B0CBC0208CC029C402A200C295CFEC04F
-:10719000801FD6071CD60F0CAE112B2124ACAAAF32
-:1071A000EEB0BB8F132CE28528A4CFAFCC2CE685A4
-:1071B0002A22152B2524B1AA2A26156490DBC9D2D0
-:1071C0008F262E22090DFF082F26060FEE0C0E0E1D
-:1071D000482E25256550E4C020D10F00C070934192
-:1071E0009F4499469A4777C70A1CD5F32CC022C002
-:1071F000810C87381CD67F0B781008E80208B8028B
-:107200000C8802984063FF8000CC57DA20DB608C4A
-:10721000115BFDE3292102689806689403C020D120
-:107220000F2B221EC0A029221D2A25027B9901C0F6
-:10723000B064BFE813D5DE2CB00728B000DA200315
-:10724000880A28824CC0D10B8000DBA065AFE763C1
-:10725000FFCA000068A779DA20DB30DC40DD505B34
-:10726000FEE8D2A0D10FC16DC19D29252C6000047C
-:1072700029252CD6902624672F2468DA20DB308C31
-:1072800011DD502E0A805BFD51D2A0D10FC168C123
-:10729000A82A252C63FFDD000000C8DF8C268B297F
-:1072A000ADCC9C260CBB0C0B0B482B25252A2C7433
-:1072B000DB602C12015BFD94D2A0D10F2A2C748BC1
-:1072C000115BF6CDD2A0D10FDA205BFE4763FF3809
-:1072D00000DA20C0B15BFE8B65AF2D63FBEDDA20D9
-:1072E0002B200C5BFE5A63FF1F00000012D6428267
-:1072F00020028257C82163FFFC12D63E03E8300407
-:10730000EE3005B13093209421952263FFFC0000FC
-:1073100010D63A910092019302940311D611821073
-:1073200001EA30A21101F031C04004E4160002006D
-:1073300011D6338210234A00032202921011D5FD88
-:10734000C021921004E43184038302820181000091
-:10735000D23001230000000010D62A910092019340
-:1073600002940311D600821001EA30A21101F1311A
-:10737000C04004E41600020011D621821013D5A7E4
-:10738000032202921004E43184038302820181000B
-:1073900000D330013300000010D61B91008101653D
-:1073A000104981026510448103CF1F92019302941A
-:1073B0000311D5EE821001EA30A21101F231C04072
-:1073C00004E41600020011D60D821013D58E03229C
-:1073D00002921004E431840383028201C0109103FD
-:1073E00091029101810000D43001430012D5BDC04B
-:1073F0003028374028374428374828374C233D0168
-:107400007233ED03020063FFFC00000010D5FF9112
-:107410000092019302940311D5FD8210921011D5B0
-:10742000AF8310032202921011D5FA12D5C1921027
-:10743000C04004E41600020011D5F1821013D5A853
-:10744000032202921004E43184038302820181004A
-:1074500000D53001530000006C10026E322FD62090
-:10746000056F04043F04745B2A05440C00410400CA
-:10747000331A220A006D490D73630403660CB122AE
-:107480000F2211031314736302222C01D10FC83B86
-:10749000D10F000073630CC021D10F000000000069
-:1074A00044495630C020D10F6C10020040046B4C90
-:1074B00007032318020219D10F020319C020D10FAC
-:1074C0006C100202EA30D10F6C1002CC2503F031AF
-:1074D00060000F006F220503F1316000056F230586
-:1074E00003F231000200D10F6C1002CC2502F03003
-:1074F000D10F00006F220402F130D10F6F2304027C
-:10750000F230D10FC020D10F6C1002220A20230AC2
-:10751000006D280E28374028374428374828374C34
-:10752000233D01030200D10F6C100202E431D10FA0
-:107530000A0000004368656C73696F204657204459
-:10754000454255473D3020284275696C7420576587
-:1075500064204F63742020382031353A35303A3575
-:1075600030205044542032303038206F6E20636C0D
-:10757000656F70617472613A2F686F6D652F666513
-:107580006C69782F772F66775F372E30292C20563D
-:10759000657273696F6E2054337878203030372EDF
-:1075A00030312E3030202D203130303730313030F6
-:0875B000100701006F4EF8BB4B
-:00000001FF
diff --git a/firmware/cxgb3/t3fw-7.4.0.bin.ihex b/firmware/cxgb3/t3fw-7.4.0.bin.ihex
new file mode 100644 (file)
index 0000000..38dda94
--- /dev/null
@@ -0,0 +1,1917 @@
+:1000000060007400200380002003700000001000D6
+:1000100000002000E100028400070000E1000288E7
+:1000200000010000E0000000E00000A0010000006E
+:1000300044444440E3000183200200002001E0002A
+:100040002001FF101FFFD0001FFFC000E300043C91
+:100050000200000020006B741FFFC29020006BBCE8
+:100060001FFFC29420006BFC1FFFC29820006C7021
+:100070001FFFC29C200003C0C00000E43100EA3131
+:1000800000A13100A03103020002ED306E2A05000C
+:10009000ED3100020002160012FFDBC03014FFDA5F
+:1000A000D30FD30FD30F03431F244C107249F0D347
+:1000B0000FD30FD30F12FFD5230A00240A00D30F4A
+:1000C000D30FD30F03431F244C107249F0D30FD327
+:1000D0000FD30F14FFCE03421F14FFCB03421F1296
+:1000E000FFCCC0302D37302D37342D37382D373CED
+:1000F000233D017233ED00020012FFC4C0302F37E0
+:10010000002F37102F37202F3730233D017233ED6A
+:1001100000020012FFBEC0302737002737102737F4
+:1001200020273730233D017233ED03020012FFB95F
+:1001300013FFBA0C0200932012FFB913FFB90C028F
+:1001400000932012FFB8C0319320822012FFB71312
+:10015000FFB7932012FFB715FFB316FFB6C030D715
+:100160002005660160001B00000000000000000088
+:10017000043605000200D30FD30F05330C6E3B1479
+:100180000747140704437631E604360505330C6F40
+:100190003BED00020012FFA615FFA3230A00D720A3
+:1001A000070443043E0505330C0747146F3BF00377
+:1001B000020012FFA1C03014FFA1D30FD30FD30F41
+:1001C0009340B4447249F2D30FD30FD30F14FF9B63
+:1001D000834014FF9B834012FF9B230A0014FF9A65
+:1001E000D30FD30FD30F9340B4447249F2D30FD33C
+:1001F0000FD30F14FF95834012FF95C92F832084DE
+:10020000218522BC22743B0F8650B4559630B433FE
+:100210007433F463FFE60000653FE1655FDE12FFC3
+:100220007C230A0028374028374428374828374C91
+:10023000233D017233ED03020000020012FF7AC079
+:1002400032032E0503020012FF7813FF819320C0B2
+:1002500011014931004831010200C00014FF7E0441
+:10026000D23115FF7D945014FF7D04D33115FF7CEE
+:10027000945014FF7C04D43115FF7C24560014FFE5
+:100280007B04D53115FF7B24560010FF7A03000054
+:10029000000000000000000000000000000000005E
+:1002A000000000000000000000000000000000004E
+:1002B000000000000000000000000000000000003E
+:1002C000000000000000000000000000000000002E
+:1002D000000000000000000000000000000000001E
+:1002E000000000000000000000000000000000000E
+:1002F00000000000000000000000000000000000FE
+:1003000000000000000000000000000000000000ED
+:1003100000000000000000000000000000000000DD
+:1003200000000000000000000000000000000000CD
+:1003300000000000000000000000000000000000BD
+:1003400000000000000000000000000000000000AD
+:10035000000000000000000000000000000000009D
+:10036000000000000000000000000000000000008D
+:10037000000000000000000000000000000000007D
+:10038000000000000000000000000000000000006D
+:10039000000000000000000000000000000000005D
+:1003A000000000000000000000000000000000004D
+:1003B000000000000000000000000000000000003D
+:1003C000000000000000000000000000000000002D
+:1003D000000000000000000000000000000000001D
+:1003E000000000000000000000000000000000000D
+:1003F00000000000000000000000000000000000FD
+:1004000000000000000000000000000000000000EC
+:1004100000000000000000000000000000000000DC
+:1004200063FFFC000000000000000000000000006E
+:100430000000000000000000000000001FFC0000A1
+:100440001FFC0000E30005C81FFC00001FFC0000AB
+:10045000E30005C81FFC00001FFC0000E30005C806
+:100460001FFFC0001FFFC000E30005C81FFFC00042
+:100470001FFFC018E30005C81FFFC0181FFFC018EA
+:10048000E30005E01FFFC0181FFFC290E30005E076
+:100490001FFFC2901FFFC290E30008581FFFC290C9
+:1004A0001FFFC58CE3000858200000002000016AEF
+:1004B000E3000B542000018020000180E3000CC009
+:1004C0002000020020000203E3000CC02000021CF8
+:1004D00020000220E3000CC420000220200002269D
+:1004E000E3000CC82000023C20000240E3000CD0D6
+:1004F0002000024020000249E3000CD42000024CFE
+:1005000020000250E3000CE02000025020000259BD
+:10051000E3000CE42000025C20000260E3000CF029
+:100520002000026020000269E3000CF42000026C4D
+:1005300020000270E3000D0020000270200002790C
+:10054000E3000D042000028C2000028CE3000D105B
+:100550002000029020000293E3000D10200002AC66
+:10056000200002B0E3000D14200002D0200002F2AF
+:10057000E3000D18200003B0200003B0E3000D3CA1
+:10058000200003B0200003B0E3000D3C200003B0C6
+:10059000200003B0E3000D3C200003B0200003B0B6
+:1005A000E3000D3C200003B020006D94E3000D3CFF
+:1005B00020006D9420006D94E3007720000000007F
+:1005C00000000000000000001FFC00001FFC0000F5
+:1005D0001FFFC5901FFFC67020006D9820006D980A
+:1005E000DEFFFE000000080CDEADBEEF1FFFC2A064
+:1005F0001FFCFE001FFFC0941FFFC5C0300000009D
+:10060000003FFFFF8040000010000000080FFFFFC8
+:100610001FFFC26D000FFFFF804FFFFF8000000033
+:1006200000000880B000000560500000600000007D
+:1006300040000011350000004100000010000001E2
+:100640002000000000001000400000000500000035
+:1006500080000019040000000000080010000005E0
+:10066000806000007000000020000009001FF800FA
+:100670008000001EA0000000F800000007FFFFFF40
+:100680000800000018000000010080014200000086
+:100690001FFFC21D1FFFC0DC000100806040000082
+:1006A0001A0000000C0000001000000A00003000DA
+:1006B000600008008000001C000100008000001A9B
+:1006C00080000018FC0000008000000100004000D5
+:1006D000030000008000040050000003FFFFBFFF84
+:1006E0001FFFC3D400000FFFFFFFF000000016D073
+:1006F0000000FFF7A50000001FFFC4B01FFFC4618A
+:100700000001000800000B20202FFF801FFFC455B0
+:1007100000002C00FFFEFFF800FFFFFF1FFFC57861
+:1007200000002000FFFFDFFF0000FFEF01001100CD
+:100730001FFFC3D21FFFC590FFFFEFFF0000FFFBAD
+:100740001FFFC6301FFFBEA0FFFFF7FF1FFFC064E3
+:100750000000FFFD1FFFC6200001FBD01FFFC5B03A
+:100760001FFFC6601FFFC591E0FFFE001FFFC5A071
+:10077000000080001FFFC53C1FFFC5B41FFFC068FD
+:100780001FFFC4D01FFCFFD8000100817FFFFFFFC7
+:10079000E1000600000027101FFCFE301FFCFE7069
+:1007A000E10002001FFFC5381FFFC5500003D090B5
+:1007B0001FFFC5642B5063802B5079802B50908095
+:1007C0002B50A6801FFFC4690100110F202FFE00CF
+:1007D00020300080202FFF000000FFFF0001FFF805
+:1007E0002B50B2002B50B208000100102B50B180EA
+:1007F0002B50B2802B50BA00000100112B50BD28A5
+:100800002B50BC802B50BDA020300000DFFFFE002D
+:100810005000000200C0000002000000FFFFF7F4DB
+:100820001FFFC06C000FF800044000000010000023
+:100830000C4000001C400000E00000A01FFFC5406D
+:100840001FFD00081FFFC5541FFFC5681FFFC57CA3
+:10085000E1000690E10006EC00000000000000004E
+:100860000000000000000000010000000000000087
+:100870000000000000000000201000402010004098
+:100880002010004020140080200C0000200C0000EC
+:10089000200C000020100040201400802014008054
+:1008A00020140080201800C0201C0100201C010022
+:1008B000201C010020200140201800C0201800C08A
+:1008C000201800C0201C0100201800C0201800C003
+:1008D000201800C0201C01002020014020200140E1
+:1008E00020200140202009402020094020200940EC
+:1008F0002020094020240980FFFFFFFFFFFFFFFFAA
+:10090000FFFFFFFF000000000000000000000000EB
+:100910000000000000000000200054902000536000
+:1009200020005490200054902000529C2000529CA3
+:100930002000529C200050DC200050DC200050D4CD
+:100940002000504020004EE820004CC820004A9C67
+:100950000000000000000000200054602000532C24
+:10096000200053D0200053D0200051842000518417
+:10097000200051842000518420005184200050CC5C
+:100980002000518420004E0820004C7820004A4866
+:10099000000000000000000020000BE820003A30BA
+:1009A000200004C02000463C20000BE0200041480D
+:1009B000200003F0200045FC20004A2420003E5483
+:1009C00020003D70200039AC2000383C200035ACC0
+:1009D0002000310C20003BCC20002D6C2000280092
+:1009E000200067182000238C2000206C2000201895
+:1009F00020001D04200018182000154820000E2C8F
+:100A000020000C2C2000110C200012F82000434084
+:100A100020003E0820000BF0200004C00000000071
+:100A200000000000000000000000000000000000C6
+:100A300000000000000000000000000000000000B6
+:100A400000000000000000000000000000000000A6
+:100A50000000000000000000000000000000000096
+:100A60000000000000000000000000000000000086
+:100A70000000000000000000000000000000000076
+:100A80000000000000000000000000000000000066
+:100A900000000000000000000000000032640000C0
+:100AA0000000000032640000640064006400640020
+:100AB00064006400640064000000000000000000A6
+:100AC0000000000000000000000000000000000026
+:100AD0000000000000000000000000000000000016
+:100AE0000000000000000000000000000000000006
+:100AF00000000000000000000000000000000000F6
+:100B000000001000000000000000000000000000D5
+:100B100000000000000000000000100000000000C5
+:100B200000000000000000000000000000432380DF
+:100B300000000000000000000000000000000000B5
+:100B400000000000000000000000000000000000A5
+:100B500000000000005C94015D94025E94035F94C9
+:100B60000043000000000000000000000000000042
+:100B70000000000000000000000000000000000075
+:100B80000000000000000000000000000000000065
+:100B900000000000005C90015D90025E90035F9099
+:100BA00000530000000000000000000000000000F2
+:100BB0000000000000000000000000000000000035
+:100BC0000000000000000000000000000000000025
+:100BD00000000000009C94001D90019D94029E94D2
+:100BE000039F94040894050994060A94070B940043
+:100BF00043000000000000000000000000000000B2
+:100C000000000000000000000000000000000000E4
+:100C100000000000009C90019D90029E90071D9096
+:100C2000039F90047890057990067A90077B900056
+:100C30005300000000000000000000000000000061
+:100C400000000000000000000000000000000000A4
+:100C50000000000000DC94001D9001DD9402DE9491
+:100C600003DF94040494050594060694070794088A
+:100C700008940909940A0A940B0B9400430000009D
+:100C80000000000000000000000000000000000064
+:100C90000000000000DC9001DD9002DE900B1D9052
+:100CA00003DF9004B49005B59006B69007B790089E
+:100CB000B89009B9900ABA900BBB9000530000009D
+:100CC00063FFFC0020006B5010FFFF0A00000000D3
+:100CD00020006B7400D23110FFFE0A0000000000FB
+:100CE00020006BBC00D33110FFFE0A0000000000A2
+:100CF00020006BFC00D43110FFFE0A000000000051
+:100D000020006C7000D53110FFFE0A0000000000CA
+:100D100063FFFC00E00000A012FFF7822002825770
+:100D2000C82163FFFC12FFF303E83004EE3005C076
+:100D30003093209421952263FFFC00001FFFD00018
+:100D4000000400201FFFC5901FFFC670200A00117D
+:100D5000FFFB13FFFB03E63101020016FFFA17FF4A
+:100D6000FAD30F776B069060B4667763F85415B5C5
+:100D7000541A610F140063FFF90000006C1004C0E6
+:100D800020D10F006C1004C0C71AEF06D830BC2B5E
+:100D9000D72085720D4211837105450B9572023380
+:100DA0000C2376017B3B04233D089371A32D12EEA7
+:100DB000FE19EEFEA2767D632C2E0A000882022820
+:100DC0000A01038E380E0E42C8EE29A67E6D4A0532
+:100DD00000208800308C8271D10FC0F0028F387FE4
+:100DE000C0EA63FFE400C0F1C050037E0CA2EE0E27
+:100DF0003D1208820203F538050542CB5729A67E2D
+:100E00002FDC100F4F366DFA0500208800308CBCA7
+:100E100075C03008E208280A01058338030342C977
+:100E20003E29A67E0D480CD30F6D8A050020880050
+:100E3000B08C8271D10FC05008F53875C0C163FF06
+:100E4000BBC06002863876C0DA63FFD46C1012161D
+:100E5000EED8C1F9C1E8C1C72B221E28221DC0D07F
+:100E60007B81312920060BB702299CFA655008289E
+:100E70002072288CFF28247264915C2AB0000CA890
+:100E80000C6481670EA90C6492B37FA13769AC2F03
+:100E90006000340000282006D7D0288CFACC572ACE
+:100EA00020722AACFF2A24726481352AD0000CA952
+:100EB0000C6491640EAC0C64C31B7FA10768AC0783
+:100EC000C020D10F002D25028A32C0900A6E5065D5
+:100ED000E5B5292467090F4765F5B12C200C1FEEF5
+:100EE000B50CCE11AFEE29E286B4487983026005D5
+:100EF0008219EEB109C90A2992A36890078F2009C7
+:100F0000FF0C65F56E2FE28564F56865559628221D
+:100F10001D7B8105D9B060000200C0908B9417EE54
+:100F2000A70B881487740B0B47A87718EEA509BB8D
+:100F30001008770297F018EEA317EEA408A8010B8B
+:100F400088020747021BEEA097F10B880298F22750
+:100F500090232B902204781006BB1007471208BB81
+:100F6000022890210777100C88100788020B88024E
+:100F700017EE988B3307BB0187340B880298F397E1
+:100F80009997F48B9587399BF588968B3898F688D6
+:100F90009797F99BF898F717EE8F28E28507C7080F
+:100FA0002D74CF08480B28E68565550F2B221E2887
+:100FB000221D7B89022B0A0064BF042CB00728B0D5
+:100FC00000DA2006880A28824CC0D10B8000DBA002
+:100FD00065AFE763FEE90000292072659E9C60040E
+:100FE000E72A207265AEC36004DE00002EB0032C39
+:100FF0002067D4E065C1058A328C330AFF500C4566
+:1010000054BC5564F4EB19EE74882A09A9010988C7
+:101010000C64821FC0926000DD2ED0032A2067D4AA
+:10102000E065A0D88A328B330AFC500B4554BC557E
+:1010300064C4BE19EE69882A09A9017989D50BEA29
+:101040005064A4E30CEE11C0F02F16132E16168A6E
+:10105000E78CE82A16128EE9DFC0AAEA7EAB01B15E
+:10106000CF0BA8506583468837DBC0AE89991E78C0
+:101070009B022BCC012B161B29120E2B0A002916C2
+:101080001A7FC3077FC9027EAB01C0B165B49D8BD7
+:10109000352F0A002A0A007AC30564C3CB2F0A0140
+:1010A00065F4892B12162B1619005104C0C100CC0F
+:1010B0001A2CCCFF2C16170CFC132C16182B121AFA
+:1010C0002A121BDC50581974C0D0C0902E5CF42C2E
+:1010D00012172812182F121B2A121A08FF010CAA25
+:1010E000018834074C0AAB8B2812192BC6162F86A1
+:1010F000082A86092E74102924672E70038975B179
+:10110000EA2A7403B09909490C659DB32B20672D19
+:10111000250265B3FA2B221E2C221D7BC901C0B00B
+:1011200064BD9C2CB00728B000DA2006880A28820B
+:101130004CC0D10B8000DBA065AFE763FD8189BAAD
+:10114000B19965909788341CEE2598BA8F331EEEBE
+:101150001E0F4F542FB42C8D2A8A320EDD020CAC98
+:10116000017DC9660A49516F92608A3375A65B2C6E
+:10117000B0130AED510DCD010D0D410C0C417DC98F
+:10118000492EB012B0EE65E3C6C0D08E378CB88A57
+:10119000368FB97CA3077AC9027EFB01C0D1CED9B4
+:1011A00088350AAD020E8E0878EB022DAC0189B7A6
+:1011B000DAC0AF9B79BB01B1CADCB0C0B07DA30778
+:1011C0007AD9027CEB01C0B164B161C09129246776
+:1011D000C020D10F00008ADAB1AA64A0C02C206719
+:1011E0002D250265C3111DEDF88A321EEDFD0DADF2
+:1011F000010EDD0C65D28A0A4E516FE20260028157
+:10120000C090292467090F4765F2F828221D7B89C1
+:10121000022B0A0064BCA82CB00728B000DA200614
+:10122000880A28824CC0D10B8000DBA065AFE76341
+:10123000FC8D00000CE9506492ED0CEF11C0802889
+:101240001611AFBF2F16198EF88BF7DAE08FF92B36
+:101250001610ABFB7FBB01B1EA0CA8506580D688A5
+:1012600037DCE0AF89991C789B022CEC012C161B13
+:1012700029120C2C0A0029161A7AE3077AE9027F50
+:10128000BB01C0C165C2A58B352C0A002A0A007AB1
+:10129000E30564E1CA2C0A0164CE0D60028E883435
+:1012A0001BEDCF98DA8F331EEDC80F4F542FD42C7F
+:1012B0008C2A8A320ECC020BAB010CBB0C65BF0A28
+:1012C0000A49516E920263FF018A330AAB5064BE31
+:1012D000F92CD0130AEE510ECE010E0E410C0C412A
+:1012E0000ECC0C65CEE42FD012B0FF65F26EC0B00C
+:1012F0008E378CD88A362FD2097CA3077AC9027E12
+:10130000FB01C0B165BEC38835DBA0AE8E78EB01B2
+:10131000B1AB89D7DAC0AF9D79DB01B1CAC0C07B60
+:10132000A3077AB9027DEB01C0C165CE9DC09029AB
+:101330002467C020D10F88378C3698140CE90C290B
+:10134000161408F80C981D78FB07281214B088288A
+:101350001614891D9F159B16C0F02B121429161AFE
+:101360002B161B8B147AE30B7AE90688158E1678F8
+:10137000EB01C0F165F1BA29121A2F12118A352E2C
+:10138000121B9A1AAFEE2F1210C0A0AF9F79FB016B
+:10139000B1EE9F11881AC0F098107AE30A7EA90571
+:1013A0002A12017A8B01C0F164F0816001838936D1
+:1013B0008B3799170BE80C981F09C90C291615785B
+:1013C000EB07281215B088281615D9C09A199E184F
+:1013D0008A1F2E12152A161A2E161BDAC0C0E08C90
+:1013E000177F930B7FA90688188F1978FB01C0E13E
+:1013F00065E13E29121A2F12138A352E121B9A1BF1
+:10140000AFEE2F1212C0A0AF9F79FB01B1EE9F1378
+:10141000881BC0F098127AE30A7EA9052A12037A83
+:101420008B01C0F165F10A2E12162E16192A121B15
+:10143000005104C0E100EE1AB0EE2E16170EFF1395
+:101440002F16180FCC01ACAA2F121A0EBC01ACFC3F
+:101450007FCB01B1AA2A161B2C161A63FC5E000072
+:101460007FB30263FE3163FE2B7EB30263FC306305
+:10147000FC2A00006450C0DA20DBC0581648C020A7
+:10148000D10FC09163FD7A00C09163FA44DA20DB8A
+:1014900070C0D12E0A80C09A2924682C7007581574
+:1014A00038D2A0D10F03470B18ED4FDB70A8287876
+:1014B00073022B7DF8D9B063FA6100002A2C74DB2B
+:1014C00040580EB363FAE4000029221D2D25027B4B
+:1014D0009901C0B0C9B62CB00728B000DA20068840
+:1014E0000A28824CC0D10B8000DBA065AFE7C0208A
+:1014F000D10FC09163FBFF00022A025802440AA2E6
+:1015000002060000022A025802410AA20206000056
+:10151000DB70DA20C0D12E0A80C09E2924682C708E
+:1015200007581517C020D10FC09463FBC9C096633C
+:10153000FBC4C09663FBBF002A2C74DB30DC405B2D
+:10154000FE11DBA0C2A02AB4002C200C63FF2700F0
+:101550008D358CB77DCB0263FDD263FC6D8F358EEC
+:10156000D77FEB0263FDC563FC6000006C1004C014
+:1015700020D10F006C1004C020D10F006C10042B80
+:10158000221E28221DC0A0C0942924062A25027BE1
+:101590008901DBA0C9B913ED06DA2028B0002CB010
+:1015A0000703880A28824CC0D10B8000DBA065AFFE
+:1015B000E7C020D10F0000006C10042C20062A2167
+:1015C0000268C80528CCF965812E0A094C6591048A
+:1015D0008F30C1B80F8F147FB00528212365812774
+:1015E00016ECF529629E6F98026000F819ECF1295B
+:1015F00092266890078A2009AA0C65A0E72A629DB6
+:1016000064A0E12B200C0CB911A6992D92866FD9FC
+:10161000026000DB1DECE90DBD0A2DD2A368D007E6
+:101620008E200DEE0C65E0C7279285C0E06470BF88
+:101630001DECEE68434E1CECED8A2B0CAA029A704E
+:1016400089200899110D99029971882A98748F320E
+:101650009F75282104088811987718ECDE0CBF11BB
+:10166000A6FF2DF285A8B82E84CF2DDC282DF68577
+:10167000C85A2A2C74DB40580E46D2A0D10FC02085
+:10168000D10F00000029CCF96490B12C206689317B
+:10169000B1CC0C0C472C24666EC60260008509F89C
+:1016A0005065807F1CECD38A2B0F08400B881008F4
+:1016B000AA020CAA029A7089200899110D99029920
+:1016C00071883398738C329C728A2A9A74893499FF
+:1016D0007563FF7D00CC57DA20DB30DC4058151DE8
+:1016E000C020D10F00DA20C0B65815AC63FFE5006A
+:1016F000DA205815AA63FFDC00DA20DB30DC40DD9D
+:1017000050581638D2A0D10FC858DA20DB30581400
+:101710008A2A210265AFBDC09409A9022925026366
+:10172000FFB200002B21045814351DECAFC0E02E91
+:1017300024668F302B200C0F8F1463FF662921380D
+:10174000C08879830263FF5B2C20662B2104B1CC17
+:101750000C0C472C24665814291DECA3C0E02E2441
+:10176000668F302B200C0F8F1463FF376C1004C072
+:10177000B7C0A116ECA015EC92D720D840B822C073
+:10178000400535029671957002A438040442C94B95
+:101790001AEC8519EC8629A67EC140D30F6D4A0547
+:1017A00000808800208C220A88A272D10FC05008C5
+:1017B000A53875B0E363FFD76C1006931394112915
+:1017C0002006655288C0716898052A9CF965A29820
+:1017D00016EC792921028A1309094C6590CD8AA05B
+:1017E0000A6A512AACFD65A0C2CC5FDB30DA208CDE
+:1017F000115814D8C0519A13C7BF9BA98E132EE25B
+:101800000968E0602F629E1DEC6A6FF80260008438
+:101810002DD22668D0052F22007DF9782C629DC735
+:101820009064C0709C108A132B200C2AA0200CBD41
+:1018300011A6DD0A4F14BFA809880129D286AF88F6
+:10184000288C09798B591FEC5C0FBF0A2FF2A36813
+:10185000F0052822007F894729D285D490659075AC
+:1018600060004300002B200C1FEC540CBD11A6DDC2
+:1018700029D2860FBF0A6E96102FF2A368F0048853
+:10188000207F890529D285659165DA20581543C9DD
+:101890005C6001FF00DA20C0B658154060000C0003
+:1018A000C09063FFB50000DA2058153C6551E48D07
+:1018B000138C11DBD08DD0022A020D6D515813AD5F
+:1018C0009A1364A1CEC75F8FA195A9C0510F0F478E
+:1018D0009F1163FEFD00C091C0F12820062C2066F8
+:1018E000288CF9A7CC0C0C472C24666FC6098D13E5
+:1018F0008DD170DE02290A00099D02648159C9D385
+:101900008A102B21045813BD8A13C0B02B24662ED5
+:10191000A2092AA0200E28141CEC338D1315EC27E5
+:10192000C1700A773685562DDC28AC2C9C12DED08F
+:10193000A8557CD3022EDDF8D3E0DA40055B02DC4B
+:10194000305BFF8AD4A028200CB455C0D02B0A8865
+:101950002F0A800C8C11A6CC29C285AF3FAB9929E8
+:10196000C6851CEC1CDEF0AC882D84CF2812022921
+:10197000120378F3022EFDF8289020D3E007880C9C
+:10198000C170080847289420087736657FAB891313
+:1019900013EC1A8990C0F47797491BEC18C1CA2838
+:1019A00021048513099E4006EE1187530488118592
+:1019B000520E88020C88029BA09FA18F2B9DA59898
+:1019C000A497A795A603FF029FA22C200C1EEC0152
+:1019D000AECE0CCC1106CC082BC2852DE4CF2BBC8F
+:1019E000202BC6852A2C748B11580D69D2A0D10FDB
+:1019F00028203DC0E07C877F2E24670E0A4765A023
+:101A00007B1AEBFF88201EEBED8F138EE48FF4081A
+:101A100088110A88020F8F14AFEE1FEBFA98910F0E
+:101A2000EE029E901EEBF9C0801AEBEA2CD285AA3A
+:101A3000BAB8CC28A4CF2CD6852C21022F20720E28
+:101A4000CC02B1FF2F24722C2502C020D10F8713A6
+:101A5000877007074763FD6E282138C099798B028C
+:101A600063FE9ADDF063FE9500DA20DB308C11DD39
+:101A70005058155CD2A0D10FC0E163FF7A8B138C54
+:101A800011DD50C0AA2E0A802A2468DA205813BC1F
+:101A9000D2A0D10FC020D10F6C1006292102C0D0D6
+:101AA0007597102A32047FA70A8B357FBF052D2535
+:101AB000020DD902090C4C65C18216EBBE1EEBBCAF
+:101AC00028629EC0FA78F30260018829E2266890B5
+:101AD000078A2009AA0C65A17A2A629DDFA064A169
+:101AE000772B200C0CBC11A6CC29C286C08C798324
+:101AF0000260015719EBB109B90A2992A36890074E
+:101B0000882009880C65814327C2851CEBB364716A
+:101B10003A8931098B140CBB016FB11D2C20669FD3
+:101B200010B1CC0C0C472C24666EC6026001400933
+:101B3000FF5065F13A8A102AAC188934C0C47F97E7
+:101B40003C18EBB31BEBB28F359C719B708B209DC7
+:101B50007408BB029B72C08298751BEBAE0F0840E5
+:101B60009B730F881198777FF70B2F2102284A006B
+:101B700008FF022F2502C0B4600004000000C0B0BE
+:101B80007E97048F362F25227D97048837282521BC
+:101B90007C9736C0F1C0900AF9382F3C20090942E1
+:101BA00064908619EB8018EB8128967E00F08800FF
+:101BB000A08C00F08800A08C00F08800A08C2A6225
+:101BC0009D2DE4A22AAC182A669D89307797388F1C
+:101BD000338A3218EB8A07BE0B2C2104B4BB04CC29
+:101BE0001198E0C08498E1882B9DE59AE69FE71A5A
+:101BF000EB82099F4006FF110FCC020A880298E28F
+:101C0000C1FC0FCC022CE604C9B82C200C1EEB71D1
+:101C10000CCA11AECC06AA0829A2852DC4CF09B9D9
+:101C20000B29A685CF5CC020D10FC081C0900F8941
+:101C300038C08779880263FF7263FF6600CC57DA89
+:101C400020DB30DC405813C3C020D10FDA205814F9
+:101C50005363FFE8C0A063FE82DA20C0B658144F79
+:101C600063FFD900DB402A2C74580CC9D2A0D10FD5
+:101C70008A102B21045812E11EEB4EC0D02D246691
+:101C800063FEB1006C1006D62019EB491EEB4B2801
+:101C9000610217EB4808084C65805F8A300A6A5178
+:101CA00069A3572B729E6EB83F2A922668A0048CB7
+:101CB000607AC9342A729D2C4CFECAAB2B600CB6DC
+:101CC0004F0CBD11A7DD28D2860EBE0A78FB269CDC
+:101CD000112EE2A32C160068E0052F62007EF91594
+:101CE00022D285CF2560000D00DA60C0B658142BD3
+:101CF000C85A60010F00DA60581428655106DC40AC
+:101D0000DB308D30DA600D6D5158129AD3A064A08B
+:101D1000F384A1C05104044763FF6D00C0B02C6080
+:101D2000668931B1CC0C0C472C64666FC602709684
+:101D30000A2B61045812B1C0B02B64666550B42AF6
+:101D40003C10C0E7DC20C0D1C0F002DF380F0F42EA
+:101D500064F09019EB1418EB1528967E8D106DDA4F
+:101D60000500A08800C08CC0A089301DEB247797A7
+:101D70005388328C108F3302CE0BC02492E1226143
+:101D8000049DE00422118D6B9BE59FE798E61FEB15
+:101D90001A0998400688110822020FDD02C18D9DA4
+:101DA000E208220292E4B4C22E600C1FEB0A0CE897
+:101DB00011A7882C8285AFEE0C220B2BE4CF228654
+:101DC00085D2A0D10F28600CD2A08C1119EB020C87
+:101DD0008D11A988A7DD2ED2852B84CF0ECC0B2C9C
+:101DE000D685D10FC0F00ADF387FE80263FF6C634D
+:101DF000FF6000002A6C74C0B2DC20DD4058128FF6
+:101E0000C0B063FF63C020D10F0000006C10042C31
+:101E1000221D2A221EC049D320293006243468C03E
+:101E2000407AC105DDA060000200C0D06E9738C0C6
+:101E30008F2E0A802B3014C0962934060EBB022E3A
+:101E400031022B34147E8004243502DE407AC10E28
+:101E5000C8ABDBD0DA302C0A00580AE52E31020E6E
+:101E60000F4CC8FEC020D10F6895F8283102080831
+:101E70004C658FEF1AEAD01CEACE2BA29EC09A7B4B
+:101E80009B462BC22668B0048D307BD93B29A29D8E
+:101E9000C0E3CB9394901BEAE02D31049B9608DDC0
+:101EA000110EDD029D979D9112EADDC0E524C4A2CA
+:101EB0002E34062F310228A29D02FF02288C3028E2
+:101EC000A69D2F3502C020D10FDA30C0B65813B30B
+:101ED000C020D10F6C1006292006689805289CF9AF
+:101EE00065825D29210209094C659210CD51DB30D4
+:101EF000DA20044C02581317C051D3A0C7AF2A36BA
+:101F00000AC0E019EAAD1DEAB31FEAAC8A3A16EA44
+:101F1000A9B1AC64C13528629E6F88026001F129C5
+:101F2000DC332992266890078B2009BB0C65B1E051
+:101F300027629DC08E6471D82B200C0CBC11A6CCDE
+:101F400029C2867983026001D219EA9B09B90A295C
+:101F500092A3971068900828220009880C6581BB1D
+:101F600027C2856471B5292006299CF96491EC2C5F
+:101F700020668931B1CC0C0C472C24666EC60260F9
+:101F800001A109F85065819B883689F4088C14AC4E
+:101F9000991CEA8B0C99022C2104997019EAA1086A
+:101FA00008479971892A09881008990218EA9E0839
+:101FB000990299722830132930120488100699105A
+:101FC00008990228302C9A740C881008C8020988D5
+:101FD00002987389379975883898768A39C0819ABA
+:101FE000771AEA918935987B99780989140A9902B8
+:101FF000997A8A30893277A73618EA808F33987CAD
+:10200000C084987D882B2E76112976122F7613198D
+:10201000EA7A0A9F4006FF1104CA110988020FAA32
+:1020200002987EC1F90FAA022A7610C0AA600001A8
+:10203000C0A6ADBF0CBC11A6CC29C2852EF4CF0919
+:10204000A90B29C685655107C020D10F2B200C0C88
+:10205000BC1106CC0828C28609B90A6F8902600142
+:102060002E2992A36890082A220009AA0C65A11FB4
+:102070002AC28564A11928203D08284064808C84E8
+:102080003504841464408485F574537F8436048455
+:1020900014644077745374293013C08C79886CC0F1
+:1020A000902924670908476580ED882089F48435E4
+:1020B0001FEA55048414A4940F440294A014EA5017
+:1020C00008881104880298A1843698A3048414A473
+:1020D000990F990299A219EA4CADB428C2852E44F1
+:1020E000CF288C1028C6852821022F20720988024B
+:1020F000B2FF2F2472282502C020D10F00CC57DA5E
+:1021000020DB30DC40581293C020D10FC09163FF18
+:102110008FDA20C0B658132163FFE100DA2058138C
+:102120001F63FFD88A102B21045811B41DEA2A1FFF
+:10213000EA232B200CC0E02E24668A3A63FE480076
+:1021400000DA20DB30DC40DD505813A6D2A0D10FDE
+:102150002A2C74DB40580B8ED2A0D10F292138C015
+:102160008879830263FE202A12002C20662B21042A
+:102170002CCC010C0C472C24665811A01DEA161F0C
+:10218000EA0F2B200CC0E02E24668A3A63FDF8008B
+:10219000DA2058130263FF64DA205BFF1CD2A0D15F
+:1021A0000F0000006C10089515C061C1B0D9402A1D
+:1021B000203DC0400BAA010A64382A2006291606D1
+:1021C00068A8052CACF965C33B1DE9FC6440052FEC
+:1021D000120564F29C2621021EE9F806064C65628F
+:1021E000E315E9F46440D98A352930039A140A9931
+:1021F0000C6490CC2C200C8B149C110CCC11A5CC15
+:102200009C122CC286B4BB7CB3026002D38F110E29
+:10221000FE0A2EE2A368E0098620D30F0E660C6545
+:1022200062BE88122882856482B6891464905EDA60
+:1022300080D9308C201EE9F21FE9F31DE9E08B14F0
+:102240008DD4D4B07FB718B88A293C10853608C61B
+:10225000110E66029681058514A5D50F550295804D
+:102260000418146D8927889608CB110888140EBBB2
+:1022700002A8D8299C200F88029BA198A088929B35
+:10228000A3088814A8D80F880298A22AAC1019E9CC
+:10229000DEC0C08F141EE9CF86128D11286285AE74
+:1022A000DD08FF0B2CD4CF2821022F66858B352A21
+:1022B0002072098802ABAA2825022A2472C020D1E4
+:1022C0000F29529E18E9BB6F9802600208288226E7
+:1022D00068800829220008990C6591F92A529DC14D
+:1022E000CA9A1364A1EF2B200C2620060CB811A566
+:1022F000882D82860EBE0A7DC3026002022EE2A3F2
+:1023000068E0082F22000EFF0C65F1F3288285DEBD
+:10231000806481FF9810266CF96461FF2C20668828
+:1023200031B1CC0C0C472C24666EC6026001BC088F
+:10233000FD5065D1B617E9BD19E9A21AE9A92C210A
+:10234000048B2D2830102F211D0C88100BFB090C3D
+:1023500088020A880209BB026441528910C04D9B61
+:1023600090979198928D35D9E064D06CD730DBD0BE
+:10237000D8307FD713273C10BCE92632168C39960B
+:10238000E69CE78A37B4389AE80B13146430492A7C
+:10239000821686799A9696978C778A7D9C982B825E
+:1023A000172C7C209A9A2A9C189B99867BB03BB864
+:1023B000896DB9218BC996A52692162AAC18B899B1
+:1023C0009BA196A08BC786CD9BA22B921596A49B12
+:1023D000A386CB2CCC2026A605C0346BD4200D3B85
+:1023E0000C0DD8090E880A7FB705C0909988BC8863
+:1023F000C0900B1A126DAA069988998B288C18C068
+:10240000D01BE98C1CE98B16E981B1FF2A211C2322
+:10241000E6130F0F4F26E6122F251D7FA906C0F0E9
+:10242000C08028251D05F6111AE97A8F202BE615A4
+:102430002CE6162DE61726E6180AFA022AE61429D3
+:102440002006299CF96490FF29200C8D15C0801A64
+:10245000E9610C9C11AA99A5CCDA202BC28528949D
+:10246000CF0B4B0B2BC685C0B08C1658118AD2A04F
+:10247000D10F8A356FA548D8308BD56DA90C8A86C7
+:102480000A8A14CBA97AB337288C10C08028246715
+:10249000080B4765B112DA20DB302C12065811AD5B
+:1024A000D3A0C0C1C0D02DA4039C1563FD268636E1
+:1024B00064610C8910C04D9B909791989263FEA423
+:1024C000C08163FFC78A15CCA7DA20DB308C165891
+:1024D00011A1C020D10FDA20C0B658123063FFE43A
+:1024E00000DA208B1158122D63FFD9009E178A1332
+:1024F0002B21045810C28E17C0B02B246663FE3403
+:10250000C08063FE09DA20DB308C16DD505812B52E
+:10251000D2A0D10FDA2058122163FFA82D2138C094
+:10252000C87DC30263FE0D8A132B21042C206698FC
+:1025300017B1CC0C0C472C24665810B08E17C0D0A5
+:102540002D246663FDEE0000262138B06606064F96
+:10255000262538656EF128206A7F870508294164A1
+:1025600090A5C0D01BE92619E93426200723E61BD5
+:10257000B16609FA022BE61A28200A2DE61D2AE682
+:102580001E09880228E61C882606064728E6202B16
+:10259000220826E53E2BE6212D24072C20062A20A2
+:1025A0006468C347B44463FE9EDB30DA208D15C0F7
+:1025B000CE2E0A802C24688C165810F1D2A0D10F90
+:1025C0008E102A321616E8FD0A2A1486662BE612A9
+:1025D00097E127E61328E614AA6609660296E02E1C
+:1025E000EC4869ED50C14663FD7A000064AFB41950
+:1025F000E8F328201689920A880C00910400881AB2
+:10260000A8B8982963FF9C002B21046EB81E2C20CB
+:1026100066B8CC0C0C472C2466C9C09E178A135888
+:1026200010778E17C0348F20C0D02D2466C0682646
+:10263000240663FF2C008D35C08064D04AD9E0DCCD
+:1026400030DBE0DF301AE8FDB188B4FF17E8FD8623
+:10265000C9249DFF8DC82CCC102D46300767012D55
+:1026600046320A66011DE8F7264631AD6D2D463328
+:1026700026F21597B796B684C3BCBB94B58D3529A1
+:102680009C107D83C22F211DC14663FD4B000000BD
+:102690006C1006292006289CF86582BF2921022B90
+:1026A000200C09094C6590E116E8C30CBA11A6AAE2
+:1026B0002DA2862C0A127DC30260028C19E8BF0984
+:1026C000B90A2992A36890078C2009CC0C65C278BE
+:1026D00029A2856492722D629E1AE8B56FD80260B5
+:1026E000026E2AA22629160168A0082B22000ABB26
+:1026F0000C65B25C29629DC18C6492542A21200A27
+:10270000806099102C203CC7EF000F3E010B3EB1BA
+:10271000BD0FDB390BBB098F260DBD112DDC1C0D48
+:102720000D410EDD038E27B1DD0D0D410FEE0C0DB9
+:10273000BB0B2BBC1C0BB7027EC71C2C21257BCBF3
+:10274000162D1AFC0CBA0C0DA16000093E01073EC3
+:10275000B1780987390B770A77EB0260020A2C21DE
+:1027600023282121B1CC0C0C4F2C25237C8B29B0A4
+:10277000CD2D2523C855DA20DB3058106F292102D2
+:10278000CC96C0E80E9E022E2502CC57DA20DB3014
+:10279000DC405810F0C020D10F2C20668931B1CC1C
+:1027A0000C0C472C24666EC6026001D309FD5065EF
+:1027B000D1CD2F0A012E301129221464E0112822D4
+:1027C0001B090C4400C10400FA1A0A880228261BBF
+:1027D0002E3010C0A0C0B0941295131CE878883039
+:1027E0002CC022088D14778704C0F10CFA38C04140
+:1027F000C0F225203CC0840858010F5F010F4B3800
+:1028000005354007BB10C0F0084F3808FF100FBB5C
+:102810000228ECFEC0F0084F38842B0BA8100AFFEA
+:10282000102A21200F88020B880208440218E8862B
+:102830008F110844022821250A2A14082814048824
+:10284000110A88022A210494F08B2004E41008BBAA
+:102850001104BB02C04A04BB029BF1842A08AB11DD
+:102860000BEB0294F40A54110B44020555100D1B96
+:102870004094F707BB100B5502085502C08195F62E
+:102880008433C05094F3B1948B3295F898F99BF24D
+:10289000C080C1BC24261499FA9BF598FB85389515
+:1028A000FC843A94FD8B3B9BFE883998FF85352547
+:1028B000F6108436851324F6118B3784122BF6120A
+:1028C000C0B064C07E89307797438D3288332E3014
+:1028D000108F111CE84A0999400699112CF614C072
+:1028E000C42CF6158C2B2DF61A28F61B2BF6190482
+:1028F000A81109880208EE0219E840C18008EE021A
+:1029000009C90229F6162EF618C09E600001C09A69
+:102910002F200C18E8300CFE11A8FFA6EE2DE28542
+:102920002BF4CF0D9D0B2DE685C87F8A268929A71C
+:10293000AA9A260A990C090948292525655050C0EC
+:1029400020D10F00C09A63FFC6DA2058111463FE2D
+:1029500038DA20C0B658111163FE2E0068973C2B60
+:102960009CFD64BE24C020D10FDA20DB705810CD4E
+:10297000C0C0C0D10ADA390ADC3865CDE063FE098F
+:102980008A102B2104580F9DC0B02B246663FE21B2
+:10299000DB402A2C7458097ED2A0D10FDA20580FC0
+:1029A000A263FCF76C1004C020D10F006C10042946
+:1029B0000A801EE8261FE8261CE7FF0C2B11ACBB83
+:1029C0002C2CFC2DB2850FCC029ED19CD0C051C0C6
+:1029D0007013E82214E82118E81F2AB285A82804F9
+:1029E000240A234691A986B8AA2AB685A9882784ED
+:1029F0009F25649FD10F00006C100AD6302830103C
+:102A0000292006288CF964829B68980B2A9CF9651A
+:102A1000A1B2022A02580F8489371BE7E8C89164E3
+:102A2000520E2A21020A0C4C65C2588D3019E7E17A
+:102A300074D7052E212365E29E2F929E1AE7DD6F43
+:102A4000F8026002532AA22668A0082C22000ACCB1
+:102A50000C65C2442A929D64A23E9A151FE7D78D49
+:102A600067C1E6C8DD2B620618E7D564B00528808B
+:102A7000217B8B432B200C18E7CF0CBC11A8CC2951
+:102A8000C28679EB460FBE0A2EE2A368E0052F222C
+:102A9000007EF9372CC2859C1864C2332B212F8706
+:102AA000660B7B360B790C6F9D266ED2462C203D33
+:102AB0007BC740CE5560001E2A200CC1B28C205826
+:102AC00010F79A1864A2458D6763FFCFC0C063FFFB
+:102AD000C5D7B063FFD300C0E06000022E60030ED4
+:102AE000DB0C6EB20EDC700CEA11AA6A2AAC20581C
+:102AF0000199D7A0DA20DB70C1C82D212058109190
+:102B00008C268B279A160CBB0C7AB3348F188963EA
+:102B100099F3886298F28E659EF82D60108A189D50
+:102B20001768D729C0D09DA92C22182B22139CAB43
+:102B30009BAA97A58E667E7302600097CF586000AF
+:102B40001FDA208B1658105765A13863FFBDC0816E
+:102B5000C0908F18C0A29AF999FB98FA97F563FF75
+:102B6000D2DB30DA20DC40580FFBC051D6A0C0C009
+:102B70002BA0102CA4039B172C1208022A02066B10
+:102B800002DF702D60038E179D149E100CDD11C0A6
+:102B9000E0AD6D2DDC205801188C148B16ACAC2CDC
+:102BA00064038A268929ABAA0A990C9A26886609A1
+:102BB000094829252507880C98662F2218A7FF2F7A
+:102BC000261863FE96DA20DB30DC40DD5058110514
+:102BD000D2A0D10FC0302C20668961B1CC0C0C473B
+:102BE0002C24666EC6026000D2C03009FD5065D04C
+:102BF000CA8E6764E069647066DB608C18DF70DA27
+:102C0000202D60038E170CDD119E10AD6D2DDC2084
+:102C10001EE78D5800F9232618DA208B16DC402F8A
+:102C20002213DD50B1FF2F2613580F9AD2A0D10FD7
+:102C30000028203D084840658DE76F953EDA308DCD
+:102C4000B56D990C8CA80C8C14CACF7CD32D2AACF2
+:102C500010C090292467090D4764DDC5600092000B
+:102C60002C1208066B022D6C20077F028E17DA20CB
+:102C70009E101EE77458007D63FF9A00C09163FFA9
+:102C8000D1000000655081DA20DB60DC40580FB1D4
+:102C9000C020C0F02FA403D10FDA20C0B658103FD7
+:102CA00063FFE000006F950263FD6CDA20DB30DC2F
+:102CB00040DD50C4E0580F32D2A0D10F8A152B212D
+:102CC00004580ECE232466286010981763FF210055
+:102CD000DA2058103263FFABC858DB30DA20580FC7
+:102CE000162A210265AF9CC09409A9022925026316
+:102CF000FF91DB30DC40DD50C0A32E0A802A24681F
+:102D0000DA20580F1FD2A0D10FC020D10FDA202B0C
+:102D1000200C58104763FF6B6C1004282006C0621B
+:102D2000288CF8658125C050C7DF2B221BC0E12A03
+:102D3000206B29212300A104B099292523B1AA00E1
+:102D4000EC1A0BC4010A0A442A246B04E4390DCCA2
+:102D5000030CBB012B261B64406929200C1BE715C3
+:102D60000C9A110BAA082FA2861BE7136FF90260B9
+:102D700000B60B9B0A2BB2A368B0082C22000BCC28
+:102D80000C65C0A42BA2851DE73664B09B8C2B2458
+:102D900021040DCC029CB08820C0C50888110C8885
+:102DA0000298B1882A08441198B48F3494B79FB51B
+:102DB000C0401EE7082DA2850E9E0825E4CF2DDC1D
+:102DC000282DA68529210209094C68941A689820A3
+:102DD000C9402A210265A00B2A221E2B221D7AB18E
+:102DE0000265A079C020D10F2C212365CFDE6000C1
+:102DF000082E21212D21237EDBD52B221E2F221DE3
+:102E00002525027BF901C0B064BFC413E6E92CB0EC
+:102E10000728B000DA2003880A28824CC0D10B8032
+:102E200000DBA065AFE763FFA62A2C74C0B02C0AB4
+:102E300002580E081CE70C9CA08B2008BB1106BB97
+:102E4000029BA1893499A263FF790000262468DAE5
+:102E500020DB30DC40DD50581063D2A0D10FDA20E7
+:102E60002B200C580FCEC020D10F00006C1006078D
+:102E70003D14C080DC30DB40DA20C047C02123BCD9
+:102E800030032838080842774001B1DD64815A1EBA
+:102E9000E6C519E6C629E67ED30F6DDA050050882F
+:102EA00000308CC0E0C02025A03C14E6C4B6D38F0F
+:102EB000C0C0D00F87142440220F8940941077F7A8
+:102EC00004C081048238C0F10B2810C044C0220421
+:102ED000540104FD3802520102FE3808DD10821C44
+:102EE00007EE100E6E020EDD02242CFEC0E004FE82
+:102EF000380AEE100E88020D88028DAB1EE6B4086B
+:102F0000D8020E880298B0C0E80428100E5E018432
+:102F1000A025A125084411084402052514045511D3
+:102F2000043402C0810E8E3994B18FAA84109FB4EC
+:102F300075660C26A11FC0F2062614600009000069
+:102F400026A120C0F20626140565020F7701078727
+:102F50003905E61007781008660206550295B62571
+:102F6000A1040AE61108581108280208660296B75B
+:102F7000C060644056649053067E11C0F489C288D4
+:102F8000C30B340B96459847994618E69B9F41041E
+:102F900059110E99021FE699020E4708D80298426D
+:102FA0000E99029F40C1E00E990299442FA00CB4E3
+:102FB000380CF91114E6881EE67FA4FFAE992E9214
+:102FC0008526F4CF0E880B289685D10F2BA00C1FD9
+:102FD000E6791CE6800CBE11ACBBAFEE2DE2852677
+:102FE000B4CF0D3D0B2DE685D10FC0800528387874
+:102FF000480263FEA263FE966C1006C0C06570F1C5
+:103000008830C030088714778712C0B0C0A619E690
+:103010006B299022C030CC97C031600003C0B0C093
+:10302000A6C0E0C091C0D4C08225203C0B3F1097C1
+:1030300012831CC0700858010D5D01089738C080CC
+:103040000B9838077710048810086802087702C0C8
+:10305000800D98382D3CFE0888100D9E388D2B0A67
+:10306000EE1008EE0207EE020CB8100FDD02053B71
+:10307000400EDD029D408920043D100899110D99F4
+:10308000022D210409A90208DD119941872A05B9F9
+:10309000100D3D020ABB110DBB02087702974428B0
+:1030A00021258712082814048811071E4007EE10F6
+:1030B0000E990275660926211F0626146000060077
+:1030C0002621200626140868029B47098802984694
+:1030D00029200CD2C0C0800C9E111BE63E1FE63595
+:1030E000AB99AFEE2DE2852894CF0DAD0B2DE68583
+:1030F000D10FDD40C0A6C0B08E51CAE0B2AAB1BBAC
+:103100002DDC108F500E7836981008770C9FD898C9
+:10311000D989538F52991199DB9FDA7E8309B1CCFB
+:10312000255C10C97763FFCF88108D1108E70C97D5
+:1031300051AD8DD7F078DB01B1F79D5397528830B0
+:10314000C030088714088840648ED565BEC963FE08
+:10315000BC0000006C1004D720B03A8820C0308238
+:1031600021CAA0742B1E2972046D080FC980C99151
+:103170008575B133A2527A3B0B742B0863FFE900CB
+:10318000649FECD10FD240D10F0000006C100AD622
+:10319000302E3027D950DA4015E6092430269A150A
+:1031A00029160464E0026493732920062A9CF865BA
+:1031B000A3CE2A2102270A040A0B4C65B3978C3050
+:1031C00074C7052D212365D4A0C0A62B0A032C2289
+:1031D00000580F0B64A3B917E5F78E389A1664E30D
+:1031E000BA2F6027285021C9F37E8311C2B08C20EA
+:1031F0002A200C580F2AD7A0CDA16004A200C2B08B
+:103200008C202A200C580EFED7A064A4862F212ED5
+:103210008B680FBF360FB90C6F9D54296027D5B04E
+:103220006E920528203D7B8F4CDA20DB50C1C42DE7
+:10323000211F580EC48B269A189A1989272AAC3850
+:103240000B990C7A93538963C08099738F62987835
+:103250009F728E659E798D679D7B8C6695759C7A35
+:103260008E687E53026000B18B1465B050600038E8
+:10327000DBF063FFA5008A14C9A92E60030E9B0C26
+:103280006EB2A5DC500CEA11AA6A2AAC285BFFB129
+:10329000D5A063FF93C0E063FFE2DA208B18580EDD
+:1032A0008165A2B163FF9E0000DA20DB308C1558E7
+:1032B0000E29D6A0C0C0C0D12D16042CA403DC70EA
+:1032C000DA20DB60DF502D6003C0E09E109D171EEA
+:1032D000E5D20CDD110D6D082DDC285BFF478E66F5
+:1032E0008F678817AF5FA8A828640375FB01B1EE4C
+:1032F0008A189E669F6789268829AA9909880C9949
+:10330000268E6808084805EE0C28252515E5AC9E94
+:103310006865EECC63FEE6000000C9432F21232B35
+:1033200021212FFC010F0F4F2F25237FBB026003AC
+:10333000142C20668961B1CC0C0C472C24666EC617
+:103340000260022809FD5065D22264E1B62E602792
+:1033500064E1B0DC70DF50DA20DB601EE5C32D6075
+:1033600003C08098100CDD11AD6D2DDC285BFF22B1
+:10337000644181C0442B0A008C202A200C580EA0E6
+:103380000AA70265A00FC0B02C22002A200C580EFC
+:103390009CD7A064AFEFDA20C1BCC1C82D21208F1B
+:1033A000188E268929AFEE9E260E990C0909482908
+:1033B0002525580E64C090C050C0C288609A191E5E
+:1033C000E57FC0A12EE022088F14778704C0810E0C
+:1033D0008938C0800B93102D203C2921200CDC0162
+:1033E00004DB010929140BA8380CA5380D3D401C3D
+:1033F000E5968B2B088810075510085502053302F7
+:103400002821250F154003BB020CBB0207551005F0
+:10341000D3100828140ADD11048811098802053325
+:10342000022921040833029B70C0808A201BE58F8B
+:1034300008AA110BAA029A71C0A1852A93769574E5
+:1034400008931103DD020ADD029D778C63C1DC9CC9
+:10345000738B6298789A799B72232214C0C0B1351D
+:103460002526149C7B9D75937A2B621A9B7C2A627D
+:103470001C9A7D28621D987E25621B957F2362170A
+:103480002376102D62182D76112C62192C76126479
+:10349000E0B98E6077E73DC0FE13E5571DE558C1E2
+:1034A000818A628B630495110E9C4006CC110C55E9
+:1034B00002247615085502C0802D76148D2B2B76AC
+:1034C0001B2A761A28761925761803DD022D761622
+:1034D0006000030000C0FA2E200C19E53E18E53507
+:1034E000A9E90CEE11A8EEC0802DE2852894CF0D3D
+:1034F000FD0B2DE685DA208B198C158D14580D6582
+:10350000D2A0D10FDC70DF50DB602D6C28C0A01E74
+:10351000E5569A10DA205BFE5563FE53002B203DE2
+:103520000B4B4065BC826FE527DA308F556DE90C97
+:103530008EAA0E8E14C9E87EF3162AAC10C090290C
+:103540002467090F4764FC6060015F00C0FA63FFF5
+:1035500085C09163FFE88814658168DA20DB608CA0
+:1035600015580D7CC020C09029A403D10F8A162BBA
+:103570002104580CA2C0A02A24668E6863FDCA00EC
+:10358000002B9CF965B0FDDA20580CA763FC2200E3
+:1035900000DA20C0B6580E0163FFBA002B200C0CD5
+:1035A000BE11A7EE2DE286C1C27DC30260011819CB
+:1035B000E50209B90A2992A36890082A220009AAFB
+:1035C0000C65A10326E2856460FD2C20668931B17B
+:1035D000CC0C0C472C24666FC60270960C8A162BF6
+:1035E0002104580C86C0D02D24668E3077E74D1C00
+:1035F000E5021BE5028F328833C0A42D21040E9909
+:103600004006991104DD1109DD029A61C19009DDBE
+:10361000029B60C0908B2B9D649F66986799650C98
+:10362000BB029B6228200C1AE4EBAA8A0C8811A723
+:10363000882F828529A4CF2FFC202F86858A1465A8
+:10364000A0A6C020D10FB0FC8B142C2523C8B70234
+:103650002A02066B02580CB82A210265AEF7C0D8C0
+:103660000DAD022D250263FEEC008E14C8E8DA20B1
+:10367000DB30580CB12A210265AEDA07AF022F25E4
+:103680000263FED100DA20DB308C158D14580E5504
+:10369000D2A0D10FDA202B200C580DC063FEB6004B
+:1036A000DA202B200C580DE263FEAADA20DB308CE6
+:1036B000152D12042E0A80280A00282468580CB000
+:1036C00063FAE500C020D10FDA20580DB48914CD7B
+:1036D00092DA20DB308C15580D1FDBA0C020C0A073
+:1036E0002AB403D10FC020D10F2A2C748B15580691
+:1036F00028D2A0D10F0000006C100C2821029410D9
+:1037000008084C6583621FE4AB29F29E6F98026043
+:1037100003661DE4A729D2266890082A220009AA78
+:103720000C65A3542CF29D64C34E2B200C0CB611D7
+:10373000AF66286286C1EC78E30260034619E49E16
+:1037400009B90A2992A36890078A2009AA0C65A3DF
+:103750003224628564432CC0E12A3109C0702724D9
+:103760006689359A11992A88369912982B89379843
+:1037700013992C883899140858149815982D89395C
+:103780002A25042E251D29251C283028C0922824EE
+:103790003C2A302908084798160989012A243D2A1D
+:1037A000311599170A094109A90C299CEC29251FF3
+:1037B0007E87192D2A000DA06000083E010A3EB147
+:1037C000AD08DA390EAA110A990C29251F2A211FE2
+:1037D00018E4A80A8160C1D0941A951B01083E0024
+:1037E000053EB184054839843C259CFC0D8836296A
+:1037F000201408AA1C8D3D2726182E26132E2614C9
+:103800002E261527261B2E246B27246727246808BD
+:10381000581C0909432924142932112A252E282548
+:103820002F27252427252527252C27252325252037
+:103830002425212D2522841A2D211C851B6FD202BF
+:10384000600209C0A099186D080AB1AA00A104007D
+:10385000E91A7D9B0263FFEE8918C080C0E1C07049
+:10386000C0D29B1D951B961C9C1E16E4722C203DFD
+:1038700015E4820C0B400DCC010BE7381DE4640A03
+:1038800077100CE8380B8810C0C49C410877029D63
+:1038900040B0A80988118B209C499D48954B9643C0
+:1038A000087702861418E47315E45A08770205BBFA
+:1038B000029B4A9B4297468812871108DA149A4E57
+:1038C0000D88100D77110877021AE44E06D8140DF2
+:1038D0006610087702974FC78F984D984C98458788
+:1038E0001598440715140D55110A5502954715E40E
+:1038F000638A262D46102D46182D46202C46112C65
+:1039000046192C46212B46122B461A2846142846C7
+:10391000152B462288162546242546268B170A0C89
+:1039200048090D4885130EDD1105CC110839400BEF
+:10393000EB390299101EE4520DCC020D5511082DE1
+:10394000400655022E461316E41D0FDD11254616BE
+:10395000080840851B0188100DBB0286671DE449DD
+:103960000988020CBB0219E4191CE4472B46172DE9
+:10397000461BA7661BE446C0702C461C0988028CB7
+:103980001E28461E2B4623C0908B1D29461D294606
+:103990001F18E43F2946272846252931162E2006E0
+:1039A00029246A243117962D242538861CCCE1273A
+:1039B0002407C0D7090E4064E0829A29092841648F
+:1039C000809164409B2D2406C098094936280AA09E
+:1039D00024628501C404A84428210424668508883B
+:1039E000118E3F8A3E2D32100EA41800C4040EAE74
+:1039F0001800EE110ACA530EDD02C0E30E880298C9
+:103A0000C11EE42409084E9EC08E2094C398C59D13
+:103A1000C418E3F01DE42105EE110EAA020DAA025E
+:103A2000A8B82784CF9AC21EE3E224F29D27E4A21D
+:103A3000244C1824F69D655052C020D10F2D240629
+:103A4000C0A0C09809493604A93863FF7FC0A063AD
+:103A5000FE070000654F6DC098C0A82A240663FFCA
+:103A60006B2D2406C09063FF63CC57DA20DB308CCB
+:103A700010580C38C020D10F00DA20C0B6580CC73F
+:103A800063FFE500DA20580CC563FFDC2A2C748B39
+:103A90001058053FD2A0D10F6C10062820068A339B
+:103AA0006F8202600161C05013E3C229210216E354
+:103AB000C1699204252502D9502C20159A2814E3B7
+:103AC000BF8F2627200B0AFE0C0477092B711C647C
+:103AD000E1398E428D436FBC0260016F00E104B09A
+:103AE000C800881A08A80808D80298272B2006685A
+:103AF000B32ECE972B221E2C221D0111027BC90151
+:103B0000C0B064B0172CB00728B000DA2003880AD0
+:103B100028824CC0D10B8000DBA065AFE7C020D16C
+:103B20000F2D206464DFCA8B29C0F10BAB0C66BF7C
+:103B3000C02B200C0CBC11A6CC28C2862E0A0878FB
+:103B4000EB611EE39D0EBE0A2EE2A368E00528226B
+:103B5000007E894F29C2851EE3A96490461FE3B603
+:103B60009E90C084989128200A95930F880298927D
+:103B70008E200FEE029E942F200788262F950A98FC
+:103B8000969A972E200625240768E3432921022AC6
+:103B9000C2851DE3902AAC20ADBD25D4CF2AC685B1
+:103BA00063FF4E002E2065CBEDC082282465C9F648
+:103BB00005E4310002002A62821BE3982941020BCE
+:103BC000AA022A668209E43129210263FF23000048
+:103BD00064DFB88F422E201600F1040DEE0C00EECB
+:103BE0001AAEAE9E2963FFA38A202B3221B1AA9A76
+:103BF000B0293221283223B4992936217989A92B79
+:103C000032222B362163FFA0C020D10F9F2725240D
+:103C100015ACB828751C2B2006C0C12EBCFE64E074
+:103C2000AB68B7772DBCFD65DEC72D2064C0F0649E
+:103C3000D0868E290EAE0C66E089C0F128205A2865
+:103C40008CFE08CF3865FEE863FF580000E004935F
+:103C500010C0810AF30C038339C78F08D80308A862
+:103C60000108F80C080819A83303C80CA8B828756F
+:103C70001C030B472B24158310CBB700E104B0BC09
+:103C800000CC1AACAC0CDC029C27659E5EC0B20B6B
+:103C9000990209094F29250263FE50002D206A0D63
+:103CA0002D4165DF7EDA20C0B0580C8F64AF18C09C
+:103CB000F163FEEF9F2763FFD02E221F65EE326374
+:103CC000FF79000028221F658E2763FF6E252406DA
+:103CD00029210263FE1B00006C10066571332B4C1A
+:103CE00018C0C7293C18C0A1C08009A838080842DC
+:103CF0006481101CE32C1AE32D2AC67E2A5CFDD3B6
+:103D00000F6DAA0500B08800908C8940C0A009887A
+:103D1000471FE355080B47094C50090D5304DD10AC
+:103D2000B4CC04CC100D5D029D310CBB029B3088DD
+:103D3000438E2098350FEE029E328D26D850A6DD98
+:103D40009D268E40C0900E5E5064E0971CE33B1EA3
+:103D5000E32B038B0BC0F49FB19EB02D200A99B3C7
+:103D60000CDD029DB28F200CFF029FB48E262D2009
+:103D7000079EB68C282DB50A9CB72924072F20064C
+:103D80002B206469F339CBB61DE30D2320168DD2A9
+:103D90000B330C00D10400331AB48DA3C393292232
+:103DA000200C13E30C1FE3030C2E11AFEEA322290A
+:103DB00024CF2FE285D2A00FDD0B2DE685D10F0099
+:103DC0002E200CB48C0CEB111FE3031DE2FAAFEEB6
+:103DD000ADBB22B28529E4CF02C20B22B685D2A0A8
+:103DE000D10F00002E200C1CE2F31FE2FA0CEB11A5
+:103DF000AFEEACBB22B28529E4CF02820B22B6859E
+:103E0000D2A0D10FC0D00BAD387DC80263FEEC63E9
+:103E1000FEE08E40272C747BEE12DA70C0B32C3C8F
+:103E200018DD50580A868940C08063FEE3066E02A2
+:103E3000022A02DB30DC40DD505800049A10DB50CF
+:103E4000DA70580453881063FEF700006C10069275
+:103E5000121EE2E48C40AE2D0C8C472E3C1804CA96
+:103E60000BD9A07DA30229ADF875C302600084C000
+:103E7000B0C023C0A09D106D0844B89F0EB80A8D35
+:103E8000900EB70BB8770D6D36ADAA9D800D660C00
+:103E9000D8F000808800708C879068B124B22277B7
+:103EA000D3278891C0D0CB879890279C100070882A
+:103EB00000F08C9D91CB6FC08108BB0375CB36633E
+:103EC000FFB4B1222EEC1863FFD485920D770C86D7
+:103ED000939790A6D67D6B01B1559693959260000D
+:103EE00016B3CC2D9C188810D9D078D3C729DDF80B
+:103EF00063FFC100C0238A421BE2E900CD322D449A
+:103F0000029B3092318942854379A1051EE2E50E7C
+:103F1000550187121BE2D5897095350B99029932AC
+:103F200088420A880C98428676A6A696768F44AF79
+:103F3000AF9F44D10F0000006C10089311D6308859
+:103F400030C0910863510808470598389812282115
+:103F500002293CFD08084C6581656591628A630A07
+:103F60002B5065B18B0A6F142E0AFF7CA60A2C20F9
+:103F70005ACCC42D0A022D245A7FE0026002158912
+:103F80002888261FE2C809880C65820F2E200B0F97
+:103F9000EE0B2DE0FE2EE0FF08DD110EDD021EE22D
+:103FA000C2AEDD1EE2C21CE2C20EDD010DCC37C185
+:103FB00080084837B88DB488981089601AE2807BF1
+:103FC00096218B622AA0219C147BA3179D132A2083
+:103FD0000C8B108C20580BB18C148D13DBA0CEAC45
+:103FE0006001C4002E200C1BE2730CEA110BAA081E
+:103FF0002BA2861FE2717BDB3B0FEF0A2FF2A36837
+:10400000F0052822007F892C2BA28564B0AA876244
+:104010008826DE700C7936097A0C6FAD1C8F279BD1
+:104020001508FF0C77F3197E7B729D139C149B156A
+:10403000CF56600025C0B063FFD0D79063FFDD008E
+:10404000009D139C14DA20DB70580B168B158C1412
+:104050008D1365A06A8E6263FFCC00DA208B11DCC1
+:1040600040580ABCD6A08B15C051DE70DA20DC6047
+:10407000DD405BFF768D138C14D9A02E200C1BE243
+:104080004D1FE2540CEA11AFEFC0E0ABAA2BA285A2
+:104090002EF4CF0B990B29A68563FF1D00DA20DCD7
+:1040A00060DD40DE708912282007DF50A9882824AF
+:1040B000075BFF09D2A0D10F00DBE0DA20580B37F5
+:1040C0006550EF2A20140A3A4065A0EBDB60DC4023
+:1040D000DD30022A025809A7D6A064A0D584A183A6
+:1040E000A00404470305479512036351C05163FEC2
+:1040F0005C2C2006D30F28CCFD6480A568C704C0C3
+:10410000932924062C2006C0B18D641FE22C9D2724
+:104110009D289D298FF29D2600F10400BB1A00F016
+:1041200004B0BE0EDD01C0F0ADBB8D652F24070DC0
+:104130000E5E01EE11AEBB2E0AFEB0BB0B0B190ECC
+:10414000BB36C0E20B0B470EBB372B241618E224FC
+:104150000A09450D0B422B240B29240AB4BE2E2438
+:104160000C7D88572920162FCCFDB09D0A5C520D7E
+:10417000CC362C246465FDEC0C0C4764CDE618E2CB
+:104180000F8E2888820C9F0C00810400FF1AAFEE6E
+:104190009E2963FDCF1CE23E63FE13001CE23563E3
+:1041A000FE0C8D6563FFA500DA202B200C580B2038
+:1041B000645F0FC020D10F00C020D10FC09329240D
+:1041C00016C09363FFA000006C1004C06017E1F8F4
+:1041D0001DE1FBC3812931012A300829240A78A175
+:1041E00008C3B27BA172D260D10FC0C16550512605
+:1041F00025022AD0202F200B290AFB2B20142E2049
+:104200001526241509BB010DFF0928F11C2B2414C8
+:10421000A8EE2EF51C64A0A92B221E28221D011138
+:10422000027B8901DB6064B0172CB00728B000DA8C
+:104230002007880A28824CC0D10B8000DBA065AF24
+:10424000E7DB30DC40DD50DA205800DE29210209AE
+:104250000B4CCAB2D2A0D10F00CC5A2C30087BC173
+:10426000372ED02064E02D022A02033B02DC40DD21
+:10427000505800D4D2A0D10F2B2014B0BB2B241443
+:104280000B0F4164F0797CB7CAC0C10C9C022C258D
+:1042900002D2A0D10FC020D10F2E200669E2C12684
+:1042A00024062B221E2F221D29200B2820150D99B4
+:1042B000092A911C262415AA8828951C7BF149609F
+:1042C0000048B0BB2B24140B0A4164A0627CB702E7
+:1042D0002C25022B221E2C221DD30F7BC901C0B01E
+:1042E000C9B62CB00728B000DA2007880A28824C0B
+:1042F000C0D10B8000DBA065AFE7C020D10F00006C
+:10430000262406D2A0D10F0000DB601DE1AC64BF03
+:104310004F2CB00728B000DA2007880A28824CC04A
+:10432000D10B8000DBA065AFE71DE1A463FF310086
+:1043300026240663FF9C00006C1004282006260A31
+:10434000046F856364502A2920147D9724022A0271
+:10435000DB30DC40DD50580019292102090A4CC825
+:10436000A2C020D10FC0B10B9B022B2502C020D1CF
+:104370000F00022A02033B022C0A015800D1C9AAED
+:10438000DA20DB30DC405809F329A011D3A07E9756
+:10439000082C0AFD0C9C012CA411C0512D201406E0
+:1043A000DD022D241463FFA4DA20DB30DC40DD5075
+:1043B000C0E0580973D2A0D10F0000006C1006169F
+:1043C000E17D1CE17D655157C0E117E179282102AB
+:1043D0002D220008084C6580932B32000B6951296F
+:1043E0009CFD6590872A629E6EA84C2A722668A062
+:1043F000027AD9432A629DCBAD7CBE502B200C0C97
+:10440000BD11A6DD28D2862F4C0478FB160CBF0AFE
+:104410002FF2A368F0052822007F89072DD285D3CB
+:104420000F65D0742A210419E1A3D30F7A9B2EDAE9
+:104430002058086E600035002D21041BE19E7DBBD5
+:1044400024DA20C0B6580869CA546001030B2B5007
+:104450002B240BB4BB0B0B472B240C63FFA0DA20DF
+:10446000580A4E600006DA20C0B6580A4C6550E083
+:10447000DC40DB302D3200022A020D6D515808BDA0
+:104480001CE14ED3A064A0C8C05184A18EA0040436
+:10449000470E0E4763FF3500002B2104C08C893185
+:1044A000C070DF7009F950098F386EB8172C20667C
+:1044B000AECC0C0C472C24667CFB099D105808CF11
+:1044C0008D1027246694D11EE151B8DC9ED0655032
+:1044D00056C0D7B83AC0B1C0F00CBF380F0F42CBAE
+:1044E000F119E13018E13228967EB04BD30F6DBA46
+:1044F0000500A08800C08C2C200CC0201DE1360CCB
+:10450000CF11A6FF2EF285ADCC27C4CF0E4E0B2EB9
+:10451000F685D10FC0800AB83878D0CD63FFC100CE
+:104520008E300E0E4763FEA12A2C742B0A01044D17
+:10453000025808C22F200C12E1270CF911A699A2EB
+:10454000FF27F4CF289285D2A008480B289685D162
+:104550000FC020D10F0000006C1004C060CB55DBF1
+:1045600030DC40055D02022A025BFF94292102092A
+:10457000084CC882D2A0D10F2B2014B0BB2B24141E
+:104580000B0C41CBC57DB7EBC0C10C9C022C2502A6
+:10459000D2A0D10F0000022A02033B02066C02C027
+:1045A000D0C7F72E201428310126250228240A0F0F
+:1045B000EE012E241458010E63FFA300262406D218
+:1045C000A0D10F006C1006282102D62008084C65E7
+:1045D000809D2B200C12E0F70CB811A2882A82864D
+:1045E000B5497A930260009719E0F409B90A299253
+:1045F000A36890082A620009AA0C65A08228828517
+:104600001CE0FF6480799C80B887B14B9B819B1034
+:10461000655074C0A7D970280A01C0D0078D380D25
+:104620000D42CBDE1FE0E01EE0E12EF67ED830D357
+:104630000F6D4A0500808800908C2E3008C0A000C5
+:10464000EE322E740028600C19E0E30C8D11A2DD0F
+:10465000A988C0202CD2852284CFD2A00CBC0B2CE0
+:10466000D685D10FC0F0038F387FA0C063FFB400A0
+:10467000CC582A6C74DB30DC405807F6C020D10FD0
+:10468000DA605809C663FFE7DD402A6C74C0B0DC0D
+:104690007058086A2E30088B1000EE322E740028F5
+:1046A000600C19E0CC0C8D11A2DDA988C0202CD2A1
+:1046B000852284CFD2A00CBC0B2CD685D10F000054
+:1046C0006C1004292014282006B19929241468812B
+:1046D00024C0AF2C0A012B21022C24067BA004C08D
+:1046E000D02D2502022A02033B02044C02C0D058FE
+:1046F00000C0D2A0D10FC020D10F00006C1004293F
+:104700003101C2B429240A2A3011C28378A16C7BFA
+:10471000A1696450472C2006C0686FC562CA572D36
+:1047200020147CD722DA20DB30DC40DD505BFFA593
+:10473000292102090E4CC8E2C020D10FC0F10F9F01
+:10474000022F2502C020D10FDA20DB30C0C05BFF72
+:10475000DC28201406880228241463FFC7292015AA
+:104760001BE0972A200BC0C09C240BAA092BA11C7C
+:104770002C2415AB9929A51C63FF9900C020D10FEB
+:10478000DA20DB30DC40DD50C0E058087DD2A0D11B
+:104790000F0000006C1004CB5513E09225221F0D72
+:1047A000461106550CA32326221E25261F06440B60
+:1047B00024261E734B1DC852D240D10F280A80C038
+:1047C0004024261FA82828261E28261DD240D10FA7
+:1047D000C020D10F244DF824261E63FFD80000000E
+:1047E0006C1004D620282006C0706E85026000D4AC
+:1047F0001DE07919E07112E06F2A8CFC64A1302B66
+:104800006102B44C0B0B4C65B0A22B600C8A600C9F
+:10481000B8110288082E828609B90A7EC302600098
+:104820009A2992A368900509AA0C65A08E28828512
+:10483000648088B8891BE07594819B80655155C060
+:10484000B7B8382A0A01C0C009AC380C0C4264C0A1
+:10485000421FE0541EE0562EF67EB04AD30F6DAADA
+:104860000500808800908CC0A029600C0C9C11A2CF
+:10487000CC2BC285AD990B4B0B2BC6852860062728
+:1048800094CF6881222D6015D2A0C9D2C0E22E64D7
+:1048900006D10F00C0F008AF387FB0BD63FFB10094
+:1048A000276406D2A0D10F00D2A0D10F00CC57DAD6
+:1048B00060DB30DC405808A7C020D10FDA6058090F
+:1048C0003763FFE80028221E29221DD30F789901A3
+:1048D000C080C1D6C1C11BE043C122AB6B64804222
+:1048E00078913F2A80000CAE0C64E0BB02AF0C64F0
+:1048F000F0B52EACEC64E0AF0DAF0C64F0A92EACBB
+:10490000E864E0A32FACE764F09D2EACE664E0978A
+:104910002F800708F80BDA807B83022A8DF8D8A055
+:1049200065AFBC28612308D739D97060007B0000CF
+:104930002B600C0CB811A2882C82862A0A087CAB4A
+:104940007E09BA0A2AA2A368A0052C62007AC96F60
+:104950002A828564A0691FE029276504C0E3C0C4DA
+:104960002E64069CA11CE0549FA02E600A97A30C05
+:10497000EE029EA28F600CFF029FA42E60147AEFBD
+:104980004627A417ADBC2F828527C4CF2FFC202F2C
+:10499000868563FE692A6C74C0B1DC90DD405807DF
+:1049A000A71DE00C63FEC100D9A0DA60DB30C2D0E5
+:1049B000C1E0DC4009DE39DD505807F1D2A0D10F4B
+:1049C000DA605808F663FEE4290A0129A4170DBF2E
+:1049D000082E828527F4CF2EEC202E868564500B7E
+:1049E0002A6C74DB4058016AD2A0D10FC020D10FCD
+:1049F0006C10062B221E28221D93107B8901C0B04B
+:104A0000C0C9C03BC1F20406401DDFF6C0E2C0745D
+:104A10000747010E4E01AD2D9E11C0402E0A1464B1
+:104A2000B06E6D084428221D7B81652AB0007EA1EE
+:104A30003B7FA1477B51207CA14968A91768AA1434
+:104A400073A111C09F79A10CC18B78A107C1AE29B8
+:104A50000A1E29B4007CA12B2AB0070BAB0BDAB0DD
+:104A60007DB3022ABDF8DBA0CAA563FFB428B0104D
+:104A700089116987BB649FB863FFDC00647FB463FE
+:104A8000FFD50000646FD0C041C1AE2AB40063FFFF
+:104A9000C62B2102CEBE2A221D2B221E7AB12A8CC1
+:104AA000107CB1217AB901C0B0C9B913DFC1DA20D5
+:104AB00028B0002CB00703880A28824CC0D10B8094
+:104AC00000DBA065AFE7D240D10F8910659FD463AA
+:104AD000FFF300006C1008C0D0C8598C30292102A7
+:104AE0000C0C4760000C8E300E1E5065E19E292193
+:104AF00002C0C116DFB0090B4C65B0908A300A6E57
+:104B00005168E3026000852F629E1BDFA96EF85397
+:104B10002BB22668B0052E22007BE94727629DB79D
+:104B200048CB7F97102B200CB04E0CBF11A6FF294D
+:104B3000F2869E12798B4117DFA007B70A2772A36E
+:104B4000687004882077893029F285DF90D79065D6
+:104B500090652A210419DFD77A9B22DA205806A310
+:104B6000600029002C21041BDFD37CBB18DA20C095
+:104B7000B658069EC95860014CC09063FFCCDA203D
+:104B8000580886600006DA20C0B65808846551359A
+:104B9000DC40DB308D30DA200D6D515806F6C0D088
+:104BA000D3A064A120292102C05184A18CA00404B7
+:104BB000470C0C4763FF3E00C09C8831DBD008F8EF
+:104BC00050089B3828210498116E8823282066AC51
+:104BD0008C0C0C472C24667CBB159F139E148A10EA
+:104BE0008B115807068E148F13C0D02D24668A307F
+:104BF000C092C1C81BDF867FA6099BF099F12CF4F7
+:104C00000827FC106550A4B83ADF70C051C0800777
+:104C1000583808084264806718DF6319DF64298602
+:104C20007E6A420AD30F6DE90500A08800F08CC0AF
+:104C3000A08930B4E37F9628C0F207E90B2C9408D2
+:104C40009B909F912F200C12DF630CF811A68829EE
+:104C50008285A2FF2DF4CFD2A009330B238685D104
+:104C60000F22200C891218DF5B0C2B11A6BBA82287
+:104C70002D24CF2CB285D2A00C990B29B685D10F4B
+:104C8000C087C0900A593879809663FF8ADB30DA92
+:104C900020C0C1C0D05BFF56292102C0D02A9CFE93
+:104CA00065AE4D2D2502C09063FE45009E142A2C52
+:104CB00074C0B1DC70DD405806E18E14C0D01BDF3B
+:104CC00053C1C863FF6AC020D10F00006C100628D2
+:104CD000210216DF3808084C65821929629E6F98F8
+:104CE0000260022019DF332992266890078A200982
+:104CF000AA0C65A20F27629DC0CC6472072B210409
+:104D00008E31C0A0DDA00EFE500ECD386EB8102C36
+:104D10002066B1CC0C0C472C24667CDB026001EFD2
+:104D2000C0C12930081BDF2564909C2F0AFFC0D327
+:104D3000B09E64E1026892136450882A2C74044B7C
+:104D4000025800930AA20206000000002B200C2744
+:104D500021040CBC11A6CC29C286280A087983023A
+:104D60006001B919DF1509B90A2992A36890082EC4
+:104D7000220009EE0C65E1A42EC28564E19E262086
+:104D80000713DF1E6E7B0260019A17DF151FDF1EFF
+:104D900019DF4BC0D228200A93E09DE1A9690F8852
+:104DA0000298E22F90802A9480B1FF07FF029FE3D0
+:104DB0002EC2851FDF080EDE0BAFBF2AF4CF2EC632
+:104DC00085655F76C020D10F2830102930112E3034
+:104DD0001300993200ED326480EE2A30141FDF3860
+:104DE00000AA3278EF050F9E092DE47F1EDF36669C
+:104DF000A0050F98092A8480B4A718DF33C76F0075
+:104E00009104AE9EDDE000AF1A00C31A6EE1052DDD
+:104E1000B2000DED0C1EDF2D08D81C063303AE8842
+:104E20002A848B2EB02E27848C03EE010FEE022EE7
+:104E3000B42E58018F63FEFF29310829250428303C
+:104E4000142E3109B0886480A32E240AC0812E302C
+:104E5000162CB4232E240BB4EF2F240C8C378B3656
+:104E6000292504DEB0DFC00C8F390B8E390FEE021E
+:104E700064EEC4089F1101C4048D380CB81800C436
+:104E8000040CBE1800EE110EDD02C0E30EFF021E80
+:104E9000DF019F719E701EDF008F2098739D740547
+:104EA000FF110BCD53C18098750FDD020EDD029D01
+:104EB000721EDEBF2A24662F629D2AE4A22FFC18F0
+:104EC0002F669D63FE710000002F30121BDF010072
+:104ED000FA3278FF050B980B2A847F66D0050B9A6F
+:104EE0000B2DA4802A301100AA3263FF442F240A1C
+:104EF0009E2B63FF56CC57DA20DB30DC4058071579
+:104F0000C020D10F00DA20C0B65807A463FFE50027
+:104F1000DA7058063AC0A02A246663FE02DA2058E6
+:104F2000079F63FFCFB16928200A862009094799A6
+:104F30001129240798107F812693E027E50A9AE338
+:104F400088109DE119DEDD8D11096F029FE42DE4CB
+:104F500016098802C0D398E22A240763FE51000094
+:104F60001DDEA60868118F11892B93E008FF02C08F
+:104F70008F9FE50D990299E2047F11C0D49DE1084D
+:104F8000FF029FE463FFD0006C1004C020D10F002B
+:104F90006C100485210D381114DE848622A42408A7
+:104FA000660C962205330B9321743B13C862D230F2
+:104FB000D10FC030BC29992199209322D230D10F32
+:104FC000233DF8932163FFE36C100AD62094181751
+:104FD000DE79D930B83898199914655252C0E1D2A7
+:104FE000E02E61021DDE760E0E4C65E1628F308E82
+:104FF000190F6F512FFCFD65F1558EE129D0230E5D
+:105000008F5077E66B8F181EDEB3B0FF0FF4110FD1
+:105010001F146590CE18DEB08C60A8CCC0B119DE2C
+:105020006428600B09CC0B0D880929811C28811A82
+:105030002A0A0009880C08BA381BDEA60CA90A291E
+:1050400092947B9B0260008C2B600C94160CBD111B
+:10505000A7DD29D286B8487983026000D219DE56CE
+:1050600009B80A2882A398176880026000A360002C
+:10507000A51ADE9A84180AEE01CA981BDE4D8C1917
+:105080002BB0008CC06EB3131DDE4A0C1C520DCC2D
+:105090000B2DC295C0A17EDBAE6000380C0C5360B6
+:1050A000000900000018DE8C8C60A8CCC0B119DEAD
+:1050B0004028600B09CC0B0D880929811C28811A16
+:1050C0002A0A0009880C08BA380CA90A2992947E89
+:1050D000930263FF72DA60C0BA580730645073609D
+:1050E000026600001ADE338C192AA0008CC06EA361
+:1050F0001A18DE2F0C1C5208CC0B18DE762BC2952A
+:10510000C0A178B30263FF3F63FFC9000C0C536377
+:10511000FF09896078991829D285C9922B729E1D42
+:10512000DE246EB8232DD226991369D00B60000DB2
+:10513000DA6058071A6000170088607D890A9A1A99
+:1051400029729D9C129915CF95DA60C0B658071345
+:105150006551F58D148C18DBD08DD0066A020D6D6B
+:1051600051580584D3A09A1464A1DD82A085A1B80A
+:10517000AF9F190505470202479518C05163FE60AD
+:105180002B6104C08C8931C0A009F950098A386E9E
+:10519000B81F2C6066A2CC0C0C472C64667CAB114B
+:1051A0009F119E1B8A155805958E1B8F11C0A02A32
+:1051B00064669F1164F0E12912032812096DF91742
+:1051C0002F810300908DAEFE0080889F9200908C0E
+:1051D000008088B89900908C65514E8A10851A8B92
+:1051E000301FDE06881229600708580A2C82942D89
+:1051F00061040ECC0C2C86946FDB3C1CDE30AC9C26
+:1052000029C0800B5D50A29909094729C48065D047
+:10521000DA2E600CC0D01FDDEF0CE811AFEEA788CE
+:105220002282852DE4CF02420B228685D2A0D10FA7
+:105230008E300E0E4763FDA6A29C0C0C472C640713
+:105240007AB6CD8B602E600A280AFF08E80C6481CC
+:105250000E18DE1983168213B33902330B2C341661
+:105260002D350AC02392319F30C020923308B202FC
+:1052700008E80292349832C0802864072B600CD270
+:10528000A01CDDD40CBE11A7EE2DE285ACBB28B46A
+:10529000CF0D9D0B2DE685D10F8B1888138D30B85F
+:1052A0008C0D8F470D4950B4990499100D0D5F0472
+:1052B000DD1009FF029F800DBB029B8165508D852B
+:1052C0001AB83AC0F1C0800CF83808084264806B04
+:1052D0001BDDB519DDB629B67E8D18B0DD6DDA059A
+:1052E00000A08800C08CC0A063FEF30082138B1660
+:1052F0001DDDC628600AC0E02EC4800D880202B2FF
+:105300000B99239F20C0D298229D2122600CB2BB12
+:105310000C2D11A7DD28D28508BB0B18DDAE2BD6CE
+:1053200085A8222E24CFD2A0D10F9E1B851A2A6CCD
+:10533000748B185BFF178E1B63FEA300C087C090A1
+:105340000AF93879809263FF86C020D10F9E1B2A0C
+:105350006C74C0B18D185805398E1B851A63FE7E9A
+:10536000886B8213891608BE110ECE0202920B9E24
+:1053700025B4991EDDA19F200E88029822C0EF045B
+:10538000D8110E88029824C0E49E21C080D2A02BA0
+:10539000600C2864071CDD8F0CBE11A7EE2DE28582
+:1053A000ACBB28B4CF0D9D0B2DE685D10F000000BE
+:1053B0006C1004C020D10F006C10048633C071C083
+:1053C00030600001B13300310400741A04620174CA
+:1053D00060F1D10F6C1004022A02033B025BFFF65E
+:1053E0001CDD771BDDBFC79F88B009A903098A01AF
+:1053F0009AB079801EC0F00FE4311DDD6E0002000E
+:105400002BD2821EDDB82AC1020EBB022BD6820A25
+:10541000E431D10F28C102C19009880208084F2841
+:10542000C50208E431D10F006C1004C0C00CE43197
+:1054300012DD631ADD6000020029A28218DDAC1BB8
+:10544000DDAA2621020B990108660129A6822625DC
+:105450000206E43114DDA715DDA2236A902326128B
+:105460008550242611252613222C40D10F00000040
+:105470006C1008D6102B0A64291AB41ADD4D0D23BE
+:10548000111CDD4E0F2511B81898130E551118DD9B
+:1054900099AC55A838AA332C80FF2A80FEA933285E
+:1054A0008D0129800108AA112880000CAA02088811
+:1054B0001109880208AA1C288C08281604580862BA
+:1054C00014DD3F0AA7022441162A30802B1204075C
+:1054D000AA2858085DB1338B13B4559A6004AC28E0
+:1054E000B4662C56277B69E016DD769412C050C056
+:1054F000D017DD329D15D370D4102F60802E6082BE
+:105500009F169E17881672891A8D128C402A607F0A
+:105510000DCC282B3A200CAA2858084BC0B10ABE43
+:10552000372E35408F1772F91A8D128C402A608100
+:105530000DCC282B3A200CAA28580843C0B10ABE2B
+:10554000372E3542B233B444B1556952B6B466C051
+:10555000508F15B877D370B2FF9F156EF899D10FA1
+:105560006C1004C021D10F006C1004270A001CDD50
+:10557000111FDD221EDD251DDD0E1ADD501BDD5E37
+:10558000C02824B0006D2A75AA48288080C0916484
+:10559000806100410415DD09C03125502E00361A06
+:1055A0000655010595390C56110C66082962966E50
+:1055B000974D0D590A29922468900812DD42024243
+:1055C0000872993B23629512DD06CB349F3002822C
+:1055D000020E4402C092993194329233AD52246249
+:1055E00095C090244C1024669524B0002924A0AACC
+:1055F00042292480B177B14404044224B400D10F7D
+:10560000D10FD10F6C10041ADCEA2AA00058021C3A
+:105610005BFFD5022A02033B025BFFD11BDCE8C91A
+:10562000A12CB102C0D40DCC020C0C4F2CB5020C35
+:10563000E431D10FC0A00AE43118DCDE0002002FF3
+:10564000828219DCF12EB10209FF022F86820EE45C
+:1056500031D10F006C1004C02002E43114DCD816E4
+:10566000DCD5000200226282234102732F0603E48C
+:1056700031C020D10F19DD221ADD212841020A2A6A
+:10568000010988012A668228450208E43115DD18DF
+:1056900012DD1D25461DD10F6C1004292006289C03
+:1056A000F96480A02A9CFD65A0968A288D262F0A81
+:1056B000087AD9042B221FC8BD2C206464C0812E17
+:1056C00022090EAE0C66E0782B200C1EDCBA0CBC56
+:1056D00011AECC28C28619DCB878F3026000AD099F
+:1056E000B90A2992A36890082E220009EE0C65E001
+:1056F0009B29C2851FDCC26490929F90C0E41FDC8E
+:10570000CE9E9128200AC0E09E930F88029892882E
+:10571000200F880298942F20079A979D962F950A1C
+:105720002E240728200629206468833328C2851286
+:10573000DCA9288C20A2B22E24CF28C685C020D177
+:105740000FC020D10F2A206A0111020A2A4165AF39
+:1057500052DA20C0B05805E464AFE5C021D10F0093
+:10576000649FC81FDC962D20168FF209DD0C00F116
+:105770000400DD1AADAD9D2912DC9728C285A2B2C6
+:105780002E24CF288C2028C685C020D10FC021D13F
+:105790000F0000006C1004260A001BDCDB15DC8700
+:1057A00028206517DC84288CFE6480940C4D110D34
+:1057B000BD082CD2F52BD2F42ED2F77CB13DB4BB70
+:1057C0002BD6F47BE9052BD2F62BD6F47CB92C2A08
+:1057D000D2F62AD6F52AD6F406E431000200287261
+:1057E000822AFAFF004104290A012F510200991A66
+:1057F0000A99030988012876820FE4312624652B53
+:10580000D2F48E5A2CD2F5B0EE9E5A7BCB1629D20A
+:10581000F62FD2F70CB80C09FF0C08FF0C0F2F1451
+:10582000C8F96000320BCA0C0A2A14CEA92B510207
+:10583000C0C20CBB020B0B4F2B55020BE431D10F36
+:1058400000DB30DA205BFF941BDCB064AF5D0C4DF5
+:1058500011ADBD63FFA8000006E4310002002F7205
+:105860008218DC6E2E510208FF022F76820EE43180
+:10587000D10F00006C1004C03003E43116DC4E156B
+:10588000DC4F00020024628274472118DCA0875A92
+:10589000084801286682CD7319DC9E0C2A11AA994A
+:1058A0002292832992847291038220CC292B510267
+:1058B0000BE431C020D10F001FDC972E51020FEEF8
+:1058C000012E55020EE431B02DB17C9C5A12DC92AF
+:1058D00008DD112D5619D10F6C10061BDC351EDCAE
+:1058E0003722B0001ADC8E6F23721DDC75C0481899
+:1058F000DC8D1FDC8BDC10D5C083F000808600506F
+:105900008A6D4A4F0F35110D34092440800B560A19
+:10591000296294B1330E55092251400F44110C44B1
+:105920000A874009A80C02883622514107883608A8
+:10593000770CA8992966949740296295874109A810
+:105940000C02883607883608770CA899296695973F
+:1059500041030342B13808084298F0D10F1CDC72B1
+:1059600013DC7327B0002332B5647057C091C0D0E8
+:1059700016DC7115DC6FC0402AC00003884328C4C0
+:10598000006D793C004104B14400971A7780148E71
+:10599000502FB2952DB695AFEE2EED2006EE369E29
+:1059A0005060001877A00983509D5023B695600081
+:1059B0000223B295223D2006223622B695B455B870
+:1059C000BBD10F0003884328C400D10F6C1004C062
+:1059D0004004E43115DC59000200885013DC58CB38
+:1059E000815BFFBD1CDC570C2D11ADCC2BC2822A74
+:1059F000C28394507BAB142EC28429C2850ABD0C8D
+:105A00000E990C0D990C0929146000050BA90C09BD
+:105A10002914993015DBEA2A51020AE4312A2CFCB8
+:105A200058004B2B32000AA2022BBCFF9B30CCB695
+:105A3000C8A4D2A0D10F000004E4311EDBDE0002B6
+:105A4000002DE2822FBAFF2C51020FDD012DE682DC
+:105A50000CE431D10F0000006C1004D10F000000E5
+:105A60006C1004C020D10F006C100413DC36C0D1C0
+:105A700003230923318DC0A06F340260008D19DB30
+:105A8000CD1BDBCE17DC2F0C2811A87726728325BF
+:105A900072822CFAFF76514788502E7285255C045D
+:105AA00025768275E9052572842576827659292E18
+:105AB00072842E76822E76830AE4310002002392CD
+:105AC000820021042FB10200D61A0C6603063301AE
+:105AD0002396820FE43126728325728260000200D1
+:105AE000D8A07659220AE4310002002392820021D4
+:105AF0000400D21A2FB1020C220302320122968234
+:105B00000FE431D280D10F00D280D10FC020D10F4D
+:105B10006C1004DB30862015DBA6280A002825023D
+:105B2000DA2028B0002CB00705880A28824C2D0AFC
+:105B3000010B8000DBA065AFE61ADB9F0A4A0A2949
+:105B4000A2A3C7BF769101D10F2BA6A3D10F00004E
+:105B50006C1004C0D1C7CF1BDB9919DB9617DB94FF
+:105B60000C2811A87786758574C0A076516288507C
+:105B70008E77B455957475E90385769574765927B3
+:105B80008F769F759F740AE431000200239282B4DD
+:105B90002E2FB10200E10400D61A0C660306330171
+:105BA0002396820FE431867583747639280AE431AE
+:105BB0000002002E9282B42200210424B10200DFF0
+:105BC0001A0CFF030FEE012E968204E431D280D12D
+:105BD0000FD8A07651D6D280D10F00006C100429C6
+:105BE0000A801EDB9A1FDB9A1CDB730C2B11ACBBEB
+:105BF0002C2CFC2DB2850FCC029ED19CD0C051C064
+:105C00007013DB9614DB9518DB932AB285A8280461
+:105C1000240A234691A986B8AA2AB685A98827848A
+:105C20009F25649FD10F00006C100419DBC70C2A5C
+:105C300011A9A98990C484798B761BDBB5ABAC2AFA
+:105C4000C2832CC2847AC1688AA02BBC30D3A064E2
+:105C5000A05E0B2B0A2CB2A319DB7F68C0071DDBEB
+:105C6000BBD30F7DC94AA929299D0129901F68919D
+:105C70003270A603D3A0CA9E689210C7AF2AB6A3FB
+:105C80002A2CFC5BFFB3D230D10F000013DBB10331
+:105C9000A3018C311DDB510C8C140DCC012CB6A34F
+:105CA00063FFDC00C020D10FDA205BFFCCC020D125
+:105CB0000FC020D10F0000006C1004DB30C0D019E1
+:105CC000DB3CDA2028300022300708481209880A15
+:105CD00028824CDC200B80001BDB370C4A11ABAA5E
+:105CE00029A28409290B29A684D10F006C1004C0B5
+:105CF0004118DB3017DB320C2611A727277030A89C
+:105D000066256286007104A35500441A7541482235
+:105D1000628415DB5202320BC922882117DB2F085F
+:105D20008414074401754905C834C020D10FD10F30
+:105D30000809471DDB86C0B28E201FDB1D0E0E43F7
+:105D4000AFEC2BC4A00FEE0A2DE6242A6284C020FB
+:105D50000A990B296684D10FC020D10F6C1004DB87
+:105D600030C0D018DB13DA20253000223007085865
+:105D70000A28824CDC200B80008931709E121BDBCC
+:105D80000D0C4A11ABAA29A28409290B29A684D19A
+:105D90000F09C95268532600910418DB08C0A12FCF
+:105DA000811200AA1A0AFF022F85121EDB020C4D77
+:105DB00011AEDD2CD2840C2C0B2CD684D10FC081DB
+:105DC0001FDAFFB89A0A0A472EF11200A1040088D0
+:105DD0001A08EE022EF5121DDAF70C4C11ADCC2B81
+:105DE000C2840B2B0B2BC684D10F00006C1004DB7C
+:105DF00030C0D019DAEFDA202830002230070988C5
+:105E00000A28824CDC200B80001CDAEA0C4B11AC17
+:105E1000BB2AB2840A2A0B2AB684D10F6C1004C0A4
+:105E20004118DAE416DAE60C2711A626266030A817
+:105E300072252286006104A35500441A7541082288
+:105E4000228402320BD10F00C020D10F6C10041538
+:105E5000DB410249142956112452120208430F88CB
+:105E600011C07300810400361A008104C78F0077C7
+:105E70001A087703074401064402245612D10F0082
+:105E80006C10066E23026000AC6420A7C0A08510D1
+:105E900013DB1916DB30C040A6AA2BA2AE0B1941AA
+:105EA00064906668915D68925268933C2AA2AA2821
+:105EB0003C7F288C7F0A0A4D2980012880002AAC6B
+:105EC000F20888110988027589462B3D0129B00026
+:105ED0002BB0010899110B99027A9934B8332A2A08
+:105EE00000B1447249B160004A7FBF0715DB1B63F4
+:105EF000FFB90000253AE863FFB10000253AE863E6
+:105F0000FFA90000250A6463FFA1C05A63FF9C003B
+:105F100000705F082534FF058C142C34FE70AF0B25
+:105F20000A8D142E3D012AE4012DE400DA405BFDC8
+:105F30005063FFA7D10FD10F6C10041ADAA019DA41
+:105F40009D1CDB061BDB07C080C07160000D0000DC
+:105F50000022A430B1AA299C107B915F26928679F9
+:105F6000C2156E6262C0206D080AB12200210400D1
+:105F7000741A764BDB63FFEE2292850D63110325C5
+:105F800014645FCFD650032D436DD9039820B422FB
+:105F90000644146D49229820982198229823982429
+:105FA00098259826982798289829982A982B982CED
+:105FB000982D982E982F222C4063FF971EDA7E276B
+:105FC000E68027E681D10F00C02063FF8300000038
+:105FD0006C1004C062C04112DA791ADA7513DAE182
+:105FE0002AA00023322D19DADB2BACFE2992AE6EEB
+:105FF000A30260008E090E402D1AC2C2CD0EDC39FC
+:106000002C251664B0895BFF9E15DAD71ADAD12BDE
+:106010003AE80A3A0158058C2B21160ABB28D3A06E
+:106020009B505805A32B52000ABB082A0A005805AA
+:10603000A215DACE2D21022C3AE80C3C2804DD0210
+:106040002D25029C5058059A8B50AABBC0A158051B
+:106050009A1CDAC72D21020C3C2806DD0213DAC592
+:106060002D25029C305805928B30AABBC0A2580542
+:10607000922A2102C0B40BAA020A0A4F2A2502580A
+:1060800005A6D10F242423C3CC2C251663FF76004C
+:1060900018DABD1CDAB919DABA1BDAB817DA8B8547
+:1060A000202E0AFD1FDAB92D202E24F47A24F47E46
+:1060B00024F4820EDD0124F4862E0AF70755280603
+:1060C000DD02C0750EDD01050506AB5BA959C0E810
+:1060D000AC5C24C4AB0EDD0227C4AC2E0ADFA8558D
+:1060E00027B4EC0EDD0124B4EBC2E027942C0EDDC6
+:1060F0000224942B2E0A800D0D4627546C24546BD9
+:106100000EDD022D242E63FEFC0000006C10042A1C
+:106110000A302B0A035BFF4D12DA8FC39029261633
+:10612000C3A1C0B3C08A2826175BFF48C03CC3B1D7
+:106130002B26161ADA222AA02023261764A079C358
+:10614000A2C0B15BFF42C3A2C0B15BFF40C3C22C7F
+:106150002616C2AFC0B12326175BFF3CC28F28268C
+:1061600016C0FE2F2617C2E22E26162A0AA1C0B19B
+:10617000C0D82D26175BFF352A0AA12A2616C3A6EA
+:10618000C0B3C1922926175BFF31C3C62C2616C1A6
+:10619000B32A0AA22B2617C0B35BFF2C290AA22917
+:1061A0002616C185282617C2FB2F2616C0E72E26E5
+:1061B000171DDA762D2610D10FC3A2C0B35BFF23C3
+:1061C00063FF82006C10041CDA3F1BDA2C18DA70B3
+:1061D00017DA7116DA7115DA71C0E0C0D414DA3B3F
+:1061E0001FD9F7C0288FF06D2A36DAC0D9C07C5B82
+:1061F000020FC90C1CDA350C9C28A8C3A6C22A368B
+:10620000802A2584A4C2A7CC2D248C2B248A2B245D
+:10621000872E248BB1BB2E369F2C369E2C369DB1FB
+:10622000AC1CDA161BDA5FC0286D2A33DAC0D9C07D
+:106230007C5B020FC90C1CDA240C9C28A8C3A6C2E4
+:106240002A36802B2584A4C2B1BBA7CC2D248C2E4A
+:10625000248B2A248A2E369F2C369E2C369DB1AC58
+:10626000C07919DA141BDA5113DA4F1ADA4F18DA37
+:106270005014DA1516DA5004F42812DA4F04660CBA
+:10628000040506A252A858AA5AA3539B3029A50078
+:1062900027848AC091C0A52A848C29848B17DA4868
+:1062A00018DA47A75726361D26361E2E361F16DA51
+:1062B0004513DA45A65504330C2826C82E75002D43
+:1062C00054AC2E54AB2E54AA2326E62326E52E26C4
+:1062D000E7D10F006C100613DA2317DA1E24723D83
+:1062E0002232937F2F0B6D08052832937F8F026334
+:1062F000FFF3C0C4C0B01AD9B1C051D94004593954
+:1063000029A4206E44020BB502C3281ED9ACDDB00F
+:1063100025E422052D392DE421C0501EDA2C19DA8E
+:106320001C18DA1C16DA1E1DDA2A94102A72451778
+:10633000D9E76DA94BD450B3557A5B17DF50756B15
+:10634000071FD99E8FF00F5F0C12D9DF02F228AE23
+:106350002222D681D54013D9DC746B0715D99885D4
+:106360005005450C035328B145A73FA832A9332255
+:10637000369D22369E2436802B369F2BF48B2CF4B0
+:106380008C14D9F824424DC030041414C84C6D0844
+:1063900006B133041414C84263FFF20015D985C452
+:1063A000400031041AD986C0D193A200DD1AC13849
+:1063B000B0DD9DA318D9EC2B824D29824E29A51C56
+:1063C0002882537A871E2C54008E106FE45D12D9F8
+:1063D0007B2F211D23211C2F251B04330C23251C5F
+:1063E00023251AD10FC06218D9DB88807E87D9890E
+:1063F000102654006F94191BD9712AB11C0A1A1463
+:1064000004AA0C2AB51C2AB51D2AB51A2AB51BD117
+:106410000F1BD96A2AB11C0A1A1403AA0C2AB51C2C
+:106420002AB51D2AB51A2AB51BD10F001CD9642B19
+:10643000C11D2DC11C2BC51B03DD0C2DC51C2DC57D
+:106440001AD10F006C100619D95D14D9C212D9C522
+:1064500015D9E0C73FC0E02E56A82E56A92E56AA41
+:106460002E56AB23262918D985DB101CD9DAC0D4C7
+:106470002A42452D16019C1000B0890A880C2896E6
+:10648000005BFF942B22E318D94D0B5B149B842AED
+:1064900022E48B84B1AA0A5A140BAA0C9A852922E9
+:1064A000E509591499862F22CD0F5F149F875BFF52
+:1064B000455BFF1623463BC1B01DD9401CD99E2A1F
+:1064C000D1022C463A0BAA020A0A4F2AD5025804D6
+:1064D000925BFEBF5BFE98C050C0B016D93614D98F
+:1064E0003E17D9AEC0C0C73E93122C262DC03060D7
+:1064F00000440000007F9F0FB155091914659FF4F7
+:10650000C0500AA9027FA7EF18D92ADA5008580A02
+:1065100028822C2B0A000B8000005104D2A0C091CD
+:10652000C7AF00991A0A99039912CE3864206BD329
+:10653000202B20072516032C12022A62827CA863D6
+:1065400018D91C01110208580A28822CDA500B8035
+:1065500000D2A0643FD58A310A8A1404AA01C82A4D
+:106560002B22010B8B1404BB017BA945DDA07A7B98
+:10657000081DD9122DD2000DAD0CDB3019D90D1A22
+:10658000D95288130ADA28DC801DD99009880A2894
+:10659000823C0DAA080B8000652F93D320C0B06306
+:1065A000FF9400007FAF34B1550050040A0919630D
+:1065B000FF42DAB07B7B081AD9012AA2000ABA0C82
+:1065C0001BD9428C310BAB280C8A141CD980ACBB74
+:1065D0001CD98004AA012BC68163FF8F645F60C051
+:1065E00050C0B0C7CE9C1263FF5500006C1004274A
+:1065F000221EC08008E4311BD8EF0002002AB282BC
+:1066000019D8EF003104C06100661A2991020A6AA4
+:10661000022AB68209E43115D94A0C3811A8532848
+:1066200032822432842A8CFC7841102921022A36B5
+:106630008297A0096902292502D10F002B21022C83
+:1066400032850B6B022CCCFC2C368297C02B25029A
+:10665000D10F00006C1004C0E71DD8D21CD8D40D97
+:106660004911D7208B228A200B4B0BD2A007A80CF4
+:106670009B72288CF4C8346F8E026000A31FD8CAA6
+:10668000A298AF7B78B334C93DC081C0F0028F3887
+:106690000F0F42C9FA2CD67ED5206D4A05003088EE
+:1066A00000508C887008980878B16DD2A09870D18D
+:1066B0000FC0F0038F387FE0DE63FFD8027B0CAFA2
+:1066C000BB0B990C643047D830C0F1C05002F5388C
+:1066D0000505426450792CD67E0B36122F6C100FB4
+:1066E0004F366DFA0500808800208C06440CC0816E
+:1066F000C05003B208237C0C038538050542645062
+:106700005A2CD67ED30F6D4A0500208800308CD2DB
+:10671000A0A798BC889870D10FD2A0BC799970D1ED
+:106720000FD2302BAD08C0F1C0500BF53805054233
+:10673000CB542CD67E083F14260A100F660C064652
+:10674000366D6A0500208800B08C827063FF2D00D2
+:10675000C05003F53875E08063FF7A00C0600286A0
+:106760003876E09F63FF9900C05003F53875E0C4A8
+:1067700063FFBE006C1004D62068520F695324DA00
+:1067800020DB30DC405800F3D2A0D10FDA20DB3020
+:10679000DC405800F09A2424240EC02122640FC04B
+:1067A00020D10F00B83BB04C2A2C7489242D200E28
+:1067B0002E200FA4DDB1EE2E240FB0DD2D240E28E7
+:1067C00090072D9003A488B088B1DD2D9403289400
+:1067D000075BFFA069511DC0E082242A600F18D812
+:1067E000FE2A240329600E8F2029240708FF029F18
+:1067F000209E64D10FC020D10F0000006C100494C3
+:106800002319D8F6C0B3083A110BAA02992019D857
+:10681000699A2116D867C05028929D2564A2288CB9
+:106820001828969DD10F00006C1004282066C038EF
+:10683000232406B788282466D10F00006C100603B5
+:106840005A0C0D36110D5C11D8208B2282210CBB05
+:106850000C06550F9B8202320B928113D853D9201C
+:10686000A38F6450561CD84FC0D71BD850A256C017
+:10687000E1C09004E93809094276F34F044302CAA3
+:10688000912BC67ED30F6DAA0500208800308C891D
+:1068900081A95909FA0C64A07D99818A8264A00FAC
+:1068A000D290D10FC06002E63876D0D763FFD10016
+:1068B000C020BC89998199809282D10F7F230429BD
+:1068C0002DF8998165BFD863FFE50000028F0CA306
+:1068D000FF0F3312931003AA0CD3406490402BC6D1
+:1068E0007E8610D30F6D6A0500208800308CBC8234
+:1068F000C090A4F3C041034938090942CA9B2BC682
+:106900007E6DAA0500208800308C0F590CA989BC27
+:1069100099998163FF8400BC89998163FF7C00C0E1
+:106920006002E63876D0B963FFB300C07002473822
+:1069300077D0CD63FFC700006C100414D82AC15271
+:10694000A424CA3128221D73811C292102659016B6
+:106950002A300075A912022A02033B022C3007C01C
+:10696000D25801D0653FDCD10F2B300703BB0B0B96
+:10697000BA0274B3022ABDF8D3A063FFC4000000BA
+:106980006C1004292006C0706E9741292102C08F27
+:106990002A2014C0B62B240606AA022A24147980C1
+:1069A000022725022A221E2C221D7AC10EC8ABDA2C
+:1069B00020DB302C0A00033D025BF80D6450742D7F
+:1069C00021020D0D4CC9D3C020D10F00002E9CFB1D
+:1069D00064E0822F21020F0F4C65F0911AD7F61C4C
+:1069E000D7F429A29EC08A798B5D2BC22668B00499
+:1069F0008D207BD95229A29DC0F364904A97901DA7
+:106A0000D8062E21049D9608EE110FEE029E979E49
+:106A10009118D802C0E527C4A22E24062BA29D2FD0
+:106A200021022BBC3008FF022F25022BA69DC0207F
+:106A3000D10F00002F300068F939DA20DB30044C28
+:106A40000258004463FF7700022A022B0A0658000E
+:106A5000D3220A00D10F6550102830006889240223
+:106A60002A02033B02DC4058003BC020D10FD27009
+:106A7000D10F00002A2C74033B02044C025BFEF58C
+:106A800063FF3B00DB30DC402A2C745BFEF2C0204D
+:106A9000D10F00006C1004C83F89268829A399995A
+:106AA0002609880C080848282525CC52C020D10F7B
+:106AB000DB402A2C745BF936D2A0D10F6C1004D8BD
+:106AC00020D73082220D451105220C928264207459
+:106AD00007420B13D7B5D420A383732302242DF8C8
+:106AE000858074514CBC82C0906D081600408800AF
+:106AF000708C773903D720C0918680743901D420F7
+:106B000074610263FFE2CA98C097C0411BD835C0C8
+:106B1000A00B8B0C0B4A380A0A42C9AA1DD7A21C2B
+:106B2000D7A32CD67EC140D30F6D4A050020880024
+:106B3000308C9780D270D10FBC8FC0E00F4E387E62
+:106B400090E263FFD6BC8292819280C0209282D173
+:106B50000F0000006C1006C0D71CD7921BD7940DF5
+:106B60004911D7202E221F28221D0E4E0BD280073E
+:106B70008A0C2E761F2AAC80C8346FAE026000CB20
+:106B80002F0A801AD798A29EAA7A7EA33FC93FC037
+:106B9000E1C05002E538050542CA552BC67EDB2010
+:106BA000D30F6D4A0500308800B08C2E721DAE9E4A
+:106BB0000EA50C645086D2802E761DC091298403C8
+:106BC000D10FC05003E53875D0D363FFCD15D785FD
+:106BD000027E0CA5EE643051C0A1250A0002A53842
+:106BE000033A020505426450922BC67E0E3512957B
+:106BF00010255C10054536D30F6D5A0500A088009E
+:106C0000208CC0A1A3E2C05023FA8003730C03A51B
+:106C100038AF730505426450722BC67E851005455A
+:106C20000C6D5A0500208800308CD280C0A10E9BCC
+:106C30000CAB7BAFBB2B761D2A8403D10FD280C057
+:106C4000C1AF7D2D761D2C8403D10F00D2302E8D47
+:106C500008C0F1C0500EF538050542CB592BC67E51
+:106C60000A3F14C1600F660C064636D30F6D6A05E5
+:106C700000208800E08C22721D63FF03C061C050B9
+:106C800003653875D80263FF6263FF5CC05002A5DC
+:106C90003875D08763FF8100C06003F63876D0BFB7
+:106CA00063FFB9006C10042A201529201614D7435D
+:106CB0000A990CCB9D2E200B04ED092BD11C8F289B
+:106CC00009BC36ACAA0CBB0C2BD51C0A0A472A24DB
+:106CD00015CAAF8B438942B0A800910400881AA856
+:106CE000FF0FBB029B278F260FB80C783B1AC020E2
+:106CF000D10F0000292102C0A20A9902292502C051
+:106D000021D10F008B2763FFDC2BD11C0CAA0C0AAE
+:106D10000A472A2415ACBB2BD51CC9AE8B438C2843
+:106D20008F42B0AD00F10400DD1AADCC0CBB029B6C
+:106D300027DA20B7EB580019C021D10F9F2763FF36
+:106D4000EF0000006C100428203C643047053060E0
+:106D500000073E01053EB156076539054928C77F42
+:106D6000A933030641076603B166060641A6337ED2
+:106D7000871E222125291AFC732B1502380C098144
+:106D80006000063E01023EB12406423903220AD1C8
+:106D90000FD230D10FC05163FFC000006C10042728
+:106DA000221EC08008E4311DD7030002002CD282CD
+:106DB0001BD703003104C06100661A2BB1020C6CB2
+:106DC000022CD6820BE43119D7870C3A11AA9328EA
+:106DD00032829780253282243284B45525368275DA
+:106DE000410A292102096902292502D10F2A21021B
+:106DF0002B32830A6A022B36822A2502D10F000029
+:106E00006C100418D6EC0C2711087708267286251A
+:106E10003C04765B1315D6E805220A2222A36820DB
+:106E200002742904227285D10FC020D10F00000006
+:106E30006C100419D6EB27221EC08009770208E4E3
+:106E4000311DD6DC0002002CD2821BD6DC003104BE
+:106E5000C06100661A2BB1020C6C022CD6820BE4C6
+:106E60003119D7600C3A11AA9328328297802532C3
+:106E700082243284B45525368275410B2A21020AB8
+:106E80006A022A2502D10F002B21022C32830B6BC0
+:106E9000022C36822B2502D10F0000006C10041B3F
+:106EA000D6C50C2A11ABAA29A286B438798B221B2D
+:106EB000D6C219D6E80B2B0A2BB2A309290868B051
+:106EC0000274B90D299D0129901F6E920822A28596
+:106ED000D10FC020D10FC892C020D10FDA205BEEB5
+:106EE000B3C020D10F0000006C100414D6B22842A9
+:106EF0009E19D6AF6F88026000BA29922668900763
+:106F00008A2009AA0C65A0AC2A429DC0DC64A0A41A
+:106F10002B200C19D6A90CBC11A4CC2EC28609B901
+:106F20000A7ED30260009A2992A36890078D2009F7
+:106F3000DD0C65D08C25C2856450862D2104C030BF
+:106F40006ED80D2C2066B8CC0C0C472C246665C07E
+:106F50007B1CD72518D6AF1AD6A619D6B61DD6AB28
+:106F6000C0E49E519D508F209357935599539A5644
+:106F70009A5408FF021AD6C29F5288269F5A9E59D9
+:106F80009D58935E9C5D935C9A5B08084805881148
+:106F9000985FC0D81FD6900CB911A499289285AFDC
+:106FA000BF23F4CF288C402896858E262D24069E5C
+:106FB00029C020D10FCA33DA20C0B65BFF78C72FB3
+:106FC000D10FC93ADA205BFF75C72FD10FDBD05B39
+:106FD000FE0B2324662B200C63FF7500C72FD10FF7
+:106FE000C72FD10F6C1004C85B29200668941C6859
+:106FF0009607C020D10FC020D10FDA20DB30DC4053
+:10700000DD502E0A005BFE5ED2A0D10F2E200C18A0
+:10701000D6690CEF11A8FF29F286C088798B791AFE
+:10702000D6660AEA0A2AA2A368A0048B207AB96865
+:1070300023F2856430621BD670290A802C206828D0
+:1070400020672D21040B881104DD1108DD020DCC11
+:1070500002C0842D4A100DCC021DD66898319D3097
+:107060008A2B99379C340BAA02C0C09C359C369A57
+:10707000322A2C74DB4028F285C0D3288C2028F6D5
+:10708000852C25042D24061FD653DD40AFEE2CE4BD
+:10709000CF5BFDEAD2A0D10F00DA20DBE05BFF3F3F
+:1070A000C020D10F6C100AD6302A200624160128E1
+:1070B000ACF86583862B2122C0F22A2124CC572AE2
+:1070C000AC010A0A4F2A25247ABB0260037F2C21D7
+:1070D000020C0C4C65C3192E22158D32C0910EDDA9
+:1070E0000C65D39088381ED63364836B8C37C0B858
+:1070F000C0960CB9399914B49A9A120D9911991332
+:107100008F6718D62EC9FB2880217F83168B142CFD
+:1071100022002A200C5BFF61D4A064A3B38F6760B8
+:10712000002800002B200C89120CBA11AEAA2CA248
+:10713000861DD6217C9B3E0DBD0A2DD2A368D004AE
+:1071400088207D893024A28564436427212E07F797
+:107150003607F90C6F9D01D7F0DA20DB70C1C42D22
+:10716000211F5BFEF889268827DDA009880C7A8B11
+:10717000179A10600006C04063FFCC0000DA208B35
+:10718000105BFEC88D1065A267C0E09E488C649CB1
+:10719000498B658A669B4A9A4B97458F677F730236
+:1071A000600120CD529D10DA20DB302C12015BFEF5
+:1071B000698D10C051D6A08FA7C0C08A68974D9A1C
+:1071C0004C8869896A984E994F8E6A8A69AE7E7733
+:1071D000EB01B1AA9E6A9A698B60C0A00B8E1477EE
+:1071E000B701C0A1C091C08493159D179516C0D05A
+:1071F00025203CC030085801089338C0820833105D
+:10720000085B010535400B9D3807DD100BAB100EF8
+:1072100019402A211F07991003DD020DBB020553F7
+:10722000100933020A55112921250A2A14092914A3
+:107230000499110A99020933028A2B2921040BAA05
+:10724000021BD66A0899110955020855020BAA02B9
+:107250009A408920881408991109880219D5EA1DD5
+:10726000D66409880298418B2A9346954783150D69
+:10727000BB0285168D179B448A658966AACAA97CBC
+:1072800077CB01B1AA07FB0C9C669A6588268E29EC
+:10729000AD87972607EE0C0E0E482E25259B672BF3
+:1072A000200C87131ED5C40CB911AE99289285A75E
+:1072B0008828968517D5C8C090A7BB29B4CF871852
+:1072C00063FE3C008C60C0E0C091C0F0C034C0B828
+:1072D0002A210428203C08AA110B8B0103830103F7
+:1072E0009F380B9B39C03208FF10038801089E3875
+:1072F0000C881407EE100FEE020388010898390578
+:10730000BF1029211F0ABB1107881008FF020BAA12
+:107310000218D5BC09291403AA022B212583200BAE
+:107320002B1404BB110833110FBB020B99028B14F1
+:107330008F2A0B33020833028B2B64708688689780
+:107340004D984C8769886A93419946974E984FC0EB
+:107350007077C701C0719A4718D6260B7C100CECC9
+:107360000208F802984418D6230CBC0208CC029CF0
+:10737000402A200C295CFEC0801FD58E1CD5960C9F
+:10738000AE112B2124ACAAAFEEB0BB8F132CE2853B
+:1073900028A4CFAFCC2CE6852A22152B2524B1AA10
+:1073A0002A26156490DBC9D28F262E22090DFF08EC
+:1073B0002F26060FEE0C0E0E482E25256550E4C034
+:1073C00020D10F00C07093419F4499469A4777C7D8
+:1073D0000A1CD57A2CC022C0810C87381CD6070B1A
+:1073E000781008E80208B8020C8802984063FF8011
+:1073F00000CC57DA20DB608C115BFDD629210268B6
+:107400009806689403C020D10F2B221EC0A0292209
+:107410001D2A25027B9901C0B064BFE813D5652CF5
+:10742000B00728B000DA2003880A28824CC0D10BAC
+:107430008000DBA065AFE763FFCA000068A779DAC8
+:1074400020DB30DC40DD505BFEE7D2A0D10FC16D08
+:10745000C19D29252C60000429252CD6902624675F
+:107460002F2468DA20DB308C11DD502E0A805BFD82
+:1074700044D2A0D10FC168C1A82A252C63FFDD002A
+:107480000000C8DF8C268B29ADCC9C260CBB0C0BD6
+:107490000B482B25252A2C74DB602C12015BFD8701
+:1074A000D2A0D10F2A2C748B115BF6B9D2A0D10FC8
+:1074B000DA205BFE3A63FF3800DA20C0B15BFE8A57
+:1074C00064ABF1655F352D2124B1DD2D252463FFEB
+:1074D0001FDA202B200C5BFE5663FF1412D5C882E6
+:1074E00020028257C82163FFFC12D5C403E8300490
+:1074F000EE3005B13093209421952263FFFC00000B
+:1075000010D5C0910092019302940311D597821077
+:1075100001EA30A21101F031C04004E4160002007B
+:1075200011D5B98210234A00032202921011D5828C
+:10753000C021921004E4318403830282018100009F
+:10754000D23001230000000010D5B09100920193C9
+:1075500002940311D586821001EA30A21101F131A3
+:10756000C04004E41600020011D5A7821013D52BE9
+:10757000032202921004E431840383028201810019
+:1075800000D330013300000010D5A19100810165C6
+:10759000104981026510448103CF1F920193029428
+:1075A0000311D574821001EA30A21101F231C040FA
+:1075B00004E41600020011D593821013D5130322A0
+:1075C00002921004E431840383028201C01091030B
+:1075D00091029101810000D43001430012D542C0D4
+:1075E0003028374028374428374828374C233D0176
+:1075F0007233ED03020063FFFC00000010D585919B
+:107600000092019302940311D5838210921011D538
+:10761000348310032202921011D58012D5469210A5
+:10762000C04004E41600020011D577821013D52D56
+:10763000032202921004E431840383028201810058
+:1076400000D53001530000006C10026E322FD6209E
+:10765000056F04043F04745B2A05440C00410400D8
+:10766000331A220A006D490D73630403660CB122BC
+:107670000F2211031314736302222C01D10FC83B94
+:10768000D10F000073630CC021D10F000000000077
+:1076900044495630C020D10F6C10020040046B4C9E
+:1076A00007032318020219D10F020319C020D10FBA
+:1076B0006C100202EA30D10F6C1002CC2503F031BD
+:1076C00060000F006F220503F1316000056F230594
+:1076D00003F231000200D10F6C1002CC2502F03011
+:1076E000D10F00006F220402F130D10F6F2304028A
+:1076F000F230D10FC020D10F6C1002220A20230AD1
+:10770000006D280E28374028374428374828374C42
+:10771000233D01030200D10F6C100202E431D10FAE
+:107720000A004368656C73696F20465720444542E0
+:1077300055473D3020284275696C74204672692097
+:107740004D61792020382031363A30373A333620AF
+:107750005044542032303039206F6E20636C656F96
+:1077600070617472612E6173696364657369676EB9
+:107770006572732E636F6D3A2F686F6D652F666546
+:107780006C69782F772F66775F372E31292C20563A
+:10779000657273696F6E2054337878203030372EDD
+:1077A00030342E3030202D203130303730343030EE
+:0877B000100704000071489469
+:00000001FF
index e8852c0..28cc03b 100644 (file)
 #define        EOWNERDEAD      130     /* Owner died */
 #define        ENOTRECOVERABLE 131     /* State not recoverable */
 
+#define ERFKILL                132     /* Operation not possible due to RF-kill */
+
 #endif
index 3f0eaa3..7e09c5c 100644 (file)
@@ -311,6 +311,7 @@ unifdef-y += ptrace.h
 unifdef-y += qnx4_fs.h
 unifdef-y += quota.h
 unifdef-y += random.h
+unifdef-y += rfkill.h
 unifdef-y += irqnr.h
 unifdef-y += reboot.h
 unifdef-y += reiserfs_fs.h
index 37966e6..01ee2ae 100644 (file)
@@ -13,6 +13,7 @@
 #define OCR_MODE_TEST     0x01
 #define OCR_MODE_NORMAL   0x02
 #define OCR_MODE_CLOCK    0x03
+#define OCR_MODE_MASK     0x07
 #define OCR_TX0_INVERT    0x04
 #define OCR_TX0_PULLDOWN  0x08
 #define OCR_TX0_PULLUP    0x10
@@ -21,6 +22,8 @@
 #define OCR_TX1_PULLDOWN  0x40
 #define OCR_TX1_PULLUP    0x80
 #define OCR_TX1_PUSHPULL  0xc0
+#define OCR_TX_MASK       0xfc
+#define OCR_TX_SHIFT      2
 
 struct sja1000_platform_data {
        u32 clock;      /* CAN bus oscillator frequency in Hz */
index 380b042..9b660bd 100644 (file)
@@ -30,7 +30,8 @@ struct ethtool_cmd {
        __u32   maxtxpkt;       /* Tx pkts before generating tx int */
        __u32   maxrxpkt;       /* Rx pkts before generating rx int */
        __u16   speed_hi;
-       __u16   reserved2;
+       __u8    eth_tp_mdix;
+       __u8    reserved2;
        __u32   lp_advertising; /* Features the link partner advertises */
        __u32   reserved[2];
 };
@@ -632,6 +633,11 @@ struct ethtool_ops {
 #define AUTONEG_DISABLE                0x00
 #define AUTONEG_ENABLE         0x01
 
+/* Mode MDI or MDI-X */
+#define ETH_TP_MDI_INVALID     0x00
+#define ETH_TP_MDI             0x01
+#define ETH_TP_MDI_X           0x02
+
 /* Wake-On-Lan options. */
 #define WAKE_PHY               (1 << 0)
 #define WAKE_UCAST             (1 << 1)
index 34de8b2..a9173d5 100644 (file)
@@ -1092,6 +1092,7 @@ enum ieee80211_key_len {
        WLAN_KEY_LEN_WEP104 = 13,
        WLAN_KEY_LEN_CCMP = 16,
        WLAN_KEY_LEN_TKIP = 32,
+       WLAN_KEY_LEN_AES_CMAC = 16,
 };
 
 /*
index 5ff8980..b554300 100644 (file)
@@ -86,6 +86,8 @@
 #define ARPHRD_IEEE80211 801           /* IEEE 802.11                  */
 #define ARPHRD_IEEE80211_PRISM 802     /* IEEE 802.11 + Prism2 header  */
 #define ARPHRD_IEEE80211_RADIOTAP 803  /* IEEE 802.11 + radiotap header */
+#define ARPHRD_IEEE802154        804
+#define ARPHRD_IEEE802154_PHY    805
 
 #define ARPHRD_PHONET  820             /* PhoNet media type            */
 #define ARPHRD_PHONET_PIPE 821         /* PhoNet pipe header           */
index cfe4fe1..11a60e4 100644 (file)
 #define ETH_P_DSA      0x001B          /* Distributed Switch Arch.     */
 #define ETH_P_TRAILER  0x001C          /* Trailer switch tagging       */
 #define ETH_P_PHONET   0x00F5          /* Nokia Phonet frames          */
+#define ETH_P_IEEE802154 0x00F6                /* IEEE802.15.4 frame           */
 
 /*
  *     This is an Ethernet frame header.
index d60122a..cf196da 100644 (file)
@@ -107,6 +107,7 @@ struct in_addr {
 #define MCAST_JOIN_SOURCE_GROUP                46
 #define MCAST_LEAVE_SOURCE_GROUP       47
 #define MCAST_MSFILTER                 48
+#define IP_MULTICAST_ALL               49
 
 #define MCAST_EXCLUDE  0
 #define MCAST_INCLUDE  1
index 476d946..c662efa 100644 (file)
@@ -169,6 +169,12 @@ struct ipv6_devconf {
        __s32           accept_dad;
        void            *sysctl;
 };
+
+struct ipv6_params {
+       __s32 disable_ipv6;
+       __s32 autoconf;
+};
+extern struct ipv6_params ipv6_defaults;
 #endif
 
 /* index values for the variables in ipv6_devconf */
index 35e9b0f..7acb87a 100644 (file)
@@ -79,7 +79,7 @@ int attach_capi_ctr(struct capi_ctr *);
 int detach_capi_ctr(struct capi_ctr *);
 
 void capi_ctr_ready(struct capi_ctr * card);
-void capi_ctr_reseted(struct capi_ctr * card);
+void capi_ctr_down(struct capi_ctr * card);
 void capi_ctr_suspend_output(struct capi_ctr * card);
 void capi_ctr_resume_output(struct capi_ctr * card);
 void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *skb);
index 5685164..cfdf1df 100644 (file)
@@ -45,6 +45,7 @@
 #define MDIO_PHYXS_LNSTAT      24      /* PHY XGXS lane state */
 
 /* Media-dependent registers. */
+#define MDIO_PMA_10GBT_SWAPPOL 130     /* 10GBASE-T pair swap & polarity */
 #define MDIO_PMA_10GBT_TXPWR   131     /* 10GBASE-T TX power control */
 #define MDIO_PMA_10GBT_SNR     133     /* 10GBASE-T SNR margin, lane A.
                                         * Lanes B-D are numbered 134-136. */
 #define MDIO_PHYXS_LNSTAT_SYNC3                0x0008
 #define MDIO_PHYXS_LNSTAT_ALIGN                0x1000
 
+/* PMA 10GBASE-T pair swap & polarity */
+#define MDIO_PMA_10GBT_SWAPPOL_ABNX    0x0001  /* Pair A/B uncrossed */
+#define MDIO_PMA_10GBT_SWAPPOL_CDNX    0x0002  /* Pair C/D uncrossed */
+#define MDIO_PMA_10GBT_SWAPPOL_AREV    0x0100  /* Pair A polarity reversed */
+#define MDIO_PMA_10GBT_SWAPPOL_BREV    0x0200  /* Pair B polarity reversed */
+#define MDIO_PMA_10GBT_SWAPPOL_CREV    0x0400  /* Pair C polarity reversed */
+#define MDIO_PMA_10GBT_SWAPPOL_DREV    0x0800  /* Pair D polarity reversed */
+
 /* PMA 10GBASE-T TX power register. */
 #define MDIO_PMA_10GBT_TXPWR_SHORT     0x0001  /* Short-reach mode */
 
index 371ece5..9ea8d6d 100644 (file)
@@ -215,9 +215,12 @@ struct netdev_hw_addr {
        struct list_head        list;
        unsigned char           addr[MAX_ADDR_LEN];
        unsigned char           type;
-#define NETDEV_HW_ADDR_T_LAN   1
-#define NETDEV_HW_ADDR_T_SAN   2
-#define NETDEV_HW_ADDR_T_SLAVE 3
+#define NETDEV_HW_ADDR_T_LAN           1
+#define NETDEV_HW_ADDR_T_SAN           2
+#define NETDEV_HW_ADDR_T_SLAVE         3
+#define NETDEV_HW_ADDR_T_UNICAST       4
+       int                     refcount;
+       bool                    synced;
        struct rcu_head         rcu_head;
 };
 
@@ -773,10 +776,11 @@ struct net_device
        unsigned char           addr_len;       /* hardware address length      */
        unsigned short          dev_id;         /* for shared network cards */
 
-       spinlock_t              addr_list_lock;
-       struct dev_addr_list    *uc_list;       /* Secondary unicast mac addresses */
+       struct list_head        uc_list;        /* Secondary unicast mac
+                                                  addresses */
        int                     uc_count;       /* Number of installed ucasts   */
        int                     uc_promisc;
+       spinlock_t              addr_list_lock;
        struct dev_addr_list    *mc_list;       /* Multicast mac addresses      */
        int                     mc_count;       /* Number of installed mcasts   */
        unsigned int            promiscuity;
@@ -905,7 +909,6 @@ struct net_device
 #define to_net_dev(d) container_of(d, struct net_device, dev)
 
 #define        NETDEV_ALIGN            32
-#define        NETDEV_ALIGN_CONST      (NETDEV_ALIGN - 1)
 
 static inline
 struct netdev_queue *netdev_get_tx_queue(const struct net_device *dev,
@@ -976,9 +979,7 @@ static inline bool netdev_uses_trailer_tags(struct net_device *dev)
  */
 static inline void *netdev_priv(const struct net_device *dev)
 {
-       return (char *)dev + ((sizeof(struct net_device)
-                              + NETDEV_ALIGN_CONST)
-                             & ~NETDEV_ALIGN_CONST);
+       return (char *)dev + ALIGN(sizeof(struct net_device), NETDEV_ALIGN);
 }
 
 /* Set the sysfs physical device reference for the network logical device
@@ -1839,8 +1840,8 @@ extern int dev_addr_del_multiple(struct net_device *to_dev,
 /* Functions used for secondary unicast and multicast support */
 extern void            dev_set_rx_mode(struct net_device *dev);
 extern void            __dev_set_rx_mode(struct net_device *dev);
-extern int             dev_unicast_delete(struct net_device *dev, void *addr, int alen);
-extern int             dev_unicast_add(struct net_device *dev, void *addr, int alen);
+extern int             dev_unicast_delete(struct net_device *dev, void *addr);
+extern int             dev_unicast_add(struct net_device *dev, void *addr);
 extern int             dev_unicast_sync(struct net_device *to, struct net_device *from);
 extern void            dev_unicast_unsync(struct net_device *to, struct net_device *from);
 extern int             dev_mc_delete(struct net_device *dev, void *addr, int alen, int all);
@@ -1902,15 +1903,14 @@ static inline int net_gso_ok(int features, int gso_type)
 
 static inline int skb_gso_ok(struct sk_buff *skb, int features)
 {
-       return net_gso_ok(features, skb_shinfo(skb)->gso_type);
+       return net_gso_ok(features, skb_shinfo(skb)->gso_type) &&
+              (!skb_has_frags(skb) || (features & NETIF_F_FRAGLIST));
 }
 
 static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb)
 {
        return skb_is_gso(skb) &&
               (!skb_gso_ok(skb, dev->features) ||
-               (skb_shinfo(skb)->frag_list &&
-                !(dev->features & NETIF_F_FRAGLIST)) ||
                unlikely(skb->ip_summed != CHECKSUM_PARTIAL));
 }
 
@@ -1920,6 +1920,16 @@ static inline void netif_set_gso_max_size(struct net_device *dev,
        dev->gso_max_size = size;
 }
 
+static inline void skb_bond_set_mac_by_master(struct sk_buff *skb,
+                                             struct net_device *master)
+{
+       if (skb->pkt_type == PACKET_HOST) {
+               u16 *dest = (u16 *) eth_hdr(skb)->h_dest;
+
+               memcpy(dest, master->dev_addr, ETH_ALEN);
+       }
+}
+
 /* On bonding slaves other than the currently active slave, suppress
  * duplicates except for 802.3ad ETH_P_SLOW, alb non-mcast/bcast, and
  * ARP on active-backup slaves with arp_validate enabled.
@@ -1933,6 +1943,14 @@ static inline int skb_bond_should_drop(struct sk_buff *skb)
                if (master->priv_flags & IFF_MASTER_ARPMON)
                        dev->last_rx = jiffies;
 
+               if ((master->priv_flags & IFF_MASTER_ALB) && master->br_port) {
+                       /* Do address unmangle. The local destination address
+                        * will be always the one master has. Provides the right
+                        * functionality in a bridge.
+                        */
+                       skb_bond_set_mac_by_master(skb, master);
+               }
+
                if (dev->priv_flags & IFF_SLAVE_INACTIVE) {
                        if ((dev->priv_flags & IFF_SLAVE_NEEDARP) &&
                            skb->protocol == __cpu_to_be16(ETH_P_ARP))
@@ -1978,4 +1996,4 @@ static inline u32 dev_ethtool_get_flags(struct net_device *dev)
 }
 #endif /* __KERNEL__ */
 
-#endif /* _LINUX_DEV_H */
+#endif /* _LINUX_NETDEVICE_H */
index 74c27ca..4352fee 100644 (file)
@@ -36,6 +36,9 @@ enum tcp_conntrack {
 /* Has unacknowledged data */
 #define IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED     0x10
 
+/* The field td_maxack has been set */
+#define IP_CT_TCP_FLAG_MAXACK_SET              0x20
+
 struct nf_ct_tcp_flags {
        __u8 flags;
        __u8 mask;
@@ -47,6 +50,7 @@ struct ip_ct_tcp_state {
        u_int32_t       td_end;         /* max of seq + len */
        u_int32_t       td_maxend;      /* max of ack + max(win, 1) */
        u_int32_t       td_maxwin;      /* max(win) */
+       u_int32_t       td_maxack;      /* max of ack */
        u_int8_t        td_scale;       /* window scale factor */
        u_int8_t        flags;          /* per direction options */
 };
diff --git a/include/linux/nl802154.h b/include/linux/nl802154.h
new file mode 100644 (file)
index 0000000..2cda00c
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * nl802154.h
+ *
+ * Copyright (C) 2007, 2008, 2009 Siemens AG
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef NL802154_H
+#define NL802154_H
+
+#define IEEE802154_NL_NAME "802.15.4 MAC"
+#define IEEE802154_MCAST_COORD_NAME "coordinator"
+#define IEEE802154_MCAST_BEACON_NAME "beacon"
+
+enum {
+       __IEEE802154_ATTR_INVALID,
+
+       IEEE802154_ATTR_DEV_NAME,
+       IEEE802154_ATTR_DEV_INDEX,
+
+       IEEE802154_ATTR_STATUS,
+
+       IEEE802154_ATTR_SHORT_ADDR,
+       IEEE802154_ATTR_HW_ADDR,
+       IEEE802154_ATTR_PAN_ID,
+
+       IEEE802154_ATTR_CHANNEL,
+
+       IEEE802154_ATTR_COORD_SHORT_ADDR,
+       IEEE802154_ATTR_COORD_HW_ADDR,
+       IEEE802154_ATTR_COORD_PAN_ID,
+
+       IEEE802154_ATTR_SRC_SHORT_ADDR,
+       IEEE802154_ATTR_SRC_HW_ADDR,
+       IEEE802154_ATTR_SRC_PAN_ID,
+
+       IEEE802154_ATTR_DEST_SHORT_ADDR,
+       IEEE802154_ATTR_DEST_HW_ADDR,
+       IEEE802154_ATTR_DEST_PAN_ID,
+
+       IEEE802154_ATTR_CAPABILITY,
+       IEEE802154_ATTR_REASON,
+       IEEE802154_ATTR_SCAN_TYPE,
+       IEEE802154_ATTR_CHANNELS,
+       IEEE802154_ATTR_DURATION,
+       IEEE802154_ATTR_ED_LIST,
+       IEEE802154_ATTR_BCN_ORD,
+       IEEE802154_ATTR_SF_ORD,
+       IEEE802154_ATTR_PAN_COORD,
+       IEEE802154_ATTR_BAT_EXT,
+       IEEE802154_ATTR_COORD_REALIGN,
+       IEEE802154_ATTR_SEC,
+
+       __IEEE802154_ATTR_MAX,
+};
+
+#define IEEE802154_ATTR_MAX (__IEEE802154_ATTR_MAX - 1)
+
+extern struct nla_policy ieee802154_policy[];
+
+/* commands */
+/* REQ should be responded with CONF
+ * and INDIC with RESP
+ */
+enum {
+       __IEEE802154_COMMAND_INVALID,
+
+       IEEE802154_ASSOCIATE_REQ,
+       IEEE802154_ASSOCIATE_CONF,
+       IEEE802154_DISASSOCIATE_REQ,
+       IEEE802154_DISASSOCIATE_CONF,
+       IEEE802154_GET_REQ,
+       IEEE802154_GET_CONF,
+       IEEE802154_RESET_REQ,
+       IEEE802154_RESET_CONF,
+       IEEE802154_SCAN_REQ,
+       IEEE802154_SCAN_CONF,
+       IEEE802154_SET_REQ,
+       IEEE802154_SET_CONF,
+       IEEE802154_START_REQ,
+       IEEE802154_START_CONF,
+       IEEE802154_SYNC_REQ,
+       IEEE802154_POLL_REQ,
+       IEEE802154_POLL_CONF,
+
+       IEEE802154_ASSOCIATE_INDIC,
+       IEEE802154_ASSOCIATE_RESP,
+       IEEE802154_DISASSOCIATE_INDIC,
+       IEEE802154_BEACON_NOTIFY_INDIC,
+       IEEE802154_ORPHAN_INDIC,
+       IEEE802154_ORPHAN_RESP,
+       IEEE802154_COMM_STATUS_INDIC,
+       IEEE802154_SYNC_LOSS_INDIC,
+
+       IEEE802154_GTS_REQ, /* Not supported yet */
+       IEEE802154_GTS_INDIC, /* Not supported yet */
+       IEEE802154_GTS_CONF, /* Not supported yet */
+       IEEE802154_RX_ENABLE_REQ, /* Not supported yet */
+       IEEE802154_RX_ENABLE_CONF, /* Not supported yet */
+
+       __IEEE802154_CMD_MAX,
+};
+
+#define IEEE802154_CMD_MAX (__IEEE802154_CMD_MAX - 1)
+
+#endif
index b86fa2f..81bc252 100644 (file)
@@ -198,6 +198,7 @@ static inline int notifier_to_errno(int ret)
 #define NETDEV_CHANGENAME      0x000A
 #define NETDEV_FEAT_CHANGE     0x000B
 #define NETDEV_BONDING_FAILOVER 0x000C
+#define NETDEV_PRE_UP          0x000D
 
 #define SYS_DOWN       0x0001  /* Notify of system down */
 #define SYS_RESTART    SYS_DOWN
index 12db06c..b87c51a 100644 (file)
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS        0x0034
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE  0x0035
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA 0x0036
-#define PCI_DEVICE_ID_NVIDIA_NVENET_10         0x0037
-#define PCI_DEVICE_ID_NVIDIA_NVENET_11         0x0038
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2        0x003e
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_ULTRA 0x0040
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800       0x0041
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE  0x0053
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA 0x0054
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2        0x0055
-#define PCI_DEVICE_ID_NVIDIA_NVENET_8          0x0056
-#define PCI_DEVICE_ID_NVIDIA_NVENET_9          0x0057
 #define PCI_DEVICE_ID_NVIDIA_CK804_AUDIO       0x0059
 #define PCI_DEVICE_ID_NVIDIA_CK804_PCIE                0x005d
 #define PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS     0x0064
 #define PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE       0x0065
-#define PCI_DEVICE_ID_NVIDIA_NVENET_2          0x0066
 #define PCI_DEVICE_ID_NVIDIA_MCP2_MODEM                0x0069
 #define PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO                0x006a
 #define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS    0x0084
 #define PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE      0x0085
-#define PCI_DEVICE_ID_NVIDIA_NVENET_4          0x0086
 #define PCI_DEVICE_ID_NVIDIA_MCP2S_MODEM       0x0089
 #define PCI_DEVICE_ID_NVIDIA_CK8_AUDIO         0x008a
-#define PCI_DEVICE_ID_NVIDIA_NVENET_5          0x008c
 #define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA     0x008e
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GT   0x0090
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GTX  0x0091
 #define PCI_DEVICE_ID_NVIDIA_NFORCE3           0x00d1
 #define PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS     0x00d4
 #define PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE       0x00d5
-#define PCI_DEVICE_ID_NVIDIA_NVENET_3          0x00d6
 #define PCI_DEVICE_ID_NVIDIA_MCP3_MODEM                0x00d9
 #define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO                0x00da
-#define PCI_DEVICE_ID_NVIDIA_NVENET_7          0x00df
 #define PCI_DEVICE_ID_NVIDIA_NFORCE3S          0x00e1
 #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA     0x00e3
 #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS    0x00e4
 #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE      0x00e5
-#define PCI_DEVICE_ID_NVIDIA_NVENET_6          0x00e6
 #define PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO                0x00ea
 #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2    0x00ee
 #define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_ALT1 0x00f0
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS      0x01b4
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_IDE                0x01bc
 #define PCI_DEVICE_ID_NVIDIA_MCP1_MODEM                0x01c1
-#define PCI_DEVICE_ID_NVIDIA_NVENET_1          0x01c3
 #define PCI_DEVICE_ID_NVIDIA_NFORCE2           0x01e0
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3          0x0200
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1                0x0201
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE  0x036E
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA 0x037E
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2        0x037F
-#define PCI_DEVICE_ID_NVIDIA_NVENET_12         0x0268
-#define PCI_DEVICE_ID_NVIDIA_NVENET_13         0x0269
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800  0x0280
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800_8X    0x0281
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800SE     0x0282
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_2    0x0348
 #define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO1000       0x034C
 #define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1100         0x034E
-#define PCI_DEVICE_ID_NVIDIA_NVENET_14              0x0372
 #define PCI_DEVICE_ID_NVIDIA_NVENET_15              0x0373
-#define PCI_DEVICE_ID_NVIDIA_NVENET_16              0x03E5
-#define PCI_DEVICE_ID_NVIDIA_NVENET_17              0x03E6
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA      0x03E7
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS            0x03EB
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE       0x03EC
-#define PCI_DEVICE_ID_NVIDIA_NVENET_18              0x03EE
-#define PCI_DEVICE_ID_NVIDIA_NVENET_19              0x03EF
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2     0x03F6
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3     0x03F7
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS            0x0446
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE      0x0448
-#define PCI_DEVICE_ID_NVIDIA_NVENET_20              0x0450
-#define PCI_DEVICE_ID_NVIDIA_NVENET_21              0x0451
-#define PCI_DEVICE_ID_NVIDIA_NVENET_22              0x0452
-#define PCI_DEVICE_ID_NVIDIA_NVENET_23              0x0453
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_SMBUS     0x0542
-#define PCI_DEVICE_ID_NVIDIA_NVENET_24              0x054C
-#define PCI_DEVICE_ID_NVIDIA_NVENET_25              0x054D
-#define PCI_DEVICE_ID_NVIDIA_NVENET_26              0x054E
-#define PCI_DEVICE_ID_NVIDIA_NVENET_27              0x054F
-#define PCI_DEVICE_ID_NVIDIA_NVENET_28              0x07DC
-#define PCI_DEVICE_ID_NVIDIA_NVENET_29              0x07DD
-#define PCI_DEVICE_ID_NVIDIA_NVENET_30              0x07DE
-#define PCI_DEVICE_ID_NVIDIA_NVENET_31              0x07DF
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE       0x0560
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE       0x056C
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP78S_SMBUS    0x0752
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE       0x0759
-#define PCI_DEVICE_ID_NVIDIA_NVENET_32              0x0760
-#define PCI_DEVICE_ID_NVIDIA_NVENET_33              0x0761
-#define PCI_DEVICE_ID_NVIDIA_NVENET_34              0x0762
-#define PCI_DEVICE_ID_NVIDIA_NVENET_35              0x0763
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_SMBUS     0x07D8
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP79_SMBUS     0x0AA2
-#define PCI_DEVICE_ID_NVIDIA_NVENET_36              0x0AB0
-#define PCI_DEVICE_ID_NVIDIA_NVENET_37              0x0AB1
-#define PCI_DEVICE_ID_NVIDIA_NVENET_38              0x0AB2
-#define PCI_DEVICE_ID_NVIDIA_NVENET_39              0x0AB3
 
 #define PCI_VENDOR_ID_IMS              0x10e0
 #define PCI_DEVICE_ID_IMS_TT128                0x9128
index de18ef2..16e39c7 100644 (file)
@@ -4,6 +4,7 @@
 /*
  * Copyright (C) 2006 - 2007 Ivo van Doorn
  * Copyright (C) 2007 Dmitry Torokhov
+ * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  */
 
 #include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/mutex.h>
-#include <linux/device.h>
-#include <linux/leds.h>
+
+/* define userspace visible states */
+#define RFKILL_STATE_SOFT_BLOCKED      0
+#define RFKILL_STATE_UNBLOCKED         1
+#define RFKILL_STATE_HARD_BLOCKED      2
 
 /**
  * enum rfkill_type - type of rfkill switch.
- * RFKILL_TYPE_WLAN: switch is on a 802.11 wireless network device.
- * RFKILL_TYPE_BLUETOOTH: switch is on a bluetooth device.
- * RFKILL_TYPE_UWB: switch is on a ultra wideband device.
- * RFKILL_TYPE_WIMAX: switch is on a WiMAX device.
- * RFKILL_TYPE_WWAN: switch is on a wireless WAN device.
+ *
+ * @RFKILL_TYPE_ALL: toggles all switches (userspace only)
+ * @RFKILL_TYPE_WLAN: switch is on a 802.11 wireless network device.
+ * @RFKILL_TYPE_BLUETOOTH: switch is on a bluetooth device.
+ * @RFKILL_TYPE_UWB: switch is on a ultra wideband device.
+ * @RFKILL_TYPE_WIMAX: switch is on a WiMAX device.
+ * @RFKILL_TYPE_WWAN: switch is on a wireless WAN device.
+ * @NUM_RFKILL_TYPES: number of defined rfkill types
  */
 enum rfkill_type {
-       RFKILL_TYPE_WLAN ,
+       RFKILL_TYPE_ALL = 0,
+       RFKILL_TYPE_WLAN,
        RFKILL_TYPE_BLUETOOTH,
        RFKILL_TYPE_UWB,
        RFKILL_TYPE_WIMAX,
        RFKILL_TYPE_WWAN,
-       RFKILL_TYPE_MAX,
+       NUM_RFKILL_TYPES,
 };
 
-enum rfkill_state {
-       RFKILL_STATE_SOFT_BLOCKED = 0,  /* Radio output blocked */
-       RFKILL_STATE_UNBLOCKED    = 1,  /* Radio output allowed */
-       RFKILL_STATE_HARD_BLOCKED = 2,  /* Output blocked, non-overrideable */
-       RFKILL_STATE_MAX,               /* marker for last valid state */
+/**
+ * enum rfkill_operation - operation types
+ * @RFKILL_OP_ADD: a device was added
+ * @RFKILL_OP_DEL: a device was removed
+ * @RFKILL_OP_CHANGE: a device's state changed -- userspace changes one device
+ * @RFKILL_OP_CHANGE_ALL: userspace changes all devices (of a type, or all)
+ */
+enum rfkill_operation {
+       RFKILL_OP_ADD = 0,
+       RFKILL_OP_DEL,
+       RFKILL_OP_CHANGE,
+       RFKILL_OP_CHANGE_ALL,
 };
 
 /**
- * struct rfkill - rfkill control structure.
- * @name: Name of the switch.
- * @type: Radio type which the button controls, the value stored
- *     here should be a value from enum rfkill_type.
- * @state: State of the switch, "UNBLOCKED" means radio can operate.
- * @mutex: Guards switch state transitions.  It serializes callbacks
- *     and also protects the state.
- * @data: Pointer to the RF button drivers private data which will be
- *     passed along when toggling radio state.
- * @toggle_radio(): Mandatory handler to control state of the radio.
- *     only RFKILL_STATE_SOFT_BLOCKED and RFKILL_STATE_UNBLOCKED are
- *     valid parameters.
- * @get_state(): handler to read current radio state from hardware,
- *      may be called from atomic context, should return 0 on success.
- *      Either this handler OR judicious use of rfkill_force_state() is
- *      MANDATORY for any driver capable of RFKILL_STATE_HARD_BLOCKED.
- * @led_trigger: A LED trigger for this button's LED.
- * @dev: Device structure integrating the switch into device tree.
- * @node: Used to place switch into list of all switches known to the
- *     the system.
- *
- * This structure represents a RF switch located on a network device.
- */
-struct rfkill {
-       const char *name;
-       enum rfkill_type type;
-
-       /* the mutex serializes callbacks and also protects
-        * the state */
-       struct mutex mutex;
-       enum rfkill_state state;
-       void *data;
-       int (*toggle_radio)(void *data, enum rfkill_state state);
-       int (*get_state)(void *data, enum rfkill_state *state);
+ * struct rfkill_event - events for userspace on /dev/rfkill
+ * @idx: index of dev rfkill
+ * @type: type of the rfkill struct
+ * @op: operation code
+ * @hard: hard state (0/1)
+ * @soft: soft state (0/1)
+ *
+ * Structure used for userspace communication on /dev/rfkill,
+ * used for events from the kernel and control to the kernel.
+ */
+struct rfkill_event {
+       __u32 idx;
+       __u8  type;
+       __u8  op;
+       __u8  soft, hard;
+} __packed;
 
-#ifdef CONFIG_RFKILL_LEDS
-       struct led_trigger led_trigger;
-#endif
+/* ioctl for turning off rfkill-input (if present) */
+#define RFKILL_IOC_MAGIC       'R'
+#define RFKILL_IOC_NOINPUT     1
+#define RFKILL_IOCTL_NOINPUT   _IO(RFKILL_IOC_MAGIC, RFKILL_IOC_NOINPUT)
+
+/* and that's all userspace gets */
+#ifdef __KERNEL__
+/* don't allow anyone to use these in the kernel */
+enum rfkill_user_states {
+       RFKILL_USER_STATE_SOFT_BLOCKED  = RFKILL_STATE_SOFT_BLOCKED,
+       RFKILL_USER_STATE_UNBLOCKED     = RFKILL_STATE_UNBLOCKED,
+       RFKILL_USER_STATE_HARD_BLOCKED  = RFKILL_STATE_HARD_BLOCKED,
+};
+#undef RFKILL_STATE_SOFT_BLOCKED
+#undef RFKILL_STATE_UNBLOCKED
+#undef RFKILL_STATE_HARD_BLOCKED
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/leds.h>
+#include <linux/err.h>
+
+/* this is opaque */
+struct rfkill;
 
-       struct device dev;
-       struct list_head node;
-       enum rfkill_state state_for_resume;
+/**
+ * struct rfkill_ops - rfkill driver methods
+ *
+ * @poll: poll the rfkill block state(s) -- only assign this method
+ *     when you need polling. When called, simply call one of the
+ *     rfkill_set{,_hw,_sw}_state family of functions. If the hw
+ *     is getting unblocked you need to take into account the return
+ *     value of those functions to make sure the software block is
+ *     properly used.
+ * @query: query the rfkill block state(s) and call exactly one of the
+ *     rfkill_set{,_hw,_sw}_state family of functions. Assign this
+ *     method if input events can cause hardware state changes to make
+ *     the rfkill core query your driver before setting a requested
+ *     block.
+ * @set_block: turn the transmitter on (blocked == false) or off
+ *     (blocked == true) -- ignore and return 0 when hard blocked.
+ *     This callback must be assigned.
+ */
+struct rfkill_ops {
+       void    (*poll)(struct rfkill *rfkill, void *data);
+       void    (*query)(struct rfkill *rfkill, void *data);
+       int     (*set_block)(void *data, bool blocked);
 };
-#define to_rfkill(d)   container_of(d, struct rfkill, dev)
 
-struct rfkill * __must_check rfkill_allocate(struct device *parent,
-                                            enum rfkill_type type);
-void rfkill_free(struct rfkill *rfkill);
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
+/**
+ * rfkill_alloc - allocate rfkill structure
+ * @name: name of the struct -- the string is not copied internally
+ * @parent: device that has rf switch on it
+ * @type: type of the switch (RFKILL_TYPE_*)
+ * @ops: rfkill methods
+ * @ops_data: data passed to each method
+ *
+ * This function should be called by the transmitter driver to allocate an
+ * rfkill structure. Returns %NULL on failure.
+ */
+struct rfkill * __must_check rfkill_alloc(const char *name,
+                                         struct device *parent,
+                                         const enum rfkill_type type,
+                                         const struct rfkill_ops *ops,
+                                         void *ops_data);
+
+/**
+ * rfkill_register - Register a rfkill structure.
+ * @rfkill: rfkill structure to be registered
+ *
+ * This function should be called by the transmitter driver to register
+ * the rfkill structure. Before calling this function the driver needs
+ * to be ready to service method calls from rfkill.
+ *
+ * If the software blocked state is not set before registration,
+ * set_block will be called to initialize it to a default value.
+ *
+ * If the hardware blocked state is not set before registration,
+ * it is assumed to be unblocked.
+ */
 int __must_check rfkill_register(struct rfkill *rfkill);
+
+/**
+ * rfkill_pause_polling(struct rfkill *rfkill)
+ *
+ * Pause polling -- say transmitter is off for other reasons.
+ * NOTE: not necessary for suspend/resume -- in that case the
+ * core stops polling anyway
+ */
+void rfkill_pause_polling(struct rfkill *rfkill);
+
+/**
+ * rfkill_resume_polling(struct rfkill *rfkill)
+ *
+ * Pause polling -- say transmitter is off for other reasons.
+ * NOTE: not necessary for suspend/resume -- in that case the
+ * core stops polling anyway
+ */
+void rfkill_resume_polling(struct rfkill *rfkill);
+
+
+/**
+ * rfkill_unregister - Unregister a rfkill structure.
+ * @rfkill: rfkill structure to be unregistered
+ *
+ * This function should be called by the network driver during device
+ * teardown to destroy rfkill structure. Until it returns, the driver
+ * needs to be able to service method calls.
+ */
 void rfkill_unregister(struct rfkill *rfkill);
 
-int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state);
-int rfkill_set_default(enum rfkill_type type, enum rfkill_state state);
+/**
+ * rfkill_destroy - free rfkill structure
+ * @rfkill: rfkill structure to be destroyed
+ *
+ * Destroys the rfkill structure.
+ */
+void rfkill_destroy(struct rfkill *rfkill);
+
+/**
+ * rfkill_set_hw_state - Set the internal rfkill hardware block state
+ * @rfkill: pointer to the rfkill class to modify.
+ * @state: the current hardware block state to set
+ *
+ * rfkill drivers that get events when the hard-blocked state changes
+ * use this function to notify the rfkill core (and through that also
+ * userspace) of the current state.  They should also use this after
+ * resume if the state could have changed.
+ *
+ * You need not (but may) call this function if poll_state is assigned.
+ *
+ * This function can be called in any context, even from within rfkill
+ * callbacks.
+ *
+ * The function returns the combined block state (true if transmitter
+ * should be blocked) so that drivers need not keep track of the soft
+ * block state -- which they might not be able to.
+ */
+bool __must_check rfkill_set_hw_state(struct rfkill *rfkill, bool blocked);
+
+/**
+ * rfkill_set_sw_state - Set the internal rfkill software block state
+ * @rfkill: pointer to the rfkill class to modify.
+ * @state: the current software block state to set
+ *
+ * rfkill drivers that get events when the soft-blocked state changes
+ * (yes, some platforms directly act on input but allow changing again)
+ * use this function to notify the rfkill core (and through that also
+ * userspace) of the current state.  It is not necessary to notify on
+ * resume; since hibernation can always change the soft-blocked state,
+ * the rfkill core will unconditionally restore the previous state.
+ *
+ * This function can be called in any context, even from within rfkill
+ * callbacks.
+ *
+ * The function returns the combined block state (true if transmitter
+ * should be blocked).
+ */
+bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked);
+
+/**
+ * rfkill_set_states - Set the internal rfkill block states
+ * @rfkill: pointer to the rfkill class to modify.
+ * @sw: the current software block state to set
+ * @hw: the current hardware block state to set
+ *
+ * This function can be called in any context, even from within rfkill
+ * callbacks.
+ */
+void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw);
 
 /**
- * rfkill_state_complement - return complementar state
- * @state: state to return the complement of
+ * rfkill_blocked - query rfkill block
  *
- * Returns RFKILL_STATE_SOFT_BLOCKED if @state is RFKILL_STATE_UNBLOCKED,
- * returns RFKILL_STATE_UNBLOCKED otherwise.
+ * @rfkill: rfkill struct to query
  */
-static inline enum rfkill_state rfkill_state_complement(enum rfkill_state state)
+bool rfkill_blocked(struct rfkill *rfkill);
+#else /* !RFKILL */
+static inline struct rfkill * __must_check
+rfkill_alloc(const char *name,
+            struct device *parent,
+            const enum rfkill_type type,
+            const struct rfkill_ops *ops,
+            void *ops_data)
+{
+       return ERR_PTR(-ENODEV);
+}
+
+static inline int __must_check rfkill_register(struct rfkill *rfkill)
+{
+       if (rfkill == ERR_PTR(-ENODEV))
+               return 0;
+       return -EINVAL;
+}
+
+static inline void rfkill_pause_polling(struct rfkill *rfkill)
+{
+}
+
+static inline void rfkill_resume_polling(struct rfkill *rfkill)
+{
+}
+
+static inline void rfkill_unregister(struct rfkill *rfkill)
+{
+}
+
+static inline void rfkill_destroy(struct rfkill *rfkill)
 {
-       return (state == RFKILL_STATE_UNBLOCKED) ?
-               RFKILL_STATE_SOFT_BLOCKED : RFKILL_STATE_UNBLOCKED;
 }
 
+static inline bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked)
+{
+       return blocked;
+}
+
+static inline bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked)
+{
+       return blocked;
+}
+
+static inline void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw)
+{
+}
+
+static inline bool rfkill_blocked(struct rfkill *rfkill)
+{
+       return false;
+}
+#endif /* RFKILL || RFKILL_MODULE */
+
+
+#ifdef CONFIG_RFKILL_LEDS
 /**
- * rfkill_get_led_name - Get the LED trigger name for the button's LED.
+ * rfkill_get_led_trigger_name - Get the LED trigger name for the button's LED.
  * This function might return a NULL pointer if registering of the
- * LED trigger failed.
- * Use this as "default_trigger" for the LED.
+ * LED trigger failed. Use this as "default_trigger" for the LED.
  */
-static inline char *rfkill_get_led_name(struct rfkill *rfkill)
-{
-#ifdef CONFIG_RFKILL_LEDS
-       return (char *)(rfkill->led_trigger.name);
+const char *rfkill_get_led_trigger_name(struct rfkill *rfkill);
+
+/**
+ * rfkill_set_led_trigger_name -- set the LED trigger name
+ * @rfkill: rfkill struct
+ * @name: LED trigger name
+ *
+ * This function sets the LED trigger name of the radio LED
+ * trigger that rfkill creates. It is optional, but if called
+ * must be called before rfkill_register() to be effective.
+ */
+void rfkill_set_led_trigger_name(struct rfkill *rfkill, const char *name);
 #else
+static inline const char *rfkill_get_led_trigger_name(struct rfkill *rfkill)
+{
        return NULL;
-#endif
 }
 
+static inline void
+rfkill_set_led_trigger_name(struct rfkill *rfkill, const char *name)
+{
+}
+#endif
+
+#endif /* __KERNEL__ */
+
 #endif /* RFKILL_H */
index c2731bf..b464b9d 100644 (file)
@@ -487,17 +487,17 @@ typedef enum {
         *
         * Value          Cause Code
         * ---------      ----------------
-        * 0x0100          Request to Delete Last Remaining IP Address.
-        * 0x0101          Operation Refused Due to Resource Shortage.
-        * 0x0102          Request to Delete Source IP Address.
-        * 0x0103          Association Aborted due to illegal ASCONF-ACK
-        * 0x0104          Request refused - no authorization.
+        * 0x00A0          Request to Delete Last Remaining IP Address.
+        * 0x00A1          Operation Refused Due to Resource Shortage.
+        * 0x00A2          Request to Delete Source IP Address.
+        * 0x00A3          Association Aborted due to illegal ASCONF-ACK
+        * 0x00A4          Request refused - no authorization.
         */
-       SCTP_ERROR_DEL_LAST_IP  = cpu_to_be16(0x0100),
-       SCTP_ERROR_RSRC_LOW     = cpu_to_be16(0x0101),
-       SCTP_ERROR_DEL_SRC_IP   = cpu_to_be16(0x0102),
-       SCTP_ERROR_ASCONF_ACK   = cpu_to_be16(0x0103),
-       SCTP_ERROR_REQ_REFUSED  = cpu_to_be16(0x0104),
+       SCTP_ERROR_DEL_LAST_IP  = cpu_to_be16(0x00A0),
+       SCTP_ERROR_RSRC_LOW     = cpu_to_be16(0x00A1),
+       SCTP_ERROR_DEL_SRC_IP   = cpu_to_be16(0x00A2),
+       SCTP_ERROR_ASCONF_ACK   = cpu_to_be16(0x00A3),
+       SCTP_ERROR_REQ_REFUSED  = cpu_to_be16(0x00A4),
 
        /* AUTH Section 4.  New Error Cause
         *
index aff494b..fa51293 100644 (file)
@@ -189,19 +189,19 @@ struct skb_shared_info {
        atomic_t        dataref;
        unsigned short  nr_frags;
        unsigned short  gso_size;
+#ifdef CONFIG_HAS_DMA
+       dma_addr_t      dma_head;
+#endif
        /* Warning: this field is not always filled in (UFO)! */
        unsigned short  gso_segs;
        unsigned short  gso_type;
        __be32          ip6_frag_id;
        union skb_shared_tx tx_flags;
-#ifdef CONFIG_HAS_DMA
-       unsigned int    num_dma_maps;
-#endif
        struct sk_buff  *frag_list;
        struct skb_shared_hwtstamps hwtstamps;
        skb_frag_t      frags[MAX_SKB_FRAGS];
 #ifdef CONFIG_HAS_DMA
-       dma_addr_t      dma_maps[MAX_SKB_FRAGS + 1];
+       dma_addr_t      dma_maps[MAX_SKB_FRAGS];
 #endif
        /* Intermediate layers must ensure that destructor_arg
         * remains valid until skb destructor */
@@ -304,9 +304,6 @@ typedef unsigned char *sk_buff_data_t;
  *     @tc_verd: traffic control verdict
  *     @ndisc_nodetype: router type (from link layer)
  *     @do_not_encrypt: set to prevent encryption of this frame
- *     @requeue: set to indicate that the wireless core should attempt
- *             a software retry on this frame if we failed to
- *             receive an ACK for it
  *     @dma_cookie: a cookie to one of several possible DMA operations
  *             done by skb DMA functions
  *     @secmark: security marking
@@ -322,10 +319,7 @@ struct sk_buff {
        ktime_t                 tstamp;
        struct net_device       *dev;
 
-       union {
-               struct  dst_entry       *dst;
-               struct  rtable          *rtable;
-       };
+       unsigned long           _skb_dst;
 #ifdef CONFIG_XFRM
        struct  sec_path        *sp;
 #endif
@@ -383,7 +377,6 @@ struct sk_buff {
 #endif
 #if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE)
        __u8                    do_not_encrypt:1;
-       __u8                    requeue:1;
 #endif
        /* 0/13/14 bit hole */
 
@@ -426,6 +419,21 @@ extern void skb_dma_unmap(struct device *dev, struct sk_buff *skb,
                          enum dma_data_direction dir);
 #endif
 
+static inline struct dst_entry *skb_dst(const struct sk_buff *skb)
+{
+       return (struct dst_entry *)skb->_skb_dst;
+}
+
+static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst)
+{
+       skb->_skb_dst = (unsigned long)dst;
+}
+
+static inline struct rtable *skb_rtable(const struct sk_buff *skb)
+{
+       return (struct rtable *)skb_dst(skb);
+}
+
 extern void kfree_skb(struct sk_buff *skb);
 extern void consume_skb(struct sk_buff *skb);
 extern void           __kfree_skb(struct sk_buff *skb);
@@ -1065,7 +1073,7 @@ extern void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page,
                            int off, int size);
 
 #define SKB_PAGE_ASSERT(skb)   BUG_ON(skb_shinfo(skb)->nr_frags)
-#define SKB_FRAG_ASSERT(skb)   BUG_ON(skb_shinfo(skb)->frag_list)
+#define SKB_FRAG_ASSERT(skb)   BUG_ON(skb_has_frags(skb))
 #define SKB_LINEAR_ASSERT(skb)  BUG_ON(skb_is_nonlinear(skb))
 
 #ifdef NET_SKBUFF_DATA_USES_OFFSET
@@ -1704,6 +1712,25 @@ static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len)
                     skb = skb->prev)
 
 
+static inline bool skb_has_frags(const struct sk_buff *skb)
+{
+       return skb_shinfo(skb)->frag_list != NULL;
+}
+
+static inline void skb_frag_list_init(struct sk_buff *skb)
+{
+       skb_shinfo(skb)->frag_list = NULL;
+}
+
+static inline void skb_frag_add_head(struct sk_buff *skb, struct sk_buff *frag)
+{
+       frag->next = skb_shinfo(skb)->frag_list;
+       skb_shinfo(skb)->frag_list = frag;
+}
+
+#define skb_walk_frags(skb, iter)      \
+       for (iter = skb_shinfo(skb)->frag_list; iter; iter = iter->next)
+
 extern struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags,
                                           int *peeked, int *err);
 extern struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags,
index d2310cb..3b461df 100644 (file)
@@ -194,7 +194,8 @@ struct ucred {
 #define AF_RXRPC       33      /* RxRPC sockets                */
 #define AF_ISDN                34      /* mISDN sockets                */
 #define AF_PHONET      35      /* Phonet sockets               */
-#define AF_MAX         36      /* For now.. */
+#define AF_IEEE802154  36      /* IEEE802154 sockets           */
+#define AF_MAX         37      /* For now.. */
 
 /* Protocol families, same as address families. */
 #define PF_UNSPEC      AF_UNSPEC
@@ -233,6 +234,7 @@ struct ucred {
 #define PF_RXRPC       AF_RXRPC
 #define PF_ISDN                AF_ISDN
 #define PF_PHONET      AF_PHONET
+#define PF_IEEE802154  AF_IEEE802154
 #define PF_MAX         AF_MAX
 
 /* Maximum queue length specifiable by listen.  */
index 79506f5..1b5d538 100644 (file)
@@ -22,9 +22,6 @@ struct libertas_spi_platform_data {
         * speed, you may want to use 0 here. */
        u16 use_dummy_writes;
 
-       /* GPIO number to use as chip select */
-       u16 gpio_cs;
-
        /* Board specific setup/teardown */
        int (*setup)(struct spi_device *spi);
        int (*teardown)(struct spi_device *spi);
index c89de7f..4fdcc56 100644 (file)
@@ -59,7 +59,7 @@ enum {
         * M - Major: change if removing or modifying an existing call.
         * m - minor: change when adding a new call
         */
-       WIMAX_GNL_VERSION = 00,
+       WIMAX_GNL_VERSION = 01,
        /* Generic NetLink attributes */
        WIMAX_GNL_ATTR_INVALID = 0x00,
        WIMAX_GNL_ATTR_MAX = 10,
@@ -78,6 +78,7 @@ enum {
        WIMAX_GNL_OP_RFKILL,    /* Run wimax_rfkill() */
        WIMAX_GNL_OP_RESET,     /* Run wimax_rfkill() */
        WIMAX_GNL_RE_STATE_CHANGE,      /* Report: status change */
+       WIMAX_GNL_OP_STATE_GET,         /* Request for current state */
 };
 
 
@@ -113,6 +114,10 @@ enum {
        WIMAX_GNL_RESET_IFIDX = 1,
 };
 
+/* Atributes for wimax_state_get() */
+enum {
+       WIMAX_GNL_STGET_IFIDX = 1,
+};
 
 /*
  * Attributes for the Report State Change
index 3ad5390..968166a 100644 (file)
@@ -81,12 +81,6 @@ enum {
        BT_CLOSED
 };
 
-/* Endianness conversions */
-#define htobs(a)       __cpu_to_le16(a)
-#define htobl(a)       __cpu_to_le32(a)
-#define btohs(a)       __le16_to_cpu(a)
-#define btohl(a)       __le32_to_cpu(a)
-
 /* BD Address */
 typedef struct {
        __u8 b[6];
@@ -171,15 +165,6 @@ static inline struct sk_buff *bt_skb_send_alloc(struct sock *sk, unsigned long l
        return skb;
 }
 
-static inline int skb_frags_no(struct sk_buff *skb)
-{
-       register struct sk_buff *frag = skb_shinfo(skb)->frag_list;
-       register int n = 1;
-
-       for (; frag; frag=frag->next, n++);
-       return n;
-}
-
 int bt_err(__u16 code);
 
 extern int hci_sock_init(void);
index 73aead2..c4ca422 100644 (file)
@@ -137,6 +137,8 @@ struct hci_dev {
        struct device           *parent;
        struct device           dev;
 
+       struct rfkill           *rfkill;
+
        struct module           *owner;
 
        int (*open)(struct hci_dev *hdev);
index f566aa1..e919fca 100644 (file)
 #define __L2CAP_H
 
 /* L2CAP defaults */
-#define L2CAP_DEFAULT_MTU      672
-#define L2CAP_DEFAULT_FLUSH_TO 0xFFFF
+#define L2CAP_DEFAULT_MTU              672
+#define L2CAP_DEFAULT_FLUSH_TO         0xffff
+#define L2CAP_DEFAULT_RX_WINDOW                1
+#define L2CAP_DEFAULT_MAX_RECEIVE      1
+#define L2CAP_DEFAULT_RETRANS_TO       300    /* 300 milliseconds */
+#define L2CAP_DEFAULT_MONITOR_TO       1000   /* 1 second */
+#define L2CAP_DEFAULT_MAX_RX_APDU      0xfff7
 
 #define L2CAP_CONN_TIMEOUT     (40000) /* 40 seconds */
 #define L2CAP_INFO_TIMEOUT     (4000)  /*  4 seconds */
@@ -64,17 +69,29 @@ struct l2cap_conninfo {
 #define L2CAP_LM_SECURE                0x0020
 
 /* L2CAP command codes */
-#define L2CAP_COMMAND_REJ 0x01
-#define L2CAP_CONN_REQ    0x02
-#define L2CAP_CONN_RSP    0x03
-#define L2CAP_CONF_REQ    0x04
-#define L2CAP_CONF_RSP    0x05
-#define L2CAP_DISCONN_REQ 0x06
-#define L2CAP_DISCONN_RSP 0x07
-#define L2CAP_ECHO_REQ    0x08
-#define L2CAP_ECHO_RSP    0x09
-#define L2CAP_INFO_REQ    0x0a
-#define L2CAP_INFO_RSP    0x0b
+#define L2CAP_COMMAND_REJ      0x01
+#define L2CAP_CONN_REQ         0x02
+#define L2CAP_CONN_RSP         0x03
+#define L2CAP_CONF_REQ         0x04
+#define L2CAP_CONF_RSP         0x05
+#define L2CAP_DISCONN_REQ      0x06
+#define L2CAP_DISCONN_RSP      0x07
+#define L2CAP_ECHO_REQ         0x08
+#define L2CAP_ECHO_RSP         0x09
+#define L2CAP_INFO_REQ         0x0a
+#define L2CAP_INFO_RSP         0x0b
+
+/* L2CAP feature mask */
+#define L2CAP_FEAT_FLOWCTL     0x00000001
+#define L2CAP_FEAT_RETRANS     0x00000002
+#define L2CAP_FEAT_ERTM                0x00000008
+#define L2CAP_FEAT_STREAMING   0x00000010
+#define L2CAP_FEAT_FCS         0x00000020
+#define L2CAP_FEAT_FIXED_CHAN  0x00000080
+
+/* L2CAP checksum option */
+#define L2CAP_FCS_NONE         0x00
+#define L2CAP_FCS_CRC16                0x01
 
 /* L2CAP structures */
 struct l2cap_hdr {
@@ -106,17 +123,23 @@ struct l2cap_conn_rsp {
        __le16     status;
 } __attribute__ ((packed));
 
+/* channel indentifier */
+#define L2CAP_CID_SIGNALING    0x0001
+#define L2CAP_CID_CONN_LESS    0x0002
+#define L2CAP_CID_DYN_START    0x0040
+#define L2CAP_CID_DYN_END      0xffff
+
 /* connect result */
-#define L2CAP_CR_SUCCESS    0x0000
-#define L2CAP_CR_PEND       0x0001
-#define L2CAP_CR_BAD_PSM    0x0002
-#define L2CAP_CR_SEC_BLOCK  0x0003
-#define L2CAP_CR_NO_MEM     0x0004
+#define L2CAP_CR_SUCCESS       0x0000
+#define L2CAP_CR_PEND          0x0001
+#define L2CAP_CR_BAD_PSM       0x0002
+#define L2CAP_CR_SEC_BLOCK     0x0003
+#define L2CAP_CR_NO_MEM                0x0004
 
 /* connect status */
-#define L2CAP_CS_NO_INFO      0x0000
-#define L2CAP_CS_AUTHEN_PEND  0x0001
-#define L2CAP_CS_AUTHOR_PEND  0x0002
+#define L2CAP_CS_NO_INFO       0x0000
+#define L2CAP_CS_AUTHEN_PEND   0x0001
+#define L2CAP_CS_AUTHOR_PEND   0x0002
 
 struct l2cap_conf_req {
        __le16     dcid;
@@ -143,10 +166,14 @@ struct l2cap_conf_opt {
 } __attribute__ ((packed));
 #define L2CAP_CONF_OPT_SIZE    2
 
+#define L2CAP_CONF_HINT                0x80
+#define L2CAP_CONF_MASK                0x7f
+
 #define L2CAP_CONF_MTU         0x01
 #define L2CAP_CONF_FLUSH_TO    0x02
 #define L2CAP_CONF_QOS         0x03
 #define L2CAP_CONF_RFC         0x04
+#define L2CAP_CONF_FCS         0x05
 
 #define L2CAP_CONF_MAX_SIZE    22
 
@@ -162,6 +189,8 @@ struct l2cap_conf_rfc {
 #define L2CAP_MODE_BASIC       0x00
 #define L2CAP_MODE_RETRANS     0x01
 #define L2CAP_MODE_FLOWCTL     0x02
+#define L2CAP_MODE_ERTM                0x03
+#define L2CAP_MODE_STREAM      0x04
 
 struct l2cap_disconn_req {
        __le16     dcid;
index f20da7d..1a21895 100644 (file)
@@ -752,6 +752,19 @@ enum wiphy_params_flags {
 };
 
 /**
+ * enum tx_power_setting - TX power adjustment
+ *
+ * @TX_POWER_AUTOMATIC: the dbm parameter is ignored
+ * @TX_POWER_LIMITED: limit TX power by the dbm parameter
+ * @TX_POWER_FIXED: fix TX power to the dbm parameter
+ */
+enum tx_power_setting {
+       TX_POWER_AUTOMATIC,
+       TX_POWER_LIMITED,
+       TX_POWER_FIXED,
+};
+
+/**
  * struct cfg80211_ops - backend description for wireless configuration
  *
  * This struct is registered by fullmac card drivers and/or wireless stacks
@@ -837,6 +850,13 @@ enum wiphy_params_flags {
  *     @changed bitfield (see &enum wiphy_params_flags) describes which values
  *     have changed. The actual parameter values are available in
  *     struct wiphy. If returning an error, no value should be changed.
+ *
+ * @set_tx_power: set the transmit power according to the parameters
+ * @get_tx_power: store the current TX power into the dbm variable;
+ *     return 0 if successful
+ *
+ * @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting
+ *     functions to adjust rfkill hw state
  */
 struct cfg80211_ops {
        int     (*suspend)(struct wiphy *wiphy);
@@ -928,6 +948,12 @@ struct cfg80211_ops {
        int     (*leave_ibss)(struct wiphy *wiphy, struct net_device *dev);
 
        int     (*set_wiphy_params)(struct wiphy *wiphy, u32 changed);
+
+       int     (*set_tx_power)(struct wiphy *wiphy,
+                               enum tx_power_setting type, int dbm);
+       int     (*get_tx_power)(struct wiphy *wiphy, int *dbm);
+
+       void    (*rfkill_poll)(struct wiphy *wiphy);
 };
 
 /*
@@ -1451,6 +1477,12 @@ int cfg80211_wext_siwencode(struct net_device *dev,
 int cfg80211_wext_giwencode(struct net_device *dev,
                            struct iw_request_info *info,
                            struct iw_point *erq, char *keybuf);
+int cfg80211_wext_siwtxpower(struct net_device *dev,
+                            struct iw_request_info *info,
+                            union iwreq_data *data, char *keybuf);
+int cfg80211_wext_giwtxpower(struct net_device *dev,
+                            struct iw_request_info *info,
+                            union iwreq_data *data, char *keybuf);
 
 /*
  * callbacks for asynchronous cfg80211 methods, notification
@@ -1636,4 +1668,23 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
  */
 void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp);
 
+/**
+ * wiphy_rfkill_set_hw_state - notify cfg80211 about hw block state
+ * @wiphy: the wiphy
+ * @blocked: block status
+ */
+void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked);
+
+/**
+ * wiphy_rfkill_start_polling - start polling rfkill
+ * @wiphy: the wiphy
+ */
+void wiphy_rfkill_start_polling(struct wiphy *wiphy);
+
+/**
+ * wiphy_rfkill_stop_polling - stop polling rfkill
+ * @wiphy: the wiphy
+ */
+void wiphy_rfkill_stop_polling(struct wiphy *wiphy);
+
 #endif /* __NET_CFG80211_H */
index 6be3b08..7fc409c 100644 (file)
@@ -195,6 +195,12 @@ struct dst_entry * dst_clone(struct dst_entry * dst)
 }
 
 extern void dst_release(struct dst_entry *dst);
+static inline void skb_dst_drop(struct sk_buff *skb)
+{
+       if (skb->_skb_dst)
+               dst_release(skb_dst(skb));
+       skb->_skb_dst = 0UL;
+}
 
 /* Children define the path of the packet through the
  * Linux networking.  Thus, destinations are stackable.
@@ -246,7 +252,7 @@ static inline void dst_negative_advice(struct dst_entry **dst_p)
 
 static inline void dst_link_failure(struct sk_buff *skb)
 {
-       struct dst_entry * dst = skb->dst;
+       struct dst_entry *dst = skb_dst(skb);
        if (dst && dst->ops && dst->ops->link_failure)
                dst->ops->link_failure(skb);
 }
@@ -265,13 +271,13 @@ static inline void dst_set_expires(struct dst_entry *dst, int timeout)
 /* Output packet to network from transport.  */
 static inline int dst_output(struct sk_buff *skb)
 {
-       return skb->dst->output(skb);
+       return skb_dst(skb)->output(skb);
 }
 
 /* Input packet from network to transport.  */
 static inline int dst_input(struct sk_buff *skb)
 {
-       return skb->dst->input(skb);
+       return skb_dst(skb)->input(skb);
 }
 
 static inline struct dst_entry *dst_check(struct dst_entry *dst, u32 cookie)
diff --git a/include/net/ieee802154/af_ieee802154.h b/include/net/ieee802154/af_ieee802154.h
new file mode 100644 (file)
index 0000000..0d78605
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * IEEE 802.15.4 inteface for userspace
+ *
+ * Copyright 2007, 2008 Siemens AG
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by:
+ * Sergey Lapin <slapin@ossfans.org>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+
+#ifndef _AF_IEEE802154_H
+#define _AF_IEEE802154_H
+
+#include <linux/socket.h> /* for sa_family_t */
+
+enum {
+       IEEE802154_ADDR_NONE = 0x0,
+       /* RESERVED = 0x01, */
+       IEEE802154_ADDR_SHORT = 0x2, /* 16-bit address + PANid */
+       IEEE802154_ADDR_LONG = 0x3, /* 64-bit address + PANid */
+};
+
+/* address length, octets */
+#define IEEE802154_ADDR_LEN    8
+
+struct ieee802154_addr {
+       int addr_type;
+       u16 pan_id;
+       union {
+               u8 hwaddr[IEEE802154_ADDR_LEN];
+               u16 short_addr;
+       };
+};
+
+#define IEEE802154_PANID_BROADCAST     0xffff
+#define IEEE802154_ADDR_BROADCAST      0xffff
+#define IEEE802154_ADDR_UNDEF          0xfffe
+
+struct sockaddr_ieee802154 {
+       sa_family_t family; /* AF_IEEE802154 */
+       struct ieee802154_addr addr;
+};
+
+/* master device */
+#define IEEE802154_SIOC_ADD_SLAVE              (SIOCDEVPRIVATE + 0)
+
+#endif
diff --git a/include/net/ieee802154/mac_def.h b/include/net/ieee802154/mac_def.h
new file mode 100644 (file)
index 0000000..8cb6846
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * IEEE802.15.4-2003 specification
+ *
+ * Copyright (C) 2007, 2008 Siemens AG
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by:
+ * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
+ * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
+ * Maxim Osipov <maxim.osipov@siemens.com>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+
+#ifndef IEEE802154_MAC_DEF_H
+#define IEEE802154_MAC_DEF_H
+
+#define IEEE802154_FC_TYPE_BEACON      0x0     /* Frame is beacon */
+#define        IEEE802154_FC_TYPE_DATA         0x1     /* Frame is data */
+#define IEEE802154_FC_TYPE_ACK         0x2     /* Frame is acknowledgment */
+#define IEEE802154_FC_TYPE_MAC_CMD     0x3     /* Frame is MAC command */
+
+#define IEEE802154_FC_TYPE_SHIFT               0
+#define IEEE802154_FC_TYPE_MASK                ((1 << 3) - 1)
+#define IEEE802154_FC_TYPE(x)          ((x & IEEE802154_FC_TYPE_MASK) >> IEEE802154_FC_TYPE_SHIFT)
+#define IEEE802154_FC_SET_TYPE(v, x)   do {    \
+       v = (((v) & ~IEEE802154_FC_TYPE_MASK) | \
+           (((x) << IEEE802154_FC_TYPE_SHIFT) & IEEE802154_FC_TYPE_MASK)); \
+       } while (0)
+
+#define IEEE802154_FC_SECEN            (1 << 3)
+#define IEEE802154_FC_FRPEND           (1 << 4)
+#define IEEE802154_FC_ACK_REQ          (1 << 5)
+#define IEEE802154_FC_INTRA_PAN                (1 << 6)
+
+#define IEEE802154_FC_SAMODE_SHIFT     14
+#define IEEE802154_FC_SAMODE_MASK      (3 << IEEE802154_FC_SAMODE_SHIFT)
+#define IEEE802154_FC_DAMODE_SHIFT     10
+#define IEEE802154_FC_DAMODE_MASK      (3 << IEEE802154_FC_DAMODE_SHIFT)
+
+#define IEEE802154_FC_SAMODE(x)                \
+       (((x) & IEEE802154_FC_SAMODE_MASK) >> IEEE802154_FC_SAMODE_SHIFT)
+
+#define IEEE802154_FC_DAMODE(x)                \
+       (((x) & IEEE802154_FC_DAMODE_MASK) >> IEEE802154_FC_DAMODE_SHIFT)
+
+
+/* MAC's Command Frames Identifiers */
+#define IEEE802154_CMD_ASSOCIATION_REQ         0x01
+#define IEEE802154_CMD_ASSOCIATION_RESP                0x02
+#define IEEE802154_CMD_DISASSOCIATION_NOTIFY   0x03
+#define IEEE802154_CMD_DATA_REQ                        0x04
+#define IEEE802154_CMD_PANID_CONFLICT_NOTIFY   0x05
+#define IEEE802154_CMD_ORPHAN_NOTIFY           0x06
+#define IEEE802154_CMD_BEACON_REQ              0x07
+#define IEEE802154_CMD_COORD_REALIGN_NOTIFY    0x08
+#define IEEE802154_CMD_GTS_REQ                 0x09
+
+/*
+ * The return values of MAC operations
+ */
+enum {
+       /*
+        * The requested operation was completed successfully.
+        * For a transmission request, this value indicates
+        * a successful transmission.
+        */
+       IEEE802154_SUCCESS = 0x0,
+
+       /* The beacon was lost following a synchronization request. */
+       IEEE802154_BEACON_LOSS = 0xe0,
+       /*
+        * A transmission could not take place due to activity on the
+        * channel, i.e., the CSMA-CA mechanism has failed.
+        */
+       IEEE802154_CHNL_ACCESS_FAIL = 0xe1,
+       /* The GTS request has been denied by the PAN coordinator. */
+       IEEE802154_DENINED = 0xe2,
+       /* The attempt to disable the transceiver has failed. */
+       IEEE802154_DISABLE_TRX_FAIL = 0xe3,
+       /*
+        * The received frame induces a failed security check according to
+        * the security suite.
+        */
+       IEEE802154_FAILED_SECURITY_CHECK = 0xe4,
+       /*
+        * The frame resulting from secure processing has a length that is
+        * greater than aMACMaxFrameSize.
+        */
+       IEEE802154_FRAME_TOO_LONG = 0xe5,
+       /*
+        * The requested GTS transmission failed because the specified GTS
+        * either did not have a transmit GTS direction or was not defined.
+        */
+       IEEE802154_INVALID_GTS = 0xe6,
+       /*
+        * A request to purge an MSDU from the transaction queue was made using
+        * an MSDU handle that was not found in the transaction table.
+        */
+       IEEE802154_INVALID_HANDLE = 0xe7,
+       /* A parameter in the primitive is out of the valid range.*/
+       IEEE802154_INVALID_PARAMETER = 0xe8,
+       /* No acknowledgment was received after aMaxFrameRetries. */
+       IEEE802154_NO_ACK = 0xe9,
+       /* A scan operation failed to find any network beacons.*/
+       IEEE802154_NO_BEACON = 0xea,
+       /* No response data were available following a request. */
+       IEEE802154_NO_DATA = 0xeb,
+       /* The operation failed because a short address was not allocated. */
+       IEEE802154_NO_SHORT_ADDRESS = 0xec,
+       /*
+        * A receiver enable request was unsuccessful because it could not be
+        * completed within the CAP.
+        */
+       IEEE802154_OUT_OF_CAP = 0xed,
+       /*
+        * A PAN identifier conflict has been detected and communicated to the
+        * PAN coordinator.
+        */
+       IEEE802154_PANID_CONFLICT = 0xee,
+       /* A coordinator realignment command has been received. */
+       IEEE802154_REALIGMENT = 0xef,
+       /* The transaction has expired and its information discarded. */
+       IEEE802154_TRANSACTION_EXPIRED = 0xf0,
+       /* There is no capacity to store the transaction. */
+       IEEE802154_TRANSACTION_OVERFLOW = 0xf1,
+       /*
+        * The transceiver was in the transmitter enabled state when the
+        * receiver was requested to be enabled.
+        */
+       IEEE802154_TX_ACTIVE = 0xf2,
+       /* The appropriate key is not available in the ACL. */
+       IEEE802154_UNAVAILABLE_KEY = 0xf3,
+       /*
+        * A SET/GET request was issued with the identifier of a PIB attribute
+        * that is not supported.
+        */
+       IEEE802154_UNSUPPORTED_ATTR = 0xf4,
+       /*
+        * A request to perform a scan operation failed because the MLME was
+        * in the process of performing a previously initiated scan operation.
+        */
+       IEEE802154_SCAN_IN_PROGRESS = 0xfc,
+};
+
+
+#endif
+
+
diff --git a/include/net/ieee802154/netdevice.h b/include/net/ieee802154/netdevice.h
new file mode 100644 (file)
index 0000000..e2506af
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * An interface between IEEE802.15.4 device and rest of the kernel.
+ *
+ * Copyright (C) 2007, 2008, 2009 Siemens AG
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by:
+ * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
+ * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
+ * Maxim Osipov <maxim.osipov@siemens.com>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+
+#ifndef IEEE802154_NETDEVICE_H
+#define IEEE802154_NETDEVICE_H
+
+/*
+ * A control block of skb passed between the ARPHRD_IEEE802154 device
+ * and other stack parts.
+ */
+struct ieee802154_mac_cb {
+       u8 lqi;
+       struct ieee802154_addr sa;
+       struct ieee802154_addr da;
+       u8 flags;
+       u8 seq;
+};
+
+static inline struct ieee802154_mac_cb *mac_cb(struct sk_buff *skb)
+{
+       return (struct ieee802154_mac_cb *)skb->cb;
+}
+
+#define MAC_CB_FLAG_TYPEMASK           ((1 << 3) - 1)
+
+#define MAC_CB_FLAG_ACKREQ             (1 << 3)
+#define MAC_CB_FLAG_SECEN              (1 << 4)
+#define MAC_CB_FLAG_INTRAPAN           (1 << 5)
+
+static inline int mac_cb_is_ackreq(struct sk_buff *skb)
+{
+       return mac_cb(skb)->flags & MAC_CB_FLAG_ACKREQ;
+}
+
+static inline int mac_cb_is_secen(struct sk_buff *skb)
+{
+       return mac_cb(skb)->flags & MAC_CB_FLAG_SECEN;
+}
+
+static inline int mac_cb_is_intrapan(struct sk_buff *skb)
+{
+       return mac_cb(skb)->flags & MAC_CB_FLAG_INTRAPAN;
+}
+
+static inline int mac_cb_type(struct sk_buff *skb)
+{
+       return mac_cb(skb)->flags & MAC_CB_FLAG_TYPEMASK;
+}
+
+#define IEEE802154_MAC_SCAN_ED         0
+#define IEEE802154_MAC_SCAN_ACTIVE     1
+#define IEEE802154_MAC_SCAN_PASSIVE    2
+#define IEEE802154_MAC_SCAN_ORPHAN     3
+
+/*
+ * This should be located at net_device->ml_priv
+ */
+struct ieee802154_mlme_ops {
+       int (*assoc_req)(struct net_device *dev,
+                       struct ieee802154_addr *addr,
+                       u8 channel, u8 cap);
+       int (*assoc_resp)(struct net_device *dev,
+                       struct ieee802154_addr *addr,
+                       u16 short_addr, u8 status);
+       int (*disassoc_req)(struct net_device *dev,
+                       struct ieee802154_addr *addr,
+                       u8 reason);
+       int (*start_req)(struct net_device *dev,
+                       struct ieee802154_addr *addr,
+                       u8 channel, u8 bcn_ord, u8 sf_ord,
+                       u8 pan_coord, u8 blx, u8 coord_realign);
+       int (*scan_req)(struct net_device *dev,
+                       u8 type, u32 channels, u8 duration);
+
+       /*
+        * FIXME: these should become the part of PIB/MIB interface.
+        * However we still don't have IB interface of any kind
+        */
+       u16 (*get_pan_id)(struct net_device *dev);
+       u16 (*get_short_addr)(struct net_device *dev);
+       u8 (*get_dsn)(struct net_device *dev);
+       u8 (*get_bsn)(struct net_device *dev);
+};
+
+static inline struct ieee802154_mlme_ops *ieee802154_mlme_ops(
+               struct net_device *dev)
+{
+       return dev->ml_priv;
+}
+
+#endif
+
+
diff --git a/include/net/ieee802154/nl802154.h b/include/net/ieee802154/nl802154.h
new file mode 100644 (file)
index 0000000..78efcdf
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * nl802154.h
+ *
+ * Copyright (C) 2007, 2008, 2009 Siemens AG
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef IEEE802154_NL_H
+#define IEEE802154_NL_H
+
+struct net_device;
+struct ieee802154_addr;
+
+int ieee802154_nl_assoc_indic(struct net_device *dev,
+               struct ieee802154_addr *addr, u8 cap);
+int ieee802154_nl_assoc_confirm(struct net_device *dev,
+               u16 short_addr, u8 status);
+int ieee802154_nl_disassoc_indic(struct net_device *dev,
+               struct ieee802154_addr *addr, u8 reason);
+int ieee802154_nl_disassoc_confirm(struct net_device *dev,
+               u8 status);
+int ieee802154_nl_scan_confirm(struct net_device *dev,
+               u8 status, u8 scan_type, u32 unscanned,
+               u8 *edl/*, struct list_head *pan_desc_list */);
+int ieee802154_nl_beacon_indic(struct net_device *dev, u16 panid,
+               u16 coord_addr);
+
+#endif
index f74665d..22c73a7 100644 (file)
@@ -100,7 +100,7 @@ static inline struct sock *__inet6_lookup_skb(struct inet_hashinfo *hashinfo,
 
        if (unlikely(sk = skb_steal_sock(skb)))
                return sk;
-       else return __inet6_lookup(dev_net(skb->dst->dev), hashinfo,
+       else return __inet6_lookup(dev_net(skb_dst(skb)->dev), hashinfo,
                                   &ipv6_hdr(skb)->saddr, sport,
                                   &ipv6_hdr(skb)->daddr, ntohs(dport),
                                   inet6_iif(skb));
index a44e224..d522dcf 100644 (file)
@@ -385,7 +385,7 @@ static inline struct sock *__inet_lookup_skb(struct inet_hashinfo *hashinfo,
        if (unlikely(sk = skb_steal_sock(skb)))
                return sk;
        else
-               return __inet_lookup(dev_net(skb->dst->dev), hashinfo,
+               return __inet_lookup(dev_net(skb_dst(skb)->dev), hashinfo,
                                     iph->saddr, sport,
                                     iph->daddr, dport, inet_iif(skb));
 }
index de0ecc7..20a6957 100644 (file)
@@ -130,7 +130,8 @@ struct inet_sock {
                                freebind:1,
                                hdrincl:1,
                                mc_loop:1,
-                               transparent:1;
+                               transparent:1,
+                               mc_all:1;
        int                     mc_index;
        __be32                  mc_addr;
        struct ip_mc_socklist   *mc_list;
index 5f53db7..0e1b8ae 100644 (file)
@@ -142,7 +142,7 @@ static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst,
 
 static inline int ipv6_unicast_destination(struct sk_buff *skb)
 {
-       struct rt6_info *rt = (struct rt6_info *) skb->dst;
+       struct rt6_info *rt = (struct rt6_info *) skb_dst(skb);
 
        return rt->rt6i_flags & RTF_LOCAL;
 }
index d72346f..c061044 100644 (file)
@@ -239,6 +239,8 @@ struct ieee80211_bss_conf {
  * @IEEE80211_TX_INTFL_NEED_TXPROCESSING: completely internal to mac80211,
  *     used to indicate that a pending frame requires TX processing before
  *     it can be sent out.
+ * @IEEE80211_TX_INTFL_RETRIED: completely internal to mac80211,
+ *     used to indicate that a frame was already retried due to PS
  */
 enum mac80211_tx_control_flags {
        IEEE80211_TX_CTL_REQ_TX_STATUS          = BIT(0),
@@ -256,6 +258,7 @@ enum mac80211_tx_control_flags {
        IEEE80211_TX_CTL_RATE_CTRL_PROBE        = BIT(12),
        IEEE80211_TX_INTFL_RCALGO               = BIT(13),
        IEEE80211_TX_INTFL_NEED_TXPROCESSING    = BIT(14),
+       IEEE80211_TX_INTFL_RETRIED              = BIT(15),
 };
 
 /**
@@ -526,8 +529,7 @@ enum ieee80211_conf_flags {
 /**
  * enum ieee80211_conf_changed - denotes which configuration changed
  *
- * @IEEE80211_CONF_CHANGE_RADIO_ENABLED: the value of radio_enabled changed
- * @_IEEE80211_CONF_CHANGE_BEACON_INTERVAL: DEPRECATED
+ * @_IEEE80211_CONF_CHANGE_RADIO_ENABLED: DEPRECATED
  * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed
  * @IEEE80211_CONF_CHANGE_RADIOTAP: the radiotap flag changed
  * @IEEE80211_CONF_CHANGE_PS: the PS flag or dynamic PS timeout changed
@@ -537,8 +539,7 @@ enum ieee80211_conf_flags {
  * @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed
  */
 enum ieee80211_conf_changed {
-       IEEE80211_CONF_CHANGE_RADIO_ENABLED     = BIT(0),
-       _IEEE80211_CONF_CHANGE_BEACON_INTERVAL  = BIT(1),
+       _IEEE80211_CONF_CHANGE_RADIO_ENABLED    = BIT(0),
        IEEE80211_CONF_CHANGE_LISTEN_INTERVAL   = BIT(2),
        IEEE80211_CONF_CHANGE_RADIOTAP          = BIT(3),
        IEEE80211_CONF_CHANGE_PS                = BIT(4),
@@ -549,12 +550,12 @@ enum ieee80211_conf_changed {
 };
 
 static inline __deprecated enum ieee80211_conf_changed
-__IEEE80211_CONF_CHANGE_BEACON_INTERVAL(void)
+__IEEE80211_CONF_CHANGE_RADIO_ENABLED(void)
 {
-       return _IEEE80211_CONF_CHANGE_BEACON_INTERVAL;
+       return _IEEE80211_CONF_CHANGE_RADIO_ENABLED;
 }
-#define IEEE80211_CONF_CHANGE_BEACON_INTERVAL \
-       __IEEE80211_CONF_CHANGE_BEACON_INTERVAL()
+#define IEEE80211_CONF_CHANGE_RADIO_ENABLED \
+       __IEEE80211_CONF_CHANGE_RADIO_ENABLED()
 
 /**
  * struct ieee80211_conf - configuration of the device
@@ -564,7 +565,7 @@ __IEEE80211_CONF_CHANGE_BEACON_INTERVAL(void)
  * @flags: configuration flags defined above
  *
  * @radio_enabled: when zero, driver is required to switch off the radio.
- * @beacon_int: beacon interval (TODO make interface config)
+ * @beacon_int: DEPRECATED, DO NOT USE
  *
  * @listen_interval: listen interval in units of beacon interval
  * @max_sleep_period: the maximum number of beacon intervals to sleep for
@@ -589,13 +590,13 @@ __IEEE80211_CONF_CHANGE_BEACON_INTERVAL(void)
  *    number of transmissions not the number of retries
  */
 struct ieee80211_conf {
-       int beacon_int;
+       int __deprecated beacon_int;
        u32 flags;
        int power_level, dynamic_ps_timeout;
        int max_sleep_period;
 
        u16 listen_interval;
-       bool radio_enabled;
+       bool __deprecated radio_enabled;
 
        u8 long_frame_max_tx_count, short_frame_max_tx_count;
 
@@ -1406,6 +1407,10 @@ enum ieee80211_ampdu_mlme_action {
  *     is the first frame we expect to perform the action on. Notice
  *     that TX/RX_STOP can pass NULL for this parameter.
  *     Returns a negative error code on failure.
+ *
+ * @rfkill_poll: Poll rfkill hardware state. If you need this, you also
+ *     need to set wiphy->rfkill_poll to %true before registration,
+ *     and need to call wiphy_rfkill_set_hw_state() in the callback.
  */
 struct ieee80211_ops {
        int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -1454,6 +1459,8 @@ struct ieee80211_ops {
        int (*ampdu_action)(struct ieee80211_hw *hw,
                            enum ieee80211_ampdu_mlme_action action,
                            struct ieee80211_sta *sta, u16 tid, u16 *ssn);
+
+       void (*rfkill_poll)(struct ieee80211_hw *hw);
 };
 
 /**
index e37fe31..120935b 100644 (file)
@@ -41,9 +41,10 @@ static inline void *qdisc_priv(struct Qdisc *q)
 typedef u64    psched_time_t;
 typedef long   psched_tdiff_t;
 
-/* Avoid doing 64 bit divide by 1000 */
-#define PSCHED_US2NS(x)                        ((s64)(x) << 10)
-#define PSCHED_NS2US(x)                        ((x) >> 10)
+/* Avoid doing 64 bit divide */
+#define PSCHED_SHIFT                   6
+#define PSCHED_US2NS(x)                        ((s64)(x) << PSCHED_SHIFT)
+#define PSCHED_NS2US(x)                        ((x) >> PSCHED_SHIFT)
 
 #define PSCHED_TICKS_PER_SEC           PSCHED_NS2US(NSEC_PER_SEC)
 #define PSCHED_PASTPERFECT             0
index 4e8cae0..40f6346 100644 (file)
@@ -210,7 +210,7 @@ static inline struct inet_peer *rt_get_peer(struct rtable *rt)
 
 static inline int inet_iif(const struct sk_buff *skb)
 {
-       return skb->rtable->rt_iif;
+       return skb_rtable(skb)->rt_iif;
 }
 
 #endif /* _ROUTE_H */
index 23f08fe..edfcacf 100644 (file)
@@ -1939,10 +1939,8 @@ void sctp_association_free(struct sctp_association *);
 void sctp_association_put(struct sctp_association *);
 void sctp_association_hold(struct sctp_association *);
 
-struct sctp_transport *sctp_assoc_choose_init_transport(
-       struct sctp_association *);
-struct sctp_transport *sctp_assoc_choose_shutdown_transport(
-       struct sctp_association *);
+struct sctp_transport *sctp_assoc_choose_alter_transport(
+       struct sctp_association *, struct sctp_transport *);
 void sctp_assoc_update_retran_path(struct sctp_association *);
 struct sctp_transport *sctp_assoc_lookup_paddr(const struct sctp_association *,
                                          const union sctp_addr *);
index b259fc5..1580c04 100644 (file)
@@ -147,6 +147,8 @@ enum sctp_optname {
 #define SCTP_GET_LOCAL_ADDRS   SCTP_GET_LOCAL_ADDRS
        SCTP_SOCKOPT_CONNECTX, /* CONNECTX requests. */
 #define SCTP_SOCKOPT_CONNECTX  SCTP_SOCKOPT_CONNECTX
+       SCTP_SOCKOPT_CONNECTX3, /* CONNECTX requests. (new implementation) */
+#define SCTP_SOCKOPT_CONNECTX3 SCTP_SOCKOPT_CONNECTX3
 };
 
 /*
index 4bb1ff9..010e14a 100644 (file)
@@ -1217,9 +1217,13 @@ static inline int skb_copy_to_page(struct sock *sk, char __user *from,
 
 static inline void skb_set_owner_w(struct sk_buff *skb, struct sock *sk)
 {
-       sock_hold(sk);
        skb->sk = sk;
        skb->destructor = sock_wfree;
+       /*
+        * We used to take a refcount on sk, but following operation
+        * is enough to guarantee sk_free() wont free this sock until
+        * all in-flight packets are completed
+        */
        atomic_add(skb->truesize, &sk->sk_wmem_alloc);
 }
 
index 6b3824e..2af7bf8 100644 (file)
 struct net_device;
 struct genl_info;
 struct wimax_dev;
-struct input_dev;
 
 /**
  * struct wimax_dev - Generic WiMAX device
@@ -293,8 +292,8 @@ struct input_dev;
  *     See wimax_reset()'s documentation.
  *
  * @name: [fill] A way to identify this device. We need to register a
- *     name with many subsystems (input for RFKILL, workqueue
- *     creation, etc). We can't use the network device name as that
+ *     name with many subsystems (rfkill, workqueue creation, etc).
+ *     We can't use the network device name as that
  *     might change and in some instances we don't know it yet (until
  *     we don't call register_netdev()). So we generate an unique one
  *     using the driver name and device bus id, place it here and use
@@ -316,9 +315,6 @@ struct input_dev;
  *
  * @rfkill: [private] integration into the RF-Kill infrastructure.
  *
- * @rfkill_input: [private] virtual input device to process the
- *     hardware RF Kill switches.
- *
  * @rf_sw: [private] State of the software radio switch (OFF/ON)
  *
  * @rf_hw: [private] State of the hardware radio switch (OFF/ON)
index 2e9f5c0..736bca4 100644 (file)
@@ -994,7 +994,7 @@ static inline int __xfrm_policy_check2(struct sock *sk, int dir,
                return __xfrm_policy_check(sk, ndir, skb, family);
 
        return  (!net->xfrm.policy_count[dir] && !skb->sp) ||
-               (skb->dst->flags & DST_NOPOLICY) ||
+               (skb_dst(skb)->flags & DST_NOPOLICY) ||
                __xfrm_policy_check(sk, ndir, skb, family);
 }
 
@@ -1048,7 +1048,7 @@ static inline int xfrm_route_forward(struct sk_buff *skb, unsigned short family)
        struct net *net = dev_net(skb->dev);
 
        return  !net->xfrm.policy_count[XFRM_POLICY_OUT] ||
-               (skb->dst->flags & DST_NOXFRM) ||
+               (skb_dst(skb)->flags & DST_NOXFRM) ||
                __xfrm_route_forward(skb, family);
 }
 
index d1e1054..fe64908 100644 (file)
@@ -378,13 +378,13 @@ static void vlan_sync_address(struct net_device *dev,
         * the new address */
        if (compare_ether_addr(vlandev->dev_addr, vlan->real_dev_addr) &&
            !compare_ether_addr(vlandev->dev_addr, dev->dev_addr))
-               dev_unicast_delete(dev, vlandev->dev_addr, ETH_ALEN);
+               dev_unicast_delete(dev, vlandev->dev_addr);
 
        /* vlan address was equal to the old address and is different from
         * the new address */
        if (!compare_ether_addr(vlandev->dev_addr, vlan->real_dev_addr) &&
            compare_ether_addr(vlandev->dev_addr, dev->dev_addr))
-               dev_unicast_add(dev, vlandev->dev_addr, ETH_ALEN);
+               dev_unicast_add(dev, vlandev->dev_addr);
 
        memcpy(vlan->real_dev_addr, dev->dev_addr, ETH_ALEN);
 }
@@ -758,7 +758,7 @@ static void __exit vlan_cleanup_module(void)
                BUG_ON(!hlist_empty(&vlan_group_hash[i]));
 
        unregister_pernet_gen_device(vlan_net_id, &vlan_net_ops);
-       synchronize_net();
+       rcu_barrier(); /* Wait for completion of call_rcu()'s */
 
        vlan_gvrp_uninit();
 }
index 1e2ad4c..96bad8f 100644 (file)
@@ -441,7 +441,7 @@ static int vlan_dev_open(struct net_device *dev)
                return -ENETDOWN;
 
        if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) {
-               err = dev_unicast_add(real_dev, dev->dev_addr, ETH_ALEN);
+               err = dev_unicast_add(real_dev, dev->dev_addr);
                if (err < 0)
                        goto out;
        }
@@ -470,7 +470,7 @@ clear_allmulti:
                dev_set_allmulti(real_dev, -1);
 del_unicast:
        if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr))
-               dev_unicast_delete(real_dev, dev->dev_addr, ETH_ALEN);
+               dev_unicast_delete(real_dev, dev->dev_addr);
 out:
        netif_carrier_off(dev);
        return err;
@@ -492,7 +492,7 @@ static int vlan_dev_stop(struct net_device *dev)
                dev_set_promiscuity(real_dev, -1);
 
        if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr))
-               dev_unicast_delete(real_dev, dev->dev_addr, dev->addr_len);
+               dev_unicast_delete(real_dev, dev->dev_addr);
 
        netif_carrier_off(dev);
        return 0;
@@ -511,13 +511,13 @@ static int vlan_dev_set_mac_address(struct net_device *dev, void *p)
                goto out;
 
        if (compare_ether_addr(addr->sa_data, real_dev->dev_addr)) {
-               err = dev_unicast_add(real_dev, addr->sa_data, ETH_ALEN);
+               err = dev_unicast_add(real_dev, addr->sa_data);
                if (err < 0)
                        return err;
        }
 
        if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr))
-               dev_unicast_delete(real_dev, dev->dev_addr, ETH_ALEN);
+               dev_unicast_delete(real_dev, dev->dev_addr);
 
 out:
        memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
index c19f549..7051b97 100644 (file)
@@ -179,6 +179,7 @@ source "net/lapb/Kconfig"
 source "net/econet/Kconfig"
 source "net/wanrouter/Kconfig"
 source "net/phonet/Kconfig"
+source "net/ieee802154/Kconfig"
 source "net/sched/Kconfig"
 source "net/dcb/Kconfig"
 
index 9e00a55..ba324ae 100644 (file)
@@ -60,6 +60,7 @@ obj-$(CONFIG_NET_9P)          += 9p/
 ifneq ($(CONFIG_DCB),)
 obj-y                          += dcb/
 endif
+obj-y                          += ieee802154/
 
 ifeq ($(CONFIG_NET),y)
 obj-$(CONFIG_SYSCTL)           += sysctl_net.o
index d6a9243..b603cba 100644 (file)
@@ -939,6 +939,7 @@ static unsigned long atalk_sum_skb(const struct sk_buff *skb, int offset,
                                   int len, unsigned long sum)
 {
        int start = skb_headlen(skb);
+       struct sk_buff *frag_iter;
        int i, copy;
 
        /* checksum stuff in header space */
@@ -977,26 +978,22 @@ static unsigned long atalk_sum_skb(const struct sk_buff *skb, int offset,
                start = end;
        }
 
-       if (skb_shinfo(skb)->frag_list) {
-               struct sk_buff *list = skb_shinfo(skb)->frag_list;
-
-               for (; list; list = list->next) {
-                       int end;
+       skb_walk_frags(skb, frag_iter) {
+               int end;
 
-                       WARN_ON(start > offset + len);
+               WARN_ON(start > offset + len);
 
-                       end = start + list->len;
-                       if ((copy = end - offset) > 0) {
-                               if (copy > len)
-                                       copy = len;
-                               sum = atalk_sum_skb(list, offset - start,
-                                                   copy, sum);
-                               if ((len -= copy) == 0)
-                                       return sum;
-                               offset += copy;
-                       }
-                       start = end;
+               end = start + frag_iter->len;
+               if ((copy = end - offset) > 0) {
+                       if (copy > len)
+                               copy = len;
+                       sum = atalk_sum_skb(frag_iter, offset - start,
+                                           copy, sum);
+                       if ((len -= copy) == 0)
+                               return sum;
+                       offset += copy;
                }
+               start = end;
        }
 
        BUG_ON(len > 0);
index 3100a89..2912665 100644 (file)
@@ -228,7 +228,7 @@ static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev)
        struct br2684_dev *brdev = BRPRIV(dev);
        struct br2684_vcc *brvcc;
 
-       pr_debug("br2684_start_xmit, skb->dst=%p\n", skb->dst);
+       pr_debug("br2684_start_xmit, skb_dst(skb)=%p\n", skb_dst(skb));
        read_lock(&devs_lock);
        brvcc = pick_outgoing_vcc(skb, brdev);
        if (brvcc == NULL) {
@@ -445,9 +445,10 @@ free_skb:
  */
 static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
 {
+       struct sk_buff_head queue;
        int err;
        struct br2684_vcc *brvcc;
-       struct sk_buff *skb;
+       struct sk_buff *skb, *tmp;
        struct sk_buff_head *rq;
        struct br2684_dev *brdev;
        struct net_device *net_dev;
@@ -505,29 +506,20 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
        barrier();
        atmvcc->push = br2684_push;
 
+       __skb_queue_head_init(&queue);
        rq = &sk_atm(atmvcc)->sk_receive_queue;
 
        spin_lock_irqsave(&rq->lock, flags);
-       if (skb_queue_empty(rq)) {
-               skb = NULL;
-       } else {
-               /* NULL terminate the list.  */
-               rq->prev->next = NULL;
-               skb = rq->next;
-       }
-       rq->prev = rq->next = (struct sk_buff *)rq;
-       rq->qlen = 0;
+       skb_queue_splice_init(rq, &queue);
        spin_unlock_irqrestore(&rq->lock, flags);
 
-       while (skb) {
-               struct sk_buff *next = skb->next;
+       skb_queue_walk_safe(&queue, skb, tmp) {
+               struct net_device *dev = skb->dev;
 
-               skb->next = skb->prev = NULL;
-               br2684_push(atmvcc, skb);
-               skb->dev->stats.rx_bytes -= skb->len;
-               skb->dev->stats.rx_packets--;
+               dev->stats.rx_bytes -= skb->len;
+               dev->stats.rx_packets--;
 
-               skb = next;
+               br2684_push(atmvcc, skb);
        }
        __module_get(THIS_MODULE);
        return 0;
index 3dc0a3a..e65a3b1 100644 (file)
@@ -369,16 +369,16 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev)
        unsigned long flags;
 
        pr_debug("clip_start_xmit (skb %p)\n", skb);
-       if (!skb->dst) {
-               printk(KERN_ERR "clip_start_xmit: skb->dst == NULL\n");
+       if (!skb_dst(skb)) {
+               printk(KERN_ERR "clip_start_xmit: skb_dst(skb) == NULL\n");
                dev_kfree_skb(skb);
                dev->stats.tx_dropped++;
                return 0;
        }
-       if (!skb->dst->neighbour) {
+       if (!skb_dst(skb)->neighbour) {
 #if 0
-               skb->dst->neighbour = clip_find_neighbour(skb->dst, 1);
-               if (!skb->dst->neighbour) {
+               skb_dst(skb)->neighbour = clip_find_neighbour(skb_dst(skb), 1);
+               if (!skb_dst(skb)->neighbour) {
                        dev_kfree_skb(skb);     /* lost that one */
                        dev->stats.tx_dropped++;
                        return 0;
@@ -389,7 +389,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev)
                dev->stats.tx_dropped++;
                return 0;
        }
-       entry = NEIGH2ENTRY(skb->dst->neighbour);
+       entry = NEIGH2ENTRY(skb_dst(skb)->neighbour);
        if (!entry->vccs) {
                if (time_after(jiffies, entry->expires)) {
                        /* should be resolved */
@@ -406,7 +406,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
        pr_debug("neigh %p, vccs %p\n", entry, entry->vccs);
        ATM_SKB(skb)->vcc = vcc = entry->vccs->vcc;
-       pr_debug("using neighbour %p, vcc %p\n", skb->dst->neighbour, vcc);
+       pr_debug("using neighbour %p, vcc %p\n", skb_dst(skb)->neighbour, vcc);
        if (entry->vccs->encap) {
                void *here;
 
@@ -445,9 +445,9 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
 static int clip_mkip(struct atm_vcc *vcc, int timeout)
 {
+       struct sk_buff_head *rq, queue;
        struct clip_vcc *clip_vcc;
-       struct sk_buff *skb;
-       struct sk_buff_head *rq;
+       struct sk_buff *skb, *tmp;
        unsigned long flags;
 
        if (!vcc->push)
@@ -469,39 +469,28 @@ static int clip_mkip(struct atm_vcc *vcc, int timeout)
        vcc->push = clip_push;
        vcc->pop = clip_pop;
 
+       __skb_queue_head_init(&queue);
        rq = &sk_atm(vcc)->sk_receive_queue;
 
        spin_lock_irqsave(&rq->lock, flags);
-       if (skb_queue_empty(rq)) {
-               skb = NULL;
-       } else {
-               /* NULL terminate the list.  */
-               rq->prev->next = NULL;
-               skb = rq->next;
-       }
-       rq->prev = rq->next = (struct sk_buff *)rq;
-       rq->qlen = 0;
+       skb_queue_splice_init(rq, &queue);
        spin_unlock_irqrestore(&rq->lock, flags);
 
        /* re-process everything received between connection setup and MKIP */
-       while (skb) {
-               struct sk_buff *next = skb->next;
-
-               skb->next = skb->prev = NULL;
+       skb_queue_walk_safe(&queue, skb, tmp) {
                if (!clip_devs) {
                        atm_return(vcc, skb->truesize);
                        kfree_skb(skb);
                } else {
+                       struct net_device *dev = skb->dev;
                        unsigned int len = skb->len;
 
                        skb_get(skb);
                        clip_push(vcc, skb);
-                       skb->dev->stats.rx_packets--;
-                       skb->dev->stats.rx_bytes -= len;
+                       dev->stats.rx_packets--;
+                       dev->stats.rx_bytes -= len;
                        kfree_skb(skb);
                }
-
-               skb = next;
        }
        return 0;
 }
@@ -568,6 +557,7 @@ static void clip_setup(struct net_device *dev)
        /* without any more elaborate queuing. 100 is a reasonable */
        /* compromise between decent burst-tolerance and protection */
        /* against memory hogs. */
+       dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
 }
 
 static int clip_create(int number)
index 78958c0..97f8d68 100644 (file)
@@ -382,7 +382,7 @@ static void cmtp_reset_ctr(struct capi_ctr *ctrl)
 
        BT_DBG("ctrl %p", ctrl);
 
-       capi_ctr_reseted(ctrl);
+       capi_ctr_down(ctrl);
 
        atomic_inc(&session->terminate);
        cmtp_schedule(session);
index cd06151..406ad07 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/skbuff.h>
 #include <linux/interrupt.h>
 #include <linux/notifier.h>
+#include <linux/rfkill.h>
 #include <net/sock.h>
 
 #include <asm/system.h>
@@ -476,6 +477,11 @@ int hci_dev_open(__u16 dev)
 
        hci_req_lock(hdev);
 
+       if (hdev->rfkill && rfkill_blocked(hdev->rfkill)) {
+               ret = -ERFKILL;
+               goto done;
+       }
+
        if (test_bit(HCI_UP, &hdev->flags)) {
                ret = -EALREADY;
                goto done;
@@ -813,6 +819,24 @@ int hci_get_dev_info(void __user *arg)
 
 /* ---- Interface to HCI drivers ---- */
 
+static int hci_rfkill_set_block(void *data, bool blocked)
+{
+       struct hci_dev *hdev = data;
+
+       BT_DBG("%p name %s blocked %d", hdev, hdev->name, blocked);
+
+       if (!blocked)
+               return 0;
+
+       hci_dev_do_close(hdev);
+
+       return 0;
+}
+
+static const struct rfkill_ops hci_rfkill_ops = {
+       .set_block = hci_rfkill_set_block,
+};
+
 /* Alloc HCI device */
 struct hci_dev *hci_alloc_dev(void)
 {
@@ -844,7 +868,8 @@ int hci_register_dev(struct hci_dev *hdev)
        struct list_head *head = &hci_dev_list, *p;
        int i, id = 0;
 
-       BT_DBG("%p name %s type %d owner %p", hdev, hdev->name, hdev->type, hdev->owner);
+       BT_DBG("%p name %s type %d owner %p", hdev, hdev->name,
+                                               hdev->type, hdev->owner);
 
        if (!hdev->open || !hdev->close || !hdev->destruct)
                return -EINVAL;
@@ -900,6 +925,15 @@ int hci_register_dev(struct hci_dev *hdev)
 
        hci_register_sysfs(hdev);
 
+       hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
+                               RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, hdev);
+       if (hdev->rfkill) {
+               if (rfkill_register(hdev->rfkill) < 0) {
+                       rfkill_destroy(hdev->rfkill);
+                       hdev->rfkill = NULL;
+               }
+       }
+
        hci_notify(hdev, HCI_DEV_REG);
 
        return id;
@@ -924,6 +958,11 @@ int hci_unregister_dev(struct hci_dev *hdev)
 
        hci_notify(hdev, HCI_DEV_UNREG);
 
+       if (hdev->rfkill) {
+               rfkill_unregister(hdev->rfkill);
+               rfkill_destroy(hdev->rfkill);
+       }
+
        hci_unregister_sysfs(hdev);
 
        __hci_dev_put(hdev);
index 4cc3624..95f7a7a 100644 (file)
@@ -90,9 +90,6 @@ static void add_conn(struct work_struct *work)
        struct hci_conn *conn = container_of(work, struct hci_conn, work_add);
        struct hci_dev *hdev = conn->hdev;
 
-       /* ensure previous del is complete */
-       flush_work(&conn->work_del);
-
        dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle);
 
        if (device_add(&conn->dev) < 0) {
@@ -118,9 +115,6 @@ static void del_conn(struct work_struct *work)
        struct hci_conn *conn = container_of(work, struct hci_conn, work_del);
        struct hci_dev *hdev = conn->hdev;
 
-       /* ensure previous add is complete */
-       flush_work(&conn->work_add);
-
        if (!device_is_registered(&conn->dev))
                return;
 
index ca4d3b4..bd0a4c1 100644 (file)
 #include <linux/skbuff.h>
 #include <linux/list.h>
 #include <linux/device.h>
+#include <linux/uaccess.h>
 #include <net/sock.h>
 
 #include <asm/system.h>
-#include <asm/uaccess.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -52,7 +52,7 @@
 
 #define VERSION "2.13"
 
-static u32 l2cap_feat_mask = 0x0080;
+static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
 static u8 l2cap_fixed_chan[8] = { 0x02, };
 
 static const struct proto_ops l2cap_sock_ops;
@@ -134,7 +134,8 @@ static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16
        struct sock *s;
        read_lock(&l->lock);
        s = __l2cap_get_chan_by_scid(l, cid);
-       if (s) bh_lock_sock(s);
+       if (s)
+               bh_lock_sock(s);
        read_unlock(&l->lock);
        return s;
 }
@@ -154,17 +155,18 @@ static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8
        struct sock *s;
        read_lock(&l->lock);
        s = __l2cap_get_chan_by_ident(l, ident);
-       if (s) bh_lock_sock(s);
+       if (s)
+               bh_lock_sock(s);
        read_unlock(&l->lock);
        return s;
 }
 
 static u16 l2cap_alloc_cid(struct l2cap_chan_list *l)
 {
-       u16 cid = 0x0040;
+       u16 cid = L2CAP_CID_DYN_START;
 
-       for (; cid < 0xffff; cid++) {
-               if(!__l2cap_get_chan_by_scid(l, cid))
+       for (; cid < L2CAP_CID_DYN_END; cid++) {
+               if (!__l2cap_get_chan_by_scid(l, cid))
                        return cid;
        }
 
@@ -204,7 +206,8 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so
 {
        struct l2cap_chan_list *l = &conn->chan_list;
 
-       BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
+       BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
+                       l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
 
        conn->disc_reason = 0x13;
 
@@ -215,13 +218,13 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so
                l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
        } else if (sk->sk_type == SOCK_DGRAM) {
                /* Connectionless socket */
-               l2cap_pi(sk)->scid = 0x0002;
-               l2cap_pi(sk)->dcid = 0x0002;
+               l2cap_pi(sk)->scid = L2CAP_CID_CONN_LESS;
+               l2cap_pi(sk)->dcid = L2CAP_CID_CONN_LESS;
                l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
        } else {
                /* Raw socket can send/recv signalling messages only */
-               l2cap_pi(sk)->scid = 0x0001;
-               l2cap_pi(sk)->dcid = 0x0001;
+               l2cap_pi(sk)->scid = L2CAP_CID_SIGNALING;
+               l2cap_pi(sk)->dcid = L2CAP_CID_SIGNALING;
                l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
        }
 
@@ -272,7 +275,7 @@ static inline int l2cap_check_security(struct sock *sk)
                if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
                        auth_type = HCI_AT_NO_BONDING_MITM;
                else
-                        auth_type = HCI_AT_NO_BONDING;
+                       auth_type = HCI_AT_NO_BONDING;
 
                if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
                        l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
@@ -588,7 +591,8 @@ static inline struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t
        struct sock *s;
        read_lock(&l2cap_sk_list.lock);
        s = __l2cap_get_sock_by_psm(state, psm, src);
-       if (s) bh_lock_sock(s);
+       if (s)
+               bh_lock_sock(s);
        read_unlock(&l2cap_sk_list.lock);
        return s;
 }
@@ -808,7 +812,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
                goto done;
        }
 
-       if (la.l2_psm && btohs(la.l2_psm) < 0x1001 &&
+       if (la.l2_psm && __le16_to_cpu(la.l2_psm) < 0x1001 &&
                                !capable(CAP_NET_BIND_SERVICE)) {
                err = -EACCES;
                goto done;
@@ -825,7 +829,8 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
                l2cap_pi(sk)->sport = la.l2_psm;
                sk->sk_state = BT_BOUND;
 
-               if (btohs(la.l2_psm) == 0x0001 || btohs(la.l2_psm) == 0x0003)
+               if (__le16_to_cpu(la.l2_psm) == 0x0001 ||
+                                       __le16_to_cpu(la.l2_psm) == 0x0003)
                        l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
        }
 
@@ -844,12 +849,13 @@ static int l2cap_do_connect(struct sock *sk)
        struct hci_conn *hcon;
        struct hci_dev *hdev;
        __u8 auth_type;
-       int err = 0;
+       int err;
 
        BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
                                                        l2cap_pi(sk)->psm);
 
-       if (!(hdev = hci_get_route(dst, src)))
+       hdev = hci_get_route(dst, src);
+       if (!hdev)
                return -EHOSTUNREACH;
 
        hci_dev_lock_bh(hdev);
@@ -950,7 +956,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
                goto done;
        }
 
-       switch(sk->sk_state) {
+       switch (sk->sk_state) {
        case BT_CONNECT:
        case BT_CONNECT2:
        case BT_CONFIG:
@@ -975,7 +981,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
        bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr);
        l2cap_pi(sk)->psm = la.l2_psm;
 
-       if ((err = l2cap_do_connect(sk)))
+       err = l2cap_do_connect(sk);
+       if (err)
                goto done;
 
 wait:
@@ -1009,9 +1016,9 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
                write_lock_bh(&l2cap_sk_list.lock);
 
                for (psm = 0x1001; psm < 0x1100; psm += 2)
-                       if (!__l2cap_get_sock_by_addr(htobs(psm), src)) {
-                               l2cap_pi(sk)->psm   = htobs(psm);
-                               l2cap_pi(sk)->sport = htobs(psm);
+                       if (!__l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) {
+                               l2cap_pi(sk)->psm   = cpu_to_le16(psm);
+                               l2cap_pi(sk)->sport = cpu_to_le16(psm);
                                err = 0;
                                break;
                        }
@@ -1100,11 +1107,11 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l
        if (peer) {
                la->l2_psm = l2cap_pi(sk)->psm;
                bacpy(&la->l2_bdaddr, &bt_sk(sk)->dst);
-               la->l2_cid = htobs(l2cap_pi(sk)->dcid);
+               la->l2_cid = cpu_to_le16(l2cap_pi(sk)->dcid);
        } else {
                la->l2_psm = l2cap_pi(sk)->sport;
                bacpy(&la->l2_bdaddr, &bt_sk(sk)->src);
-               la->l2_cid = htobs(l2cap_pi(sk)->scid);
+               la->l2_cid = cpu_to_le16(l2cap_pi(sk)->scid);
        }
 
        return 0;
@@ -1114,7 +1121,7 @@ static inline int l2cap_do_send(struct sock *sk, struct msghdr *msg, int len)
 {
        struct l2cap_conn *conn = l2cap_pi(sk)->conn;
        struct sk_buff *skb, **frag;
-       int err, hlen, count, sent=0;
+       int err, hlen, count, sent = 0;
        struct l2cap_hdr *lh;
 
        BT_DBG("sk %p len %d", sk, len);
@@ -1167,8 +1174,8 @@ static inline int l2cap_do_send(struct sock *sk, struct msghdr *msg, int len)
 
                frag = &(*frag)->next;
        }
-
-       if ((err = hci_send_acl(conn->hcon, skb, 0)) < 0)
+       err = hci_send_acl(conn->hcon, skb, 0);
+       if (err < 0)
                goto fail;
 
        return sent;
@@ -1556,7 +1563,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
 {
        struct l2cap_chan_list *l = &conn->chan_list;
        struct sk_buff *nskb;
-       struct sock * sk;
+       struct sock *sk;
 
        BT_DBG("conn %p", conn);
 
@@ -1568,8 +1575,8 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
                /* Don't send frame to the socket it came from */
                if (skb->sk == sk)
                        continue;
-
-               if (!(nskb = skb_clone(skb, GFP_ATOMIC)))
+               nskb = skb_clone(skb, GFP_ATOMIC);
+               if (!nskb)
                        continue;
 
                if (sock_queue_rcv_skb(sk, nskb))
@@ -1587,7 +1594,8 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
        struct l2cap_hdr *lh;
        int len, count;
 
-       BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d", conn, code, ident, dlen);
+       BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
+                       conn, code, ident, dlen);
 
        len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
        count = min_t(unsigned int, conn->mtu, len);
@@ -1598,7 +1606,7 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
 
        lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
        lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
-       lh->cid = cpu_to_le16(0x0001);
+       lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
 
        cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
        cmd->code  = code;
@@ -1739,8 +1747,8 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
        while (len >= L2CAP_CONF_OPT_SIZE) {
                len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
 
-               hint  = type & 0x80;
-               type &= 0x7f;
+               hint  = type & L2CAP_CONF_HINT;
+               type &= L2CAP_CONF_MASK;
 
                switch (type) {
                case L2CAP_CONF_MTU:
@@ -1966,10 +1974,12 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
        BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
 
        if (scid) {
-               if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
+               sk = l2cap_get_chan_by_scid(&conn->chan_list, scid);
+               if (!sk)
                        return 0;
        } else {
-               if (!(sk = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident)))
+               sk = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident);
+               if (!sk)
                        return 0;
        }
 
@@ -2012,7 +2022,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 
        BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
 
-       if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
+       sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid);
+       if (!sk)
                return -ENOENT;
 
        if (sk->sk_state == BT_DISCONN)
@@ -2079,9 +2090,11 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        flags  = __le16_to_cpu(rsp->flags);
        result = __le16_to_cpu(rsp->result);
 
-       BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result);
+       BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
+                       scid, flags, result);
 
-       if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
+       sk = l2cap_get_chan_by_scid(&conn->chan_list, scid);
+       if (!sk)
                return 0;
 
        switch (result) {
@@ -2142,7 +2155,8 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
 
        BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
 
-       if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
+       sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid);
+       if (!sk)
                return 0;
 
        rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
@@ -2169,7 +2183,8 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
 
        BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
 
-       if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
+       sk = l2cap_get_chan_by_scid(&conn->chan_list, scid);
+       if (!sk)
                return 0;
 
        l2cap_chan_del(sk, 0);
@@ -2230,7 +2245,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
        if (type == L2CAP_IT_FEAT_MASK) {
                conn->feat_mask = get_unaligned_le32(rsp->data);
 
-               if (conn->feat_mask & 0x0080) {
+               if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
                        struct l2cap_info_req req;
                        req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
 
@@ -2403,7 +2418,8 @@ drop:
        kfree_skb(skb);
 
 done:
-       if (sk) bh_unlock_sock(sk);
+       if (sk)
+               bh_unlock_sock(sk);
        return 0;
 }
 
@@ -2420,11 +2436,11 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
        BT_DBG("len %d, cid 0x%4.4x", len, cid);
 
        switch (cid) {
-       case 0x0001:
+       case L2CAP_CID_SIGNALING:
                l2cap_sig_channel(conn, skb);
                break;
 
-       case 0x0002:
+       case L2CAP_CID_CONN_LESS:
                psm = get_unaligned((__le16 *) skb->data);
                skb_pull(skb, 2);
                l2cap_conless_channel(conn, psm, skb);
@@ -2650,7 +2666,8 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
                }
 
                /* Allocate skb for the complete frame (with header) */
-               if (!(conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC)))
+               conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
+               if (!conn->rx_skb)
                        goto drop;
 
                skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
@@ -2704,13 +2721,13 @@ static ssize_t l2cap_sysfs_show(struct class *dev, char *buf)
 
                str += sprintf(str, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d\n",
                                batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
-                               sk->sk_state, btohs(pi->psm), pi->scid, pi->dcid,
-                               pi->imtu, pi->omtu, pi->sec_level);
+                               sk->sk_state, __le16_to_cpu(pi->psm), pi->scid,
+                               pi->dcid, pi->imtu, pi->omtu, pi->sec_level);
        }
 
        read_unlock_bh(&l2cap_sk_list.lock);
 
-       return (str - buf);
+       return str - buf;
 }
 
 static CLASS_ATTR(l2cap, S_IRUGO, l2cap_sysfs_show, NULL);
index 374536e..e50566e 100644 (file)
@@ -679,7 +679,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst
 
        bacpy(&addr.l2_bdaddr, dst);
        addr.l2_family = AF_BLUETOOTH;
-       addr.l2_psm    = htobs(RFCOMM_PSM);
+       addr.l2_psm    = cpu_to_le16(RFCOMM_PSM);
        addr.l2_cid    = 0;
        *err = kernel_connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
        if (*err == 0 || *err == -EINPROGRESS)
@@ -852,9 +852,9 @@ static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d
        }
 
        if (cr && channel_mtu >= 0)
-               pn->mtu = htobs(channel_mtu);
+               pn->mtu = cpu_to_le16(channel_mtu);
        else
-               pn->mtu = htobs(d->mtu);
+               pn->mtu = cpu_to_le16(d->mtu);
 
        *ptr = __fcs(buf); ptr++;
 
@@ -1056,7 +1056,7 @@ static void rfcomm_make_uih(struct sk_buff *skb, u8 addr)
 
        if (len > 127) {
                hdr = (void *) skb_push(skb, 4);
-               put_unaligned(htobs(__len16(len)), (__le16 *) &hdr->len);
+               put_unaligned(cpu_to_le16(__len16(len)), (__le16 *) &hdr->len);
        } else {
                hdr = (void *) skb_push(skb, 3);
                hdr->len = __len8(len);
@@ -1289,7 +1289,7 @@ static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn)
 
        d->priority = pn->priority;
 
-       d->mtu = btohs(pn->mtu);
+       d->mtu = __le16_to_cpu(pn->mtu);
 
        if (cr && d->mtu > s->mtu)
                d->mtu = s->mtu;
@@ -1922,7 +1922,7 @@ static int rfcomm_add_listener(bdaddr_t *ba)
        /* Bind socket */
        bacpy(&addr.l2_bdaddr, ba);
        addr.l2_family = AF_BLUETOOTH;
-       addr.l2_psm    = htobs(RFCOMM_PSM);
+       addr.l2_psm    = cpu_to_le16(RFCOMM_PSM);
        addr.l2_cid    = 0;
        err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr));
        if (err < 0) {
index a48f5ef..cb3e97b 100644 (file)
@@ -398,7 +398,7 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
                if (unlikely(fdb->is_local)) {
                        if (net_ratelimit())
                                printk(KERN_WARNING "%s: received packet with "
-                                      " own address as source address\n",
+                                      "own address as source address\n",
                                       source->dev->name);
                } else {
                        /* fastpath: update of existing entry */
index e4a418f..d22f611 100644 (file)
@@ -228,6 +228,7 @@ int nf_bridge_copy_header(struct sk_buff *skb)
 static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
 {
        struct nf_bridge_info *nf_bridge = skb->nf_bridge;
+       struct rtable *rt;
 
        if (nf_bridge->mask & BRNF_PKT_TYPE) {
                skb->pkt_type = PACKET_OTHERHOST;
@@ -235,12 +236,13 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
        }
        nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
 
-       skb->rtable = bridge_parent_rtable(nf_bridge->physindev);
-       if (!skb->rtable) {
+       rt = bridge_parent_rtable(nf_bridge->physindev);
+       if (!rt) {
                kfree_skb(skb);
                return 0;
        }
-       dst_hold(&skb->rtable->u.dst);
+       dst_hold(&rt->u.dst);
+       skb_dst_set(skb, &rt->u.dst);
 
        skb->dev = nf_bridge->physindev;
        nf_bridge_push_encap_header(skb);
@@ -320,7 +322,7 @@ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb)
 
        skb->dev = bridge_parent(skb->dev);
        if (skb->dev) {
-               struct dst_entry *dst = skb->dst;
+               struct dst_entry *dst = skb_dst(skb);
 
                nf_bridge_pull_encap_header(skb);
 
@@ -338,6 +340,7 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb)
        struct net_device *dev = skb->dev;
        struct iphdr *iph = ip_hdr(skb);
        struct nf_bridge_info *nf_bridge = skb->nf_bridge;
+       struct rtable *rt;
        int err;
 
        if (nf_bridge->mask & BRNF_PKT_TYPE) {
@@ -347,7 +350,6 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb)
        nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
        if (dnat_took_place(skb)) {
                if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))) {
-                       struct rtable *rt;
                        struct flowi fl = {
                                .nl_u = {
                                        .ip4_u = {
@@ -373,7 +375,7 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb)
                                /* - Bridged-and-DNAT'ed traffic doesn't
                                 *   require ip_forwarding. */
                                if (((struct dst_entry *)rt)->dev == dev) {
-                                       skb->dst = (struct dst_entry *)rt;
+                                       skb_dst_set(skb, (struct dst_entry *)rt);
                                        goto bridged_dnat;
                                }
                                /* we are sure that forwarding is disabled, so printing
@@ -387,7 +389,7 @@ free_skb:
                        kfree_skb(skb);
                        return 0;
                } else {
-                       if (skb->dst->dev == dev) {
+                       if (skb_dst(skb)->dev == dev) {
 bridged_dnat:
                                /* Tell br_nf_local_out this is a
                                 * bridged frame */
@@ -404,12 +406,13 @@ bridged_dnat:
                        skb->pkt_type = PACKET_HOST;
                }
        } else {
-               skb->rtable = bridge_parent_rtable(nf_bridge->physindev);
-               if (!skb->rtable) {
+               rt = bridge_parent_rtable(nf_bridge->physindev);
+               if (!rt) {
                        kfree_skb(skb);
                        return 0;
                }
-               dst_hold(&skb->rtable->u.dst);
+               dst_hold(&rt->u.dst);
+               skb_dst_set(skb, &rt->u.dst);
        }
 
        skb->dev = nf_bridge->physindev;
@@ -628,10 +631,10 @@ static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff *skb,
                                   const struct net_device *out,
                                   int (*okfn)(struct sk_buff *))
 {
-       if (skb->rtable && skb->rtable == bridge_parent_rtable(in)) {
-               dst_release(&skb->rtable->u.dst);
-               skb->rtable = NULL;
-       }
+       struct rtable *rt = skb_rtable(skb);
+
+       if (rt && rt == bridge_parent_rtable(in))
+               skb_dst_drop(skb);
 
        return NF_ACCEPT;
 }
@@ -846,7 +849,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb,
                return NF_ACCEPT;
 
 #ifdef CONFIG_NETFILTER_DEBUG
-       if (skb->dst == NULL) {
+       if (skb_dst(skb) == NULL) {
                printk(KERN_INFO "br_netfilter post_routing: skb->dst == NULL\n");
                goto print_error;
        }
index 10f0528..e733725 100644 (file)
@@ -903,6 +903,8 @@ static __exit void can_exit(void)
        }
        spin_unlock(&can_rcvlists_lock);
 
+       rcu_barrier(); /* Wait for completion of call_rcu()'s */
+
        kmem_cache_destroy(rcv_cache);
 }
 
index e2a36f0..58abee1 100644 (file)
@@ -282,6 +282,7 @@ int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset,
 {
        int start = skb_headlen(skb);
        int i, copy = start - offset;
+       struct sk_buff *frag_iter;
 
        /* Copy header. */
        if (copy > 0) {
@@ -322,28 +323,24 @@ int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset,
                start = end;
        }
 
-       if (skb_shinfo(skb)->frag_list) {
-               struct sk_buff *list = skb_shinfo(skb)->frag_list;
-
-               for (; list; list = list->next) {
-                       int end;
-
-                       WARN_ON(start > offset + len);
-
-                       end = start + list->len;
-                       if ((copy = end - offset) > 0) {
-                               if (copy > len)
-                                       copy = len;
-                               if (skb_copy_datagram_iovec(list,
-                                                           offset - start,
-                                                           to, copy))
-                                       goto fault;
-                               if ((len -= copy) == 0)
-                                       return 0;
-                               offset += copy;
-                       }
-                       start = end;
+       skb_walk_frags(skb, frag_iter) {
+               int end;
+
+               WARN_ON(start > offset + len);
+
+               end = start + frag_iter->len;
+               if ((copy = end - offset) > 0) {
+                       if (copy > len)
+                               copy = len;
+                       if (skb_copy_datagram_iovec(frag_iter,
+                                                   offset - start,
+                                                   to, copy))
+                               goto fault;
+                       if ((len -= copy) == 0)
+                               return 0;
+                       offset += copy;
                }
+               start = end;
        }
        if (!len)
                return 0;
@@ -369,6 +366,7 @@ int skb_copy_datagram_const_iovec(const struct sk_buff *skb, int offset,
 {
        int start = skb_headlen(skb);
        int i, copy = start - offset;
+       struct sk_buff *frag_iter;
 
        /* Copy header. */
        if (copy > 0) {
@@ -411,30 +409,26 @@ int skb_copy_datagram_const_iovec(const struct sk_buff *skb, int offset,
                start = end;
        }
 
-       if (skb_shinfo(skb)->frag_list) {
-               struct sk_buff *list = skb_shinfo(skb)->frag_list;
-
-               for (; list; list = list->next) {
-                       int end;
-
-                       WARN_ON(start > offset + len);
-
-                       end = start + list->len;
-                       if ((copy = end - offset) > 0) {
-                               if (copy > len)
-                                       copy = len;
-                               if (skb_copy_datagram_const_iovec(list,
-                                                           offset - start,
-                                                           to, to_offset,
-                                                           copy))
-                                       goto fault;
-                               if ((len -= copy) == 0)
-                                       return 0;
-                               offset += copy;
-                               to_offset += copy;
-                       }
-                       start = end;
+       skb_walk_frags(skb, frag_iter) {
+               int end;
+
+               WARN_ON(start > offset + len);
+
+               end = start + frag_iter->len;
+               if ((copy = end - offset) > 0) {
+                       if (copy > len)
+                               copy = len;
+                       if (skb_copy_datagram_const_iovec(frag_iter,
+                                                         offset - start,
+                                                         to, to_offset,
+                                                         copy))
+                               goto fault;
+                       if ((len -= copy) == 0)
+                               return 0;
+                       offset += copy;
+                       to_offset += copy;
                }
+               start = end;
        }
        if (!len)
                return 0;
@@ -461,12 +455,14 @@ int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset,
 {
        int start = skb_headlen(skb);
        int i, copy = start - offset;
+       struct sk_buff *frag_iter;
 
        /* Copy header. */
        if (copy > 0) {
                if (copy > len)
                        copy = len;
-               if (memcpy_fromiovecend(skb->data + offset, from, 0, copy))
+               if (memcpy_fromiovecend(skb->data + offset, from, from_offset,
+                                       copy))
                        goto fault;
                if ((len -= copy) == 0)
                        return 0;
@@ -505,31 +501,27 @@ int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset,
                start = end;
        }
 
-       if (skb_shinfo(skb)->frag_list) {
-               struct sk_buff *list = skb_shinfo(skb)->frag_list;
-
-               for (; list; list = list->next) {
-                       int end;
-
-                       WARN_ON(start > offset + len);
-
-                       end = start + list->len;
-                       if ((copy = end - offset) > 0) {
-                               if (copy > len)
-                                       copy = len;
-                               if (skb_copy_datagram_from_iovec(list,
-                                                                offset - start,
-                                                                from,
-                                                                from_offset,
-                                                                copy))
-                                       goto fault;
-                               if ((len -= copy) == 0)
-                                       return 0;
-                               offset += copy;
-                               from_offset += copy;
-                       }
-                       start = end;
+       skb_walk_frags(skb, frag_iter) {
+               int end;
+
+               WARN_ON(start > offset + len);
+
+               end = start + frag_iter->len;
+               if ((copy = end - offset) > 0) {
+                       if (copy > len)
+                               copy = len;
+                       if (skb_copy_datagram_from_iovec(frag_iter,
+                                                        offset - start,
+                                                        from,
+                                                        from_offset,
+                                                        copy))
+                               goto fault;
+                       if ((len -= copy) == 0)
+                               return 0;
+                       offset += copy;
+                       from_offset += copy;
                }
+               start = end;
        }
        if (!len)
                return 0;
@@ -544,8 +536,9 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
                                      __wsum *csump)
 {
        int start = skb_headlen(skb);
-       int pos = 0;
        int i, copy = start - offset;
+       struct sk_buff *frag_iter;
+       int pos = 0;
 
        /* Copy header. */
        if (copy > 0) {
@@ -596,33 +589,29 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
                start = end;
        }
 
-       if (skb_shinfo(skb)->frag_list) {
-               struct sk_buff *list = skb_shinfo(skb)->frag_list;
-
-               for (; list; list=list->next) {
-                       int end;
-
-                       WARN_ON(start > offset + len);
-
-                       end = start + list->len;
-                       if ((copy = end - offset) > 0) {
-                               __wsum csum2 = 0;
-                               if (copy > len)
-                                       copy = len;
-                               if (skb_copy_and_csum_datagram(list,
-                                                              offset - start,
-                                                              to, copy,
-                                                              &csum2))
-                                       goto fault;
-                               *csump = csum_block_add(*csump, csum2, pos);
-                               if ((len -= copy) == 0)
-                                       return 0;
-                               offset += copy;
-                               to += copy;
-                               pos += copy;
-                       }
-                       start = end;
+       skb_walk_frags(skb, frag_iter) {
+               int end;
+
+               WARN_ON(start > offset + len);
+
+               end = start + frag_iter->len;
+               if ((copy = end - offset) > 0) {
+                       __wsum csum2 = 0;
+                       if (copy > len)
+                               copy = len;
+                       if (skb_copy_and_csum_datagram(frag_iter,
+                                                      offset - start,
+                                                      to, copy,
+                                                      &csum2))
+                               goto fault;
+                       *csump = csum_block_add(*csump, csum2, pos);
+                       if ((len -= copy) == 0)
+                               return 0;
+                       offset += copy;
+                       to += copy;
+                       pos += copy;
                }
+               start = end;
        }
        if (!len)
                return 0;
index ed4550f..11560e3 100644 (file)
@@ -269,7 +269,8 @@ static const unsigned short netdev_lock_type[] =
         ARPHRD_IRDA, ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL,
         ARPHRD_FCFABRIC, ARPHRD_IEEE802_TR, ARPHRD_IEEE80211,
         ARPHRD_IEEE80211_PRISM, ARPHRD_IEEE80211_RADIOTAP, ARPHRD_PHONET,
-        ARPHRD_PHONET_PIPE, ARPHRD_VOID, ARPHRD_NONE};
+        ARPHRD_PHONET_PIPE, ARPHRD_IEEE802154, ARPHRD_IEEE802154_PHY,
+        ARPHRD_VOID, ARPHRD_NONE};
 
 static const char *netdev_lock_name[] =
        {"_xmit_NETROM", "_xmit_ETHER", "_xmit_EETHER", "_xmit_AX25",
@@ -286,7 +287,8 @@ static const char *netdev_lock_name[] =
         "_xmit_IRDA", "_xmit_FCPP", "_xmit_FCAL", "_xmit_FCPL",
         "_xmit_FCFABRIC", "_xmit_IEEE802_TR", "_xmit_IEEE80211",
         "_xmit_IEEE80211_PRISM", "_xmit_IEEE80211_RADIOTAP", "_xmit_PHONET",
-        "_xmit_PHONET_PIPE", "_xmit_VOID", "_xmit_NONE"};
+        "_xmit_PHONET_PIPE", "_xmit_IEEE802154", "_xmit_IEEE802154_PHY",
+        "_xmit_VOID", "_xmit_NONE"};
 
 static struct lock_class_key netdev_xmit_lock_key[ARRAY_SIZE(netdev_lock_type)];
 static struct lock_class_key netdev_addr_lock_key[ARRAY_SIZE(netdev_lock_type)];
@@ -1048,7 +1050,7 @@ void dev_load(struct net *net, const char *name)
 int dev_open(struct net_device *dev)
 {
        const struct net_device_ops *ops = dev->netdev_ops;
-       int ret = 0;
+       int ret;
 
        ASSERT_RTNL();
 
@@ -1065,6 +1067,11 @@ int dev_open(struct net_device *dev)
        if (!netif_device_present(dev))
                return -ENODEV;
 
+       ret = call_netdevice_notifiers(NETDEV_PRE_UP, dev);
+       ret = notifier_to_errno(ret);
+       if (ret)
+               return ret;
+
        /*
         *      Call device private open method
         */
@@ -1693,10 +1700,9 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
                 * If device doesnt need skb->dst, release it right now while
                 * its hot in this cpu cache
                 */
-               if ((dev->priv_flags & IFF_XMIT_DST_RELEASE) && skb->dst) {
-                       dst_release(skb->dst);
-                       skb->dst = NULL;
-               }
+               if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
+                       skb_dst_drop(skb);
+
                rc = ops->ndo_start_xmit(skb, dev);
                if (rc == 0)
                        txq_trans_update(txq);
@@ -1816,7 +1822,7 @@ int dev_queue_xmit(struct sk_buff *skb)
        if (netif_needs_gso(dev, skb))
                goto gso;
 
-       if (skb_shinfo(skb)->frag_list &&
+       if (skb_has_frags(skb) &&
            !(dev->features & NETIF_F_FRAGLIST) &&
            __skb_linearize(skb))
                goto out_kfree_skb;
@@ -2403,7 +2409,7 @@ int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
        if (!(skb->dev->features & NETIF_F_GRO))
                goto normal;
 
-       if (skb_is_gso(skb) || skb_shinfo(skb)->frag_list)
+       if (skb_is_gso(skb) || skb_has_frags(skb))
                goto normal;
 
        rcu_read_lock();
@@ -3473,8 +3479,9 @@ void dev_set_rx_mode(struct net_device *dev)
 
 /* hw addresses list handling functions */
 
-static int __hw_addr_add(struct list_head *list, unsigned char *addr,
-                        int addr_len, unsigned char addr_type)
+static int __hw_addr_add(struct list_head *list, int *delta,
+                        unsigned char *addr, int addr_len,
+                        unsigned char addr_type)
 {
        struct netdev_hw_addr *ha;
        int alloc_size;
@@ -3482,6 +3489,15 @@ static int __hw_addr_add(struct list_head *list, unsigned char *addr,
        if (addr_len > MAX_ADDR_LEN)
                return -EINVAL;
 
+       list_for_each_entry(ha, list, list) {
+               if (!memcmp(ha->addr, addr, addr_len) &&
+                   ha->type == addr_type) {
+                       ha->refcount++;
+                       return 0;
+               }
+       }
+
+
        alloc_size = sizeof(*ha);
        if (alloc_size < L1_CACHE_BYTES)
                alloc_size = L1_CACHE_BYTES;
@@ -3490,7 +3506,11 @@ static int __hw_addr_add(struct list_head *list, unsigned char *addr,
                return -ENOMEM;
        memcpy(ha->addr, addr, addr_len);
        ha->type = addr_type;
+       ha->refcount = 1;
+       ha->synced = false;
        list_add_tail_rcu(&ha->list, list);
+       if (delta)
+               (*delta)++;
        return 0;
 }
 
@@ -3502,29 +3522,30 @@ static void ha_rcu_free(struct rcu_head *head)
        kfree(ha);
 }
 
-static int __hw_addr_del_ii(struct list_head *list, unsigned char *addr,
-                           int addr_len, unsigned char addr_type,
-                           int ignore_index)
+static int __hw_addr_del(struct list_head *list, int *delta,
+                        unsigned char *addr, int addr_len,
+                        unsigned char addr_type)
 {
        struct netdev_hw_addr *ha;
-       int i = 0;
 
        list_for_each_entry(ha, list, list) {
-               if (i++ != ignore_index &&
-                   !memcmp(ha->addr, addr, addr_len) &&
+               if (!memcmp(ha->addr, addr, addr_len) &&
                    (ha->type == addr_type || !addr_type)) {
+                       if (--ha->refcount)
+                               return 0;
                        list_del_rcu(&ha->list);
                        call_rcu(&ha->rcu_head, ha_rcu_free);
+                       if (delta)
+                               (*delta)--;
                        return 0;
                }
        }
        return -ENOENT;
 }
 
-static int __hw_addr_add_multiple_ii(struct list_head *to_list,
-                                    struct list_head *from_list,
-                                    int addr_len, unsigned char addr_type,
-                                    int ignore_index)
+static int __hw_addr_add_multiple(struct list_head *to_list, int *to_delta,
+                                 struct list_head *from_list, int addr_len,
+                                 unsigned char addr_type)
 {
        int err;
        struct netdev_hw_addr *ha, *ha2;
@@ -3532,7 +3553,8 @@ static int __hw_addr_add_multiple_ii(struct list_head *to_list,
 
        list_for_each_entry(ha, from_list, list) {
                type = addr_type ? addr_type : ha->type;
-               err = __hw_addr_add(to_list, ha->addr, addr_len, type);
+               err = __hw_addr_add(to_list, to_delta, ha->addr,
+                                   addr_len, type);
                if (err)
                        goto unroll;
        }
@@ -3543,27 +3565,69 @@ unroll:
                if (ha2 == ha)
                        break;
                type = addr_type ? addr_type : ha2->type;
-               __hw_addr_del_ii(to_list, ha2->addr, addr_len, type,
-                                ignore_index);
+               __hw_addr_del(to_list, to_delta, ha2->addr,
+                             addr_len, type);
        }
        return err;
 }
 
-static void __hw_addr_del_multiple_ii(struct list_head *to_list,
-                                     struct list_head *from_list,
-                                     int addr_len, unsigned char addr_type,
-                                     int ignore_index)
+static void __hw_addr_del_multiple(struct list_head *to_list, int *to_delta,
+                                  struct list_head *from_list, int addr_len,
+                                  unsigned char addr_type)
 {
        struct netdev_hw_addr *ha;
        unsigned char type;
 
        list_for_each_entry(ha, from_list, list) {
                type = addr_type ? addr_type : ha->type;
-               __hw_addr_del_ii(to_list, ha->addr, addr_len, addr_type,
-                                ignore_index);
+               __hw_addr_del(to_list, to_delta, ha->addr,
+                             addr_len, addr_type);
+       }
+}
+
+static int __hw_addr_sync(struct list_head *to_list, int *to_delta,
+                         struct list_head *from_list, int *from_delta,
+                         int addr_len)
+{
+       int err = 0;
+       struct netdev_hw_addr *ha, *tmp;
+
+       list_for_each_entry_safe(ha, tmp, from_list, list) {
+               if (!ha->synced) {
+                       err = __hw_addr_add(to_list, to_delta, ha->addr,
+                                           addr_len, ha->type);
+                       if (err)
+                               break;
+                       ha->synced = true;
+                       ha->refcount++;
+               } else if (ha->refcount == 1) {
+                       __hw_addr_del(to_list, to_delta, ha->addr,
+                                     addr_len, ha->type);
+                       __hw_addr_del(from_list, from_delta, ha->addr,
+                                     addr_len, ha->type);
+               }
+       }
+       return err;
+}
+
+static void __hw_addr_unsync(struct list_head *to_list, int *to_delta,
+                            struct list_head *from_list, int *from_delta,
+                            int addr_len)
+{
+       struct netdev_hw_addr *ha, *tmp;
+
+       list_for_each_entry_safe(ha, tmp, from_list, list) {
+               if (ha->synced) {
+                       __hw_addr_del(to_list, to_delta, ha->addr,
+                                     addr_len, ha->type);
+                       ha->synced = false;
+                       __hw_addr_del(from_list, from_delta, ha->addr,
+                                     addr_len, ha->type);
+               }
        }
 }
 
+
 static void __hw_addr_flush(struct list_head *list)
 {
        struct netdev_hw_addr *ha, *tmp;
@@ -3593,8 +3657,8 @@ static int dev_addr_init(struct net_device *dev)
        /* rtnl_mutex must be held here */
 
        INIT_LIST_HEAD(&dev->dev_addr_list);
-       memset(addr, 0, sizeof(*addr));
-       err = __hw_addr_add(&dev->dev_addr_list, addr, sizeof(*addr),
+       memset(addr, 0, sizeof(addr));
+       err = __hw_addr_add(&dev->dev_addr_list, NULL, addr, sizeof(addr),
                            NETDEV_HW_ADDR_T_LAN);
        if (!err) {
                /*
@@ -3626,7 +3690,7 @@ int dev_addr_add(struct net_device *dev, unsigned char *addr,
 
        ASSERT_RTNL();
 
-       err = __hw_addr_add(&dev->dev_addr_list, addr, dev->addr_len,
+       err = __hw_addr_add(&dev->dev_addr_list, NULL, addr, dev->addr_len,
                            addr_type);
        if (!err)
                call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
@@ -3649,11 +3713,20 @@ int dev_addr_del(struct net_device *dev, unsigned char *addr,
                 unsigned char addr_type)
 {
        int err;
+       struct netdev_hw_addr *ha;
 
        ASSERT_RTNL();
 
-       err = __hw_addr_del_ii(&dev->dev_addr_list, addr, dev->addr_len,
-                              addr_type, 0);
+       /*
+        * We can not remove the first address from the list because
+        * dev->dev_addr points to that.
+        */
+       ha = list_first_entry(&dev->dev_addr_list, struct netdev_hw_addr, list);
+       if (ha->addr == dev->dev_addr && ha->refcount == 1)
+               return -ENOENT;
+
+       err = __hw_addr_del(&dev->dev_addr_list, NULL, addr, dev->addr_len,
+                           addr_type);
        if (!err)
                call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
        return err;
@@ -3680,9 +3753,9 @@ int dev_addr_add_multiple(struct net_device *to_dev,
 
        if (from_dev->addr_len != to_dev->addr_len)
                return -EINVAL;
-       err = __hw_addr_add_multiple_ii(&to_dev->dev_addr_list,
-                                       &from_dev->dev_addr_list,
-                                       to_dev->addr_len, addr_type, 0);
+       err = __hw_addr_add_multiple(&to_dev->dev_addr_list, NULL,
+                                    &from_dev->dev_addr_list,
+                                    to_dev->addr_len, addr_type);
        if (!err)
                call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev);
        return err;
@@ -3707,9 +3780,9 @@ int dev_addr_del_multiple(struct net_device *to_dev,
 
        if (from_dev->addr_len != to_dev->addr_len)
                return -EINVAL;
-       __hw_addr_del_multiple_ii(&to_dev->dev_addr_list,
-                                 &from_dev->dev_addr_list,
-                                 to_dev->addr_len, addr_type, 0);
+       __hw_addr_del_multiple(&to_dev->dev_addr_list, NULL,
+                              &from_dev->dev_addr_list,
+                              to_dev->addr_len, addr_type);
        call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev);
        return 0;
 }
@@ -3779,24 +3852,22 @@ int __dev_addr_add(struct dev_addr_list **list, int *count,
  *     dev_unicast_delete      - Release secondary unicast address.
  *     @dev: device
  *     @addr: address to delete
- *     @alen: length of @addr
  *
  *     Release reference to a secondary unicast address and remove it
  *     from the device if the reference count drops to zero.
  *
  *     The caller must hold the rtnl_mutex.
  */
-int dev_unicast_delete(struct net_device *dev, void *addr, int alen)
+int dev_unicast_delete(struct net_device *dev, void *addr)
 {
        int err;
 
        ASSERT_RTNL();
 
-       netif_addr_lock_bh(dev);
-       err = __dev_addr_delete(&dev->uc_list, &dev->uc_count, addr, alen, 0);
+       err = __hw_addr_del(&dev->uc_list, &dev->uc_count, addr,
+                           dev->addr_len, NETDEV_HW_ADDR_T_UNICAST);
        if (!err)
                __dev_set_rx_mode(dev);
-       netif_addr_unlock_bh(dev);
        return err;
 }
 EXPORT_SYMBOL(dev_unicast_delete);
@@ -3805,24 +3876,22 @@ EXPORT_SYMBOL(dev_unicast_delete);
  *     dev_unicast_add         - add a secondary unicast address
  *     @dev: device
  *     @addr: address to add
- *     @alen: length of @addr
  *
  *     Add a secondary unicast address to the device or increase
  *     the reference count if it already exists.
  *
  *     The caller must hold the rtnl_mutex.
  */
-int dev_unicast_add(struct net_device *dev, void *addr, int alen)
+int dev_unicast_add(struct net_device *dev, void *addr)
 {
        int err;
 
        ASSERT_RTNL();
 
-       netif_addr_lock_bh(dev);
-       err = __dev_addr_add(&dev->uc_list, &dev->uc_count, addr, alen, 0);
+       err = __hw_addr_add(&dev->uc_list, &dev->uc_count, addr,
+                           dev->addr_len, NETDEV_HW_ADDR_T_UNICAST);
        if (!err)
                __dev_set_rx_mode(dev);
-       netif_addr_unlock_bh(dev);
        return err;
 }
 EXPORT_SYMBOL(dev_unicast_add);
@@ -3879,8 +3948,7 @@ void __dev_addr_unsync(struct dev_addr_list **to, int *to_count,
  *     @from: source device
  *
  *     Add newly added addresses to the destination device and release
- *     addresses that have no users left. The source device must be
- *     locked by netif_tx_lock_bh.
+ *     addresses that have no users left.
  *
  *     This function is intended to be called from the dev->set_rx_mode
  *     function of layered software devices.
@@ -3889,12 +3957,15 @@ int dev_unicast_sync(struct net_device *to, struct net_device *from)
 {
        int err = 0;
 
-       netif_addr_lock_bh(to);
-       err = __dev_addr_sync(&to->uc_list, &to->uc_count,
-                             &from->uc_list, &from->uc_count);
+       ASSERT_RTNL();
+
+       if (to->addr_len != from->addr_len)
+               return -EINVAL;
+
+       err = __hw_addr_sync(&to->uc_list, &to->uc_count,
+                            &from->uc_list, &from->uc_count, to->addr_len);
        if (!err)
                __dev_set_rx_mode(to);
-       netif_addr_unlock_bh(to);
        return err;
 }
 EXPORT_SYMBOL(dev_unicast_sync);
@@ -3910,18 +3981,33 @@ EXPORT_SYMBOL(dev_unicast_sync);
  */
 void dev_unicast_unsync(struct net_device *to, struct net_device *from)
 {
-       netif_addr_lock_bh(from);
-       netif_addr_lock(to);
+       ASSERT_RTNL();
 
-       __dev_addr_unsync(&to->uc_list, &to->uc_count,
-                         &from->uc_list, &from->uc_count);
-       __dev_set_rx_mode(to);
+       if (to->addr_len != from->addr_len)
+               return;
 
-       netif_addr_unlock(to);
-       netif_addr_unlock_bh(from);
+       __hw_addr_unsync(&to->uc_list, &to->uc_count,
+                        &from->uc_list, &from->uc_count, to->addr_len);
+       __dev_set_rx_mode(to);
 }
 EXPORT_SYMBOL(dev_unicast_unsync);
 
+static void dev_unicast_flush(struct net_device *dev)
+{
+       /* rtnl_mutex must be held here */
+
+       __hw_addr_flush(&dev->uc_list);
+       dev->uc_count = 0;
+}
+
+static void dev_unicast_init(struct net_device *dev)
+{
+       /* rtnl_mutex must be held here */
+
+       INIT_LIST_HEAD(&dev->uc_list);
+}
+
+
 static void __dev_addr_discard(struct dev_addr_list **list)
 {
        struct dev_addr_list *tmp;
@@ -3940,9 +4026,6 @@ static void dev_addr_discard(struct net_device *dev)
 {
        netif_addr_lock_bh(dev);
 
-       __dev_addr_discard(&dev->uc_list);
-       dev->uc_count = 0;
-
        __dev_addr_discard(&dev->mc_list);
        dev->mc_count = 0;
 
@@ -4535,6 +4618,7 @@ static void rollback_registered(struct net_device *dev)
        /*
         *      Flush the unicast and multicast chains
         */
+       dev_unicast_flush(dev);
        dev_addr_discard(dev);
 
        if (dev->netdev_ops->ndo_uninit)
@@ -4988,18 +5072,18 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
        struct netdev_queue *tx;
        struct net_device *dev;
        size_t alloc_size;
-       void *p;
+       struct net_device *p;
 
        BUG_ON(strlen(name) >= sizeof(dev->name));
 
        alloc_size = sizeof(struct net_device);
        if (sizeof_priv) {
                /* ensure 32-byte alignment of private area */
-               alloc_size = (alloc_size + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST;
+               alloc_size = ALIGN(alloc_size, NETDEV_ALIGN);
                alloc_size += sizeof_priv;
        }
        /* ensure 32-byte alignment of whole construct */
-       alloc_size += NETDEV_ALIGN_CONST;
+       alloc_size += NETDEV_ALIGN - 1;
 
        p = kzalloc(alloc_size, GFP_KERNEL);
        if (!p) {
@@ -5014,13 +5098,14 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
                goto free_p;
        }
 
-       dev = (struct net_device *)
-               (((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);
+       dev = PTR_ALIGN(p, NETDEV_ALIGN);
        dev->padded = (char *)dev - (char *)p;
 
        if (dev_addr_init(dev))
                goto free_tx;
 
+       dev_unicast_init(dev);
+
        dev_net_set(dev, &init_net);
 
        dev->_tx = tx;
@@ -5224,6 +5309,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
        /*
         *      Flush the unicast and multicast chains
         */
+       dev_unicast_flush(dev);
        dev_addr_discard(dev);
 
        netdev_unregister_kobject(dev);
index 40a76ce..16ad45d 100644 (file)
@@ -112,9 +112,9 @@ int memcpy_toiovecend(const struct iovec *iov, unsigned char *kdata,
                        continue;
                }
                copy = min_t(unsigned int, iov->iov_len - offset, len);
-               offset = 0;
-               if (copy_to_user(iov->iov_base, kdata, copy))
+               if (copy_to_user(iov->iov_base + offset, kdata, copy))
                        return -EFAULT;
+               offset = 0;
                kdata += copy;
                len -= copy;
        }
index a1cbce7..163b4f5 100644 (file)
@@ -771,6 +771,28 @@ static __inline__ int neigh_max_probes(struct neighbour *n)
                p->ucast_probes + p->app_probes + p->mcast_probes);
 }
 
+static void neigh_invalidate(struct neighbour *neigh)
+{
+       struct sk_buff *skb;
+
+       NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
+       NEIGH_PRINTK2("neigh %p is failed.\n", neigh);
+       neigh->updated = jiffies;
+
+       /* It is very thin place. report_unreachable is very complicated
+          routine. Particularly, it can hit the same neighbour entry!
+
+          So that, we try to be accurate and avoid dead loop. --ANK
+        */
+       while (neigh->nud_state == NUD_FAILED &&
+              (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
+               write_unlock(&neigh->lock);
+               neigh->ops->error_report(neigh, skb);
+               write_lock(&neigh->lock);
+       }
+       skb_queue_purge(&neigh->arp_queue);
+}
+
 /* Called when a timer expires for a neighbour entry. */
 
 static void neigh_timer_handler(unsigned long arg)
@@ -835,26 +857,9 @@ static void neigh_timer_handler(unsigned long arg)
 
        if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
            atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
-               struct sk_buff *skb;
-
                neigh->nud_state = NUD_FAILED;
-               neigh->updated = jiffies;
                notify = 1;
-               NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
-               NEIGH_PRINTK2("neigh %p is failed.\n", neigh);
-
-               /* It is very thin place. report_unreachable is very complicated
-                  routine. Particularly, it can hit the same neighbour entry!
-
-                  So that, we try to be accurate and avoid dead loop. --ANK
-                */
-               while (neigh->nud_state == NUD_FAILED &&
-                      (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
-                       write_unlock(&neigh->lock);
-                       neigh->ops->error_report(neigh, skb);
-                       write_lock(&neigh->lock);
-               }
-               skb_queue_purge(&neigh->arp_queue);
+               neigh_invalidate(neigh);
        }
 
        if (neigh->nud_state & NUD_IN_TIMER) {
@@ -1001,6 +1006,11 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
                neigh->nud_state = new;
                err = 0;
                notify = old & NUD_VALID;
+               if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&
+                   (new & NUD_FAILED)) {
+                       neigh_invalidate(neigh);
+                       notify = 1;
+               }
                goto out;
        }
 
@@ -1088,8 +1098,8 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
                        struct neighbour *n1 = neigh;
                        write_unlock_bh(&neigh->lock);
                        /* On shaper/eql skb->dst->neighbour != neigh :( */
-                       if (skb->dst && skb->dst->neighbour)
-                               n1 = skb->dst->neighbour;
+                       if (skb_dst(skb) && skb_dst(skb)->neighbour)
+                               n1 = skb_dst(skb)->neighbour;
                        n1->output(skb);
                        write_lock_bh(&neigh->lock);
                }
@@ -1182,7 +1192,7 @@ EXPORT_SYMBOL(neigh_compat_output);
 
 int neigh_resolve_output(struct sk_buff *skb)
 {
-       struct dst_entry *dst = skb->dst;
+       struct dst_entry *dst = skb_dst(skb);
        struct neighbour *neigh;
        int rc = 0;
 
@@ -1229,7 +1239,7 @@ EXPORT_SYMBOL(neigh_resolve_output);
 int neigh_connected_output(struct sk_buff *skb)
 {
        int err;
-       struct dst_entry *dst = skb->dst;
+       struct dst_entry *dst = skb_dst(skb);
        struct neighbour *neigh = dst->neighbour;
        struct net_device *dev = neigh->dev;
 
@@ -1298,8 +1308,7 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
                if (time_before(tbl->proxy_timer.expires, sched_next))
                        sched_next = tbl->proxy_timer.expires;
        }
-       dst_release(skb->dst);
-       skb->dst = NULL;
+       skb_dst_drop(skb);
        dev_hold(skb->dev);
        __skb_queue_tail(&tbl->proxy_queue, skb);
        mod_timer(&tbl->proxy_timer, sched_next);
index b8ccd3c..19b8c20 100644 (file)
@@ -3691,8 +3691,7 @@ out1:
 #ifdef CONFIG_XFRM
        free_SAs(pkt_dev);
 #endif
-       if (pkt_dev->flows)
-               vfree(pkt_dev->flows);
+       vfree(pkt_dev->flows);
        kfree(pkt_dev);
        return err;
 }
@@ -3791,8 +3790,7 @@ static int pktgen_remove_device(struct pktgen_thread *t,
 #ifdef CONFIG_XFRM
        free_SAs(pkt_dev);
 #endif
-       if (pkt_dev->flows)
-               vfree(pkt_dev->flows);
+       vfree(pkt_dev->flows);
        kfree(pkt_dev);
        return 0;
 }
index 8623492..79687df 100644 (file)
@@ -20,7 +20,7 @@ int skb_dma_map(struct device *dev, struct sk_buff *skb,
        if (dma_mapping_error(dev, map))
                goto out_err;
 
-       sp->dma_maps[0] = map;
+       sp->dma_head = map;
        for (i = 0; i < sp->nr_frags; i++) {
                skb_frag_t *fp = &sp->frags[i];
 
@@ -28,9 +28,8 @@ int skb_dma_map(struct device *dev, struct sk_buff *skb,
                                   fp->size, dir);
                if (dma_mapping_error(dev, map))
                        goto unwind;
-               sp->dma_maps[i + 1] = map;
+               sp->dma_maps[i] = map;
        }
-       sp->num_dma_maps = i + 1;
 
        return 0;
 
@@ -38,10 +37,10 @@ unwind:
        while (--i >= 0) {
                skb_frag_t *fp = &sp->frags[i];
 
-               dma_unmap_page(dev, sp->dma_maps[i + 1],
+               dma_unmap_page(dev, sp->dma_maps[i],
                               fp->size, dir);
        }
-       dma_unmap_single(dev, sp->dma_maps[0],
+       dma_unmap_single(dev, sp->dma_head,
                         skb_headlen(skb), dir);
 out_err:
        return -ENOMEM;
@@ -54,12 +53,12 @@ void skb_dma_unmap(struct device *dev, struct sk_buff *skb,
        struct skb_shared_info *sp = skb_shinfo(skb);
        int i;
 
-       dma_unmap_single(dev, sp->dma_maps[0],
+       dma_unmap_single(dev, sp->dma_head,
                         skb_headlen(skb), dir);
        for (i = 0; i < sp->nr_frags; i++) {
                skb_frag_t *fp = &sp->frags[i];
 
-               dma_unmap_page(dev, sp->dma_maps[i + 1],
+               dma_unmap_page(dev, sp->dma_maps[i],
                               fp->size, dir);
        }
 }
index 8e815e6..b94d777 100644 (file)
@@ -210,7 +210,7 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
        shinfo->gso_type = 0;
        shinfo->ip6_frag_id = 0;
        shinfo->tx_flags.flags = 0;
-       shinfo->frag_list = NULL;
+       skb_frag_list_init(skb);
        memset(&shinfo->hwtstamps, 0, sizeof(shinfo->hwtstamps));
 
        if (fclone) {
@@ -323,7 +323,7 @@ static void skb_clone_fraglist(struct sk_buff *skb)
 {
        struct sk_buff *list;
 
-       for (list = skb_shinfo(skb)->frag_list; list; list = list->next)
+       skb_walk_frags(skb, list)
                skb_get(list);
 }
 
@@ -338,7 +338,7 @@ static void skb_release_data(struct sk_buff *skb)
                                put_page(skb_shinfo(skb)->frags[i].page);
                }
 
-               if (skb_shinfo(skb)->frag_list)
+               if (skb_has_frags(skb))
                        skb_drop_fraglist(skb);
 
                kfree(skb->head);
@@ -381,7 +381,7 @@ static void kfree_skbmem(struct sk_buff *skb)
 
 static void skb_release_head_state(struct sk_buff *skb)
 {
-       dst_release(skb->dst);
+       skb_dst_drop(skb);
 #ifdef CONFIG_XFRM
        secpath_put(skb->sp);
 #endif
@@ -503,7 +503,7 @@ int skb_recycle_check(struct sk_buff *skb, int skb_size)
        shinfo->gso_type = 0;
        shinfo->ip6_frag_id = 0;
        shinfo->tx_flags.flags = 0;
-       shinfo->frag_list = NULL;
+       skb_frag_list_init(skb);
        memset(&shinfo->hwtstamps, 0, sizeof(shinfo->hwtstamps));
 
        memset(skb, 0, offsetof(struct sk_buff, tail));
@@ -521,7 +521,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
        new->transport_header   = old->transport_header;
        new->network_header     = old->network_header;
        new->mac_header         = old->mac_header;
-       new->dst                = dst_clone(old->dst);
+       skb_dst_set(new, dst_clone(skb_dst(old)));
 #ifdef CONFIG_XFRM
        new->sp                 = secpath_get(old->sp);
 #endif
@@ -552,7 +552,6 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
        new->vlan_tci           = old->vlan_tci;
 #if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE)
        new->do_not_encrypt     = old->do_not_encrypt;
-       new->requeue            = old->requeue;
 #endif
 
        skb_copy_secmark(new, old);
@@ -758,7 +757,7 @@ struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask)
                skb_shinfo(n)->nr_frags = i;
        }
 
-       if (skb_shinfo(skb)->frag_list) {
+       if (skb_has_frags(skb)) {
                skb_shinfo(n)->frag_list = skb_shinfo(skb)->frag_list;
                skb_clone_fraglist(n);
        }
@@ -821,7 +820,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
        for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
                get_page(skb_shinfo(skb)->frags[i].page);
 
-       if (skb_shinfo(skb)->frag_list)
+       if (skb_has_frags(skb))
                skb_clone_fraglist(skb);
 
        skb_release_data(skb);
@@ -1093,7 +1092,7 @@ drop_pages:
                for (; i < nfrags; i++)
                        put_page(skb_shinfo(skb)->frags[i].page);
 
-               if (skb_shinfo(skb)->frag_list)
+               if (skb_has_frags(skb))
                        skb_drop_fraglist(skb);
                goto done;
        }
@@ -1188,7 +1187,7 @@ unsigned char *__pskb_pull_tail(struct sk_buff *skb, int delta)
        /* Optimization: no fragments, no reasons to preestimate
         * size of pulled pages. Superb.
         */
-       if (!skb_shinfo(skb)->frag_list)
+       if (!skb_has_frags(skb))
                goto pull_pages;
 
        /* Estimate size of pulled pages. */
@@ -1285,8 +1284,9 @@ EXPORT_SYMBOL(__pskb_pull_tail);
 
 int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
 {
-       int i, copy;
        int start = skb_headlen(skb);
+       struct sk_buff *frag_iter;
+       int i, copy;
 
        if (offset > (int)skb->len - len)
                goto fault;
@@ -1328,28 +1328,23 @@ int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
                start = end;
        }
 
-       if (skb_shinfo(skb)->frag_list) {
-               struct sk_buff *list = skb_shinfo(skb)->frag_list;
+       skb_walk_frags(skb, frag_iter) {
+               int end;
 
-               for (; list; list = list->next) {
-                       int end;
-
-                       WARN_ON(start > offset + len);
-
-                       end = start + list->len;
-                       if ((copy = end - offset) > 0) {
-                               if (copy > len)
-                                       copy = len;
-                               if (skb_copy_bits(list, offset - start,
-                                                 to, copy))
-                                       goto fault;
-                               if ((len -= copy) == 0)
-                                       return 0;
-                               offset += copy;
-                               to     += copy;
-                       }
-                       start = end;
+               WARN_ON(start > offset + len);
+
+               end = start + frag_iter->len;
+               if ((copy = end - offset) > 0) {
+                       if (copy > len)
+                               copy = len;
+                       if (skb_copy_bits(frag_iter, offset - start, to, copy))
+                               goto fault;
+                       if ((len -= copy) == 0)
+                               return 0;
+                       offset += copy;
+                       to     += copy;
                }
+               start = end;
        }
        if (!len)
                return 0;
@@ -1534,6 +1529,7 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset,
                .ops = &sock_pipe_buf_ops,
                .spd_release = sock_spd_release,
        };
+       struct sk_buff *frag_iter;
        struct sock *sk = skb->sk;
 
        /*
@@ -1548,13 +1544,11 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset,
        /*
         * now see if we have a frag_list to map
         */
-       if (skb_shinfo(skb)->frag_list) {
-               struct sk_buff *list = skb_shinfo(skb)->frag_list;
-
-               for (; list && tlen; list = list->next) {
-                       if (__skb_splice_bits(list, &offset, &tlen, &spd, sk))
-                               break;
-               }
+       skb_walk_frags(skb, frag_iter) {
+               if (!tlen)
+                       break;
+               if (__skb_splice_bits(frag_iter, &offset, &tlen, &spd, sk))
+                       break;
        }
 
 done:
@@ -1593,8 +1587,9 @@ done:
 
 int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len)
 {
-       int i, copy;
        int start = skb_headlen(skb);
+       struct sk_buff *frag_iter;
+       int i, copy;
 
        if (offset > (int)skb->len - len)
                goto fault;
@@ -1635,28 +1630,24 @@ int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len)
                start = end;
        }
 
-       if (skb_shinfo(skb)->frag_list) {
-               struct sk_buff *list = skb_shinfo(skb)->frag_list;
+       skb_walk_frags(skb, frag_iter) {
+               int end;
 
-               for (; list; list = list->next) {
-                       int end;
-
-                       WARN_ON(start > offset + len);
-
-                       end = start + list->len;
-                       if ((copy = end - offset) > 0) {
-                               if (copy > len)
-                                       copy = len;
-                               if (skb_store_bits(list, offset - start,
-                                                  from, copy))
-                                       goto fault;
-                               if ((len -= copy) == 0)
-                                       return 0;
-                               offset += copy;
-                               from += copy;
-                       }
-                       start = end;
+               WARN_ON(start > offset + len);
+
+               end = start + frag_iter->len;
+               if ((copy = end - offset) > 0) {
+                       if (copy > len)
+                               copy = len;
+                       if (skb_store_bits(frag_iter, offset - start,
+                                          from, copy))
+                               goto fault;
+                       if ((len -= copy) == 0)
+                               return 0;
+                       offset += copy;
+                       from += copy;
                }
+               start = end;
        }
        if (!len)
                return 0;
@@ -1673,6 +1664,7 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,
 {
        int start = skb_headlen(skb);
        int i, copy = start - offset;
+       struct sk_buff *frag_iter;
        int pos = 0;
 
        /* Checksum header. */
@@ -1712,29 +1704,25 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,
                start = end;
        }
 
-       if (skb_shinfo(skb)->frag_list) {
-               struct sk_buff *list = skb_shinfo(skb)->frag_list;
+       skb_walk_frags(skb, frag_iter) {
+               int end;
 
-               for (; list; list = list->next) {
-                       int end;
-
-                       WARN_ON(start > offset + len);
-
-                       end = start + list->len;
-                       if ((copy = end - offset) > 0) {
-                               __wsum csum2;
-                               if (copy > len)
-                                       copy = len;
-                               csum2 = skb_checksum(list, offset - start,
-                                                    copy, 0);
-                               csum = csum_block_add(csum, csum2, pos);
-                               if ((len -= copy) == 0)
-                                       return csum;
-                               offset += copy;
-                               pos    += copy;
-                       }
-                       start = end;
+               WARN_ON(start > offset + len);
+
+               end = start + frag_iter->len;
+               if ((copy = end - offset) > 0) {
+                       __wsum csum2;
+                       if (copy > len)
+                               copy = len;
+                       csum2 = skb_checksum(frag_iter, offset - start,
+                                            copy, 0);
+                       csum = csum_block_add(csum, csum2, pos);
+                       if ((len -= copy) == 0)
+                               return csum;
+                       offset += copy;
+                       pos    += copy;
                }
+               start = end;
        }
        BUG_ON(len);
 
@@ -1749,6 +1737,7 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
 {
        int start = skb_headlen(skb);
        int i, copy = start - offset;
+       struct sk_buff *frag_iter;
        int pos = 0;
 
        /* Copy header. */
@@ -1793,31 +1782,27 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
                start = end;
        }
 
-       if (skb_shinfo(skb)->frag_list) {
-               struct sk_buff *list = skb_shinfo(skb)->frag_list;
+       skb_walk_frags(skb, frag_iter) {
+               __wsum csum2;
+               int end;
 
-               for (; list; list = list->next) {
-                       __wsum csum2;
-                       int end;
-
-                       WARN_ON(start > offset + len);
-
-                       end = start + list->len;
-                       if ((copy = end - offset) > 0) {
-                               if (copy > len)
-                                       copy = len;
-                               csum2 = skb_copy_and_csum_bits(list,
-                                                              offset - start,
-                                                              to, copy, 0);
-                               csum = csum_block_add(csum, csum2, pos);
-                               if ((len -= copy) == 0)
-                                       return csum;
-                               offset += copy;
-                               to     += copy;
-                               pos    += copy;
-                       }
-                       start = end;
+               WARN_ON(start > offset + len);
+
+               end = start + frag_iter->len;
+               if ((copy = end - offset) > 0) {
+                       if (copy > len)
+                               copy = len;
+                       csum2 = skb_copy_and_csum_bits(frag_iter,
+                                                      offset - start,
+                                                      to, copy, 0);
+                       csum = csum_block_add(csum, csum2, pos);
+                       if ((len -= copy) == 0)
+                               return csum;
+                       offset += copy;
+                       to     += copy;
+                       pos    += copy;
                }
+               start = end;
        }
        BUG_ON(len);
        return csum;
@@ -2327,8 +2312,7 @@ next_skb:
                st->frag_data = NULL;
        }
 
-       if (st->root_skb == st->cur_skb &&
-           skb_shinfo(st->root_skb)->frag_list) {
+       if (st->root_skb == st->cur_skb && skb_has_frags(st->root_skb)) {
                st->cur_skb = skb_shinfo(st->root_skb)->frag_list;
                st->frag_idx = 0;
                goto next_skb;
@@ -2639,7 +2623,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features)
                        } else
                                skb_get(fskb2);
 
-                       BUG_ON(skb_shinfo(nskb)->frag_list);
+                       SKB_FRAG_ASSERT(nskb);
                        skb_shinfo(nskb)->frag_list = fskb2;
                }
 
@@ -2796,6 +2780,7 @@ __skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
 {
        int start = skb_headlen(skb);
        int i, copy = start - offset;
+       struct sk_buff *frag_iter;
        int elt = 0;
 
        if (copy > 0) {
@@ -2829,26 +2814,22 @@ __skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
                start = end;
        }
 
-       if (skb_shinfo(skb)->frag_list) {
-               struct sk_buff *list = skb_shinfo(skb)->frag_list;
-
-               for (; list; list = list->next) {
-                       int end;
+       skb_walk_frags(skb, frag_iter) {
+               int end;
 
-                       WARN_ON(start > offset + len);
+               WARN_ON(start > offset + len);
 
-                       end = start + list->len;
-                       if ((copy = end - offset) > 0) {
-                               if (copy > len)
-                                       copy = len;
-                               elt += __skb_to_sgvec(list, sg+elt, offset - start,
-                                                     copy);
-                               if ((len -= copy) == 0)
-                                       return elt;
-                               offset += copy;
-                       }
-                       start = end;
+               end = start + frag_iter->len;
+               if ((copy = end - offset) > 0) {
+                       if (copy > len)
+                               copy = len;
+                       elt += __skb_to_sgvec(frag_iter, sg+elt, offset - start,
+                                             copy);
+                       if ((len -= copy) == 0)
+                               return elt;
+                       offset += copy;
                }
+               start = end;
        }
        BUG_ON(len);
        return elt;
@@ -2896,7 +2877,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)
                return -ENOMEM;
 
        /* Easy case. Most of packets will go this way. */
-       if (!skb_shinfo(skb)->frag_list) {
+       if (!skb_has_frags(skb)) {
                /* A little of trouble, not enough of space for trailer.
                 * This should not happen, when stack is tuned to generate
                 * good frames. OK, on miss we reallocate and reserve even more
@@ -2931,7 +2912,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)
 
                if (skb1->next == NULL && tailbits) {
                        if (skb_shinfo(skb1)->nr_frags ||
-                           skb_shinfo(skb1)->frag_list ||
+                           skb_has_frags(skb1) ||
                            skb_tailroom(skb1) < tailbits)
                                ntail = tailbits + 128;
                }
@@ -2940,7 +2921,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)
                    skb_cloned(skb1) ||
                    ntail ||
                    skb_shinfo(skb1)->nr_frags ||
-                   skb_shinfo(skb1)->frag_list) {
+                   skb_has_frags(skb1)) {
                        struct sk_buff *skb2;
 
                        /* Fuck, we are miserable poor guys... */
@@ -3026,12 +3007,12 @@ EXPORT_SYMBOL_GPL(skb_tstamp_tx);
  */
 bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off)
 {
-       if (unlikely(start > skb->len - 2) ||
-           unlikely((int)start + off > skb->len - 2)) {
+       if (unlikely(start > skb_headlen(skb)) ||
+           unlikely((int)start + off > skb_headlen(skb) - 2)) {
                if (net_ratelimit())
                        printk(KERN_WARNING
                               "bad partial csum: csum=%u/%u len=%u\n",
-                              start, off, skb->len);
+                              start, off, skb_headlen(skb));
                return false;
        }
        skb->ip_summed = CHECKSUM_PARTIAL;
index 7dbf3ff..06e26b7 100644 (file)
@@ -155,6 +155,7 @@ static const char *af_family_key_strings[AF_MAX+1] = {
   "sk_lock-27"       , "sk_lock-28"          , "sk_lock-AF_CAN"      ,
   "sk_lock-AF_TIPC"  , "sk_lock-AF_BLUETOOTH", "sk_lock-IUCV"        ,
   "sk_lock-AF_RXRPC" , "sk_lock-AF_ISDN"     , "sk_lock-AF_PHONET"   ,
+  "sk_lock-AF_IEEE802154",
   "sk_lock-AF_MAX"
 };
 static const char *af_family_slock_key_strings[AF_MAX+1] = {
@@ -170,6 +171,7 @@ static const char *af_family_slock_key_strings[AF_MAX+1] = {
   "slock-27"       , "slock-28"          , "slock-AF_CAN"      ,
   "slock-AF_TIPC"  , "slock-AF_BLUETOOTH", "slock-AF_IUCV"     ,
   "slock-AF_RXRPC" , "slock-AF_ISDN"     , "slock-AF_PHONET"   ,
+  "slock-AF_IEEE802154",
   "slock-AF_MAX"
 };
 static const char *af_family_clock_key_strings[AF_MAX+1] = {
@@ -185,6 +187,7 @@ static const char *af_family_clock_key_strings[AF_MAX+1] = {
   "clock-27"       , "clock-28"          , "clock-AF_CAN"      ,
   "clock-AF_TIPC"  , "clock-AF_BLUETOOTH", "clock-AF_IUCV"     ,
   "clock-AF_RXRPC" , "clock-AF_ISDN"     , "clock-AF_PHONET"   ,
+  "clock-AF_IEEE802154",
   "clock-AF_MAX"
 };
 
@@ -212,6 +215,7 @@ __u32 sysctl_rmem_default __read_mostly = SK_RMEM_MAX;
 
 /* Maximal space eaten by iovec or ancilliary data plus some space */
 int sysctl_optmem_max __read_mostly = sizeof(unsigned long)*(2*UIO_MAXIOV+512);
+EXPORT_SYMBOL(sysctl_optmem_max);
 
 static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen)
 {
@@ -444,7 +448,7 @@ static inline void sock_valbool_flag(struct sock *sk, int bit, int valbool)
 int sock_setsockopt(struct socket *sock, int level, int optname,
                    char __user *optval, int optlen)
 {
-       struct sock *sk=sock->sk;
+       struct sock *sk = sock->sk;
        int val;
        int valbool;
        struct linger ling;
@@ -463,15 +467,15 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
        if (get_user(val, (int __user *)optval))
                return -EFAULT;
 
-       valbool = val?1:0;
+       valbool = val ? 1 : 0;
 
        lock_sock(sk);
 
-       switch(optname) {
+       switch (optname) {
        case SO_DEBUG:
-               if (val && !capable(CAP_NET_ADMIN)) {
+               if (val && !capable(CAP_NET_ADMIN))
                        ret = -EACCES;
-               else
+               else
                        sock_valbool_flag(sk, SOCK_DBG, valbool);
                break;
        case SO_REUSEADDR:
@@ -582,7 +586,7 @@ set_rcvbuf:
                        ret = -EINVAL;  /* 1003.1g */
                        break;
                }
-               if (copy_from_user(&ling,optval,sizeof(ling))) {
+               if (copy_from_user(&ling, optval, sizeof(ling))) {
                        ret = -EFAULT;
                        break;
                }
@@ -690,9 +694,8 @@ set_rcvbuf:
        case SO_MARK:
                if (!capable(CAP_NET_ADMIN))
                        ret = -EPERM;
-               else {
+               else
                        sk->sk_mark = val;
-               }
                break;
 
                /* We implement the SO_SNDLOWAT etc to
@@ -704,6 +707,7 @@ set_rcvbuf:
        release_sock(sk);
        return ret;
 }
+EXPORT_SYMBOL(sock_setsockopt);
 
 
 int sock_getsockopt(struct socket *sock, int level, int optname,
@@ -727,7 +731,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
 
        memset(&v, 0, sizeof(v));
 
-       switch(optname) {
+       switch (optname) {
        case SO_DEBUG:
                v.val = sock_flag(sk, SOCK_DBG);
                break;
@@ -762,7 +766,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
 
        case SO_ERROR:
                v.val = -sock_error(sk);
-               if (v.val==0)
+               if (v.val == 0)
                        v.val = xchg(&sk->sk_err_soft, 0);
                break;
 
@@ -816,7 +820,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
                break;
 
        case SO_RCVTIMEO:
-               lv=sizeof(struct timeval);
+               lv = sizeof(struct timeval);
                if (sk->sk_rcvtimeo == MAX_SCHEDULE_TIMEOUT) {
                        v.tm.tv_sec = 0;
                        v.tm.tv_usec = 0;
@@ -827,7 +831,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
                break;
 
        case SO_SNDTIMEO:
-               lv=sizeof(struct timeval);
+               lv = sizeof(struct timeval);
                if (sk->sk_sndtimeo == MAX_SCHEDULE_TIMEOUT) {
                        v.tm.tv_sec = 0;
                        v.tm.tv_usec = 0;
@@ -842,7 +846,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
                break;
 
        case SO_SNDLOWAT:
-               v.val=1;
+               v.val = 1;
                break;
 
        case SO_PASSCRED:
@@ -1002,8 +1006,9 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority,
 
        return sk;
 }
+EXPORT_SYMBOL(sk_alloc);
 
-void sk_free(struct sock *sk)
+static void __sk_free(struct sock *sk)
 {
        struct sk_filter *filter;
 
@@ -1027,6 +1032,18 @@ void sk_free(struct sock *sk)
        sk_prot_free(sk->sk_prot_creator, sk);
 }
 
+void sk_free(struct sock *sk)
+{
+       /*
+        * We substract one from sk_wmem_alloc and can know if
+        * some packets are still in some tx queue.
+        * If not null, sock_wfree() will call __sk_free(sk) later
+        */
+       if (atomic_dec_and_test(&sk->sk_wmem_alloc))
+               __sk_free(sk);
+}
+EXPORT_SYMBOL(sk_free);
+
 /*
  * Last sock_put should drop referrence to sk->sk_net. It has already
  * been dropped in sk_change_net. Taking referrence to stopping namespace
@@ -1065,7 +1082,10 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority)
                newsk->sk_backlog.head  = newsk->sk_backlog.tail = NULL;
 
                atomic_set(&newsk->sk_rmem_alloc, 0);
-               atomic_set(&newsk->sk_wmem_alloc, 0);
+               /*
+                * sk_wmem_alloc set to one (see sk_free() and sock_wfree())
+                */
+               atomic_set(&newsk->sk_wmem_alloc, 1);
                atomic_set(&newsk->sk_omem_alloc, 0);
                skb_queue_head_init(&newsk->sk_receive_queue);
                skb_queue_head_init(&newsk->sk_write_queue);
@@ -1126,7 +1146,6 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority)
 out:
        return newsk;
 }
-
 EXPORT_SYMBOL_GPL(sk_clone);
 
 void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
@@ -1170,13 +1189,20 @@ void __init sk_init(void)
 void sock_wfree(struct sk_buff *skb)
 {
        struct sock *sk = skb->sk;
+       int res;
 
        /* In case it might be waiting for more memory. */
-       atomic_sub(skb->truesize, &sk->sk_wmem_alloc);
+       res = atomic_sub_return(skb->truesize, &sk->sk_wmem_alloc);
        if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE))
                sk->sk_write_space(sk);
-       sock_put(sk);
+       /*
+        * if sk_wmem_alloc reached 0, we are last user and should
+        * free this sock, as sk_free() call could not do it.
+        */
+       if (res == 0)
+               __sk_free(sk);
 }
+EXPORT_SYMBOL(sock_wfree);
 
 /*
  * Read buffer destructor automatically called from kfree_skb.
@@ -1188,6 +1214,7 @@ void sock_rfree(struct sk_buff *skb)
        atomic_sub(skb->truesize, &sk->sk_rmem_alloc);
        sk_mem_uncharge(skb->sk, skb->truesize);
 }
+EXPORT_SYMBOL(sock_rfree);
 
 
 int sock_i_uid(struct sock *sk)
@@ -1199,6 +1226,7 @@ int sock_i_uid(struct sock *sk)
        read_unlock(&sk->sk_callback_lock);
        return uid;
 }
+EXPORT_SYMBOL(sock_i_uid);
 
 unsigned long sock_i_ino(struct sock *sk)
 {
@@ -1209,6 +1237,7 @@ unsigned long sock_i_ino(struct sock *sk)
        read_unlock(&sk->sk_callback_lock);
        return ino;
 }
+EXPORT_SYMBOL(sock_i_ino);
 
 /*
  * Allocate a skb from the socket's send buffer.
@@ -1217,7 +1246,7 @@ struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force,
                             gfp_t priority)
 {
        if (force || atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) {
-               struct sk_buff * skb = alloc_skb(size, priority);
+               struct sk_buff *skb = alloc_skb(size, priority);
                if (skb) {
                        skb_set_owner_w(skb, sk);
                        return skb;
@@ -1225,6 +1254,7 @@ struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force,
        }
        return NULL;
 }
+EXPORT_SYMBOL(sock_wmalloc);
 
 /*
  * Allocate a skb from the socket's receive buffer.
@@ -1261,6 +1291,7 @@ void *sock_kmalloc(struct sock *sk, int size, gfp_t priority)
        }
        return NULL;
 }
+EXPORT_SYMBOL(sock_kmalloc);
 
 /*
  * Free an option memory block.
@@ -1270,11 +1301,12 @@ void sock_kfree_s(struct sock *sk, void *mem, int size)
        kfree(mem);
        atomic_sub(size, &sk->sk_omem_alloc);
 }
+EXPORT_SYMBOL(sock_kfree_s);
 
 /* It is almost wait_for_tcp_memory minus release_sock/lock_sock.
    I think, these locks should be removed for datagram sockets.
  */
-static long sock_wait_for_wmem(struct sock * sk, long timeo)
+static long sock_wait_for_wmem(struct sock *sk, long timeo)
 {
        DEFINE_WAIT(wait);
 
@@ -1392,6 +1424,7 @@ struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size,
 {
        return sock_alloc_send_pskb(sk, size, 0, noblock, errcode);
 }
+EXPORT_SYMBOL(sock_alloc_send_skb);
 
 static void __lock_sock(struct sock *sk)
 {
@@ -1460,7 +1493,6 @@ int sk_wait_data(struct sock *sk, long *timeo)
        finish_wait(sk->sk_sleep, &wait);
        return rc;
 }
-
 EXPORT_SYMBOL(sk_wait_data);
 
 /**
@@ -1541,7 +1573,6 @@ suppress_allocation:
        atomic_sub(amt, prot->memory_allocated);
        return 0;
 }
-
 EXPORT_SYMBOL(__sk_mem_schedule);
 
 /**
@@ -1560,7 +1591,6 @@ void __sk_mem_reclaim(struct sock *sk)
            (atomic_read(prot->memory_allocated) < prot->sysctl_mem[0]))
                *prot->memory_pressure = 0;
 }
-
 EXPORT_SYMBOL(__sk_mem_reclaim);
 
 
@@ -1575,78 +1605,92 @@ int sock_no_bind(struct socket *sock, struct sockaddr *saddr, int len)
 {
        return -EOPNOTSUPP;
 }
+EXPORT_SYMBOL(sock_no_bind);
 
 int sock_no_connect(struct socket *sock, struct sockaddr *saddr,
                    int len, int flags)
 {
        return -EOPNOTSUPP;
 }
+EXPORT_SYMBOL(sock_no_connect);
 
 int sock_no_socketpair(struct socket *sock1, struct socket *sock2)
 {
        return -EOPNOTSUPP;
 }
+EXPORT_SYMBOL(sock_no_socketpair);
 
 int sock_no_accept(struct socket *sock, struct socket *newsock, int flags)
 {
        return -EOPNOTSUPP;
 }
+EXPORT_SYMBOL(sock_no_accept);
 
 int sock_no_getname(struct socket *sock, struct sockaddr *saddr,
                    int *len, int peer)
 {
        return -EOPNOTSUPP;
 }
+EXPORT_SYMBOL(sock_no_getname);
 
-unsigned int sock_no_poll(struct file * file, struct socket *sock, poll_table *pt)
+unsigned int sock_no_poll(struct file *file, struct socket *sock, poll_table *pt)
 {
        return 0;
 }
+EXPORT_SYMBOL(sock_no_poll);
 
 int sock_no_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
        return -EOPNOTSUPP;
 }
+EXPORT_SYMBOL(sock_no_ioctl);
 
 int sock_no_listen(struct socket *sock, int backlog)
 {
        return -EOPNOTSUPP;
 }
+EXPORT_SYMBOL(sock_no_listen);
 
 int sock_no_shutdown(struct socket *sock, int how)
 {
        return -EOPNOTSUPP;
 }
+EXPORT_SYMBOL(sock_no_shutdown);
 
 int sock_no_setsockopt(struct socket *sock, int level, int optname,
                    char __user *optval, int optlen)
 {
        return -EOPNOTSUPP;
 }
+EXPORT_SYMBOL(sock_no_setsockopt);
 
 int sock_no_getsockopt(struct socket *sock, int level, int optname,
                    char __user *optval, int __user *optlen)
 {
        return -EOPNOTSUPP;
 }
+EXPORT_SYMBOL(sock_no_getsockopt);
 
 int sock_no_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
                    size_t len)
 {
        return -EOPNOTSUPP;
 }
+EXPORT_SYMBOL(sock_no_sendmsg);
 
 int sock_no_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
                    size_t len, int flags)
 {
        return -EOPNOTSUPP;
 }
+EXPORT_SYMBOL(sock_no_recvmsg);
 
 int sock_no_mmap(struct file *file, struct socket *sock, struct vm_area_struct *vma)
 {
        /* Mirror missing mmap method error code */
        return -ENODEV;
 }
+EXPORT_SYMBOL(sock_no_mmap);
 
 ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags)
 {
@@ -1660,6 +1704,7 @@ ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, siz
        kunmap(page);
        return res;
 }
+EXPORT_SYMBOL(sock_no_sendpage);
 
 /*
  *     Default Socket Callbacks
@@ -1723,6 +1768,7 @@ void sk_send_sigurg(struct sock *sk)
                if (send_sigurg(&sk->sk_socket->file->f_owner))
                        sk_wake_async(sk, SOCK_WAKE_URG, POLL_PRI);
 }
+EXPORT_SYMBOL(sk_send_sigurg);
 
 void sk_reset_timer(struct sock *sk, struct timer_list* timer,
                    unsigned long expires)
@@ -1730,7 +1776,6 @@ void sk_reset_timer(struct sock *sk, struct timer_list* timer,
        if (!mod_timer(timer, expires))
                sock_hold(sk);
 }
-
 EXPORT_SYMBOL(sk_reset_timer);
 
 void sk_stop_timer(struct sock *sk, struct timer_list* timer)
@@ -1738,7 +1783,6 @@ void sk_stop_timer(struct sock *sk, struct timer_list* timer)
        if (timer_pending(timer) && del_timer(timer))
                __sock_put(sk);
 }
-
 EXPORT_SYMBOL(sk_stop_timer);
 
 void sock_init_data(struct socket *sock, struct sock *sk)
@@ -1795,8 +1839,10 @@ void sock_init_data(struct socket *sock, struct sock *sk)
        sk->sk_stamp = ktime_set(-1L, 0);
 
        atomic_set(&sk->sk_refcnt, 1);
+       atomic_set(&sk->sk_wmem_alloc, 1);
        atomic_set(&sk->sk_drops, 0);
 }
+EXPORT_SYMBOL(sock_init_data);
 
 void lock_sock_nested(struct sock *sk, int subclass)
 {
@@ -1812,7 +1858,6 @@ void lock_sock_nested(struct sock *sk, int subclass)
        mutex_acquire(&sk->sk_lock.dep_map, subclass, 0, _RET_IP_);
        local_bh_enable();
 }
-
 EXPORT_SYMBOL(lock_sock_nested);
 
 void release_sock(struct sock *sk)
@@ -1895,7 +1940,6 @@ int sock_common_getsockopt(struct socket *sock, int level, int optname,
 
        return sk->sk_prot->getsockopt(sk, level, optname, optval, optlen);
 }
-
 EXPORT_SYMBOL(sock_common_getsockopt);
 
 #ifdef CONFIG_COMPAT
@@ -1925,7 +1969,6 @@ int sock_common_recvmsg(struct kiocb *iocb, struct socket *sock,
                msg->msg_namelen = addr_len;
        return err;
 }
-
 EXPORT_SYMBOL(sock_common_recvmsg);
 
 /*
@@ -1938,7 +1981,6 @@ int sock_common_setsockopt(struct socket *sock, int level, int optname,
 
        return sk->sk_prot->setsockopt(sk, level, optname, optval, optlen);
 }
-
 EXPORT_SYMBOL(sock_common_setsockopt);
 
 #ifdef CONFIG_COMPAT
@@ -1989,7 +2031,6 @@ void sk_common_release(struct sock *sk)
        sk_refcnt_debug_release(sk);
        sock_put(sk);
 }
-
 EXPORT_SYMBOL(sk_common_release);
 
 static DEFINE_RWLOCK(proto_list_lock);
@@ -2171,7 +2212,6 @@ out_free_sock_slab:
 out:
        return -ENOBUFS;
 }
-
 EXPORT_SYMBOL(proto_register);
 
 void proto_unregister(struct proto *prot)
@@ -2198,7 +2238,6 @@ void proto_unregister(struct proto *prot)
                prot->twsk_prot->twsk_slab = NULL;
        }
 }
-
 EXPORT_SYMBOL(proto_unregister);
 
 #ifdef CONFIG_PROC_FS
@@ -2324,33 +2363,3 @@ static int __init proto_init(void)
 subsys_initcall(proto_init);
 
 #endif /* PROC_FS */
-
-EXPORT_SYMBOL(sk_alloc);
-EXPORT_SYMBOL(sk_free);
-EXPORT_SYMBOL(sk_send_sigurg);
-EXPORT_SYMBOL(sock_alloc_send_skb);
-EXPORT_SYMBOL(sock_init_data);
-EXPORT_SYMBOL(sock_kfree_s);
-EXPORT_SYMBOL(sock_kmalloc);
-EXPORT_SYMBOL(sock_no_accept);
-EXPORT_SYMBOL(sock_no_bind);
-EXPORT_SYMBOL(sock_no_connect);
-EXPORT_SYMBOL(sock_no_getname);
-EXPORT_SYMBOL(sock_no_getsockopt);
-EXPORT_SYMBOL(sock_no_ioctl);
-EXPORT_SYMBOL(sock_no_listen);
-EXPORT_SYMBOL(sock_no_mmap);
-EXPORT_SYMBOL(sock_no_poll);
-EXPORT_SYMBOL(sock_no_recvmsg);
-EXPORT_SYMBOL(sock_no_sendmsg);
-EXPORT_SYMBOL(sock_no_sendpage);
-EXPORT_SYMBOL(sock_no_setsockopt);
-EXPORT_SYMBOL(sock_no_shutdown);
-EXPORT_SYMBOL(sock_no_socketpair);
-EXPORT_SYMBOL(sock_rfree);
-EXPORT_SYMBOL(sock_setsockopt);
-EXPORT_SYMBOL(sock_wfree);
-EXPORT_SYMBOL(sock_wmalloc);
-EXPORT_SYMBOL(sock_i_uid);
-EXPORT_SYMBOL(sock_i_ino);
-EXPORT_SYMBOL(sysctl_optmem_max);
index 164b090..25d717e 100644 (file)
@@ -51,6 +51,7 @@ int dma_skb_copy_datagram_iovec(struct dma_chan *chan,
 {
        int start = skb_headlen(skb);
        int i, copy = start - offset;
+       struct sk_buff *frag_iter;
        dma_cookie_t cookie = 0;
 
        /* Copy header. */
@@ -94,31 +95,28 @@ int dma_skb_copy_datagram_iovec(struct dma_chan *chan,
                start = end;
        }
 
-       if (skb_shinfo(skb)->frag_list) {
-               struct sk_buff *list = skb_shinfo(skb)->frag_list;
-
-               for (; list; list = list->next) {
-                       int end;
-
-                       WARN_ON(start > offset + len);
-
-                       end = start + list->len;
-                       copy = end - offset;
-                       if (copy > 0) {
-                               if (copy > len)
-                                       copy = len;
-                               cookie = dma_skb_copy_datagram_iovec(chan, list,
-                                               offset - start, to, copy,
-                                               pinned_list);
-                               if (cookie < 0)
-                                       goto fault;
-                               len -= copy;
-                               if (len == 0)
-                                       goto end;
-                               offset += copy;
-                       }
-                       start = end;
+       skb_walk_frags(skb, frag_iter) {
+               int end;
+
+               WARN_ON(start > offset + len);
+
+               end = start + frag_iter->len;
+               copy = end - offset;
+               if (copy > 0) {
+                       if (copy > len)
+                               copy = len;
+                       cookie = dma_skb_copy_datagram_iovec(chan, frag_iter,
+                                                            offset - start,
+                                                            to, copy,
+                                                            pinned_list);
+                       if (cookie < 0)
+                               goto fault;
+                       len -= copy;
+                       if (len == 0)
+                               goto end;
+                       offset += copy;
                }
+               start = end;
        }
 
 end:
index d1dd952..a0a36c9 100644 (file)
@@ -452,7 +452,7 @@ static struct dst_entry* dccp_v4_route_skb(struct net *net, struct sock *sk,
                                           struct sk_buff *skb)
 {
        struct rtable *rt;
-       struct flowi fl = { .oif = skb->rtable->rt_iif,
+       struct flowi fl = { .oif = skb_rtable(skb)->rt_iif,
                            .nl_u = { .ip4_u =
                                      { .daddr = ip_hdr(skb)->saddr,
                                        .saddr = ip_hdr(skb)->daddr,
@@ -507,14 +507,14 @@ static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
        const struct iphdr *rxiph;
        struct sk_buff *skb;
        struct dst_entry *dst;
-       struct net *net = dev_net(rxskb->dst->dev);
+       struct net *net = dev_net(skb_dst(rxskb)->dev);
        struct sock *ctl_sk = net->dccp.v4_ctl_sk;
 
        /* Never send a reset in response to a reset. */
        if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET)
                return;
 
-       if (rxskb->rtable->rt_type != RTN_LOCAL)
+       if (skb_rtable(rxskb)->rt_type != RTN_LOCAL)
                return;
 
        dst = dccp_v4_route_skb(net, ctl_sk, rxskb);
@@ -528,7 +528,7 @@ static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
        rxiph = ip_hdr(rxskb);
        dccp_hdr(skb)->dccph_checksum = dccp_v4_csum_finish(skb, rxiph->saddr,
                                                                 rxiph->daddr);
-       skb->dst = dst_clone(dst);
+       skb_dst_set(skb, dst_clone(dst));
 
        bh_lock_sock(ctl_sk);
        err = ip_build_and_send_pkt(skb, ctl_sk,
@@ -567,7 +567,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
        struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
 
        /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */
-       if (skb->rtable->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
+       if (skb_rtable(skb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
                return 0;       /* discard, don't send a reset here */
 
        if (dccp_bad_service_code(sk, service)) {
index b963f35..05ea744 100644 (file)
@@ -314,8 +314,9 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
        struct ipv6hdr *rxip6h;
        struct sk_buff *skb;
        struct flowi fl;
-       struct net *net = dev_net(rxskb->dst->dev);
+       struct net *net = dev_net(skb_dst(rxskb)->dev);
        struct sock *ctl_sk = net->dccp.v6_ctl_sk;
+       struct dst_entry *dst;
 
        if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET)
                return;
@@ -342,8 +343,9 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
        security_skb_classify_flow(rxskb, &fl);
 
        /* sk = NULL, but it is safe for now. RST socket required. */
-       if (!ip6_dst_lookup(ctl_sk, &skb->dst, &fl)) {
-               if (xfrm_lookup(net, &skb->dst, &fl, NULL, 0) >= 0) {
+       if (!ip6_dst_lookup(ctl_sk, &dst, &fl)) {
+               if (xfrm_lookup(net, &dst, &fl, NULL, 0) >= 0) {
+                       skb_dst_set(skb, dst);
                        ip6_xmit(ctl_sk, skb, &fl, NULL, 0);
                        DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
                        DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);
index 36bcc00..c0e88c1 100644 (file)
@@ -350,7 +350,7 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
        /* Reserve space for headers. */
        skb_reserve(skb, sk->sk_prot->max_header);
 
-       skb->dst = dst_clone(dst);
+       skb_dst_set(skb, dst_clone(dst));
 
        dreq = dccp_rsk(req);
        if (inet_rsk(req)->acked)       /* increase ISS upon retransmission */
index 9647d91..a5e3a59 100644 (file)
@@ -1075,6 +1075,7 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags)
        int err = 0;
        unsigned char type;
        long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
+       struct dst_entry *dst;
 
        lock_sock(sk);
 
@@ -1102,8 +1103,9 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags)
        }
        release_sock(sk);
 
-       dst_release(xchg(&newsk->sk_dst_cache, skb->dst));
-       skb->dst = NULL;
+       dst = skb_dst(skb);
+       dst_release(xchg(&newsk->sk_dst_cache, dst));
+       skb_dst_set(skb, NULL);
 
        DN_SK(newsk)->state        = DN_CR;
        DN_SK(newsk)->addrrem      = cb->src_port;
@@ -1250,14 +1252,8 @@ static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                if (skb) {
                        amount = skb->len;
                } else {
-                       skb = sk->sk_receive_queue.next;
-                       for (;;) {
-                               if (skb ==
-                                   (struct sk_buff *)&sk->sk_receive_queue)
-                                       break;
+                       skb_queue_walk(&sk->sk_receive_queue, skb)
                                amount += skb->len;
-                               skb = skb->next;
-                       }
                }
                release_sock(sk);
                err = put_user(amount, (int __user *)arg);
@@ -1644,13 +1640,13 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char __us
 
 static int dn_data_ready(struct sock *sk, struct sk_buff_head *q, int flags, int target)
 {
-       struct sk_buff *skb = q->next;
+       struct sk_buff *skb;
        int len = 0;
 
        if (flags & MSG_OOB)
                return !skb_queue_empty(q) ? 1 : 0;
 
-       while(skb != (struct sk_buff *)q) {
+       skb_queue_walk(q, skb) {
                struct dn_skb_cb *cb = DN_SKB_CB(skb);
                len += skb->len;
 
@@ -1666,8 +1662,6 @@ static int dn_data_ready(struct sock *sk, struct sk_buff_head *q, int flags, int
                /* minimum data length for read exceeded */
                if (len >= target)
                        return 1;
-
-               skb = skb->next;
        }
 
        return 0;
@@ -1683,7 +1677,7 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock,
        size_t target = size > 1 ? 1 : 0;
        size_t copied = 0;
        int rv = 0;
-       struct sk_buff *skb, *nskb;
+       struct sk_buff *skb, *n;
        struct dn_skb_cb *cb = NULL;
        unsigned char eor = 0;
        long timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
@@ -1758,7 +1752,7 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock,
                finish_wait(sk->sk_sleep, &wait);
        }
 
-       for(skb = queue->next; skb != (struct sk_buff *)queue; skb = nskb) {
+       skb_queue_walk_safe(queue, skb, n) {
                unsigned int chunk = skb->len;
                cb = DN_SKB_CB(skb);
 
@@ -1775,7 +1769,6 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock,
                        skb_pull(skb, chunk);
 
                eor = cb->nsp_flags & 0x40;
-               nskb = skb->next;
 
                if (skb->len == 0) {
                        skb_unlink(skb, queue);
index 05b5aa0..923786b 100644 (file)
@@ -204,7 +204,7 @@ static void dn_short_error_report(struct neighbour *neigh, struct sk_buff *skb)
 
 static int dn_neigh_output_packet(struct sk_buff *skb)
 {
-       struct dst_entry *dst = skb->dst;
+       struct dst_entry *dst = skb_dst(skb);
        struct dn_route *rt = (struct dn_route *)dst;
        struct neighbour *neigh = dst->neighbour;
        struct net_device *dev = neigh->dev;
@@ -224,7 +224,7 @@ static int dn_neigh_output_packet(struct sk_buff *skb)
 
 static int dn_long_output(struct sk_buff *skb)
 {
-       struct dst_entry *dst = skb->dst;
+       struct dst_entry *dst = skb_dst(skb);
        struct neighbour *neigh = dst->neighbour;
        struct net_device *dev = neigh->dev;
        int headroom = dev->hard_header_len + sizeof(struct dn_long_packet) + 3;
@@ -270,7 +270,7 @@ static int dn_long_output(struct sk_buff *skb)
 
 static int dn_short_output(struct sk_buff *skb)
 {
-       struct dst_entry *dst = skb->dst;
+       struct dst_entry *dst = skb_dst(skb);
        struct neighbour *neigh = dst->neighbour;
        struct net_device *dev = neigh->dev;
        int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2;
@@ -313,7 +313,7 @@ static int dn_short_output(struct sk_buff *skb)
  */
 static int dn_phase3_output(struct sk_buff *skb)
 {
-       struct dst_entry *dst = skb->dst;
+       struct dst_entry *dst = skb_dst(skb);
        struct neighbour *neigh = dst->neighbour;
        struct net_device *dev = neigh->dev;
        int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2;
index 2013c25..a65e929 100644 (file)
@@ -85,7 +85,7 @@ static void dn_nsp_send(struct sk_buff *skb)
        dst = sk_dst_check(sk, 0);
        if (dst) {
 try_again:
-               skb->dst = dst;
+               skb_dst_set(skb, dst);
                dst_output(skb);
                return;
        }
@@ -382,7 +382,7 @@ int dn_nsp_check_xmit_queue(struct sock *sk, struct sk_buff *skb, struct sk_buff
 {
        struct dn_skb_cb *cb = DN_SKB_CB(skb);
        struct dn_scp *scp = DN_SK(sk);
-       struct sk_buff *skb2, *list, *ack = NULL;
+       struct sk_buff *skb2, *n, *ack = NULL;
        int wakeup = 0;
        int try_retrans = 0;
        unsigned long reftime = cb->stamp;
@@ -390,9 +390,7 @@ int dn_nsp_check_xmit_queue(struct sock *sk, struct sk_buff *skb, struct sk_buff
        unsigned short xmit_count;
        unsigned short segnum;
 
-       skb2 = q->next;
-       list = (struct sk_buff *)q;
-       while(list != skb2) {
+       skb_queue_walk_safe(q, skb2, n) {
                struct dn_skb_cb *cb2 = DN_SKB_CB(skb2);
 
                if (dn_before_or_equal(cb2->segnum, acknum))
@@ -400,8 +398,6 @@ int dn_nsp_check_xmit_queue(struct sock *sk, struct sk_buff *skb, struct sk_buff
 
                /* printk(KERN_DEBUG "ack: %s %04x %04x\n", ack ? "ACK" : "SKIP", (int)cb2->segnum, (int)acknum); */
 
-               skb2 = skb2->next;
-
                if (ack == NULL)
                        continue;
 
@@ -586,7 +582,7 @@ static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg,
         * to be able to send disc packets out which have no socket
         * associations.
         */
-       skb->dst = dst_clone(dst);
+       skb_dst_set(skb, dst_clone(dst));
        dst_output(skb);
 }
 
@@ -615,7 +611,7 @@ void dn_nsp_return_disc(struct sk_buff *skb, unsigned char msgflg,
        int ddl = 0;
        gfp_t gfp = GFP_ATOMIC;
 
-       dn_nsp_do_disc(NULL, msgflg, reason, gfp, skb->dst, ddl,
+       dn_nsp_do_disc(NULL, msgflg, reason, gfp, skb_dst(skb), ddl,
                        NULL, cb->src_port, cb->dst_port);
 }
 
index 0cc4394..1d6ca8a 100644 (file)
@@ -678,7 +678,7 @@ out:
 
 static int dn_output(struct sk_buff *skb)
 {
-       struct dst_entry *dst = skb->dst;
+       struct dst_entry *dst = skb_dst(skb);
        struct dn_route *rt = (struct dn_route *)dst;
        struct net_device *dev = dst->dev;
        struct dn_skb_cb *cb = DN_SKB_CB(skb);
@@ -717,7 +717,7 @@ error:
 static int dn_forward(struct sk_buff *skb)
 {
        struct dn_skb_cb *cb = DN_SKB_CB(skb);
-       struct dst_entry *dst = skb->dst;
+       struct dst_entry *dst = skb_dst(skb);
        struct dn_dev *dn_db = dst->dev->dn_ptr;
        struct dn_route *rt;
        struct neighbour *neigh = dst->neighbour;
@@ -730,7 +730,7 @@ static int dn_forward(struct sk_buff *skb)
                goto drop;
 
        /* Ensure that we have enough space for headers */
-       rt = (struct dn_route *)skb->dst;
+       rt = (struct dn_route *)skb_dst(skb);
        header_len = dn_db->use_long ? 21 : 6;
        if (skb_cow(skb, LL_RESERVED_SPACE(rt->u.dst.dev)+header_len))
                goto drop;
@@ -1392,7 +1392,8 @@ make_route:
                goto e_neighbour;
 
        hash = dn_hash(rt->fl.fld_src, rt->fl.fld_dst);
-       dn_insert_route(rt, hash, (struct dn_route **)&skb->dst);
+       dn_insert_route(rt, hash, &rt);
+       skb_dst_set(skb, &rt->u.dst);
 
 done:
        if (neigh)
@@ -1424,7 +1425,7 @@ static int dn_route_input(struct sk_buff *skb)
        struct dn_skb_cb *cb = DN_SKB_CB(skb);
        unsigned hash = dn_hash(cb->src, cb->dst);
 
-       if (skb->dst)
+       if (skb_dst(skb))
                return 0;
 
        rcu_read_lock();
@@ -1437,7 +1438,7 @@ static int dn_route_input(struct sk_buff *skb)
                    (rt->fl.iif == cb->iif)) {
                        dst_use(&rt->u.dst, jiffies);
                        rcu_read_unlock();
-                       skb->dst = (struct dst_entry *)rt;
+                       skb_dst_set(skb, (struct dst_entry *)rt);
                        return 0;
                }
        }
@@ -1449,7 +1450,7 @@ static int dn_route_input(struct sk_buff *skb)
 static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
                           int event, int nowait, unsigned int flags)
 {
-       struct dn_route *rt = (struct dn_route *)skb->dst;
+       struct dn_route *rt = (struct dn_route *)skb_dst(skb);
        struct rtmsg *r;
        struct nlmsghdr *nlh;
        unsigned char *b = skb_tail_pointer(skb);
@@ -1554,7 +1555,7 @@ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void
                err = dn_route_input(skb);
                local_bh_enable();
                memset(cb, 0, sizeof(struct dn_skb_cb));
-               rt = (struct dn_route *)skb->dst;
+               rt = (struct dn_route *)skb_dst(skb);
                if (!err && -rt->u.dst.error)
                        err = rt->u.dst.error;
        } else {
@@ -1570,7 +1571,7 @@ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void
        skb->dev = NULL;
        if (err)
                goto out_free;
-       skb->dst = &rt->u.dst;
+       skb_dst_set(skb, &rt->u.dst);
        if (rtm->rtm_flags & RTM_F_NOTIFY)
                rt->rt_flags |= RTCF_NOTIFY;
 
@@ -1622,15 +1623,15 @@ int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb)
                        rt = rcu_dereference(rt->u.dst.dn_next), idx++) {
                        if (idx < s_idx)
                                continue;
-                       skb->dst = dst_clone(&rt->u.dst);
+                       skb_dst_set(skb, dst_clone(&rt->u.dst));
                        if (dn_rt_fill_info(skb, NETLINK_CB(cb->skb).pid,
                                        cb->nlh->nlmsg_seq, RTM_NEWROUTE,
                                        1, NLM_F_MULTI) <= 0) {
-                               dst_release(xchg(&skb->dst, NULL));
+                               skb_dst_drop(skb);
                                rcu_read_unlock_bh();
                                goto done;
                        }
-                       dst_release(xchg(&skb->dst, NULL));
+                       skb_dst_drop(skb);
                }
                rcu_read_unlock_bh();
        }
index ed13118..2175e6d 100644 (file)
@@ -67,7 +67,7 @@ static int dsa_slave_open(struct net_device *dev)
                return -ENETDOWN;
 
        if (compare_ether_addr(dev->dev_addr, master->dev_addr)) {
-               err = dev_unicast_add(master, dev->dev_addr, ETH_ALEN);
+               err = dev_unicast_add(master, dev->dev_addr);
                if (err < 0)
                        goto out;
        }
@@ -90,7 +90,7 @@ clear_allmulti:
                dev_set_allmulti(master, -1);
 del_unicast:
        if (compare_ether_addr(dev->dev_addr, master->dev_addr))
-               dev_unicast_delete(master, dev->dev_addr, ETH_ALEN);
+               dev_unicast_delete(master, dev->dev_addr);
 out:
        return err;
 }
@@ -108,7 +108,7 @@ static int dsa_slave_close(struct net_device *dev)
                dev_set_promiscuity(master, -1);
 
        if (compare_ether_addr(dev->dev_addr, master->dev_addr))
-               dev_unicast_delete(master, dev->dev_addr, ETH_ALEN);
+               dev_unicast_delete(master, dev->dev_addr);
 
        return 0;
 }
@@ -147,13 +147,13 @@ static int dsa_slave_set_mac_address(struct net_device *dev, void *a)
                goto out;
 
        if (compare_ether_addr(addr->sa_data, master->dev_addr)) {
-               err = dev_unicast_add(master, addr->sa_data, ETH_ALEN);
+               err = dev_unicast_add(master, addr->sa_data);
                if (err < 0)
                        return err;
        }
 
        if (compare_ether_addr(dev->dev_addr, master->dev_addr))
-               dev_unicast_delete(master, dev->dev_addr, ETH_ALEN);
+               dev_unicast_delete(master, dev->dev_addr);
 
 out:
        memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
index 6f479fa..8121bf0 100644 (file)
@@ -901,15 +901,10 @@ static void aun_tx_ack(unsigned long seq, int result)
        struct ec_cb *eb;
 
        spin_lock_irqsave(&aun_queue_lock, flags);
-       skb = skb_peek(&aun_queue);
-       while (skb && skb != (struct sk_buff *)&aun_queue)
-       {
-               struct sk_buff *newskb = skb->next;
+       skb_queue_walk(&aun_queue, skb) {
                eb = (struct ec_cb *)&skb->cb;
                if (eb->seq == seq)
                        goto foundit;
-
-               skb = newskb;
        }
        spin_unlock_irqrestore(&aun_queue_lock, flags);
        printk(KERN_DEBUG "AUN: unknown sequence %ld\n", seq);
@@ -982,23 +977,18 @@ static void aun_data_available(struct sock *sk, int slen)
 
 static void ab_cleanup(unsigned long h)
 {
-       struct sk_buff *skb;
+       struct sk_buff *skb, *n;
        unsigned long flags;
 
        spin_lock_irqsave(&aun_queue_lock, flags);
-       skb = skb_peek(&aun_queue);
-       while (skb && skb != (struct sk_buff *)&aun_queue)
-       {
-               struct sk_buff *newskb = skb->next;
+       skb_queue_walk_safe(&aun_queue, skb, n) {
                struct ec_cb *eb = (struct ec_cb *)&skb->cb;
-               if ((jiffies - eb->start) > eb->timeout)
-               {
+               if ((jiffies - eb->start) > eb->timeout) {
                        tx_result(skb->sk, eb->cookie,
                                  ECTYPE_TRANSMIT_NOT_PRESENT);
                        skb_unlink(skb, &aun_queue);
                        kfree_skb(skb);
                }
-               skb = newskb;
        }
        spin_unlock_irqrestore(&aun_queue_lock, flags);
 
diff --git a/net/ieee802154/Kconfig b/net/ieee802154/Kconfig
new file mode 100644 (file)
index 0000000..1c1de97
--- /dev/null
@@ -0,0 +1,12 @@
+config IEEE802154
+       tristate "IEEE Std 802.15.4 Low-Rate Wireless Personal Area Networks support (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
+       ---help---
+         IEEE Std 802.15.4 defines a low data rate, low power and low
+         complexity short range wireless personal area networks. It was
+         designed to organise networks of sensors, switches, etc automation
+         devices. Maximum allowed data rate is 250 kb/s and typical personal
+         operating space around 10m.
+
+         Say Y here to compile LR-WPAN support into the kernel or say M to
+         compile it as modules.
diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile
new file mode 100644 (file)
index 0000000..f99338a
--- /dev/null
@@ -0,0 +1,5 @@
+obj-$(CONFIG_IEEE802154) +=    nl802154.o af_802154.o
+nl802154-y             := netlink.o nl_policy.o
+af_802154-y            := af_ieee802154.o raw.o dgram.o
+
+ccflags-y += -Wall -DDEBUG
diff --git a/net/ieee802154/af802154.h b/net/ieee802154/af802154.h
new file mode 100644 (file)
index 0000000..b1ec525
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Internal interfaces for ieee 802.15.4 address family.
+ *
+ * Copyright 2007, 2008, 2009 Siemens AG
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by:
+ * Sergey Lapin <slapin@ossfans.org>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+
+#ifndef AF802154_H
+#define AF802154_H
+
+struct sk_buff;
+struct net_devce;
+extern struct proto ieee802154_raw_prot;
+extern struct proto ieee802154_dgram_prot;
+void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb);
+int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb);
+struct net_device *ieee802154_get_dev(struct net *net,
+               struct ieee802154_addr *addr);
+
+#endif
diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c
new file mode 100644 (file)
index 0000000..882a927
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+ * IEEE802154.4 socket interface
+ *
+ * Copyright 2007, 2008 Siemens AG
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by:
+ * Sergey Lapin <slapin@ossfans.org>
+ * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
+ */
+
+#include <linux/net.h>
+#include <linux/capability.h>
+#include <linux/module.h>
+#include <linux/if_arp.h>
+#include <linux/if.h>
+#include <linux/termios.h>     /* For TIOCOUTQ/INQ */
+#include <linux/list.h>
+#include <net/datalink.h>
+#include <net/psnap.h>
+#include <net/sock.h>
+#include <net/tcp_states.h>
+#include <net/route.h>
+
+#include <net/ieee802154/af_ieee802154.h>
+#include <net/ieee802154/netdevice.h>
+
+#include "af802154.h"
+
+#define DBG_DUMP(data, len) { \
+       int i; \
+       pr_debug("function: %s: data: len %d:\n", __func__, len); \
+       for (i = 0; i < len; i++) {\
+               pr_debug("%02x: %02x\n", i, (data)[i]); \
+       } \
+}
+
+/*
+ * Utility function for families
+ */
+struct net_device *ieee802154_get_dev(struct net *net,
+               struct ieee802154_addr *addr)
+{
+       struct net_device *dev = NULL;
+       struct net_device *tmp;
+       u16 pan_id, short_addr;
+
+       switch (addr->addr_type) {
+       case IEEE802154_ADDR_LONG:
+               rtnl_lock();
+               dev = dev_getbyhwaddr(net, ARPHRD_IEEE802154, addr->hwaddr);
+               if (dev)
+                       dev_hold(dev);
+               rtnl_unlock();
+               break;
+       case IEEE802154_ADDR_SHORT:
+               if (addr->pan_id == 0xffff ||
+                   addr->short_addr == IEEE802154_ADDR_UNDEF ||
+                   addr->short_addr == 0xffff)
+                       break;
+
+               rtnl_lock();
+
+               for_each_netdev(net, tmp) {
+                       if (tmp->type != ARPHRD_IEEE802154)
+                               continue;
+
+                       pan_id = ieee802154_mlme_ops(tmp)->get_pan_id(tmp);
+                       short_addr =
+                               ieee802154_mlme_ops(tmp)->get_short_addr(tmp);
+
+                       if (pan_id == addr->pan_id &&
+                           short_addr == addr->short_addr) {
+                               dev = tmp;
+                               dev_hold(dev);
+                               break;
+                       }
+               }
+
+               rtnl_unlock();
+               break;
+       default:
+               pr_warning("Unsupported ieee802154 address type: %d\n",
+                               addr->addr_type);
+               break;
+       }
+
+       return dev;
+}
+
+static int ieee802154_sock_release(struct socket *sock)
+{
+       struct sock *sk = sock->sk;
+
+       if (sk) {
+               sock->sk = NULL;
+               sk->sk_prot->close(sk, 0);
+       }
+       return 0;
+}
+static int ieee802154_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
+               struct msghdr *msg, size_t len)
+{
+       struct sock *sk = sock->sk;
+
+       return sk->sk_prot->sendmsg(iocb, sk, msg, len);
+}
+
+static int ieee802154_sock_bind(struct socket *sock, struct sockaddr *uaddr,
+               int addr_len)
+{
+       struct sock *sk = sock->sk;
+
+       if (sk->sk_prot->bind)
+               return sk->sk_prot->bind(sk, uaddr, addr_len);
+
+       return sock_no_bind(sock, uaddr, addr_len);
+}
+
+static int ieee802154_sock_connect(struct socket *sock, struct sockaddr *uaddr,
+                       int addr_len, int flags)
+{
+       struct sock *sk = sock->sk;
+
+       if (uaddr->sa_family == AF_UNSPEC)
+               return sk->sk_prot->disconnect(sk, flags);
+
+       return sk->sk_prot->connect(sk, uaddr, addr_len);
+}
+
+static int ieee802154_dev_ioctl(struct sock *sk, struct ifreq __user *arg,
+               unsigned int cmd)
+{
+       struct ifreq ifr;
+       int ret = -EINVAL;
+       struct net_device *dev;
+
+       if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
+               return -EFAULT;
+
+       ifr.ifr_name[IFNAMSIZ-1] = 0;
+
+       dev_load(sock_net(sk), ifr.ifr_name);
+       dev = dev_get_by_name(sock_net(sk), ifr.ifr_name);
+       if (dev->type == ARPHRD_IEEE802154 ||
+           dev->type == ARPHRD_IEEE802154_PHY)
+               ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, cmd);
+
+       if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq)))
+               ret = -EFAULT;
+       dev_put(dev);
+
+       return ret;
+}
+
+static int ieee802154_sock_ioctl(struct socket *sock, unsigned int cmd,
+               unsigned long arg)
+{
+       struct sock *sk = sock->sk;
+
+       switch (cmd) {
+       case SIOCGSTAMP:
+               return sock_get_timestamp(sk, (struct timeval __user *)arg);
+       case SIOCGSTAMPNS:
+               return sock_get_timestampns(sk, (struct timespec __user *)arg);
+       case SIOCGIFADDR:
+       case SIOCSIFADDR:
+               return ieee802154_dev_ioctl(sk, (struct ifreq __user *)arg,
+                               cmd);
+       default:
+               if (!sk->sk_prot->ioctl)
+                       return -ENOIOCTLCMD;
+               return sk->sk_prot->ioctl(sk, cmd, arg);
+       }
+}
+
+static const struct proto_ops ieee802154_raw_ops = {
+       .family            = PF_IEEE802154,
+       .owner             = THIS_MODULE,
+       .release           = ieee802154_sock_release,
+       .bind              = ieee802154_sock_bind,
+       .connect           = ieee802154_sock_connect,
+       .socketpair        = sock_no_socketpair,
+       .accept            = sock_no_accept,
+       .getname           = sock_no_getname,
+       .poll              = datagram_poll,
+       .ioctl             = ieee802154_sock_ioctl,
+       .listen            = sock_no_listen,
+       .shutdown          = sock_no_shutdown,
+       .setsockopt        = sock_common_setsockopt,
+       .getsockopt        = sock_common_getsockopt,
+       .sendmsg           = ieee802154_sock_sendmsg,
+       .recvmsg           = sock_common_recvmsg,
+       .mmap              = sock_no_mmap,
+       .sendpage          = sock_no_sendpage,
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_sock_common_setsockopt,
+       .compat_getsockopt = compat_sock_common_getsockopt,
+#endif
+};
+
+static const struct proto_ops ieee802154_dgram_ops = {
+       .family            = PF_IEEE802154,
+       .owner             = THIS_MODULE,
+       .release           = ieee802154_sock_release,
+       .bind              = ieee802154_sock_bind,
+       .connect           = ieee802154_sock_connect,
+       .socketpair        = sock_no_socketpair,
+       .accept            = sock_no_accept,
+       .getname           = sock_no_getname,
+       .poll              = datagram_poll,
+       .ioctl             = ieee802154_sock_ioctl,
+       .listen            = sock_no_listen,
+       .shutdown          = sock_no_shutdown,
+       .setsockopt        = sock_common_setsockopt,
+       .getsockopt        = sock_common_getsockopt,
+       .sendmsg           = ieee802154_sock_sendmsg,
+       .recvmsg           = sock_common_recvmsg,
+       .mmap              = sock_no_mmap,
+       .sendpage          = sock_no_sendpage,
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_sock_common_setsockopt,
+       .compat_getsockopt = compat_sock_common_getsockopt,
+#endif
+};
+
+
+/*
+ * Create a socket. Initialise the socket, blank the addresses
+ * set the state.
+ */
+static int ieee802154_create(struct net *net, struct socket *sock,
+               int protocol)
+{
+       struct sock *sk;
+       int rc;
+       struct proto *proto;
+       const struct proto_ops *ops;
+
+       if (net != &init_net)
+               return -EAFNOSUPPORT;
+
+       switch (sock->type) {
+       case SOCK_RAW:
+               proto = &ieee802154_raw_prot;
+               ops = &ieee802154_raw_ops;
+               break;
+       case SOCK_DGRAM:
+               proto = &ieee802154_dgram_prot;
+               ops = &ieee802154_dgram_ops;
+               break;
+       default:
+               rc = -ESOCKTNOSUPPORT;
+               goto out;
+       }
+
+       rc = -ENOMEM;
+       sk = sk_alloc(net, PF_IEEE802154, GFP_KERNEL, proto);
+       if (!sk)
+               goto out;
+       rc = 0;
+
+       sock->ops = ops;
+
+       sock_init_data(sock, sk);
+       /* FIXME: sk->sk_destruct */
+       sk->sk_family = PF_IEEE802154;
+
+       /* Checksums on by default */
+       sock_set_flag(sk, SOCK_ZAPPED);
+
+       if (sk->sk_prot->hash)
+               sk->sk_prot->hash(sk);
+
+       if (sk->sk_prot->init) {
+               rc = sk->sk_prot->init(sk);
+               if (rc)
+                       sk_common_release(sk);
+       }
+out:
+       return rc;
+}
+
+static struct net_proto_family ieee802154_family_ops = {
+       .family         = PF_IEEE802154,
+       .create         = ieee802154_create,
+       .owner          = THIS_MODULE,
+};
+
+static int ieee802154_rcv(struct sk_buff *skb, struct net_device *dev,
+       struct packet_type *pt, struct net_device *orig_dev)
+{
+       DBG_DUMP(skb->data, skb->len);
+       if (!netif_running(dev))
+               return -ENODEV;
+       pr_debug("got frame, type %d, dev %p\n", dev->type, dev);
+
+       if (!net_eq(dev_net(dev), &init_net))
+               goto drop;
+
+       ieee802154_raw_deliver(dev, skb);
+
+       if (dev->type != ARPHRD_IEEE802154)
+               goto drop;
+
+       if (skb->pkt_type != PACKET_OTHERHOST)
+               return ieee802154_dgram_deliver(dev, skb);
+
+drop:
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+
+static struct packet_type ieee802154_packet_type = {
+       .type = __constant_htons(ETH_P_IEEE802154),
+       .func = ieee802154_rcv,
+};
+
+static int __init af_ieee802154_init(void)
+{
+       int rc = -EINVAL;
+
+       rc = proto_register(&ieee802154_raw_prot, 1);
+       if (rc)
+               goto out;
+
+       rc = proto_register(&ieee802154_dgram_prot, 1);
+       if (rc)
+               goto err_dgram;
+
+       /* Tell SOCKET that we are alive */
+       rc = sock_register(&ieee802154_family_ops);
+       if (rc)
+               goto err_sock;
+       dev_add_pack(&ieee802154_packet_type);
+
+       rc = 0;
+       goto out;
+
+err_sock:
+       proto_unregister(&ieee802154_dgram_prot);
+err_dgram:
+       proto_unregister(&ieee802154_raw_prot);
+out:
+       return rc;
+}
+static void __exit af_ieee802154_remove(void)
+{
+       dev_remove_pack(&ieee802154_packet_type);
+       sock_unregister(PF_IEEE802154);
+       proto_unregister(&ieee802154_dgram_prot);
+       proto_unregister(&ieee802154_raw_prot);
+}
+
+module_init(af_ieee802154_init);
+module_exit(af_ieee802154_remove);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_NETPROTO(PF_IEEE802154);
diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c
new file mode 100644 (file)
index 0000000..1779677
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * ZigBee socket interface
+ *
+ * Copyright 2007, 2008 Siemens AG
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by:
+ * Sergey Lapin <slapin@ossfans.org>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+
+#include <linux/net.h>
+#include <linux/module.h>
+#include <linux/if_arp.h>
+#include <linux/list.h>
+#include <net/sock.h>
+#include <net/ieee802154/af_ieee802154.h>
+#include <net/ieee802154/mac_def.h>
+#include <net/ieee802154/netdevice.h>
+
+#include <asm/ioctls.h>
+
+#include "af802154.h"
+
+static HLIST_HEAD(dgram_head);
+static DEFINE_RWLOCK(dgram_lock);
+
+struct dgram_sock {
+       struct sock sk;
+
+       int bound;
+       struct ieee802154_addr src_addr;
+       struct ieee802154_addr dst_addr;
+};
+
+static inline struct dgram_sock *dgram_sk(const struct sock *sk)
+{
+       return container_of(sk, struct dgram_sock, sk);
+}
+
+
+static void dgram_hash(struct sock *sk)
+{
+       write_lock_bh(&dgram_lock);
+       sk_add_node(sk, &dgram_head);
+       sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
+       write_unlock_bh(&dgram_lock);
+}
+
+static void dgram_unhash(struct sock *sk)
+{
+       write_lock_bh(&dgram_lock);
+       if (sk_del_node_init(sk))
+               sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
+       write_unlock_bh(&dgram_lock);
+}
+
+static int dgram_init(struct sock *sk)
+{
+       struct dgram_sock *ro = dgram_sk(sk);
+
+       ro->dst_addr.addr_type = IEEE802154_ADDR_LONG;
+       ro->dst_addr.pan_id = 0xffff;
+       memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr));
+       return 0;
+}
+
+static void dgram_close(struct sock *sk, long timeout)
+{
+       sk_common_release(sk);
+}
+
+static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)
+{
+       struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
+       struct dgram_sock *ro = dgram_sk(sk);
+       int err = 0;
+       struct net_device *dev;
+
+       ro->bound = 0;
+
+       if (len < sizeof(*addr))
+               return -EINVAL;
+
+       if (addr->family != AF_IEEE802154)
+               return -EINVAL;
+
+       lock_sock(sk);
+
+       dev = ieee802154_get_dev(sock_net(sk), &addr->addr);
+       if (!dev) {
+               err = -ENODEV;
+               goto out;
+       }
+
+       if (dev->type != ARPHRD_IEEE802154) {
+               err = -ENODEV;
+               goto out_put;
+       }
+
+       memcpy(&ro->src_addr, &addr->addr, sizeof(struct ieee802154_addr));
+
+       ro->bound = 1;
+out_put:
+       dev_put(dev);
+out:
+       release_sock(sk);
+
+       return err;
+}
+
+static int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case SIOCOUTQ:
+       {
+               int amount = atomic_read(&sk->sk_wmem_alloc);
+               return put_user(amount, (int __user *)arg);
+       }
+
+       case SIOCINQ:
+       {
+               struct sk_buff *skb;
+               unsigned long amount;
+
+               amount = 0;
+               spin_lock_bh(&sk->sk_receive_queue.lock);
+               skb = skb_peek(&sk->sk_receive_queue);
+               if (skb != NULL) {
+                       /*
+                        * We will only return the amount
+                        * of this packet since that is all
+                        * that will be read.
+                        */
+                       /* FIXME: parse the header for more correct value */
+                       amount = skb->len - (3+8+8);
+               }
+               spin_unlock_bh(&sk->sk_receive_queue.lock);
+               return put_user(amount, (int __user *)arg);
+       }
+
+       }
+       return -ENOIOCTLCMD;
+}
+
+/* FIXME: autobind */
+static int dgram_connect(struct sock *sk, struct sockaddr *uaddr,
+                       int len)
+{
+       struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
+       struct dgram_sock *ro = dgram_sk(sk);
+       int err = 0;
+
+       if (len < sizeof(*addr))
+               return -EINVAL;
+
+       if (addr->family != AF_IEEE802154)
+               return -EINVAL;
+
+       lock_sock(sk);
+
+       if (!ro->bound) {
+               err = -ENETUNREACH;
+               goto out;
+       }
+
+       memcpy(&ro->dst_addr, &addr->addr, sizeof(struct ieee802154_addr));
+
+out:
+       release_sock(sk);
+       return err;
+}
+
+static int dgram_disconnect(struct sock *sk, int flags)
+{
+       struct dgram_sock *ro = dgram_sk(sk);
+
+       lock_sock(sk);
+
+       ro->dst_addr.addr_type = IEEE802154_ADDR_LONG;
+       memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr));
+
+       release_sock(sk);
+
+       return 0;
+}
+
+static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk,
+               struct msghdr *msg, size_t size)
+{
+       struct net_device *dev;
+       unsigned mtu;
+       struct sk_buff *skb;
+       struct dgram_sock *ro = dgram_sk(sk);
+       int err;
+
+       if (msg->msg_flags & MSG_OOB) {
+               pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags);
+               return -EOPNOTSUPP;
+       }
+
+       if (!ro->bound)
+               dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154);
+       else
+               dev = ieee802154_get_dev(sock_net(sk), &ro->src_addr);
+
+       if (!dev) {
+               pr_debug("no dev\n");
+               err = -ENXIO;
+               goto out;
+       }
+       mtu = dev->mtu;
+       pr_debug("name = %s, mtu = %u\n", dev->name, mtu);
+
+       skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + size,
+                       msg->msg_flags & MSG_DONTWAIT,
+                       &err);
+       if (!skb)
+               goto out_dev;
+
+       skb_reserve(skb, LL_RESERVED_SPACE(dev));
+
+       skb_reset_network_header(skb);
+
+       mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA | MAC_CB_FLAG_ACKREQ;
+       mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
+       err = dev_hard_header(skb, dev, ETH_P_IEEE802154, &ro->dst_addr,
+                       ro->bound ? &ro->src_addr : NULL, size);
+       if (err < 0)
+               goto out_skb;
+
+       skb_reset_mac_header(skb);
+
+       err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
+       if (err < 0)
+               goto out_skb;
+
+       if (size > mtu) {
+               pr_debug("size = %Zu, mtu = %u\n", size, mtu);
+               err = -EINVAL;
+               goto out_skb;
+       }
+
+       skb->dev = dev;
+       skb->sk  = sk;
+       skb->protocol = htons(ETH_P_IEEE802154);
+
+       dev_put(dev);
+
+       err = dev_queue_xmit(skb);
+       if (err > 0)
+               err = net_xmit_errno(err);
+
+       return err ?: size;
+
+out_skb:
+       kfree_skb(skb);
+out_dev:
+       dev_put(dev);
+out:
+       return err;
+}
+
+static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk,
+               struct msghdr *msg, size_t len, int noblock, int flags,
+               int *addr_len)
+{
+       size_t copied = 0;
+       int err = -EOPNOTSUPP;
+       struct sk_buff *skb;
+
+       skb = skb_recv_datagram(sk, flags, noblock, &err);
+       if (!skb)
+               goto out;
+
+       copied = skb->len;
+       if (len < copied) {
+               msg->msg_flags |= MSG_TRUNC;
+               copied = len;
+       }
+
+       /* FIXME: skip headers if necessary ?! */
+       err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+       if (err)
+               goto done;
+
+       sock_recv_timestamp(msg, sk, skb);
+
+       if (flags & MSG_TRUNC)
+               copied = skb->len;
+done:
+       skb_free_datagram(sk, skb);
+out:
+       if (err)
+               return err;
+       return copied;
+}
+
+static int dgram_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+       if (sock_queue_rcv_skb(sk, skb) < 0) {
+               atomic_inc(&sk->sk_drops);
+               kfree_skb(skb);
+               return NET_RX_DROP;
+       }
+
+       return NET_RX_SUCCESS;
+}
+
+static inline int ieee802154_match_sock(u8 *hw_addr, u16 pan_id,
+               u16 short_addr, struct dgram_sock *ro)
+{
+       if (!ro->bound)
+               return 1;
+
+       if (ro->src_addr.addr_type == IEEE802154_ADDR_LONG &&
+           !memcmp(ro->src_addr.hwaddr, hw_addr, IEEE802154_ADDR_LEN))
+               return 1;
+
+       if (ro->src_addr.addr_type == IEEE802154_ADDR_SHORT &&
+                    pan_id == ro->src_addr.pan_id &&
+                    short_addr == ro->src_addr.short_addr)
+               return 1;
+
+       return 0;
+}
+
+int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb)
+{
+       struct sock *sk, *prev = NULL;
+       struct hlist_node *node;
+       int ret = NET_RX_SUCCESS;
+       u16 pan_id, short_addr;
+
+       /* Data frame processing */
+       BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+       pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
+       short_addr = ieee802154_mlme_ops(dev)->get_short_addr(dev);
+
+       read_lock(&dgram_lock);
+       sk_for_each(sk, node, &dgram_head) {
+               if (ieee802154_match_sock(dev->dev_addr, pan_id, short_addr,
+                                       dgram_sk(sk))) {
+                       if (prev) {
+                               struct sk_buff *clone;
+                               clone = skb_clone(skb, GFP_ATOMIC);
+                               if (clone)
+                                       dgram_rcv_skb(prev, clone);
+                       }
+
+                       prev = sk;
+               }
+       }
+
+       if (prev)
+               dgram_rcv_skb(prev, skb);
+       else {
+               kfree_skb(skb);
+               ret = NET_RX_DROP;
+       }
+       read_unlock(&dgram_lock);
+
+       return ret;
+}
+
+struct proto ieee802154_dgram_prot = {
+       .name           = "IEEE-802.15.4-MAC",
+       .owner          = THIS_MODULE,
+       .obj_size       = sizeof(struct dgram_sock),
+       .init           = dgram_init,
+       .close          = dgram_close,
+       .bind           = dgram_bind,
+       .sendmsg        = dgram_sendmsg,
+       .recvmsg        = dgram_recvmsg,
+       .hash           = dgram_hash,
+       .unhash         = dgram_unhash,
+       .connect        = dgram_connect,
+       .disconnect     = dgram_disconnect,
+       .ioctl          = dgram_ioctl,
+};
+
diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c
new file mode 100644 (file)
index 0000000..105ad10
--- /dev/null
@@ -0,0 +1,523 @@
+/*
+ * Netlink inteface for IEEE 802.15.4 stack
+ *
+ * Copyright 2007, 2008 Siemens AG
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by:
+ * Sergey Lapin <slapin@ossfans.org>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+#include <net/netlink.h>
+#include <net/genetlink.h>
+#include <linux/nl802154.h>
+#include <net/ieee802154/af_ieee802154.h>
+#include <net/ieee802154/nl802154.h>
+#include <net/ieee802154/netdevice.h>
+
+static unsigned int ieee802154_seq_num;
+
+static struct genl_family ieee802154_coordinator_family = {
+       .id             = GENL_ID_GENERATE,
+       .hdrsize        = 0,
+       .name           = IEEE802154_NL_NAME,
+       .version        = 1,
+       .maxattr        = IEEE802154_ATTR_MAX,
+};
+
+static struct genl_multicast_group ieee802154_coord_mcgrp = {
+       .name           = IEEE802154_MCAST_COORD_NAME,
+};
+
+static struct genl_multicast_group ieee802154_beacon_mcgrp = {
+       .name           = IEEE802154_MCAST_BEACON_NAME,
+};
+
+/* Requests to userspace */
+static struct sk_buff *ieee802154_nl_create(int flags, u8 req)
+{
+       void *hdr;
+       struct sk_buff *msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
+
+       if (!msg)
+               return NULL;
+
+       hdr = genlmsg_put(msg, 0, ieee802154_seq_num++,
+                       &ieee802154_coordinator_family, flags, req);
+       if (!hdr) {
+               nlmsg_free(msg);
+               return NULL;
+       }
+
+       return msg;
+}
+
+static int ieee802154_nl_finish(struct sk_buff *msg)
+{
+       /* XXX: nlh is right at the start of msg */
+       void *hdr = genlmsg_data(NLMSG_DATA(msg->data));
+
+       if (!genlmsg_end(msg, hdr))
+               goto out;
+
+       return genlmsg_multicast(msg, 0, ieee802154_coord_mcgrp.id,
+                       GFP_ATOMIC);
+out:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+
+int ieee802154_nl_assoc_indic(struct net_device *dev,
+               struct ieee802154_addr *addr, u8 cap)
+{
+       struct sk_buff *msg;
+
+       pr_debug("%s\n", __func__);
+
+       if (addr->addr_type != IEEE802154_ADDR_LONG) {
+               pr_err("%s: received non-long source address!\n", __func__);
+               return -EINVAL;
+       }
+
+       msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_INDIC);
+       if (!msg)
+               return -ENOBUFS;
+
+       NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
+       NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
+       NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
+                       dev->dev_addr);
+
+       NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
+                       addr->hwaddr);
+
+       NLA_PUT_U8(msg, IEEE802154_ATTR_CAPABILITY, cap);
+
+       return ieee802154_nl_finish(msg);
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+EXPORT_SYMBOL(ieee802154_nl_assoc_indic);
+
+int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr,
+               u8 status)
+{
+       struct sk_buff *msg;
+
+       pr_debug("%s\n", __func__);
+
+       msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_CONF);
+       if (!msg)
+               return -ENOBUFS;
+
+       NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
+       NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
+       NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
+                       dev->dev_addr);
+
+       NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr);
+       NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
+
+       return ieee802154_nl_finish(msg);
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+EXPORT_SYMBOL(ieee802154_nl_assoc_confirm);
+
+int ieee802154_nl_disassoc_indic(struct net_device *dev,
+               struct ieee802154_addr *addr, u8 reason)
+{
+       struct sk_buff *msg;
+
+       pr_debug("%s\n", __func__);
+
+       msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_INDIC);
+       if (!msg)
+               return -ENOBUFS;
+
+       NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
+       NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
+       NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
+                       dev->dev_addr);
+
+       if (addr->addr_type == IEEE802154_ADDR_LONG)
+               NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
+                               addr->hwaddr);
+       else
+               NLA_PUT_U16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR,
+                               addr->short_addr);
+
+       NLA_PUT_U8(msg, IEEE802154_ATTR_REASON, reason);
+
+       return ieee802154_nl_finish(msg);
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+EXPORT_SYMBOL(ieee802154_nl_disassoc_indic);
+
+int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status)
+{
+       struct sk_buff *msg;
+
+       pr_debug("%s\n", __func__);
+
+       msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_CONF);
+       if (!msg)
+               return -ENOBUFS;
+
+       NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
+       NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
+       NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
+                       dev->dev_addr);
+
+       NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
+
+       return ieee802154_nl_finish(msg);
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm);
+
+int ieee802154_nl_beacon_indic(struct net_device *dev,
+               u16 panid, u16 coord_addr)
+{
+       struct sk_buff *msg;
+
+       pr_debug("%s\n", __func__);
+
+       msg = ieee802154_nl_create(0, IEEE802154_BEACON_NOTIFY_INDIC);
+       if (!msg)
+               return -ENOBUFS;
+
+       NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
+       NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
+       NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
+                       dev->dev_addr);
+       NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr);
+       NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid);
+
+       return ieee802154_nl_finish(msg);
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+EXPORT_SYMBOL(ieee802154_nl_beacon_indic);
+
+int ieee802154_nl_scan_confirm(struct net_device *dev,
+               u8 status, u8 scan_type, u32 unscanned,
+               u8 *edl/* , struct list_head *pan_desc_list */)
+{
+       struct sk_buff *msg;
+
+       pr_debug("%s\n", __func__);
+
+       msg = ieee802154_nl_create(0, IEEE802154_SCAN_CONF);
+       if (!msg)
+               return -ENOBUFS;
+
+       NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
+       NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
+       NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
+                       dev->dev_addr);
+
+       NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
+       NLA_PUT_U8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type);
+       NLA_PUT_U32(msg, IEEE802154_ATTR_CHANNELS, unscanned);
+
+       if (edl)
+               NLA_PUT(msg, IEEE802154_ATTR_ED_LIST, 27, edl);
+
+       return ieee802154_nl_finish(msg);
+
+nla_put_failure:
+       nlmsg_free(msg);
+       return -ENOBUFS;
+}
+EXPORT_SYMBOL(ieee802154_nl_scan_confirm);
+
+/* Requests from userspace */
+static struct net_device *ieee802154_nl_get_dev(struct genl_info *info)
+{
+       struct net_device *dev;
+
+       if (info->attrs[IEEE802154_ATTR_DEV_NAME]) {
+               char name[IFNAMSIZ + 1];
+               nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME],
+                               sizeof(name));
+               dev = dev_get_by_name(&init_net, name);
+       } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX])
+               dev = dev_get_by_index(&init_net,
+                               nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX]));
+       else
+               return NULL;
+
+       if (dev->type != ARPHRD_IEEE802154) {
+               dev_put(dev);
+               return NULL;
+       }
+
+       return dev;
+}
+
+static int ieee802154_associate_req(struct sk_buff *skb,
+               struct genl_info *info)
+{
+       struct net_device *dev;
+       struct ieee802154_addr addr;
+       int ret = -EINVAL;
+
+       if (!info->attrs[IEEE802154_ATTR_CHANNEL] ||
+           !info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
+           (!info->attrs[IEEE802154_ATTR_COORD_HW_ADDR] &&
+               !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]) ||
+           !info->attrs[IEEE802154_ATTR_CAPABILITY])
+               return -EINVAL;
+
+       dev = ieee802154_nl_get_dev(info);
+       if (!dev)
+               return -ENODEV;
+
+       if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) {
+               addr.addr_type = IEEE802154_ADDR_LONG;
+               nla_memcpy(addr.hwaddr,
+                               info->attrs[IEEE802154_ATTR_COORD_HW_ADDR],
+                               IEEE802154_ADDR_LEN);
+       } else {
+               addr.addr_type = IEEE802154_ADDR_SHORT;
+               addr.short_addr = nla_get_u16(
+                               info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
+       }
+       addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
+
+       ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr,
+                       nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]),
+                       nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY]));
+
+       dev_put(dev);
+       return ret;
+}
+
+static int ieee802154_associate_resp(struct sk_buff *skb,
+               struct genl_info *info)
+{
+       struct net_device *dev;
+       struct ieee802154_addr addr;
+       int ret = -EINVAL;
+
+       if (!info->attrs[IEEE802154_ATTR_STATUS] ||
+           !info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] ||
+           !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR])
+               return -EINVAL;
+
+       dev = ieee802154_nl_get_dev(info);
+       if (!dev)
+               return -ENODEV;
+
+       addr.addr_type = IEEE802154_ADDR_LONG;
+       nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
+                       IEEE802154_ADDR_LEN);
+       addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
+
+
+       ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr,
+               nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]),
+               nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS]));
+
+       dev_put(dev);
+       return ret;
+}
+
+static int ieee802154_disassociate_req(struct sk_buff *skb,
+               struct genl_info *info)
+{
+       struct net_device *dev;
+       struct ieee802154_addr addr;
+       int ret = -EINVAL;
+
+       if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] &&
+               !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) ||
+           !info->attrs[IEEE802154_ATTR_REASON])
+               return -EINVAL;
+
+       dev = ieee802154_nl_get_dev(info);
+       if (!dev)
+               return -ENODEV;
+
+       if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) {
+               addr.addr_type = IEEE802154_ADDR_LONG;
+               nla_memcpy(addr.hwaddr,
+                               info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
+                               IEEE802154_ADDR_LEN);
+       } else {
+               addr.addr_type = IEEE802154_ADDR_SHORT;
+               addr.short_addr = nla_get_u16(
+                               info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]);
+       }
+       addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
+
+       ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr,
+                       nla_get_u8(info->attrs[IEEE802154_ATTR_REASON]));
+
+       dev_put(dev);
+       return ret;
+}
+
+/*
+ * PANid, channel, beacon_order = 15, superframe_order = 15,
+ * PAN_coordinator, battery_life_extension = 0,
+ * coord_realignment = 0, security_enable = 0
+*/
+static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
+{
+       struct net_device *dev;
+       struct ieee802154_addr addr;
+
+       u8 channel, bcn_ord, sf_ord;
+       int pan_coord, blx, coord_realign;
+       int ret;
+
+       if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
+           !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR] ||
+           !info->attrs[IEEE802154_ATTR_CHANNEL] ||
+           !info->attrs[IEEE802154_ATTR_BCN_ORD] ||
+           !info->attrs[IEEE802154_ATTR_SF_ORD] ||
+           !info->attrs[IEEE802154_ATTR_PAN_COORD] ||
+           !info->attrs[IEEE802154_ATTR_BAT_EXT] ||
+           !info->attrs[IEEE802154_ATTR_COORD_REALIGN]
+        )
+               return -EINVAL;
+
+       dev = ieee802154_nl_get_dev(info);
+       if (!dev)
+               return -ENODEV;
+
+       addr.addr_type = IEEE802154_ADDR_SHORT;
+       addr.short_addr = nla_get_u16(
+                       info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
+       addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
+
+       channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]);
+       bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]);
+       sf_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_SF_ORD]);
+       pan_coord = nla_get_u8(info->attrs[IEEE802154_ATTR_PAN_COORD]);
+       blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]);
+       coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]);
+
+       ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel,
+               bcn_ord, sf_ord, pan_coord, blx, coord_realign);
+
+       dev_put(dev);
+       return ret;
+}
+
+static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
+{
+       struct net_device *dev;
+       int ret;
+       u8 type;
+       u32 channels;
+       u8 duration;
+
+       if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] ||
+           !info->attrs[IEEE802154_ATTR_CHANNELS] ||
+           !info->attrs[IEEE802154_ATTR_DURATION])
+               return -EINVAL;
+
+       dev = ieee802154_nl_get_dev(info);
+       if (!dev)
+               return -ENODEV;
+
+       type = nla_get_u8(info->attrs[IEEE802154_ATTR_SCAN_TYPE]);
+       channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]);
+       duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]);
+
+       ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels,
+                       duration);
+
+       dev_put(dev);
+       return ret;
+}
+
+#define IEEE802154_OP(_cmd, _func)                     \
+       {                                               \
+               .cmd    = _cmd,                         \
+               .policy = ieee802154_policy,            \
+               .doit   = _func,                        \
+               .dumpit = NULL,                         \
+               .flags  = GENL_ADMIN_PERM,              \
+       }
+
+static struct genl_ops ieee802154_coordinator_ops[] = {
+       IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req),
+       IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp),
+       IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req),
+       IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req),
+       IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req),
+};
+
+static int __init ieee802154_nl_init(void)
+{
+       int rc;
+       int i;
+
+       rc = genl_register_family(&ieee802154_coordinator_family);
+       if (rc)
+               goto fail;
+
+       rc = genl_register_mc_group(&ieee802154_coordinator_family,
+                       &ieee802154_coord_mcgrp);
+       if (rc)
+               goto fail;
+
+       rc = genl_register_mc_group(&ieee802154_coordinator_family,
+                       &ieee802154_beacon_mcgrp);
+       if (rc)
+               goto fail;
+
+
+       for (i = 0; i < ARRAY_SIZE(ieee802154_coordinator_ops); i++) {
+               rc = genl_register_ops(&ieee802154_coordinator_family,
+                               &ieee802154_coordinator_ops[i]);
+               if (rc)
+                       goto fail;
+       }
+
+       return 0;
+
+fail:
+       genl_unregister_family(&ieee802154_coordinator_family);
+       return rc;
+}
+module_init(ieee802154_nl_init);
+
+static void __exit ieee802154_nl_exit(void)
+{
+       genl_unregister_family(&ieee802154_coordinator_family);
+}
+module_exit(ieee802154_nl_exit);
+
diff --git a/net/ieee802154/nl_policy.c b/net/ieee802154/nl_policy.c
new file mode 100644 (file)
index 0000000..c7d71d1
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * nl802154.h
+ *
+ * Copyright (C) 2007, 2008 Siemens AG
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <net/netlink.h>
+#include <linux/nl802154.h>
+
+#define NLA_HW_ADDR NLA_U64
+
+struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = {
+       [IEEE802154_ATTR_DEV_NAME] = { .type = NLA_STRING, },
+       [IEEE802154_ATTR_DEV_INDEX] = { .type = NLA_U32, },
+
+       [IEEE802154_ATTR_STATUS] = { .type = NLA_U8, },
+       [IEEE802154_ATTR_SHORT_ADDR] = { .type = NLA_U16, },
+       [IEEE802154_ATTR_HW_ADDR] = { .type = NLA_HW_ADDR, },
+       [IEEE802154_ATTR_PAN_ID] = { .type = NLA_U16, },
+       [IEEE802154_ATTR_CHANNEL] = { .type = NLA_U8, },
+       [IEEE802154_ATTR_COORD_SHORT_ADDR] = { .type = NLA_U16, },
+       [IEEE802154_ATTR_COORD_HW_ADDR] = { .type = NLA_HW_ADDR, },
+       [IEEE802154_ATTR_COORD_PAN_ID] = { .type = NLA_U16, },
+       [IEEE802154_ATTR_SRC_SHORT_ADDR] = { .type = NLA_U16, },
+       [IEEE802154_ATTR_SRC_HW_ADDR] = { .type = NLA_HW_ADDR, },
+       [IEEE802154_ATTR_SRC_PAN_ID] = { .type = NLA_U16, },
+       [IEEE802154_ATTR_DEST_SHORT_ADDR] = { .type = NLA_U16, },
+       [IEEE802154_ATTR_DEST_HW_ADDR] = { .type = NLA_HW_ADDR, },
+       [IEEE802154_ATTR_DEST_PAN_ID] = { .type = NLA_U16, },
+
+       [IEEE802154_ATTR_CAPABILITY] = { .type = NLA_U8, },
+       [IEEE802154_ATTR_REASON] = { .type = NLA_U8, },
+       [IEEE802154_ATTR_SCAN_TYPE] = { .type = NLA_U8, },
+       [IEEE802154_ATTR_CHANNELS] = { .type = NLA_U32, },
+       [IEEE802154_ATTR_DURATION] = { .type = NLA_U8, },
+       [IEEE802154_ATTR_ED_LIST] = { .len = 27 },
+};
diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c
new file mode 100644 (file)
index 0000000..fca44d5
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Raw IEEE 802.15.4 sockets
+ *
+ * Copyright 2007, 2008 Siemens AG
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by:
+ * Sergey Lapin <slapin@ossfans.org>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ */
+
+#include <linux/net.h>
+#include <linux/module.h>
+#include <linux/if_arp.h>
+#include <linux/list.h>
+#include <net/sock.h>
+#include <net/ieee802154/af_ieee802154.h>
+
+#include "af802154.h"
+
+static HLIST_HEAD(raw_head);
+static DEFINE_RWLOCK(raw_lock);
+
+static void raw_hash(struct sock *sk)
+{
+       write_lock_bh(&raw_lock);
+       sk_add_node(sk, &raw_head);
+       sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
+       write_unlock_bh(&raw_lock);
+}
+
+static void raw_unhash(struct sock *sk)
+{
+       write_lock_bh(&raw_lock);
+       if (sk_del_node_init(sk))
+               sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
+       write_unlock_bh(&raw_lock);
+}
+
+static void raw_close(struct sock *sk, long timeout)
+{
+       sk_common_release(sk);
+}
+
+static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int len)
+{
+       struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
+       int err = 0;
+       struct net_device *dev = NULL;
+
+       if (len < sizeof(*addr))
+               return -EINVAL;
+
+       if (addr->family != AF_IEEE802154)
+               return -EINVAL;
+
+       lock_sock(sk);
+
+       dev = ieee802154_get_dev(sock_net(sk), &addr->addr);
+       if (!dev) {
+               err = -ENODEV;
+               goto out;
+       }
+
+       if (dev->type != ARPHRD_IEEE802154_PHY &&
+           dev->type != ARPHRD_IEEE802154) {
+               err = -ENODEV;
+               goto out_put;
+       }
+
+       sk->sk_bound_dev_if = dev->ifindex;
+       sk_dst_reset(sk);
+
+out_put:
+       dev_put(dev);
+out:
+       release_sock(sk);
+
+       return err;
+}
+
+static int raw_connect(struct sock *sk, struct sockaddr *uaddr,
+                       int addr_len)
+{
+       return -ENOTSUPP;
+}
+
+static int raw_disconnect(struct sock *sk, int flags)
+{
+       return 0;
+}
+
+static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+                      size_t size)
+{
+       struct net_device *dev;
+       unsigned mtu;
+       struct sk_buff *skb;
+       int err;
+
+       if (msg->msg_flags & MSG_OOB) {
+               pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags);
+               return -EOPNOTSUPP;
+       }
+
+       lock_sock(sk);
+       if (!sk->sk_bound_dev_if)
+               dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154);
+       else
+               dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if);
+       release_sock(sk);
+
+       if (!dev) {
+               pr_debug("no dev\n");
+               err = -ENXIO;
+               goto out;
+       }
+
+       mtu = dev->mtu;
+       pr_debug("name = %s, mtu = %u\n", dev->name, mtu);
+
+       if (size > mtu) {
+               pr_debug("size = %Zu, mtu = %u\n", size, mtu);
+               err = -EINVAL;
+               goto out_dev;
+       }
+
+       skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + size,
+                       msg->msg_flags & MSG_DONTWAIT, &err);
+       if (!skb)
+               goto out_dev;
+
+       skb_reserve(skb, LL_RESERVED_SPACE(dev));
+
+       skb_reset_mac_header(skb);
+       skb_reset_network_header(skb);
+
+       err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
+       if (err < 0)
+               goto out_skb;
+
+       skb->dev = dev;
+       skb->sk  = sk;
+       skb->protocol = htons(ETH_P_IEEE802154);
+
+       dev_put(dev);
+
+       err = dev_queue_xmit(skb);
+       if (err > 0)
+               err = net_xmit_errno(err);
+
+       return err ?: size;
+
+out_skb:
+       kfree_skb(skb);
+out_dev:
+       dev_put(dev);
+out:
+       return err;
+}
+
+static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+                      size_t len, int noblock, int flags, int *addr_len)
+{
+       size_t copied = 0;
+       int err = -EOPNOTSUPP;
+       struct sk_buff *skb;
+
+       skb = skb_recv_datagram(sk, flags, noblock, &err);
+       if (!skb)
+               goto out;
+
+       copied = skb->len;
+       if (len < copied) {
+               msg->msg_flags |= MSG_TRUNC;
+               copied = len;
+       }
+
+       err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+       if (err)
+               goto done;
+
+       sock_recv_timestamp(msg, sk, skb);
+
+       if (flags & MSG_TRUNC)
+               copied = skb->len;
+done:
+       skb_free_datagram(sk, skb);
+out:
+       if (err)
+               return err;
+       return copied;
+}
+
+static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+       if (sock_queue_rcv_skb(sk, skb) < 0) {
+               atomic_inc(&sk->sk_drops);
+               kfree_skb(skb);
+               return NET_RX_DROP;
+       }
+
+       return NET_RX_SUCCESS;
+}
+
+
+void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb)
+{
+       struct sock *sk;
+       struct hlist_node *node;
+
+       read_lock(&raw_lock);
+       sk_for_each(sk, node, &raw_head) {
+               bh_lock_sock(sk);
+               if (!sk->sk_bound_dev_if ||
+                   sk->sk_bound_dev_if == dev->ifindex) {
+
+                       struct sk_buff *clone;
+
+                       clone = skb_clone(skb, GFP_ATOMIC);
+                       if (clone)
+                               raw_rcv_skb(sk, clone);
+               }
+               bh_unlock_sock(sk);
+       }
+       read_unlock(&raw_lock);
+}
+
+struct proto ieee802154_raw_prot = {
+       .name           = "IEEE-802.15.4-RAW",
+       .owner          = THIS_MODULE,
+       .obj_size       = sizeof(struct sock),
+       .close          = raw_close,
+       .bind           = raw_bind,
+       .sendmsg        = raw_sendmsg,
+       .recvmsg        = raw_recvmsg,
+       .hash           = raw_hash,
+       .unhash         = raw_unhash,
+       .connect        = raw_connect,
+       .disconnect     = raw_disconnect,
+};
+
index 5abee4c..566ea6c 100644 (file)
 #include <linux/mroute.h>
 #endif
 
-extern void ip_mc_drop_socket(struct sock *sk);
 
 /* The inetsw table contains everything that inet_create needs to
  * build a new socket.
@@ -375,6 +374,7 @@ lookup_protocol:
        inet->uc_ttl    = -1;
        inet->mc_loop   = 1;
        inet->mc_ttl    = 1;
+       inet->mc_all    = 1;
        inet->mc_index  = 0;
        inet->mc_list   = NULL;
 
index f11931c..8a3881e 100644 (file)
@@ -468,13 +468,13 @@ int arp_find(unsigned char *haddr, struct sk_buff *skb)
        __be32 paddr;
        struct neighbour *n;
 
-       if (!skb->dst) {
+       if (!skb_dst(skb)) {
                printk(KERN_DEBUG "arp_find is called with dst==NULL\n");
                kfree_skb(skb);
                return 1;
        }
 
-       paddr = skb->rtable->rt_gateway;
+       paddr = skb_rtable(skb)->rt_gateway;
 
        if (arp_set_predefined(inet_addr_type(dev_net(dev), paddr), haddr, paddr, dev))
                return 0;
@@ -817,7 +817,7 @@ static int arp_process(struct sk_buff *skb)
        if (arp->ar_op == htons(ARPOP_REQUEST) &&
            ip_route_input(skb, tip, sip, 0, dev) == 0) {
 
-               rt = skb->rtable;
+               rt = skb_rtable(skb);
                addr_type = rt->rt_type;
 
                if (addr_type == RTN_LOCAL) {
index 3f50807..97c410e 100644 (file)
@@ -356,7 +356,7 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param,
 static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
 {
        struct ipcm_cookie ipc;
-       struct rtable *rt = skb->rtable;
+       struct rtable *rt = skb_rtable(skb);
        struct net *net = dev_net(rt->u.dst.dev);
        struct sock *sk;
        struct inet_sock *inet;
@@ -416,7 +416,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
        struct iphdr *iph;
        int room;
        struct icmp_bxm icmp_param;
-       struct rtable *rt = skb_in->rtable;
+       struct rtable *rt = skb_rtable(skb_in);
        struct ipcm_cookie ipc;
        __be32 saddr;
        u8  tos;
@@ -591,13 +591,13 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
                                goto relookup_failed;
 
                        /* Ugh! */
-                       odst = skb_in->dst;
+                       odst = skb_dst(skb_in);
                        err = ip_route_input(skb_in, fl.fl4_dst, fl.fl4_src,
                                             RT_TOS(tos), rt2->u.dst.dev);
 
                        dst_release(&rt2->u.dst);
-                       rt2 = skb_in->rtable;
-                       skb_in->dst = odst;
+                       rt2 = skb_rtable(skb_in);
+                       skb_dst_set(skb_in, odst);
                }
 
                if (err)
@@ -659,7 +659,7 @@ static void icmp_unreach(struct sk_buff *skb)
        u32 info = 0;
        struct net *net;
 
-       net = dev_net(skb->dst->dev);
+       net = dev_net(skb_dst(skb)->dev);
 
        /*
         *      Incomplete header ?
@@ -822,7 +822,7 @@ static void icmp_echo(struct sk_buff *skb)
 {
        struct net *net;
 
-       net = dev_net(skb->dst->dev);
+       net = dev_net(skb_dst(skb)->dev);
        if (!net->ipv4.sysctl_icmp_echo_ignore_all) {
                struct icmp_bxm icmp_param;
 
@@ -873,7 +873,7 @@ static void icmp_timestamp(struct sk_buff *skb)
 out:
        return;
 out_err:
-       ICMP_INC_STATS_BH(dev_net(skb->dst->dev), ICMP_MIB_INERRORS);
+       ICMP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), ICMP_MIB_INERRORS);
        goto out;
 }
 
@@ -926,7 +926,7 @@ static void icmp_address(struct sk_buff *skb)
 
 static void icmp_address_reply(struct sk_buff *skb)
 {
-       struct rtable *rt = skb->rtable;
+       struct rtable *rt = skb_rtable(skb);
        struct net_device *dev = skb->dev;
        struct in_device *in_dev;
        struct in_ifaddr *ifa;
@@ -970,7 +970,7 @@ static void icmp_discard(struct sk_buff *skb)
 int icmp_rcv(struct sk_buff *skb)
 {
        struct icmphdr *icmph;
-       struct rtable *rt = skb->rtable;
+       struct rtable *rt = skb_rtable(skb);
        struct net *net = dev_net(rt->u.dst.dev);
 
        if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
index 9eb6219..01b4284 100644 (file)
@@ -311,7 +311,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
                return NULL;
        }
 
-       skb->dst = &rt->u.dst;
+       skb_dst_set(skb, &rt->u.dst);
        skb->dev = dev;
 
        skb_reserve(skb, LL_RESERVED_SPACE(dev));
@@ -659,7 +659,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
                return -1;
        }
 
-       skb->dst = &rt->u.dst;
+       skb_dst_set(skb, &rt->u.dst);
 
        skb_reserve(skb, LL_RESERVED_SPACE(dev));
 
@@ -948,7 +948,7 @@ int igmp_rcv(struct sk_buff *skb)
        case IGMPV2_HOST_MEMBERSHIP_REPORT:
        case IGMPV3_HOST_MEMBERSHIP_REPORT:
                /* Is it our report looped back? */
-               if (skb->rtable->fl.iif == 0)
+               if (skb_rtable(skb)->fl.iif == 0)
                        break;
                /* don't rely on MC router hearing unicast reports */
                if (skb->pkt_type == PACKET_MULTICAST ||
@@ -2196,7 +2196,7 @@ int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr, int dif)
                        break;
        }
        if (!pmc)
-               return 1;
+               return inet->mc_all;
        psl = pmc->sflist;
        if (!psl)
                return pmc->sfmode == MCAST_EXCLUDE;
index df3fe50..a2991bc 100644 (file)
@@ -42,7 +42,7 @@ static int ip_forward_finish(struct sk_buff *skb)
 {
        struct ip_options * opt = &(IPCB(skb)->opt);
 
-       IP_INC_STATS_BH(dev_net(skb->dst->dev), IPSTATS_MIB_OUTFORWDATAGRAMS);
+       IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTFORWDATAGRAMS);
 
        if (unlikely(opt->optlen))
                ip_forward_options(skb);
@@ -81,7 +81,7 @@ int ip_forward(struct sk_buff *skb)
        if (!xfrm4_route_forward(skb))
                goto drop;
 
-       rt = skb->rtable;
+       rt = skb_rtable(skb);
 
        if (opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
                goto sr_failed;
@@ -123,7 +123,7 @@ sr_failed:
 
 too_many_hops:
        /* Tell the sender its packet died... */
-       IP_INC_STATS_BH(dev_net(skb->dst->dev), IPSTATS_MIB_INHDRERRORS);
+       IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_INHDRERRORS);
        icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0);
 drop:
        kfree_skb(skb);
index 7985346..575f9bd 100644 (file)
@@ -507,7 +507,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
        /* If the first fragment is fragmented itself, we split
         * it to two chunks: the first with data and paged part
         * and the second, holding only fragments. */
-       if (skb_shinfo(head)->frag_list) {
+       if (skb_has_frags(head)) {
                struct sk_buff *clone;
                int i, plen = 0;
 
@@ -516,7 +516,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
                clone->next = head->next;
                head->next = clone;
                skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;
-               skb_shinfo(head)->frag_list = NULL;
+               skb_frag_list_init(head);
                for (i=0; i<skb_shinfo(head)->nr_frags; i++)
                        plen += skb_shinfo(head)->frags[i].size;
                clone->len = clone->data_len = head->data_len - plen;
@@ -573,7 +573,7 @@ int ip_defrag(struct sk_buff *skb, u32 user)
        struct ipq *qp;
        struct net *net;
 
-       net = skb->dev ? dev_net(skb->dev) : dev_net(skb->dst->dev);
+       net = skb->dev ? dev_net(skb->dev) : dev_net(skb_dst(skb)->dev);
        IP_INC_STATS_BH(net, IPSTATS_MIB_REASMREQDS);
 
        /* Start by cleaning up the memory. */
index e62510d..44e2a3d 100644 (file)
@@ -602,7 +602,7 @@ static int ipgre_rcv(struct sk_buff *skb)
 #ifdef CONFIG_NET_IPGRE_BROADCAST
                if (ipv4_is_multicast(iph->daddr)) {
                        /* Looped back packet, drop it! */
-                       if (skb->rtable->fl.iif == 0)
+                       if (skb_rtable(skb)->fl.iif == 0)
                                goto drop;
                        stats->multicast++;
                        skb->pkt_type = PACKET_BROADCAST;
@@ -643,8 +643,7 @@ static int ipgre_rcv(struct sk_buff *skb)
                stats->rx_packets++;
                stats->rx_bytes += len;
                skb->dev = tunnel->dev;
-               dst_release(skb->dst);
-               skb->dst = NULL;
+               skb_dst_drop(skb);
                nf_reset(skb);
 
                skb_reset_network_header(skb);
@@ -698,13 +697,13 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        if ((dst = tiph->daddr) == 0) {
                /* NBMA tunnel */
 
-               if (skb->dst == NULL) {
+               if (skb_dst(skb) == NULL) {
                        stats->tx_fifo_errors++;
                        goto tx_error;
                }
 
                if (skb->protocol == htons(ETH_P_IP)) {
-                       rt = skb->rtable;
+                       rt = skb_rtable(skb);
                        if ((dst = rt->rt_gateway) == 0)
                                goto tx_error_icmp;
                }
@@ -712,7 +711,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
                else if (skb->protocol == htons(ETH_P_IPV6)) {
                        struct in6_addr *addr6;
                        int addr_type;
-                       struct neighbour *neigh = skb->dst->neighbour;
+                       struct neighbour *neigh = skb_dst(skb)->neighbour;
 
                        if (neigh == NULL)
                                goto tx_error;
@@ -766,10 +765,10 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        if (df)
                mtu = dst_mtu(&rt->u.dst) - dev->hard_header_len - tunnel->hlen;
        else
-               mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu;
+               mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu;
 
-       if (skb->dst)
-               skb->dst->ops->update_pmtu(skb->dst, mtu);
+       if (skb_dst(skb))
+               skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
 
        if (skb->protocol == htons(ETH_P_IP)) {
                df |= (old_iph->frag_off&htons(IP_DF));
@@ -783,14 +782,14 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 #ifdef CONFIG_IPV6
        else if (skb->protocol == htons(ETH_P_IPV6)) {
-               struct rt6_info *rt6 = (struct rt6_info *)skb->dst;
+               struct rt6_info *rt6 = (struct rt6_info *)skb_dst(skb);
 
-               if (rt6 && mtu < dst_mtu(skb->dst) && mtu >= IPV6_MIN_MTU) {
+               if (rt6 && mtu < dst_mtu(skb_dst(skb)) && mtu >= IPV6_MIN_MTU) {
                        if ((tunnel->parms.iph.daddr &&
                             !ipv4_is_multicast(tunnel->parms.iph.daddr)) ||
                            rt6->rt6i_dst.plen == 128) {
                                rt6->rt6i_flags |= RTF_MODIFIED;
-                               skb->dst->metrics[RTAX_MTU-1] = mtu;
+                               skb_dst(skb)->metrics[RTAX_MTU-1] = mtu;
                        }
                }
 
@@ -837,8 +836,8 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
        IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
                              IPSKB_REROUTED);
-       dst_release(skb->dst);
-       skb->dst = &rt->u.dst;
+       skb_dst_drop(skb);
+       skb_dst_set(skb, &rt->u.dst);
 
        /*
         *      Push down and install the IPIP header.
@@ -1238,6 +1237,7 @@ static void ipgre_tunnel_setup(struct net_device *dev)
        dev->iflink             = 0;
        dev->addr_len           = 4;
        dev->features           |= NETIF_F_NETNS_LOCAL;
+       dev->priv_flags         &= ~IFF_XMIT_DST_RELEASE;
 }
 
 static int ipgre_tunnel_init(struct net_device *dev)
index 40f6206..490ce20 100644 (file)
@@ -329,7 +329,7 @@ static int ip_rcv_finish(struct sk_buff *skb)
         *      Initialise the virtual path cache for the packet. It describes
         *      how the packet travels inside Linux networking.
         */
-       if (skb->dst == NULL) {
+       if (skb_dst(skb) == NULL) {
                int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
                                         skb->dev);
                if (unlikely(err)) {
@@ -344,9 +344,9 @@ static int ip_rcv_finish(struct sk_buff *skb)
        }
 
 #ifdef CONFIG_NET_CLS_ROUTE
-       if (unlikely(skb->dst->tclassid)) {
+       if (unlikely(skb_dst(skb)->tclassid)) {
                struct ip_rt_acct *st = per_cpu_ptr(ip_rt_acct, smp_processor_id());
-               u32 idx = skb->dst->tclassid;
+               u32 idx = skb_dst(skb)->tclassid;
                st[idx&0xFF].o_packets++;
                st[idx&0xFF].o_bytes += skb->len;
                st[(idx>>16)&0xFF].i_packets++;
@@ -357,7 +357,7 @@ static int ip_rcv_finish(struct sk_buff *skb)
        if (iph->ihl > 5 && ip_rcv_options(skb))
                goto drop;
 
-       rt = skb->rtable;
+       rt = skb_rtable(skb);
        if (rt->rt_type == RTN_MULTICAST) {
                IP_UPD_PO_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INMCAST,
                                skb->len);
index 2c88da6..94bf105 100644 (file)
@@ -102,7 +102,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb)
        sptr = skb_network_header(skb);
        dptr = dopt->__data;
 
-       daddr = skb->rtable->rt_spec_dst;
+       daddr = skb_rtable(skb)->rt_spec_dst;
 
        if (sopt->rr) {
                optlen  = sptr[sopt->rr+1];
@@ -143,7 +143,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb)
                                                __be32 addr;
 
                                                memcpy(&addr, sptr+soffset-1, 4);
-                                               if (inet_addr_type(dev_net(skb->dst->dev), addr) != RTN_LOCAL) {
+                                               if (inet_addr_type(dev_net(skb_dst(skb)->dev), addr) != RTN_LOCAL) {
                                                        dopt->ts_needtime = 1;
                                                        soffset += 8;
                                                }
@@ -257,7 +257,7 @@ int ip_options_compile(struct net *net,
        struct rtable *rt = NULL;
 
        if (skb != NULL) {
-               rt = skb->rtable;
+               rt = skb_rtable(skb);
                optptr = (unsigned char *)&(ip_hdr(skb)[1]);
        } else
                optptr = opt->__data;
@@ -550,7 +550,7 @@ void ip_forward_options(struct sk_buff *skb)
 {
        struct   ip_options * opt       = &(IPCB(skb)->opt);
        unsigned char * optptr;
-       struct rtable *rt = skb->rtable;
+       struct rtable *rt = skb_rtable(skb);
        unsigned char *raw = skb_network_header(skb);
 
        if (opt->rr_needaddr) {
@@ -598,7 +598,7 @@ int ip_options_rcv_srr(struct sk_buff *skb)
        __be32 nexthop;
        struct iphdr *iph = ip_hdr(skb);
        unsigned char *optptr = skb_network_header(skb) + opt->srr;
-       struct rtable *rt = skb->rtable;
+       struct rtable *rt = skb_rtable(skb);
        struct rtable *rt2;
        int err;
 
@@ -623,13 +623,13 @@ int ip_options_rcv_srr(struct sk_buff *skb)
                }
                memcpy(&nexthop, &optptr[srrptr-1], 4);
 
-               rt = skb->rtable;
-               skb->rtable = NULL;
+               rt = skb_rtable(skb);
+               skb_dst_set(skb, NULL);
                err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, skb->dev);
-               rt2 = skb->rtable;
+               rt2 = skb_rtable(skb);
                if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) {
                        ip_rt_put(rt2);
-                       skb->rtable = rt;
+                       skb_dst_set(skb, &rt->u.dst);
                        return -EINVAL;
                }
                ip_rt_put(rt);
index ea19c37..2470262 100644 (file)
@@ -95,7 +95,7 @@ int __ip_local_out(struct sk_buff *skb)
 
        iph->tot_len = htons(skb->len);
        ip_send_check(iph);
-       return nf_hook(PF_INET, NF_INET_LOCAL_OUT, skb, NULL, skb->dst->dev,
+       return nf_hook(PF_INET, NF_INET_LOCAL_OUT, skb, NULL, skb_dst(skb)->dev,
                       dst_output);
 }
 
@@ -118,7 +118,7 @@ static int ip_dev_loopback_xmit(struct sk_buff *newskb)
        __skb_pull(newskb, skb_network_offset(newskb));
        newskb->pkt_type = PACKET_LOOPBACK;
        newskb->ip_summed = CHECKSUM_UNNECESSARY;
-       WARN_ON(!newskb->dst);
+       WARN_ON(!skb_dst(newskb));
        netif_rx(newskb);
        return 0;
 }
@@ -140,7 +140,7 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
                          __be32 saddr, __be32 daddr, struct ip_options *opt)
 {
        struct inet_sock *inet = inet_sk(sk);
-       struct rtable *rt = skb->rtable;
+       struct rtable *rt = skb_rtable(skb);
        struct iphdr *iph;
 
        /* Build the IP header. */
@@ -176,7 +176,7 @@ EXPORT_SYMBOL_GPL(ip_build_and_send_pkt);
 
 static inline int ip_finish_output2(struct sk_buff *skb)
 {
-       struct dst_entry *dst = skb->dst;
+       struct dst_entry *dst = skb_dst(skb);
        struct rtable *rt = (struct rtable *)dst;
        struct net_device *dev = dst->dev;
        unsigned int hh_len = LL_RESERVED_SPACE(dev);
@@ -217,14 +217,14 @@ static inline int ip_skb_dst_mtu(struct sk_buff *skb)
        struct inet_sock *inet = skb->sk ? inet_sk(skb->sk) : NULL;
 
        return (inet && inet->pmtudisc == IP_PMTUDISC_PROBE) ?
-              skb->dst->dev->mtu : dst_mtu(skb->dst);
+              skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
 }
 
 static int ip_finish_output(struct sk_buff *skb)
 {
 #if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
        /* Policy lookup after SNAT yielded a new policy */
-       if (skb->dst->xfrm != NULL) {
+       if (skb_dst(skb)->xfrm != NULL) {
                IPCB(skb)->flags |= IPSKB_REROUTED;
                return dst_output(skb);
        }
@@ -238,7 +238,7 @@ static int ip_finish_output(struct sk_buff *skb)
 int ip_mc_output(struct sk_buff *skb)
 {
        struct sock *sk = skb->sk;
-       struct rtable *rt = skb->rtable;
+       struct rtable *rt = skb_rtable(skb);
        struct net_device *dev = rt->u.dst.dev;
 
        /*
@@ -296,7 +296,7 @@ int ip_mc_output(struct sk_buff *skb)
 
 int ip_output(struct sk_buff *skb)
 {
-       struct net_device *dev = skb->dst->dev;
+       struct net_device *dev = skb_dst(skb)->dev;
 
        IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUT, skb->len);
 
@@ -319,7 +319,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
        /* Skip all of this if the packet is already routed,
         * f.e. by something like SCTP.
         */
-       rt = skb->rtable;
+       rt = skb_rtable(skb);
        if (rt != NULL)
                goto packet_routed;
 
@@ -355,7 +355,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
                }
                sk_setup_caps(sk, &rt->u.dst);
        }
-       skb->dst = dst_clone(&rt->u.dst);
+       skb_dst_set(skb, dst_clone(&rt->u.dst));
 
 packet_routed:
        if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
@@ -401,8 +401,8 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
        to->pkt_type = from->pkt_type;
        to->priority = from->priority;
        to->protocol = from->protocol;
-       dst_release(to->dst);
-       to->dst = dst_clone(from->dst);
+       skb_dst_drop(to);
+       skb_dst_set(to, dst_clone(skb_dst(from)));
        to->dev = from->dev;
        to->mark = from->mark;
 
@@ -440,7 +440,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
        unsigned int mtu, hlen, left, len, ll_rs, pad;
        int offset;
        __be16 not_last_frag;
-       struct rtable *rt = skb->rtable;
+       struct rtable *rt = skb_rtable(skb);
        int err = 0;
 
        dev = rt->u.dst.dev;
@@ -474,7 +474,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
         * LATER: this step can be merged to real generation of fragments,
         * we can switch to copy when see the first bad fragment.
         */
-       if (skb_shinfo(skb)->frag_list) {
+       if (skb_has_frags(skb)) {
                struct sk_buff *frag;
                int first_len = skb_pagelen(skb);
                int truesizes = 0;
@@ -485,7 +485,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
                    skb_cloned(skb))
                        goto slow_path;
 
-               for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) {
+               skb_walk_frags(skb, frag) {
                        /* Correct geometry. */
                        if (frag->len > mtu ||
                            ((frag->len & 7) && frag->next) ||
@@ -498,7 +498,6 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 
                        BUG_ON(frag->sk);
                        if (skb->sk) {
-                               sock_hold(skb->sk);
                                frag->sk = skb->sk;
                                frag->destructor = sock_wfree;
                                truesizes += frag->truesize;
@@ -510,7 +509,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
                err = 0;
                offset = 0;
                frag = skb_shinfo(skb)->frag_list;
-               skb_shinfo(skb)->frag_list = NULL;
+               skb_frag_list_init(skb);
                skb->data_len = first_len - skb_headlen(skb);
                skb->truesize -= truesizes;
                skb->len = first_len;
@@ -1294,7 +1293,7 @@ int ip_push_pending_frames(struct sock *sk)
         * on dst refcount
         */
        inet->cork.dst = NULL;
-       skb->dst = &rt->u.dst;
+       skb_dst_set(skb, &rt->u.dst);
 
        if (iph->protocol == IPPROTO_ICMP)
                icmp_out_count(net, ((struct icmphdr *)
@@ -1362,7 +1361,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
        } replyopts;
        struct ipcm_cookie ipc;
        __be32 daddr;
-       struct rtable *rt = skb->rtable;
+       struct rtable *rt = skb_rtable(skb);
 
        if (ip_options_echo(&replyopts.opt, skb))
                return;
index 43c0585..fc7993e 100644 (file)
@@ -57,7 +57,7 @@
 static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb)
 {
        struct in_pktinfo info;
-       struct rtable *rt = skb->rtable;
+       struct rtable *rt = skb_rtable(skb);
 
        info.ipi_addr.s_addr = ip_hdr(skb)->daddr;
        if (rt) {
@@ -157,38 +157,39 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
        /* Ordered by supposed usage frequency */
        if (flags & 1)
                ip_cmsg_recv_pktinfo(msg, skb);
-       if ((flags>>=1) == 0)
+       if ((flags >>= 1) == 0)
                return;
 
        if (flags & 1)
                ip_cmsg_recv_ttl(msg, skb);
-       if ((flags>>=1) == 0)
+       if ((flags >>= 1) == 0)
                return;
 
        if (flags & 1)
                ip_cmsg_recv_tos(msg, skb);
-       if ((flags>>=1) == 0)
+       if ((flags >>= 1) == 0)
                return;
 
        if (flags & 1)
                ip_cmsg_recv_opts(msg, skb);
-       if ((flags>>=1) == 0)
+       if ((flags >>= 1) == 0)
                return;
 
        if (flags & 1)
                ip_cmsg_recv_retopts(msg, skb);
-       if ((flags>>=1) == 0)
+       if ((flags >>= 1) == 0)
                return;
 
        if (flags & 1)
                ip_cmsg_recv_security(msg, skb);
 
-       if ((flags>>=1) == 0)
+       if ((flags >>= 1) == 0)
                return;
        if (flags & 1)
                ip_cmsg_recv_dstaddr(msg, skb);
 
 }
+EXPORT_SYMBOL(ip_cmsg_recv);
 
 int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc)
 {
@@ -203,7 +204,8 @@ int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc)
                switch (cmsg->cmsg_type) {
                case IP_RETOPTS:
                        err = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr));
-                       err = ip_options_get(net, &ipc->opt, CMSG_DATA(cmsg), err < 40 ? err : 40);
+                       err = ip_options_get(net, &ipc->opt, CMSG_DATA(cmsg),
+                                            err < 40 ? err : 40);
                        if (err)
                                return err;
                        break;
@@ -238,7 +240,8 @@ int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc)
 struct ip_ra_chain *ip_ra_chain;
 DEFINE_RWLOCK(ip_ra_lock);
 
-int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct sock *))
+int ip_ra_control(struct sock *sk, unsigned char on,
+                 void (*destructor)(struct sock *))
 {
        struct ip_ra_chain *ra, *new_ra, **rap;
 
@@ -248,7 +251,7 @@ int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct s
        new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
 
        write_lock_bh(&ip_ra_lock);
-       for (rap = &ip_ra_chain; (ra=*rap) != NULL; rap = &ra->next) {
+       for (rap = &ip_ra_chain; (ra = *rap) != NULL; rap = &ra->next) {
                if (ra->sk == sk) {
                        if (on) {
                                write_unlock_bh(&ip_ra_lock);
@@ -416,7 +419,8 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len)
        /* Reset and regenerate socket error */
        spin_lock_bh(&sk->sk_error_queue.lock);
        sk->sk_err = 0;
-       if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) {
+       skb2 = skb_peek(&sk->sk_error_queue);
+       if (skb2 != NULL) {
                sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno;
                spin_unlock_bh(&sk->sk_error_queue.lock);
                sk->sk_error_report(sk);
@@ -431,8 +435,8 @@ out:
 
 
 /*
- *     Socket option code for IP. This is the end of the line after any TCP,UDP etc options on
- *     an IP socket.
+ *     Socket option code for IP. This is the end of the line after any
+ *     TCP,UDP etc options on an IP socket.
  */
 
 static int do_ip_setsockopt(struct sock *sk, int level,
@@ -449,6 +453,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
                             (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
                             (1<<IP_PASSSEC) | (1<<IP_TRANSPARENT))) ||
            optname == IP_MULTICAST_TTL ||
+           optname == IP_MULTICAST_ALL ||
            optname == IP_MULTICAST_LOOP ||
            optname == IP_RECVORIGDSTADDR) {
                if (optlen >= sizeof(int)) {
@@ -474,7 +479,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
        switch (optname) {
        case IP_OPTIONS:
        {
-               struct ip_options * opt = NULL;
+               struct ip_options *opt = NULL;
                if (optlen > 40 || optlen < 0)
                        goto e_inval;
                err = ip_options_get_from_user(sock_net(sk), &opt,
@@ -556,9 +561,9 @@ static int do_ip_setsockopt(struct sock *sk, int level,
                }
                break;
        case IP_TTL:
-               if (optlen<1)
+               if (optlen < 1)
                        goto e_inval;
-               if (val != -1 && (val < 1 || val>255))
+               if (val != -1 && (val < 0 || val > 255))
                        goto e_inval;
                inet->uc_ttl = val;
                break;
@@ -570,7 +575,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
                inet->hdrincl = val ? 1 : 0;
                break;
        case IP_MTU_DISCOVER:
-               if (val<0 || val>3)
+               if (val < 0 || val > 3)
                        goto e_inval;
                inet->pmtudisc = val;
                break;
@@ -582,7 +587,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
        case IP_MULTICAST_TTL:
                if (sk->sk_type == SOCK_STREAM)
                        goto e_inval;
-               if (optlen<1)
+               if (optlen < 1)
                        goto e_inval;
                if (val == -1)
                        val = 1;
@@ -591,7 +596,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
                inet->mc_ttl = val;
                break;
        case IP_MULTICAST_LOOP:
-               if (optlen<1)
+               if (optlen < 1)
                        goto e_inval;
                inet->mc_loop = !!val;
                break;
@@ -613,7 +618,8 @@ static int do_ip_setsockopt(struct sock *sk, int level,
                } else {
                        memset(&mreq, 0, sizeof(mreq));
                        if (optlen >= sizeof(struct in_addr) &&
-                           copy_from_user(&mreq.imr_address, optval, sizeof(struct in_addr)))
+                           copy_from_user(&mreq.imr_address, optval,
+                                          sizeof(struct in_addr)))
                                break;
                }
 
@@ -677,7 +683,6 @@ static int do_ip_setsockopt(struct sock *sk, int level,
        }
        case IP_MSFILTER:
        {
-               extern int sysctl_igmp_max_msf;
                struct ip_msfilter *msf;
 
                if (optlen < IP_MSFILTER_SIZE(0))
@@ -831,7 +836,6 @@ static int do_ip_setsockopt(struct sock *sk, int level,
        }
        case MCAST_MSFILTER:
        {
-               extern int sysctl_igmp_max_msf;
                struct sockaddr_in *psin;
                struct ip_msfilter *msf = NULL;
                struct group_filter *gsf = NULL;
@@ -849,9 +853,9 @@ static int do_ip_setsockopt(struct sock *sk, int level,
                        break;
                }
                err = -EFAULT;
-               if (copy_from_user(gsf, optval, optlen)) {
+               if (copy_from_user(gsf, optval, optlen))
                        goto mc_msf_out;
-               }
+
                /* numsrc >= (4G-140)/128 overflow in 32 bits */
                if (gsf->gf_numsrc >= 0x1ffffff ||
                    gsf->gf_numsrc > sysctl_igmp_max_msf) {
@@ -879,7 +883,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
                msf->imsf_fmode = gsf->gf_fmode;
                msf->imsf_numsrc = gsf->gf_numsrc;
                err = -EADDRNOTAVAIL;
-               for (i=0; i<gsf->gf_numsrc; ++i) {
+               for (i = 0; i < gsf->gf_numsrc; ++i) {
                        psin = (struct sockaddr_in *)&gsf->gf_slist[i];
 
                        if (psin->sin_family != AF_INET)
@@ -890,17 +894,24 @@ static int do_ip_setsockopt(struct sock *sk, int level,
                gsf = NULL;
 
                err = ip_mc_msfilter(sk, msf, ifindex);
-       mc_msf_out:
+mc_msf_out:
                kfree(msf);
                kfree(gsf);
                break;
        }
+       case IP_MULTICAST_ALL:
+               if (optlen < 1)
+                       goto e_inval;
+               if (val != 0 && val != 1)
+                       goto e_inval;
+               inet->mc_all = val;
+               break;
        case IP_ROUTER_ALERT:
                err = ip_ra_control(sk, val ? 1 : 0, NULL);
                break;
 
        case IP_FREEBIND:
-               if (optlen<1)
+               if (optlen < 1)
                        goto e_inval;
                inet->freebind = !!val;
                break;
@@ -957,6 +968,7 @@ int ip_setsockopt(struct sock *sk, int level,
 #endif
        return err;
 }
+EXPORT_SYMBOL(ip_setsockopt);
 
 #ifdef CONFIG_COMPAT
 int compat_ip_setsockopt(struct sock *sk, int level, int optname,
@@ -986,13 +998,12 @@ int compat_ip_setsockopt(struct sock *sk, int level, int optname,
 #endif
        return err;
 }
-
 EXPORT_SYMBOL(compat_ip_setsockopt);
 #endif
 
 /*
- *     Get the options. Note for future reference. The GET of IP options gets the
- *     _received_ ones. The set sets the _sent_ ones.
+ *     Get the options. Note for future reference. The GET of IP options gets
+ *     the _received_ ones. The set sets the _sent_ ones.
  */
 
 static int do_ip_getsockopt(struct sock *sk, int level, int optname,
@@ -1143,10 +1154,14 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
                        return -EFAULT;
                }
                err = ip_mc_gsfget(sk, &gsf,
-                                  (struct group_filter __user *)optval, optlen);
+                                  (struct group_filter __user *)optval,
+                                  optlen);
                release_sock(sk);
                return err;
        }
+       case IP_MULTICAST_ALL:
+               val = inet->mc_all;
+               break;
        case IP_PKTOPTIONS:
        {
                struct msghdr msg;
@@ -1187,7 +1202,7 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
        }
        release_sock(sk);
 
-       if (len < sizeof(int) && len > 0 && val>=0 && val<=255) {
+       if (len < sizeof(int) && len > 0 && val >= 0 && val <= 255) {
                unsigned char ucval = (unsigned char)val;
                len = 1;
                if (put_user(len, optlen))
@@ -1230,6 +1245,7 @@ int ip_getsockopt(struct sock *sk, int level,
 #endif
        return err;
 }
+EXPORT_SYMBOL(ip_getsockopt);
 
 #ifdef CONFIG_COMPAT
 int compat_ip_getsockopt(struct sock *sk, int level, int optname,
@@ -1262,11 +1278,5 @@ int compat_ip_getsockopt(struct sock *sk, int level, int optname,
 #endif
        return err;
 }
-
 EXPORT_SYMBOL(compat_ip_getsockopt);
 #endif
-
-EXPORT_SYMBOL(ip_cmsg_recv);
-
-EXPORT_SYMBOL(ip_getsockopt);
-EXPORT_SYMBOL(ip_setsockopt);
index 9054139..93e2b78 100644 (file)
@@ -370,8 +370,7 @@ static int ipip_rcv(struct sk_buff *skb)
                tunnel->dev->stats.rx_packets++;
                tunnel->dev->stats.rx_bytes += skb->len;
                skb->dev = tunnel->dev;
-               dst_release(skb->dst);
-               skb->dst = NULL;
+               skb_dst_drop(skb);
                nf_reset(skb);
                ipip_ecn_decapsulate(iph, skb);
                netif_rx(skb);
@@ -416,7 +415,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 
        if (!dst) {
                /* NBMA tunnel */
-               if ((rt = skb->rtable) == NULL) {
+               if ((rt = skb_rtable(skb)) == NULL) {
                        stats->tx_fifo_errors++;
                        goto tx_error;
                }
@@ -447,15 +446,15 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        if (tiph->frag_off)
                mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr);
        else
-               mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu;
+               mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu;
 
        if (mtu < 68) {
                stats->collisions++;
                ip_rt_put(rt);
                goto tx_error;
        }
-       if (skb->dst)
-               skb->dst->ops->update_pmtu(skb->dst, mtu);
+       if (skb_dst(skb))
+               skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
 
        df |= (old_iph->frag_off&htons(IP_DF));
 
@@ -502,8 +501,8 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
        IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
                              IPSKB_REROUTED);
-       dst_release(skb->dst);
-       skb->dst = &rt->u.dst;
+       skb_dst_drop(skb);
+       skb_dst_set(skb, &rt->u.dst);
 
        /*
         *      Push down and install the IPIP header.
@@ -713,6 +712,7 @@ static void ipip_tunnel_setup(struct net_device *dev)
        dev->iflink             = 0;
        dev->addr_len           = 4;
        dev->features           |= NETIF_F_NETNS_LOCAL;
+       dev->priv_flags         &= ~IFF_XMIT_DST_RELEASE;
 }
 
 static void ipip_tunnel_init(struct net_device *dev)
index 13e9dd3..ffd9861 100644 (file)
@@ -651,7 +651,7 @@ static int ipmr_cache_report(struct net *net,
        ip_hdr(skb)->protocol = 0;                      /* Flag to the kernel this is a route add */
        msg = (struct igmpmsg *)skb_network_header(skb);
        msg->im_vif = vifi;
-       skb->dst = dst_clone(pkt->dst);
+       skb_dst_set(skb, dst_clone(skb_dst(pkt)));
 
        /*
         *      Add our header
@@ -1201,7 +1201,7 @@ static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr)
        iph->protocol   =       IPPROTO_IPIP;
        iph->ihl        =       5;
        iph->tot_len    =       htons(skb->len);
-       ip_select_ident(iph, skb->dst, NULL);
+       ip_select_ident(iph, skb_dst(skb), NULL);
        ip_send_check(iph);
 
        memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
@@ -1212,7 +1212,7 @@ static inline int ipmr_forward_finish(struct sk_buff *skb)
 {
        struct ip_options * opt = &(IPCB(skb)->opt);
 
-       IP_INC_STATS_BH(dev_net(skb->dst->dev), IPSTATS_MIB_OUTFORWDATAGRAMS);
+       IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTFORWDATAGRAMS);
 
        if (unlikely(opt->optlen))
                ip_forward_options(skb);
@@ -1290,8 +1290,8 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi)
        vif->pkt_out++;
        vif->bytes_out += skb->len;
 
-       dst_release(skb->dst);
-       skb->dst = &rt->u.dst;
+       skb_dst_drop(skb);
+       skb_dst_set(skb, &rt->u.dst);
        ip_decrease_ttl(ip_hdr(skb));
 
        /* FIXME: forward and output firewalls used to be called here.
@@ -1354,7 +1354,7 @@ static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local
        if (net->ipv4.vif_table[vif].dev != skb->dev) {
                int true_vifi;
 
-               if (skb->rtable->fl.iif == 0) {
+               if (skb_rtable(skb)->fl.iif == 0) {
                        /* It is our own packet, looped back.
                           Very complicated situation...
 
@@ -1430,7 +1430,7 @@ int ip_mr_input(struct sk_buff *skb)
 {
        struct mfc_cache *cache;
        struct net *net = dev_net(skb->dev);
-       int local = skb->rtable->rt_flags&RTCF_LOCAL;
+       int local = skb_rtable(skb)->rt_flags & RTCF_LOCAL;
 
        /* Packet is looped back after forward, it should not be
           forwarded second time, but still can be delivered locally.
@@ -1543,8 +1543,7 @@ static int __pim_rcv(struct sk_buff *skb, unsigned int pimlen)
        skb->protocol = htons(ETH_P_IP);
        skb->ip_summed = 0;
        skb->pkt_type = PACKET_HOST;
-       dst_release(skb->dst);
-       skb->dst = NULL;
+       skb_dst_drop(skb);
        reg_dev->stats.rx_bytes += skb->len;
        reg_dev->stats.rx_packets++;
        nf_reset(skb);
@@ -1646,7 +1645,7 @@ int ipmr_get_route(struct net *net,
 {
        int err;
        struct mfc_cache *cache;
-       struct rtable *rt = skb->rtable;
+       struct rtable *rt = skb_rtable(skb);
 
        read_lock(&mrt_lock);
        cache = ipmr_cache_find(net, rt->rt_src, rt->rt_dst);
index fdf6811..1725dc0 100644 (file)
@@ -12,7 +12,7 @@
 /* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */
 int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type)
 {
-       struct net *net = dev_net(skb->dst->dev);
+       struct net *net = dev_net(skb_dst(skb)->dev);
        const struct iphdr *iph = ip_hdr(skb);
        struct rtable *rt;
        struct flowi fl = {};
@@ -41,8 +41,8 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type)
                        return -1;
 
                /* Drop old route. */
-               dst_release(skb->dst);
-               skb->dst = &rt->u.dst;
+               skb_dst_drop(skb);
+               skb_dst_set(skb, &rt->u.dst);
        } else {
                /* non-local src, find valid iif to satisfy
                 * rp-filter when calling ip_route_input. */
@@ -50,7 +50,7 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type)
                if (ip_route_output_key(net, &rt, &fl) != 0)
                        return -1;
 
-               odst = skb->dst;
+               odst = skb_dst(skb);
                if (ip_route_input(skb, iph->daddr, iph->saddr,
                                   RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
                        dst_release(&rt->u.dst);
@@ -60,18 +60,22 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type)
                dst_release(odst);
        }
 
-       if (skb->dst->error)
+       if (skb_dst(skb)->error)
                return -1;
 
 #ifdef CONFIG_XFRM
        if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
-           xfrm_decode_session(skb, &fl, AF_INET) == 0)
-               if (xfrm_lookup(net, &skb->dst, &fl, skb->sk, 0))
+           xfrm_decode_session(skb, &fl, AF_INET) == 0) {
+               struct dst_entry *dst = skb_dst(skb);
+               skb_dst_set(skb, NULL);
+               if (xfrm_lookup(net, &dst, &fl, skb->sk, 0))
                        return -1;
+               skb_dst_set(skb, dst);
+       }
 #endif
 
        /* Change in oif may mean change in hh_len. */
-       hh_len = skb->dst->dev->hard_header_len;
+       hh_len = skb_dst(skb)->dev->hard_header_len;
        if (skb_headroom(skb) < hh_len &&
            pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC))
                return -1;
@@ -92,7 +96,7 @@ int ip_xfrm_me_harder(struct sk_buff *skb)
        if (xfrm_decode_session(skb, &fl, AF_INET) < 0)
                return -1;
 
-       dst = skb->dst;
+       dst = skb_dst(skb);
        if (dst->xfrm)
                dst = ((struct xfrm_dst *)dst)->route;
        dst_hold(dst);
@@ -100,11 +104,11 @@ int ip_xfrm_me_harder(struct sk_buff *skb)
        if (xfrm_lookup(dev_net(dst->dev), &dst, &fl, skb->sk, 0) < 0)
                return -1;
 
-       dst_release(skb->dst);
-       skb->dst = dst;
+       skb_dst_drop(skb);
+       skb_dst_set(skb, dst);
 
        /* Change in oif may mean change in hh_len. */
-       hh_len = skb->dst->dev->hard_header_len;
+       hh_len = skb_dst(skb)->dev->hard_header_len;
        if (skb_headroom(skb) < hh_len &&
            pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC))
                return -1;
index 855505d..dada086 100644 (file)
@@ -69,7 +69,7 @@ masquerade_tg(struct sk_buff *skb, const struct xt_target_param *par)
                return NF_ACCEPT;
 
        mr = par->targinfo;
-       rt = skb->rtable;
+       rt = skb_rtable(skb);
        newsrc = inet_select_addr(par->out, rt->rt_gateway, RT_SCOPE_UNIVERSE);
        if (!newsrc) {
                printk("MASQUERADE: %s ate my IP address\n", par->out->name);
index 0b4b6e0..c93ae44 100644 (file)
@@ -108,17 +108,16 @@ static void send_reset(struct sk_buff *oldskb, int hook)
                addr_type = RTN_LOCAL;
 
        /* ip_route_me_harder expects skb->dst to be set */
-       dst_hold(oldskb->dst);
-       nskb->dst = oldskb->dst;
+       skb_dst_set(nskb, dst_clone(skb_dst(oldskb)));
 
        if (ip_route_me_harder(nskb, addr_type))
                goto free_nskb;
 
-       niph->ttl       = dst_metric(nskb->dst, RTAX_HOPLIMIT);
+       niph->ttl       = dst_metric(skb_dst(nskb), RTAX_HOPLIMIT);
        nskb->ip_summed = CHECKSUM_NONE;
 
        /* "Never happens" */
-       if (nskb->len > dst_mtu(nskb->dst))
+       if (nskb->len > dst_mtu(skb_dst(nskb)))
                goto free_nskb;
 
        nf_ct_attach(nskb, oldskb);
index cf7a42b..155c008 100644 (file)
@@ -140,7 +140,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff *skb,
                         const char *rep_buffer,
                         unsigned int rep_len)
 {
-       struct rtable *rt = skb->rtable;
+       struct rtable *rt = skb_rtable(skb);
        struct iphdr *iph;
        struct tcphdr *tcph;
        int oldlen, datalen;
@@ -218,7 +218,7 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb,
                         const char *rep_buffer,
                         unsigned int rep_len)
 {
-       struct rtable *rt = skb->rtable;
+       struct rtable *rt = skb_rtable(skb);
        struct iphdr *iph;
        struct udphdr *udph;
        int datalen, oldlen;
index 65e470b..3fc598e 100644 (file)
@@ -33,6 +33,7 @@ sctp_manip_pkt(struct sk_buff *skb,
               enum nf_nat_manip_type maniptype)
 {
        const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
+       struct sk_buff *frag;
        sctp_sctphdr_t *hdr;
        unsigned int hdroff = iphdroff + iph->ihl*4;
        __be32 oldip, newip;
@@ -57,8 +58,8 @@ sctp_manip_pkt(struct sk_buff *skb,
        }
 
        crc32 = sctp_start_cksum((u8 *)hdr, skb_headlen(skb) - hdroff);
-       for (skb = skb_shinfo(skb)->frag_list; skb; skb = skb->next)
-               crc32 = sctp_update_cksum((u8 *)skb->data, skb_headlen(skb),
+       skb_walk_frags(skb, frag)
+               crc32 = sctp_update_cksum((u8 *)frag->data, skb_headlen(frag),
                                          crc32);
        crc32 = sctp_end_cksum(crc32);
        hdr->checksum = crc32;
index b7dd695..5567bd0 100644 (file)
@@ -167,10 +167,9 @@ nf_nat_in(unsigned int hooknum,
 
        ret = nf_nat_fn(hooknum, skb, in, out, okfn);
        if (ret != NF_DROP && ret != NF_STOLEN &&
-           daddr != ip_hdr(skb)->daddr) {
-               dst_release(skb->dst);
-               skb->dst = NULL;
-       }
+           daddr != ip_hdr(skb)->daddr)
+               skb_dst_drop(skb);
+
        return ret;
 }
 
index f774651..3dc9171 100644 (file)
@@ -343,7 +343,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
 
        skb->priority = sk->sk_priority;
        skb->mark = sk->sk_mark;
-       skb->dst = dst_clone(&rt->u.dst);
+       skb_dst_set(skb, dst_clone(&rt->u.dst));
 
        skb_reset_network_header(skb);
        iph = ip_hdr(skb);
index 28205e5..a849bb1 100644 (file)
@@ -1064,7 +1064,8 @@ work_done:
 out:   return 0;
 }
 
-static int rt_intern_hash(unsigned hash, struct rtable *rt, struct rtable **rp)
+static int rt_intern_hash(unsigned hash, struct rtable *rt,
+                         struct rtable **rp, struct sk_buff *skb)
 {
        struct rtable   *rth, **rthp;
        unsigned long   now;
@@ -1114,7 +1115,10 @@ restart:
                        spin_unlock_bh(rt_hash_lock_addr(hash));
 
                        rt_drop(rt);
-                       *rp = rth;
+                       if (rp)
+                               *rp = rth;
+                       else
+                               skb_dst_set(skb, &rth->u.dst);
                        return 0;
                }
 
@@ -1210,7 +1214,10 @@ restart:
        rcu_assign_pointer(rt_hash_table[hash].chain, rt);
 
        spin_unlock_bh(rt_hash_lock_addr(hash));
-       *rp = rt;
+       if (rp)
+               *rp = rt;
+       else
+               skb_dst_set(skb, &rt->u.dst);
        return 0;
 }
 
@@ -1407,7 +1414,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
                                                        &netevent);
 
                                rt_del(hash, rth);
-                               if (!rt_intern_hash(hash, rt, &rt))
+                               if (!rt_intern_hash(hash, rt, &rt, NULL))
                                        ip_rt_put(rt);
                                goto do_next;
                        }
@@ -1473,7 +1480,7 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
 
 void ip_rt_send_redirect(struct sk_buff *skb)
 {
-       struct rtable *rt = skb->rtable;
+       struct rtable *rt = skb_rtable(skb);
        struct in_device *in_dev = in_dev_get(rt->u.dst.dev);
 
        if (!in_dev)
@@ -1521,7 +1528,7 @@ out:
 
 static int ip_error(struct sk_buff *skb)
 {
-       struct rtable *rt = skb->rtable;
+       struct rtable *rt = skb_rtable(skb);
        unsigned long now;
        int code;
 
@@ -1698,7 +1705,7 @@ static void ipv4_link_failure(struct sk_buff *skb)
 
        icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
 
-       rt = skb->rtable;
+       rt = skb_rtable(skb);
        if (rt)
                dst_set_expires(&rt->u.dst, 0);
 }
@@ -1858,7 +1865,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
 
        in_dev_put(in_dev);
        hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev)));
-       return rt_intern_hash(hash, rth, &skb->rtable);
+       return rt_intern_hash(hash, rth, NULL, skb);
 
 e_nobufs:
        in_dev_put(in_dev);
@@ -2019,7 +2026,7 @@ static int ip_mkroute_input(struct sk_buff *skb,
        /* put it into the cache */
        hash = rt_hash(daddr, saddr, fl->iif,
                       rt_genid(dev_net(rth->u.dst.dev)));
-       return rt_intern_hash(hash, rth, &skb->rtable);
+       return rt_intern_hash(hash, rth, NULL, skb);
 }
 
 /*
@@ -2175,7 +2182,7 @@ local_input:
        }
        rth->rt_type    = res.type;
        hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net));
-       err = rt_intern_hash(hash, rth, &skb->rtable);
+       err = rt_intern_hash(hash, rth, NULL, skb);
        goto done;
 
 no_route:
@@ -2244,7 +2251,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
                        dst_use(&rth->u.dst, jiffies);
                        RT_CACHE_STAT_INC(in_hit);
                        rcu_read_unlock();
-                       skb->rtable = rth;
+                       skb_dst_set(skb, &rth->u.dst);
                        return 0;
                }
                RT_CACHE_STAT_INC(in_hlist_search);
@@ -2420,7 +2427,7 @@ static int ip_mkroute_output(struct rtable **rp,
        if (err == 0) {
                hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src, oldflp->oif,
                               rt_genid(dev_net(dev_out)));
-               err = rt_intern_hash(hash, rth, rp);
+               err = rt_intern_hash(hash, rth, rp, NULL);
        }
 
        return err;
@@ -2763,7 +2770,7 @@ static int rt_fill_info(struct net *net,
                        struct sk_buff *skb, u32 pid, u32 seq, int event,
                        int nowait, unsigned int flags)
 {
-       struct rtable *rt = skb->rtable;
+       struct rtable *rt = skb_rtable(skb);
        struct rtmsg *r;
        struct nlmsghdr *nlh;
        long expires;
@@ -2907,7 +2914,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
                err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev);
                local_bh_enable();
 
-               rt = skb->rtable;
+               rt = skb_rtable(skb);
                if (err == 0 && rt->u.dst.error)
                        err = -rt->u.dst.error;
        } else {
@@ -2927,7 +2934,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
        if (err)
                goto errout_free;
 
-       skb->rtable = rt;
+       skb_dst_set(skb, &rt->u.dst);
        if (rtm->rtm_flags & RTM_F_NOTIFY)
                rt->rt_flags |= RTCF_NOTIFY;
 
@@ -2968,15 +2975,15 @@ int ip_rt_dump(struct sk_buff *skb,  struct netlink_callback *cb)
                                continue;
                        if (rt_is_expired(rt))
                                continue;
-                       skb->dst = dst_clone(&rt->u.dst);
+                       skb_dst_set(skb, dst_clone(&rt->u.dst));
                        if (rt_fill_info(net, skb, NETLINK_CB(cb->skb).pid,
                                         cb->nlh->nlmsg_seq, RTM_NEWROUTE,
                                         1, NLM_F_MULTI) <= 0) {
-                               dst_release(xchg(&skb->dst, NULL));
+                               skb_dst_drop(skb);
                                rcu_read_unlock_bh();
                                goto done;
                        }
-                       dst_release(xchg(&skb->dst, NULL));
+                       skb_dst_drop(skb);
                }
                rcu_read_unlock_bh();
        }
index 0fb8b44..17b89c5 100644 (file)
@@ -439,12 +439,14 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
                         !tp->urg_data ||
                         before(tp->urg_seq, tp->copied_seq) ||
                         !before(tp->urg_seq, tp->rcv_nxt)) {
+                       struct sk_buff *skb;
+
                        answ = tp->rcv_nxt - tp->copied_seq;
 
                        /* Subtract 1, if FIN is in queue. */
-                       if (answ && !skb_queue_empty(&sk->sk_receive_queue))
-                               answ -=
-                      tcp_hdr((struct sk_buff *)sk->sk_receive_queue.prev)->fin;
+                       skb = skb_peek_tail(&sk->sk_receive_queue);
+                       if (answ && skb)
+                               answ -= tcp_hdr(skb)->fin;
                } else
                        answ = tp->urg_seq - tp->copied_seq;
                release_sock(sk);
@@ -1382,11 +1384,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 
                /* Next get a buffer. */
 
-               skb = skb_peek(&sk->sk_receive_queue);
-               do {
-                       if (!skb)
-                               break;
-
+               skb_queue_walk(&sk->sk_receive_queue, skb) {
                        /* Now that we have two receive queues this
                         * shouldn't happen.
                         */
@@ -1403,8 +1401,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                        if (tcp_hdr(skb)->fin)
                                goto found_fin_ok;
                        WARN_ON(!(flags & MSG_PEEK));
-                       skb = skb->next;
-               } while (skb != (struct sk_buff *)&sk->sk_receive_queue);
+               }
 
                /* Well, if we have backlog, try to process it now yet. */
 
index eeb8a92..2bdb0da 100644 (file)
@@ -4426,7 +4426,7 @@ drop:
                }
                __skb_queue_head(&tp->out_of_order_queue, skb);
        } else {
-               struct sk_buff *skb1 = tp->out_of_order_queue.prev;
+               struct sk_buff *skb1 = skb_peek_tail(&tp->out_of_order_queue);
                u32 seq = TCP_SKB_CB(skb)->seq;
                u32 end_seq = TCP_SKB_CB(skb)->end_seq;
 
@@ -4443,15 +4443,18 @@ drop:
                }
 
                /* Find place to insert this segment. */
-               do {
+               while (1) {
                        if (!after(TCP_SKB_CB(skb1)->seq, seq))
                                break;
-               } while ((skb1 = skb1->prev) !=
-                        (struct sk_buff *)&tp->out_of_order_queue);
+                       if (skb_queue_is_first(&tp->out_of_order_queue, skb1)) {
+                               skb1 = NULL;
+                               break;
+                       }
+                       skb1 = skb_queue_prev(&tp->out_of_order_queue, skb1);
+               }
 
                /* Do skb overlap to previous one? */
-               if (skb1 != (struct sk_buff *)&tp->out_of_order_queue &&
-                   before(seq, TCP_SKB_CB(skb1)->end_seq)) {
+               if (skb1 && before(seq, TCP_SKB_CB(skb1)->end_seq)) {
                        if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq)) {
                                /* All the bits are present. Drop. */
                                __kfree_skb(skb);
@@ -4463,15 +4466,26 @@ drop:
                                tcp_dsack_set(sk, seq,
                                              TCP_SKB_CB(skb1)->end_seq);
                        } else {
-                               skb1 = skb1->prev;
+                               if (skb_queue_is_first(&tp->out_of_order_queue,
+                                                      skb1))
+                                       skb1 = NULL;
+                               else
+                                       skb1 = skb_queue_prev(
+                                               &tp->out_of_order_queue,
+                                               skb1);
                        }
                }
-               __skb_queue_after(&tp->out_of_order_queue, skb1, skb);
+               if (!skb1)
+                       __skb_queue_head(&tp->out_of_order_queue, skb);
+               else
+                       __skb_queue_after(&tp->out_of_order_queue, skb1, skb);
 
                /* And clean segments covered by new one as whole. */
-               while ((skb1 = skb->next) !=
-                      (struct sk_buff *)&tp->out_of_order_queue &&
-                      after(end_seq, TCP_SKB_CB(skb1)->seq)) {
+               while (!skb_queue_is_last(&tp->out_of_order_queue, skb)) {
+                       skb1 = skb_queue_next(&tp->out_of_order_queue, skb);
+
+                       if (!after(end_seq, TCP_SKB_CB(skb1)->seq))
+                               break;
                        if (before(end_seq, TCP_SKB_CB(skb1)->end_seq)) {
                                tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq,
                                                 end_seq);
@@ -4492,7 +4506,10 @@ add_sack:
 static struct sk_buff *tcp_collapse_one(struct sock *sk, struct sk_buff *skb,
                                        struct sk_buff_head *list)
 {
-       struct sk_buff *next = skb->next;
+       struct sk_buff *next = NULL;
+
+       if (!skb_queue_is_last(list, skb))
+               next = skb_queue_next(list, skb);
 
        __skb_unlink(skb, list);
        __kfree_skb(skb);
@@ -4503,6 +4520,9 @@ static struct sk_buff *tcp_collapse_one(struct sock *sk, struct sk_buff *skb,
 
 /* Collapse contiguous sequence of skbs head..tail with
  * sequence numbers start..end.
+ *
+ * If tail is NULL, this means until the end of the list.
+ *
  * Segments with FIN/SYN are not collapsed (only because this
  * simplifies code)
  */
@@ -4511,15 +4531,23 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list,
             struct sk_buff *head, struct sk_buff *tail,
             u32 start, u32 end)
 {
-       struct sk_buff *skb;
+       struct sk_buff *skb, *n;
+       bool end_of_skbs;
 
        /* First, check that queue is collapsible and find
         * the point where collapsing can be useful. */
-       for (skb = head; skb != tail;) {
+       skb = head;
+restart:
+       end_of_skbs = true;
+       skb_queue_walk_from_safe(list, skb, n) {
+               if (skb == tail)
+                       break;
                /* No new bits? It is possible on ofo queue. */
                if (!before(start, TCP_SKB_CB(skb)->end_seq)) {
                        skb = tcp_collapse_one(sk, skb, list);
-                       continue;
+                       if (!skb)
+                               break;
+                       goto restart;
                }
 
                /* The first skb to collapse is:
@@ -4529,16 +4557,24 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list,
                 */
                if (!tcp_hdr(skb)->syn && !tcp_hdr(skb)->fin &&
                    (tcp_win_from_space(skb->truesize) > skb->len ||
-                    before(TCP_SKB_CB(skb)->seq, start) ||
-                    (skb->next != tail &&
-                     TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb->next)->seq)))
+                    before(TCP_SKB_CB(skb)->seq, start))) {
+                       end_of_skbs = false;
                        break;
+               }
+
+               if (!skb_queue_is_last(list, skb)) {
+                       struct sk_buff *next = skb_queue_next(list, skb);
+                       if (next != tail &&
+                           TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(next)->seq) {
+                               end_of_skbs = false;
+                               break;
+                       }
+               }
 
                /* Decided to skip this, advance start seq. */
                start = TCP_SKB_CB(skb)->end_seq;
-               skb = skb->next;
        }
-       if (skb == tail || tcp_hdr(skb)->syn || tcp_hdr(skb)->fin)
+       if (end_of_skbs || tcp_hdr(skb)->syn || tcp_hdr(skb)->fin)
                return;
 
        while (before(start, end)) {
@@ -4583,7 +4619,8 @@ tcp_collapse(struct sock *sk, struct sk_buff_head *list,
                        }
                        if (!before(start, TCP_SKB_CB(skb)->end_seq)) {
                                skb = tcp_collapse_one(sk, skb, list);
-                               if (skb == tail ||
+                               if (!skb ||
+                                   skb == tail ||
                                    tcp_hdr(skb)->syn ||
                                    tcp_hdr(skb)->fin)
                                        return;
@@ -4610,17 +4647,21 @@ static void tcp_collapse_ofo_queue(struct sock *sk)
        head = skb;
 
        for (;;) {
-               skb = skb->next;
+               struct sk_buff *next = NULL;
+
+               if (!skb_queue_is_last(&tp->out_of_order_queue, skb))
+                       next = skb_queue_next(&tp->out_of_order_queue, skb);
+               skb = next;
 
                /* Segment is terminated when we see gap or when
                 * we are at the end of all the queue. */
-               if (skb == (struct sk_buff *)&tp->out_of_order_queue ||
+               if (!skb ||
                    after(TCP_SKB_CB(skb)->seq, end) ||
                    before(TCP_SKB_CB(skb)->end_seq, start)) {
                        tcp_collapse(sk, &tp->out_of_order_queue,
                                     head, skb, start, end);
                        head = skb;
-                       if (skb == (struct sk_buff *)&tp->out_of_order_queue)
+                       if (!skb)
                                break;
                        /* Start new segment */
                        start = TCP_SKB_CB(skb)->seq;
@@ -4681,10 +4722,11 @@ static int tcp_prune_queue(struct sock *sk)
                tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4U * tp->advmss);
 
        tcp_collapse_ofo_queue(sk);
-       tcp_collapse(sk, &sk->sk_receive_queue,
-                    sk->sk_receive_queue.next,
-                    (struct sk_buff *)&sk->sk_receive_queue,
-                    tp->copied_seq, tp->rcv_nxt);
+       if (!skb_queue_empty(&sk->sk_receive_queue))
+               tcp_collapse(sk, &sk->sk_receive_queue,
+                            skb_peek(&sk->sk_receive_queue),
+                            NULL,
+                            tp->copied_seq, tp->rcv_nxt);
        sk_mem_reclaim(sk);
 
        if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf)
index fc79e34..5a1ca26 100644 (file)
@@ -546,7 +546,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
        if (th->rst)
                return;
 
-       if (skb->rtable->rt_type != RTN_LOCAL)
+       if (skb_rtable(skb)->rt_type != RTN_LOCAL)
                return;
 
        /* Swap the send and the receive. */
@@ -590,7 +590,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
        arg.csumoffset = offsetof(struct tcphdr, check) / 2;
        arg.flags = (sk && inet_sk(sk)->transparent) ? IP_REPLY_ARG_NOSRCCHECK : 0;
 
-       net = dev_net(skb->dst->dev);
+       net = dev_net(skb_dst(skb)->dev);
        ip_send_reply(net->ipv4.tcp_sock, skb,
                      &arg, arg.iov[0].iov_len);
 
@@ -617,7 +617,7 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
                        ];
        } rep;
        struct ip_reply_arg arg;
-       struct net *net = dev_net(skb->dst->dev);
+       struct net *net = dev_net(skb_dst(skb)->dev);
 
        memset(&rep.th, 0, sizeof(struct tcphdr));
        memset(&arg, 0, sizeof(arg));
@@ -1185,7 +1185,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 #endif
 
        /* Never answer to SYNs send to broadcast or multicast */
-       if (skb->rtable->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
+       if (skb_rtable(skb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
                goto drop;
 
        /* TW buckets are converted to open requests without
index 79c39dc..416fc4c 100644 (file)
@@ -2202,7 +2202,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
        /* Reserve space for headers. */
        skb_reserve(skb, MAX_TCP_HEADER);
 
-       skb->dst = dst_clone(dst);
+       skb_dst_set(skb, dst_clone(dst));
 
        mss = dst_metric(dst, RTAX_ADVMSS);
        if (tp->rx_opt.user_mss && tp->rx_opt.user_mss < mss)
index a453aac..c6743ee 100644 (file)
@@ -158,6 +158,11 @@ void tcp_vegas_cwnd_event(struct sock *sk, enum tcp_ca_event event)
 }
 EXPORT_SYMBOL_GPL(tcp_vegas_cwnd_event);
 
+static inline u32 tcp_vegas_ssthresh(struct tcp_sock *tp)
+{
+       return  min(tp->snd_ssthresh, tp->snd_cwnd-1);
+}
+
 static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
 {
        struct tcp_sock *tp = tcp_sk(sk);
@@ -221,11 +226,10 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
                         */
                        diff = tp->snd_cwnd * (rtt-vegas->baseRTT) / vegas->baseRTT;
 
-                       if (diff > gamma && tp->snd_ssthresh > 2 ) {
+                       if (diff > gamma && tp->snd_cwnd <= tp->snd_ssthresh) {
                                /* Going too fast. Time to slow down
                                 * and switch to congestion avoidance.
                                 */
-                               tp->snd_ssthresh = 2;
 
                                /* Set cwnd to match the actual rate
                                 * exactly:
@@ -235,6 +239,7 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
                                 * utilization.
                                 */
                                tp->snd_cwnd = min(tp->snd_cwnd, (u32)target_cwnd+1);
+                               tp->snd_ssthresh = tcp_vegas_ssthresh(tp);
 
                        } else if (tp->snd_cwnd <= tp->snd_ssthresh) {
                                /* Slow start.  */
@@ -250,6 +255,8 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
                                         * we slow down.
                                         */
                                        tp->snd_cwnd--;
+                                       tp->snd_ssthresh
+                                               = tcp_vegas_ssthresh(tp);
                                } else if (diff < alpha) {
                                        /* We don't have enough extra packets
                                         * in the network, so speed up.
index 7a1d1ce..8f4158d 100644 (file)
@@ -328,7 +328,7 @@ static inline struct sock *__udp4_lib_lookup_skb(struct sk_buff *skb,
        if (unlikely(sk = skb_steal_sock(skb)))
                return sk;
        else
-               return __udp4_lib_lookup(dev_net(skb->dst->dev), iph->saddr, sport,
+               return __udp4_lib_lookup(dev_net(skb_dst(skb)->dev), iph->saddr, sport,
                                         iph->daddr, dport, inet_iif(skb),
                                         udptable);
 }
@@ -1237,7 +1237,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
        struct sock *sk;
        struct udphdr *uh;
        unsigned short ulen;
-       struct rtable *rt = (struct rtable*)skb->dst;
+       struct rtable *rt = skb_rtable(skb);
        __be32 saddr, daddr;
        struct net *net = dev_net(skb->dev);
 
index 4ec2162..f9f922a 100644 (file)
@@ -23,7 +23,7 @@ int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb)
 
 static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb)
 {
-       if (skb->dst == NULL) {
+       if (skb_dst(skb) == NULL) {
                const struct iphdr *iph = ip_hdr(skb);
 
                if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
index 7135279..3444f3b 100644 (file)
@@ -28,7 +28,7 @@ static inline void ipip_ecn_decapsulate(struct sk_buff *skb)
  */
 static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
 {
-       struct dst_entry *dst = skb->dst;
+       struct dst_entry *dst = skb_dst(skb);
        struct iphdr *top_iph;
        int flags;
 
@@ -41,7 +41,7 @@ static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
        top_iph->ihl = 5;
        top_iph->version = 4;
 
-       top_iph->protocol = xfrm_af2proto(skb->dst->ops->family);
+       top_iph->protocol = xfrm_af2proto(skb_dst(skb)->ops->family);
 
        /* DS disclosed */
        top_iph->tos = INET_ECN_encapsulate(XFRM_MODE_SKB_CB(skb)->tos,
index 8c3180a..c908bd9 100644 (file)
@@ -29,7 +29,7 @@ static int xfrm4_tunnel_check_size(struct sk_buff *skb)
        if (!(ip_hdr(skb)->frag_off & htons(IP_DF)) || skb->local_df)
                goto out;
 
-       dst = skb->dst;
+       dst = skb_dst(skb);
        mtu = dst_mtu(dst);
        if (skb->len > mtu) {
                icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
@@ -72,7 +72,7 @@ EXPORT_SYMBOL(xfrm4_prepare_output);
 static int xfrm4_output_finish(struct sk_buff *skb)
 {
 #ifdef CONFIG_NETFILTER
-       if (!skb->dst->xfrm) {
+       if (!skb_dst(skb)->xfrm) {
                IPCB(skb)->flags |= IPSKB_REROUTED;
                return dst_output(skb);
        }
@@ -87,6 +87,6 @@ static int xfrm4_output_finish(struct sk_buff *skb)
 int xfrm4_output(struct sk_buff *skb)
 {
        return NF_HOOK_COND(PF_INET, NF_INET_POST_ROUTING, skb,
-                           NULL, skb->dst->dev, xfrm4_output_finish,
+                           NULL, skb_dst(skb)->dev, xfrm4_output_finish,
                            !(IPCB(skb)->flags & IPSKB_REROUTED));
 }
index 31938e5..c348837 100644 (file)
@@ -591,7 +591,6 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
 {
        struct inet6_ifaddr *ifa = NULL;
        struct rt6_info *rt;
-       struct net *net = dev_net(idev->dev);
        int hash;
        int err = 0;
        int addr_type = ipv6_addr_type(addr);
@@ -608,7 +607,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
                goto out2;
        }
 
-       if (idev->cnf.disable_ipv6 || net->ipv6.devconf_all->disable_ipv6) {
+       if (idev->cnf.disable_ipv6) {
                err = -EACCES;
                goto out2;
        }
@@ -1752,6 +1751,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
        __u32 prefered_lft;
        int addr_type;
        struct inet6_dev *in6_dev;
+       struct net *net = dev_net(dev);
 
        pinfo = (struct prefix_info *) opt;
 
@@ -1809,7 +1809,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
                if (addrconf_finite_timeout(rt_expires))
                        rt_expires *= HZ;
 
-               rt = rt6_lookup(dev_net(dev), &pinfo->prefix, NULL,
+               rt = rt6_lookup(net, &pinfo->prefix, NULL,
                                dev->ifindex, 1);
 
                if (rt && addrconf_is_prefix_route(rt)) {
@@ -1846,7 +1846,6 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
                struct inet6_ifaddr * ifp;
                struct in6_addr addr;
                int create = 0, update_lft = 0;
-               struct net *net = dev_net(dev);
 
                if (pinfo->prefix_len == 64) {
                        memcpy(&addr, &pinfo->prefix, 8);
@@ -3988,6 +3987,75 @@ static int addrconf_sysctl_forward_strategy(ctl_table *table,
        return addrconf_fixup_forwarding(table, valp, val);
 }
 
+static void dev_disable_change(struct inet6_dev *idev)
+{
+       if (!idev || !idev->dev)
+               return;
+
+       if (idev->cnf.disable_ipv6)
+               addrconf_notify(NULL, NETDEV_DOWN, idev->dev);
+       else
+               addrconf_notify(NULL, NETDEV_UP, idev->dev);
+}
+
+static void addrconf_disable_change(struct net *net, __s32 newf)
+{
+       struct net_device *dev;
+       struct inet6_dev *idev;
+
+       read_lock(&dev_base_lock);
+       for_each_netdev(net, dev) {
+               rcu_read_lock();
+               idev = __in6_dev_get(dev);
+               if (idev) {
+                       int changed = (!idev->cnf.disable_ipv6) ^ (!newf);
+                       idev->cnf.disable_ipv6 = newf;
+                       if (changed)
+                               dev_disable_change(idev);
+               }
+               rcu_read_unlock();
+       }
+       read_unlock(&dev_base_lock);
+}
+
+static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old)
+{
+       struct net *net;
+
+       net = (struct net *)table->extra2;
+
+       if (p == &net->ipv6.devconf_dflt->disable_ipv6)
+               return 0;
+
+       if (!rtnl_trylock())
+               return restart_syscall();
+
+       if (p == &net->ipv6.devconf_all->disable_ipv6) {
+               __s32 newf = net->ipv6.devconf_all->disable_ipv6;
+               net->ipv6.devconf_dflt->disable_ipv6 = newf;
+               addrconf_disable_change(net, newf);
+       } else if ((!*p) ^ (!old))
+               dev_disable_change((struct inet6_dev *)table->extra1);
+
+       rtnl_unlock();
+       return 0;
+}
+
+static
+int addrconf_sysctl_disable(ctl_table *ctl, int write, struct file * filp,
+                           void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       int *valp = ctl->data;
+       int val = *valp;
+       int ret;
+
+       ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
+
+       if (write)
+               ret = addrconf_disable_ipv6(ctl, valp, val);
+       return ret;
+}
+
 static struct addrconf_sysctl_table
 {
        struct ctl_table_header *sysctl_header;
@@ -4225,7 +4293,8 @@ static struct addrconf_sysctl_table
                        .data           =       &ipv6_devconf.disable_ipv6,
                        .maxlen         =       sizeof(int),
                        .mode           =       0644,
-                       .proc_handler   =       proc_dointvec,
+                       .proc_handler   =       addrconf_sysctl_disable,
+                       .strategy       =       sysctl_intvec,
                },
                {
                        .ctl_name       =       CTL_UNNUMBERED,
@@ -4346,6 +4415,10 @@ static int addrconf_init_net(struct net *net)
                dflt = kmemdup(dflt, sizeof(ipv6_devconf_dflt), GFP_KERNEL);
                if (dflt == NULL)
                        goto err_alloc_dflt;
+       } else {
+               /* these will be inherited by all namespaces */
+               dflt->autoconf = ipv6_defaults.autoconf;
+               dflt->disable_ipv6 = ipv6_defaults.disable_ipv6;
        }
 
        net->ipv6.devconf_all = all;
index b6215be..85b3d00 100644 (file)
@@ -72,9 +72,21 @@ MODULE_LICENSE("GPL");
 static struct list_head inetsw6[SOCK_MAX];
 static DEFINE_SPINLOCK(inetsw6_lock);
 
-static int disable_ipv6 = 0;
-module_param_named(disable, disable_ipv6, int, 0);
-MODULE_PARM_DESC(disable, "Disable IPv6 such that it is non-functional");
+struct ipv6_params ipv6_defaults = {
+       .disable_ipv6 = 0,
+       .autoconf = 1,
+};
+
+static int disable_ipv6_mod = 0;
+
+module_param_named(disable, disable_ipv6_mod, int, 0444);
+MODULE_PARM_DESC(disable, "Disable IPv6 module such that it is non-functional");
+
+module_param_named(disable_ipv6, ipv6_defaults.disable_ipv6, int, 0444);
+MODULE_PARM_DESC(disable_ipv6, "Disable IPv6 on all interfaces");
+
+module_param_named(autoconf, ipv6_defaults.autoconf, int, 0444);
+MODULE_PARM_DESC(autoconf, "Enable IPv6 address autoconfiguration on all interfaces");
 
 static __inline__ struct ipv6_pinfo *inet6_sk_generic(struct sock *sk)
 {
@@ -1038,7 +1050,7 @@ static int __init inet6_init(void)
        for(r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r)
                INIT_LIST_HEAD(r);
 
-       if (disable_ipv6) {
+       if (disable_ipv6_mod) {
                printk(KERN_INFO
                       "IPv6: Loaded, but administratively disabled, "
                       "reboot required to enable\n");
@@ -1227,7 +1239,7 @@ module_init(inet6_init);
 
 static void __exit inet6_exit(void)
 {
-       if (disable_ipv6)
+       if (disable_ipv6_mod)
                return;
 
        /* First of all disallow new sockets creation. */
index 1c7f400..4aae658 100644 (file)
@@ -277,7 +277,7 @@ static int ipv6_destopt_rcv(struct sk_buff *skb)
        if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
            !pskb_may_pull(skb, (skb_transport_offset(skb) +
                                 ((skb_transport_header(skb)[1] + 1) << 3)))) {
-               IP6_INC_STATS_BH(dev_net(skb->dst->dev), ip6_dst_idev(skb->dst),
+               IP6_INC_STATS_BH(dev_net(skb_dst(skb)->dev), ip6_dst_idev(skb_dst(skb)),
                                 IPSTATS_MIB_INHDRERRORS);
                kfree_skb(skb);
                return -1;
@@ -288,7 +288,7 @@ static int ipv6_destopt_rcv(struct sk_buff *skb)
        dstbuf = opt->dst1;
 #endif
 
-       dst = dst_clone(skb->dst);
+       dst = dst_clone(skb_dst(skb));
        if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) {
                dst_release(dst);
                skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3;
@@ -333,7 +333,7 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb)
        if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
            !pskb_may_pull(skb, (skb_transport_offset(skb) +
                                 ((skb_transport_header(skb)[1] + 1) << 3)))) {
-               IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst),
+               IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
                                 IPSTATS_MIB_INHDRERRORS);
                kfree_skb(skb);
                return -1;
@@ -343,7 +343,7 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb)
 
        if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ||
            skb->pkt_type != PACKET_HOST) {
-               IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst),
+               IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
                                 IPSTATS_MIB_INADDRERRORS);
                kfree_skb(skb);
                return -1;
@@ -358,7 +358,7 @@ looped_back:
                         * processed by own
                         */
                        if (!addr) {
-                               IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst),
+                               IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
                                                 IPSTATS_MIB_INADDRERRORS);
                                kfree_skb(skb);
                                return -1;
@@ -384,7 +384,7 @@ looped_back:
                        goto unknown_rh;
                /* Silently discard invalid RTH type 2 */
                if (hdr->hdrlen != 2 || hdr->segments_left != 1) {
-                       IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst),
+                       IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
                                         IPSTATS_MIB_INHDRERRORS);
                        kfree_skb(skb);
                        return -1;
@@ -403,7 +403,7 @@ looped_back:
        n = hdr->hdrlen >> 1;
 
        if (hdr->segments_left > n) {
-               IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst),
+               IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
                                 IPSTATS_MIB_INHDRERRORS);
                icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
                                  ((&hdr->segments_left) -
@@ -417,7 +417,7 @@ looped_back:
        if (skb_cloned(skb)) {
                /* the copy is a forwarded packet */
                if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
-                       IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst),
+                       IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
                                         IPSTATS_MIB_OUTDISCARDS);
                        kfree_skb(skb);
                        return -1;
@@ -440,13 +440,13 @@ looped_back:
                if (xfrm6_input_addr(skb, (xfrm_address_t *)addr,
                                     (xfrm_address_t *)&ipv6_hdr(skb)->saddr,
                                     IPPROTO_ROUTING) < 0) {
-                       IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst),
+                       IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
                                         IPSTATS_MIB_INADDRERRORS);
                        kfree_skb(skb);
                        return -1;
                }
-               if (!ipv6_chk_home_addr(dev_net(skb->dst->dev), addr)) {
-                       IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst),
+               if (!ipv6_chk_home_addr(dev_net(skb_dst(skb)->dev), addr)) {
+                       IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
                                         IPSTATS_MIB_INADDRERRORS);
                        kfree_skb(skb);
                        return -1;
@@ -458,7 +458,7 @@ looped_back:
        }
 
        if (ipv6_addr_is_multicast(addr)) {
-               IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst),
+               IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
                                 IPSTATS_MIB_INADDRERRORS);
                kfree_skb(skb);
                return -1;
@@ -468,17 +468,17 @@ looped_back:
        ipv6_addr_copy(addr, &ipv6_hdr(skb)->daddr);
        ipv6_addr_copy(&ipv6_hdr(skb)->daddr, &daddr);
 
-       dst_release(xchg(&skb->dst, NULL));
+       skb_dst_drop(skb);
        ip6_route_input(skb);
-       if (skb->dst->error) {
+       if (skb_dst(skb)->error) {
                skb_push(skb, skb->data - skb_network_header(skb));
                dst_input(skb);
                return -1;
        }
 
-       if (skb->dst->dev->flags&IFF_LOOPBACK) {
+       if (skb_dst(skb)->dev->flags&IFF_LOOPBACK) {
                if (ipv6_hdr(skb)->hop_limit <= 1) {
-                       IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst),
+                       IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
                                         IPSTATS_MIB_INHDRERRORS);
                        icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
                                    0, skb->dev);
@@ -494,7 +494,7 @@ looped_back:
        return -1;
 
 unknown_rh:
-       IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
+       IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS);
        icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
                          (&hdr->type) - skb_network_header(skb));
        return -1;
@@ -552,11 +552,11 @@ void ipv6_exthdrs_exit(void)
  **********************************/
 
 /*
- * Note: we cannot rely on skb->dst before we assign it in ip6_route_input().
+ * Note: we cannot rely on skb_dst(skb) before we assign it in ip6_route_input().
  */
 static inline struct inet6_dev *ipv6_skb_idev(struct sk_buff *skb)
 {
-       return skb->dst ? ip6_dst_idev(skb->dst) : __in6_dev_get(skb->dev);
+       return skb_dst(skb) ? ip6_dst_idev(skb_dst(skb)) : __in6_dev_get(skb->dev);
 }
 
 /* Router Alert as of RFC 2711 */
@@ -581,7 +581,7 @@ static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff)
 {
        const unsigned char *nh = skb_network_header(skb);
        u32 pkt_len;
-       struct net *net = dev_net(skb->dst->dev);
+       struct net *net = dev_net(skb_dst(skb)->dev);
 
        if (nh[optoff + 1] != 4 || (optoff & 3) != 2) {
                LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
index 3c3732d..cc4797d 100644 (file)
@@ -228,7 +228,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok)
                __inet6_csk_dst_store(sk, dst, NULL, NULL);
        }
 
-       skb->dst = dst_clone(dst);
+       skb_dst_set(skb, dst_clone(dst));
 
        /* Restore final destination back after routing done */
        ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
index bc1a920..c3a07d7 100644 (file)
@@ -48,7 +48,7 @@
 
 inline int ip6_rcv_finish( struct sk_buff *skb)
 {
-       if (skb->dst == NULL)
+       if (skb_dst(skb) == NULL)
                ip6_route_input(skb);
 
        return dst_input(skb);
@@ -91,7 +91,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
         * arrived via the sending interface (ethX), because of the
         * nature of scoping architecture. --yoshfuji
         */
-       IP6CB(skb)->iif = skb->dst ? ip6_dst_idev(skb->dst)->dev->ifindex : dev->ifindex;
+       IP6CB(skb)->iif = skb_dst(skb) ? ip6_dst_idev(skb_dst(skb))->dev->ifindex : dev->ifindex;
 
        if (unlikely(!pskb_may_pull(skb, sizeof(*hdr))))
                goto err;
@@ -161,7 +161,7 @@ static int ip6_input_finish(struct sk_buff *skb)
        int nexthdr, raw;
        u8 hash;
        struct inet6_dev *idev;
-       struct net *net = dev_net(skb->dst->dev);
+       struct net *net = dev_net(skb_dst(skb)->dev);
 
        /*
         *      Parse extension headers
@@ -169,7 +169,7 @@ static int ip6_input_finish(struct sk_buff *skb)
 
        rcu_read_lock();
 resubmit:
-       idev = ip6_dst_idev(skb->dst);
+       idev = ip6_dst_idev(skb_dst(skb));
        if (!pskb_pull(skb, skb_transport_offset(skb)))
                goto discard;
        nhoff = IP6CB(skb)->nhoff;
@@ -242,8 +242,8 @@ int ip6_mc_input(struct sk_buff *skb)
        struct ipv6hdr *hdr;
        int deliver;
 
-       IP6_UPD_PO_STATS_BH(dev_net(skb->dst->dev),
-                        ip6_dst_idev(skb->dst), IPSTATS_MIB_INMCAST,
+       IP6_UPD_PO_STATS_BH(dev_net(skb_dst(skb)->dev),
+                        ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INMCAST,
                         skb->len);
 
        hdr = ipv6_hdr(skb);
index 735a2bf..7c76e3d 100644 (file)
@@ -78,7 +78,7 @@ int __ip6_local_out(struct sk_buff *skb)
                len = 0;
        ipv6_hdr(skb)->payload_len = htons(len);
 
-       return nf_hook(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dst->dev,
+       return nf_hook(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb_dst(skb)->dev,
                       dst_output);
 }
 
@@ -96,7 +96,7 @@ EXPORT_SYMBOL_GPL(ip6_local_out);
 
 static int ip6_output_finish(struct sk_buff *skb)
 {
-       struct dst_entry *dst = skb->dst;
+       struct dst_entry *dst = skb_dst(skb);
 
        if (dst->hh)
                return neigh_hh_output(dst->hh, skb);
@@ -117,7 +117,7 @@ static int ip6_dev_loopback_xmit(struct sk_buff *newskb)
        __skb_pull(newskb, skb_network_offset(newskb));
        newskb->pkt_type = PACKET_LOOPBACK;
        newskb->ip_summed = CHECKSUM_UNNECESSARY;
-       WARN_ON(!newskb->dst);
+       WARN_ON(!skb_dst(newskb));
 
        netif_rx(newskb);
        return 0;
@@ -126,7 +126,7 @@ static int ip6_dev_loopback_xmit(struct sk_buff *newskb)
 
 static int ip6_output2(struct sk_buff *skb)
 {
-       struct dst_entry *dst = skb->dst;
+       struct dst_entry *dst = skb_dst(skb);
        struct net_device *dev = dst->dev;
 
        skb->protocol = htons(ETH_P_IPV6);
@@ -134,7 +134,7 @@ static int ip6_output2(struct sk_buff *skb)
 
        if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) {
                struct ipv6_pinfo* np = skb->sk ? inet6_sk(skb->sk) : NULL;
-               struct inet6_dev *idev = ip6_dst_idev(skb->dst);
+               struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
 
                if (!(dev->flags & IFF_LOOPBACK) && (!np || np->mc_loop) &&
                    ((mroute6_socket(dev_net(dev)) &&
@@ -172,21 +172,21 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
        struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL;
 
        return (np && np->pmtudisc == IPV6_PMTUDISC_PROBE) ?
-              skb->dst->dev->mtu : dst_mtu(skb->dst);
+              skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
 }
 
 int ip6_output(struct sk_buff *skb)
 {
-       struct inet6_dev *idev = ip6_dst_idev(skb->dst);
+       struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
        if (unlikely(idev->cnf.disable_ipv6)) {
-               IP6_INC_STATS(dev_net(skb->dst->dev), idev,
+               IP6_INC_STATS(dev_net(skb_dst(skb)->dev), idev,
                              IPSTATS_MIB_OUTDISCARDS);
                kfree_skb(skb);
                return 0;
        }
 
        if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
-                               dst_allfrag(skb->dst))
+                               dst_allfrag(skb_dst(skb)))
                return ip6_fragment(skb, ip6_output2);
        else
                return ip6_output2(skb);
@@ -202,7 +202,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
        struct net *net = sock_net(sk);
        struct ipv6_pinfo *np = inet6_sk(sk);
        struct in6_addr *first_hop = &fl->fl6_dst;
-       struct dst_entry *dst = skb->dst;
+       struct dst_entry *dst = skb_dst(skb);
        struct ipv6hdr *hdr;
        u8  proto = fl->proto;
        int seg_len = skb->len;
@@ -222,7 +222,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
                if (skb_headroom(skb) < head_room) {
                        struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room);
                        if (skb2 == NULL) {
-                               IP6_INC_STATS(net, ip6_dst_idev(skb->dst),
+                               IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
                                              IPSTATS_MIB_OUTDISCARDS);
                                kfree_skb(skb);
                                return -ENOBUFS;
@@ -276,7 +276,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
 
        mtu = dst_mtu(dst);
        if ((skb->len <= mtu) || skb->local_df || skb_is_gso(skb)) {
-               IP6_UPD_PO_STATS(net, ip6_dst_idev(skb->dst),
+               IP6_UPD_PO_STATS(net, ip6_dst_idev(skb_dst(skb)),
                              IPSTATS_MIB_OUT, skb->len);
                return NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,
                                dst_output);
@@ -286,7 +286,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
                printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n");
        skb->dev = dst->dev;
        icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
-       IP6_INC_STATS(net, ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGFAILS);
+       IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS);
        kfree_skb(skb);
        return -EMSGSIZE;
 }
@@ -416,7 +416,7 @@ static inline int ip6_forward_finish(struct sk_buff *skb)
 
 int ip6_forward(struct sk_buff *skb)
 {
-       struct dst_entry *dst = skb->dst;
+       struct dst_entry *dst = skb_dst(skb);
        struct ipv6hdr *hdr = ipv6_hdr(skb);
        struct inet6_skb_parm *opt = IP6CB(skb);
        struct net *net = dev_net(dst->dev);
@@ -485,7 +485,7 @@ int ip6_forward(struct sk_buff *skb)
                IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS);
                goto drop;
        }
-       dst = skb->dst;
+       dst = skb_dst(skb);
 
        /* IPv6 specs say nothing about it, but it is clear that we cannot
           send redirects to source routed frames.
@@ -566,8 +566,8 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
        to->pkt_type = from->pkt_type;
        to->priority = from->priority;
        to->protocol = from->protocol;
-       dst_release(to->dst);
-       to->dst = dst_clone(from->dst);
+       skb_dst_drop(to);
+       skb_dst_set(to, dst_clone(skb_dst(from)));
        to->dev = from->dev;
        to->mark = from->mark;
 
@@ -624,7 +624,7 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
 static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 {
        struct sk_buff *frag;
-       struct rt6_info *rt = (struct rt6_info*)skb->dst;
+       struct rt6_info *rt = (struct rt6_info*)skb_dst(skb);
        struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL;
        struct ipv6hdr *tmp_hdr;
        struct frag_hdr *fh;
@@ -632,7 +632,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
        __be32 frag_id = 0;
        int ptr, offset = 0, err=0;
        u8 *prevhdr, nexthdr = 0;
-       struct net *net = dev_net(skb->dst->dev);
+       struct net *net = dev_net(skb_dst(skb)->dev);
 
        hlen = ip6_find_1stfragopt(skb, &prevhdr);
        nexthdr = *prevhdr;
@@ -644,9 +644,9 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
         * check should be redundant, but it's free.)
         */
        if (!skb->local_df) {
-               skb->dev = skb->dst->dev;
+               skb->dev = skb_dst(skb)->dev;
                icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
-               IP6_INC_STATS(net, ip6_dst_idev(skb->dst),
+               IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
                              IPSTATS_MIB_FRAGFAILS);
                kfree_skb(skb);
                return -EMSGSIZE;
@@ -658,7 +658,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
        }
        mtu -= hlen + sizeof(struct frag_hdr);
 
-       if (skb_shinfo(skb)->frag_list) {
+       if (skb_has_frags(skb)) {
                int first_len = skb_pagelen(skb);
                int truesizes = 0;
 
@@ -667,7 +667,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
                    skb_cloned(skb))
                        goto slow_path;
 
-               for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) {
+               skb_walk_frags(skb, frag) {
                        /* Correct geometry. */
                        if (frag->len > mtu ||
                            ((frag->len & 7) && frag->next) ||
@@ -680,7 +680,6 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 
                        BUG_ON(frag->sk);
                        if (skb->sk) {
-                               sock_hold(skb->sk);
                                frag->sk = skb->sk;
                                frag->destructor = sock_wfree;
                                truesizes += frag->truesize;
@@ -690,13 +689,13 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
                err = 0;
                offset = 0;
                frag = skb_shinfo(skb)->frag_list;
-               skb_shinfo(skb)->frag_list = NULL;
+               skb_frag_list_init(skb);
                /* BUILD HEADER */
 
                *prevhdr = NEXTHDR_FRAGMENT;
                tmp_hdr = kmemdup(skb_network_header(skb), hlen, GFP_ATOMIC);
                if (!tmp_hdr) {
-                       IP6_INC_STATS(net, ip6_dst_idev(skb->dst),
+                       IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
                                      IPSTATS_MIB_FRAGFAILS);
                        return -ENOMEM;
                }
@@ -809,7 +808,7 @@ slow_path:
 
                if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_ALLOCATED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) {
                        NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n");
-                       IP6_INC_STATS(net, ip6_dst_idev(skb->dst),
+                       IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
                                      IPSTATS_MIB_FRAGFAILS);
                        err = -ENOMEM;
                        goto fail;
@@ -873,16 +872,16 @@ slow_path:
                if (err)
                        goto fail;
 
-               IP6_INC_STATS(net, ip6_dst_idev(skb->dst),
+               IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
                              IPSTATS_MIB_FRAGCREATES);
        }
-       IP6_INC_STATS(net, ip6_dst_idev(skb->dst),
+       IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
                      IPSTATS_MIB_FRAGOKS);
        kfree_skb(skb);
        return err;
 
 fail:
-       IP6_INC_STATS(net, ip6_dst_idev(skb->dst),
+       IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
                      IPSTATS_MIB_FRAGFAILS);
        kfree_skb(skb);
        return err;
@@ -1516,10 +1515,10 @@ int ip6_push_pending_frames(struct sock *sk)
        skb->priority = sk->sk_priority;
        skb->mark = sk->sk_mark;
 
-       skb->dst = dst_clone(&rt->u.dst);
+       skb_dst_set(skb, dst_clone(&rt->u.dst));
        IP6_UPD_PO_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len);
        if (proto == IPPROTO_ICMPV6) {
-               struct inet6_dev *idev = ip6_dst_idev(skb->dst);
+               struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
 
                ICMP6MSGOUT_INC_STATS_BH(net, idev, icmp6_hdr(skb)->icmp6_type);
                ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTMSGS);
@@ -1545,8 +1544,8 @@ void ip6_flush_pending_frames(struct sock *sk)
        struct sk_buff *skb;
 
        while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) {
-               if (skb->dst)
-                       IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb->dst),
+               if (skb_dst(skb))
+                       IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb_dst(skb)),
                                      IPSTATS_MIB_OUTDISCARDS);
                kfree_skb(skb);
        }
index af256d4..404d16a 100644 (file)
@@ -532,8 +532,8 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        if (!skb2)
                return 0;
 
-       dst_release(skb2->dst);
-       skb2->dst = NULL;
+       skb_dst_drop(skb2);
+
        skb_pull(skb2, offset);
        skb_reset_network_header(skb2);
        eiph = ip_hdr(skb2);
@@ -560,21 +560,21 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                        ip_rt_put(rt);
                        goto out;
                }
-               skb2->dst = (struct dst_entry *)rt;
+               skb_dst_set(skb2, (struct dst_entry *)rt);
        } else {
                ip_rt_put(rt);
                if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos,
                                   skb2->dev) ||
-                   skb2->dst->dev->type != ARPHRD_TUNNEL)
+                   skb_dst(skb2)->dev->type != ARPHRD_TUNNEL)
                        goto out;
        }
 
        /* change mtu on this route */
        if (rel_type == ICMP_DEST_UNREACH && rel_code == ICMP_FRAG_NEEDED) {
-               if (rel_info > dst_mtu(skb2->dst))
+               if (rel_info > dst_mtu(skb_dst(skb2)))
                        goto out;
 
-               skb2->dst->ops->update_pmtu(skb2->dst, rel_info);
+               skb_dst(skb2)->ops->update_pmtu(skb_dst(skb2), rel_info);
        }
 
        icmp_send(skb2, rel_type, rel_code, htonl(rel_info));
@@ -606,8 +606,7 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                if (!skb2)
                        return 0;
 
-               dst_release(skb2->dst);
-               skb2->dst = NULL;
+               skb_dst_drop(skb2);
                skb_pull(skb2, offset);
                skb_reset_network_header(skb2);
 
@@ -720,8 +719,7 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
                skb->pkt_type = PACKET_HOST;
                memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
                skb->dev = t->dev;
-               dst_release(skb->dst);
-               skb->dst = NULL;
+               skb_dst_drop(skb);
                nf_reset(skb);
 
                dscp_ecn_decapsulate(t, ipv6h, skb);
@@ -885,8 +883,8 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
        }
        if (mtu < IPV6_MIN_MTU)
                mtu = IPV6_MIN_MTU;
-       if (skb->dst)
-               skb->dst->ops->update_pmtu(skb->dst, mtu);
+       if (skb_dst(skb))
+               skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
        if (skb->len > mtu) {
                *pmtu = mtu;
                err = -EMSGSIZE;
@@ -910,8 +908,8 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
                kfree_skb(skb);
                skb = new_skb;
        }
-       dst_release(skb->dst);
-       skb->dst = dst_clone(dst);
+       skb_dst_drop(skb);
+       skb_dst_set(skb, dst_clone(dst));
 
        skb->transport_header = skb->network_header;
 
index 228be55..a35d8fc 100644 (file)
@@ -398,10 +398,9 @@ static int pim6_rcv(struct sk_buff *skb)
        skb->protocol = htons(ETH_P_IPV6);
        skb->ip_summed = 0;
        skb->pkt_type = PACKET_HOST;
-       dst_release(skb->dst);
+       skb_dst_drop(skb);
        reg_dev->stats.rx_bytes += skb->len;
        reg_dev->stats.rx_packets++;
-       skb->dst = NULL;
        nf_reset(skb);
        netif_rx(skb);
        dev_put(reg_dev);
@@ -849,7 +848,7 @@ static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, mifi_t mifi,
        ipv6_addr_copy(&msg->im6_src, &ipv6_hdr(pkt)->saddr);
        ipv6_addr_copy(&msg->im6_dst, &ipv6_hdr(pkt)->daddr);
 
-       skb->dst = dst_clone(pkt->dst);
+       skb_dst_set(skb, dst_clone(skb_dst(pkt)));
        skb->ip_summed = CHECKSUM_UNNECESSARY;
        }
 
@@ -1487,7 +1486,7 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
 
 static inline int ip6mr_forward2_finish(struct sk_buff *skb)
 {
-       IP6_INC_STATS_BH(dev_net(skb->dst->dev), ip6_dst_idev(skb->dst),
+       IP6_INC_STATS_BH(dev_net(skb_dst(skb)->dev), ip6_dst_idev(skb_dst(skb)),
                         IPSTATS_MIB_OUTFORWDATAGRAMS);
        return dst_output(skb);
 }
@@ -1532,8 +1531,8 @@ static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi)
        if (!dst)
                goto out_free;
 
-       dst_release(skb->dst);
-       skb->dst = dst;
+       skb_dst_drop(skb);
+       skb_dst_set(skb, dst);
 
        /*
         * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
@@ -1722,7 +1721,7 @@ int ip6mr_get_route(struct net *net,
 {
        int err;
        struct mfc6_cache *cache;
-       struct rt6_info *rt = (struct rt6_info *)skb->dst;
+       struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
 
        read_lock(&mrt_lock);
        cache = ip6mr_cache_find(net, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
index 4b48819..4b264ed 100644 (file)
@@ -1448,6 +1448,7 @@ static void mld_sendpack(struct sk_buff *skb)
        struct net *net = dev_net(skb->dev);
        int err;
        struct flowi fl;
+       struct dst_entry *dst;
 
        IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
 
@@ -1459,9 +1460,9 @@ static void mld_sendpack(struct sk_buff *skb)
                IPPROTO_ICMPV6, csum_partial(skb_transport_header(skb),
                                             mldlen, 0));
 
-       skb->dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr);
+       dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr);
 
-       if (!skb->dst) {
+       if (!dst) {
                err = -ENOMEM;
                goto err_out;
        }
@@ -1470,7 +1471,8 @@ static void mld_sendpack(struct sk_buff *skb)
                         &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
                         skb->dev->ifindex);
 
-       err = xfrm_lookup(net, &skb->dst, &fl, NULL, 0);
+       err = xfrm_lookup(net, &dst, &fl, NULL, 0);
+       skb_dst_set(skb, dst);
        if (err)
                goto err_out;
 
@@ -1775,6 +1777,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
                     IPV6_TLV_ROUTERALERT, 2, 0, 0,
                     IPV6_TLV_PADN, 0 };
        struct flowi fl;
+       struct dst_entry *dst;
 
        if (type == ICMPV6_MGM_REDUCTION)
                snd_addr = &in6addr_linklocal_allrouters;
@@ -1828,8 +1831,8 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
 
        idev = in6_dev_get(skb->dev);
 
-       skb->dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr);
-       if (!skb->dst) {
+       dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr);
+       if (!dst) {
                err = -ENOMEM;
                goto err_out;
        }
@@ -1838,11 +1841,11 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
                         &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
                         skb->dev->ifindex);
 
-       err = xfrm_lookup(net, &skb->dst, &fl, NULL, 0);
+       err = xfrm_lookup(net, &dst, &fl, NULL, 0);
        if (err)
                goto err_out;
 
-
+       skb_dst_set(skb, dst);
        err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev,
                      dst_output);
 out:
index e09f12e..9eb68e9 100644 (file)
@@ -465,8 +465,8 @@ struct sk_buff *ndisc_build_skb(struct net_device *dev,
                                  1, &err);
        if (!skb) {
                ND_PRINTK0(KERN_ERR
-                          "ICMPv6 ND: %s() failed to allocate an skb.\n",
-                          __func__);
+                          "ICMPv6 ND: %s() failed to allocate an skb, err=%d.\n",
+                          __func__, err);
                return NULL;
        }
 
@@ -530,7 +530,7 @@ void ndisc_send_skb(struct sk_buff *skb,
                return;
        }
 
-       skb->dst = dst;
+       skb_dst_set(skb, dst);
 
        idev = in6_dev_get(dst->dev);
        IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
@@ -1562,8 +1562,8 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
                                   1, &err);
        if (buff == NULL) {
                ND_PRINTK0(KERN_ERR
-                          "ICMPv6 Redirect: %s() failed to allocate an skb.\n",
-                          __func__);
+                          "ICMPv6 Redirect: %s() failed to allocate an skb, err=%d.\n",
+                          __func__, err);
                goto release;
        }
 
@@ -1612,7 +1612,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
                                             len, IPPROTO_ICMPV6,
                                             csum_partial(icmph, len, 0));
 
-       buff->dst = dst;
+       skb_dst_set(buff, dst);
        idev = in6_dev_get(dst->dev);
        IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
        err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev,
index 834cea6..d5ed92b 100644 (file)
@@ -12,7 +12,7 @@
 
 int ip6_route_me_harder(struct sk_buff *skb)
 {
-       struct net *net = dev_net(skb->dst->dev);
+       struct net *net = dev_net(skb_dst(skb)->dev);
        struct ipv6hdr *iph = ipv6_hdr(skb);
        struct dst_entry *dst;
        struct flowi fl = {
@@ -28,9 +28,15 @@ int ip6_route_me_harder(struct sk_buff *skb)
 
 #ifdef CONFIG_XFRM
        if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
-           xfrm_decode_session(skb, &fl, AF_INET6) == 0)
-               if (xfrm_lookup(net, &skb->dst, &fl, skb->sk, 0))
+           xfrm_decode_session(skb, &fl, AF_INET6) == 0) {
+               struct dst_entry *dst2 = skb_dst(skb);
+
+               if (xfrm_lookup(net, &dst2, &fl, skb->sk, 0)) {
+                       skb_dst_set(skb, NULL);
                        return -1;
+               }
+               skb_dst_set(skb, dst2);
+       }
 #endif
 
        if (dst->error) {
@@ -41,9 +47,9 @@ int ip6_route_me_harder(struct sk_buff *skb)
        }
 
        /* Drop old route. */
-       dst_release(skb->dst);
+       skb_dst_drop(skb);
 
-       skb->dst = dst;
+       skb_dst_set(skb, dst);
        return 0;
 }
 EXPORT_SYMBOL(ip6_route_me_harder);
index 5a2d0a4..5a7f00c 100644 (file)
@@ -112,7 +112,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)
                return;
        }
 
-       nskb->dst = dst;
+       skb_dst_set(nskb, dst);
 
        skb_reserve(nskb, hh_len + dst->header_len);
 
index 058a5e4..f3aba25 100644 (file)
@@ -409,7 +409,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
        /* If the first fragment is fragmented itself, we split
         * it to two chunks: the first with data and paged part
         * and the second, holding only fragments. */
-       if (skb_shinfo(head)->frag_list) {
+       if (skb_has_frags(head)) {
                struct sk_buff *clone;
                int i, plen = 0;
 
@@ -420,7 +420,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
                clone->next = head->next;
                head->next = clone;
                skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;
-               skb_shinfo(head)->frag_list = NULL;
+               skb_frag_list_init(head);
                for (i=0; i<skb_shinfo(head)->nr_frags; i++)
                        plen += skb_shinfo(head)->frags[i].size;
                clone->len = clone->data_len = head->data_len - plen;
index e99307f..36a090d 100644 (file)
@@ -625,7 +625,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
 
        skb->priority = sk->sk_priority;
        skb->mark = sk->sk_mark;
-       skb->dst = dst_clone(&rt->u.dst);
+       skb_dst_set(skb, dst_clone(&rt->u.dst));
 
        skb_put(skb, length);
        skb_reset_network_header(skb);
index e9ac7a1..2642a41 100644 (file)
@@ -267,7 +267,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
        struct sk_buff *prev, *next;
        struct net_device *dev;
        int offset, end;
-       struct net *net = dev_net(skb->dst->dev);
+       struct net *net = dev_net(skb_dst(skb)->dev);
 
        if (fq->q.last_in & INET_FRAG_COMPLETE)
                goto err;
@@ -277,7 +277,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
                        ((u8 *)(fhdr + 1) - (u8 *)(ipv6_hdr(skb) + 1)));
 
        if ((unsigned int)end > IPV6_MAXPLEN) {
-               IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst),
+               IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
                                 IPSTATS_MIB_INHDRERRORS);
                icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
                                  ((u8 *)&fhdr->frag_off -
@@ -310,7 +310,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
                        /* RFC2460 says always send parameter problem in
                         * this case. -DaveM
                         */
-                       IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst),
+                       IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
                                         IPSTATS_MIB_INHDRERRORS);
                        icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
                                          offsetof(struct ipv6hdr, payload_len));
@@ -434,7 +434,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
        return -1;
 
 err:
-       IP6_INC_STATS(net, ip6_dst_idev(skb->dst),
+       IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
                      IPSTATS_MIB_REASMFAILS);
        kfree_skb(skb);
        return -1;
@@ -494,7 +494,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
        /* If the first fragment is fragmented itself, we split
         * it to two chunks: the first with data and paged part
         * and the second, holding only fragments. */
-       if (skb_shinfo(head)->frag_list) {
+       if (skb_has_frags(head)) {
                struct sk_buff *clone;
                int i, plen = 0;
 
@@ -503,7 +503,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
                clone->next = head->next;
                head->next = clone;
                skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;
-               skb_shinfo(head)->frag_list = NULL;
+               skb_frag_list_init(head);
                for (i=0; i<skb_shinfo(head)->nr_frags; i++)
                        plen += skb_shinfo(head)->frags[i].size;
                clone->len = clone->data_len = head->data_len - plen;
@@ -576,9 +576,9 @@ static int ipv6_frag_rcv(struct sk_buff *skb)
        struct frag_hdr *fhdr;
        struct frag_queue *fq;
        struct ipv6hdr *hdr = ipv6_hdr(skb);
-       struct net *net = dev_net(skb->dst->dev);
+       struct net *net = dev_net(skb_dst(skb)->dev);
 
-       IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMREQDS);
+       IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMREQDS);
 
        /* Jumbo payload inhibits frag. header */
        if (hdr->payload_len==0)
@@ -595,17 +595,17 @@ static int ipv6_frag_rcv(struct sk_buff *skb)
                /* It is not a fragmented frame */
                skb->transport_header += sizeof(struct frag_hdr);
                IP6_INC_STATS_BH(net,
-                                ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMOKS);
+                                ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMOKS);
 
                IP6CB(skb)->nhoff = (u8 *)fhdr - skb_network_header(skb);
                return 1;
        }
 
        if (atomic_read(&net->ipv6.frags.mem) > net->ipv6.frags.high_thresh)
-               ip6_evictor(net, ip6_dst_idev(skb->dst));
+               ip6_evictor(net, ip6_dst_idev(skb_dst(skb)));
 
        if ((fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr,
-                         ip6_dst_idev(skb->dst))) != NULL) {
+                         ip6_dst_idev(skb_dst(skb)))) != NULL) {
                int ret;
 
                spin_lock(&fq->q.lock);
@@ -617,12 +617,12 @@ static int ipv6_frag_rcv(struct sk_buff *skb)
                return ret;
        }
 
-       IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMFAILS);
+       IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMFAILS);
        kfree_skb(skb);
        return -1;
 
 fail_hdr:
-       IP6_INC_STATS(net, ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
+       IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS);
        icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb_network_header_len(skb));
        return -1;
 }
index 032a5ec..658293e 100644 (file)
@@ -800,7 +800,7 @@ void ip6_route_input(struct sk_buff *skb)
        if (rt6_need_strict(&iph->daddr) && skb->dev->type != ARPHRD_PIMREG)
                flags |= RT6_LOOKUP_F_IFACE;
 
-       skb->dst = fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input);
+       skb_dst_set(skb, fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input));
 }
 
 static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
@@ -911,7 +911,7 @@ static void ip6_link_failure(struct sk_buff *skb)
 
        icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev);
 
-       rt = (struct rt6_info *) skb->dst;
+       rt = (struct rt6_info *) skb_dst(skb);
        if (rt) {
                if (rt->rt6i_flags&RTF_CACHE) {
                        dst_set_expires(&rt->u.dst, 0);
@@ -1868,7 +1868,7 @@ int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
 static int ip6_pkt_drop(struct sk_buff *skb, int code, int ipstats_mib_noroutes)
 {
        int type;
-       struct dst_entry *dst = skb->dst;
+       struct dst_entry *dst = skb_dst(skb);
        switch (ipstats_mib_noroutes) {
        case IPSTATS_MIB_INNOROUTES:
                type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
@@ -1895,7 +1895,7 @@ static int ip6_pkt_discard(struct sk_buff *skb)
 
 static int ip6_pkt_discard_out(struct sk_buff *skb)
 {
-       skb->dev = skb->dst->dev;
+       skb->dev = skb_dst(skb)->dev;
        return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
 }
 
@@ -1908,7 +1908,7 @@ static int ip6_pkt_prohibit(struct sk_buff *skb)
 
 static int ip6_pkt_prohibit_out(struct sk_buff *skb)
 {
-       skb->dev = skb->dst->dev;
+       skb->dev = skb_dst(skb)->dev;
        return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
 }
 
@@ -2366,7 +2366,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
        skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
 
        rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl);
-       skb->dst = &rt->u.dst;
+       skb_dst_set(skb, &rt->u.dst);
 
        err = rt6_fill_node(net, skb, rt, &fl.fl6_dst, &fl.fl6_src, iif,
                            RTM_NEWROUTE, NETLINK_CB(in_skb).pid,
index b3a59bd..68e5230 100644 (file)
@@ -575,8 +575,7 @@ static int ipip6_rcv(struct sk_buff *skb)
                tunnel->dev->stats.rx_packets++;
                tunnel->dev->stats.rx_bytes += skb->len;
                skb->dev = tunnel->dev;
-               dst_release(skb->dst);
-               skb->dst = NULL;
+               skb_dst_drop(skb);
                nf_reset(skb);
                ipip6_ecn_decapsulate(iph, skb);
                netif_rx(skb);
@@ -638,8 +637,8 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        if (dev->priv_flags & IFF_ISATAP) {
                struct neighbour *neigh = NULL;
 
-               if (skb->dst)
-                       neigh = skb->dst->neighbour;
+               if (skb_dst(skb))
+                       neigh = skb_dst(skb)->neighbour;
 
                if (neigh == NULL) {
                        if (net_ratelimit())
@@ -663,8 +662,8 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        if (!dst) {
                struct neighbour *neigh = NULL;
 
-               if (skb->dst)
-                       neigh = skb->dst->neighbour;
+               if (skb_dst(skb))
+                       neigh = skb_dst(skb)->neighbour;
 
                if (neigh == NULL) {
                        if (net_ratelimit())
@@ -714,7 +713,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        if (tiph->frag_off)
                mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr);
        else
-               mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu;
+               mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu;
 
        if (mtu < 68) {
                stats->collisions++;
@@ -723,8 +722,8 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        }
        if (mtu < IPV6_MIN_MTU)
                mtu = IPV6_MIN_MTU;
-       if (tunnel->parms.iph.daddr && skb->dst)
-               skb->dst->ops->update_pmtu(skb->dst, mtu);
+       if (tunnel->parms.iph.daddr && skb_dst(skb))
+               skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
 
        if (skb->len > mtu) {
                icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev);
@@ -768,8 +767,8 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        skb_reset_network_header(skb);
        memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
        IPCB(skb)->flags = 0;
-       dst_release(skb->dst);
-       skb->dst = &rt->u.dst;
+       skb_dst_drop(skb);
+       skb_dst_set(skb, &rt->u.dst);
 
        /*
         *      Push down and install the IPIP header.
index ea37741..53b6a41 100644 (file)
@@ -981,9 +981,10 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
        struct tcphdr *th = tcp_hdr(skb), *t1;
        struct sk_buff *buff;
        struct flowi fl;
-       struct net *net = dev_net(skb->dst->dev);
+       struct net *net = dev_net(skb_dst(skb)->dev);
        struct sock *ctl_sk = net->ipv6.tcp_sk;
        unsigned int tot_len = sizeof(struct tcphdr);
+       struct dst_entry *dst;
        __be32 *topt;
 
        if (ts)
@@ -1052,8 +1053,9 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
         * Underlying function will use this to retrieve the network
         * namespace
         */
-       if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) {
-               if (xfrm_lookup(net, &buff->dst, &fl, NULL, 0) >= 0) {
+       if (!ip6_dst_lookup(ctl_sk, &dst, &fl)) {
+               if (xfrm_lookup(net, &dst, &fl, NULL, 0) >= 0) {
+                       skb_dst_set(buff, dst);
                        ip6_xmit(ctl_sk, buff, &fl, NULL, 0);
                        TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
                        if (rst)
index 8905712..fc333d8 100644 (file)
@@ -177,10 +177,9 @@ static struct sock *__udp6_lib_lookup_skb(struct sk_buff *skb,
 
        if (unlikely(sk = skb_steal_sock(skb)))
                return sk;
-       else
-               return __udp6_lib_lookup(dev_net(skb->dst->dev), &iph->saddr, sport,
-                                        &iph->daddr, dport, inet6_iif(skb),
-                                        udptable);
+       return __udp6_lib_lookup(dev_net(skb_dst(skb)->dev), &iph->saddr, sport,
+                                &iph->daddr, dport, inet6_iif(skb),
+                                udptable);
 }
 
 /*
index e20529b..3927832 100644 (file)
@@ -31,7 +31,7 @@ static inline void ipip6_ecn_decapsulate(struct sk_buff *skb)
  */
 static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
 {
-       struct dst_entry *dst = skb->dst;
+       struct dst_entry *dst = skb_dst(skb);
        struct ipv6hdr *top_iph;
        int dsfield;
 
@@ -45,7 +45,7 @@ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
 
        memcpy(top_iph->flow_lbl, XFRM_MODE_SKB_CB(skb)->flow_lbl,
               sizeof(top_iph->flow_lbl));
-       top_iph->nexthdr = xfrm_af2proto(skb->dst->ops->family);
+       top_iph->nexthdr = xfrm_af2proto(skb_dst(skb)->ops->family);
 
        dsfield = XFRM_MODE_SKB_CB(skb)->tos;
        dsfield = INET_ECN_encapsulate(dsfield, dsfield);
index 5ee5a03..c4f4eef 100644 (file)
@@ -30,7 +30,7 @@ EXPORT_SYMBOL(xfrm6_find_1stfragopt);
 static int xfrm6_tunnel_check_size(struct sk_buff *skb)
 {
        int mtu, ret = 0;
-       struct dst_entry *dst = skb->dst;
+       struct dst_entry *dst = skb_dst(skb);
 
        mtu = dst_mtu(dst);
        if (mtu < IPV6_MIN_MTU)
@@ -90,6 +90,6 @@ static int xfrm6_output_finish(struct sk_buff *skb)
 
 int xfrm6_output(struct sk_buff *skb)
 {
-       return NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, skb, NULL, skb->dst->dev,
+       return NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, skb, NULL, skb_dst(skb)->dev,
                       xfrm6_output_finish);
 }
index 2562ebc..7af2e74 100644 (file)
@@ -982,17 +982,12 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
 {
        struct sk_buff *tx_skb;
        struct sk_buff *skb;
-       int count;
 
        IRDA_ASSERT(self != NULL, return;);
        IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
-       /* Initialize variables */
-       count = skb_queue_len(&self->wx_list);
-
        /*  Resend unacknowledged frame(s) */
-       skb = skb_peek(&self->wx_list);
-       while (skb != NULL) {
+       skb_queue_walk(&self->wx_list, skb) {
                irlap_wait_min_turn_around(self, &self->qos_tx);
 
                /* We copy the skb to be retransmitted since we will have to
@@ -1011,21 +1006,12 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
                /*
                 *  Set poll bit on the last frame retransmitted
                 */
-               if (count-- == 1)
+               if (skb_queue_is_last(&self->wx_list, skb))
                        tx_skb->data[1] |= PF_BIT; /* Set p/f bit */
                else
                        tx_skb->data[1] &= ~PF_BIT; /* Clear p/f bit */
 
                irlap_send_i_frame(self, tx_skb, command);
-
-               /*
-                *  If our skb is the last buffer in the list, then
-                *  we are finished, if not, move to the next sk-buffer
-                */
-               if (skb == skb_peek_tail(&self->wx_list))
-                       skb = NULL;
-               else
-                       skb = skb->next;
        }
 #if 0 /* Not yet */
        /*
index 3477624..c6bab39 100644 (file)
@@ -79,10 +79,6 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
 
        if (unlikely(!ev->ind_prim && !ev->cfm_prim)) {
                /* indicate or confirm not required */
-               /* XXX this is not very pretty, perhaps we should store
-                * XXX indicate/confirm-needed state in the llc_conn_state_ev
-                * XXX control block of the SKB instead? -DaveM
-                */
                if (!skb->next)
                        goto out_kfree_skb;
                goto out_skb_put;
index 9cbf545..ba2643a 100644 (file)
@@ -1,16 +1,19 @@
 config MAC80211
        tristate "Generic IEEE 802.11 Networking Stack (mac80211)"
+       depends on CFG80211
        select CRYPTO
        select CRYPTO_ECB
        select CRYPTO_ARC4
        select CRYPTO_AES
        select CRC32
        select WIRELESS_EXT
-       select CFG80211
        ---help---
          This option enables the hardware independent IEEE 802.11
          networking stack.
 
+comment "CFG80211 needs to be enabled for MAC80211"
+       depends on CFG80211=n
+
 config MAC80211_DEFAULT_PS
        bool "enable powersave by default"
        depends on MAC80211
index 43d00ff..9e5762a 100644 (file)
@@ -132,6 +132,9 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
 
        state = &sta->ampdu_mlme.tid_state_tx[tid];
 
+       if (*state == HT_AGG_STATE_OPERATIONAL)
+               sta->ampdu_mlme.addba_req_num[tid] = 0;
+
        *state = HT_AGG_STATE_REQ_STOP_BA_MSK |
                (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
 
@@ -337,6 +340,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
                         sta->ampdu_mlme.tid_tx[tid]->dialog_token,
                         sta->ampdu_mlme.tid_tx[tid]->ssn,
                         0x40, 5000);
+       sta->ampdu_mlme.addba_req_num[tid]++;
        /* activate the timer for the recipient's addBA response */
        sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
                                jiffies + ADDBA_RESP_INTERVAL;
@@ -606,7 +610,6 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
 
        *state = HT_AGG_STATE_IDLE;
        /* from now on packets are no longer put onto sta->pending */
-       sta->ampdu_mlme.addba_req_num[tid] = 0;
        kfree(sta->ampdu_mlme.tid_tx[tid]);
        sta->ampdu_mlme.tid_tx[tid] = NULL;
 
@@ -689,7 +692,6 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
 
                sta->ampdu_mlme.addba_req_num[tid] = 0;
        } else {
-               sta->ampdu_mlme.addba_req_num[tid]++;
                ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR);
        }
        spin_unlock_bh(&sta->lock);
index 77e9ff5..3f47276 100644 (file)
@@ -664,18 +664,19 @@ static void sta_apply_parameters(struct ieee80211_local *local,
        spin_unlock_bh(&sta->lock);
 
        /*
+        * cfg80211 validates this (1-2007) and allows setting the AID
+        * only when creating a new station entry
+        */
+       if (params->aid)
+               sta->sta.aid = params->aid;
+
+       /*
         * FIXME: updating the following information is racy when this
         *        function is called from ieee80211_change_station().
         *        However, all this information should be static so
         *        maybe we should just reject attemps to change it.
         */
 
-       if (params->aid) {
-               sta->sta.aid = params->aid;
-               if (sta->sta.aid > IEEE80211_MAX_AID)
-                       sta->sta.aid = 0; /* XXX: should this be an error? */
-       }
-
        if (params->listen_interval >= 0)
                sta->listen_interval = params->listen_interval;
 
@@ -1121,8 +1122,8 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
        p.txop = params->txop;
        if (drv_conf_tx(local, params->queue, &p)) {
                printk(KERN_DEBUG "%s: failed to set TX queue "
-                      "parameters for queue %d\n", local->mdev->name,
-                      params->queue);
+                      "parameters for queue %d\n",
+                      wiphy_name(local->hw.wiphy), params->queue);
                return -EINVAL;
        }
 
@@ -1255,7 +1256,7 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
                sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL;
 
        ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len);
-       if (ret)
+       if (ret && ret != -EALREADY)
                return ret;
 
        if (req->use_mfp) {
@@ -1333,6 +1334,53 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
        return 0;
 }
 
+static int ieee80211_set_tx_power(struct wiphy *wiphy,
+                                 enum tx_power_setting type, int dbm)
+{
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_channel *chan = local->hw.conf.channel;
+       u32 changes = 0;
+
+       switch (type) {
+       case TX_POWER_AUTOMATIC:
+               local->user_power_level = -1;
+               break;
+       case TX_POWER_LIMITED:
+               if (dbm < 0)
+                       return -EINVAL;
+               local->user_power_level = dbm;
+               break;
+       case TX_POWER_FIXED:
+               if (dbm < 0)
+                       return -EINVAL;
+               /* TODO: move to cfg80211 when it knows the channel */
+               if (dbm > chan->max_power)
+                       return -EINVAL;
+               local->user_power_level = dbm;
+               break;
+       }
+
+       ieee80211_hw_config(local, changes);
+
+       return 0;
+}
+
+static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm)
+{
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+
+       *dbm = local->hw.conf.power_level;
+
+       return 0;
+}
+
+static void ieee80211_rfkill_poll(struct wiphy *wiphy)
+{
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+
+       drv_rfkill_poll(local);
+}
+
 struct cfg80211_ops mac80211_config_ops = {
        .add_virtual_intf = ieee80211_add_iface,
        .del_virtual_intf = ieee80211_del_iface,
@@ -1372,4 +1420,7 @@ struct cfg80211_ops mac80211_config_ops = {
        .join_ibss = ieee80211_join_ibss,
        .leave_ibss = ieee80211_leave_ibss,
        .set_wiphy_params = ieee80211_set_wiphy_params,
+       .set_tx_power = ieee80211_set_tx_power,
+       .get_tx_power = ieee80211_get_tx_power,
+       .rfkill_poll = ieee80211_rfkill_poll,
 };
index 3912b53..b13446a 100644 (file)
@@ -181,4 +181,11 @@ static inline int drv_ampdu_action(struct ieee80211_local *local,
                                                sta, tid, ssn);
        return -EOPNOTSUPP;
 }
+
+
+static inline void drv_rfkill_poll(struct ieee80211_local *local)
+{
+       if (local->ops->rfkill_poll)
+               local->ops->rfkill_poll(&local->hw);
+}
 #endif /* __MAC80211_DRIVER_OPS */
index c088c46..4dbc289 100644 (file)
@@ -589,6 +589,7 @@ enum queue_stop_reason {
        IEEE80211_QUEUE_STOP_REASON_AGGREGATION,
        IEEE80211_QUEUE_STOP_REASON_SUSPEND,
        IEEE80211_QUEUE_STOP_REASON_PENDING,
+       IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
 };
 
 struct ieee80211_master_priv {
@@ -1121,6 +1122,10 @@ void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
                                    enum queue_stop_reason reason);
 void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
                                    enum queue_stop_reason reason);
+void ieee80211_add_pending_skb(struct ieee80211_local *local,
+                              struct sk_buff *skb);
+int ieee80211_add_pending_skbs(struct ieee80211_local *local,
+                              struct sk_buff_head *skbs);
 
 void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
                         u16 transaction, u16 auth_alg,
index 8c9f1c7..b7c8a44 100644 (file)
@@ -170,7 +170,7 @@ static int ieee80211_open(struct net_device *dev)
                        goto err_del_bss;
                /* we're brought up, everything changes */
                hw_reconf_flags = ~0;
-               ieee80211_led_radio(local, local->hw.conf.radio_enabled);
+               ieee80211_led_radio(local, true);
        }
 
        /*
@@ -560,7 +560,7 @@ static int ieee80211_stop(struct net_device *dev)
 
                drv_stop(local);
 
-               ieee80211_led_radio(local, 0);
+               ieee80211_led_radio(local, false);
 
                flush_workqueue(local->hw.workqueue);
 
index 6b7e92e..092a017 100644 (file)
@@ -289,16 +289,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
        drv_bss_info_changed(local, &sdata->vif,
                             &sdata->vif.bss_conf, changed);
 
-       /*
-        * DEPRECATED
-        *
-        * ~changed is just there to not do this at resume time
-        */
-       if (changed & BSS_CHANGED_BEACON_INT && ~changed) {
-               local->hw.conf.beacon_int = sdata->vif.bss_conf.beacon_int;
-               ieee80211_hw_config(local,
-                                   _IEEE80211_CONF_CHANGE_BEACON_INTERVAL);
-       }
+       /* DEPRECATED */
+       local->hw.conf.beacon_int = sdata->vif.bss_conf.beacon_int;
 }
 
 u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
@@ -377,60 +369,12 @@ static void ieee80211_tasklet_handler(unsigned long data)
        }
 }
 
-/* Remove added headers (e.g., QoS control), encryption header/MIC, etc. to
- * make a prepared TX frame (one that has been given to hw) to look like brand
- * new IEEE 802.11 frame that is ready to go through TX processing again.
- */
-static void ieee80211_remove_tx_extra(struct ieee80211_local *local,
-                                     struct ieee80211_key *key,
-                                     struct sk_buff *skb)
-{
-       unsigned int hdrlen, iv_len, mic_len;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-
-       hdrlen = ieee80211_hdrlen(hdr->frame_control);
-
-       if (!key)
-               goto no_key;
-
-       switch (key->conf.alg) {
-       case ALG_WEP:
-               iv_len = WEP_IV_LEN;
-               mic_len = WEP_ICV_LEN;
-               break;
-       case ALG_TKIP:
-               iv_len = TKIP_IV_LEN;
-               mic_len = TKIP_ICV_LEN;
-               break;
-       case ALG_CCMP:
-               iv_len = CCMP_HDR_LEN;
-               mic_len = CCMP_MIC_LEN;
-               break;
-       default:
-               goto no_key;
-       }
-
-       if (skb->len >= hdrlen + mic_len &&
-           !(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
-               skb_trim(skb, skb->len - mic_len);
-       if (skb->len >= hdrlen + iv_len) {
-               memmove(skb->data + iv_len, skb->data, hdrlen);
-               hdr = (struct ieee80211_hdr *)skb_pull(skb, iv_len);
-       }
-
-no_key:
-       if (ieee80211_is_data_qos(hdr->frame_control)) {
-               hdr->frame_control &= ~cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
-               memmove(skb->data + IEEE80211_QOS_CTL_LEN, skb->data,
-                       hdrlen - IEEE80211_QOS_CTL_LEN);
-               skb_pull(skb, IEEE80211_QOS_CTL_LEN);
-       }
-}
-
 static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
                                            struct sta_info *sta,
                                            struct sk_buff *skb)
 {
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
        sta->tx_filtered_count++;
 
        /*
@@ -472,16 +416,15 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
         */
        if (test_sta_flags(sta, WLAN_STA_PS) &&
            skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
-               ieee80211_remove_tx_extra(local, sta->key, skb);
                skb_queue_tail(&sta->tx_filtered, skb);
                return;
        }
 
-       if (!test_sta_flags(sta, WLAN_STA_PS) && !skb->requeue) {
+       if (!test_sta_flags(sta, WLAN_STA_PS) &&
+           !(info->flags & IEEE80211_TX_INTFL_RETRIED)) {
                /* Software retry the packet once */
-               skb->requeue = 1;
-               ieee80211_remove_tx_extra(local, sta->key, skb);
-               dev_queue_xmit(skb);
+               info->flags |= IEEE80211_TX_INTFL_RETRIED;
+               ieee80211_add_pending_skb(local, skb);
                return;
        }
 
@@ -735,9 +678,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
         * +-------------------------+
         *
         */
-       priv_size = ((sizeof(struct ieee80211_local) +
-                     NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST) +
-                   priv_data_len;
+       priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len;
 
        wiphy = wiphy_new(&mac80211_config_ops, priv_size);
 
@@ -754,9 +695,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 
        local->hw.wiphy = wiphy;
 
-       local->hw.priv = (char *)local +
-                        ((sizeof(struct ieee80211_local) +
-                          NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);
+       local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN);
 
        BUG_ON(!ops->tx);
        BUG_ON(!ops->start);
index 509469c..d779c57 100644 (file)
@@ -621,9 +621,6 @@ static void ieee80211_change_ps(struct ieee80211_local *local)
        struct ieee80211_conf *conf = &local->hw.conf;
 
        if (local->ps_sdata) {
-               if (!(local->ps_sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED))
-                       return;
-
                ieee80211_enable_ps(local, local->ps_sdata);
        } else if (conf->flags & IEEE80211_CONF_PS) {
                conf->flags &= ~IEEE80211_CONF_PS;
@@ -653,7 +650,9 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
                count++;
        }
 
-       if (count == 1 && found->u.mgd.powersave) {
+       if (count == 1 && found->u.mgd.powersave &&
+           (found->u.mgd.flags & IEEE80211_STA_ASSOCIATED) &&
+           !(found->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL)) {
                s32 beaconint_us;
 
                if (latency < 0)
@@ -793,13 +792,13 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
                       "cWmin=%d cWmax=%d txop=%d\n",
-                      local->mdev->name, queue, aci, acm, params.aifs, params.cw_min,
-                      params.cw_max, params.txop);
+                      wiphy_name(local->hw.wiphy), queue, aci, acm,
+                      params.aifs, params.cw_min, params.cw_max, params.txop);
 #endif
                if (drv_conf_tx(local, queue, &params) && local->ops->conf_tx)
                        printk(KERN_DEBUG "%s: failed to set TX queue "
-                              "parameters for queue %d\n", local->mdev->name,
-                              queue);
+                              "parameters for queue %d\n",
+                              wiphy_name(local->hw.wiphy), queue);
        }
 }
 
@@ -1322,6 +1321,11 @@ void ieee80211_beacon_loss_work(struct work_struct *work)
 #endif
 
        ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
+
+       mutex_lock(&sdata->local->iflist_mtx);
+       ieee80211_recalc_ps(sdata->local, -1);
+       mutex_unlock(&sdata->local->iflist_mtx);
+
        ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid,
                                 ifmgd->ssid_len, NULL, 0);
 
@@ -1342,6 +1346,7 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata)
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
        struct sta_info *sta;
+       unsigned long last_rx;
        bool disassoc = false;
 
        /* TODO: start monitoring current AP signal quality and number of
@@ -1358,17 +1363,21 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata)
                printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n",
                       sdata->dev->name, ifmgd->bssid);
                disassoc = true;
-               goto unlock;
+               rcu_read_unlock();
+               goto out;
        }
 
+       last_rx = sta->last_rx;
+       rcu_read_unlock();
+
        if ((ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) &&
-           time_after(jiffies, sta->last_rx + IEEE80211_PROBE_WAIT)) {
+           time_after(jiffies, last_rx + IEEE80211_PROBE_WAIT)) {
                printk(KERN_DEBUG "%s: no probe response from AP %pM "
                       "- disassociating\n",
                       sdata->dev->name, ifmgd->bssid);
                disassoc = true;
                ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
-               goto unlock;
+               goto out;
        }
 
        /*
@@ -1387,26 +1396,29 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata)
                }
 #endif
                ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
+               mutex_lock(&local->iflist_mtx);
+               ieee80211_recalc_ps(local, -1);
+               mutex_unlock(&local->iflist_mtx);
                ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid,
                                         ifmgd->ssid_len, NULL, 0);
                mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT);
-               goto unlock;
+               goto out;
        }
 
-       if (time_after(jiffies, sta->last_rx + IEEE80211_PROBE_IDLE_TIME)) {
+       if (time_after(jiffies, last_rx + IEEE80211_PROBE_IDLE_TIME)) {
                ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
+               mutex_lock(&local->iflist_mtx);
+               ieee80211_recalc_ps(local, -1);
+               mutex_unlock(&local->iflist_mtx);
                ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid,
                                         ifmgd->ssid_len, NULL, 0);
        }
 
+ out:
        if (!disassoc)
                mod_timer(&ifmgd->timer,
                          jiffies + IEEE80211_MONITORING_INTERVAL);
-
- unlock:
-       rcu_read_unlock();
-
-       if (disassoc)
+       else
                ieee80211_set_disassoc(sdata, true, true,
                                        WLAN_REASON_PREV_AUTH_NOT_VALID);
 }
@@ -1889,8 +1901,12 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
                ieee80211_authenticate(sdata);
        }
 
-       if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL)
+       if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) {
                ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
+               mutex_lock(&sdata->local->iflist_mtx);
+               ieee80211_recalc_ps(sdata->local, -1);
+               mutex_unlock(&sdata->local->iflist_mtx);
+       }
 }
 
 /*
@@ -1948,6 +1964,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                }
 #endif
                ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
+               mutex_lock(&local->iflist_mtx);
+               ieee80211_recalc_ps(local, -1);
+               mutex_unlock(&local->iflist_mtx);
        }
 
        ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
index 0a11515..b218b98 100644 (file)
@@ -215,7 +215,7 @@ minstrel_get_next_sample(struct minstrel_sta_info *mi)
        unsigned int sample_ndx;
        sample_ndx = SAMPLE_TBL(mi, mi->sample_idx, mi->sample_column);
        mi->sample_idx++;
-       if (mi->sample_idx > (mi->n_rates - 2)) {
+       if ((int) mi->sample_idx > (mi->n_rates - 2)) {
                mi->sample_idx = 0;
                mi->sample_column++;
                if (mi->sample_column >= SAMPLE_COLUMNS)
index 6a9b8e6..de5bba7 100644 (file)
@@ -797,8 +797,7 @@ static int ap_sta_ps_end(struct sta_info *sta)
 {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
        struct ieee80211_local *local = sdata->local;
-       struct sk_buff *skb;
-       int sent = 0;
+       int sent, buffered;
 
        atomic_dec(&sdata->bss->num_sta_ps);
 
@@ -814,22 +813,16 @@ static int ap_sta_ps_end(struct sta_info *sta)
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
 
        /* Send all buffered frames to the station */
-       while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
-               sent++;
-               skb->requeue = 1;
-               dev_queue_xmit(skb);
-       }
-       while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
-               local->total_ps_buffered--;
-               sent++;
+       sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered);
+       buffered = ieee80211_add_pending_skbs(local, &sta->ps_tx_buf);
+       sent += buffered;
+       local->total_ps_buffered -= buffered;
+
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-               printk(KERN_DEBUG "%s: STA %pM aid %d send PS frame "
-                      "since STA not sleeping anymore\n", sdata->dev->name,
-                      sta->sta.addr, sta->sta.aid);
+       printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames "
+              "since STA not sleeping anymore\n", sdata->dev->name,
+              sta->sta.addr, sta->sta.aid, sent - buffered, buffered);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
-               skb->requeue = 1;
-               dev_queue_xmit(skb);
-       }
 
        return sent;
 }
@@ -1335,7 +1328,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
                 * mac80211. That also explains the __skb_push()
                 * below.
                 */
-               align = (unsigned long)skb->data & 3;
+               align = ((unsigned long)(skb->data + sizeof(struct ethhdr))) & 3;
                if (align) {
                        if (WARN_ON(skb_headroom(skb) < 3)) {
                                dev_kfree_skb(skb);
index d5611d8..a360bce 100644 (file)
  * When the insertion fails (sta_info_insert()) returns non-zero), the
  * structure will have been freed by sta_info_insert()!
  *
+ * sta entries are added by mac80211 when you establish a link with a
+ * peer. This means different things for the different type of interfaces
+ * we support. For a regular station this mean we add the AP sta when we
+ * receive an assocation response from the AP. For IBSS this occurs when
+ * we receive a probe response or a beacon from target IBSS network. For
+ * WDS we add the sta for the peer imediately upon device open. When using
+ * AP mode we add stations for each respective station upon request from
+ * userspace through nl80211.
+ *
  * Because there are debugfs entries for each station, and adding those
  * must be able to sleep, it is also possible to "pin" a station entry,
  * that means it can be removed from the hash table but not be freed.
index a910148..364222b 100644 (file)
@@ -400,6 +400,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
                        sta_info_set_tim_bit(sta);
 
                info->control.jiffies = jiffies;
+               info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
                skb_queue_tail(&sta->ps_tx_buf, tx->skb);
                return TX_QUEUED;
        }
@@ -420,7 +421,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
                 * frame filtering and keeps a station  blacklist on its own
                 * (e.g: p54), so that frames can be delivered unimpeded.
                 *
-                * Note: It should be save to disable the filter now.
+                * Note: It should be safe to disable the filter now.
                 * As, it is really unlikely that we still have any pending
                 * frame for this station in the hw's buffers/fifos left,
                 * that is not rejected with a unsuccessful tx_status yet.
@@ -907,9 +908,8 @@ ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
  * deal with packet injection down monitor interface
  * with Radiotap Header -- only called for monitor mode interface
  */
-static ieee80211_tx_result
-__ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
-                             struct sk_buff *skb)
+static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
+                                         struct sk_buff *skb)
 {
        /*
         * this is the moment to interpret and discard the radiotap header that
@@ -960,7 +960,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
                                 * on transmission
                                 */
                                if (skb->len < (iterator.max_length + FCS_LEN))
-                                       return TX_DROP;
+                                       return false;
 
                                skb_trim(skb, skb->len - FCS_LEN);
                        }
@@ -982,7 +982,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
        }
 
        if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
-               return TX_DROP;
+               return false;
 
        /*
         * remove the radiotap header
@@ -991,7 +991,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
         */
        skb_pull(skb, iterator.max_length);
 
-       return TX_CONTINUE;
+       return true;
 }
 
 /*
@@ -1025,7 +1025,7 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
        /* process and remove the injection radiotap header */
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) {
-               if (__ieee80211_parse_tx_radiotap(tx, skb) == TX_DROP)
+               if (!__ieee80211_parse_tx_radiotap(tx, skb))
                        return TX_DROP;
 
                /*
@@ -1238,7 +1238,6 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
                         bool txpending)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct sta_info *sta;
        struct ieee80211_tx_data tx;
        ieee80211_tx_result res_prepare;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -1270,7 +1269,6 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
                return;
        }
 
-       sta = tx.sta;
        tx.channel = local->hw.conf.channel;
        info->band = tx.channel->band;
 
@@ -1417,7 +1415,8 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
-           local->hw.conf.dynamic_ps_timeout > 0) {
+           local->hw.conf.dynamic_ps_timeout > 0 &&
+           !local->sw_scanning && !local->hw_scanning && local->ps_sdata) {
                if (local->hw.conf.flags & IEEE80211_CONF_PS) {
                        ieee80211_stop_queues_by_reason(&local->hw,
                                        IEEE80211_QUEUE_STOP_REASON_PS);
index 949d857..66ce96a 100644 (file)
@@ -341,6 +341,52 @@ void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue)
 }
 EXPORT_SYMBOL(ieee80211_stop_queue);
 
+void ieee80211_add_pending_skb(struct ieee80211_local *local,
+                              struct sk_buff *skb)
+{
+       struct ieee80211_hw *hw = &local->hw;
+       unsigned long flags;
+       int queue = skb_get_queue_mapping(skb);
+
+       spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+       __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
+       __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_PENDING);
+       skb_queue_tail(&local->pending[queue], skb);
+       __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
+       spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+}
+
+int ieee80211_add_pending_skbs(struct ieee80211_local *local,
+                              struct sk_buff_head *skbs)
+{
+       struct ieee80211_hw *hw = &local->hw;
+       struct sk_buff *skb;
+       unsigned long flags;
+       int queue, ret = 0, i;
+
+       spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+       for (i = 0; i < hw->queues; i++)
+               __ieee80211_stop_queue(hw, i,
+                       IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
+
+       while ((skb = skb_dequeue(skbs))) {
+               ret++;
+               queue = skb_get_queue_mapping(skb);
+               skb_queue_tail(&local->pending[queue], skb);
+       }
+
+       for (i = 0; i < hw->queues; i++) {
+               if (ret)
+                       __ieee80211_stop_queue(hw, i,
+                               IEEE80211_QUEUE_STOP_REASON_PENDING);
+               __ieee80211_wake_queue(hw, i,
+                       IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
+       }
+       spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+
+       return ret;
+}
+
 void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
                                    enum queue_stop_reason reason)
 {
@@ -657,15 +703,15 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
 
                switch (queue) {
                case 3: /* AC_BK */
-                       qparam.cw_max = aCWmin;
-                       qparam.cw_min = aCWmax;
+                       qparam.cw_max = aCWmax;
+                       qparam.cw_min = aCWmin;
                        qparam.txop = 0;
                        qparam.aifs = 7;
                        break;
                default: /* never happens but let's not leave undefined */
                case 2: /* AC_BE */
-                       qparam.cw_max = aCWmin;
-                       qparam.cw_min = aCWmax;
+                       qparam.cw_max = aCWmax;
+                       qparam.cw_min = aCWmin;
                        qparam.txop = 0;
                        qparam.aifs = 3;
                        break;
@@ -973,7 +1019,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        if (local->open_count) {
                res = drv_start(local);
 
-               ieee80211_led_radio(local, hw->conf.radio_enabled);
+               ieee80211_led_radio(local, true);
        }
 
        /* add interfaces */
index a01154e..d2d81b1 100644 (file)
@@ -306,82 +306,6 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev,
        return 0;
 }
 
-static int ieee80211_ioctl_siwtxpower(struct net_device *dev,
-                                     struct iw_request_info *info,
-                                     union iwreq_data *data, char *extra)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_channel* chan = local->hw.conf.channel;
-       bool reconf = false;
-       u32 reconf_flags = 0;
-       int new_power_level;
-
-       if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
-               return -EINVAL;
-       if (data->txpower.flags & IW_TXPOW_RANGE)
-               return -EINVAL;
-       if (!chan)
-               return -EINVAL;
-
-       /* only change when not disabling */
-       if (!data->txpower.disabled) {
-               if (data->txpower.fixed) {
-                       if (data->txpower.value < 0)
-                               return -EINVAL;
-                       new_power_level = data->txpower.value;
-                       /*
-                        * Debatable, but we cannot do a fixed power
-                        * level above the regulatory constraint.
-                        * Use "iwconfig wlan0 txpower 15dBm" instead.
-                        */
-                       if (new_power_level > chan->max_power)
-                               return -EINVAL;
-               } else {
-                       /*
-                        * Automatic power level setting, max being the value
-                        * passed in from userland.
-                        */
-                       if (data->txpower.value < 0)
-                               new_power_level = -1;
-                       else
-                               new_power_level = data->txpower.value;
-               }
-
-               reconf = true;
-
-               /*
-                * ieee80211_hw_config() will limit to the channel's
-                * max power and possibly power constraint from AP.
-                */
-               local->user_power_level = new_power_level;
-       }
-
-       if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) {
-               local->hw.conf.radio_enabled = !(data->txpower.disabled);
-               reconf_flags |= IEEE80211_CONF_CHANGE_RADIO_ENABLED;
-               ieee80211_led_radio(local, local->hw.conf.radio_enabled);
-       }
-
-       if (reconf || reconf_flags)
-               ieee80211_hw_config(local, reconf_flags);
-
-       return 0;
-}
-
-static int ieee80211_ioctl_giwtxpower(struct net_device *dev,
-                                  struct iw_request_info *info,
-                                  union iwreq_data *data, char *extra)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
-       data->txpower.fixed = 1;
-       data->txpower.disabled = !(local->hw.conf.radio_enabled);
-       data->txpower.value = local->hw.conf.power_level;
-       data->txpower.flags = IW_TXPOW_DBM;
-
-       return 0;
-}
-
 static int ieee80211_ioctl_siwpower(struct net_device *dev,
                                    struct iw_request_info *info,
                                    struct iw_param *wrq,
@@ -658,8 +582,8 @@ static const iw_handler ieee80211_handler[] =
        (iw_handler) cfg80211_wext_giwrts,              /* SIOCGIWRTS */
        (iw_handler) cfg80211_wext_siwfrag,             /* SIOCSIWFRAG */
        (iw_handler) cfg80211_wext_giwfrag,             /* SIOCGIWFRAG */
-       (iw_handler) ieee80211_ioctl_siwtxpower,        /* SIOCSIWTXPOW */
-       (iw_handler) ieee80211_ioctl_giwtxpower,        /* SIOCGIWTXPOW */
+       (iw_handler) cfg80211_wext_siwtxpower,          /* SIOCSIWTXPOW */
+       (iw_handler) cfg80211_wext_giwtxpower,          /* SIOCGIWTXPOW */
        (iw_handler) cfg80211_wext_siwretry,            /* SIOCSIWRETRY */
        (iw_handler) cfg80211_wext_giwretry,            /* SIOCGIWRETRY */
        (iw_handler) cfg80211_wext_siwencode,           /* SIOCSIWENCODE */
index 694343b..116a923 100644 (file)
@@ -101,7 +101,7 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb)
         * Now we know the 1d priority, fill in the QoS header if
         * there is one (and we haven't done this before).
         */
-       if (!skb->requeue && ieee80211_is_data_qos(hdr->frame_control)) {
+       if (ieee80211_is_data_qos(hdr->frame_control)) {
                u8 *p = ieee80211_get_qos_ctl(hdr);
                u8 ack_policy = 0;
                tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
index 425ab14..5874657 100644 (file)
@@ -260,8 +260,8 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
        ip_send_check(ip_hdr(skb));
 
        /* drop old route */
-       dst_release(skb->dst);
-       skb->dst = &rt->u.dst;
+       skb_dst_drop(skb);
+       skb_dst_set(skb, &rt->u.dst);
 
        /* Another hack: avoid icmp_send in ip_fragment */
        skb->local_df = 1;
@@ -324,8 +324,8 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
        }
 
        /* drop old route */
-       dst_release(skb->dst);
-       skb->dst = &rt->u.dst;
+       skb_dst_drop(skb);
+       skb_dst_set(skb, &rt->u.dst);
 
        /* Another hack: avoid icmp_send in ip_fragment */
        skb->local_df = 1;
@@ -388,8 +388,8 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
                goto tx_error_put;
 
        /* drop old route */
-       dst_release(skb->dst);
-       skb->dst = &rt->u.dst;
+       skb_dst_drop(skb);
+       skb_dst_set(skb, &rt->u.dst);
 
        /* mangle the packet */
        if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp))
@@ -465,8 +465,8 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
                goto tx_error_put;
 
        /* drop old route */
-       dst_release(skb->dst);
-       skb->dst = &rt->u.dst;
+       skb_dst_drop(skb);
+       skb_dst_set(skb, &rt->u.dst);
 
        /* mangle the packet */
        if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp))
@@ -553,8 +553,8 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
                IP_VS_DBG_RL("ip_vs_tunnel_xmit(): mtu less than 68\n");
                goto tx_error;
        }
-       if (skb->dst)
-               skb->dst->ops->update_pmtu(skb->dst, mtu);
+       if (skb_dst(skb))
+               skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
 
        df |= (old_iph->frag_off & htons(IP_DF));
 
@@ -596,8 +596,8 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
        memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
 
        /* drop old route */
-       dst_release(skb->dst);
-       skb->dst = &rt->u.dst;
+       skb_dst_drop(skb);
+       skb_dst_set(skb, &rt->u.dst);
 
        /*
         *      Push down and install the IPIP header.
@@ -665,8 +665,8 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
                IP_VS_DBG_RL("ip_vs_tunnel_xmit_v6(): mtu less than 1280\n");
                goto tx_error;
        }
-       if (skb->dst)
-               skb->dst->ops->update_pmtu(skb->dst, mtu);
+       if (skb_dst(skb))
+               skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
 
        if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr)) {
                icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
@@ -702,8 +702,8 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
        memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
 
        /* drop old route */
-       dst_release(skb->dst);
-       skb->dst = &rt->u.dst;
+       skb_dst_drop(skb);
+       skb_dst_set(skb, &rt->u.dst);
 
        /*
         *      Push down and install the IPIP header.
@@ -775,8 +775,8 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
        ip_send_check(ip_hdr(skb));
 
        /* drop old route */
-       dst_release(skb->dst);
-       skb->dst = &rt->u.dst;
+       skb_dst_drop(skb);
+       skb_dst_set(skb, &rt->u.dst);
 
        /* Another hack: avoid icmp_send in ip_fragment */
        skb->local_df = 1;
@@ -828,8 +828,8 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
        }
 
        /* drop old route */
-       dst_release(skb->dst);
-       skb->dst = &rt->u.dst;
+       skb_dst_drop(skb);
+       skb_dst_set(skb, &rt->u.dst);
 
        /* Another hack: avoid icmp_send in ip_fragment */
        skb->local_df = 1;
@@ -900,8 +900,8 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
                goto tx_error_put;
 
        /* drop the old route when skb is not shared */
-       dst_release(skb->dst);
-       skb->dst = &rt->u.dst;
+       skb_dst_drop(skb);
+       skb_dst_set(skb, &rt->u.dst);
 
        ip_vs_nat_icmp(skb, pp, cp, 0);
 
@@ -975,8 +975,8 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
                goto tx_error_put;
 
        /* drop the old route when skb is not shared */
-       dst_release(skb->dst);
-       skb->dst = &rt->u.dst;
+       skb_dst_drop(skb);
+       skb_dst_set(skb, &rt->u.dst);
 
        ip_vs_nat_icmp_v6(skb, pp, cp, 0);
 
index 8a3875e..497b222 100644 (file)
@@ -48,7 +48,7 @@ static int help(struct sk_buff *skb, unsigned int protoff,
 {
        struct nf_conntrack_expect *exp;
        struct iphdr *iph = ip_hdr(skb);
-       struct rtable *rt = skb->rtable;
+       struct rtable *rt = skb_rtable(skb);
        struct in_device *in_dev;
        __be32 mask = 0;
 
index 6b08d32..1b816a2 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/netfilter/nfnetlink_conntrack.h>
 #include <net/netfilter/nf_conntrack.h>
 #include <net/netfilter/nf_conntrack_l4proto.h>
+#include <net/netfilter/nf_conntrack_ecache.h>
 #include <net/netfilter/nf_log.h>
 
 /* Timeouts are based on values from RFC4340:
@@ -551,6 +552,9 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
        ct->proto.dccp.state = new_state;
        spin_unlock_bh(&ct->lock);
 
+       if (new_state != old_state)
+               nf_conntrack_event_cache(IPCT_PROTOINFO, ct);
+
        dn = dccp_pernet(net);
        nf_ct_refresh_acct(ct, ctinfo, skb, dn->dccp_timeout[new_state]);
 
index 175a28c..a54a0af 100644 (file)
@@ -176,7 +176,7 @@ static bool gre_invert_tuple(struct nf_conntrack_tuple *tuple,
 static bool gre_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff,
                             struct nf_conntrack_tuple *tuple)
 {
-       struct net *net = dev_net(skb->dev ? skb->dev : skb->dst->dev);
+       struct net *net = dev_net(skb->dev ? skb->dev : skb_dst(skb)->dev);
        const struct gre_hdr_pptp *pgrehdr;
        struct gre_hdr_pptp _pgrehdr;
        __be16 srckey;
index 5c5739c..5142e60 100644 (file)
@@ -648,6 +648,14 @@ static bool tcp_in_window(const struct nf_conn *ct,
                        sender->td_end = end;
                        sender->flags |= IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED;
                }
+               if (tcph->ack) {
+                       if (!(sender->flags & IP_CT_TCP_FLAG_MAXACK_SET)) {
+                               sender->td_maxack = ack;
+                               sender->flags |= IP_CT_TCP_FLAG_MAXACK_SET;
+                       } else if (after(ack, sender->td_maxack))
+                               sender->td_maxack = ack;
+               }
+
                /*
                 * Update receiver data.
                 */
@@ -933,6 +941,16 @@ static int tcp_packet(struct nf_conn *ct,
                return -NF_ACCEPT;
        case TCP_CONNTRACK_CLOSE:
                if (index == TCP_RST_SET
+                   && (ct->proto.tcp.seen[!dir].flags & IP_CT_TCP_FLAG_MAXACK_SET)
+                   && before(ntohl(th->seq), ct->proto.tcp.seen[!dir].td_maxack)) {
+                       /* Invalid RST  */
+                       write_unlock_bh(&tcp_lock);
+                       if (LOG_INVALID(net, IPPROTO_TCP))
+                               nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+                                         "nf_ct_tcp: invalid RST ");
+                       return -NF_ACCEPT;
+               }
+               if (index == TCP_RST_SET
                    && ((test_bit(IPS_SEEN_REPLY_BIT, &ct->status)
                         && ct->proto.tcp.last_index == TCP_SYN_SET)
                        || (!test_bit(IPS_ASSURED_BIT, &ct->status)
index fd326ac..66a6dd5 100644 (file)
@@ -581,6 +581,12 @@ nfulnl_log_packet(u_int8_t pf,
                + nla_total_size(sizeof(struct nfulnl_msg_packet_hw))
                + nla_total_size(sizeof(struct nfulnl_msg_packet_timestamp));
 
+       if (in && skb_mac_header_was_set(skb)) {
+               size +=   nla_total_size(skb->dev->hard_header_len)
+                       + nla_total_size(sizeof(u_int16_t))     /* hwtype */
+                       + nla_total_size(sizeof(u_int16_t));    /* hwlen */
+       }
+
        spin_lock_bh(&inst->lock);
 
        if (inst->flags & NFULNL_CFG_F_SEQ)
index 8c86011..71daa09 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * This is a module which is used for queueing packets and communicating with
- * userspace via nfetlink.
+ * userspace via nfnetlink.
  *
  * (C) 2005 by Harald Welte <laforge@netfilter.org>
  * (C) 2007 by Patrick McHardy <kaber@trash.net>
@@ -932,6 +932,8 @@ static void __exit nfnetlink_queue_fini(void)
 #endif
        nfnetlink_subsys_unregister(&nfqnl_subsys);
        netlink_unregister_notifier(&nfqnl_rtnl_notifier);
+
+       rcu_barrier(); /* Wait for completion of call_rcu()'s */
 }
 
 MODULE_DESCRIPTION("netfilter packet queue handler");
index 4f3b1f8..eda64c1 100644 (file)
@@ -73,11 +73,11 @@ tcpmss_mangle_packet(struct sk_buff *skb,
        }
 
        if (info->mss == XT_TCPMSS_CLAMP_PMTU) {
-               if (dst_mtu(skb->dst) <= minlen) {
+               if (dst_mtu(skb_dst(skb)) <= minlen) {
                        if (net_ratelimit())
                                printk(KERN_ERR "xt_TCPMSS: "
                                       "unknown or invalid path-MTU (%u)\n",
-                                      dst_mtu(skb->dst));
+                                      dst_mtu(skb_dst(skb)));
                        return -1;
                }
                if (in_mtu <= minlen) {
@@ -86,7 +86,7 @@ tcpmss_mangle_packet(struct sk_buff *skb,
                                       "invalid path-MTU (%u)\n", in_mtu);
                        return -1;
                }
-               newmss = min(dst_mtu(skb->dst), in_mtu) - minlen;
+               newmss = min(dst_mtu(skb_dst(skb)), in_mtu) - minlen;
        } else
                newmss = info->mss;
 
index a5b5369..219dcdb 100644 (file)
@@ -926,7 +926,7 @@ static int dl_seq_show(struct seq_file *s, void *v)
        if (!hlist_empty(&htable->hash[*bucket])) {
                hlist_for_each_entry(ent, pos, &htable->hash[*bucket], node)
                        if (dl_seq_real_show(ent, htable->family, s))
-                               return 1;
+                               return -1;
        }
        return 0;
 }
index 328bd20..4cbfebd 100644 (file)
@@ -86,7 +86,7 @@ match_policy_out(const struct sk_buff *skb, const struct xt_policy_info *info,
                 unsigned short family)
 {
        const struct xt_policy_elem *e;
-       const struct dst_entry *dst = skb->dst;
+       const struct dst_entry *dst = skb_dst(skb);
        int strict = info->flags & XT_POLICY_MATCH_STRICT;
        int i, pos;
 
index 6741928..484d168 100644 (file)
@@ -25,7 +25,7 @@ static bool
 realm_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 {
        const struct xt_realm_info *info = par->matchinfo;
-       const struct dst_entry *dst = skb->dst;
+       const struct dst_entry *dst = skb_dst(skb);
 
        return (info->id == (dst->tclassid & info->mask)) ^ info->invert;
 }
index c7c5d52..4f76e55 100644 (file)
@@ -372,8 +372,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev,  struct
                goto oom;
 
        /* drop any routing info */
-       dst_release(skb->dst);
-       skb->dst = NULL;
+       skb_dst_drop(skb);
 
        /* drop conntrack reference */
        nf_reset(skb);
@@ -621,8 +620,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
 
        skb_set_owner_r(skb, sk);
        skb->dev = NULL;
-       dst_release(skb->dst);
-       skb->dst = NULL;
+       skb_dst_drop(skb);
 
        /* drop conntrack reference */
        nf_reset(skb);
@@ -1582,9 +1580,9 @@ static int packet_dev_mc(struct net_device *dev, struct packet_mclist *i,
                break;
        case PACKET_MR_UNICAST:
                if (what > 0)
-                       return dev_unicast_add(dev, i->addr, i->alen);
+                       return dev_unicast_add(dev, i->addr);
                else
-                       return dev_unicast_delete(dev, i->addr, i->alen);
+                       return dev_unicast_delete(dev, i->addr);
                break;
        default:;
        }
index 4aa8885..480839d 100644 (file)
@@ -115,10 +115,10 @@ static int gprs_recv(struct gprs_dev *gp, struct sk_buff *skb)
                rskb->truesize += rskb->len;
 
                /* Avoid nested fragments */
-               for (fs = skb_shinfo(skb)->frag_list; fs; fs = fs->next)
+               skb_walk_frags(skb, fs)
                        flen += fs->len;
                skb->next = skb_shinfo(skb)->frag_list;
-               skb_shinfo(skb)->frag_list = NULL;
+               skb_frag_list_init(skb);
                skb->len -= flen;
                skb->data_len -= flen;
                skb->truesize -= flen;
@@ -212,8 +212,9 @@ static int gprs_xmit(struct sk_buff *skb, struct net_device *dev)
                dev->stats.tx_bytes += len;
        }
 
-       if (!pep_writeable(sk))
-               netif_stop_queue(dev);
+       netif_stop_queue(dev);
+       if (pep_writeable(sk))
+               netif_wake_queue(dev);
        return 0;
 }
 
index 8ad2b53..eef833e 100644 (file)
@@ -940,10 +940,10 @@ int pep_write(struct sock *sk, struct sk_buff *skb)
        rskb->truesize += rskb->len;
 
        /* Avoid nested fragments */
-       for (fs = skb_shinfo(skb)->frag_list; fs; fs = fs->next)
+       skb_walk_frags(skb, fs)
                flen += fs->len;
        skb->next = skb_shinfo(skb)->frag_list;
-       skb_shinfo(skb)->frag_list = NULL;
+       skb_frag_list_init(skb);
        skb->len -= flen;
        skb->data_len -= flen;
        skb->truesize -= flen;
index 7f807b3..eaf7658 100644 (file)
@@ -10,22 +10,15 @@ menuconfig RFKILL
          To compile this driver as a module, choose M here: the
          module will be called rfkill.
 
-config RFKILL_INPUT
-       tristate "Input layer to RF switch connector"
-       depends on RFKILL && INPUT
-       help
-         Say Y here if you want kernel automatically toggle state
-         of RF switches on and off when user presses appropriate
-         button or a key on the keyboard. Without this module you
-         need a some kind of userspace application to control
-         state of the switches.
-
-         To compile this driver as a module, choose M here: the
-         module will be called rfkill-input.
-
 # LED trigger support
 config RFKILL_LEDS
        bool
-       depends on RFKILL && LEDS_TRIGGERS
+       depends on RFKILL
+       depends on LEDS_TRIGGERS = y || RFKILL = LEDS_TRIGGERS
        default y
 
+config RFKILL_INPUT
+       bool "RF switch input support" if EMBEDDED
+       depends on RFKILL
+       depends on INPUT = y || RFKILL = INPUT
+       default y if !EMBEDDED
index b38c430..6621053 100644 (file)
@@ -2,5 +2,6 @@
 # Makefile for the RF switch subsystem.
 #
 
-obj-$(CONFIG_RFKILL)                   += rfkill.o
-obj-$(CONFIG_RFKILL_INPUT)             += rfkill-input.o
+rfkill-y                       += core.o
+rfkill-$(CONFIG_RFKILL_INPUT)  += input.o
+obj-$(CONFIG_RFKILL)           += rfkill.o
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
new file mode 100644 (file)
index 0000000..4e68ab4
--- /dev/null
@@ -0,0 +1,1205 @@
+/*
+ * Copyright (C) 2006 - 2007 Ivo van Doorn
+ * Copyright (C) 2007 Dmitry Torokhov
+ * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/workqueue.h>
+#include <linux/capability.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/rfkill.h>
+#include <linux/spinlock.h>
+#include <linux/miscdevice.h>
+#include <linux/wait.h>
+#include <linux/poll.h>
+#include <linux/fs.h>
+
+#include "rfkill.h"
+
+#define POLL_INTERVAL          (5 * HZ)
+
+#define RFKILL_BLOCK_HW                BIT(0)
+#define RFKILL_BLOCK_SW                BIT(1)
+#define RFKILL_BLOCK_SW_PREV   BIT(2)
+#define RFKILL_BLOCK_ANY       (RFKILL_BLOCK_HW |\
+                                RFKILL_BLOCK_SW |\
+                                RFKILL_BLOCK_SW_PREV)
+#define RFKILL_BLOCK_SW_SETCALL        BIT(31)
+
+struct rfkill {
+       spinlock_t              lock;
+
+       const char              *name;
+       enum rfkill_type        type;
+
+       unsigned long           state;
+
+       u32                     idx;
+
+       bool                    registered;
+       bool                    suspended;
+       bool                    persistent;
+
+       const struct rfkill_ops *ops;
+       void                    *data;
+
+#ifdef CONFIG_RFKILL_LEDS
+       struct led_trigger      led_trigger;
+       const char              *ledtrigname;
+#endif
+
+       struct device           dev;
+       struct list_head        node;
+
+       struct delayed_work     poll_work;
+       struct work_struct      uevent_work;
+       struct work_struct      sync_work;
+};
+#define to_rfkill(d)   container_of(d, struct rfkill, dev)
+
+struct rfkill_int_event {
+       struct list_head        list;
+       struct rfkill_event     ev;
+};
+
+struct rfkill_data {
+       struct list_head        list;
+       struct list_head        events;
+       struct mutex            mtx;
+       wait_queue_head_t       read_wait;
+       bool                    input_handler;
+};
+
+
+MODULE_AUTHOR("Ivo van Doorn <IvDoorn@gmail.com>");
+MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
+MODULE_DESCRIPTION("RF switch support");
+MODULE_LICENSE("GPL");
+
+
+/*
+ * The locking here should be made much smarter, we currently have
+ * a bit of a stupid situation because drivers might want to register
+ * the rfkill struct under their own lock, and take this lock during
+ * rfkill method calls -- which will cause an AB-BA deadlock situation.
+ *
+ * To fix that, we need to rework this code here to be mostly lock-free
+ * and only use the mutex for list manipulations, not to protect the
+ * various other global variables. Then we can avoid holding the mutex
+ * around driver operations, and all is happy.
+ */
+static LIST_HEAD(rfkill_list); /* list of registered rf switches */
+static DEFINE_MUTEX(rfkill_global_mutex);
+static LIST_HEAD(rfkill_fds);  /* list of open fds of /dev/rfkill */
+
+static unsigned int rfkill_default_state = 1;
+module_param_named(default_state, rfkill_default_state, uint, 0444);
+MODULE_PARM_DESC(default_state,
+                "Default initial state for all radio types, 0 = radio off");
+
+static struct {
+       bool cur, sav;
+} rfkill_global_states[NUM_RFKILL_TYPES];
+
+static bool rfkill_epo_lock_active;
+
+
+#ifdef CONFIG_RFKILL_LEDS
+static void rfkill_led_trigger_event(struct rfkill *rfkill)
+{
+       struct led_trigger *trigger;
+
+       if (!rfkill->registered)
+               return;
+
+       trigger = &rfkill->led_trigger;
+
+       if (rfkill->state & RFKILL_BLOCK_ANY)
+               led_trigger_event(trigger, LED_OFF);
+       else
+               led_trigger_event(trigger, LED_FULL);
+}
+
+static void rfkill_led_trigger_activate(struct led_classdev *led)
+{
+       struct rfkill *rfkill;
+
+       rfkill = container_of(led->trigger, struct rfkill, led_trigger);
+
+       rfkill_led_trigger_event(rfkill);
+}
+
+const char *rfkill_get_led_trigger_name(struct rfkill *rfkill)
+{
+       return rfkill->led_trigger.name;
+}
+EXPORT_SYMBOL(rfkill_get_led_trigger_name);
+
+void rfkill_set_led_trigger_name(struct rfkill *rfkill, const char *name)
+{
+       BUG_ON(!rfkill);
+
+       rfkill->ledtrigname = name;
+}
+EXPORT_SYMBOL(rfkill_set_led_trigger_name);
+
+static int rfkill_led_trigger_register(struct rfkill *rfkill)
+{
+       rfkill->led_trigger.name = rfkill->ledtrigname
+                                       ? : dev_name(&rfkill->dev);
+       rfkill->led_trigger.activate = rfkill_led_trigger_activate;
+       return led_trigger_register(&rfkill->led_trigger);
+}
+
+static void rfkill_led_trigger_unregister(struct rfkill *rfkill)
+{
+       led_trigger_unregister(&rfkill->led_trigger);
+}
+#else
+static void rfkill_led_trigger_event(struct rfkill *rfkill)
+{
+}
+
+static inline int rfkill_led_trigger_register(struct rfkill *rfkill)
+{
+       return 0;
+}
+
+static inline void rfkill_led_trigger_unregister(struct rfkill *rfkill)
+{
+}
+#endif /* CONFIG_RFKILL_LEDS */
+
+static void rfkill_fill_event(struct rfkill_event *ev, struct rfkill *rfkill,
+                             enum rfkill_operation op)
+{
+       unsigned long flags;
+
+       ev->idx = rfkill->idx;
+       ev->type = rfkill->type;
+       ev->op = op;
+
+       spin_lock_irqsave(&rfkill->lock, flags);
+       ev->hard = !!(rfkill->state & RFKILL_BLOCK_HW);
+       ev->soft = !!(rfkill->state & (RFKILL_BLOCK_SW |
+                                       RFKILL_BLOCK_SW_PREV));
+       spin_unlock_irqrestore(&rfkill->lock, flags);
+}
+
+static void rfkill_send_events(struct rfkill *rfkill, enum rfkill_operation op)
+{
+       struct rfkill_data *data;
+       struct rfkill_int_event *ev;
+
+       list_for_each_entry(data, &rfkill_fds, list) {
+               ev = kzalloc(sizeof(*ev), GFP_KERNEL);
+               if (!ev)
+                       continue;
+               rfkill_fill_event(&ev->ev, rfkill, op);
+               mutex_lock(&data->mtx);
+               list_add_tail(&ev->list, &data->events);
+               mutex_unlock(&data->mtx);
+               wake_up_interruptible(&data->read_wait);
+       }
+}
+
+static void rfkill_event(struct rfkill *rfkill)
+{
+       if (!rfkill->registered || rfkill->suspended)
+               return;
+
+       kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE);
+
+       /* also send event to /dev/rfkill */
+       rfkill_send_events(rfkill, RFKILL_OP_CHANGE);
+}
+
+static bool __rfkill_set_hw_state(struct rfkill *rfkill,
+                                 bool blocked, bool *change)
+{
+       unsigned long flags;
+       bool prev, any;
+
+       BUG_ON(!rfkill);
+
+       spin_lock_irqsave(&rfkill->lock, flags);
+       prev = !!(rfkill->state & RFKILL_BLOCK_HW);
+       if (blocked)
+               rfkill->state |= RFKILL_BLOCK_HW;
+       else
+               rfkill->state &= ~RFKILL_BLOCK_HW;
+       *change = prev != blocked;
+       any = rfkill->state & RFKILL_BLOCK_ANY;
+       spin_unlock_irqrestore(&rfkill->lock, flags);
+
+       rfkill_led_trigger_event(rfkill);
+
+       return any;
+}
+
+/**
+ * rfkill_set_block - wrapper for set_block method
+ *
+ * @rfkill: the rfkill struct to use
+ * @blocked: the new software state
+ *
+ * Calls the set_block method (when applicable) and handles notifications
+ * etc. as well.
+ */
+static void rfkill_set_block(struct rfkill *rfkill, bool blocked)
+{
+       unsigned long flags;
+       int err;
+
+       /*
+        * Some platforms (...!) generate input events which affect the
+        * _hard_ kill state -- whenever something tries to change the
+        * current software state query the hardware state too.
+        */
+       if (rfkill->ops->query)
+               rfkill->ops->query(rfkill, rfkill->data);
+
+       spin_lock_irqsave(&rfkill->lock, flags);
+       if (rfkill->state & RFKILL_BLOCK_SW)
+               rfkill->state |= RFKILL_BLOCK_SW_PREV;
+       else
+               rfkill->state &= ~RFKILL_BLOCK_SW_PREV;
+
+       if (blocked)
+               rfkill->state |= RFKILL_BLOCK_SW;
+       else
+               rfkill->state &= ~RFKILL_BLOCK_SW;
+
+       rfkill->state |= RFKILL_BLOCK_SW_SETCALL;
+       spin_unlock_irqrestore(&rfkill->lock, flags);
+
+       if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP))
+               return;
+
+       err = rfkill->ops->set_block(rfkill->data, blocked);
+
+       spin_lock_irqsave(&rfkill->lock, flags);
+       if (err) {
+               /*
+                * Failed -- reset status to _prev, this may be different
+                * from what set set _PREV to earlier in this function
+                * if rfkill_set_sw_state was invoked.
+                */
+               if (rfkill->state & RFKILL_BLOCK_SW_PREV)
+                       rfkill->state |= RFKILL_BLOCK_SW;
+               else
+                       rfkill->state &= ~RFKILL_BLOCK_SW;
+       }
+       rfkill->state &= ~RFKILL_BLOCK_SW_SETCALL;
+       rfkill->state &= ~RFKILL_BLOCK_SW_PREV;
+       spin_unlock_irqrestore(&rfkill->lock, flags);
+
+       rfkill_led_trigger_event(rfkill);
+       rfkill_event(rfkill);
+}
+
+#ifdef CONFIG_RFKILL_INPUT
+static atomic_t rfkill_input_disabled = ATOMIC_INIT(0);
+
+/**
+ * __rfkill_switch_all - Toggle state of all switches of given type
+ * @type: type of interfaces to be affected
+ * @state: the new state
+ *
+ * This function sets the state of all switches of given type,
+ * unless a specific switch is claimed by userspace (in which case,
+ * that switch is left alone) or suspended.
+ *
+ * Caller must have acquired rfkill_global_mutex.
+ */
+static void __rfkill_switch_all(const enum rfkill_type type, bool blocked)
+{
+       struct rfkill *rfkill;
+
+       rfkill_global_states[type].cur = blocked;
+       list_for_each_entry(rfkill, &rfkill_list, node) {
+               if (rfkill->type != type)
+                       continue;
+
+               rfkill_set_block(rfkill, blocked);
+       }
+}
+
+/**
+ * rfkill_switch_all - Toggle state of all switches of given type
+ * @type: type of interfaces to be affected
+ * @state: the new state
+ *
+ * Acquires rfkill_global_mutex and calls __rfkill_switch_all(@type, @state).
+ * Please refer to __rfkill_switch_all() for details.
+ *
+ * Does nothing if the EPO lock is active.
+ */
+void rfkill_switch_all(enum rfkill_type type, bool blocked)
+{
+       if (atomic_read(&rfkill_input_disabled))
+               return;
+
+       mutex_lock(&rfkill_global_mutex);
+
+       if (!rfkill_epo_lock_active)
+               __rfkill_switch_all(type, blocked);
+
+       mutex_unlock(&rfkill_global_mutex);
+}
+
+/**
+ * rfkill_epo - emergency power off all transmitters
+ *
+ * This kicks all non-suspended rfkill devices to RFKILL_STATE_SOFT_BLOCKED,
+ * ignoring everything in its path but rfkill_global_mutex and rfkill->mutex.
+ *
+ * The global state before the EPO is saved and can be restored later
+ * using rfkill_restore_states().
+ */
+void rfkill_epo(void)
+{
+       struct rfkill *rfkill;
+       int i;
+
+       if (atomic_read(&rfkill_input_disabled))
+               return;
+
+       mutex_lock(&rfkill_global_mutex);
+
+       rfkill_epo_lock_active = true;
+       list_for_each_entry(rfkill, &rfkill_list, node)
+               rfkill_set_block(rfkill, true);
+
+       for (i = 0; i < NUM_RFKILL_TYPES; i++) {
+               rfkill_global_states[i].sav = rfkill_global_states[i].cur;
+               rfkill_global_states[i].cur = true;
+       }
+
+       mutex_unlock(&rfkill_global_mutex);
+}
+
+/**
+ * rfkill_restore_states - restore global states
+ *
+ * Restore (and sync switches to) the global state from the
+ * states in rfkill_default_states.  This can undo the effects of
+ * a call to rfkill_epo().
+ */
+void rfkill_restore_states(void)
+{
+       int i;
+
+       if (atomic_read(&rfkill_input_disabled))
+               return;
+
+       mutex_lock(&rfkill_global_mutex);
+
+       rfkill_epo_lock_active = false;
+       for (i = 0; i < NUM_RFKILL_TYPES; i++)
+               __rfkill_switch_all(i, rfkill_global_states[i].sav);
+       mutex_unlock(&rfkill_global_mutex);
+}
+
+/**
+ * rfkill_remove_epo_lock - unlock state changes
+ *
+ * Used by rfkill-input manually unlock state changes, when
+ * the EPO switch is deactivated.
+ */
+void rfkill_remove_epo_lock(void)
+{
+       if (atomic_read(&rfkill_input_disabled))
+               return;
+
+       mutex_lock(&rfkill_global_mutex);
+       rfkill_epo_lock_active = false;
+       mutex_unlock(&rfkill_global_mutex);
+}
+
+/**
+ * rfkill_is_epo_lock_active - returns true EPO is active
+ *
+ * Returns 0 (false) if there is NOT an active EPO contidion,
+ * and 1 (true) if there is an active EPO contition, which
+ * locks all radios in one of the BLOCKED states.
+ *
+ * Can be called in atomic context.
+ */
+bool rfkill_is_epo_lock_active(void)
+{
+       return rfkill_epo_lock_active;
+}
+
+/**
+ * rfkill_get_global_sw_state - returns global state for a type
+ * @type: the type to get the global state of
+ *
+ * Returns the current global state for a given wireless
+ * device type.
+ */
+bool rfkill_get_global_sw_state(const enum rfkill_type type)
+{
+       return rfkill_global_states[type].cur;
+}
+#endif
+
+
+bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked)
+{
+       bool ret, change;
+
+       ret = __rfkill_set_hw_state(rfkill, blocked, &change);
+
+       if (!rfkill->registered)
+               return ret;
+
+       if (change)
+               schedule_work(&rfkill->uevent_work);
+
+       return ret;
+}
+EXPORT_SYMBOL(rfkill_set_hw_state);
+
+static void __rfkill_set_sw_state(struct rfkill *rfkill, bool blocked)
+{
+       u32 bit = RFKILL_BLOCK_SW;
+
+       /* if in a ops->set_block right now, use other bit */
+       if (rfkill->state & RFKILL_BLOCK_SW_SETCALL)
+               bit = RFKILL_BLOCK_SW_PREV;
+
+       if (blocked)
+               rfkill->state |= bit;
+       else
+               rfkill->state &= ~bit;
+}
+
+bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked)
+{
+       unsigned long flags;
+       bool prev, hwblock;
+
+       BUG_ON(!rfkill);
+
+       spin_lock_irqsave(&rfkill->lock, flags);
+       prev = !!(rfkill->state & RFKILL_BLOCK_SW);
+       __rfkill_set_sw_state(rfkill, blocked);
+       hwblock = !!(rfkill->state & RFKILL_BLOCK_HW);
+       blocked = blocked || hwblock;
+       spin_unlock_irqrestore(&rfkill->lock, flags);
+
+       if (!rfkill->registered) {
+               rfkill->persistent = true;
+       } else {
+               if (prev != blocked && !hwblock)
+                       schedule_work(&rfkill->uevent_work);
+
+               rfkill_led_trigger_event(rfkill);
+       }
+
+       return blocked;
+}
+EXPORT_SYMBOL(rfkill_set_sw_state);
+
+void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw)
+{
+       unsigned long flags;
+       bool swprev, hwprev;
+
+       BUG_ON(!rfkill);
+
+       spin_lock_irqsave(&rfkill->lock, flags);
+
+       /*
+        * No need to care about prev/setblock ... this is for uevent only
+        * and that will get triggered by rfkill_set_block anyway.
+        */
+       swprev = !!(rfkill->state & RFKILL_BLOCK_SW);
+       hwprev = !!(rfkill->state & RFKILL_BLOCK_HW);
+       __rfkill_set_sw_state(rfkill, sw);
+
+       spin_unlock_irqrestore(&rfkill->lock, flags);
+
+       if (!rfkill->registered) {
+               rfkill->persistent = true;
+       } else {
+               if (swprev != sw || hwprev != hw)
+                       schedule_work(&rfkill->uevent_work);
+
+               rfkill_led_trigger_event(rfkill);
+       }
+}
+EXPORT_SYMBOL(rfkill_set_states);
+
+static ssize_t rfkill_name_show(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+       struct rfkill *rfkill = to_rfkill(dev);
+
+       return sprintf(buf, "%s\n", rfkill->name);
+}
+
+static const char *rfkill_get_type_str(enum rfkill_type type)
+{
+       switch (type) {
+       case RFKILL_TYPE_WLAN:
+               return "wlan";
+       case RFKILL_TYPE_BLUETOOTH:
+               return "bluetooth";
+       case RFKILL_TYPE_UWB:
+               return "ultrawideband";
+       case RFKILL_TYPE_WIMAX:
+               return "wimax";
+       case RFKILL_TYPE_WWAN:
+               return "wwan";
+       default:
+               BUG();
+       }
+
+       BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_WWAN + 1);
+}
+
+static ssize_t rfkill_type_show(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+       struct rfkill *rfkill = to_rfkill(dev);
+
+       return sprintf(buf, "%s\n", rfkill_get_type_str(rfkill->type));
+}
+
+static ssize_t rfkill_idx_show(struct device *dev,
+                              struct device_attribute *attr,
+                              char *buf)
+{
+       struct rfkill *rfkill = to_rfkill(dev);
+
+       return sprintf(buf, "%d\n", rfkill->idx);
+}
+
+static u8 user_state_from_blocked(unsigned long state)
+{
+       if (state & RFKILL_BLOCK_HW)
+               return RFKILL_USER_STATE_HARD_BLOCKED;
+       if (state & RFKILL_BLOCK_SW)
+               return RFKILL_USER_STATE_SOFT_BLOCKED;
+
+       return RFKILL_USER_STATE_UNBLOCKED;
+}
+
+static ssize_t rfkill_state_show(struct device *dev,
+                                struct device_attribute *attr,
+                                char *buf)
+{
+       struct rfkill *rfkill = to_rfkill(dev);
+       unsigned long flags;
+       u32 state;
+
+       spin_lock_irqsave(&rfkill->lock, flags);
+       state = rfkill->state;
+       spin_unlock_irqrestore(&rfkill->lock, flags);
+
+       return sprintf(buf, "%d\n", user_state_from_blocked(state));
+}
+
+static ssize_t rfkill_state_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       /*
+        * The intention was that userspace can only take control over
+        * a given device when/if rfkill-input doesn't control it due
+        * to user_claim. Since user_claim is currently unsupported,
+        * we never support changing the state from userspace -- this
+        * can be implemented again later.
+        */
+
+       return -EPERM;
+}
+
+static ssize_t rfkill_claim_show(struct device *dev,
+                                struct device_attribute *attr,
+                                char *buf)
+{
+       return sprintf(buf, "%d\n", 0);
+}
+
+static ssize_t rfkill_claim_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       return -EOPNOTSUPP;
+}
+
+static struct device_attribute rfkill_dev_attrs[] = {
+       __ATTR(name, S_IRUGO, rfkill_name_show, NULL),
+       __ATTR(type, S_IRUGO, rfkill_type_show, NULL),
+       __ATTR(index, S_IRUGO, rfkill_idx_show, NULL),
+       __ATTR(state, S_IRUGO|S_IWUSR, rfkill_state_show, rfkill_state_store),
+       __ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store),
+       __ATTR_NULL
+};
+
+static void rfkill_release(struct device *dev)
+{
+       struct rfkill *rfkill = to_rfkill(dev);
+
+       kfree(rfkill);
+}
+
+static int rfkill_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct rfkill *rfkill = to_rfkill(dev);
+       unsigned long flags;
+       u32 state;
+       int error;
+
+       error = add_uevent_var(env, "RFKILL_NAME=%s", rfkill->name);
+       if (error)
+               return error;
+       error = add_uevent_var(env, "RFKILL_TYPE=%s",
+                              rfkill_get_type_str(rfkill->type));
+       if (error)
+               return error;
+       spin_lock_irqsave(&rfkill->lock, flags);
+       state = rfkill->state;
+       spin_unlock_irqrestore(&rfkill->lock, flags);
+       error = add_uevent_var(env, "RFKILL_STATE=%d",
+                              user_state_from_blocked(state));
+       return error;
+}
+
+void rfkill_pause_polling(struct rfkill *rfkill)
+{
+       BUG_ON(!rfkill);
+
+       if (!rfkill->ops->poll)
+               return;
+
+       cancel_delayed_work_sync(&rfkill->poll_work);
+}
+EXPORT_SYMBOL(rfkill_pause_polling);
+
+void rfkill_resume_polling(struct rfkill *rfkill)
+{
+       BUG_ON(!rfkill);
+
+       if (!rfkill->ops->poll)
+               return;
+
+       schedule_work(&rfkill->poll_work.work);
+}
+EXPORT_SYMBOL(rfkill_resume_polling);
+
+static int rfkill_suspend(struct device *dev, pm_message_t state)
+{
+       struct rfkill *rfkill = to_rfkill(dev);
+
+       rfkill_pause_polling(rfkill);
+
+       rfkill->suspended = true;
+
+       return 0;
+}
+
+static int rfkill_resume(struct device *dev)
+{
+       struct rfkill *rfkill = to_rfkill(dev);
+       bool cur;
+
+       cur = !!(rfkill->state & RFKILL_BLOCK_SW);
+       rfkill_set_block(rfkill, cur);
+
+       rfkill->suspended = false;
+
+       rfkill_resume_polling(rfkill);
+
+       return 0;
+}
+
+static struct class rfkill_class = {
+       .name           = "rfkill",
+       .dev_release    = rfkill_release,
+       .dev_attrs      = rfkill_dev_attrs,
+       .dev_uevent     = rfkill_dev_uevent,
+       .suspend        = rfkill_suspend,
+       .resume         = rfkill_resume,
+};
+
+bool rfkill_blocked(struct rfkill *rfkill)
+{
+       unsigned long flags;
+       u32 state;
+
+       spin_lock_irqsave(&rfkill->lock, flags);
+       state = rfkill->state;
+       spin_unlock_irqrestore(&rfkill->lock, flags);
+
+       return !!(state & RFKILL_BLOCK_ANY);
+}
+EXPORT_SYMBOL(rfkill_blocked);
+
+
+struct rfkill * __must_check rfkill_alloc(const char *name,
+                                         struct device *parent,
+                                         const enum rfkill_type type,
+                                         const struct rfkill_ops *ops,
+                                         void *ops_data)
+{
+       struct rfkill *rfkill;
+       struct device *dev;
+
+       if (WARN_ON(!ops))
+               return NULL;
+
+       if (WARN_ON(!ops->set_block))
+               return NULL;
+
+       if (WARN_ON(!name))
+               return NULL;
+
+       if (WARN_ON(type == RFKILL_TYPE_ALL || type >= NUM_RFKILL_TYPES))
+               return NULL;
+
+       rfkill = kzalloc(sizeof(*rfkill), GFP_KERNEL);
+       if (!rfkill)
+               return NULL;
+
+       spin_lock_init(&rfkill->lock);
+       INIT_LIST_HEAD(&rfkill->node);
+       rfkill->type = type;
+       rfkill->name = name;
+       rfkill->ops = ops;
+       rfkill->data = ops_data;
+
+       dev = &rfkill->dev;
+       dev->class = &rfkill_class;
+       dev->parent = parent;
+       device_initialize(dev);
+
+       return rfkill;
+}
+EXPORT_SYMBOL(rfkill_alloc);
+
+static void rfkill_poll(struct work_struct *work)
+{
+       struct rfkill *rfkill;
+
+       rfkill = container_of(work, struct rfkill, poll_work.work);
+
+       /*
+        * Poll hardware state -- driver will use one of the
+        * rfkill_set{,_hw,_sw}_state functions and use its
+        * return value to update the current status.
+        */
+       rfkill->ops->poll(rfkill, rfkill->data);
+
+       schedule_delayed_work(&rfkill->poll_work,
+               round_jiffies_relative(POLL_INTERVAL));
+}
+
+static void rfkill_uevent_work(struct work_struct *work)
+{
+       struct rfkill *rfkill;
+
+       rfkill = container_of(work, struct rfkill, uevent_work);
+
+       mutex_lock(&rfkill_global_mutex);
+       rfkill_event(rfkill);
+       mutex_unlock(&rfkill_global_mutex);
+}
+
+static void rfkill_sync_work(struct work_struct *work)
+{
+       struct rfkill *rfkill;
+       bool cur;
+
+       rfkill = container_of(work, struct rfkill, sync_work);
+
+       mutex_lock(&rfkill_global_mutex);
+       cur = rfkill_global_states[rfkill->type].cur;
+       rfkill_set_block(rfkill, cur);
+       mutex_unlock(&rfkill_global_mutex);
+}
+
+int __must_check rfkill_register(struct rfkill *rfkill)
+{
+       static unsigned long rfkill_no;
+       struct device *dev = &rfkill->dev;
+       int error;
+
+       BUG_ON(!rfkill);
+
+       mutex_lock(&rfkill_global_mutex);
+
+       if (rfkill->registered) {
+               error = -EALREADY;
+               goto unlock;
+       }
+
+       rfkill->idx = rfkill_no;
+       dev_set_name(dev, "rfkill%lu", rfkill_no);
+       rfkill_no++;
+
+       list_add_tail(&rfkill->node, &rfkill_list);
+
+       error = device_add(dev);
+       if (error)
+               goto remove;
+
+       error = rfkill_led_trigger_register(rfkill);
+       if (error)
+               goto devdel;
+
+       rfkill->registered = true;
+
+       INIT_DELAYED_WORK(&rfkill->poll_work, rfkill_poll);
+       INIT_WORK(&rfkill->uevent_work, rfkill_uevent_work);
+       INIT_WORK(&rfkill->sync_work, rfkill_sync_work);
+
+       if (rfkill->ops->poll)
+               schedule_delayed_work(&rfkill->poll_work,
+                       round_jiffies_relative(POLL_INTERVAL));
+
+       if (!rfkill->persistent || rfkill_epo_lock_active) {
+               schedule_work(&rfkill->sync_work);
+       } else {
+#ifdef CONFIG_RFKILL_INPUT
+               bool soft_blocked = !!(rfkill->state & RFKILL_BLOCK_SW);
+
+               if (!atomic_read(&rfkill_input_disabled))
+                       __rfkill_switch_all(rfkill->type, soft_blocked);
+#endif
+       }
+
+       rfkill_send_events(rfkill, RFKILL_OP_ADD);
+
+       mutex_unlock(&rfkill_global_mutex);
+       return 0;
+
+ devdel:
+       device_del(&rfkill->dev);
+ remove:
+       list_del_init(&rfkill->node);
+ unlock:
+       mutex_unlock(&rfkill_global_mutex);
+       return error;
+}
+EXPORT_SYMBOL(rfkill_register);
+
+void rfkill_unregister(struct rfkill *rfkill)
+{
+       BUG_ON(!rfkill);
+
+       if (rfkill->ops->poll)
+               cancel_delayed_work_sync(&rfkill->poll_work);
+
+       cancel_work_sync(&rfkill->uevent_work);
+       cancel_work_sync(&rfkill->sync_work);
+
+       rfkill->registered = false;
+
+       device_del(&rfkill->dev);
+
+       mutex_lock(&rfkill_global_mutex);
+       rfkill_send_events(rfkill, RFKILL_OP_DEL);
+       list_del_init(&rfkill->node);
+       mutex_unlock(&rfkill_global_mutex);
+
+       rfkill_led_trigger_unregister(rfkill);
+}
+EXPORT_SYMBOL(rfkill_unregister);
+
+void rfkill_destroy(struct rfkill *rfkill)
+{
+       if (rfkill)
+               put_device(&rfkill->dev);
+}
+EXPORT_SYMBOL(rfkill_destroy);
+
+static int rfkill_fop_open(struct inode *inode, struct file *file)
+{
+       struct rfkill_data *data;
+       struct rfkill *rfkill;
+       struct rfkill_int_event *ev, *tmp;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&data->events);
+       mutex_init(&data->mtx);
+       init_waitqueue_head(&data->read_wait);
+
+       mutex_lock(&rfkill_global_mutex);
+       mutex_lock(&data->mtx);
+       /*
+        * start getting events from elsewhere but hold mtx to get
+        * startup events added first
+        */
+       list_add(&data->list, &rfkill_fds);
+
+       list_for_each_entry(rfkill, &rfkill_list, node) {
+               ev = kzalloc(sizeof(*ev), GFP_KERNEL);
+               if (!ev)
+                       goto free;
+               rfkill_fill_event(&ev->ev, rfkill, RFKILL_OP_ADD);
+               list_add_tail(&ev->list, &data->events);
+       }
+       mutex_unlock(&data->mtx);
+       mutex_unlock(&rfkill_global_mutex);
+
+       file->private_data = data;
+
+       return nonseekable_open(inode, file);
+
+ free:
+       mutex_unlock(&data->mtx);
+       mutex_unlock(&rfkill_global_mutex);
+       mutex_destroy(&data->mtx);
+       list_for_each_entry_safe(ev, tmp, &data->events, list)
+               kfree(ev);
+       kfree(data);
+       return -ENOMEM;
+}
+
+static unsigned int rfkill_fop_poll(struct file *file, poll_table *wait)
+{
+       struct rfkill_data *data = file->private_data;
+       unsigned int res = POLLOUT | POLLWRNORM;
+
+       poll_wait(file, &data->read_wait, wait);
+
+       mutex_lock(&data->mtx);
+       if (!list_empty(&data->events))
+               res = POLLIN | POLLRDNORM;
+       mutex_unlock(&data->mtx);
+
+       return res;
+}
+
+static bool rfkill_readable(struct rfkill_data *data)
+{
+       bool r;
+
+       mutex_lock(&data->mtx);
+       r = !list_empty(&data->events);
+       mutex_unlock(&data->mtx);
+
+       return r;
+}
+
+static ssize_t rfkill_fop_read(struct file *file, char __user *buf,
+                              size_t count, loff_t *pos)
+{
+       struct rfkill_data *data = file->private_data;
+       struct rfkill_int_event *ev;
+       unsigned long sz;
+       int ret;
+
+       mutex_lock(&data->mtx);
+
+       while (list_empty(&data->events)) {
+               if (file->f_flags & O_NONBLOCK) {
+                       ret = -EAGAIN;
+                       goto out;
+               }
+               mutex_unlock(&data->mtx);
+               ret = wait_event_interruptible(data->read_wait,
+                                              rfkill_readable(data));
+               mutex_lock(&data->mtx);
+
+               if (ret)
+                       goto out;
+       }
+
+       ev = list_first_entry(&data->events, struct rfkill_int_event,
+                               list);
+
+       sz = min_t(unsigned long, sizeof(ev->ev), count);
+       ret = sz;
+       if (copy_to_user(buf, &ev->ev, sz))
+               ret = -EFAULT;
+
+       list_del(&ev->list);
+       kfree(ev);
+ out:
+       mutex_unlock(&data->mtx);
+       return ret;
+}
+
+static ssize_t rfkill_fop_write(struct file *file, const char __user *buf,
+                               size_t count, loff_t *pos)
+{
+       struct rfkill *rfkill;
+       struct rfkill_event ev;
+
+       /* we don't need the 'hard' variable but accept it */
+       if (count < sizeof(ev) - 1)
+               return -EINVAL;
+
+       if (copy_from_user(&ev, buf, sizeof(ev) - 1))
+               return -EFAULT;
+
+       if (ev.op != RFKILL_OP_CHANGE && ev.op != RFKILL_OP_CHANGE_ALL)
+               return -EINVAL;
+
+       if (ev.type >= NUM_RFKILL_TYPES)
+               return -EINVAL;
+
+       mutex_lock(&rfkill_global_mutex);
+
+       if (ev.op == RFKILL_OP_CHANGE_ALL) {
+               if (ev.type == RFKILL_TYPE_ALL) {
+                       enum rfkill_type i;
+                       for (i = 0; i < NUM_RFKILL_TYPES; i++)
+                               rfkill_global_states[i].cur = ev.soft;
+               } else {
+                       rfkill_global_states[ev.type].cur = ev.soft;
+               }
+       }
+
+       list_for_each_entry(rfkill, &rfkill_list, node) {
+               if (rfkill->idx != ev.idx && ev.op != RFKILL_OP_CHANGE_ALL)
+                       continue;
+
+               if (rfkill->type != ev.type && ev.type != RFKILL_TYPE_ALL)
+                       continue;
+
+               rfkill_set_block(rfkill, ev.soft);
+       }
+       mutex_unlock(&rfkill_global_mutex);
+
+       return count;
+}
+
+static int rfkill_fop_release(struct inode *inode, struct file *file)
+{
+       struct rfkill_data *data = file->private_data;
+       struct rfkill_int_event *ev, *tmp;
+
+       mutex_lock(&rfkill_global_mutex);
+       list_del(&data->list);
+       mutex_unlock(&rfkill_global_mutex);
+
+       mutex_destroy(&data->mtx);
+       list_for_each_entry_safe(ev, tmp, &data->events, list)
+               kfree(ev);
+
+#ifdef CONFIG_RFKILL_INPUT
+       if (data->input_handler)
+               if (atomic_dec_return(&rfkill_input_disabled) == 0)
+                       printk(KERN_DEBUG "rfkill: input handler enabled\n");
+#endif
+
+       kfree(data);
+
+       return 0;
+}
+
+#ifdef CONFIG_RFKILL_INPUT
+static long rfkill_fop_ioctl(struct file *file, unsigned int cmd,
+                            unsigned long arg)
+{
+       struct rfkill_data *data = file->private_data;
+
+       if (_IOC_TYPE(cmd) != RFKILL_IOC_MAGIC)
+               return -ENOSYS;
+
+       if (_IOC_NR(cmd) != RFKILL_IOC_NOINPUT)
+               return -ENOSYS;
+
+       mutex_lock(&data->mtx);
+
+       if (!data->input_handler) {
+               if (atomic_inc_return(&rfkill_input_disabled) == 1)
+                       printk(KERN_DEBUG "rfkill: input handler disabled\n");
+               data->input_handler = true;
+       }
+
+       mutex_unlock(&data->mtx);
+
+       return 0;
+}
+#endif
+
+static const struct file_operations rfkill_fops = {
+       .open           = rfkill_fop_open,
+       .read           = rfkill_fop_read,
+       .write          = rfkill_fop_write,
+       .poll           = rfkill_fop_poll,
+       .release        = rfkill_fop_release,
+#ifdef CONFIG_RFKILL_INPUT
+       .unlocked_ioctl = rfkill_fop_ioctl,
+       .compat_ioctl   = rfkill_fop_ioctl,
+#endif
+};
+
+static struct miscdevice rfkill_miscdev = {
+       .name   = "rfkill",
+       .fops   = &rfkill_fops,
+       .minor  = MISC_DYNAMIC_MINOR,
+};
+
+static int __init rfkill_init(void)
+{
+       int error;
+       int i;
+
+       for (i = 0; i < NUM_RFKILL_TYPES; i++)
+               rfkill_global_states[i].cur = !rfkill_default_state;
+
+       error = class_register(&rfkill_class);
+       if (error)
+               goto out;
+
+       error = misc_register(&rfkill_miscdev);
+       if (error) {
+               class_unregister(&rfkill_class);
+               goto out;
+       }
+
+#ifdef CONFIG_RFKILL_INPUT
+       error = rfkill_handler_init();
+       if (error) {
+               misc_deregister(&rfkill_miscdev);
+               class_unregister(&rfkill_class);
+               goto out;
+       }
+#endif
+
+ out:
+       return error;
+}
+subsys_initcall(rfkill_init);
+
+static void __exit rfkill_exit(void)
+{
+#ifdef CONFIG_RFKILL_INPUT
+       rfkill_handler_exit();
+#endif
+       misc_deregister(&rfkill_miscdev);
+       class_unregister(&rfkill_class);
+}
+module_exit(rfkill_exit);
diff --git a/net/rfkill/input.c b/net/rfkill/input.c
new file mode 100644 (file)
index 0000000..a7295ad
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * Input layer to RF Kill interface connector
+ *
+ * Copyright (c) 2007 Dmitry Torokhov
+ * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * If you ever run into a situation in which you have a SW_ type rfkill
+ * input device, then you can revive code that was removed in the patch
+ * "rfkill-input: remove unused code".
+ */
+
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/init.h>
+#include <linux/rfkill.h>
+#include <linux/sched.h>
+
+#include "rfkill.h"
+
+enum rfkill_input_master_mode {
+       RFKILL_INPUT_MASTER_UNLOCK = 0,
+       RFKILL_INPUT_MASTER_RESTORE = 1,
+       RFKILL_INPUT_MASTER_UNBLOCKALL = 2,
+       NUM_RFKILL_INPUT_MASTER_MODES
+};
+
+/* Delay (in ms) between consecutive switch ops */
+#define RFKILL_OPS_DELAY 200
+
+static enum rfkill_input_master_mode rfkill_master_switch_mode =
+                                       RFKILL_INPUT_MASTER_UNBLOCKALL;
+module_param_named(master_switch_mode, rfkill_master_switch_mode, uint, 0);
+MODULE_PARM_DESC(master_switch_mode,
+       "SW_RFKILL_ALL ON should: 0=do nothing (only unlock); 1=restore; 2=unblock all");
+
+static spinlock_t rfkill_op_lock;
+static bool rfkill_op_pending;
+static unsigned long rfkill_sw_pending[BITS_TO_LONGS(NUM_RFKILL_TYPES)];
+static unsigned long rfkill_sw_state[BITS_TO_LONGS(NUM_RFKILL_TYPES)];
+
+enum rfkill_sched_op {
+       RFKILL_GLOBAL_OP_EPO = 0,
+       RFKILL_GLOBAL_OP_RESTORE,
+       RFKILL_GLOBAL_OP_UNLOCK,
+       RFKILL_GLOBAL_OP_UNBLOCK,
+};
+
+static enum rfkill_sched_op rfkill_master_switch_op;
+static enum rfkill_sched_op rfkill_op;
+
+static void __rfkill_handle_global_op(enum rfkill_sched_op op)
+{
+       unsigned int i;
+
+       switch (op) {
+       case RFKILL_GLOBAL_OP_EPO:
+               rfkill_epo();
+               break;
+       case RFKILL_GLOBAL_OP_RESTORE:
+               rfkill_restore_states();
+               break;
+       case RFKILL_GLOBAL_OP_UNLOCK:
+               rfkill_remove_epo_lock();
+               break;
+       case RFKILL_GLOBAL_OP_UNBLOCK:
+               rfkill_remove_epo_lock();
+               for (i = 0; i < NUM_RFKILL_TYPES; i++)
+                       rfkill_switch_all(i, false);
+               break;
+       default:
+               /* memory corruption or bug, fail safely */
+               rfkill_epo();
+               WARN(1, "Unknown requested operation %d! "
+                       "rfkill Emergency Power Off activated\n",
+                       op);
+       }
+}
+
+static void __rfkill_handle_normal_op(const enum rfkill_type type,
+                                     const bool complement)
+{
+       bool blocked;
+
+       blocked = rfkill_get_global_sw_state(type);
+       if (complement)
+               blocked = !blocked;
+
+       rfkill_switch_all(type, blocked);
+}
+
+static void rfkill_op_handler(struct work_struct *work)
+{
+       unsigned int i;
+       bool c;
+
+       spin_lock_irq(&rfkill_op_lock);
+       do {
+               if (rfkill_op_pending) {
+                       enum rfkill_sched_op op = rfkill_op;
+                       rfkill_op_pending = false;
+                       memset(rfkill_sw_pending, 0,
+                               sizeof(rfkill_sw_pending));
+                       spin_unlock_irq(&rfkill_op_lock);
+
+                       __rfkill_handle_global_op(op);
+
+                       spin_lock_irq(&rfkill_op_lock);
+
+                       /*
+                        * handle global ops first -- during unlocked period
+                        * we might have gotten a new global op.
+                        */
+                       if (rfkill_op_pending)
+                               continue;
+               }
+
+               if (rfkill_is_epo_lock_active())
+                       continue;
+
+               for (i = 0; i < NUM_RFKILL_TYPES; i++) {
+                       if (__test_and_clear_bit(i, rfkill_sw_pending)) {
+                               c = __test_and_clear_bit(i, rfkill_sw_state);
+                               spin_unlock_irq(&rfkill_op_lock);
+
+                               __rfkill_handle_normal_op(i, c);
+
+                               spin_lock_irq(&rfkill_op_lock);
+                       }
+               }
+       } while (rfkill_op_pending);
+       spin_unlock_irq(&rfkill_op_lock);
+}
+
+static DECLARE_DELAYED_WORK(rfkill_op_work, rfkill_op_handler);
+static unsigned long rfkill_last_scheduled;
+
+static unsigned long rfkill_ratelimit(const unsigned long last)
+{
+       const unsigned long delay = msecs_to_jiffies(RFKILL_OPS_DELAY);
+       return (time_after(jiffies, last + delay)) ? 0 : delay;
+}
+
+static void rfkill_schedule_ratelimited(void)
+{
+       if (delayed_work_pending(&rfkill_op_work))
+               return;
+       schedule_delayed_work(&rfkill_op_work,
+                             rfkill_ratelimit(rfkill_last_scheduled));
+       rfkill_last_scheduled = jiffies;
+}
+
+static void rfkill_schedule_global_op(enum rfkill_sched_op op)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&rfkill_op_lock, flags);
+       rfkill_op = op;
+       rfkill_op_pending = true;
+       if (op == RFKILL_GLOBAL_OP_EPO && !rfkill_is_epo_lock_active()) {
+               /* bypass the limiter for EPO */
+               cancel_delayed_work(&rfkill_op_work);
+               schedule_delayed_work(&rfkill_op_work, 0);
+               rfkill_last_scheduled = jiffies;
+       } else
+               rfkill_schedule_ratelimited();
+       spin_unlock_irqrestore(&rfkill_op_lock, flags);
+}
+
+static void rfkill_schedule_toggle(enum rfkill_type type)
+{
+       unsigned long flags;
+
+       if (rfkill_is_epo_lock_active())
+               return;
+
+       spin_lock_irqsave(&rfkill_op_lock, flags);
+       if (!rfkill_op_pending) {
+               __set_bit(type, rfkill_sw_pending);
+               __change_bit(type, rfkill_sw_state);
+               rfkill_schedule_ratelimited();
+       }
+       spin_unlock_irqrestore(&rfkill_op_lock, flags);
+}
+
+static void rfkill_schedule_evsw_rfkillall(int state)
+{
+       if (state)
+               rfkill_schedule_global_op(rfkill_master_switch_op);
+       else
+               rfkill_schedule_global_op(RFKILL_GLOBAL_OP_EPO);
+}
+
+static void rfkill_event(struct input_handle *handle, unsigned int type,
+                       unsigned int code, int data)
+{
+       if (type == EV_KEY && data == 1) {
+               switch (code) {
+               case KEY_WLAN:
+                       rfkill_schedule_toggle(RFKILL_TYPE_WLAN);
+                       break;
+               case KEY_BLUETOOTH:
+                       rfkill_schedule_toggle(RFKILL_TYPE_BLUETOOTH);
+                       break;
+               case KEY_UWB:
+                       rfkill_schedule_toggle(RFKILL_TYPE_UWB);
+                       break;
+               case KEY_WIMAX:
+                       rfkill_schedule_toggle(RFKILL_TYPE_WIMAX);
+                       break;
+               }
+       } else if (type == EV_SW && code == SW_RFKILL_ALL)
+               rfkill_schedule_evsw_rfkillall(data);
+}
+
+static int rfkill_connect(struct input_handler *handler, struct input_dev *dev,
+                         const struct input_device_id *id)
+{
+       struct input_handle *handle;
+       int error;
+
+       handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
+       if (!handle)
+               return -ENOMEM;
+
+       handle->dev = dev;
+       handle->handler = handler;
+       handle->name = "rfkill";
+
+       /* causes rfkill_start() to be called */
+       error = input_register_handle(handle);
+       if (error)
+               goto err_free_handle;
+
+       error = input_open_device(handle);
+       if (error)
+               goto err_unregister_handle;
+
+       return 0;
+
+ err_unregister_handle:
+       input_unregister_handle(handle);
+ err_free_handle:
+       kfree(handle);
+       return error;
+}
+
+static void rfkill_start(struct input_handle *handle)
+{
+       /*
+        * Take event_lock to guard against configuration changes, we
+        * should be able to deal with concurrency with rfkill_event()
+        * just fine (which event_lock will also avoid).
+        */
+       spin_lock_irq(&handle->dev->event_lock);
+
+       if (test_bit(EV_SW, handle->dev->evbit) &&
+           test_bit(SW_RFKILL_ALL, handle->dev->swbit))
+               rfkill_schedule_evsw_rfkillall(test_bit(SW_RFKILL_ALL,
+                                                       handle->dev->sw));
+
+       spin_unlock_irq(&handle->dev->event_lock);
+}
+
+static void rfkill_disconnect(struct input_handle *handle)
+{
+       input_close_device(handle);
+       input_unregister_handle(handle);
+       kfree(handle);
+}
+
+static const struct input_device_id rfkill_ids[] = {
+       {
+               .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
+               .evbit = { BIT_MASK(EV_KEY) },
+               .keybit = { [BIT_WORD(KEY_WLAN)] = BIT_MASK(KEY_WLAN) },
+       },
+       {
+               .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
+               .evbit = { BIT_MASK(EV_KEY) },
+               .keybit = { [BIT_WORD(KEY_BLUETOOTH)] = BIT_MASK(KEY_BLUETOOTH) },
+       },
+       {
+               .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
+               .evbit = { BIT_MASK(EV_KEY) },
+               .keybit = { [BIT_WORD(KEY_UWB)] = BIT_MASK(KEY_UWB) },
+       },
+       {
+               .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
+               .evbit = { BIT_MASK(EV_KEY) },
+               .keybit = { [BIT_WORD(KEY_WIMAX)] = BIT_MASK(KEY_WIMAX) },
+       },
+       {
+               .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_SWBIT,
+               .evbit = { BIT(EV_SW) },
+               .swbit = { [BIT_WORD(SW_RFKILL_ALL)] = BIT_MASK(SW_RFKILL_ALL) },
+       },
+       { }
+};
+
+static struct input_handler rfkill_handler = {
+       .name = "rfkill",
+       .event = rfkill_event,
+       .connect = rfkill_connect,
+       .start = rfkill_start,
+       .disconnect = rfkill_disconnect,
+       .id_table = rfkill_ids,
+};
+
+int __init rfkill_handler_init(void)
+{
+       switch (rfkill_master_switch_mode) {
+       case RFKILL_INPUT_MASTER_UNBLOCKALL:
+               rfkill_master_switch_op = RFKILL_GLOBAL_OP_UNBLOCK;
+               break;
+       case RFKILL_INPUT_MASTER_RESTORE:
+               rfkill_master_switch_op = RFKILL_GLOBAL_OP_RESTORE;
+               break;
+       case RFKILL_INPUT_MASTER_UNLOCK:
+               rfkill_master_switch_op = RFKILL_GLOBAL_OP_UNLOCK;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       spin_lock_init(&rfkill_op_lock);
+
+       /* Avoid delay at first schedule */
+       rfkill_last_scheduled =
+                       jiffies - msecs_to_jiffies(RFKILL_OPS_DELAY) - 1;
+       return input_register_handler(&rfkill_handler);
+}
+
+void __exit rfkill_handler_exit(void)
+{
+       input_unregister_handler(&rfkill_handler);
+       cancel_delayed_work_sync(&rfkill_op_work);
+}
diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c
deleted file mode 100644 (file)
index 60a34f3..0000000
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * Input layer to RF Kill interface connector
- *
- * Copyright (c) 2007 Dmitry Torokhov
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/input.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
-#include <linux/init.h>
-#include <linux/rfkill.h>
-#include <linux/sched.h>
-
-#include "rfkill-input.h"
-
-MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
-MODULE_DESCRIPTION("Input layer to RF switch connector");
-MODULE_LICENSE("GPL");
-
-enum rfkill_input_master_mode {
-       RFKILL_INPUT_MASTER_DONOTHING = 0,
-       RFKILL_INPUT_MASTER_RESTORE = 1,
-       RFKILL_INPUT_MASTER_UNBLOCKALL = 2,
-       RFKILL_INPUT_MASTER_MAX,        /* marker */
-};
-
-/* Delay (in ms) between consecutive switch ops */
-#define RFKILL_OPS_DELAY 200
-
-static enum rfkill_input_master_mode rfkill_master_switch_mode =
-                                       RFKILL_INPUT_MASTER_UNBLOCKALL;
-module_param_named(master_switch_mode, rfkill_master_switch_mode, uint, 0);
-MODULE_PARM_DESC(master_switch_mode,
-       "SW_RFKILL_ALL ON should: 0=do nothing; 1=restore; 2=unblock all");
-
-enum rfkill_global_sched_op {
-       RFKILL_GLOBAL_OP_EPO = 0,
-       RFKILL_GLOBAL_OP_RESTORE,
-       RFKILL_GLOBAL_OP_UNLOCK,
-       RFKILL_GLOBAL_OP_UNBLOCK,
-};
-
-struct rfkill_task {
-       struct delayed_work dwork;
-
-       /* ensures that task is serialized */
-       struct mutex mutex;
-
-       /* protects everything below */
-       spinlock_t lock;
-
-       /* pending regular switch operations (1=pending) */
-       unsigned long sw_pending[BITS_TO_LONGS(RFKILL_TYPE_MAX)];
-
-       /* should the state be complemented (1=yes) */
-       unsigned long sw_togglestate[BITS_TO_LONGS(RFKILL_TYPE_MAX)];
-
-       bool global_op_pending;
-       enum rfkill_global_sched_op op;
-
-       /* last time it was scheduled */
-       unsigned long last_scheduled;
-};
-
-static void __rfkill_handle_global_op(enum rfkill_global_sched_op op)
-{
-       unsigned int i;
-
-       switch (op) {
-       case RFKILL_GLOBAL_OP_EPO:
-               rfkill_epo();
-               break;
-       case RFKILL_GLOBAL_OP_RESTORE:
-               rfkill_restore_states();
-               break;
-       case RFKILL_GLOBAL_OP_UNLOCK:
-               rfkill_remove_epo_lock();
-               break;
-       case RFKILL_GLOBAL_OP_UNBLOCK:
-               rfkill_remove_epo_lock();
-               for (i = 0; i < RFKILL_TYPE_MAX; i++)
-                       rfkill_switch_all(i, RFKILL_STATE_UNBLOCKED);
-               break;
-       default:
-               /* memory corruption or bug, fail safely */
-               rfkill_epo();
-               WARN(1, "Unknown requested operation %d! "
-                       "rfkill Emergency Power Off activated\n",
-                       op);
-       }
-}
-
-static void __rfkill_handle_normal_op(const enum rfkill_type type,
-                       const bool c)
-{
-       enum rfkill_state state;
-
-       state = rfkill_get_global_state(type);
-       if (c)
-               state = rfkill_state_complement(state);
-
-       rfkill_switch_all(type, state);
-}
-
-static void rfkill_task_handler(struct work_struct *work)
-{
-       struct rfkill_task *task = container_of(work,
-                                       struct rfkill_task, dwork.work);
-       bool doit = true;
-
-       mutex_lock(&task->mutex);
-
-       spin_lock_irq(&task->lock);
-       while (doit) {
-               if (task->global_op_pending) {
-                       enum rfkill_global_sched_op op = task->op;
-                       task->global_op_pending = false;
-                       memset(task->sw_pending, 0, sizeof(task->sw_pending));
-                       spin_unlock_irq(&task->lock);
-
-                       __rfkill_handle_global_op(op);
-
-                       /* make sure we do at least one pass with
-                        * !task->global_op_pending */
-                       spin_lock_irq(&task->lock);
-                       continue;
-               } else if (!rfkill_is_epo_lock_active()) {
-                       unsigned int i = 0;
-
-                       while (!task->global_op_pending &&
-                                               i < RFKILL_TYPE_MAX) {
-                               if (test_and_clear_bit(i, task->sw_pending)) {
-                                       bool c;
-                                       c = test_and_clear_bit(i,
-                                                       task->sw_togglestate);
-                                       spin_unlock_irq(&task->lock);
-
-                                       __rfkill_handle_normal_op(i, c);
-
-                                       spin_lock_irq(&task->lock);
-                               }
-                               i++;
-                       }
-               }
-               doit = task->global_op_pending;
-       }
-       spin_unlock_irq(&task->lock);
-
-       mutex_unlock(&task->mutex);
-}
-
-static struct rfkill_task rfkill_task = {
-       .dwork = __DELAYED_WORK_INITIALIZER(rfkill_task.dwork,
-                               rfkill_task_handler),
-       .mutex = __MUTEX_INITIALIZER(rfkill_task.mutex),
-       .lock = __SPIN_LOCK_UNLOCKED(rfkill_task.lock),
-};
-
-static unsigned long rfkill_ratelimit(const unsigned long last)
-{
-       const unsigned long delay = msecs_to_jiffies(RFKILL_OPS_DELAY);
-       return (time_after(jiffies, last + delay)) ? 0 : delay;
-}
-
-static void rfkill_schedule_ratelimited(void)
-{
-       if (!delayed_work_pending(&rfkill_task.dwork)) {
-               schedule_delayed_work(&rfkill_task.dwork,
-                               rfkill_ratelimit(rfkill_task.last_scheduled));
-               rfkill_task.last_scheduled = jiffies;
-       }
-}
-
-static void rfkill_schedule_global_op(enum rfkill_global_sched_op op)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&rfkill_task.lock, flags);
-       rfkill_task.op = op;
-       rfkill_task.global_op_pending = true;
-       if (op == RFKILL_GLOBAL_OP_EPO && !rfkill_is_epo_lock_active()) {
-               /* bypass the limiter for EPO */
-               cancel_delayed_work(&rfkill_task.dwork);
-               schedule_delayed_work(&rfkill_task.dwork, 0);
-               rfkill_task.last_scheduled = jiffies;
-       } else
-               rfkill_schedule_ratelimited();
-       spin_unlock_irqrestore(&rfkill_task.lock, flags);
-}
-
-static void rfkill_schedule_toggle(enum rfkill_type type)
-{
-       unsigned long flags;
-
-       if (rfkill_is_epo_lock_active())
-               return;
-
-       spin_lock_irqsave(&rfkill_task.lock, flags);
-       if (!rfkill_task.global_op_pending) {
-               set_bit(type, rfkill_task.sw_pending);
-               change_bit(type, rfkill_task.sw_togglestate);
-               rfkill_schedule_ratelimited();
-       }
-       spin_unlock_irqrestore(&rfkill_task.lock, flags);
-}
-
-static void rfkill_schedule_evsw_rfkillall(int state)
-{
-       if (state) {
-               switch (rfkill_master_switch_mode) {
-               case RFKILL_INPUT_MASTER_UNBLOCKALL:
-                       rfkill_schedule_global_op(RFKILL_GLOBAL_OP_UNBLOCK);
-                       break;
-               case RFKILL_INPUT_MASTER_RESTORE:
-                       rfkill_schedule_global_op(RFKILL_GLOBAL_OP_RESTORE);
-                       break;
-               case RFKILL_INPUT_MASTER_DONOTHING:
-                       rfkill_schedule_global_op(RFKILL_GLOBAL_OP_UNLOCK);
-                       break;
-               default:
-                       /* memory corruption or driver bug! fail safely */
-                       rfkill_schedule_global_op(RFKILL_GLOBAL_OP_EPO);
-                       WARN(1, "Unknown rfkill_master_switch_mode (%d), "
-                               "driver bug or memory corruption detected!\n",
-                               rfkill_master_switch_mode);
-                       break;
-               }
-       } else
-               rfkill_schedule_global_op(RFKILL_GLOBAL_OP_EPO);
-}
-
-static void rfkill_event(struct input_handle *handle, unsigned int type,
-                       unsigned int code, int data)
-{
-       if (type == EV_KEY && data == 1) {
-               enum rfkill_type t;
-
-               switch (code) {
-               case KEY_WLAN:
-                       t = RFKILL_TYPE_WLAN;
-                       break;
-               case KEY_BLUETOOTH:
-                       t = RFKILL_TYPE_BLUETOOTH;
-                       break;
-               case KEY_UWB:
-                       t = RFKILL_TYPE_UWB;
-                       break;
-               case KEY_WIMAX:
-                       t = RFKILL_TYPE_WIMAX;
-                       break;
-               default:
-                       return;
-               }
-               rfkill_schedule_toggle(t);
-               return;
-       } else if (type == EV_SW) {
-               switch (code) {
-               case SW_RFKILL_ALL:
-                       rfkill_schedule_evsw_rfkillall(data);
-                       return;
-               default:
-                       return;
-               }
-       }
-}
-
-static int rfkill_connect(struct input_handler *handler, struct input_dev *dev,
-                         const struct input_device_id *id)
-{
-       struct input_handle *handle;
-       int error;
-
-       handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
-       if (!handle)
-               return -ENOMEM;
-
-       handle->dev = dev;
-       handle->handler = handler;
-       handle->name = "rfkill";
-
-       /* causes rfkill_start() to be called */
-       error = input_register_handle(handle);
-       if (error)
-               goto err_free_handle;
-
-       error = input_open_device(handle);
-       if (error)
-               goto err_unregister_handle;
-
-       return 0;
-
- err_unregister_handle:
-       input_unregister_handle(handle);
- err_free_handle:
-       kfree(handle);
-       return error;
-}
-
-static void rfkill_start(struct input_handle *handle)
-{
-       /* Take event_lock to guard against configuration changes, we
-        * should be able to deal with concurrency with rfkill_event()
-        * just fine (which event_lock will also avoid). */
-       spin_lock_irq(&handle->dev->event_lock);
-
-       if (test_bit(EV_SW, handle->dev->evbit)) {
-               if (test_bit(SW_RFKILL_ALL, handle->dev->swbit))
-                       rfkill_schedule_evsw_rfkillall(test_bit(SW_RFKILL_ALL,
-                                                       handle->dev->sw));
-               /* add resync for further EV_SW events here */
-       }
-
-       spin_unlock_irq(&handle->dev->event_lock);
-}
-
-static void rfkill_disconnect(struct input_handle *handle)
-{
-       input_close_device(handle);
-       input_unregister_handle(handle);
-       kfree(handle);
-}
-
-static const struct input_device_id rfkill_ids[] = {
-       {
-               .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
-               .evbit = { BIT_MASK(EV_KEY) },
-               .keybit = { [BIT_WORD(KEY_WLAN)] = BIT_MASK(KEY_WLAN) },
-       },
-       {
-               .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
-               .evbit = { BIT_MASK(EV_KEY) },
-               .keybit = { [BIT_WORD(KEY_BLUETOOTH)] = BIT_MASK(KEY_BLUETOOTH) },
-       },
-       {
-               .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
-               .evbit = { BIT_MASK(EV_KEY) },
-               .keybit = { [BIT_WORD(KEY_UWB)] = BIT_MASK(KEY_UWB) },
-       },
-       {
-               .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
-               .evbit = { BIT_MASK(EV_KEY) },
-               .keybit = { [BIT_WORD(KEY_WIMAX)] = BIT_MASK(KEY_WIMAX) },
-       },
-       {
-               .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_SWBIT,
-               .evbit = { BIT(EV_SW) },
-               .swbit = { [BIT_WORD(SW_RFKILL_ALL)] = BIT_MASK(SW_RFKILL_ALL) },
-       },
-       { }
-};
-
-static struct input_handler rfkill_handler = {
-       .event =        rfkill_event,
-       .connect =      rfkill_connect,
-       .disconnect =   rfkill_disconnect,
-       .start =        rfkill_start,
-       .name =         "rfkill",
-       .id_table =     rfkill_ids,
-};
-
-static int __init rfkill_handler_init(void)
-{
-       if (rfkill_master_switch_mode >= RFKILL_INPUT_MASTER_MAX)
-               return -EINVAL;
-
-       /*
-        * The penalty to not doing this is a possible RFKILL_OPS_DELAY delay
-        * at the first use.  Acceptable, but if we can avoid it, why not?
-        */
-       rfkill_task.last_scheduled =
-                       jiffies - msecs_to_jiffies(RFKILL_OPS_DELAY) - 1;
-       return input_register_handler(&rfkill_handler);
-}
-
-static void __exit rfkill_handler_exit(void)
-{
-       input_unregister_handler(&rfkill_handler);
-       cancel_delayed_work_sync(&rfkill_task.dwork);
-       rfkill_remove_epo_lock();
-}
-
-module_init(rfkill_handler_init);
-module_exit(rfkill_handler_exit);
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c
deleted file mode 100644 (file)
index 4f5a831..0000000
+++ /dev/null
@@ -1,855 +0,0 @@
-/*
- * Copyright (C) 2006 - 2007 Ivo van Doorn
- * Copyright (C) 2007 Dmitry Torokhov
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the
- * Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/workqueue.h>
-#include <linux/capability.h>
-#include <linux/list.h>
-#include <linux/mutex.h>
-#include <linux/rfkill.h>
-
-/* Get declaration of rfkill_switch_all() to shut up sparse. */
-#include "rfkill-input.h"
-
-
-MODULE_AUTHOR("Ivo van Doorn <IvDoorn@gmail.com>");
-MODULE_VERSION("1.0");
-MODULE_DESCRIPTION("RF switch support");
-MODULE_LICENSE("GPL");
-
-static LIST_HEAD(rfkill_list); /* list of registered rf switches */
-static DEFINE_MUTEX(rfkill_global_mutex);
-
-static unsigned int rfkill_default_state = RFKILL_STATE_UNBLOCKED;
-module_param_named(default_state, rfkill_default_state, uint, 0444);
-MODULE_PARM_DESC(default_state,
-                "Default initial state for all radio types, 0 = radio off");
-
-struct rfkill_gsw_state {
-       enum rfkill_state current_state;
-       enum rfkill_state default_state;
-};
-
-static struct rfkill_gsw_state rfkill_global_states[RFKILL_TYPE_MAX];
-static unsigned long rfkill_states_lockdflt[BITS_TO_LONGS(RFKILL_TYPE_MAX)];
-static bool rfkill_epo_lock_active;
-
-
-#ifdef CONFIG_RFKILL_LEDS
-static void rfkill_led_trigger(struct rfkill *rfkill,
-                              enum rfkill_state state)
-{
-       struct led_trigger *led = &rfkill->led_trigger;
-
-       if (!led->name)
-               return;
-       if (state != RFKILL_STATE_UNBLOCKED)
-               led_trigger_event(led, LED_OFF);
-       else
-               led_trigger_event(led, LED_FULL);
-}
-
-static void rfkill_led_trigger_activate(struct led_classdev *led)
-{
-       struct rfkill *rfkill = container_of(led->trigger,
-                       struct rfkill, led_trigger);
-
-       rfkill_led_trigger(rfkill, rfkill->state);
-}
-#else
-static inline void rfkill_led_trigger(struct rfkill *rfkill,
-                                       enum rfkill_state state)
-{
-}
-#endif /* CONFIG_RFKILL_LEDS */
-
-static void rfkill_uevent(struct rfkill *rfkill)
-{
-       kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE);
-}
-
-static void update_rfkill_state(struct rfkill *rfkill)
-{
-       enum rfkill_state newstate, oldstate;
-
-       if (rfkill->get_state) {
-               mutex_lock(&rfkill->mutex);
-               if (!rfkill->get_state(rfkill->data, &newstate)) {
-                       oldstate = rfkill->state;
-                       rfkill->state = newstate;
-                       if (oldstate != newstate)
-                               rfkill_uevent(rfkill);
-               }
-               mutex_unlock(&rfkill->mutex);
-       }
-       rfkill_led_trigger(rfkill, rfkill->state);
-}
-
-/**
- * rfkill_toggle_radio - wrapper for toggle_radio hook
- * @rfkill: the rfkill struct to use
- * @force: calls toggle_radio even if cache says it is not needed,
- *     and also makes sure notifications of the state will be
- *     sent even if it didn't change
- * @state: the new state to call toggle_radio() with
- *
- * Calls rfkill->toggle_radio, enforcing the API for toggle_radio
- * calls and handling all the red tape such as issuing notifications
- * if the call is successful.
- *
- * Suspended devices are not touched at all, and -EAGAIN is returned.
- *
- * Note that the @force parameter cannot override a (possibly cached)
- * state of RFKILL_STATE_HARD_BLOCKED.  Any device making use of
- * RFKILL_STATE_HARD_BLOCKED implements either get_state() or
- * rfkill_force_state(), so the cache either is bypassed or valid.
- *
- * Note that we do call toggle_radio for RFKILL_STATE_SOFT_BLOCKED
- * even if the radio is in RFKILL_STATE_HARD_BLOCKED state, so as to
- * give the driver a hint that it should double-BLOCK the transmitter.
- *
- * Caller must have acquired rfkill->mutex.
- */
-static int rfkill_toggle_radio(struct rfkill *rfkill,
-                               enum rfkill_state state,
-                               int force)
-{
-       int retval = 0;
-       enum rfkill_state oldstate, newstate;
-
-       if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP))
-               return -EBUSY;
-
-       oldstate = rfkill->state;
-
-       if (rfkill->get_state && !force &&
-           !rfkill->get_state(rfkill->data, &newstate)) {
-               rfkill->state = newstate;
-       }
-
-       switch (state) {
-       case RFKILL_STATE_HARD_BLOCKED:
-               /* typically happens when refreshing hardware state,
-                * such as on resume */
-               state = RFKILL_STATE_SOFT_BLOCKED;
-               break;
-       case RFKILL_STATE_UNBLOCKED:
-               /* force can't override this, only rfkill_force_state() can */
-               if (rfkill->state == RFKILL_STATE_HARD_BLOCKED)
-                       return -EPERM;
-               break;
-       case RFKILL_STATE_SOFT_BLOCKED:
-               /* nothing to do, we want to give drivers the hint to double
-                * BLOCK even a transmitter that is already in state
-                * RFKILL_STATE_HARD_BLOCKED */
-               break;
-       default:
-               WARN(1, KERN_WARNING
-                       "rfkill: illegal state %d passed as parameter "
-                       "to rfkill_toggle_radio\n", state);
-               return -EINVAL;
-       }
-
-       if (force || state != rfkill->state) {
-               retval = rfkill->toggle_radio(rfkill->data, state);
-               /* never allow a HARD->SOFT downgrade! */
-               if (!retval && rfkill->state != RFKILL_STATE_HARD_BLOCKED)
-                       rfkill->state = state;
-       }
-
-       if (force || rfkill->state != oldstate)
-               rfkill_uevent(rfkill);
-
-       rfkill_led_trigger(rfkill, rfkill->state);
-       return retval;
-}
-
-/**
- * __rfkill_switch_all - Toggle state of all switches of given type
- * @type: type of interfaces to be affected
- * @state: the new state
- *
- * This function toggles the state of all switches of given type,
- * unless a specific switch is claimed by userspace (in which case,
- * that switch is left alone) or suspended.
- *
- * Caller must have acquired rfkill_global_mutex.
- */
-static void __rfkill_switch_all(const enum rfkill_type type,
-                               const enum rfkill_state state)
-{
-       struct rfkill *rfkill;
-
-       if (WARN((state >= RFKILL_STATE_MAX || type >= RFKILL_TYPE_MAX),
-                       KERN_WARNING
-                       "rfkill: illegal state %d or type %d "
-                       "passed as parameter to __rfkill_switch_all\n",
-                       state, type))
-               return;
-
-       rfkill_global_states[type].current_state = state;
-       list_for_each_entry(rfkill, &rfkill_list, node) {
-               if (rfkill->type == type) {
-                       mutex_lock(&rfkill->mutex);
-                       rfkill_toggle_radio(rfkill, state, 0);
-                       mutex_unlock(&rfkill->mutex);
-                       rfkill_led_trigger(rfkill, rfkill->state);
-               }
-       }
-}
-
-/**
- * rfkill_switch_all - Toggle state of all switches of given type
- * @type: type of interfaces to be affected
- * @state: the new state
- *
- * Acquires rfkill_global_mutex and calls __rfkill_switch_all(@type, @state).
- * Please refer to __rfkill_switch_all() for details.
- *
- * Does nothing if the EPO lock is active.
- */
-void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state)
-{
-       mutex_lock(&rfkill_global_mutex);
-       if (!rfkill_epo_lock_active)
-               __rfkill_switch_all(type, state);
-       mutex_unlock(&rfkill_global_mutex);
-}
-EXPORT_SYMBOL(rfkill_switch_all);
-
-/**
- * rfkill_epo - emergency power off all transmitters
- *
- * This kicks all non-suspended rfkill devices to RFKILL_STATE_SOFT_BLOCKED,
- * ignoring everything in its path but rfkill_global_mutex and rfkill->mutex.
- *
- * The global state before the EPO is saved and can be restored later
- * using rfkill_restore_states().
- */
-void rfkill_epo(void)
-{
-       struct rfkill *rfkill;
-       int i;
-
-       mutex_lock(&rfkill_global_mutex);
-
-       rfkill_epo_lock_active = true;
-       list_for_each_entry(rfkill, &rfkill_list, node) {
-               mutex_lock(&rfkill->mutex);
-               rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1);
-               mutex_unlock(&rfkill->mutex);
-       }
-       for (i = 0; i < RFKILL_TYPE_MAX; i++) {
-               rfkill_global_states[i].default_state =
-                               rfkill_global_states[i].current_state;
-               rfkill_global_states[i].current_state =
-                               RFKILL_STATE_SOFT_BLOCKED;
-       }
-       mutex_unlock(&rfkill_global_mutex);
-       rfkill_led_trigger(rfkill, rfkill->state);
-}
-EXPORT_SYMBOL_GPL(rfkill_epo);
-
-/**
- * rfkill_restore_states - restore global states
- *
- * Restore (and sync switches to) the global state from the
- * states in rfkill_default_states.  This can undo the effects of
- * a call to rfkill_epo().
- */
-void rfkill_restore_states(void)
-{
-       int i;
-
-       mutex_lock(&rfkill_global_mutex);
-
-       rfkill_epo_lock_active = false;
-       for (i = 0; i < RFKILL_TYPE_MAX; i++)
-               __rfkill_switch_all(i, rfkill_global_states[i].default_state);
-       mutex_unlock(&rfkill_global_mutex);
-}
-EXPORT_SYMBOL_GPL(rfkill_restore_states);
-
-/**
- * rfkill_remove_epo_lock - unlock state changes
- *
- * Used by rfkill-input manually unlock state changes, when
- * the EPO switch is deactivated.
- */
-void rfkill_remove_epo_lock(void)
-{
-       mutex_lock(&rfkill_global_mutex);
-       rfkill_epo_lock_active = false;
-       mutex_unlock(&rfkill_global_mutex);
-}
-EXPORT_SYMBOL_GPL(rfkill_remove_epo_lock);
-
-/**
- * rfkill_is_epo_lock_active - returns true EPO is active
- *
- * Returns 0 (false) if there is NOT an active EPO contidion,
- * and 1 (true) if there is an active EPO contition, which
- * locks all radios in one of the BLOCKED states.
- *
- * Can be called in atomic context.
- */
-bool rfkill_is_epo_lock_active(void)
-{
-       return rfkill_epo_lock_active;
-}
-EXPORT_SYMBOL_GPL(rfkill_is_epo_lock_active);
-
-/**
- * rfkill_get_global_state - returns global state for a type
- * @type: the type to get the global state of
- *
- * Returns the current global state for a given wireless
- * device type.
- */
-enum rfkill_state rfkill_get_global_state(const enum rfkill_type type)
-{
-       return rfkill_global_states[type].current_state;
-}
-EXPORT_SYMBOL_GPL(rfkill_get_global_state);
-
-/**
- * rfkill_force_state - Force the internal rfkill radio state
- * @rfkill: pointer to the rfkill class to modify.
- * @state: the current radio state the class should be forced to.
- *
- * This function updates the internal state of the radio cached
- * by the rfkill class.  It should be used when the driver gets
- * a notification by the firmware/hardware of the current *real*
- * state of the radio rfkill switch.
- *
- * Devices which are subject to external changes on their rfkill
- * state (such as those caused by a hardware rfkill line) MUST
- * have their driver arrange to call rfkill_force_state() as soon
- * as possible after such a change.
- *
- * This function may not be called from an atomic context.
- */
-int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state)
-{
-       enum rfkill_state oldstate;
-
-       BUG_ON(!rfkill);
-       if (WARN((state >= RFKILL_STATE_MAX),
-                       KERN_WARNING
-                       "rfkill: illegal state %d passed as parameter "
-                       "to rfkill_force_state\n", state))
-               return -EINVAL;
-
-       mutex_lock(&rfkill->mutex);
-
-       oldstate = rfkill->state;
-       rfkill->state = state;
-
-       if (state != oldstate)
-               rfkill_uevent(rfkill);
-
-       mutex_unlock(&rfkill->mutex);
-       rfkill_led_trigger(rfkill, rfkill->state);
-
-       return 0;
-}
-EXPORT_SYMBOL(rfkill_force_state);
-
-static ssize_t rfkill_name_show(struct device *dev,
-                               struct device_attribute *attr,
-                               char *buf)
-{
-       struct rfkill *rfkill = to_rfkill(dev);
-
-       return sprintf(buf, "%s\n", rfkill->name);
-}
-
-static const char *rfkill_get_type_str(enum rfkill_type type)
-{
-       switch (type) {
-       case RFKILL_TYPE_WLAN:
-               return "wlan";
-       case RFKILL_TYPE_BLUETOOTH:
-               return "bluetooth";
-       case RFKILL_TYPE_UWB:
-               return "ultrawideband";
-       case RFKILL_TYPE_WIMAX:
-               return "wimax";
-       case RFKILL_TYPE_WWAN:
-               return "wwan";
-       default:
-               BUG();
-       }
-}
-
-static ssize_t rfkill_type_show(struct device *dev,
-                               struct device_attribute *attr,
-                               char *buf)
-{
-       struct rfkill *rfkill = to_rfkill(dev);
-
-       return sprintf(buf, "%s\n", rfkill_get_type_str(rfkill->type));
-}
-
-static ssize_t rfkill_state_show(struct device *dev,
-                                struct device_attribute *attr,
-                                char *buf)
-{
-       struct rfkill *rfkill = to_rfkill(dev);
-
-       update_rfkill_state(rfkill);
-       return sprintf(buf, "%d\n", rfkill->state);
-}
-
-static ssize_t rfkill_state_store(struct device *dev,
-                                 struct device_attribute *attr,
-                                 const char *buf, size_t count)
-{
-       struct rfkill *rfkill = to_rfkill(dev);
-       unsigned long state;
-       int error;
-
-       if (!capable(CAP_NET_ADMIN))
-               return -EPERM;
-
-       error = strict_strtoul(buf, 0, &state);
-       if (error)
-               return error;
-
-       /* RFKILL_STATE_HARD_BLOCKED is illegal here... */
-       if (state != RFKILL_STATE_UNBLOCKED &&
-           state != RFKILL_STATE_SOFT_BLOCKED)
-               return -EINVAL;
-
-       error = mutex_lock_killable(&rfkill->mutex);
-       if (error)
-               return error;
-
-       if (!rfkill_epo_lock_active)
-               error = rfkill_toggle_radio(rfkill, state, 0);
-       else
-               error = -EPERM;
-
-       mutex_unlock(&rfkill->mutex);
-
-       return error ? error : count;
-}
-
-static ssize_t rfkill_claim_show(struct device *dev,
-                                struct device_attribute *attr,
-                                char *buf)
-{
-       return sprintf(buf, "%d\n", 0);
-}
-
-static ssize_t rfkill_claim_store(struct device *dev,
-                                 struct device_attribute *attr,
-                                 const char *buf, size_t count)
-{
-       return -EOPNOTSUPP;
-}
-
-static struct device_attribute rfkill_dev_attrs[] = {
-       __ATTR(name, S_IRUGO, rfkill_name_show, NULL),
-       __ATTR(type, S_IRUGO, rfkill_type_show, NULL),
-       __ATTR(state, S_IRUGO|S_IWUSR, rfkill_state_show, rfkill_state_store),
-       __ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store),
-       __ATTR_NULL
-};
-
-static void rfkill_release(struct device *dev)
-{
-       struct rfkill *rfkill = to_rfkill(dev);
-
-       kfree(rfkill);
-       module_put(THIS_MODULE);
-}
-
-#ifdef CONFIG_PM
-static int rfkill_suspend(struct device *dev, pm_message_t state)
-{
-       struct rfkill *rfkill = to_rfkill(dev);
-
-       /* mark class device as suspended */
-       if (dev->power.power_state.event != state.event)
-               dev->power.power_state = state;
-
-       /* store state for the resume handler */
-       rfkill->state_for_resume = rfkill->state;
-
-       return 0;
-}
-
-static int rfkill_resume(struct device *dev)
-{
-       struct rfkill *rfkill = to_rfkill(dev);
-       enum rfkill_state newstate;
-
-       if (dev->power.power_state.event != PM_EVENT_ON) {
-               mutex_lock(&rfkill->mutex);
-
-               dev->power.power_state.event = PM_EVENT_ON;
-
-               /*
-                * rfkill->state could have been modified before we got
-                * called, and won't be updated by rfkill_toggle_radio()
-                * in force mode.  Sync it FIRST.
-                */
-               if (rfkill->get_state &&
-                   !rfkill->get_state(rfkill->data, &newstate))
-                       rfkill->state = newstate;
-
-               /*
-                * If we are under EPO, kick transmitter offline,
-                * otherwise restore to pre-suspend state.
-                *
-                * Issue a notification in any case
-                */
-               rfkill_toggle_radio(rfkill,
-                               rfkill_epo_lock_active ?
-                                       RFKILL_STATE_SOFT_BLOCKED :
-                                       rfkill->state_for_resume,
-                               1);
-
-               mutex_unlock(&rfkill->mutex);
-               rfkill_led_trigger(rfkill, rfkill->state);
-       }
-
-       return 0;
-}
-#else
-#define rfkill_suspend NULL
-#define rfkill_resume NULL
-#endif
-
-static int rfkill_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
-       struct rfkill *rfkill = to_rfkill(dev);
-       int error;
-
-       error = add_uevent_var(env, "RFKILL_NAME=%s", rfkill->name);
-       if (error)
-               return error;
-       error = add_uevent_var(env, "RFKILL_TYPE=%s",
-                               rfkill_get_type_str(rfkill->type));
-       if (error)
-               return error;
-       error = add_uevent_var(env, "RFKILL_STATE=%d", rfkill->state);
-       return error;
-}
-
-static struct class rfkill_class = {
-       .name           = "rfkill",
-       .dev_release    = rfkill_release,
-       .dev_attrs      = rfkill_dev_attrs,
-       .suspend        = rfkill_suspend,
-       .resume         = rfkill_resume,
-       .dev_uevent     = rfkill_dev_uevent,
-};
-
-static int rfkill_check_duplicity(const struct rfkill *rfkill)
-{
-       struct rfkill *p;
-       unsigned long seen[BITS_TO_LONGS(RFKILL_TYPE_MAX)];
-
-       memset(seen, 0, sizeof(seen));
-
-       list_for_each_entry(p, &rfkill_list, node) {
-               if (WARN((p == rfkill), KERN_WARNING
-                               "rfkill: illegal attempt to register "
-                               "an already registered rfkill struct\n"))
-                       return -EEXIST;
-               set_bit(p->type, seen);
-       }
-
-       /* 0: first switch of its kind */
-       return (test_bit(rfkill->type, seen)) ? 1 : 0;
-}
-
-static int rfkill_add_switch(struct rfkill *rfkill)
-{
-       int error;
-
-       mutex_lock(&rfkill_global_mutex);
-
-       error = rfkill_check_duplicity(rfkill);
-       if (error < 0)
-               goto unlock_out;
-
-       if (!error) {
-               /* lock default after first use */
-               set_bit(rfkill->type, rfkill_states_lockdflt);
-               rfkill_global_states[rfkill->type].current_state =
-                       rfkill_global_states[rfkill->type].default_state;
-       }
-
-       rfkill_toggle_radio(rfkill,
-                           rfkill_global_states[rfkill->type].current_state,
-                           0);
-
-       list_add_tail(&rfkill->node, &rfkill_list);
-
-       error = 0;
-unlock_out:
-       mutex_unlock(&rfkill_global_mutex);
-
-       return error;
-}
-
-static void rfkill_remove_switch(struct rfkill *rfkill)
-{
-       mutex_lock(&rfkill_global_mutex);
-       list_del_init(&rfkill->node);
-       mutex_unlock(&rfkill_global_mutex);
-
-       mutex_lock(&rfkill->mutex);
-       rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1);
-       mutex_unlock(&rfkill->mutex);
-}
-
-/**
- * rfkill_allocate - allocate memory for rfkill structure.
- * @parent: device that has rf switch on it
- * @type: type of the switch (RFKILL_TYPE_*)
- *
- * This function should be called by the network driver when it needs
- * rfkill structure.  Once the structure is allocated the driver should
- * finish its initialization by setting the name, private data, enable_radio
- * and disable_radio methods and then register it with rfkill_register().
- *
- * NOTE: If registration fails the structure shoudl be freed by calling
- * rfkill_free() otherwise rfkill_unregister() should be used.
- */
-struct rfkill * __must_check rfkill_allocate(struct device *parent,
-                                            enum rfkill_type type)
-{
-       struct rfkill *rfkill;
-       struct device *dev;
-
-       if (WARN((type >= RFKILL_TYPE_MAX),
-                       KERN_WARNING
-                       "rfkill: illegal type %d passed as parameter "
-                       "to rfkill_allocate\n", type))
-               return NULL;
-
-       rfkill = kzalloc(sizeof(struct rfkill), GFP_KERNEL);
-       if (!rfkill)
-               return NULL;
-
-       mutex_init(&rfkill->mutex);
-       INIT_LIST_HEAD(&rfkill->node);
-       rfkill->type = type;
-
-       dev = &rfkill->dev;
-       dev->class = &rfkill_class;
-       dev->parent = parent;
-       device_initialize(dev);
-
-       __module_get(THIS_MODULE);
-
-       return rfkill;
-}
-EXPORT_SYMBOL(rfkill_allocate);
-
-/**
- * rfkill_free - Mark rfkill structure for deletion
- * @rfkill: rfkill structure to be destroyed
- *
- * Decrements reference count of the rfkill structure so it is destroyed.
- * Note that rfkill_free() should _not_ be called after rfkill_unregister().
- */
-void rfkill_free(struct rfkill *rfkill)
-{
-       if (rfkill)
-               put_device(&rfkill->dev);
-}
-EXPORT_SYMBOL(rfkill_free);
-
-static void rfkill_led_trigger_register(struct rfkill *rfkill)
-{
-#ifdef CONFIG_RFKILL_LEDS
-       int error;
-
-       if (!rfkill->led_trigger.name)
-               rfkill->led_trigger.name = dev_name(&rfkill->dev);
-       if (!rfkill->led_trigger.activate)
-               rfkill->led_trigger.activate = rfkill_led_trigger_activate;
-       error = led_trigger_register(&rfkill->led_trigger);
-       if (error)
-               rfkill->led_trigger.name = NULL;
-#endif /* CONFIG_RFKILL_LEDS */
-}
-
-static void rfkill_led_trigger_unregister(struct rfkill *rfkill)
-{
-#ifdef CONFIG_RFKILL_LEDS
-       if (rfkill->led_trigger.name) {
-               led_trigger_unregister(&rfkill->led_trigger);
-               rfkill->led_trigger.name = NULL;
-       }
-#endif
-}
-
-/**
- * rfkill_register - Register a rfkill structure.
- * @rfkill: rfkill structure to be registered
- *
- * This function should be called by the network driver when the rfkill
- * structure needs to be registered. Immediately from registration the
- * switch driver should be able to service calls to toggle_radio.
- */
-int __must_check rfkill_register(struct rfkill *rfkill)
-{
-       static atomic_t rfkill_no = ATOMIC_INIT(0);
-       struct device *dev = &rfkill->dev;
-       int error;
-
-       if (WARN((!rfkill || !rfkill->toggle_radio ||
-                       rfkill->type >= RFKILL_TYPE_MAX ||
-                       rfkill->state >= RFKILL_STATE_MAX),
-                       KERN_WARNING
-                       "rfkill: attempt to register a "
-                       "badly initialized rfkill struct\n"))
-               return -EINVAL;
-
-       dev_set_name(dev, "rfkill%ld", (long)atomic_inc_return(&rfkill_no) - 1);
-
-       rfkill_led_trigger_register(rfkill);
-
-       error = rfkill_add_switch(rfkill);
-       if (error) {
-               rfkill_led_trigger_unregister(rfkill);
-               return error;
-       }
-
-       error = device_add(dev);
-       if (error) {
-               rfkill_remove_switch(rfkill);
-               rfkill_led_trigger_unregister(rfkill);
-               return error;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL(rfkill_register);
-
-/**
- * rfkill_unregister - Unregister a rfkill structure.
- * @rfkill: rfkill structure to be unregistered
- *
- * This function should be called by the network driver during device
- * teardown to destroy rfkill structure. Note that rfkill_free() should
- * _not_ be called after rfkill_unregister().
- */
-void rfkill_unregister(struct rfkill *rfkill)
-{
-       BUG_ON(!rfkill);
-       device_del(&rfkill->dev);
-       rfkill_remove_switch(rfkill);
-       rfkill_led_trigger_unregister(rfkill);
-       put_device(&rfkill->dev);
-}
-EXPORT_SYMBOL(rfkill_unregister);
-
-/**
- * rfkill_set_default - set initial value for a switch type
- * @type - the type of switch to set the default state of
- * @state - the new default state for that group of switches
- *
- * Sets the initial state rfkill should use for a given type.
- * The following initial states are allowed: RFKILL_STATE_SOFT_BLOCKED
- * and RFKILL_STATE_UNBLOCKED.
- *
- * This function is meant to be used by platform drivers for platforms
- * that can save switch state across power down/reboot.
- *
- * The default state for each switch type can be changed exactly once.
- * After a switch of that type is registered, the default state cannot
- * be changed anymore.  This guards against multiple drivers it the
- * same platform trying to set the initial switch default state, which
- * is not allowed.
- *
- * Returns -EPERM if the state has already been set once or is in use,
- * so drivers likely want to either ignore or at most printk(KERN_NOTICE)
- * if this function returns -EPERM.
- *
- * Returns 0 if the new default state was set, or an error if it
- * could not be set.
- */
-int rfkill_set_default(enum rfkill_type type, enum rfkill_state state)
-{
-       int error;
-
-       if (WARN((type >= RFKILL_TYPE_MAX ||
-                       (state != RFKILL_STATE_SOFT_BLOCKED &&
-                        state != RFKILL_STATE_UNBLOCKED)),
-                       KERN_WARNING
-                       "rfkill: illegal state %d or type %d passed as "
-                       "parameter to rfkill_set_default\n", state, type))
-               return -EINVAL;
-
-       mutex_lock(&rfkill_global_mutex);
-
-       if (!test_and_set_bit(type, rfkill_states_lockdflt)) {
-               rfkill_global_states[type].default_state = state;
-               rfkill_global_states[type].current_state = state;
-               error = 0;
-       } else
-               error = -EPERM;
-
-       mutex_unlock(&rfkill_global_mutex);
-       return error;
-}
-EXPORT_SYMBOL_GPL(rfkill_set_default);
-
-/*
- * Rfkill module initialization/deinitialization.
- */
-static int __init rfkill_init(void)
-{
-       int error;
-       int i;
-
-       /* RFKILL_STATE_HARD_BLOCKED is illegal here... */
-       if (rfkill_default_state != RFKILL_STATE_SOFT_BLOCKED &&
-           rfkill_default_state != RFKILL_STATE_UNBLOCKED)
-               return -EINVAL;
-
-       for (i = 0; i < RFKILL_TYPE_MAX; i++)
-               rfkill_global_states[i].default_state = rfkill_default_state;
-
-       error = class_register(&rfkill_class);
-       if (error) {
-               printk(KERN_ERR "rfkill: unable to register rfkill class\n");
-               return error;
-       }
-
-       return 0;
-}
-
-static void __exit rfkill_exit(void)
-{
-       class_unregister(&rfkill_class);
-}
-
-subsys_initcall(rfkill_init);
-module_exit(rfkill_exit);
similarity index 60%
rename from net/rfkill/rfkill-input.h
rename to net/rfkill/rfkill.h
index fe8df6b..d1117cb 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2007 Ivo van Doorn
+ * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
  */
 
 /*
 #ifndef __RFKILL_INPUT_H
 #define __RFKILL_INPUT_H
 
-void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state);
+/* core code */
+void rfkill_switch_all(const enum rfkill_type type, bool blocked);
 void rfkill_epo(void);
 void rfkill_restore_states(void);
 void rfkill_remove_epo_lock(void);
 bool rfkill_is_epo_lock_active(void);
-enum rfkill_state rfkill_get_global_state(const enum rfkill_type type);
+bool rfkill_get_global_sw_state(const enum rfkill_type type);
+
+/* input handler */
+int rfkill_handler_init(void);
+void rfkill_handler_exit(void);
 
 #endif /* __RFKILL_INPUT_H */
index 0759f32..09cdcdf 100644 (file)
@@ -135,6 +135,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
        unsigned long cl;
        unsigned long fh;
        int err;
+       int tp_created = 0;
 
        if (net != &init_net)
                return -EINVAL;
@@ -266,10 +267,7 @@ replay:
                        goto errout;
                }
 
-               spin_lock_bh(root_lock);
-               tp->next = *back;
-               *back = tp;
-               spin_unlock_bh(root_lock);
+               tp_created = 1;
 
        } else if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], tp->ops->kind))
                goto errout;
@@ -296,8 +294,11 @@ replay:
                switch (n->nlmsg_type) {
                case RTM_NEWTFILTER:
                        err = -EEXIST;
-                       if (n->nlmsg_flags & NLM_F_EXCL)
+                       if (n->nlmsg_flags & NLM_F_EXCL) {
+                               if (tp_created)
+                                       tcf_destroy(tp);
                                goto errout;
+                       }
                        break;
                case RTM_DELTFILTER:
                        err = tp->ops->delete(tp, fh);
@@ -314,8 +315,18 @@ replay:
        }
 
        err = tp->ops->change(tp, cl, t->tcm_handle, tca, &fh);
-       if (err == 0)
+       if (err == 0) {
+               if (tp_created) {
+                       spin_lock_bh(root_lock);
+                       tp->next = *back;
+                       *back = tp;
+                       spin_unlock_bh(root_lock);
+               }
                tfilter_notify(skb, n, tp, fh, RTM_NEWTFILTER);
+       } else {
+               if (tp_created)
+                       tcf_destroy(tp);
+       }
 
 errout:
        if (cl)
index 1ab4542..0f815cc 100644 (file)
@@ -98,8 +98,7 @@ static int cls_cgroup_classify(struct sk_buff *skb, struct tcf_proto *tp,
                               struct tcf_result *res)
 {
        struct cls_cgroup_head *head = tp->root;
-       struct cgroup_cls_state *cs;
-       int ret = 0;
+       u32 classid;
 
        /*
         * Due to the nature of the classifier it is required to ignore all
@@ -115,17 +114,18 @@ static int cls_cgroup_classify(struct sk_buff *skb, struct tcf_proto *tp,
                return -1;
 
        rcu_read_lock();
-       cs = task_cls_state(current);
-       if (cs->classid && tcf_em_tree_match(skb, &head->ematches, NULL)) {
-               res->classid = cs->classid;
-               res->class = 0;
-               ret = tcf_exts_exec(skb, &head->exts, res);
-       } else
-               ret = -1;
-
+       classid = task_cls_state(current)->classid;
        rcu_read_unlock();
 
-       return ret;
+       if (!classid)
+               return -1;
+
+       if (!tcf_em_tree_match(skb, &head->ematches, NULL))
+               return -1;
+
+       res->classid = classid;
+       res->class = 0;
+       return tcf_exts_exec(skb, &head->exts, res);
 }
 
 static unsigned long cls_cgroup_get(struct tcf_proto *tp, u32 handle)
index 0ef4e30..9402a7f 100644 (file)
@@ -84,7 +84,7 @@ static u32 flow_get_dst(const struct sk_buff *skb)
        case htons(ETH_P_IPV6):
                return ntohl(ipv6_hdr(skb)->daddr.s6_addr32[3]);
        default:
-               return addr_fold(skb->dst) ^ (__force u16)skb->protocol;
+               return addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol;
        }
 }
 
@@ -163,7 +163,7 @@ static u32 flow_get_proto_dst(const struct sk_buff *skb)
                break;
        }
        default:
-               res = addr_fold(skb->dst) ^ (__force u16)skb->protocol;
+               res = addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol;
        }
 
        return res;
@@ -251,8 +251,8 @@ fallback:
 static u32 flow_get_rtclassid(const struct sk_buff *skb)
 {
 #ifdef CONFIG_NET_CLS_ROUTE
-       if (skb->dst)
-               return skb->dst->tclassid;
+       if (skb_dst(skb))
+               return skb_dst(skb)->tclassid;
 #endif
        return 0;
 }
index bdf1f41..dd872d5 100644 (file)
@@ -137,7 +137,7 @@ static int route4_classify(struct sk_buff *skb, struct tcf_proto *tp,
        u32 id, h;
        int iif, dont_cache = 0;
 
-       if ((dst = skb->dst) == NULL)
+       if ((dst = skb_dst(skb)) == NULL)
                goto failure;
 
        id = dst->tclassid;
index fad596b..266151a 100644 (file)
@@ -246,11 +246,11 @@ META_COLLECTOR(int_tcindex)
 
 META_COLLECTOR(int_rtclassid)
 {
-       if (unlikely(skb->dst == NULL))
+       if (unlikely(skb_dst(skb) == NULL))
                *err = -1;
        else
 #ifdef CONFIG_NET_CLS_ROUTE
-               dst->value = skb->dst->tclassid;
+               dst->value = skb_dst(skb)->tclassid;
 #else
                dst->value = 0;
 #endif
@@ -258,10 +258,10 @@ META_COLLECTOR(int_rtclassid)
 
 META_COLLECTOR(int_rtiif)
 {
-       if (unlikely(skb->rtable == NULL))
+       if (unlikely(skb_rtable(skb) == NULL))
                *err = -1;
        else
-               dst->value = skb->rtable->fl.iif;
+               dst->value = skb_rtable(skb)->fl.iif;
 }
 
 /**************************************************************************
index 5022f9c..362c281 100644 (file)
@@ -372,7 +372,7 @@ cftree_update(struct hfsc_class *cl)
  *     ism: (psched_us/byte) << ISM_SHIFT
  *     dx: psched_us
  *
- * The clock source resolution with ktime is 1.024us.
+ * The clock source resolution with ktime and PSCHED_SHIFT 10 is 1.024us.
  *
  * sm and ism are scaled in order to keep effective digits.
  * SM_SHIFT and ISM_SHIFT are selected to keep at least 4 effective
@@ -383,9 +383,11 @@ cftree_update(struct hfsc_class *cl)
  *  bytes/1.024us 12.8e-3    128e-3     1280e-3    12800e-3   128000e-3
  *
  *  1.024us/byte  78.125     7.8125     0.78125    0.078125   0.0078125
+ *
+ * So, for PSCHED_SHIFT 10 we need: SM_SHIFT 20, ISM_SHIFT 18.
  */
-#define        SM_SHIFT        20
-#define        ISM_SHIFT       18
+#define        SM_SHIFT        (30 - PSCHED_SHIFT)
+#define        ISM_SHIFT       (8 + PSCHED_SHIFT)
 
 #define        SM_MASK         ((1ULL << SM_SHIFT) - 1)
 #define        ISM_MASK        ((1ULL << ISM_SHIFT) - 1)
index 33133d2..8706920 100644 (file)
@@ -149,7 +149,7 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb)
                break;
        }
        default:
-               h = (unsigned long)skb->dst ^ skb->protocol;
+               h = (unsigned long)skb_dst(skb) ^ skb->protocol;
                h2 = (unsigned long)skb->sk;
        }
 
index a886496..cb1cb1e 100644 (file)
@@ -222,7 +222,7 @@ __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct net_device *
 {
        struct netdev_queue *dev_queue = netdev_get_tx_queue(dev, 0);
        struct teql_sched_data *q = qdisc_priv(dev_queue->qdisc);
-       struct neighbour *mn = skb->dst->neighbour;
+       struct neighbour *mn = skb_dst(skb)->neighbour;
        struct neighbour *n = q->ncache;
 
        if (mn->tbl == NULL)
@@ -262,8 +262,8 @@ static inline int teql_resolve(struct sk_buff *skb,
                return -ENODEV;
 
        if (dev->header_ops == NULL ||
-           skb->dst == NULL ||
-           skb->dst->neighbour == NULL)
+           skb_dst(skb) == NULL ||
+           skb_dst(skb)->neighbour == NULL)
                return 0;
        return __teql_resolve(skb, skb_res, dev);
 }
index f4b2304..525864b 100644 (file)
@@ -293,7 +293,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
         * told otherwise.
         */
        asoc->peer.ipv4_address = 1;
-       asoc->peer.ipv6_address = 1;
+       if (asoc->base.sk->sk_family == PF_INET6)
+               asoc->peer.ipv6_address = 1;
        INIT_LIST_HEAD(&asoc->asocs);
 
        asoc->autoclose = sp->autoclose;
@@ -566,6 +567,21 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
        if (asoc->init_last_sent_to == peer)
                asoc->init_last_sent_to = NULL;
 
+       /* If we remove the transport an SHUTDOWN was last sent to, set it
+        * to NULL. Combined with the update of the retran path above, this
+        * will cause the next SHUTDOWN to be sent to the next available
+        * transport, maintaining the cycle.
+        */
+       if (asoc->shutdown_last_sent_to == peer)
+               asoc->shutdown_last_sent_to = NULL;
+
+       /* If we remove the transport an ASCONF was last sent to, set it to
+        * NULL.
+        */
+       if (asoc->addip_last_asconf &&
+           asoc->addip_last_asconf->transport == peer)
+               asoc->addip_last_asconf->transport = NULL;
+
        asoc->peer.transport_count--;
 
        sctp_transport_free(peer);
@@ -1268,49 +1284,21 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc)
                                 ntohs(t->ipaddr.v4.sin_port));
 }
 
-/* Choose the transport for sending a INIT packet.  */
-struct sctp_transport *sctp_assoc_choose_init_transport(
-       struct sctp_association *asoc)
-{
-       struct sctp_transport *t;
-
-       /* Use the retran path. If the last INIT was sent over the
-        * retran path, update the retran path and use it.
-        */
-       if (!asoc->init_last_sent_to) {
-               t = asoc->peer.active_path;
-       } else {
-               if (asoc->init_last_sent_to == asoc->peer.retran_path)
-                       sctp_assoc_update_retran_path(asoc);
-               t = asoc->peer.retran_path;
-       }
-
-       SCTP_DEBUG_PRINTK_IPADDR("sctp_assoc_update_retran_path:association"
-                                " %p addr: ",
-                                " port: %d\n",
-                                asoc,
-                                (&t->ipaddr),
-                                ntohs(t->ipaddr.v4.sin_port));
-
-       return t;
-}
-
-/* Choose the transport for sending a SHUTDOWN packet.  */
-struct sctp_transport *sctp_assoc_choose_shutdown_transport(
-       struct sctp_association *asoc)
+/* Choose the transport for sending retransmit packet.  */
+struct sctp_transport *sctp_assoc_choose_alter_transport(
+       struct sctp_association *asoc, struct sctp_transport *last_sent_to)
 {
-       /* If this is the first time SHUTDOWN is sent, use the active path,
-        * else use the retran path. If the last SHUTDOWN was sent over the
+       /* If this is the first time packet is sent, use the active path,
+        * else use the retran path. If the last packet was sent over the
         * retran path, update the retran path and use it.
         */
-       if (!asoc->shutdown_last_sent_to)
+       if (!last_sent_to)
                return asoc->peer.active_path;
        else {
-               if (asoc->shutdown_last_sent_to == asoc->peer.retran_path)
+               if (last_sent_to == asoc->peer.retran_path)
                        sctp_assoc_update_retran_path(asoc);
                return asoc->peer.retran_path;
        }
-
 }
 
 /* Update the association's pmtu and frag_point by going through all the
@@ -1482,6 +1470,10 @@ int sctp_assoc_set_id(struct sctp_association *asoc, gfp_t gfp)
 {
        int assoc_id;
        int error = 0;
+
+       /* If the id is already assigned, keep it. */
+       if (asoc->assoc_id)
+               return error;
 retry:
        if (unlikely(!idr_pre_get(&sctp_assocs_id, gfp)))
                return -ENOMEM;
index d2e9880..c0c973e 100644 (file)
@@ -81,13 +81,13 @@ static void sctp_add_backlog(struct sock *sk, struct sk_buff *skb);
 /* Calculate the SCTP checksum of an SCTP packet.  */
 static inline int sctp_rcv_checksum(struct sk_buff *skb)
 {
-       struct sk_buff *list = skb_shinfo(skb)->frag_list;
        struct sctphdr *sh = sctp_hdr(skb);
        __le32 cmp = sh->checksum;
+       struct sk_buff *list;
        __le32 val;
        __u32 tmp = sctp_start_cksum((__u8 *)sh, skb_headlen(skb));
 
-       for (; list; list = list->next)
+       skb_walk_frags(skb, list)
                tmp = sctp_update_cksum((__u8 *)list->data, skb_headlen(list),
                                        tmp);
 
index f0c91df..b764114 100644 (file)
@@ -405,10 +405,10 @@ int sctp_packet_transmit(struct sctp_packet *packet)
                        sctp_assoc_sync_pmtu(asoc);
                }
        }
-       nskb->dst = dst_clone(tp->dst);
-       if (!nskb->dst)
+       dst = dst_clone(tp->dst);
+       skb_dst_set(nskb, dst);
+       if (dst)
                goto no_route;
-       dst = nskb->dst;
 
        /* Build the SCTP header.  */
        sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr));
index 8eb3e61..79cbd47 100644 (file)
@@ -393,7 +393,7 @@ static int sctp_v4_addr_valid(union sctp_addr *addr,
                return 0;
 
        /* Is this a broadcast address? */
-       if (skb && skb->rtable->rt_flags & RTCF_BROADCAST)
+       if (skb && skb_rtable(skb)->rt_flags & RTCF_BROADCAST)
                return 0;
 
        return 1;
@@ -572,7 +572,7 @@ static void sctp_v4_get_saddr(struct sctp_sock *sk,
 /* What interface did this skb arrive on? */
 static int sctp_v4_skb_iif(const struct sk_buff *skb)
 {
-       return skb->rtable->rt_iif;
+       return skb_rtable(skb)->rt_iif;
 }
 
 /* Was this packet marked by Explicit Congestion Notification? */
@@ -848,8 +848,8 @@ static inline int sctp_v4_xmit(struct sk_buff *skb,
 
        SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI4, dst:%pI4\n",
                          __func__, skb, skb->len,
-                         &skb->rtable->rt_src,
-                         &skb->rtable->rt_dst);
+                         &skb_rtable(skb)->rt_src,
+                         &skb_rtable(skb)->rt_dst);
 
        inet->pmtudisc = transport->param_flags & SPP_PMTUD_ENABLE ?
                         IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
@@ -1370,6 +1370,8 @@ SCTP_STATIC __exit void sctp_exit(void)
        sctp_proc_exit();
        cleanup_sctp_mibs();
 
+       rcu_barrier(); /* Wait for completion of call_rcu()'s */
+
        kmem_cache_destroy(sctp_chunk_cachep);
        kmem_cache_destroy(sctp_bucket_cachep);
 }
index 6851ee9..61cc607 100644 (file)
@@ -2864,19 +2864,19 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
        switch (addr_param->v4.param_hdr.type) {
        case SCTP_PARAM_IPV6_ADDRESS:
                if (!asoc->peer.ipv6_address)
-                       return SCTP_ERROR_INV_PARAM;
+                       return SCTP_ERROR_DNS_FAILED;
                break;
        case SCTP_PARAM_IPV4_ADDRESS:
                if (!asoc->peer.ipv4_address)
-                       return SCTP_ERROR_INV_PARAM;
+                       return SCTP_ERROR_DNS_FAILED;
                break;
        default:
-               return SCTP_ERROR_INV_PARAM;
+               return SCTP_ERROR_DNS_FAILED;
        }
 
        af = sctp_get_af_specific(param_type2af(addr_param->v4.param_hdr.type));
        if (unlikely(!af))
-               return SCTP_ERROR_INV_PARAM;
+               return SCTP_ERROR_DNS_FAILED;
 
        af->from_addr_param(&addr, addr_param, htons(asoc->peer.port), 0);
 
@@ -2886,7 +2886,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
         *  make sure we check for that)
         */
        if (!af->is_any(&addr) && !af->addr_valid(&addr, NULL, asconf->skb))
-               return SCTP_ERROR_INV_PARAM;
+               return SCTP_ERROR_DNS_FAILED;
 
        switch (asconf_param->param_hdr.type) {
        case SCTP_PARAM_ADD_IP:
@@ -2954,12 +2954,12 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
 
                peer = sctp_assoc_lookup_paddr(asoc, &addr);
                if (!peer)
-                       return SCTP_ERROR_INV_PARAM;
+                       return SCTP_ERROR_DNS_FAILED;
 
                sctp_assoc_set_primary(asoc, peer);
                break;
        default:
-               return SCTP_ERROR_INV_PARAM;
+               return SCTP_ERROR_UNKNOWN_PARAM;
                break;
        }
 
@@ -3273,7 +3273,7 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
                        retval = 1;
                        break;
 
-               case SCTP_ERROR_INV_PARAM:
+               case SCTP_ERROR_UNKNOWN_PARAM:
                        /* Disable sending this type of asconf parameter in
                         * future.
                         */
index e2020eb..86426aa 100644 (file)
@@ -686,7 +686,8 @@ static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds,
 {
        struct sctp_transport *t;
 
-       t = sctp_assoc_choose_shutdown_transport(asoc);
+       t = sctp_assoc_choose_alter_transport(asoc,
+                                             asoc->shutdown_last_sent_to);
        asoc->shutdown_last_sent_to = t;
        asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = t->rto;
        chunk->transport = t;
@@ -777,7 +778,7 @@ static void sctp_cmd_setup_t4(sctp_cmd_seq_t *cmds,
 {
        struct sctp_transport *t;
 
-       t = asoc->peer.active_path;
+       t = sctp_assoc_choose_alter_transport(asoc, chunk->transport);
        asoc->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = t->rto;
        chunk->transport = t;
 }
@@ -1379,7 +1380,8 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
 
                case SCTP_CMD_INIT_CHOOSE_TRANSPORT:
                        chunk = cmd->obj.ptr;
-                       t = sctp_assoc_choose_init_transport(asoc);
+                       t = sctp_assoc_choose_alter_transport(asoc,
+                                               asoc->init_last_sent_to);
                        asoc->init_last_sent_to = t;
                        chunk->transport = t;
                        t->init_sent_count++;
index 55a61aa..7288192 100644 (file)
@@ -5432,9 +5432,13 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep,
        if (!reply)
                goto nomem;
 
-       /* Do some failure management (Section 8.2). */
-       sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE,
-                       SCTP_TRANSPORT(asoc->shutdown_last_sent_to));
+       /* Do some failure management (Section 8.2).
+        * If we remove the transport an SHUTDOWN was last sent to, don't
+        * do failure management.
+        */
+       if (asoc->shutdown_last_sent_to)
+               sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE,
+                               SCTP_TRANSPORT(asoc->shutdown_last_sent_to));
 
        /* Set the transport for the SHUTDOWN/ACK chunk and the timeout for
         * the T2-shutdown timer.
@@ -5471,7 +5475,9 @@ sctp_disposition_t sctp_sf_t4_timer_expire(
         * detection on the appropriate destination address as defined in
         * RFC2960 [5] section 8.1 and 8.2.
         */
-       sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE, SCTP_TRANSPORT(transport));
+       if (transport)
+               sctp_add_cmd_sf(commands, SCTP_CMD_STRIKE,
+                               SCTP_TRANSPORT(transport));
 
        /* Reconfig T4 timer and transport. */
        sctp_add_cmd_sf(commands, SCTP_CMD_SETUP_T4, SCTP_CHUNK(chunk));
index 5c8186d..6d9b3aa 100644 (file)
@@ -698,7 +698,7 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
        TYPE_SCTP_FUNC(sctp_sf_do_prm_asconf), \
        /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
        TYPE_SCTP_FUNC(sctp_sf_error_shutdown), \
-} /* TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT */
+} /* TYPE_SCTP_PRIMITIVE_ASCONF */
 
 /* The primary index for this table is the primitive type.
  * The secondary index for this table is the state.
index 5fb3a8c..0f01e5d 100644 (file)
@@ -1100,6 +1100,15 @@ static int __sctp_connect(struct sock* sk,
                goto out_free;
        }
 
+       /* In case the user of sctp_connectx() wants an association
+        * id back, assign one now.
+        */
+       if (assoc_id) {
+               err = sctp_assoc_set_id(asoc, GFP_KERNEL);
+               if (err < 0)
+                       goto out_free;
+       }
+
        err = sctp_primitive_ASSOCIATE(asoc, NULL);
        if (err < 0) {
                goto out_free;
@@ -1120,7 +1129,7 @@ static int __sctp_connect(struct sock* sk,
        timeo = sock_sndtimeo(sk, f_flags & O_NONBLOCK);
 
        err = sctp_wait_for_connect(asoc, &timeo);
-       if (!err && assoc_id)
+       if ((err == 0 || err == -EINPROGRESS) && assoc_id)
                *assoc_id = asoc->assoc_id;
 
        /* Don't free association on exit. */
@@ -1264,6 +1273,34 @@ SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk,
                return assoc_id;
 }
 
+/*
+ * New (hopefully final) interface for the API.  The option buffer is used
+ * both for the returned association id and the addresses.
+ */
+SCTP_STATIC int sctp_getsockopt_connectx3(struct sock* sk, int len,
+                                       char __user *optval,
+                                       int __user *optlen)
+{
+       sctp_assoc_t assoc_id = 0;
+       int err = 0;
+
+       if (len < sizeof(assoc_id))
+               return -EINVAL;
+
+       err = __sctp_setsockopt_connectx(sk,
+                       (struct sockaddr __user *)(optval + sizeof(assoc_id)),
+                       len - sizeof(assoc_id), &assoc_id);
+
+       if (err == 0 || err == -EINPROGRESS) {
+               if (copy_to_user(optval, &assoc_id, sizeof(assoc_id)))
+                       return -EFAULT;
+               if (put_user(sizeof(assoc_id), optlen))
+                       return -EFAULT;
+       }
+
+       return err;
+}
+
 /* API 3.1.4 close() - UDP Style Syntax
  * Applications use close() to perform graceful shutdown (as described in
  * Section 10.1 of [SCTP]) on ALL the associations currently represented
@@ -1844,7 +1881,7 @@ static int sctp_skb_pull(struct sk_buff *skb, int len)
        len -= skb_len;
        __skb_pull(skb, skb_len);
 
-       for (list = skb_shinfo(skb)->frag_list; list; list = list->next) {
+       skb_walk_frags(skb, list) {
                rlen = sctp_skb_pull(list, len);
                skb->len -= (len-rlen);
                skb->data_len -= (len-rlen);
@@ -5578,6 +5615,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
                retval = sctp_getsockopt_local_addrs(sk, len, optval,
                                                     optlen);
                break;
+       case SCTP_SOCKOPT_CONNECTX3:
+               retval = sctp_getsockopt_connectx3(sk, len, optval, optlen);
+               break;
        case SCTP_DEFAULT_SEND_PARAM:
                retval = sctp_getsockopt_default_send_param(sk, len,
                                                            optval, optlen);
@@ -6620,7 +6660,7 @@ static void sctp_sock_rfree_frag(struct sk_buff *skb)
                goto done;
 
        /* Don't forget the fragments. */
-       for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next)
+       skb_walk_frags(skb, frag)
                sctp_sock_rfree_frag(frag);
 
 done:
@@ -6635,7 +6675,7 @@ static void sctp_skb_set_owner_r_frag(struct sk_buff *skb, struct sock *sk)
                goto done;
 
        /* Don't forget the fragments. */
-       for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next)
+       skb_walk_frags(skb, frag)
                sctp_skb_set_owner_r_frag(frag, sk);
 
 done:
index f58e994..63eabbc 100644 (file)
@@ -49,8 +49,8 @@ static int zero = 0;
 static int one = 1;
 static int timer_max = 86400000; /* ms in one day */
 static int int_max = INT_MAX;
-static long sack_timer_min = 1;
-static long sack_timer_max = 500;
+static int sack_timer_min = 1;
+static int sack_timer_max = 500;
 
 extern int sysctl_sctp_mem[3];
 extern int sysctl_sctp_rmem[3];
@@ -223,7 +223,7 @@ static ctl_table sctp_table[] = {
                .ctl_name       = NET_SCTP_SACK_TIMEOUT,
                .procname       = "sack_timeout",
                .data           = &sctp_sack_timeout,
-               .maxlen         = sizeof(long),
+               .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
                .strategy       = sysctl_intvec,
index 5f186ca..8b3560f 100644 (file)
@@ -976,9 +976,8 @@ static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event,
         * In general, the skb passed from IP can have only 1 level of
         * fragments. But we allow multiple levels of fragments.
         */
-       for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) {
+       skb_walk_frags(skb, frag)
                sctp_ulpevent_receive_data(sctp_skb2event(frag), asoc);
-       }
 }
 
 /* Do accounting for bytes just read by user and release the references to
@@ -1003,7 +1002,7 @@ static void sctp_ulpevent_release_data(struct sctp_ulpevent *event)
                goto done;
 
        /* Don't forget the fragments. */
-       for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) {
+       skb_walk_frags(skb, frag) {
                /* NOTE:  skb_shinfos are recursive. Although IP returns
                 * skb's with only 1 level of fragments, SCTP reassembly can
                 * increase the levels.
@@ -1026,7 +1025,7 @@ static void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event)
                goto done;
 
        /* Don't forget the fragments. */
-       for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) {
+       skb_walk_frags(skb, frag) {
                /* NOTE:  skb_shinfos are recursive. Although IP returns
                 * skb's with only 1 level of fragments, SCTP reassembly can
                 * increase the levels.
index e630b38..66d458f 100644 (file)
@@ -1548,6 +1548,7 @@ static void __exit exit_rpcsec_gss(void)
 {
        gss_svc_shutdown();
        rpcauth_unregister(&authgss_ops);
+       rcu_barrier(); /* Wait for completion of call_rcu()'s */
 }
 
 MODULE_LICENSE("GPL");
index e185961..6c2d615 100644 (file)
@@ -918,7 +918,7 @@ static void xs_udp_data_ready(struct sock *sk, int len)
        UDPX_INC_STATS_BH(sk, UDP_MIB_INDATAGRAMS);
 
        /* Something worked... */
-       dst_confirm(skb->dst);
+       dst_confirm(skb_dst(skb));
 
        xprt_adjust_cwnd(task, copied);
        xprt_update_rtt(task);
index 1b46747..e4d97ab 100644 (file)
@@ -1,23 +1,10 @@
 #
 # WiMAX LAN device configuration
 #
-# Note the ugly 'depends on' on WIMAX: that disallows RFKILL to be a
-# module if WIMAX is to be linked in. The WiMAX code is done in such a
-# way that it doesn't require and explicit dependency on RFKILL in
-# case an embedded system wants to rip it out.
-#
-# As well, enablement of the RFKILL code means we need the INPUT layer
-# support to inject events coming from hw rfkill switches. That
-# dependency could be killed if input.h provided appropriate means to
-# work when input is disabled.
-
-comment "WiMAX Wireless Broadband support requires CONFIG_INPUT enabled"
-       depends on INPUT = n && RFKILL != n
 
 menuconfig WIMAX
        tristate "WiMAX Wireless Broadband support"
-       depends on (y && RFKILL != m) || m
-       depends on (INPUT && RFKILL != n) || RFKILL = n
+       depends on RFKILL || !RFKILL
        help
 
          Select to configure support for devices that provide
index 5b80b94..8f1510d 100644 (file)
@@ -6,6 +6,7 @@ wimax-y :=              \
        op-msg.o        \
        op-reset.o      \
        op-rfkill.o     \
+       op-state-get.o  \
        stack.o
 
 wimax-$(CONFIG_DEBUG_FS) += debugfs.o
index 1c29123..0975adb 100644 (file)
@@ -36,6 +36,7 @@ enum d_module {
        D_SUBMODULE_DECLARE(op_msg),
        D_SUBMODULE_DECLARE(op_reset),
        D_SUBMODULE_DECLARE(op_rfkill),
+       D_SUBMODULE_DECLARE(op_state_get),
        D_SUBMODULE_DECLARE(stack),
 };
 
index 94d216a..6c9bedb 100644 (file)
@@ -61,6 +61,7 @@ int wimax_debugfs_add(struct wimax_dev *wimax_dev)
        __debugfs_register("wimax_dl_", op_msg, dentry);
        __debugfs_register("wimax_dl_", op_reset, dentry);
        __debugfs_register("wimax_dl_", op_rfkill, dentry);
+       __debugfs_register("wimax_dl_", op_state_get, dentry);
        __debugfs_register("wimax_dl_", stack, dentry);
        result = 0;
 out:
index 9ad4d89..d631a17 100644 (file)
  * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as
  * wimax_msg_send() depends on skb->data being placed at the
  * beginning of the user message.
+ *
+ * Unlike other WiMAX stack calls, this call can be used way early,
+ * even before wimax_dev_add() is called, as long as the
+ * wimax_dev->net_dev pointer is set to point to a proper
+ * net_dev. This is so that drivers can use it early in case they need
+ * to send stuff around or communicate with user space.
  */
 struct sk_buff *wimax_msg_alloc(struct wimax_dev *wimax_dev,
                                const char *pipe_name,
@@ -115,7 +121,7 @@ struct sk_buff *wimax_msg_alloc(struct wimax_dev *wimax_dev,
                                gfp_t gfp_flags)
 {
        int result;
-       struct device *dev = wimax_dev->net_dev->dev.parent;
+       struct device *dev = wimax_dev_to_dev(wimax_dev);
        size_t msg_size;
        void *genl_msg;
        struct sk_buff *skb;
@@ -161,7 +167,6 @@ error_genlmsg_put:
 error_new:
        nlmsg_free(skb);
        return ERR_PTR(result);
-
 }
 EXPORT_SYMBOL_GPL(wimax_msg_alloc);
 
@@ -256,10 +261,16 @@ EXPORT_SYMBOL_GPL(wimax_msg_len);
  * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as
  * wimax_msg_send() depends on skb->data being placed at the
  * beginning of the user message.
+ *
+ * Unlike other WiMAX stack calls, this call can be used way early,
+ * even before wimax_dev_add() is called, as long as the
+ * wimax_dev->net_dev pointer is set to point to a proper
+ * net_dev. This is so that drivers can use it early in case they need
+ * to send stuff around or communicate with user space.
  */
 int wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb)
 {
-       struct device *dev = wimax_dev->net_dev->dev.parent;
+       struct device *dev = wimax_dev_to_dev(wimax_dev);
        void *msg = skb->data;
        size_t size = skb->len;
        might_sleep();
index a3616e2..bb102e4 100644 (file)
@@ -29,8 +29,8 @@
  * A non-polled generic rfkill device is embedded into the WiMAX
  * subsystem's representation of a device.
  *
- * FIXME: Need polled support? use a timer or add the implementation
- *     to the stack.
+ * FIXME: Need polled support? Let drivers provide a poll routine
+ *       and hand it to rfkill ops then?
  *
  * All device drivers have to do is after wimax_dev_init(), call
  * wimax_report_rfkill_hw() and wimax_report_rfkill_sw() to update
@@ -43,7 +43,7 @@
  *   wimax_rfkill()             Kernel calling wimax_rfkill()
  *     __wimax_rf_toggle_radio()
  *
- * wimax_rfkill_toggle_radio()  RF-Kill subsytem calling
+ * wimax_rfkill_set_radio_block()  RF-Kill subsytem calling
  *   __wimax_rf_toggle_radio()
  *
  * __wimax_rf_toggle_radio()
 #include <linux/wimax.h>
 #include <linux/security.h>
 #include <linux/rfkill.h>
-#include <linux/input.h>
 #include "wimax-internal.h"
 
 #define D_SUBMODULE op_rfkill
 #include "debug-levels.h"
 
-#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
-
-
 /**
  * wimax_report_rfkill_hw - Reports changes in the hardware RF switch
  *
@@ -99,7 +95,6 @@ void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev,
        int result;
        struct device *dev = wimax_dev_to_dev(wimax_dev);
        enum wimax_st wimax_state;
-       enum rfkill_state rfkill_state;
 
        d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state);
        BUG_ON(state == WIMAX_RF_QUERY);
@@ -112,16 +107,15 @@ void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev,
 
        if (state != wimax_dev->rf_hw) {
                wimax_dev->rf_hw = state;
-               rfkill_state = state == WIMAX_RF_ON ?
-                       RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
                if (wimax_dev->rf_hw == WIMAX_RF_ON
                    && wimax_dev->rf_sw == WIMAX_RF_ON)
                        wimax_state = WIMAX_ST_READY;
                else
                        wimax_state = WIMAX_ST_RADIO_OFF;
+
+               rfkill_set_hw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF);
+
                __wimax_state_change(wimax_dev, wimax_state);
-               input_report_key(wimax_dev->rfkill_input, KEY_WIMAX,
-                                rfkill_state);
        }
 error_not_ready:
        mutex_unlock(&wimax_dev->mutex);
@@ -174,6 +168,7 @@ void wimax_report_rfkill_sw(struct wimax_dev *wimax_dev,
                else
                        wimax_state = WIMAX_ST_RADIO_OFF;
                __wimax_state_change(wimax_dev, wimax_state);
+               rfkill_set_sw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF);
        }
 error_not_ready:
        mutex_unlock(&wimax_dev->mutex);
@@ -249,36 +244,31 @@ out_no_change:
  *
  * NOTE: This call will block until the operation is completed.
  */
-static
-int wimax_rfkill_toggle_radio(void *data, enum rfkill_state state)
+static int wimax_rfkill_set_radio_block(void *data, bool blocked)
 {
        int result;
        struct wimax_dev *wimax_dev = data;
        struct device *dev = wimax_dev_to_dev(wimax_dev);
        enum wimax_rf_state rf_state;
 
-       d_fnstart(3, dev, "(wimax_dev %p state %u)\n", wimax_dev, state);
-       switch (state) {
-       case RFKILL_STATE_SOFT_BLOCKED:
+       d_fnstart(3, dev, "(wimax_dev %p blocked %u)\n", wimax_dev, blocked);
+       rf_state = WIMAX_RF_ON;
+       if (blocked)
                rf_state = WIMAX_RF_OFF;
-               break;
-       case RFKILL_STATE_UNBLOCKED:
-               rf_state = WIMAX_RF_ON;
-               break;
-       default:
-               BUG();
-       }
        mutex_lock(&wimax_dev->mutex);
        if (wimax_dev->state <= __WIMAX_ST_QUIESCING)
-               result = 0;     /* just pretend it didn't happen */
+               result = 0;
        else
                result = __wimax_rf_toggle_radio(wimax_dev, rf_state);
        mutex_unlock(&wimax_dev->mutex);
-       d_fnend(3, dev, "(wimax_dev %p state %u) = %d\n",
-               wimax_dev, state, result);
+       d_fnend(3, dev, "(wimax_dev %p blocked %u) = %d\n",
+               wimax_dev, blocked, result);
        return result;
 }
 
+static const struct rfkill_ops wimax_rfkill_ops = {
+       .set_block = wimax_rfkill_set_radio_block,
+};
 
 /**
  * wimax_rfkill - Set the software RF switch state for a WiMAX device
@@ -322,6 +312,7 @@ int wimax_rfkill(struct wimax_dev *wimax_dev, enum wimax_rf_state state)
                result = __wimax_rf_toggle_radio(wimax_dev, state);
                if (result < 0)
                        goto error;
+               rfkill_set_sw_state(wimax_dev->rfkill, state == WIMAX_RF_OFF);
                break;
        case WIMAX_RF_QUERY:
                break;
@@ -349,40 +340,20 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev)
 {
        int result;
        struct rfkill *rfkill;
-       struct input_dev *input_dev;
        struct device *dev = wimax_dev_to_dev(wimax_dev);
 
        d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev);
        /* Initialize RF Kill */
        result = -ENOMEM;
-       rfkill = rfkill_allocate(dev, RFKILL_TYPE_WIMAX);
+       rfkill = rfkill_alloc(wimax_dev->name, dev, RFKILL_TYPE_WIMAX,
+                             &wimax_rfkill_ops, wimax_dev);
        if (rfkill == NULL)
                goto error_rfkill_allocate;
+
+       d_printf(1, dev, "rfkill %p\n", rfkill);
+
        wimax_dev->rfkill = rfkill;
 
-       rfkill->name = wimax_dev->name;
-       rfkill->state = RFKILL_STATE_UNBLOCKED;
-       rfkill->data = wimax_dev;
-       rfkill->toggle_radio = wimax_rfkill_toggle_radio;
-
-       /* Initialize the input device for the hw key */
-       input_dev = input_allocate_device();
-       if (input_dev == NULL)
-               goto error_input_allocate;
-       wimax_dev->rfkill_input = input_dev;
-       d_printf(1, dev, "rfkill %p input %p\n", rfkill, input_dev);
-
-       input_dev->name = wimax_dev->name;
-       /* FIXME: get a real device bus ID and stuff? do we care? */
-       input_dev->id.bustype = BUS_HOST;
-       input_dev->id.vendor = 0xffff;
-       input_dev->evbit[0] = BIT(EV_KEY);
-       set_bit(KEY_WIMAX, input_dev->keybit);
-
-       /* Register both */
-       result = input_register_device(wimax_dev->rfkill_input);
-       if (result < 0)
-               goto error_input_register;
        result = rfkill_register(wimax_dev->rfkill);
        if (result < 0)
                goto error_rfkill_register;
@@ -394,17 +365,8 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev)
        d_fnend(3, dev, "(wimax_dev %p) = 0\n", wimax_dev);
        return 0;
 
-       /* if rfkill_register() suceeds, can't use rfkill_free() any
-        * more, only rfkill_unregister() [it owns the refcount]; with
-        * the input device we have the same issue--hence the if. */
 error_rfkill_register:
-       input_unregister_device(wimax_dev->rfkill_input);
-       wimax_dev->rfkill_input = NULL;
-error_input_register:
-       if (wimax_dev->rfkill_input)
-               input_free_device(wimax_dev->rfkill_input);
-error_input_allocate:
-       rfkill_free(wimax_dev->rfkill);
+       rfkill_destroy(wimax_dev->rfkill);
 error_rfkill_allocate:
        d_fnend(3, dev, "(wimax_dev %p) = %d\n", wimax_dev, result);
        return result;
@@ -423,45 +385,12 @@ void wimax_rfkill_rm(struct wimax_dev *wimax_dev)
 {
        struct device *dev = wimax_dev_to_dev(wimax_dev);
        d_fnstart(3, dev, "(wimax_dev %p)\n", wimax_dev);
-       rfkill_unregister(wimax_dev->rfkill);   /* frees */
-       input_unregister_device(wimax_dev->rfkill_input);
+       rfkill_unregister(wimax_dev->rfkill);
+       rfkill_destroy(wimax_dev->rfkill);
        d_fnend(3, dev, "(wimax_dev %p)\n", wimax_dev);
 }
 
 
-#else /* #ifdef CONFIG_RFKILL */
-
-void wimax_report_rfkill_hw(struct wimax_dev *wimax_dev,
-                           enum wimax_rf_state state)
-{
-}
-EXPORT_SYMBOL_GPL(wimax_report_rfkill_hw);
-
-void wimax_report_rfkill_sw(struct wimax_dev *wimax_dev,
-                           enum wimax_rf_state state)
-{
-}
-EXPORT_SYMBOL_GPL(wimax_report_rfkill_sw);
-
-int wimax_rfkill(struct wimax_dev *wimax_dev,
-                enum wimax_rf_state state)
-{
-       return WIMAX_RF_ON << 1 | WIMAX_RF_ON;
-}
-EXPORT_SYMBOL_GPL(wimax_rfkill);
-
-int wimax_rfkill_add(struct wimax_dev *wimax_dev)
-{
-       return 0;
-}
-
-void wimax_rfkill_rm(struct wimax_dev *wimax_dev)
-{
-}
-
-#endif /* #ifdef CONFIG_RFKILL */
-
-
 /*
  * Exporting to user space over generic netlink
  *
diff --git a/net/wimax/op-state-get.c b/net/wimax/op-state-get.c
new file mode 100644 (file)
index 0000000..a76b8fc
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Linux WiMAX
+ * Implement and export a method for getting a WiMAX device current state
+ *
+ * Copyright (C) 2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * Based on previous WiMAX core work by:
+ *  Copyright (C) 2008 Intel Corporation <linux-wimax@intel.com>
+ *  Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.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 Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <net/wimax.h>
+#include <net/genetlink.h>
+#include <linux/wimax.h>
+#include <linux/security.h>
+#include "wimax-internal.h"
+
+#define D_SUBMODULE op_state_get
+#include "debug-levels.h"
+
+
+static const
+struct nla_policy wimax_gnl_state_get_policy[WIMAX_GNL_ATTR_MAX + 1] = {
+       [WIMAX_GNL_STGET_IFIDX] = {
+               .type = NLA_U32,
+       },
+};
+
+
+/*
+ * Exporting to user space over generic netlink
+ *
+ * Parse the state get command from user space, return a combination
+ * value that describe the current state.
+ *
+ * No attributes.
+ */
+static
+int wimax_gnl_doit_state_get(struct sk_buff *skb, struct genl_info *info)
+{
+       int result, ifindex;
+       struct wimax_dev *wimax_dev;
+       struct device *dev;
+
+       d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info);
+       result = -ENODEV;
+       if (info->attrs[WIMAX_GNL_STGET_IFIDX] == NULL) {
+               printk(KERN_ERR "WIMAX_GNL_OP_STATE_GET: can't find IFIDX "
+                       "attribute\n");
+               goto error_no_wimax_dev;
+       }
+       ifindex = nla_get_u32(info->attrs[WIMAX_GNL_STGET_IFIDX]);
+       wimax_dev = wimax_dev_get_by_genl_info(info, ifindex);
+       if (wimax_dev == NULL)
+               goto error_no_wimax_dev;
+       dev = wimax_dev_to_dev(wimax_dev);
+       /* Execute the operation and send the result back to user space */
+       result = wimax_state_get(wimax_dev);
+       dev_put(wimax_dev->net_dev);
+error_no_wimax_dev:
+       d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result);
+       return result;
+}
+
+
+struct genl_ops wimax_gnl_state_get = {
+       .cmd = WIMAX_GNL_OP_STATE_GET,
+       .flags = GENL_ADMIN_PERM,
+       .policy = wimax_gnl_state_get_policy,
+       .doit = wimax_gnl_doit_state_get,
+       .dumpit = NULL,
+};
index 933e142..79fb7d7 100644 (file)
@@ -402,13 +402,15 @@ EXPORT_SYMBOL_GPL(wimax_dev_init);
 extern struct genl_ops
        wimax_gnl_msg_from_user,
        wimax_gnl_reset,
-       wimax_gnl_rfkill;
+       wimax_gnl_rfkill,
+       wimax_gnl_state_get;
 
 static
 struct genl_ops *wimax_gnl_ops[] = {
        &wimax_gnl_msg_from_user,
        &wimax_gnl_reset,
        &wimax_gnl_rfkill,
+       &wimax_gnl_state_get,
 };
 
 
@@ -533,6 +535,7 @@ struct d_level D_LEVEL[] = {
        D_SUBMODULE_DEFINE(op_msg),
        D_SUBMODULE_DEFINE(op_reset),
        D_SUBMODULE_DEFINE(op_rfkill),
+       D_SUBMODULE_DEFINE(op_state_get),
        D_SUBMODULE_DEFINE(stack),
 };
 size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL);
index 4500549..4428dd5 100644 (file)
@@ -1,5 +1,6 @@
 config CFG80211
-        tristate "Improved wireless configuration API"
+       tristate "Improved wireless configuration API"
+       depends on RFKILL || !RFKILL
 
 config CFG80211_REG_DEBUG
        bool "cfg80211 regulatory debugging"
index a5dbea1..d585029 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/debugfs.h>
 #include <linux/notifier.h>
 #include <linux/device.h>
+#include <linux/rtnetlink.h>
 #include <net/genetlink.h>
 #include <net/cfg80211.h>
 #include "nl80211.h"
@@ -227,6 +228,41 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
        return 0;
 }
 
+static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data)
+{
+       struct cfg80211_registered_device *drv = data;
+
+       drv->ops->rfkill_poll(&drv->wiphy);
+}
+
+static int cfg80211_rfkill_set_block(void *data, bool blocked)
+{
+       struct cfg80211_registered_device *drv = data;
+       struct wireless_dev *wdev;
+
+       if (!blocked)
+               return 0;
+
+       rtnl_lock();
+       mutex_lock(&drv->devlist_mtx);
+
+       list_for_each_entry(wdev, &drv->netdev_list, list)
+               dev_close(wdev->netdev);
+
+       mutex_unlock(&drv->devlist_mtx);
+       rtnl_unlock();
+
+       return 0;
+}
+
+static void cfg80211_rfkill_sync_work(struct work_struct *work)
+{
+       struct cfg80211_registered_device *drv;
+
+       drv = container_of(work, struct cfg80211_registered_device, rfkill_sync);
+       cfg80211_rfkill_set_block(drv, rfkill_blocked(drv->rfkill));
+}
+
 /* exported functions */
 
 struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
@@ -274,6 +310,18 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
        drv->wiphy.dev.class = &ieee80211_class;
        drv->wiphy.dev.platform_data = drv;
 
+       drv->rfkill_ops.set_block = cfg80211_rfkill_set_block;
+       drv->rfkill = rfkill_alloc(dev_name(&drv->wiphy.dev),
+                                  &drv->wiphy.dev, RFKILL_TYPE_WLAN,
+                                  &drv->rfkill_ops, drv);
+
+       if (!drv->rfkill) {
+               kfree(drv);
+               return NULL;
+       }
+
+       INIT_WORK(&drv->rfkill_sync, cfg80211_rfkill_sync_work);
+
        /*
         * Initialize wiphy parameters to IEEE 802.11 MIB default values.
         * Fragmentation and RTS threshold are disabled by default with the
@@ -347,17 +395,23 @@ int wiphy_register(struct wiphy *wiphy)
        /* check and set up bitrates */
        ieee80211_set_bitrate_flags(wiphy);
 
+       res = device_add(&drv->wiphy.dev);
+       if (res)
+               return res;
+
+       res = rfkill_register(drv->rfkill);
+       if (res)
+               goto out_rm_dev;
+
        mutex_lock(&cfg80211_mutex);
 
        /* set up regulatory info */
        wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
 
-       res = device_add(&drv->wiphy.dev);
-       if (res)
-               goto out_unlock;
-
        list_add(&drv->list, &cfg80211_drv_list);
 
+       mutex_unlock(&cfg80211_mutex);
+
        /* add to debugfs */
        drv->wiphy.debugfsdir =
                debugfs_create_dir(wiphy_name(&drv->wiphy),
@@ -378,17 +432,39 @@ int wiphy_register(struct wiphy *wiphy)
 
        cfg80211_debugfs_drv_add(drv);
 
-       res = 0;
-out_unlock:
-       mutex_unlock(&cfg80211_mutex);
+       return 0;
+
+ out_rm_dev:
+       device_del(&drv->wiphy.dev);
        return res;
 }
 EXPORT_SYMBOL(wiphy_register);
 
+void wiphy_rfkill_start_polling(struct wiphy *wiphy)
+{
+       struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
+
+       if (!drv->ops->rfkill_poll)
+               return;
+       drv->rfkill_ops.poll = cfg80211_rfkill_poll;
+       rfkill_resume_polling(drv->rfkill);
+}
+EXPORT_SYMBOL(wiphy_rfkill_start_polling);
+
+void wiphy_rfkill_stop_polling(struct wiphy *wiphy)
+{
+       struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
+
+       rfkill_pause_polling(drv->rfkill);
+}
+EXPORT_SYMBOL(wiphy_rfkill_stop_polling);
+
 void wiphy_unregister(struct wiphy *wiphy)
 {
        struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
 
+       rfkill_unregister(drv->rfkill);
+
        /* protect the device list */
        mutex_lock(&cfg80211_mutex);
 
@@ -425,6 +501,7 @@ EXPORT_SYMBOL(wiphy_unregister);
 void cfg80211_dev_free(struct cfg80211_registered_device *drv)
 {
        struct cfg80211_internal_bss *scan, *tmp;
+       rfkill_destroy(drv->rfkill);
        mutex_destroy(&drv->mtx);
        mutex_destroy(&drv->devlist_mtx);
        list_for_each_entry_safe(scan, tmp, &drv->bss_list, list)
@@ -438,6 +515,15 @@ void wiphy_free(struct wiphy *wiphy)
 }
 EXPORT_SYMBOL(wiphy_free);
 
+void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked)
+{
+       struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
+
+       if (rfkill_set_hw_state(drv->rfkill, blocked))
+               schedule_work(&drv->rfkill_sync);
+}
+EXPORT_SYMBOL(wiphy_rfkill_set_hw_state);
+
 static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
                                         unsigned long state,
                                         void *ndev)
@@ -446,7 +532,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
        struct cfg80211_registered_device *rdev;
 
        if (!dev->ieee80211_ptr)
-               return 0;
+               return NOTIFY_DONE;
 
        rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy);
 
@@ -492,9 +578,13 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
                }
                mutex_unlock(&rdev->devlist_mtx);
                break;
+       case NETDEV_PRE_UP:
+               if (rfkill_blocked(rdev->rfkill))
+                       return notifier_from_errno(-ERFKILL);
+               break;
        }
 
-       return 0;
+       return NOTIFY_DONE;
 }
 
 static struct notifier_block cfg80211_netdev_notifier = {
index ab512bc..bfa340c 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/kref.h>
 #include <linux/rbtree.h>
 #include <linux/debugfs.h>
+#include <linux/rfkill.h>
+#include <linux/workqueue.h>
 #include <net/genetlink.h>
 #include <net/cfg80211.h>
 #include "reg.h"
@@ -24,6 +26,11 @@ struct cfg80211_registered_device {
         * any call is in progress */
        struct mutex mtx;
 
+       /* rfkill support */
+       struct rfkill_ops rfkill_ops;
+       struct rfkill *rfkill;
+       struct work_struct rfkill_sync;
+
        /* ISO / IEC 3166 alpha2 for which this device is receiving
         * country IEs on, this can help disregard country IEs from APs
         * on the same alpha2 quickly. The alpha2 may differ from
index 4b4d3c8..2416856 100644 (file)
@@ -1687,6 +1687,12 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
        if (err)
                goto out_rtnl;
 
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) {
+               err = -EINVAL;
+               goto out;
+       }
+
        err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
        if (err)
                goto out;
@@ -1738,7 +1744,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
                nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
        params.listen_interval =
                nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
+
        params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
+       if (!params.aid || params.aid > IEEE80211_MAX_AID)
+               return -EINVAL;
+
        if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
                params.ht_capa =
                        nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
@@ -3559,11 +3569,43 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev)
        genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL);
 }
 
+static int nl80211_add_scan_req(struct sk_buff *msg,
+                               struct cfg80211_registered_device *rdev)
+{
+       struct cfg80211_scan_request *req = rdev->scan_req;
+       struct nlattr *nest;
+       int i;
+
+       if (WARN_ON(!req))
+               return 0;
+
+       nest = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
+       if (!nest)
+               goto nla_put_failure;
+       for (i = 0; i < req->n_ssids; i++)
+               NLA_PUT(msg, i, req->ssids[i].ssid_len, req->ssids[i].ssid);
+       nla_nest_end(msg, nest);
+
+       nest = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
+       if (!nest)
+               goto nla_put_failure;
+       for (i = 0; i < req->n_channels; i++)
+               NLA_PUT_U32(msg, i, req->channels[i]->center_freq);
+       nla_nest_end(msg, nest);
+
+       if (req->ie)
+               NLA_PUT(msg, NL80211_ATTR_IE, req->ie_len, req->ie);
+
+       return 0;
+ nla_put_failure:
+       return -ENOBUFS;
+}
+
 static int nl80211_send_scan_donemsg(struct sk_buff *msg,
-                                   struct cfg80211_registered_device *rdev,
-                                   struct net_device *netdev,
-                                   u32 pid, u32 seq, int flags,
-                                   u32 cmd)
+                                    struct cfg80211_registered_device *rdev,
+                                    struct net_device *netdev,
+                                    u32 pid, u32 seq, int flags,
+                                    u32 cmd)
 {
        void *hdr;
 
@@ -3574,7 +3616,8 @@ static int nl80211_send_scan_donemsg(struct sk_buff *msg,
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
 
-       /* XXX: we should probably bounce back the request? */
+       /* ignore errors and send incomplete event anyway */
+       nl80211_add_scan_req(msg, rdev);
 
        return genlmsg_end(msg, hdr);
 
@@ -3828,7 +3871,7 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
        struct sk_buff *msg;
        void *hdr;
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
        if (!msg)
                return;
 
@@ -3852,7 +3895,7 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
                return;
        }
 
-       genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL);
+       genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC);
        return;
 
  nla_put_failure:
index f87ac1d..5e14371 100644 (file)
@@ -2129,7 +2129,12 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
                 * driver wanted to the wiphy to deal with conflicts
                 */
 
-               BUG_ON(request_wiphy->regd);
+               /*
+                * Userspace could have sent two replies with only
+                * one kernel request.
+                */
+               if (request_wiphy->regd)
+                       return -EALREADY;
 
                r = reg_copy_regd(&request_wiphy->regd, rd);
                if (r)
@@ -2171,7 +2176,13 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
         * the country IE rd with what CRDA believes that country should have
         */
 
-       BUG_ON(!country_ie_regdomain);
+       /*
+        * Userspace could have sent two replies with only
+        * one kernel request. By the second reply we would have
+        * already processed and consumed the country_ie_regdomain.
+        */
+       if (!country_ie_regdomain)
+               return -EALREADY;
        BUG_ON(rd == country_ie_regdomain);
 
        /*
index df59440..e95b638 100644 (file)
@@ -29,13 +29,14 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
                goto out;
 
        WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
-       wiphy_to_dev(request->wiphy)->scan_req = NULL;
 
        if (aborted)
                nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev);
        else
                nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev);
 
+       wiphy_to_dev(request->wiphy)->scan_req = NULL;
+
 #ifdef CONFIG_WIRELESS_EXT
        if (!aborted) {
                memset(&wrqu, 0, sizeof(wrqu));
index d072bff..2555069 100644 (file)
@@ -157,26 +157,25 @@ int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
            params->cipher != WLAN_CIPHER_SUITE_WEP104)
                return -EINVAL;
 
-       /* TODO: add definitions for the lengths to linux/ieee80211.h */
        switch (params->cipher) {
        case WLAN_CIPHER_SUITE_WEP40:
-               if (params->key_len != 5)
+               if (params->key_len != WLAN_KEY_LEN_WEP40)
                        return -EINVAL;
                break;
        case WLAN_CIPHER_SUITE_TKIP:
-               if (params->key_len != 32)
+               if (params->key_len != WLAN_KEY_LEN_TKIP)
                        return -EINVAL;
                break;
        case WLAN_CIPHER_SUITE_CCMP:
-               if (params->key_len != 16)
+               if (params->key_len != WLAN_KEY_LEN_CCMP)
                        return -EINVAL;
                break;
        case WLAN_CIPHER_SUITE_WEP104:
-               if (params->key_len != 13)
+               if (params->key_len != WLAN_KEY_LEN_WEP104)
                        return -EINVAL;
                break;
        case WLAN_CIPHER_SUITE_AES_CMAC:
-               if (params->key_len != 16)
+               if (params->key_len != WLAN_KEY_LEN_AES_CMAC)
                        return -EINVAL;
                break;
        default:
@@ -259,7 +258,7 @@ unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
 }
 EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
 
-int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
+static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
 {
        int ae = meshhdr->flags & MESH_FLAGS_AE;
        /* 7.1.3.5a.2 */
index 711e00a..d030c53 100644 (file)
@@ -744,3 +744,86 @@ int cfg80211_wext_giwencode(struct net_device *dev,
        return err;
 }
 EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode);
+
+int cfg80211_wext_siwtxpower(struct net_device *dev,
+                            struct iw_request_info *info,
+                            union iwreq_data *data, char *extra)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       enum tx_power_setting type;
+       int dbm = 0;
+
+       if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
+               return -EINVAL;
+       if (data->txpower.flags & IW_TXPOW_RANGE)
+               return -EINVAL;
+
+       if (!rdev->ops->set_tx_power)
+               return -EOPNOTSUPP;
+
+       /* only change when not disabling */
+       if (!data->txpower.disabled) {
+               rfkill_set_sw_state(rdev->rfkill, false);
+
+               if (data->txpower.fixed) {
+                       /*
+                        * wext doesn't support negative values, see
+                        * below where it's for automatic
+                        */
+                       if (data->txpower.value < 0)
+                               return -EINVAL;
+                       dbm = data->txpower.value;
+                       type = TX_POWER_FIXED;
+                       /* TODO: do regulatory check! */
+               } else {
+                       /*
+                        * Automatic power level setting, max being the value
+                        * passed in from userland.
+                        */
+                       if (data->txpower.value < 0) {
+                               type = TX_POWER_AUTOMATIC;
+                       } else {
+                               dbm = data->txpower.value;
+                               type = TX_POWER_LIMITED;
+                       }
+               }
+       } else {
+               rfkill_set_sw_state(rdev->rfkill, true);
+               schedule_work(&rdev->rfkill_sync);
+               return 0;
+       }
+
+       return rdev->ops->set_tx_power(wdev->wiphy, type, dbm);;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwtxpower);
+
+int cfg80211_wext_giwtxpower(struct net_device *dev,
+                            struct iw_request_info *info,
+                            union iwreq_data *data, char *extra)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       int err, val;
+
+       if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
+               return -EINVAL;
+       if (data->txpower.flags & IW_TXPOW_RANGE)
+               return -EINVAL;
+
+       if (!rdev->ops->get_tx_power)
+               return -EOPNOTSUPP;
+
+       err = rdev->ops->get_tx_power(wdev->wiphy, &val);
+       if (err)
+               return err;
+
+       /* well... oh well */
+       data->txpower.fixed = 1;
+       data->txpower.disabled = rfkill_blocked(rdev->rfkill);
+       data->txpower.value = val;
+       data->txpower.flags = IW_TXPOW_DBM;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_giwtxpower);
index 96036cf..d31ccb4 100644 (file)
@@ -696,8 +696,9 @@ int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *desc,
 {
        int start = skb_headlen(skb);
        int i, copy = start - offset;
-       int err;
+       struct sk_buff *frag_iter;
        struct scatterlist sg;
+       int err;
 
        /* Checksum header. */
        if (copy > 0) {
@@ -742,28 +743,24 @@ int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *desc,
                start = end;
        }
 
-       if (skb_shinfo(skb)->frag_list) {
-               struct sk_buff *list = skb_shinfo(skb)->frag_list;
-
-               for (; list; list = list->next) {
-                       int end;
-
-                       WARN_ON(start > offset + len);
-
-                       end = start + list->len;
-                       if ((copy = end - offset) > 0) {
-                               if (copy > len)
-                                       copy = len;
-                               err = skb_icv_walk(list, desc, offset-start,
-                                                  copy, icv_update);
-                               if (unlikely(err))
-                                       return err;
-                               if ((len -= copy) == 0)
-                                       return 0;
-                               offset += copy;
-                       }
-                       start = end;
+       skb_walk_frags(skb, frag_iter) {
+               int end;
+
+               WARN_ON(start > offset + len);
+
+               end = start + frag_iter->len;
+               if ((copy = end - offset) > 0) {
+                       if (copy > len)
+                               copy = len;
+                       err = skb_icv_walk(frag_iter, desc, offset-start,
+                                          copy, icv_update);
+                       if (unlikely(err))
+                               return err;
+                       if ((len -= copy) == 0)
+                               return 0;
+                       offset += copy;
                }
+               start = end;
        }
        BUG_ON(len);
        return 0;
index b4a1317..e0009c1 100644 (file)
@@ -251,8 +251,7 @@ resume:
        nf_reset(skb);
 
        if (decaps) {
-               dst_release(skb->dst);
-               skb->dst = NULL;
+               skb_dst_drop(skb);
                netif_rx(skb);
                return 0;
        } else {
index c235597..b9fe131 100644 (file)
@@ -22,7 +22,7 @@ static int xfrm_output2(struct sk_buff *skb);
 
 static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb)
 {
-       struct dst_entry *dst = skb->dst;
+       struct dst_entry *dst = skb_dst(skb);
        int nhead = dst->header_len + LL_RESERVED_SPACE(dst->dev)
                - skb_headroom(skb);
        int ntail = dst->dev->needed_tailroom - skb_tailroom(skb);
@@ -39,7 +39,7 @@ static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb)
 
 static int xfrm_output_one(struct sk_buff *skb, int err)
 {
-       struct dst_entry *dst = skb->dst;
+       struct dst_entry *dst = skb_dst(skb);
        struct xfrm_state *x = dst->xfrm;
        struct net *net = xs_net(x);
 
@@ -94,12 +94,13 @@ resume:
                        goto error_nolock;
                }
 
-               if (!(skb->dst = dst_pop(dst))) {
+               dst = dst_pop(dst);
+               if (!dst) {
                        XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
                        err = -EHOSTUNREACH;
                        goto error_nolock;
                }
-               dst = skb->dst;
+               skb_dst_set(skb, dst);
                x = dst->xfrm;
        } while (x && !(x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL));
 
@@ -119,16 +120,16 @@ int xfrm_output_resume(struct sk_buff *skb, int err)
        while (likely((err = xfrm_output_one(skb, err)) == 0)) {
                nf_reset(skb);
 
-               err = skb->dst->ops->local_out(skb);
+               err = skb_dst(skb)->ops->local_out(skb);
                if (unlikely(err != 1))
                        goto out;
 
-               if (!skb->dst->xfrm)
+               if (!skb_dst(skb)->xfrm)
                        return dst_output(skb);
 
-               err = nf_hook(skb->dst->ops->family,
+               err = nf_hook(skb_dst(skb)->ops->family,
                              NF_INET_POST_ROUTING, skb,
-                             NULL, skb->dst->dev, xfrm_output2);
+                             NULL, skb_dst(skb)->dev, xfrm_output2);
                if (unlikely(err != 1))
                        goto out;
        }
@@ -179,7 +180,7 @@ static int xfrm_output_gso(struct sk_buff *skb)
 
 int xfrm_output(struct sk_buff *skb)
 {
-       struct net *net = dev_net(skb->dst->dev);
+       struct net *net = dev_net(skb_dst(skb)->dev);
        int err;
 
        if (skb_is_gso(skb))
@@ -202,7 +203,7 @@ int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb)
        struct xfrm_mode *inner_mode;
        if (x->sel.family == AF_UNSPEC)
                inner_mode = xfrm_ip2inner_mode(x,
-                               xfrm_af2proto(skb->dst->ops->family));
+                               xfrm_af2proto(skb_dst(skb)->ops->family));
        else
                inner_mode = x->inner_mode;
 
index 9c068ab..cb81ca3 100644 (file)
@@ -2027,6 +2027,8 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family)
 {
        struct net *net = dev_net(skb->dev);
        struct flowi fl;
+       struct dst_entry *dst;
+       int res;
 
        if (xfrm_decode_session(skb, &fl, family) < 0) {
                /* XXX: we should have something like FWDHDRERROR here. */
@@ -2034,7 +2036,11 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family)
                return 0;
        }
 
-       return xfrm_lookup(net, &skb->dst, &fl, NULL, 0) == 0;
+       dst = skb_dst(skb);
+
+       res = xfrm_lookup(net, &dst, &fl, NULL, 0) == 0;
+       skb_dst_set(skb, dst);
+       return res;
 }
 EXPORT_SYMBOL(__xfrm_route_forward);
 
index 2fcad7c..4bfc615 100644 (file)
@@ -4503,7 +4503,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
         * when the packet is on it's final way out.
         * NOTE: there appear to be some IPv6 multicast cases where skb->dst
         *       is NULL, in this case go ahead and apply access control. */
-       if (skb->dst != NULL && skb->dst->xfrm != NULL)
+       if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL)
                return NF_ACCEPT;
 #endif
        secmark_active = selinux_secmark_enabled();
index c0eb720..72b1845 100644 (file)
@@ -447,7 +447,7 @@ int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb,
        struct dst_entry *dst;
        int rc = 0;
 
-       dst = skb->dst;
+       dst = skb_dst(skb);
 
        if (dst) {
                struct dst_entry *dst_test;