]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
authorDavid S. Miller <davem@davemloft.net>
Tue, 10 Jun 2008 09:22:26 +0000 (02:22 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 10 Jun 2008 09:22:26 +0000 (02:22 -0700)
Conflicts:

drivers/net/tg3.c
drivers/net/wireless/rt2x00/rt2x00dev.c
net/mac80211/ieee80211_i.h

349 files changed:
Documentation/networking/bonding.txt
Documentation/powerpc/booting-without-of.txt
drivers/net/3c515.c
drivers/net/3c523.c
drivers/net/3c527.c
drivers/net/8139cp.c
drivers/net/8139too.c
drivers/net/8390.h
drivers/net/Kconfig
drivers/net/acenic.c
drivers/net/acenic.h
drivers/net/atlx/atl1.c
drivers/net/bnx2.c
drivers/net/bnx2.h
drivers/net/bnx2_fw.h
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_sysfs.c
drivers/net/bonding/bonding.h
drivers/net/cxgb3/adapter.h
drivers/net/cxgb3/common.h
drivers/net/cxgb3/cxgb3_ioctl.h
drivers/net/cxgb3/cxgb3_main.c
drivers/net/cxgb3/sge.c
drivers/net/cxgb3/t3_cpl.h
drivers/net/dl2k.c
drivers/net/dm9000.c
drivers/net/forcedeth.c
drivers/net/fs_enet/fs_enet-main.c
drivers/net/gianfar.c
drivers/net/hamachi.c
drivers/net/hamradio/6pack.c
drivers/net/ixp2000/ixpdev.c
drivers/net/lib8390.c
drivers/net/myri10ge/myri10ge.c
drivers/net/natsemi.c
drivers/net/niu.h
drivers/net/ns83820.c
drivers/net/pcmcia/3c574_cs.c
drivers/net/pcmcia/3c589_cs.c
drivers/net/pcmcia/axnet_cs.c
drivers/net/pcnet32.c
drivers/net/phy/Kconfig
drivers/net/phy/Makefile
drivers/net/phy/broadcom.c
drivers/net/phy/mdio-ofgpio.c [new file with mode: 0644]
drivers/net/ppp_generic.c
drivers/net/ps3_gelic_net.c
drivers/net/ps3_gelic_net.h
drivers/net/ps3_gelic_wireless.c
drivers/net/ps3_gelic_wireless.h
drivers/net/qla3xxx.c
drivers/net/s2io.c
drivers/net/s2io.h
drivers/net/sb1250-mac.c
drivers/net/sfc/Kconfig
drivers/net/sfc/Makefile
drivers/net/sfc/boards.c
drivers/net/sfc/boards.h
drivers/net/sfc/efx.c
drivers/net/sfc/falcon.c
drivers/net/sfc/i2c-direct.c [deleted file]
drivers/net/sfc/i2c-direct.h [deleted file]
drivers/net/sfc/net_driver.h
drivers/net/sfc/sfe4001.c
drivers/net/sis190.c
drivers/net/sis900.c
drivers/net/sky2.c
drivers/net/sky2.h
drivers/net/spider_net.c
drivers/net/tg3.c
drivers/net/tg3.h
drivers/net/tlan.c
drivers/net/tlan.h
drivers/net/tokenring/3c359.c
drivers/net/tokenring/3c359.h
drivers/net/tsi108_eth.c
drivers/net/ucc_geth_ethtool.c
drivers/net/via-velocity.c
drivers/net/wireless/adm8211.c
drivers/net/wireless/adm8211.h
drivers/net/wireless/airo.c
drivers/net/wireless/arlan-main.c
drivers/net/wireless/arlan.h
drivers/net/wireless/ath5k/base.c
drivers/net/wireless/ath5k/base.h
drivers/net/wireless/atmel.c
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/debugfs.c
drivers/net/wireless/b43/debugfs.h
drivers/net/wireless/b43/dma.c
drivers/net/wireless/b43/dma.h
drivers/net/wireless/b43/lo.c
drivers/net/wireless/b43/lo.h
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/main.h
drivers/net/wireless/b43/nphy.c
drivers/net/wireless/b43/phy.c
drivers/net/wireless/b43/phy.h
drivers/net/wireless/b43/pio.c
drivers/net/wireless/b43/pio.h
drivers/net/wireless/b43/xmit.c
drivers/net/wireless/b43/xmit.h
drivers/net/wireless/b43legacy/b43legacy.h
drivers/net/wireless/b43legacy/dma.c
drivers/net/wireless/b43legacy/dma.h
drivers/net/wireless/b43legacy/main.c
drivers/net/wireless/b43legacy/phy.c
drivers/net/wireless/b43legacy/pio.c
drivers/net/wireless/b43legacy/pio.h
drivers/net/wireless/b43legacy/radio.c
drivers/net/wireless/b43legacy/xmit.c
drivers/net/wireless/b43legacy/xmit.h
drivers/net/wireless/iwlwifi/Kconfig
drivers/net/wireless/iwlwifi/Makefile
drivers/net/wireless/iwlwifi/iwl-3945-hw.h
drivers/net/wireless/iwlwifi/iwl-3945-rs.c
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/iwlwifi/iwl-3945.h
drivers/net/wireless/iwlwifi/iwl-4965-hw.h
drivers/net/wireless/iwlwifi/iwl-4965-rs.c
drivers/net/wireless/iwlwifi/iwl-4965-rs.h
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-5000-hw.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-5000.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-calib.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-calib.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-commands.h [moved from drivers/net/wireless/iwlwifi/iwl-4965-commands.h with 91% similarity]
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-csr.h
drivers/net/wireless/iwlwifi/iwl-debug.h
drivers/net/wireless/iwlwifi/iwl-debugfs.c
drivers/net/wireless/iwlwifi/iwl-dev.h [moved from drivers/net/wireless/iwlwifi/iwl-4965.h with 80% similarity]
drivers/net/wireless/iwlwifi/iwl-eeprom.c
drivers/net/wireless/iwlwifi/iwl-eeprom.h
drivers/net/wireless/iwlwifi/iwl-fh.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-hcmd.c
drivers/net/wireless/iwlwifi/iwl-helpers.h
drivers/net/wireless/iwlwifi/iwl-led.c
drivers/net/wireless/iwlwifi/iwl-power.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-power.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/iwl-rfkill.c
drivers/net/wireless/iwlwifi/iwl-rx.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-sta.c
drivers/net/wireless/iwlwifi/iwl-sta.h
drivers/net/wireless/iwlwifi/iwl-tx.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/iwlwifi/iwl4965-base.c
drivers/net/wireless/libertas/Makefile
drivers/net/wireless/libertas/assoc.c
drivers/net/wireless/libertas/cmd.c
drivers/net/wireless/libertas/cmd.h
drivers/net/wireless/libertas/cmdresp.c
drivers/net/wireless/libertas/decl.h
drivers/net/wireless/libertas/defs.h
drivers/net/wireless/libertas/dev.h
drivers/net/wireless/libertas/host.h
drivers/net/wireless/libertas/hostcmd.h
drivers/net/wireless/libertas/if_cs.c
drivers/net/wireless/libertas/if_usb.c
drivers/net/wireless/libertas/main.c
drivers/net/wireless/libertas/persistcfg.c [new file with mode: 0644]
drivers/net/wireless/libertas/rx.c
drivers/net/wireless/libertas/types.h
drivers/net/wireless/libertas/wext.c
drivers/net/wireless/p54/p54.h
drivers/net/wireless/p54/p54common.c
drivers/net/wireless/p54/p54common.h
drivers/net/wireless/p54/p54pci.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/Kconfig
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2400pci.h
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2500pci.h
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2500usb.h
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00debug.c
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00lib.h
drivers/net/wireless/rt2x00/rt2x00mac.c
drivers/net/wireless/rt2x00/rt2x00pci.c
drivers/net/wireless/rt2x00/rt2x00pci.h
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rt2x00/rt2x00queue.h
drivers/net/wireless/rt2x00/rt2x00reg.h
drivers/net/wireless/rt2x00/rt2x00usb.c
drivers/net/wireless/rt2x00/rt2x00usb.h
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt61pci.h
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rt2x00/rt73usb.h
drivers/net/wireless/rtl8180_dev.c
drivers/net/wireless/rtl8187.h
drivers/net/wireless/rtl8187_dev.c
drivers/net/wireless/zd1211rw/zd_mac.c
drivers/net/wireless/zd1211rw/zd_mac.h
drivers/net/wireless/zd1211rw/zd_usb.c
drivers/ssb/pci.c
include/linux/brcmphy.h [new file with mode: 0644]
include/linux/ieee80211.h
include/linux/netfilter/nfnetlink_conntrack.h
include/linux/netfilter_bridge/ebt_ip6.h [new file with mode: 0644]
include/linux/netfilter_bridge/ebt_log.h
include/linux/netfilter_ipv4.h
include/linux/netfilter_ipv6.h
include/linux/netlink.h
include/linux/pci_ids.h
include/linux/tcp.h
include/linux/tipc_config.h
include/linux/wanrouter.h
include/linux/wireless.h
include/net/ieee80211.h
include/net/ip6_tunnel.h
include/net/ipip.h
include/net/mac80211.h
include/net/net_namespace.h
include/net/netfilter/ipv4/nf_conntrack_ipv4.h
include/net/netfilter/nf_conntrack.h
include/net/netns/ipv4.h
include/net/netns/ipv6.h
include/net/sctp/sctp.h
include/net/sctp/structs.h
include/net/sctp/user.h
include/net/tipc/tipc_port.h
include/net/wireless.h
ipc/mqueue.c
net/bridge/br_device.c
net/bridge/br_forward.c
net/bridge/br_input.c
net/bridge/br_private.h
net/bridge/netfilter/Kconfig
net/bridge/netfilter/Makefile
net/bridge/netfilter/ebt_ip6.c [new file with mode: 0644]
net/bridge/netfilter/ebt_log.c
net/core/net-sysfs.c
net/core/rtnetlink.c
net/core/sysctl_net_core.c
net/ieee80211/ieee80211_rx.c
net/ieee80211/ieee80211_tx.c
net/ieee80211/ieee80211_wx.c
net/ipv4/ip_fragment.c
net/ipv4/ip_gre.c
net/ipv4/ipip.c
net/ipv4/ipmr.c
net/ipv4/netfilter/Kconfig
net/ipv4/netfilter/Makefile
net/ipv4/netfilter/ip_queue.c
net/ipv4/netfilter/iptable_security.c [new file with mode: 0644]
net/ipv4/netfilter/nf_conntrack_proto_icmp.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6mr.c
net/ipv6/netfilter/Kconfig
net/ipv6/netfilter/Makefile
net/ipv6/netfilter/ip6_queue.c
net/ipv6/netfilter/ip6table_security.c [new file with mode: 0644]
net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
net/ipv6/reassembly.c
net/ipv6/sit.c
net/ipv6/sysctl_net_ipv6.c
net/irda/irnet/irnet_ppp.c
net/irda/irnet/irnet_ppp.h
net/iucv/af_iucv.c
net/iucv/iucv.c
net/mac80211/Kconfig
net/mac80211/Makefile
net/mac80211/aes_ccm.c
net/mac80211/aes_ccm.h
net/mac80211/cfg.c
net/mac80211/debugfs.c
net/mac80211/debugfs_key.c
net/mac80211/debugfs_netdev.c
net/mac80211/debugfs_sta.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/key.h
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mesh_hwmp.c
net/mac80211/mesh_pathtbl.c
net/mac80211/mesh_plink.c
net/mac80211/michael.c
net/mac80211/michael.h
net/mac80211/mlme.c
net/mac80211/rate.c
net/mac80211/rate.h
net/mac80211/rc80211_pid.h
net/mac80211/rc80211_pid_algo.c
net/mac80211/rc80211_pid_debugfs.c
net/mac80211/rx.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/tkip.c
net/mac80211/tkip.h
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wep.c
net/mac80211/wep.h
net/mac80211/wext.c
net/mac80211/wme.c
net/mac80211/wme.h
net/mac80211/wpa.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_extend.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_proto_dccp.c
net/netfilter/nf_conntrack_proto_sctp.c
net/netfilter/nf_conntrack_proto_tcp.c
net/netfilter/nfnetlink_queue.c
net/netfilter/xt_CONNSECMARK.c
net/netfilter/xt_SECMARK.c
net/netlink/af_netlink.c
net/sctp/associola.c
net/sctp/proc.c
net/sctp/protocol.c
net/sctp/sm_sideeffect.c
net/sctp/socket.c
net/sysctl_net.c
net/tipc/bcast.c
net/tipc/cluster.c
net/tipc/config.c
net/tipc/core.c
net/tipc/core.h
net/tipc/dbg.c
net/tipc/dbg.h
net/tipc/discover.c
net/tipc/discover.h
net/tipc/link.c
net/tipc/msg.c
net/tipc/msg.h
net/tipc/name_distr.c
net/tipc/name_table.c
net/tipc/net.c
net/tipc/net.h
net/tipc/netlink.c
net/tipc/node.c
net/tipc/port.c
net/tipc/ref.c
net/tipc/socket.c
net/tipc/subscr.c
net/tipc/subscr.h
net/wanrouter/wanmain.c
net/wanrouter/wanproc.c
net/wireless/core.c
net/wireless/radiotap.c

index a0cda062bc33b6e1de3dd2bb60d5ff62bdf97cd4..8e6b8d3c7410eeb2470af2f1d1b45c0983a8aa9d 100644 (file)
@@ -289,35 +289,73 @@ downdelay
 fail_over_mac
 
        Specifies whether active-backup mode should set all slaves to
-       the same MAC address (the traditional behavior), or, when
-       enabled, change the bond's MAC address when changing the
-       active interface (i.e., fail over the MAC address itself).
-
-       Fail over MAC is useful for devices that cannot ever alter
-       their MAC address, or for devices that refuse incoming
-       broadcasts with their own source MAC (which interferes with
-       the ARP monitor).
-
-       The down side of fail over MAC is that every device on the
-       network must be updated via gratuitous ARP, vs. just updating
-       a switch or set of switches (which often takes place for any
-       traffic, not just ARP traffic, if the switch snoops incoming
-       traffic to update its tables) for the traditional method.  If
-       the gratuitous ARP is lost, communication may be disrupted.
-
-       When fail over MAC is used in conjuction with the mii monitor,
-       devices which assert link up prior to being able to actually
-       transmit and receive are particularly susecptible to loss of
-       the gratuitous ARP, and an appropriate updelay setting may be
-       required.
-
-       A value of 0 disables fail over MAC, and is the default.  A
-       value of 1 enables fail over MAC.  This option is enabled
-       automatically if the first slave added cannot change its MAC
-       address.  This option may be modified via sysfs only when no
-       slaves are present in the bond.
-
-       This option was added in bonding version 3.2.0.
+       the same MAC address at enslavement (the traditional
+       behavior), or, when enabled, perform special handling of the
+       bond's MAC address in accordance with the selected policy.
+
+       Possible values are:
+
+       none or 0
+
+               This setting disables fail_over_mac, and causes
+               bonding to set all slaves of an active-backup bond to
+               the same MAC address at enslavement time.  This is the
+               default.
+
+       active or 1
+
+               The "active" fail_over_mac policy indicates that the
+               MAC address of the bond should always be the MAC
+               address of the currently active slave.  The MAC
+               address of the slaves is not changed; instead, the MAC
+               address of the bond changes during a failover.
+
+               This policy is useful for devices that cannot ever
+               alter their MAC address, or for devices that refuse
+               incoming broadcasts with their own source MAC (which
+               interferes with the ARP monitor).
+
+               The down side of this policy is that every device on
+               the network must be updated via gratuitous ARP,
+               vs. just updating a switch or set of switches (which
+               often takes place for any traffic, not just ARP
+               traffic, if the switch snoops incoming traffic to
+               update its tables) for the traditional method.  If the
+               gratuitous ARP is lost, communication may be
+               disrupted.
+
+               When this policy is used in conjuction with the mii
+               monitor, devices which assert link up prior to being
+               able to actually transmit and receive are particularly
+               susecptible to loss of the gratuitous ARP, and an
+               appropriate updelay setting may be required.
+
+       follow or 2
+
+               The "follow" fail_over_mac policy causes the MAC
+               address of the bond to be selected normally (normally
+               the MAC address of the first slave added to the bond).
+               However, the second and subsequent slaves are not set
+               to this MAC address while they are in a backup role; a
+               slave is programmed with the bond's MAC address at
+               failover time (and the formerly active slave receives
+               the newly active slave's MAC address).
+
+               This policy is useful for multiport devices that
+               either become confused or incur a performance penalty
+               when multiple ports are programmed with the same MAC
+               address.
+
+
+       The default policy is none, unless the first slave cannot
+       change its MAC address, in which case the active policy is
+       selected by default.
+
+       This option may be modified via sysfs only when no slaves are
+       present in the bond.
+
+       This option was added in bonding version 3.2.0.  The "follow"
+       policy was added in bonding version 3.3.0.
 
 lacp_rate
 
index 1d2a772506cfa46e23acda9c3660369b72e1e85f..46a9dba11f2f003334f2ef44d275895b2477856f 100644 (file)
@@ -58,6 +58,7 @@ Table of Contents
       o) Xilinx IP cores
       p) Freescale Synchronous Serial Interface
          q) USB EHCI controllers
+      r) MDIO on GPIOs
 
   VII - Marvell Discovery mv64[345]6x System Controller chips
     1) The /system-controller node
@@ -2870,6 +2871,26 @@ platforms are moved over to use the flattened-device-tree model.
                reg = <0xe8000000 32>;
        };
 
+   r) MDIO on GPIOs
+
+   Currently defined compatibles:
+   - virtual,gpio-mdio
+
+   MDC and MDIO lines connected to GPIO controllers are listed in the
+   gpios property as described in section VIII.1 in the following order:
+
+   MDC, MDIO.
+
+   Example:
+
+       mdio {
+               compatible = "virtual,mdio-gpio";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               gpios = <&qe_pio_a 11
+                        &qe_pio_c 6>;
+       };
+
 VII - Marvell Discovery mv64[345]6x System Controller chips
 ===========================================================
 
index 105a8c7ca7e9dce46ab3aae935db671df7949b8f..e4e3241628d615bb752d99c3cfc18c2ab4e0124e 100644 (file)
@@ -572,12 +572,16 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr,
        int irq;
        DECLARE_MAC_BUF(mac);
 
+#ifdef __ISAPNP__
        if (idev) {
                irq = pnp_irq(idev, 0);
                vp->dev = &idev->dev;
        } else {
                irq = inw(ioaddr + 0x2002) & 15;
        }
+#else
+       irq = inw(ioaddr + 0x2002) & 15;
+#endif
 
        dev->base_addr = ioaddr;
        dev->irq = irq;
index 239fc42fb8df6c97ffe535da49d9b0d2df3e5387..dc6e474229b1fae95923ce733b5647d9ac4be771 100644 (file)
@@ -202,7 +202,6 @@ static void elmc_xmt_int(struct net_device *dev);
 static void elmc_rnr_int(struct net_device *dev);
 
 struct priv {
-       struct net_device_stats stats;
        unsigned long base;
        char *memtop;
        unsigned long mapped_start;             /* Start of ioremap */
@@ -989,18 +988,18 @@ static void elmc_rcv_int(struct net_device *dev)
                                        skb->protocol = eth_type_trans(skb, dev);
                                        netif_rx(skb);
                                        dev->last_rx = jiffies;
-                                       p->stats.rx_packets++;
-                                       p->stats.rx_bytes += totlen;
+                                       dev->stats.rx_packets++;
+                                       dev->stats.rx_bytes += totlen;
                                } else {
-                                       p->stats.rx_dropped++;
+                                       dev->stats.rx_dropped++;
                                }
                        } else {
                                printk(KERN_WARNING "%s: received oversized frame.\n", dev->name);
-                               p->stats.rx_dropped++;
+                               dev->stats.rx_dropped++;
                        }
                } else {        /* frame !(ok), only with 'save-bad-frames' */
                        printk(KERN_WARNING "%s: oops! rfd-error-status: %04x\n", dev->name, status);
-                       p->stats.rx_errors++;
+                       dev->stats.rx_errors++;
                }
                p->rfd_top->status = 0;
                p->rfd_top->last = RFD_SUSP;
@@ -1018,7 +1017,7 @@ static void elmc_rnr_int(struct net_device *dev)
 {
        struct priv *p = (struct priv *) dev->priv;
 
-       p->stats.rx_errors++;
+       dev->stats.rx_errors++;
 
        WAIT_4_SCB_CMD();       /* wait for the last cmd */
        p->scb->cmd = RUC_ABORT;        /* usually the RU is in the 'no resource'-state .. abort it now. */
@@ -1046,24 +1045,24 @@ static void elmc_xmt_int(struct net_device *dev)
                printk(KERN_WARNING "%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name);
        }
        if (status & STAT_OK) {
-               p->stats.tx_packets++;
-               p->stats.collisions += (status & TCMD_MAXCOLLMASK);
+               dev->stats.tx_packets++;
+               dev->stats.collisions += (status & TCMD_MAXCOLLMASK);
        } else {
-               p->stats.tx_errors++;
+               dev->stats.tx_errors++;
                if (status & TCMD_LATECOLL) {
                        printk(KERN_WARNING "%s: late collision detected.\n", dev->name);
-                       p->stats.collisions++;
+                       dev->stats.collisions++;
                } else if (status & TCMD_NOCARRIER) {
-                       p->stats.tx_carrier_errors++;
+                       dev->stats.tx_carrier_errors++;
                        printk(KERN_WARNING "%s: no carrier detected.\n", dev->name);
                } else if (status & TCMD_LOSTCTS) {
                        printk(KERN_WARNING "%s: loss of CTS detected.\n", dev->name);
                } else if (status & TCMD_UNDERRUN) {
-                       p->stats.tx_fifo_errors++;
+                       dev->stats.tx_fifo_errors++;
                        printk(KERN_WARNING "%s: DMA underrun detected.\n", dev->name);
                } else if (status & TCMD_MAXCOLL) {
                        printk(KERN_WARNING "%s: Max. collisions exceeded.\n", dev->name);
-                       p->stats.collisions += 16;
+                       dev->stats.collisions += 16;
                }
        }
 
@@ -1215,12 +1214,12 @@ static struct net_device_stats *elmc_get_stats(struct net_device *dev)
        ovrn = p->scb->ovrn_errs;
        p->scb->ovrn_errs -= ovrn;
 
-       p->stats.rx_crc_errors += crc;
-       p->stats.rx_fifo_errors += ovrn;
-       p->stats.rx_frame_errors += aln;
-       p->stats.rx_dropped += rsc;
+       dev->stats.rx_crc_errors += crc;
+       dev->stats.rx_fifo_errors += ovrn;
+       dev->stats.rx_frame_errors += aln;
+       dev->stats.rx_dropped += rsc;
 
-       return &p->stats;
+       return &dev->stats;
 }
 
 /********************************************************
index fae295b6809c4a83050e23905df2d25da00001cf..6aca0c640f13949ae2033cac47df4e1ba3b4783d 100644 (file)
@@ -158,7 +158,6 @@ struct mc32_local
        int slot;
 
        u32 base;
-       struct net_device_stats net_stats;
        volatile struct mc32_mailbox *rx_box;
        volatile struct mc32_mailbox *tx_box;
        volatile struct mc32_mailbox *exec_box;
@@ -1093,24 +1092,24 @@ static void mc32_update_stats(struct net_device *dev)
 
        u32 rx_errors=0;
 
-       rx_errors+=lp->net_stats.rx_crc_errors   +=st->rx_crc_errors;
+       rx_errors+=dev->stats.rx_crc_errors   +=st->rx_crc_errors;
                                                   st->rx_crc_errors=0;
-       rx_errors+=lp->net_stats.rx_fifo_errors  +=st->rx_overrun_errors;
+       rx_errors+=dev->stats.rx_fifo_errors  +=st->rx_overrun_errors;
                                                   st->rx_overrun_errors=0;
-       rx_errors+=lp->net_stats.rx_frame_errors +=st->rx_alignment_errors;
+       rx_errors+=dev->stats.rx_frame_errors +=st->rx_alignment_errors;
                                                   st->rx_alignment_errors=0;
-       rx_errors+=lp->net_stats.rx_length_errors+=st->rx_tooshort_errors;
+       rx_errors+=dev->stats.rx_length_errors+=st->rx_tooshort_errors;
                                                   st->rx_tooshort_errors=0;
-       rx_errors+=lp->net_stats.rx_missed_errors+=st->rx_outofresource_errors;
+       rx_errors+=dev->stats.rx_missed_errors+=st->rx_outofresource_errors;
                                                   st->rx_outofresource_errors=0;
-        lp->net_stats.rx_errors=rx_errors;
+        dev->stats.rx_errors=rx_errors;
 
        /* Number of packets which saw one collision */
-       lp->net_stats.collisions+=st->dataC[10];
+       dev->stats.collisions+=st->dataC[10];
        st->dataC[10]=0;
 
        /* Number of packets which saw 2--15 collisions */
-       lp->net_stats.collisions+=st->dataC[11];
+       dev->stats.collisions+=st->dataC[11];
        st->dataC[11]=0;
 }
 
@@ -1178,7 +1177,7 @@ static void mc32_rx_ring(struct net_device *dev)
                                skb=dev_alloc_skb(length+2);
 
                                if(skb==NULL) {
-                                       lp->net_stats.rx_dropped++;
+                                       dev->stats.rx_dropped++;
                                        goto dropped;
                                }
 
@@ -1189,8 +1188,8 @@ static void mc32_rx_ring(struct net_device *dev)
 
                        skb->protocol=eth_type_trans(skb,dev);
                        dev->last_rx = jiffies;
-                       lp->net_stats.rx_packets++;
-                       lp->net_stats.rx_bytes += length;
+                       dev->stats.rx_packets++;
+                       dev->stats.rx_bytes += length;
                        netif_rx(skb);
                }
 
@@ -1253,34 +1252,34 @@ static void mc32_tx_ring(struct net_device *dev)
                        /* Not COMPLETED */
                        break;
                }
-               lp->net_stats.tx_packets++;
+               dev->stats.tx_packets++;
                if(!(np->status & (1<<6))) /* Not COMPLETED_OK */
                {
-                       lp->net_stats.tx_errors++;
+                       dev->stats.tx_errors++;
 
                        switch(np->status&0x0F)
                        {
                                case 1:
-                                       lp->net_stats.tx_aborted_errors++;
+                                       dev->stats.tx_aborted_errors++;
                                        break; /* Max collisions */
                                case 2:
-                                       lp->net_stats.tx_fifo_errors++;
+                                       dev->stats.tx_fifo_errors++;
                                        break;
                                case 3:
-                                       lp->net_stats.tx_carrier_errors++;
+                                       dev->stats.tx_carrier_errors++;
                                        break;
                                case 4:
-                                       lp->net_stats.tx_window_errors++;
+                                       dev->stats.tx_window_errors++;
                                        break;  /* CTS Lost */
                                case 5:
-                                       lp->net_stats.tx_aborted_errors++;
+                                       dev->stats.tx_aborted_errors++;
                                        break; /* Transmit timeout */
                        }
                }
                /* Packets are sent in order - this is
                    basically a FIFO queue of buffers matching
                    the card ring */
-               lp->net_stats.tx_bytes+=lp->tx_ring[t].skb->len;
+               dev->stats.tx_bytes+=lp->tx_ring[t].skb->len;
                dev_kfree_skb_irq(lp->tx_ring[t].skb);
                lp->tx_ring[t].skb=NULL;
                atomic_inc(&lp->tx_count);
@@ -1367,7 +1366,7 @@ static irqreturn_t mc32_interrupt(int irq, void *dev_id)
                        case 6:
                                /* Out of RX buffers stat */
                                /* Must restart rx */
-                               lp->net_stats.rx_dropped++;
+                               dev->stats.rx_dropped++;
                                mc32_rx_ring(dev);
                                mc32_start_transceiver(dev);
                                break;
@@ -1489,10 +1488,8 @@ static int mc32_close(struct net_device *dev)
 
 static struct net_device_stats *mc32_get_stats(struct net_device *dev)
 {
-       struct mc32_local *lp = netdev_priv(dev);
-
        mc32_update_stats(dev);
-       return &lp->net_stats;
+       return &dev->stats;
 }
 
 
index a453eda834d52e3584755367169ada0ff22e4bc6..934db350e339c93d67433f6e79a238efd060651a 100644 (file)
@@ -340,7 +340,6 @@ struct cp_private {
        u32                     rx_config;
        u16                     cpcmd;
 
-       struct net_device_stats net_stats;
        struct cp_extra_stats   cp_stats;
 
        unsigned                rx_head         ____cacheline_aligned;
@@ -457,8 +456,8 @@ static inline void cp_rx_skb (struct cp_private *cp, struct sk_buff *skb,
 {
        skb->protocol = eth_type_trans (skb, cp->dev);
 
-       cp->net_stats.rx_packets++;
-       cp->net_stats.rx_bytes += skb->len;
+       cp->dev->stats.rx_packets++;
+       cp->dev->stats.rx_bytes += skb->len;
        cp->dev->last_rx = jiffies;
 
 #if CP_VLAN_TAG_USED
@@ -477,17 +476,17 @@ static void cp_rx_err_acct (struct cp_private *cp, unsigned rx_tail,
                printk (KERN_DEBUG
                        "%s: rx err, slot %d status 0x%x len %d\n",
                        cp->dev->name, rx_tail, status, len);
-       cp->net_stats.rx_errors++;
+       cp->dev->stats.rx_errors++;
        if (status & RxErrFrame)
-               cp->net_stats.rx_frame_errors++;
+               cp->dev->stats.rx_frame_errors++;
        if (status & RxErrCRC)
-               cp->net_stats.rx_crc_errors++;
+               cp->dev->stats.rx_crc_errors++;
        if ((status & RxErrRunt) || (status & RxErrLong))
-               cp->net_stats.rx_length_errors++;
+               cp->dev->stats.rx_length_errors++;
        if ((status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag))
-               cp->net_stats.rx_length_errors++;
+               cp->dev->stats.rx_length_errors++;
        if (status & RxErrFIFO)
-               cp->net_stats.rx_fifo_errors++;
+               cp->dev->stats.rx_fifo_errors++;
 }
 
 static inline unsigned int cp_rx_csum_ok (u32 status)
@@ -539,7 +538,7 @@ rx_status_loop:
                         * that RX fragments are never encountered
                         */
                        cp_rx_err_acct(cp, rx_tail, status, len);
-                       cp->net_stats.rx_dropped++;
+                       dev->stats.rx_dropped++;
                        cp->cp_stats.rx_frags++;
                        goto rx_next;
                }
@@ -556,7 +555,7 @@ rx_status_loop:
                buflen = cp->rx_buf_sz + RX_OFFSET;
                new_skb = dev_alloc_skb (buflen);
                if (!new_skb) {
-                       cp->net_stats.rx_dropped++;
+                       dev->stats.rx_dropped++;
                        goto rx_next;
                }
 
@@ -710,20 +709,20 @@ static void cp_tx (struct cp_private *cp)
                                if (netif_msg_tx_err(cp))
                                        printk(KERN_DEBUG "%s: tx err, status 0x%x\n",
                                               cp->dev->name, status);
-                               cp->net_stats.tx_errors++;
+                               cp->dev->stats.tx_errors++;
                                if (status & TxOWC)
-                                       cp->net_stats.tx_window_errors++;
+                                       cp->dev->stats.tx_window_errors++;
                                if (status & TxMaxCol)
-                                       cp->net_stats.tx_aborted_errors++;
+                                       cp->dev->stats.tx_aborted_errors++;
                                if (status & TxLinkFail)
-                                       cp->net_stats.tx_carrier_errors++;
+                                       cp->dev->stats.tx_carrier_errors++;
                                if (status & TxFIFOUnder)
-                                       cp->net_stats.tx_fifo_errors++;
+                                       cp->dev->stats.tx_fifo_errors++;
                        } else {
-                               cp->net_stats.collisions +=
+                               cp->dev->stats.collisions +=
                                        ((status >> TxColCntShift) & TxColCntMask);
-                               cp->net_stats.tx_packets++;
-                               cp->net_stats.tx_bytes += skb->len;
+                               cp->dev->stats.tx_packets++;
+                               cp->dev->stats.tx_bytes += skb->len;
                                if (netif_msg_tx_done(cp))
                                        printk(KERN_DEBUG "%s: tx done, slot %d\n", cp->dev->name, tx_tail);
                        }
@@ -956,7 +955,7 @@ static void cp_set_rx_mode (struct net_device *dev)
 static void __cp_get_stats(struct cp_private *cp)
 {
        /* only lower 24 bits valid; write any value to clear */
-       cp->net_stats.rx_missed_errors += (cpr32 (RxMissed) & 0xffffff);
+       cp->dev->stats.rx_missed_errors += (cpr32 (RxMissed) & 0xffffff);
        cpw32 (RxMissed, 0);
 }
 
@@ -971,7 +970,7 @@ static struct net_device_stats *cp_get_stats(struct net_device *dev)
                __cp_get_stats(cp);
        spin_unlock_irqrestore(&cp->lock, flags);
 
-       return &cp->net_stats;
+       return &dev->stats;
 }
 
 static void cp_stop_hw (struct cp_private *cp)
@@ -1142,7 +1141,7 @@ static void cp_clean_rings (struct cp_private *cp)
                                         PCI_DMA_TODEVICE);
                        if (le32_to_cpu(desc->opts1) & LastFrag)
                                dev_kfree_skb(skb);
-                       cp->net_stats.tx_dropped++;
+                       cp->dev->stats.tx_dropped++;
                }
        }
 
index 53bd903d2321c770cf9ad18dca6559712f86e51c..b23a00c5b84fed9de0362209b9a3f68f22c9c2e8 100644 (file)
@@ -574,7 +574,6 @@ struct rtl8139_private {
        u32                     msg_enable;
        struct napi_struct      napi;
        struct net_device       *dev;
-       struct net_device_stats stats;
 
        unsigned char           *rx_ring;
        unsigned int            cur_rx; /* RX buf index of next pkt */
@@ -1711,7 +1710,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
                dev_kfree_skb(skb);
        } else {
                dev_kfree_skb(skb);
-               tp->stats.tx_dropped++;
+               dev->stats.tx_dropped++;
                return 0;
        }
 
@@ -1762,27 +1761,27 @@ static void rtl8139_tx_interrupt (struct net_device *dev,
                        if (netif_msg_tx_err(tp))
                                printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
                                        dev->name, txstatus);
-                       tp->stats.tx_errors++;
+                       dev->stats.tx_errors++;
                        if (txstatus & TxAborted) {
-                               tp->stats.tx_aborted_errors++;
+                               dev->stats.tx_aborted_errors++;
                                RTL_W32 (TxConfig, TxClearAbt);
                                RTL_W16 (IntrStatus, TxErr);
                                wmb();
                        }
                        if (txstatus & TxCarrierLost)
-                               tp->stats.tx_carrier_errors++;
+                               dev->stats.tx_carrier_errors++;
                        if (txstatus & TxOutOfWindow)
-                               tp->stats.tx_window_errors++;
+                               dev->stats.tx_window_errors++;
                } else {
                        if (txstatus & TxUnderrun) {
                                /* Add 64 to the Tx FIFO threshold. */
                                if (tp->tx_flag < 0x00300000)
                                        tp->tx_flag += 0x00020000;
-                               tp->stats.tx_fifo_errors++;
+                               dev->stats.tx_fifo_errors++;
                        }
-                       tp->stats.collisions += (txstatus >> 24) & 15;
-                       tp->stats.tx_bytes += txstatus & 0x7ff;
-                       tp->stats.tx_packets++;
+                       dev->stats.collisions += (txstatus >> 24) & 15;
+                       dev->stats.tx_bytes += txstatus & 0x7ff;
+                       dev->stats.tx_packets++;
                }
 
                dirty_tx++;
@@ -1818,7 +1817,7 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev,
        if (netif_msg_rx_err (tp))
                printk(KERN_DEBUG "%s: Ethernet frame had errors, status %8.8x.\n",
                        dev->name, rx_status);
-       tp->stats.rx_errors++;
+       dev->stats.rx_errors++;
        if (!(rx_status & RxStatusOK)) {
                if (rx_status & RxTooLong) {
                        DPRINTK ("%s: Oversized Ethernet frame, status %4.4x!\n",
@@ -1826,11 +1825,11 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev,
                        /* A.C.: The chip hangs here. */
                }
                if (rx_status & (RxBadSymbol | RxBadAlign))
-                       tp->stats.rx_frame_errors++;
+                       dev->stats.rx_frame_errors++;
                if (rx_status & (RxRunt | RxTooLong))
-                       tp->stats.rx_length_errors++;
+                       dev->stats.rx_length_errors++;
                if (rx_status & RxCRCErr)
-                       tp->stats.rx_crc_errors++;
+                       dev->stats.rx_crc_errors++;
        } else {
                tp->xstats.rx_lost_in_ring++;
        }
@@ -1913,9 +1912,9 @@ static void rtl8139_isr_ack(struct rtl8139_private *tp)
        /* Clear out errors and receive interrupts */
        if (likely(status != 0)) {
                if (unlikely(status & (RxFIFOOver | RxOverflow))) {
-                       tp->stats.rx_errors++;
+                       tp->dev->stats.rx_errors++;
                        if (status & RxFIFOOver)
-                               tp->stats.rx_fifo_errors++;
+                               tp->dev->stats.rx_fifo_errors++;
                }
                RTL_W16_F (IntrStatus, RxAckBits);
        }
@@ -2016,8 +2015,8 @@ no_early_rx:
                        skb->protocol = eth_type_trans (skb, dev);
 
                        dev->last_rx = jiffies;
-                       tp->stats.rx_bytes += pkt_size;
-                       tp->stats.rx_packets++;
+                       dev->stats.rx_bytes += pkt_size;
+                       dev->stats.rx_packets++;
 
                        netif_receive_skb (skb);
                } else {
@@ -2025,7 +2024,7 @@ no_early_rx:
                                printk (KERN_WARNING
                                        "%s: Memory squeeze, dropping packet.\n",
                                        dev->name);
-                       tp->stats.rx_dropped++;
+                       dev->stats.rx_dropped++;
                }
                received++;
 
@@ -2072,7 +2071,7 @@ static void rtl8139_weird_interrupt (struct net_device *dev,
        assert (ioaddr != NULL);
 
        /* Update the error count. */
-       tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+       dev->stats.rx_missed_errors += RTL_R32 (RxMissed);
        RTL_W32 (RxMissed, 0);
 
        if ((status & RxUnderrun) && link_changed &&
@@ -2082,12 +2081,12 @@ static void rtl8139_weird_interrupt (struct net_device *dev,
        }
 
        if (status & (RxUnderrun | RxErr))
-               tp->stats.rx_errors++;
+               dev->stats.rx_errors++;
 
        if (status & PCSTimeout)
-               tp->stats.rx_length_errors++;
+               dev->stats.rx_length_errors++;
        if (status & RxUnderrun)
-               tp->stats.rx_fifo_errors++;
+               dev->stats.rx_fifo_errors++;
        if (status & PCIErr) {
                u16 pci_cmd_status;
                pci_read_config_word (tp->pci_dev, PCI_STATUS, &pci_cmd_status);
@@ -2227,7 +2226,7 @@ static int rtl8139_close (struct net_device *dev)
        RTL_W16 (IntrMask, 0);
 
        /* Update the error counts. */
-       tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+       dev->stats.rx_missed_errors += RTL_R32 (RxMissed);
        RTL_W32 (RxMissed, 0);
 
        spin_unlock_irqrestore (&tp->lock, flags);
@@ -2472,12 +2471,12 @@ static struct net_device_stats *rtl8139_get_stats (struct net_device *dev)
 
        if (netif_running(dev)) {
                spin_lock_irqsave (&tp->lock, flags);
-               tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+               dev->stats.rx_missed_errors += RTL_R32 (RxMissed);
                RTL_W32 (RxMissed, 0);
                spin_unlock_irqrestore (&tp->lock, flags);
        }
 
-       return &tp->stats;
+       return &dev->stats;
 }
 
 /* Set or clear the multicast filter for this adaptor.
@@ -2561,7 +2560,7 @@ static int rtl8139_suspend (struct pci_dev *pdev, pm_message_t state)
        RTL_W8 (ChipCmd, 0);
 
        /* Update the error counts. */
-       tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
+       dev->stats.rx_missed_errors += RTL_R32 (RxMissed);
        RTL_W32 (RxMissed, 0);
 
        spin_unlock_irqrestore (&tp->lock, flags);
index 04ddec0f4c61a4ed98d8f37d49df59daf8c7ee42..cf020d45aea645878c3b16a7891c536a2d21dfa7 100644 (file)
@@ -69,7 +69,6 @@ struct ei_device {
        unsigned char reg0;             /* Register '0' in a WD8013 */
        unsigned char reg5;             /* Register '5' in a WD8013 */
        unsigned char saved_irq;        /* Original dev->irq value. */
-       struct net_device_stats stat;   /* The new statistics table. */
        u32 *reg_offset;                /* Register mapping table */
        spinlock_t page_lock;           /* Page register locks */
        unsigned long priv;             /* Private field to store bus IDs etc. */
index dd0ec9ebc939a92d0bb4fadaba75648b95297359..c537f53ffcb9c6714594213ba1de96565d9a5dcf 100644 (file)
@@ -1670,7 +1670,7 @@ config SUNDANCE_MMIO
 
 config TLAN
        tristate "TI ThunderLAN support"
-       depends on NET_PCI && (PCI || EISA) && !64BIT
+       depends on NET_PCI && (PCI || EISA)
        ---help---
          If you have a PCI Ethernet network card based on the ThunderLAN chip
          which is supported by this driver, say Y and read the
@@ -2228,6 +2228,7 @@ config VIA_VELOCITY
 config TIGON3
        tristate "Broadcom Tigon3 support"
        depends on PCI
+       select PHYLIB
        help
          This driver supports Broadcom Tigon3 based gigabit Ethernet cards.
 
@@ -2283,6 +2284,19 @@ config GELIC_WIRELESS
          the driver automatically distinguishes the models, you can
          safely enable this option even if you have a wireless-less model.
 
+config GELIC_WIRELESS_OLD_PSK_INTERFACE
+       bool "PS3 Wireless private PSK interface (OBSOLETE)"
+       depends on GELIC_WIRELESS
+       help
+          This option retains the obsolete private interface to pass
+          the PSK from user space programs to the driver.  The PSK
+          stands for 'Pre Shared Key' and is used for WPA[2]-PSK
+          (WPA-Personal) environment.
+          If WPA[2]-PSK is used and you need to use old programs that
+          support only this old interface, say Y.  Otherwise N.
+
+          If unsure, say N.
+
 config GIANFAR
        tristate "Gianfar Ethernet"
        depends on FSL_SOC
@@ -2407,8 +2421,9 @@ config CHELSIO_T1_NAPI
 
 config CHELSIO_T3
        tristate "Chelsio Communications T3 10Gb Ethernet support"
-       depends on PCI
+       depends on PCI && INET
        select FW_LOADER
+       select INET_LRO
        help
          This driver supports Chelsio T3-based gigabit and 10Gb Ethernet
          adapters.
index 6c192650d34943451317142cdf8300052c8a43c2..e4483de84e7f5558cf0e62e7ae40eef16dd68796 100644 (file)
@@ -1457,11 +1457,6 @@ static int __devinit ace_init(struct net_device *dev)
        ace_set_txprd(regs, ap, 0);
        writel(0, &regs->RxRetCsm);
 
-       /*
-        * Zero the stats before starting the interface
-        */
-       memset(&ap->stats, 0, sizeof(ap->stats));
-
        /*
        * Enable DMA engine now.
        * If we do this sooner, Mckinley box pukes.
@@ -2041,8 +2036,8 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
                        netif_rx(skb);
 
                dev->last_rx = jiffies;
-               ap->stats.rx_packets++;
-               ap->stats.rx_bytes += retdesc->size;
+               dev->stats.rx_packets++;
+               dev->stats.rx_bytes += retdesc->size;
 
                idx = (idx + 1) % RX_RETURN_RING_ENTRIES;
        }
@@ -2090,8 +2085,8 @@ static inline void ace_tx_int(struct net_device *dev,
                }
 
                if (skb) {
-                       ap->stats.tx_packets++;
-                       ap->stats.tx_bytes += skb->len;
+                       dev->stats.tx_packets++;
+                       dev->stats.tx_bytes += skb->len;
                        dev_kfree_skb_irq(skb);
                        info->skb = NULL;
                }
@@ -2863,11 +2858,11 @@ static struct net_device_stats *ace_get_stats(struct net_device *dev)
        struct ace_mac_stats __iomem *mac_stats =
                (struct ace_mac_stats __iomem *)ap->regs->Stats;
 
-       ap->stats.rx_missed_errors = readl(&mac_stats->drop_space);
-       ap->stats.multicast = readl(&mac_stats->kept_mc);
-       ap->stats.collisions = readl(&mac_stats->coll);
+       dev->stats.rx_missed_errors = readl(&mac_stats->drop_space);
+       dev->stats.multicast = readl(&mac_stats->kept_mc);
+       dev->stats.collisions = readl(&mac_stats->coll);
 
-       return &ap->stats;
+       return &dev->stats;
 }
 
 
index 60ed1837fa8fd8435da2efa09c2c5c63dd619d28..4487f32759a4829d023225912bbe29abafc38fec 100644 (file)
@@ -693,7 +693,6 @@ struct ace_private
                                __attribute__ ((aligned (SMP_CACHE_BYTES)));
        u32                     last_tx, last_std_rx, last_mini_rx;
 #endif
-       struct net_device_stats stats;
        int                     pci_using_dac;
 };
 
index 6ddc911e7d159730e26c3dd79c916d5395c93d9d..32dc391e63ccaadb53017ddcda76582d96b3c792 100644 (file)
@@ -1876,7 +1876,8 @@ static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter)
 
                rfd_desc = ATL1_RFD_DESC(rfd_ring, rfd_next_to_use);
 
-               skb = dev_alloc_skb(adapter->rx_buffer_len + NET_IP_ALIGN);
+               skb = netdev_alloc_skb(adapter->netdev,
+                                      adapter->rx_buffer_len + NET_IP_ALIGN);
                if (unlikely(!skb)) {
                        /* Better luck next round */
                        adapter->net_stats.rx_dropped++;
index 4b46e68183e059fbddb9eb6c007fcab7894e68b2..b32d22762b9bc9dfe603e83b366c9e0a273bc25e 100644 (file)
@@ -56,8 +56,8 @@
 
 #define DRV_MODULE_NAME                "bnx2"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "1.7.5"
-#define DRV_MODULE_RELDATE     "April 29, 2008"
+#define DRV_MODULE_VERSION     "1.7.6"
+#define DRV_MODULE_RELDATE     "May 16, 2008"
 
 #define RUN_AT(x) (jiffies + (x))
 
@@ -1875,7 +1875,7 @@ bnx2_setup_phy(struct bnx2 *bp, u8 port)
 }
 
 static int
-bnx2_init_5709s_phy(struct bnx2 *bp)
+bnx2_init_5709s_phy(struct bnx2 *bp, int reset_phy)
 {
        u32 val;
 
@@ -1890,7 +1890,8 @@ bnx2_init_5709s_phy(struct bnx2 *bp)
        bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD);
 
        bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
-       bnx2_reset_phy(bp);
+       if (reset_phy)
+               bnx2_reset_phy(bp);
 
        bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG);
 
@@ -1924,11 +1925,12 @@ bnx2_init_5709s_phy(struct bnx2 *bp)
 }
 
 static int
-bnx2_init_5708s_phy(struct bnx2 *bp)
+bnx2_init_5708s_phy(struct bnx2 *bp, int reset_phy)
 {
        u32 val;
 
-       bnx2_reset_phy(bp);
+       if (reset_phy)
+               bnx2_reset_phy(bp);
 
        bp->mii_up1 = BCM5708S_UP1;
 
@@ -1981,9 +1983,10 @@ bnx2_init_5708s_phy(struct bnx2 *bp)
 }
 
 static int
-bnx2_init_5706s_phy(struct bnx2 *bp)
+bnx2_init_5706s_phy(struct bnx2 *bp, int reset_phy)
 {
-       bnx2_reset_phy(bp);
+       if (reset_phy)
+               bnx2_reset_phy(bp);
 
        bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
 
@@ -2018,11 +2021,12 @@ bnx2_init_5706s_phy(struct bnx2 *bp)
 }
 
 static int
-bnx2_init_copper_phy(struct bnx2 *bp)
+bnx2_init_copper_phy(struct bnx2 *bp, int reset_phy)
 {
        u32 val;
 
-       bnx2_reset_phy(bp);
+       if (reset_phy)
+               bnx2_reset_phy(bp);
 
        if (bp->phy_flags & BNX2_PHY_FLAG_CRC_FIX) {
                bnx2_write_phy(bp, 0x18, 0x0c00);
@@ -2070,7 +2074,7 @@ bnx2_init_copper_phy(struct bnx2 *bp)
 
 
 static int
-bnx2_init_phy(struct bnx2 *bp)
+bnx2_init_phy(struct bnx2 *bp, int reset_phy)
 {
        u32 val;
        int rc = 0;
@@ -2096,14 +2100,14 @@ bnx2_init_phy(struct bnx2 *bp)
 
        if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
                if (CHIP_NUM(bp) == CHIP_NUM_5706)
-                       rc = bnx2_init_5706s_phy(bp);
+                       rc = bnx2_init_5706s_phy(bp, reset_phy);
                else if (CHIP_NUM(bp) == CHIP_NUM_5708)
-                       rc = bnx2_init_5708s_phy(bp);
+                       rc = bnx2_init_5708s_phy(bp, reset_phy);
                else if (CHIP_NUM(bp) == CHIP_NUM_5709)
-                       rc = bnx2_init_5709s_phy(bp);
+                       rc = bnx2_init_5709s_phy(bp, reset_phy);
        }
        else {
-               rc = bnx2_init_copper_phy(bp);
+               rc = bnx2_init_copper_phy(bp, reset_phy);
        }
 
 setup_phy:
@@ -2620,7 +2624,7 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb,
 
        pci_dma_sync_single_for_device(bp->pdev,
                pci_unmap_addr(cons_rx_buf, mapping),
-               bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
+               BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
 
        bnapi->rx_prod_bseq += bp->rx_buf_use_size;
 
@@ -2658,7 +2662,7 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb,
                return err;
        }
 
-       skb_reserve(skb, bp->rx_offset);
+       skb_reserve(skb, BNX2_RX_OFFSET);
        pci_unmap_single(bp->pdev, dma_addr, bp->rx_buf_use_size,
                         PCI_DMA_FROMDEVICE);
 
@@ -2773,7 +2777,8 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
                dma_addr = pci_unmap_addr(rx_buf, mapping);
 
                pci_dma_sync_single_for_cpu(bp->pdev, dma_addr,
-                       bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
+                       BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH,
+                       PCI_DMA_FROMDEVICE);
 
                rx_hdr = (struct l2_fhdr *) skb->data;
                len = rx_hdr->l2_fhdr_pkt_len;
@@ -2811,7 +2816,8 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
                        }
 
                        /* aligned copy */
-                       skb_copy_from_linear_data_offset(skb, bp->rx_offset - 2,
+                       skb_copy_from_linear_data_offset(skb,
+                                                        BNX2_RX_OFFSET - 2,
                                      new_skb->data, len + 2);
                        skb_reserve(new_skb, 2);
                        skb_put(new_skb, len);
@@ -3213,7 +3219,7 @@ load_rv2p_fw(struct bnx2 *bp, __le32 *rv2p_code, u32 rv2p_code_len,
 }
 
 static int
-load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
+load_cpu_fw(struct bnx2 *bp, const struct cpu_reg *cpu_reg, struct fw_info *fw)
 {
        u32 offset;
        u32 val;
@@ -3297,7 +3303,6 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
 static int
 bnx2_init_cpus(struct bnx2 *bp)
 {
-       struct cpu_reg cpu_reg;
        struct fw_info *fw;
        int rc, rv2p_len;
        void *text, *rv2p;
@@ -3333,122 +3338,57 @@ bnx2_init_cpus(struct bnx2 *bp)
        load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC2);
 
        /* Initialize the RX Processor. */
-       cpu_reg.mode = BNX2_RXP_CPU_MODE;
-       cpu_reg.mode_value_halt = BNX2_RXP_CPU_MODE_SOFT_HALT;
-       cpu_reg.mode_value_sstep = BNX2_RXP_CPU_MODE_STEP_ENA;
-       cpu_reg.state = BNX2_RXP_CPU_STATE;
-       cpu_reg.state_value_clear = 0xffffff;
-       cpu_reg.gpr0 = BNX2_RXP_CPU_REG_FILE;
-       cpu_reg.evmask = BNX2_RXP_CPU_EVENT_MASK;
-       cpu_reg.pc = BNX2_RXP_CPU_PROGRAM_COUNTER;
-       cpu_reg.inst = BNX2_RXP_CPU_INSTRUCTION;
-       cpu_reg.bp = BNX2_RXP_CPU_HW_BREAKPOINT;
-       cpu_reg.spad_base = BNX2_RXP_SCRATCH;
-       cpu_reg.mips_view_base = 0x8000000;
-
        if (CHIP_NUM(bp) == CHIP_NUM_5709)
                fw = &bnx2_rxp_fw_09;
        else
                fw = &bnx2_rxp_fw_06;
 
        fw->text = text;
-       rc = load_cpu_fw(bp, &cpu_reg, fw);
+       rc = load_cpu_fw(bp, &cpu_reg_rxp, fw);
        if (rc)
                goto init_cpu_err;
 
        /* Initialize the TX Processor. */
-       cpu_reg.mode = BNX2_TXP_CPU_MODE;
-       cpu_reg.mode_value_halt = BNX2_TXP_CPU_MODE_SOFT_HALT;
-       cpu_reg.mode_value_sstep = BNX2_TXP_CPU_MODE_STEP_ENA;
-       cpu_reg.state = BNX2_TXP_CPU_STATE;
-       cpu_reg.state_value_clear = 0xffffff;
-       cpu_reg.gpr0 = BNX2_TXP_CPU_REG_FILE;
-       cpu_reg.evmask = BNX2_TXP_CPU_EVENT_MASK;
-       cpu_reg.pc = BNX2_TXP_CPU_PROGRAM_COUNTER;
-       cpu_reg.inst = BNX2_TXP_CPU_INSTRUCTION;
-       cpu_reg.bp = BNX2_TXP_CPU_HW_BREAKPOINT;
-       cpu_reg.spad_base = BNX2_TXP_SCRATCH;
-       cpu_reg.mips_view_base = 0x8000000;
-
        if (CHIP_NUM(bp) == CHIP_NUM_5709)
                fw = &bnx2_txp_fw_09;
        else
                fw = &bnx2_txp_fw_06;
 
        fw->text = text;
-       rc = load_cpu_fw(bp, &cpu_reg, fw);
+       rc = load_cpu_fw(bp, &cpu_reg_txp, fw);
        if (rc)
                goto init_cpu_err;
 
        /* Initialize the TX Patch-up Processor. */
-       cpu_reg.mode = BNX2_TPAT_CPU_MODE;
-       cpu_reg.mode_value_halt = BNX2_TPAT_CPU_MODE_SOFT_HALT;
-       cpu_reg.mode_value_sstep = BNX2_TPAT_CPU_MODE_STEP_ENA;
-       cpu_reg.state = BNX2_TPAT_CPU_STATE;
-       cpu_reg.state_value_clear = 0xffffff;
-       cpu_reg.gpr0 = BNX2_TPAT_CPU_REG_FILE;
-       cpu_reg.evmask = BNX2_TPAT_CPU_EVENT_MASK;
-       cpu_reg.pc = BNX2_TPAT_CPU_PROGRAM_COUNTER;
-       cpu_reg.inst = BNX2_TPAT_CPU_INSTRUCTION;
-       cpu_reg.bp = BNX2_TPAT_CPU_HW_BREAKPOINT;
-       cpu_reg.spad_base = BNX2_TPAT_SCRATCH;
-       cpu_reg.mips_view_base = 0x8000000;
-
        if (CHIP_NUM(bp) == CHIP_NUM_5709)
                fw = &bnx2_tpat_fw_09;
        else
                fw = &bnx2_tpat_fw_06;
 
        fw->text = text;
-       rc = load_cpu_fw(bp, &cpu_reg, fw);
+       rc = load_cpu_fw(bp, &cpu_reg_tpat, fw);
        if (rc)
                goto init_cpu_err;
 
        /* Initialize the Completion Processor. */
-       cpu_reg.mode = BNX2_COM_CPU_MODE;
-       cpu_reg.mode_value_halt = BNX2_COM_CPU_MODE_SOFT_HALT;
-       cpu_reg.mode_value_sstep = BNX2_COM_CPU_MODE_STEP_ENA;
-       cpu_reg.state = BNX2_COM_CPU_STATE;
-       cpu_reg.state_value_clear = 0xffffff;
-       cpu_reg.gpr0 = BNX2_COM_CPU_REG_FILE;
-       cpu_reg.evmask = BNX2_COM_CPU_EVENT_MASK;
-       cpu_reg.pc = BNX2_COM_CPU_PROGRAM_COUNTER;
-       cpu_reg.inst = BNX2_COM_CPU_INSTRUCTION;
-       cpu_reg.bp = BNX2_COM_CPU_HW_BREAKPOINT;
-       cpu_reg.spad_base = BNX2_COM_SCRATCH;
-       cpu_reg.mips_view_base = 0x8000000;
-
        if (CHIP_NUM(bp) == CHIP_NUM_5709)
                fw = &bnx2_com_fw_09;
        else
                fw = &bnx2_com_fw_06;
 
        fw->text = text;
-       rc = load_cpu_fw(bp, &cpu_reg, fw);
+       rc = load_cpu_fw(bp, &cpu_reg_com, fw);
        if (rc)
                goto init_cpu_err;
 
        /* Initialize the Command Processor. */
-       cpu_reg.mode = BNX2_CP_CPU_MODE;
-       cpu_reg.mode_value_halt = BNX2_CP_CPU_MODE_SOFT_HALT;
-       cpu_reg.mode_value_sstep = BNX2_CP_CPU_MODE_STEP_ENA;
-       cpu_reg.state = BNX2_CP_CPU_STATE;
-       cpu_reg.state_value_clear = 0xffffff;
-       cpu_reg.gpr0 = BNX2_CP_CPU_REG_FILE;
-       cpu_reg.evmask = BNX2_CP_CPU_EVENT_MASK;
-       cpu_reg.pc = BNX2_CP_CPU_PROGRAM_COUNTER;
-       cpu_reg.inst = BNX2_CP_CPU_INSTRUCTION;
-       cpu_reg.bp = BNX2_CP_CPU_HW_BREAKPOINT;
-       cpu_reg.spad_base = BNX2_CP_SCRATCH;
-       cpu_reg.mips_view_base = 0x8000000;
-
        if (CHIP_NUM(bp) == CHIP_NUM_5709)
                fw = &bnx2_cp_fw_09;
        else
                fw = &bnx2_cp_fw_06;
 
        fw->text = text;
-       rc = load_cpu_fw(bp, &cpu_reg, fw);
+       rc = load_cpu_fw(bp, &cpu_reg_cp, fw);
 
 init_cpu_err:
        vfree(text);
@@ -4750,12 +4690,12 @@ bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
        u32 rx_size, rx_space, jumbo_size;
 
        /* 8 for CRC and VLAN */
-       rx_size = bp->dev->mtu + ETH_HLEN + bp->rx_offset + 8;
+       rx_size = bp->dev->mtu + ETH_HLEN + BNX2_RX_OFFSET + 8;
 
        rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD +
                sizeof(struct skb_shared_info);
 
-       bp->rx_copy_thresh = RX_COPY_THRESH;
+       bp->rx_copy_thresh = BNX2_RX_COPY_THRESH;
        bp->rx_pg_ring_size = 0;
        bp->rx_max_pg_ring = 0;
        bp->rx_max_pg_ring_idx = 0;
@@ -4770,14 +4710,14 @@ bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
                bp->rx_max_pg_ring = bnx2_find_max_ring(jumbo_size,
                                                        MAX_RX_PG_RINGS);
                bp->rx_max_pg_ring_idx = (bp->rx_max_pg_ring * RX_DESC_CNT) - 1;
-               rx_size = RX_COPY_THRESH + bp->rx_offset;
+               rx_size = BNX2_RX_COPY_THRESH + BNX2_RX_OFFSET;
                bp->rx_copy_thresh = 0;
        }
 
        bp->rx_buf_use_size = rx_size;
        /* hw alignment */
        bp->rx_buf_size = bp->rx_buf_use_size + BNX2_RX_ALIGN;
-       bp->rx_jumbo_thresh = rx_size - bp->rx_offset;
+       bp->rx_jumbo_thresh = rx_size - BNX2_RX_OFFSET;
        bp->rx_ring_size = size;
        bp->rx_max_ring = bnx2_find_max_ring(size, MAX_RX_RINGS);
        bp->rx_max_ring_idx = (bp->rx_max_ring * RX_DESC_CNT) - 1;
@@ -4873,7 +4813,7 @@ bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
 }
 
 static int
-bnx2_init_nic(struct bnx2 *bp)
+bnx2_init_nic(struct bnx2 *bp, int reset_phy)
 {
        int rc;
 
@@ -4881,7 +4821,7 @@ bnx2_init_nic(struct bnx2 *bp)
                return rc;
 
        spin_lock_bh(&bp->phy_lock);
-       bnx2_init_phy(bp);
+       bnx2_init_phy(bp, reset_phy);
        bnx2_set_link(bp);
        if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
                bnx2_remote_phy_event(bp);
@@ -5221,7 +5161,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
        rx_skb = rx_buf->skb;
 
        rx_hdr = (struct l2_fhdr *) rx_skb->data;
-       skb_reserve(rx_skb, bp->rx_offset);
+       skb_reserve(rx_skb, BNX2_RX_OFFSET);
 
        pci_dma_sync_single_for_cpu(bp->pdev,
                pci_unmap_addr(rx_buf, mapping),
@@ -5269,7 +5209,7 @@ bnx2_test_loopback(struct bnx2 *bp)
 
        bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
        spin_lock_bh(&bp->phy_lock);
-       bnx2_init_phy(bp);
+       bnx2_init_phy(bp, 1);
        spin_unlock_bh(&bp->phy_lock);
        if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK))
                rc |= BNX2_MAC_LOOPBACK_FAILED;
@@ -5659,7 +5599,7 @@ bnx2_open(struct net_device *dev)
                return rc;
        }
 
-       rc = bnx2_init_nic(bp);
+       rc = bnx2_init_nic(bp, 1);
 
        if (rc) {
                bnx2_napi_disable(bp);
@@ -5691,7 +5631,7 @@ bnx2_open(struct net_device *dev)
 
                        bnx2_setup_int_mode(bp, 1);
 
-                       rc = bnx2_init_nic(bp);
+                       rc = bnx2_init_nic(bp, 0);
 
                        if (!rc)
                                rc = bnx2_request_irq(bp);
@@ -5727,7 +5667,7 @@ bnx2_reset_task(struct work_struct *work)
        bp->in_reset_task = 1;
        bnx2_netif_stop(bp);
 
-       bnx2_init_nic(bp);
+       bnx2_init_nic(bp, 1);
 
        atomic_set(&bp->intr_sem, 1);
        bnx2_netif_start(bp);
@@ -6421,7 +6361,7 @@ bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
 
        if (netif_running(bp->dev)) {
                bnx2_netif_stop(bp);
-               bnx2_init_nic(bp);
+               bnx2_init_nic(bp, 0);
                bnx2_netif_start(bp);
        }
 
@@ -6464,7 +6404,7 @@ bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx)
                rc = bnx2_alloc_mem(bp);
                if (rc)
                        return rc;
-               bnx2_init_nic(bp);
+               bnx2_init_nic(bp, 0);
                bnx2_netif_start(bp);
        }
        return 0;
@@ -6732,7 +6672,7 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
                        bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
                }
                else {
-                       bnx2_init_nic(bp);
+                       bnx2_init_nic(bp, 1);
                        bnx2_netif_start(bp);
                }
 
@@ -7115,6 +7055,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        }
 
        pci_set_master(pdev);
+       pci_save_state(pdev);
 
        bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
        if (bp->pm_cap == 0) {
@@ -7301,8 +7242,6 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        bp->mac_addr[4] = (u8) (reg >> 8);
        bp->mac_addr[5] = (u8) reg;
 
-       bp->rx_offset = sizeof(struct l2_fhdr) + 2;
-
        bp->tx_ring_size = MAX_TX_DESC_CNT;
        bnx2_set_rx_ring_size(bp, 255);
 
@@ -7619,11 +7558,97 @@ bnx2_resume(struct pci_dev *pdev)
 
        bnx2_set_power_state(bp, PCI_D0);
        netif_device_attach(dev);
-       bnx2_init_nic(bp);
+       bnx2_init_nic(bp, 1);
        bnx2_netif_start(bp);
        return 0;
 }
 
+/**
+ * bnx2_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci connection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t bnx2_io_error_detected(struct pci_dev *pdev,
+                                              pci_channel_state_t state)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct bnx2 *bp = netdev_priv(dev);
+
+       rtnl_lock();
+       netif_device_detach(dev);
+
+       if (netif_running(dev)) {
+               bnx2_netif_stop(bp);
+               del_timer_sync(&bp->timer);
+               bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
+       }
+
+       pci_disable_device(pdev);
+       rtnl_unlock();
+
+       /* Request a slot slot reset. */
+       return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * bnx2_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot.
+ */
+static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct bnx2 *bp = netdev_priv(dev);
+
+       rtnl_lock();
+       if (pci_enable_device(pdev)) {
+               dev_err(&pdev->dev,
+                       "Cannot re-enable PCI device after reset.\n");
+               rtnl_unlock();
+               return PCI_ERS_RESULT_DISCONNECT;
+       }
+       pci_set_master(pdev);
+       pci_restore_state(pdev);
+
+       if (netif_running(dev)) {
+               bnx2_set_power_state(bp, PCI_D0);
+               bnx2_init_nic(bp, 1);
+       }
+
+       rtnl_unlock();
+       return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * bnx2_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells us that
+ * its OK to resume normal operation.
+ */
+static void bnx2_io_resume(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct bnx2 *bp = netdev_priv(dev);
+
+       rtnl_lock();
+       if (netif_running(dev))
+               bnx2_netif_start(bp);
+
+       netif_device_attach(dev);
+       rtnl_unlock();
+}
+
+static struct pci_error_handlers bnx2_err_handler = {
+       .error_detected = bnx2_io_error_detected,
+       .slot_reset     = bnx2_io_slot_reset,
+       .resume         = bnx2_io_resume,
+};
+
 static struct pci_driver bnx2_pci_driver = {
        .name           = DRV_MODULE_NAME,
        .id_table       = bnx2_pci_tbl,
@@ -7631,6 +7656,7 @@ static struct pci_driver bnx2_pci_driver = {
        .remove         = __devexit_p(bnx2_remove_one),
        .suspend        = bnx2_suspend,
        .resume         = bnx2_resume,
+       .err_handler    = &bnx2_err_handler,
 };
 
 static int __init bnx2_init(void)
index 1eaf5bb3d9c2233f12b2861445af1a714cfa9625..16020a10bf42e79dfa0198f9ad4b37e222f4f423 100644 (file)
@@ -309,6 +309,7 @@ struct l2_fhdr {
 #endif
 };
 
+#define BNX2_RX_OFFSET         (sizeof(struct l2_fhdr) + 2)
 
 /*
  *  l2_context definition
@@ -6412,7 +6413,7 @@ struct l2_fhdr {
 #define MAX_ETHERNET_PACKET_SIZE       1514
 #define MAX_ETHERNET_JUMBO_PACKET_SIZE 9014
 
-#define RX_COPY_THRESH                 128
+#define BNX2_RX_COPY_THRESH            128
 
 #define BNX2_MISC_ENABLE_DEFAULT       0x17ffffff
 
@@ -6627,7 +6628,6 @@ struct bnx2 {
        struct                  vlan_group *vlgrp;
 #endif
 
-       u32                     rx_offset;
        u32                     rx_buf_use_size;        /* useable size */
        u32                     rx_buf_size;            /* with alignment */
        u32                     rx_copy_thresh;
index 3b839d4626fe8ab9132ba1cfd7a4b3b19762bfc9..e4b1de4355677877b6dc970fa940340730b102db 100644 (file)
@@ -886,6 +886,23 @@ static struct fw_info bnx2_com_fw_06 = {
        .rodata                         = bnx2_COM_b06FwRodata,
 };
 
+/* Initialized Values for the Completion Processor. */
+static const struct cpu_reg cpu_reg_com = {
+       .mode = BNX2_COM_CPU_MODE,
+       .mode_value_halt = BNX2_COM_CPU_MODE_SOFT_HALT,
+       .mode_value_sstep = BNX2_COM_CPU_MODE_STEP_ENA,
+       .state = BNX2_COM_CPU_STATE,
+       .state_value_clear = 0xffffff,
+       .gpr0 = BNX2_COM_CPU_REG_FILE,
+       .evmask = BNX2_COM_CPU_EVENT_MASK,
+       .pc = BNX2_COM_CPU_PROGRAM_COUNTER,
+       .inst = BNX2_COM_CPU_INSTRUCTION,
+       .bp = BNX2_COM_CPU_HW_BREAKPOINT,
+       .spad_base = BNX2_COM_SCRATCH,
+       .mips_view_base = 0x8000000,
+};
+
+
 static u8 bnx2_CP_b06FwText[] = {
        0x9d, 0xbc, 0x0d, 0x78, 0x13, 0xe7, 0x99, 0x2e, 0x7c, 0xcf, 0x48, 0xb2,
        0x65, 0x5b, 0xb6, 0xc7, 0xb6, 0x0c, 0x22, 0x65, 0x41, 0x83, 0x47, 0x20,
@@ -2167,6 +2184,22 @@ static struct fw_info bnx2_cp_fw_06 = {
        .rodata                         = bnx2_CP_b06FwRodata,
 };
 
+/* Initialized Values the Command Processor. */
+static const struct cpu_reg cpu_reg_cp = {
+       .mode = BNX2_CP_CPU_MODE,
+       .mode_value_halt = BNX2_CP_CPU_MODE_SOFT_HALT,
+       .mode_value_sstep = BNX2_CP_CPU_MODE_STEP_ENA,
+       .state = BNX2_CP_CPU_STATE,
+       .state_value_clear = 0xffffff,
+       .gpr0 = BNX2_CP_CPU_REG_FILE,
+       .evmask = BNX2_CP_CPU_EVENT_MASK,
+       .pc = BNX2_CP_CPU_PROGRAM_COUNTER,
+       .inst = BNX2_CP_CPU_INSTRUCTION,
+       .bp = BNX2_CP_CPU_HW_BREAKPOINT,
+       .spad_base = BNX2_CP_SCRATCH,
+       .mips_view_base = 0x8000000,
+};
+
 static u8 bnx2_RXP_b06FwText[] = {
        0xec, 0x5b, 0x5d, 0x70, 0x5c, 0xd7, 0x5d, 0xff, 0xdf, 0xb3, 0x2b, 0x69,
        0x2d, 0x4b, 0xf2, 0x95, 0xbc, 0x71, 0x56, 0xa9, 0x92, 0xec, 0x5a, 0x57,
@@ -2946,6 +2979,22 @@ static struct fw_info bnx2_rxp_fw_06 = {
        .rodata                         = bnx2_RXP_b06FwRodata,
 };
 
+/* Initialized Values for the RX Processor. */
+static const struct cpu_reg cpu_reg_rxp = {
+       .mode = BNX2_RXP_CPU_MODE,
+       .mode_value_halt = BNX2_RXP_CPU_MODE_SOFT_HALT,
+       .mode_value_sstep = BNX2_RXP_CPU_MODE_STEP_ENA,
+       .state = BNX2_RXP_CPU_STATE,
+       .state_value_clear = 0xffffff,
+       .gpr0 = BNX2_RXP_CPU_REG_FILE,
+       .evmask = BNX2_RXP_CPU_EVENT_MASK,
+       .pc = BNX2_RXP_CPU_PROGRAM_COUNTER,
+       .inst = BNX2_RXP_CPU_INSTRUCTION,
+       .bp = BNX2_RXP_CPU_HW_BREAKPOINT,
+       .spad_base = BNX2_RXP_SCRATCH,
+       .mips_view_base = 0x8000000,
+};
+
 static u8 bnx2_rv2p_proc1[] = {
        /* Date:        12/07/2007 15:02 */
        0xd5, 0x56, 0x41, 0x6b, 0x13, 0x51, 0x10, 0x9e, 0xdd, 0x6c, 0xbb, 0xdb,
@@ -3651,6 +3700,22 @@ static struct fw_info bnx2_tpat_fw_06 = {
        .rodata                         = bnx2_TPAT_b06FwRodata,
 };
 
+/* Initialized Values for the TX Patch-up Processor. */
+static const struct cpu_reg cpu_reg_tpat = {
+       .mode = BNX2_TPAT_CPU_MODE,
+       .mode_value_halt = BNX2_TPAT_CPU_MODE_SOFT_HALT,
+       .mode_value_sstep = BNX2_TPAT_CPU_MODE_STEP_ENA,
+       .state = BNX2_TPAT_CPU_STATE,
+       .state_value_clear = 0xffffff,
+       .gpr0 = BNX2_TPAT_CPU_REG_FILE,
+       .evmask = BNX2_TPAT_CPU_EVENT_MASK,
+       .pc = BNX2_TPAT_CPU_PROGRAM_COUNTER,
+       .inst = BNX2_TPAT_CPU_INSTRUCTION,
+       .bp = BNX2_TPAT_CPU_HW_BREAKPOINT,
+       .spad_base = BNX2_TPAT_SCRATCH,
+       .mips_view_base = 0x8000000,
+};
+
 static u8 bnx2_TXP_b06FwText[] = {
        0xad, 0x7b, 0x7f, 0x70, 0x9b, 0x75, 0x7a, 0xe7, 0xe7, 0xd5, 0x0f, 0x5b,
        0xb2, 0x65, 0x59, 0x0e, 0x4a, 0x90, 0x77, 0xbd, 0x8d, 0x5e, 0xf4, 0xca,
@@ -4531,3 +4596,18 @@ static struct fw_info bnx2_txp_fw_06 = {
        .rodata                         = bnx2_TXP_b06FwRodata,
 };
 
+/* Initialized Values for the TX Processor. */
+static const struct cpu_reg cpu_reg_txp = {
+       .mode = BNX2_TXP_CPU_MODE,
+       .mode_value_halt = BNX2_TXP_CPU_MODE_SOFT_HALT,
+       .mode_value_sstep = BNX2_TXP_CPU_MODE_STEP_ENA,
+       .state = BNX2_TXP_CPU_STATE,
+       .state_value_clear = 0xffffff,
+       .gpr0 = BNX2_TXP_CPU_REG_FILE,
+       .evmask = BNX2_TXP_CPU_EVENT_MASK,
+       .pc = BNX2_TXP_CPU_PROGRAM_COUNTER,
+       .inst = BNX2_TXP_CPU_INSTRUCTION,
+       .bp = BNX2_TXP_CPU_HW_BREAKPOINT,
+       .spad_base = BNX2_TXP_SCRATCH,
+       .mips_view_base = 0x8000000,
+};
index 50a40e4331542e63f711d4536ad936ce9a0fa009..5b4af3cc2a44231ecae682180abc0e3ac3d77ef2 100644 (file)
@@ -88,6 +88,7 @@
 #define BOND_LINK_ARP_INTERV   0
 
 static int max_bonds   = BOND_DEFAULT_MAX_BONDS;
+static int num_grat_arp = 1;
 static int miimon      = BOND_LINK_MON_INTERV;
 static int updelay     = 0;
 static int downdelay   = 0;
@@ -99,11 +100,13 @@ static char *xmit_hash_policy = NULL;
 static int arp_interval = BOND_LINK_ARP_INTERV;
 static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, };
 static char *arp_validate = NULL;
-static int fail_over_mac = 0;
+static char *fail_over_mac = NULL;
 struct bond_params bonding_defaults;
 
 module_param(max_bonds, int, 0);
 MODULE_PARM_DESC(max_bonds, "Max number of bonded devices");
+module_param(num_grat_arp, int, 0644);
+MODULE_PARM_DESC(num_grat_arp, "Number of gratuitous ARP packets to send on failover event");
 module_param(miimon, int, 0);
 MODULE_PARM_DESC(miimon, "Link check interval in milliseconds");
 module_param(updelay, int, 0);
@@ -133,8 +136,8 @@ module_param_array(arp_ip_target, charp, NULL, 0);
 MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form");
 module_param(arp_validate, charp, 0);
 MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all");
-module_param(fail_over_mac, int, 0);
-MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the same MAC.  0 of off (default), 1 for on.");
+module_param(fail_over_mac, charp, 0);
+MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the same MAC.  none (default), active or follow");
 
 /*----------------------------- Global variables ----------------------------*/
 
@@ -187,6 +190,13 @@ struct bond_parm_tbl arp_validate_tbl[] = {
 {      NULL,                   -1},
 };
 
+struct bond_parm_tbl fail_over_mac_tbl[] = {
+{      "none",                 BOND_FOM_NONE},
+{      "active",               BOND_FOM_ACTIVE},
+{      "follow",               BOND_FOM_FOLLOW},
+{      NULL,                   -1},
+};
+
 /*-------------------------- Forward declarations ---------------------------*/
 
 static void bond_send_gratuitous_arp(struct bonding *bond);
@@ -261,14 +271,14 @@ static int bond_add_vlan(struct bonding *bond, unsigned short vlan_id)
  */
 static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id)
 {
-       struct vlan_entry *vlan, *next;
+       struct vlan_entry *vlan;
        int res = -ENODEV;
 
        dprintk("bond: %s, vlan id %d\n", bond->dev->name, vlan_id);
 
        write_lock_bh(&bond->lock);
 
-       list_for_each_entry_safe(vlan, next, &bond->vlan_list, vlan_list) {
+       list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
                if (vlan->vlan_id == vlan_id) {
                        list_del(&vlan->vlan_list);
 
@@ -970,6 +980,82 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active, struct
        }
 }
 
+/*
+ * bond_do_fail_over_mac
+ *
+ * Perform special MAC address swapping for fail_over_mac settings
+ *
+ * Called with RTNL, bond->lock for read, curr_slave_lock for write_bh.
+ */
+static void bond_do_fail_over_mac(struct bonding *bond,
+                                 struct slave *new_active,
+                                 struct slave *old_active)
+{
+       u8 tmp_mac[ETH_ALEN];
+       struct sockaddr saddr;
+       int rv;
+
+       switch (bond->params.fail_over_mac) {
+       case BOND_FOM_ACTIVE:
+               if (new_active)
+                       memcpy(bond->dev->dev_addr,  new_active->dev->dev_addr,
+                              new_active->dev->addr_len);
+               break;
+       case BOND_FOM_FOLLOW:
+               /*
+                * if new_active && old_active, swap them
+                * if just old_active, do nothing (going to no active slave)
+                * if just new_active, set new_active to bond's MAC
+                */
+               if (!new_active)
+                       return;
+
+               write_unlock_bh(&bond->curr_slave_lock);
+               read_unlock(&bond->lock);
+
+               if (old_active) {
+                       memcpy(tmp_mac, new_active->dev->dev_addr, ETH_ALEN);
+                       memcpy(saddr.sa_data, old_active->dev->dev_addr,
+                              ETH_ALEN);
+                       saddr.sa_family = new_active->dev->type;
+               } else {
+                       memcpy(saddr.sa_data, bond->dev->dev_addr, ETH_ALEN);
+                       saddr.sa_family = bond->dev->type;
+               }
+
+               rv = dev_set_mac_address(new_active->dev, &saddr);
+               if (rv) {
+                       printk(KERN_ERR DRV_NAME
+                              ": %s: Error %d setting MAC of slave %s\n",
+                              bond->dev->name, -rv, new_active->dev->name);
+                       goto out;
+               }
+
+               if (!old_active)
+                       goto out;
+
+               memcpy(saddr.sa_data, tmp_mac, ETH_ALEN);
+               saddr.sa_family = old_active->dev->type;
+
+               rv = dev_set_mac_address(old_active->dev, &saddr);
+               if (rv)
+                       printk(KERN_ERR DRV_NAME
+                              ": %s: Error %d setting MAC of slave %s\n",
+                              bond->dev->name, -rv, new_active->dev->name);
+out:
+               read_lock(&bond->lock);
+               write_lock_bh(&bond->curr_slave_lock);
+               break;
+       default:
+               printk(KERN_ERR DRV_NAME
+                      ": %s: bond_do_fail_over_mac impossible: bad policy %d\n",
+                      bond->dev->name, bond->params.fail_over_mac);
+               break;
+       }
+
+}
+
+
 /**
  * find_best_interface - select the best available slave to be the active one
  * @bond: our bonding struct
@@ -1037,7 +1123,8 @@ static struct slave *bond_find_best_slave(struct bonding *bond)
  * because it is apparently the best available slave we have, even though its
  * updelay hasn't timed out yet.
  *
- * Warning: Caller must hold curr_slave_lock for writing.
+ * If new_active is not NULL, caller must hold bond->lock for read and
+ * curr_slave_lock for write_bh.
  */
 void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
 {
@@ -1048,6 +1135,8 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
        }
 
        if (new_active) {
+               new_active->jiffies = jiffies;
+
                if (new_active->link == BOND_LINK_BACK) {
                        if (USES_PRIMARY(bond->params.mode)) {
                                printk(KERN_INFO DRV_NAME
@@ -1059,7 +1148,6 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
 
                        new_active->delay = 0;
                        new_active->link = BOND_LINK_UP;
-                       new_active->jiffies = jiffies;
 
                        if (bond->params.mode == BOND_MODE_8023AD) {
                                bond_3ad_handle_link_change(new_active, BOND_LINK_UP);
@@ -1103,20 +1191,21 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
                        bond_set_slave_active_flags(new_active);
                }
 
-               /* when bonding does not set the slave MAC address, the bond MAC
-                * address is the one of the active slave.
-                */
                if (new_active && bond->params.fail_over_mac)
-                       memcpy(bond->dev->dev_addr,  new_active->dev->dev_addr,
-                               new_active->dev->addr_len);
+                       bond_do_fail_over_mac(bond, new_active, old_active);
+
+               bond->send_grat_arp = bond->params.num_grat_arp;
                if (bond->curr_active_slave &&
                        test_bit(__LINK_STATE_LINKWATCH_PENDING,
                                        &bond->curr_active_slave->dev->state)) {
                        dprintk("delaying gratuitous arp on %s\n",
                                bond->curr_active_slave->dev->name);
-                       bond->send_grat_arp = 1;
-               } else
-                       bond_send_gratuitous_arp(bond);
+               } else {
+                       if (bond->send_grat_arp > 0) {
+                               bond_send_gratuitous_arp(bond);
+                               bond->send_grat_arp--;
+                       }
+               }
        }
 }
 
@@ -1129,7 +1218,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
  * - The primary_slave has got its link back.
  * - A slave has got its link back and there's no old curr_active_slave.
  *
- * Warning: Caller must hold curr_slave_lock for writing.
+ * Caller must hold bond->lock for read and curr_slave_lock for write_bh.
  */
 void bond_select_active_slave(struct bonding *bond)
 {
@@ -1376,14 +1465,14 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                        printk(KERN_WARNING DRV_NAME
                               ": %s: Warning: The first slave device "
                               "specified does not support setting the MAC "
-                              "address. Enabling the fail_over_mac option.",
+                              "address. Setting fail_over_mac to active.",
                               bond_dev->name);
-                       bond->params.fail_over_mac = 1;
-               } else if (!bond->params.fail_over_mac) {
+                       bond->params.fail_over_mac = BOND_FOM_ACTIVE;
+               } else if (bond->params.fail_over_mac != BOND_FOM_ACTIVE) {
                        printk(KERN_ERR DRV_NAME
                                ": %s: Error: The slave device specified "
                                "does not support setting the MAC address, "
-                               "but fail_over_mac is not enabled.\n"
+                               "but fail_over_mac is not set to active.\n"
                                , bond_dev->name);
                        res = -EOPNOTSUPP;
                        goto err_undo_flags;
@@ -1490,6 +1579,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 
        bond_compute_features(bond);
 
+       write_unlock_bh(&bond->lock);
+
+       read_lock(&bond->lock);
+
        new_slave->last_arp_rx = jiffies;
 
        if (bond->params.miimon && !bond->params.use_carrier) {
@@ -1566,6 +1659,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                }
        }
 
+       write_lock_bh(&bond->curr_slave_lock);
+
        switch (bond->params.mode) {
        case BOND_MODE_ACTIVEBACKUP:
                bond_set_slave_inactive_flags(new_slave);
@@ -1613,9 +1708,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                break;
        } /* switch(bond_mode) */
 
+       write_unlock_bh(&bond->curr_slave_lock);
+
        bond_set_carrier(bond);
 
-       write_unlock_bh(&bond->lock);
+       read_unlock(&bond->lock);
 
        res = bond_create_slave_symlinks(bond_dev, slave_dev);
        if (res)
@@ -1639,6 +1736,10 @@ err_unset_master:
 
 err_restore_mac:
        if (!bond->params.fail_over_mac) {
+               /* XXX TODO - fom follow mode needs to change master's
+                * MAC if this slave's MAC is in use by the bond, or at
+                * least print a warning.
+                */
                memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN);
                addr.sa_family = slave_dev->type;
                dev_set_mac_address(slave_dev, &addr);
@@ -1693,20 +1794,18 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
                return -EINVAL;
        }
 
-       mac_addr_differ = memcmp(bond_dev->dev_addr,
-                                slave->perm_hwaddr,
-                                ETH_ALEN);
-       if (!mac_addr_differ && (bond->slave_cnt > 1)) {
-               printk(KERN_WARNING DRV_NAME
-                      ": %s: Warning: the permanent HWaddr of %s - "
-                      "%s - is still in use by %s. "
-                      "Set the HWaddr of %s to a different address "
-                      "to avoid conflicts.\n",
-                      bond_dev->name,
-                      slave_dev->name,
-                      print_mac(mac, slave->perm_hwaddr),
-                      bond_dev->name,
-                      slave_dev->name);
+       if (!bond->params.fail_over_mac) {
+               mac_addr_differ = memcmp(bond_dev->dev_addr, slave->perm_hwaddr,
+                                        ETH_ALEN);
+               if (!mac_addr_differ && (bond->slave_cnt > 1))
+                       printk(KERN_WARNING DRV_NAME
+                              ": %s: Warning: the permanent HWaddr of %s - "
+                              "%s - is still in use by %s. "
+                              "Set the HWaddr of %s to a different address "
+                              "to avoid conflicts.\n",
+                              bond_dev->name, slave_dev->name,
+                              print_mac(mac, slave->perm_hwaddr),
+                              bond_dev->name, slave_dev->name);
        }
 
        /* Inform AD package of unbinding of slave. */
@@ -1833,7 +1932,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
        /* close slave before restoring its mac address */
        dev_close(slave_dev);
 
-       if (!bond->params.fail_over_mac) {
+       if (bond->params.fail_over_mac != BOND_FOM_ACTIVE) {
                /* restore original ("permanent") mac address */
                memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
                addr.sa_family = slave_dev->type;
@@ -2144,7 +2243,7 @@ static int __bond_mii_monitor(struct bonding *bond, int have_locks)
                        dprintk("sending delayed gratuitous arp on on %s\n",
                                bond->curr_active_slave->dev->name);
                        bond_send_gratuitous_arp(bond);
-                       bond->send_grat_arp = 0;
+                       bond->send_grat_arp--;
                }
        }
        read_lock(&bond->curr_slave_lock);
@@ -2397,7 +2496,7 @@ void bond_mii_monitor(struct work_struct *work)
                read_lock(&bond->lock);
        }
 
-       delay = ((bond->params.miimon * HZ) / 1000) ? : 1;
+       delay = msecs_to_jiffies(bond->params.miimon);
        read_unlock(&bond->lock);
        queue_delayed_work(bond->wq, &bond->mii_work, delay);
 }
@@ -2426,37 +2525,14 @@ out:
        return addr;
 }
 
-static int bond_has_ip(struct bonding *bond)
-{
-       struct vlan_entry *vlan, *vlan_next;
-
-       if (bond->master_ip)
-               return 1;
-
-       if (list_empty(&bond->vlan_list))
-               return 0;
-
-       list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list,
-                                vlan_list) {
-               if (vlan->vlan_ip)
-                       return 1;
-       }
-
-       return 0;
-}
-
 static int bond_has_this_ip(struct bonding *bond, __be32 ip)
 {
-       struct vlan_entry *vlan, *vlan_next;
+       struct vlan_entry *vlan;
 
        if (ip == bond->master_ip)
                return 1;
 
-       if (list_empty(&bond->vlan_list))
-               return 0;
-
-       list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list,
-                                vlan_list) {
+       list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
                if (ip == vlan->vlan_ip)
                        return 1;
        }
@@ -2498,7 +2574,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
 {
        int i, vlan_id, rv;
        __be32 *targets = bond->params.arp_targets;
-       struct vlan_entry *vlan, *vlan_next;
+       struct vlan_entry *vlan;
        struct net_device *vlan_dev;
        struct flowi fl;
        struct rtable *rt;
@@ -2545,8 +2621,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
                }
 
                vlan_id = 0;
-               list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list,
-                                        vlan_list) {
+               list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
                        vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id);
                        if (vlan_dev == rt->u.dst.dev) {
                                vlan_id = vlan->vlan_id;
@@ -2707,7 +2782,7 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
 
        read_lock(&bond->lock);
 
-       delta_in_ticks = (bond->params.arp_interval * HZ) / 1000;
+       delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
 
        if (bond->kill_timers) {
                goto out;
@@ -2764,8 +2839,7 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
                         * if we don't know our ip yet
                         */
                        if (time_after_eq(jiffies, slave->dev->trans_start + 2*delta_in_ticks) ||
-                           (time_after_eq(jiffies, slave->dev->last_rx + 2*delta_in_ticks) &&
-                            bond_has_ip(bond))) {
+                           (time_after_eq(jiffies, slave->dev->last_rx + 2*delta_in_ticks))) {
 
                                slave->link  = BOND_LINK_DOWN;
                                slave->state = BOND_STATE_BACKUP;
@@ -2813,246 +2887,299 @@ out:
 }
 
 /*
- * When using arp monitoring in active-backup mode, this function is
- * called to determine if any backup slaves have went down or a new
- * current slave needs to be found.
- * The backup slaves never generate traffic, they are considered up by merely
- * receiving traffic. If the current slave goes down, each backup slave will
- * be given the opportunity to tx/rx an arp before being taken down - this
- * prevents all slaves from being taken down due to the current slave not
- * sending any traffic for the backups to receive. The arps are not necessarily
- * necessary, any tx and rx traffic will keep the current slave up. While any
- * rx traffic will keep the backup slaves up, the current slave is responsible
- * for generating traffic to keep them up regardless of any other traffic they
- * may have received.
- * see loadbalance_arp_monitor for arp monitoring in load balancing mode
+ * Called to inspect slaves for active-backup mode ARP monitor link state
+ * changes.  Sets new_link in slaves to specify what action should take
+ * place for the slave.  Returns 0 if no changes are found, >0 if changes
+ * to link states must be committed.
+ *
+ * Called with bond->lock held for read.
  */
-void bond_activebackup_arp_mon(struct work_struct *work)
+static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
 {
-       struct bonding *bond = container_of(work, struct bonding,
-                                           arp_work.work);
        struct slave *slave;
-       int delta_in_ticks;
-       int i;
+       int i, commit = 0;
 
-       read_lock(&bond->lock);
+       bond_for_each_slave(bond, slave, i) {
+               slave->new_link = BOND_LINK_NOCHANGE;
 
-       delta_in_ticks = (bond->params.arp_interval * HZ) / 1000;
+               if (slave->link != BOND_LINK_UP) {
+                       if (time_before_eq(jiffies, slave_last_rx(bond, slave) +
+                                          delta_in_ticks)) {
+                               slave->new_link = BOND_LINK_UP;
+                               commit++;
+                       }
 
-       if (bond->kill_timers) {
-               goto out;
-       }
+                       continue;
+               }
 
-       if (bond->slave_cnt == 0) {
-               goto re_arm;
+               /*
+                * Give slaves 2*delta after being enslaved or made
+                * active.  This avoids bouncing, as the last receive
+                * times need a full ARP monitor cycle to be updated.
+                */
+               if (!time_after_eq(jiffies, slave->jiffies +
+                                  2 * delta_in_ticks))
+                       continue;
+
+               /*
+                * Backup slave is down if:
+                * - No current_arp_slave AND
+                * - more than 3*delta since last receive AND
+                * - the bond has an IP address
+                *
+                * Note: a non-null current_arp_slave indicates
+                * the curr_active_slave went down and we are
+                * searching for a new one; under this condition
+                * we only take the curr_active_slave down - this
+                * gives each slave a chance to tx/rx traffic
+                * before being taken out
+                */
+               if (slave->state == BOND_STATE_BACKUP &&
+                   !bond->current_arp_slave &&
+                   time_after(jiffies, slave_last_rx(bond, slave) +
+                              3 * delta_in_ticks)) {
+                       slave->new_link = BOND_LINK_DOWN;
+                       commit++;
+               }
+
+               /*
+                * Active slave is down if:
+                * - more than 2*delta since transmitting OR
+                * - (more than 2*delta since receive AND
+                *    the bond has an IP address)
+                */
+               if ((slave->state == BOND_STATE_ACTIVE) &&
+                   (time_after_eq(jiffies, slave->dev->trans_start +
+                                   2 * delta_in_ticks) ||
+                     (time_after_eq(jiffies, slave_last_rx(bond, slave)
+                                    + 2 * delta_in_ticks)))) {
+                       slave->new_link = BOND_LINK_DOWN;
+                       commit++;
+               }
        }
 
-       /* determine if any slave has come up or any backup slave has
-        * gone down
-        * TODO: what about up/down delay in arp mode? it wasn't here before
-        *       so it can wait
+       read_lock(&bond->curr_slave_lock);
+
+       /*
+        * Trigger a commit if the primary option setting has changed.
         */
-       bond_for_each_slave(bond, slave, i) {
-               if (slave->link != BOND_LINK_UP) {
-                       if (time_before_eq(jiffies,
-                           slave_last_rx(bond, slave) + delta_in_ticks)) {
+       if (bond->primary_slave &&
+           (bond->primary_slave != bond->curr_active_slave) &&
+           (bond->primary_slave->link == BOND_LINK_UP))
+               commit++;
 
-                               slave->link = BOND_LINK_UP;
+       read_unlock(&bond->curr_slave_lock);
 
-                               write_lock_bh(&bond->curr_slave_lock);
+       return commit;
+}
 
-                               if ((!bond->curr_active_slave) &&
-                                   time_before_eq(jiffies, slave->dev->trans_start + delta_in_ticks)) {
-                                       bond_change_active_slave(bond, slave);
-                                       bond->current_arp_slave = NULL;
-                               } else if (bond->curr_active_slave != slave) {
-                                       /* this slave has just come up but we
-                                        * already have a current slave; this
-                                        * can also happen if bond_enslave adds
-                                        * a new slave that is up while we are
-                                        * searching for a new slave
-                                        */
-                                       bond_set_slave_inactive_flags(slave);
-                                       bond->current_arp_slave = NULL;
-                               }
+/*
+ * Called to commit link state changes noted by inspection step of
+ * active-backup mode ARP monitor.
+ *
+ * Called with RTNL and bond->lock for read.
+ */
+static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks)
+{
+       struct slave *slave;
+       int i;
 
-                               bond_set_carrier(bond);
+       bond_for_each_slave(bond, slave, i) {
+               switch (slave->new_link) {
+               case BOND_LINK_NOCHANGE:
+                       continue;
 
-                               if (slave == bond->curr_active_slave) {
-                                       printk(KERN_INFO DRV_NAME
-                                              ": %s: %s is up and now the "
-                                              "active interface\n",
-                                              bond->dev->name,
-                                              slave->dev->name);
-                                       netif_carrier_on(bond->dev);
-                               } else {
-                                       printk(KERN_INFO DRV_NAME
-                                              ": %s: backup interface %s is "
-                                              "now up\n",
-                                              bond->dev->name,
-                                              slave->dev->name);
-                               }
+               case BOND_LINK_UP:
+                       write_lock_bh(&bond->curr_slave_lock);
 
-                               write_unlock_bh(&bond->curr_slave_lock);
-                       }
-               } else {
-                       read_lock(&bond->curr_slave_lock);
+                       if (!bond->curr_active_slave &&
+                           time_before_eq(jiffies, slave->dev->trans_start +
+                                          delta_in_ticks)) {
+                               slave->link = BOND_LINK_UP;
+                               bond_change_active_slave(bond, slave);
+                               bond->current_arp_slave = NULL;
 
-                       if ((slave != bond->curr_active_slave) &&
-                           (!bond->current_arp_slave) &&
-                           (time_after_eq(jiffies, slave_last_rx(bond, slave) + 3*delta_in_ticks) &&
-                            bond_has_ip(bond))) {
-                               /* a backup slave has gone down; three times
-                                * the delta allows the current slave to be
-                                * taken out before the backup slave.
-                                * note: a non-null current_arp_slave indicates
-                                * the curr_active_slave went down and we are
-                                * searching for a new one; under this
-                                * condition we only take the curr_active_slave
-                                * down - this gives each slave a chance to
-                                * tx/rx traffic before being taken out
+                               printk(KERN_INFO DRV_NAME
+                                      ": %s: %s is up and now the "
+                                      "active interface\n",
+                                      bond->dev->name, slave->dev->name);
+
+                       } else if (bond->curr_active_slave != slave) {
+                               /* this slave has just come up but we
+                                * already have a current slave; this can
+                                * also happen if bond_enslave adds a new
+                                * slave that is up while we are searching
+                                * for a new slave
                                 */
+                               slave->link = BOND_LINK_UP;
+                               bond_set_slave_inactive_flags(slave);
+                               bond->current_arp_slave = NULL;
 
-                               read_unlock(&bond->curr_slave_lock);
+                               printk(KERN_INFO DRV_NAME
+                                      ": %s: backup interface %s is now up\n",
+                                      bond->dev->name, slave->dev->name);
+                       }
 
-                               slave->link  = BOND_LINK_DOWN;
+                       write_unlock_bh(&bond->curr_slave_lock);
 
-                               if (slave->link_failure_count < UINT_MAX) {
-                                       slave->link_failure_count++;
-                               }
+                       break;
+
+               case BOND_LINK_DOWN:
+                       if (slave->link_failure_count < UINT_MAX)
+                               slave->link_failure_count++;
+
+                       slave->link = BOND_LINK_DOWN;
+
+                       if (slave == bond->curr_active_slave) {
+                               printk(KERN_INFO DRV_NAME
+                                      ": %s: link status down for active "
+                                      "interface %s, disabling it\n",
+                                      bond->dev->name, slave->dev->name);
 
                                bond_set_slave_inactive_flags(slave);
 
+                               write_lock_bh(&bond->curr_slave_lock);
+
+                               bond_select_active_slave(bond);
+                               if (bond->curr_active_slave)
+                                       bond->curr_active_slave->jiffies =
+                                               jiffies;
+
+                               write_unlock_bh(&bond->curr_slave_lock);
+
+                               bond->current_arp_slave = NULL;
+
+                       } else if (slave->state == BOND_STATE_BACKUP) {
                                printk(KERN_INFO DRV_NAME
                                       ": %s: backup interface %s is now down\n",
-                                      bond->dev->name,
-                                      slave->dev->name);
-                       } else {
-                               read_unlock(&bond->curr_slave_lock);
+                                      bond->dev->name, slave->dev->name);
+
+                               bond_set_slave_inactive_flags(slave);
                        }
+                       break;
+
+               default:
+                       printk(KERN_ERR DRV_NAME
+                              ": %s: impossible: new_link %d on slave %s\n",
+                              bond->dev->name, slave->new_link,
+                              slave->dev->name);
                }
        }
 
-       read_lock(&bond->curr_slave_lock);
-       slave = bond->curr_active_slave;
-       read_unlock(&bond->curr_slave_lock);
-
-       if (slave) {
-               /* if we have sent traffic in the past 2*arp_intervals but
-                * haven't xmit and rx traffic in that time interval, select
-                * a different slave. slave->jiffies is only updated when
-                * a slave first becomes the curr_active_slave - not necessarily
-                * after every arp; this ensures the slave has a full 2*delta
-                * before being taken out. if a primary is being used, check
-                * if it is up and needs to take over as the curr_active_slave
-                */
-               if ((time_after_eq(jiffies, slave->dev->trans_start + 2*delta_in_ticks) ||
-                       (time_after_eq(jiffies, slave_last_rx(bond, slave) + 2*delta_in_ticks) &&
-                        bond_has_ip(bond))) &&
-                       time_after_eq(jiffies, slave->jiffies + 2*delta_in_ticks)) {
+       /*
+        * No race with changes to primary via sysfs, as we hold rtnl.
+        */
+       if (bond->primary_slave &&
+           (bond->primary_slave != bond->curr_active_slave) &&
+           (bond->primary_slave->link == BOND_LINK_UP)) {
+               write_lock_bh(&bond->curr_slave_lock);
+               bond_change_active_slave(bond, bond->primary_slave);
+               write_unlock_bh(&bond->curr_slave_lock);
+       }
 
-                       slave->link  = BOND_LINK_DOWN;
+       bond_set_carrier(bond);
+}
 
-                       if (slave->link_failure_count < UINT_MAX) {
-                               slave->link_failure_count++;
-                       }
+/*
+ * Send ARP probes for active-backup mode ARP monitor.
+ *
+ * Called with bond->lock held for read.
+ */
+static void bond_ab_arp_probe(struct bonding *bond)
+{
+       struct slave *slave;
+       int i;
 
-                       printk(KERN_INFO DRV_NAME
-                              ": %s: link status down for active interface "
-                              "%s, disabling it\n",
-                              bond->dev->name,
-                              slave->dev->name);
+       read_lock(&bond->curr_slave_lock);
 
-                       write_lock_bh(&bond->curr_slave_lock);
+       if (bond->current_arp_slave && bond->curr_active_slave)
+               printk("PROBE: c_arp %s && cas %s BAD\n",
+                      bond->current_arp_slave->dev->name,
+                      bond->curr_active_slave->dev->name);
 
-                       bond_select_active_slave(bond);
-                       slave = bond->curr_active_slave;
+       if (bond->curr_active_slave) {
+               bond_arp_send_all(bond, bond->curr_active_slave);
+               read_unlock(&bond->curr_slave_lock);
+               return;
+       }
 
-                       write_unlock_bh(&bond->curr_slave_lock);
+       read_unlock(&bond->curr_slave_lock);
 
-                       bond->current_arp_slave = slave;
+       /* if we don't have a curr_active_slave, search for the next available
+        * backup slave from the current_arp_slave and make it the candidate
+        * for becoming the curr_active_slave
+        */
 
-                       if (slave) {
-                               slave->jiffies = jiffies;
-                       }
-               } else if ((bond->primary_slave) &&
-                          (bond->primary_slave != slave) &&
-                          (bond->primary_slave->link == BOND_LINK_UP)) {
-                       /* at this point, slave is the curr_active_slave */
-                       printk(KERN_INFO DRV_NAME
-                              ": %s: changing from interface %s to primary "
-                              "interface %s\n",
-                              bond->dev->name,
-                              slave->dev->name,
-                              bond->primary_slave->dev->name);
+       if (!bond->current_arp_slave) {
+               bond->current_arp_slave = bond->first_slave;
+               if (!bond->current_arp_slave)
+                       return;
+       }
 
-                       /* primary is up so switch to it */
-                       write_lock_bh(&bond->curr_slave_lock);
-                       bond_change_active_slave(bond, bond->primary_slave);
-                       write_unlock_bh(&bond->curr_slave_lock);
+       bond_set_slave_inactive_flags(bond->current_arp_slave);
 
-                       slave = bond->primary_slave;
+       /* search for next candidate */
+       bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave->next) {
+               if (IS_UP(slave->dev)) {
+                       slave->link = BOND_LINK_BACK;
+                       bond_set_slave_active_flags(slave);
+                       bond_arp_send_all(bond, slave);
                        slave->jiffies = jiffies;
-               } else {
-                       bond->current_arp_slave = NULL;
+                       bond->current_arp_slave = slave;
+                       break;
                }
 
-               /* the current slave must tx an arp to ensure backup slaves
-                * rx traffic
+               /* if the link state is up at this point, we
+                * mark it down - this can happen if we have
+                * simultaneous link failures and
+                * reselect_active_interface doesn't make this
+                * one the current slave so it is still marked
+                * up when it is actually down
                 */
-               if (slave && bond_has_ip(bond)) {
-                       bond_arp_send_all(bond, slave);
+               if (slave->link == BOND_LINK_UP) {
+                       slave->link = BOND_LINK_DOWN;
+                       if (slave->link_failure_count < UINT_MAX)
+                               slave->link_failure_count++;
+
+                       bond_set_slave_inactive_flags(slave);
+
+                       printk(KERN_INFO DRV_NAME
+                              ": %s: backup interface %s is now down.\n",
+                              bond->dev->name, slave->dev->name);
                }
        }
+}
 
-       /* if we don't have a curr_active_slave, search for the next available
-        * backup slave from the current_arp_slave and make it the candidate
-        * for becoming the curr_active_slave
-        */
-       if (!slave) {
-               if (!bond->current_arp_slave) {
-                       bond->current_arp_slave = bond->first_slave;
-               }
+void bond_activebackup_arp_mon(struct work_struct *work)
+{
+       struct bonding *bond = container_of(work, struct bonding,
+                                           arp_work.work);
+       int delta_in_ticks;
 
-               if (bond->current_arp_slave) {
-                       bond_set_slave_inactive_flags(bond->current_arp_slave);
+       read_lock(&bond->lock);
 
-                       /* search for next candidate */
-                       bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave->next) {
-                               if (IS_UP(slave->dev)) {
-                                       slave->link = BOND_LINK_BACK;
-                                       bond_set_slave_active_flags(slave);
-                                       bond_arp_send_all(bond, slave);
-                                       slave->jiffies = jiffies;
-                                       bond->current_arp_slave = slave;
-                                       break;
-                               }
+       if (bond->kill_timers)
+               goto out;
 
-                               /* if the link state is up at this point, we
-                                * mark it down - this can happen if we have
-                                * simultaneous link failures and
-                                * reselect_active_interface doesn't make this
-                                * one the current slave so it is still marked
-                                * up when it is actually down
-                                */
-                               if (slave->link == BOND_LINK_UP) {
-                                       slave->link  = BOND_LINK_DOWN;
-                                       if (slave->link_failure_count < UINT_MAX) {
-                                               slave->link_failure_count++;
-                                       }
+       delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
 
-                                       bond_set_slave_inactive_flags(slave);
+       if (bond->slave_cnt == 0)
+               goto re_arm;
 
-                                       printk(KERN_INFO DRV_NAME
-                                              ": %s: backup interface %s is "
-                                              "now down.\n",
-                                              bond->dev->name,
-                                              slave->dev->name);
-                               }
-                       }
-               }
+       if (bond_ab_arp_inspect(bond, delta_in_ticks)) {
+               read_unlock(&bond->lock);
+               rtnl_lock();
+               read_lock(&bond->lock);
+
+               bond_ab_arp_commit(bond, delta_in_ticks);
+
+               read_unlock(&bond->lock);
+               rtnl_unlock();
+               read_lock(&bond->lock);
        }
 
+       bond_ab_arp_probe(bond);
+
 re_arm:
        if (bond->params.arp_interval) {
                queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
@@ -3128,7 +3255,8 @@ static void bond_info_show_master(struct seq_file *seq)
 
        if (bond->params.mode == BOND_MODE_ACTIVEBACKUP &&
            bond->params.fail_over_mac)
-               seq_printf(seq, " (fail_over_mac)");
+               seq_printf(seq, " (fail_over_mac %s)",
+                  fail_over_mac_tbl[bond->params.fail_over_mac].modename);
 
        seq_printf(seq, "\n");
 
@@ -3500,13 +3628,13 @@ static int bond_inetaddr_event(struct notifier_block *this, unsigned long event,
 {
        struct in_ifaddr *ifa = ptr;
        struct net_device *vlan_dev, *event_dev = ifa->ifa_dev->dev;
-       struct bonding *bond, *bond_next;
-       struct vlan_entry *vlan, *vlan_next;
+       struct bonding *bond;
+       struct vlan_entry *vlan;
 
        if (dev_net(ifa->ifa_dev->dev) != &init_net)
                return NOTIFY_DONE;
 
-       list_for_each_entry_safe(bond, bond_next, &bond_dev_list, bond_list) {
+       list_for_each_entry(bond, &bond_dev_list, bond_list) {
                if (bond->dev == event_dev) {
                        switch (event) {
                        case NETDEV_UP:
@@ -3520,11 +3648,7 @@ static int bond_inetaddr_event(struct notifier_block *this, unsigned long event,
                        }
                }
 
-               if (list_empty(&bond->vlan_list))
-                       continue;
-
-               list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list,
-                                        vlan_list) {
+               list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
                        vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id);
                        if (vlan_dev == event_dev) {
                                switch (event) {
@@ -4060,10 +4184,10 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
        dprintk("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None"));
 
        /*
-        * If fail_over_mac is enabled, do nothing and return success.
-        * Returning an error causes ifenslave to fail.
+        * If fail_over_mac is set to active, do nothing and return
+        * success.  Returning an error causes ifenslave to fail.
         */
-       if (bond->params.fail_over_mac)
+       if (bond->params.fail_over_mac == BOND_FOM_ACTIVE)
                return 0;
 
        if (!is_valid_ether_addr(sa->sa_data)) {
@@ -4568,7 +4692,7 @@ int bond_parse_parm(const char *buf, struct bond_parm_tbl *tbl)
 
 static int bond_check_params(struct bond_params *params)
 {
-       int arp_validate_value;
+       int arp_validate_value, fail_over_mac_value;
 
        /*
         * Convert string parameters.
@@ -4658,6 +4782,13 @@ static int bond_check_params(struct bond_params *params)
                use_carrier = 1;
        }
 
+       if (num_grat_arp < 0 || num_grat_arp > 255) {
+               printk(KERN_WARNING DRV_NAME
+                      ": Warning: num_grat_arp (%d) not in range 0-255 so it "
+                      "was reset to 1 \n", num_grat_arp);
+               num_grat_arp = 1;
+       }
+
        /* reset values for 802.3ad */
        if (bond_mode == BOND_MODE_8023AD) {
                if (!miimon) {
@@ -4836,15 +4967,29 @@ static int bond_check_params(struct bond_params *params)
                primary = NULL;
        }
 
-       if (fail_over_mac && (bond_mode != BOND_MODE_ACTIVEBACKUP))
-               printk(KERN_WARNING DRV_NAME
-                      ": Warning: fail_over_mac only affects "
-                      "active-backup mode.\n");
+       if (fail_over_mac) {
+               fail_over_mac_value = bond_parse_parm(fail_over_mac,
+                                                     fail_over_mac_tbl);
+               if (fail_over_mac_value == -1) {
+                       printk(KERN_ERR DRV_NAME
+                              ": Error: invalid fail_over_mac \"%s\"\n",
+                              arp_validate == NULL ? "NULL" : arp_validate);
+                       return -EINVAL;
+               }
+
+               if (bond_mode != BOND_MODE_ACTIVEBACKUP)
+                       printk(KERN_WARNING DRV_NAME
+                              ": Warning: fail_over_mac only affects "
+                              "active-backup mode.\n");
+       } else {
+               fail_over_mac_value = BOND_FOM_NONE;
+       }
 
        /* fill params struct with the proper values */
        params->mode = bond_mode;
        params->xmit_policy = xmit_hashtype;
        params->miimon = miimon;
+       params->num_grat_arp = num_grat_arp;
        params->arp_interval = arp_interval;
        params->arp_validate = arp_validate_value;
        params->updelay = updelay;
@@ -4852,7 +4997,7 @@ static int bond_check_params(struct bond_params *params)
        params->use_carrier = use_carrier;
        params->lacp_fast = lacp_fast;
        params->primary[0] = 0;
-       params->fail_over_mac = fail_over_mac;
+       params->fail_over_mac = fail_over_mac_value;
 
        if (primary) {
                strncpy(params->primary, primary, IFNAMSIZ);
@@ -4871,10 +5016,10 @@ static struct lock_class_key bonding_netdev_xmit_lock_key;
  * Caller must NOT hold rtnl_lock; we need to release it here before we
  * set up our sysfs entries.
  */
-int bond_create(char *name, struct bond_params *params, struct bonding **newbond)
+int bond_create(char *name, struct bond_params *params)
 {
        struct net_device *bond_dev;
-       struct bonding *bond, *nxt;
+       struct bonding *bond;
        int res;
 
        rtnl_lock();
@@ -4882,7 +5027,7 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond
 
        /* Check to see if the bond already exists. */
        if (name) {
-               list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list)
+               list_for_each_entry(bond, &bond_dev_list, bond_list)
                        if (strnicmp(bond->dev->name, name, IFNAMSIZ) == 0) {
                                printk(KERN_ERR DRV_NAME
                               ": cannot add bond %s; it already exists\n",
@@ -4925,9 +5070,6 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond
 
        lockdep_set_class(&bond_dev->_xmit_lock, &bonding_netdev_xmit_lock_key);
 
-       if (newbond)
-               *newbond = bond_dev->priv;
-
        netif_carrier_off(bond_dev);
 
        up_write(&bonding_rwsem);
@@ -4957,7 +5099,7 @@ static int __init bonding_init(void)
 {
        int i;
        int res;
-       struct bonding *bond, *nxt;
+       struct bonding *bond;
 
        printk(KERN_INFO "%s", version);
 
@@ -4973,7 +5115,7 @@ static int __init bonding_init(void)
        init_rwsem(&bonding_rwsem);
 
        for (i = 0; i < max_bonds; i++) {
-               res = bond_create(NULL, &bonding_defaults, NULL);
+               res = bond_create(NULL, &bonding_defaults);
                if (res)
                        goto err;
        }
@@ -4987,7 +5129,7 @@ static int __init bonding_init(void)
 
        goto out;
 err:
-       list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) {
+       list_for_each_entry(bond, &bond_dev_list, bond_list) {
                bond_work_cancel_all(bond);
                destroy_workqueue(bond->wq);
        }
index 08f3d396bcd68a669e5cce60a24158dce7c29cdd..dd265c69b0dffc1b85de39bb9412a75373913b2e 100644 (file)
@@ -50,6 +50,7 @@ extern struct bond_parm_tbl bond_mode_tbl[];
 extern struct bond_parm_tbl bond_lacp_tbl[];
 extern struct bond_parm_tbl xmit_hashtype_tbl[];
 extern struct bond_parm_tbl arp_validate_tbl[];
+extern struct bond_parm_tbl fail_over_mac_tbl[];
 
 static int expected_refcount = -1;
 static struct class *netdev_class;
@@ -111,7 +112,6 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t
        char *ifname;
        int rv, res = count;
        struct bonding *bond;
-       struct bonding *nxt;
 
        sscanf(buffer, "%16s", command); /* IFNAMSIZ*/
        ifname = command + 1;
@@ -122,7 +122,7 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t
        if (command[0] == '+') {
                printk(KERN_INFO DRV_NAME
                        ": %s is being created...\n", ifname);
-               rv = bond_create(ifname, &bonding_defaults, &bond);
+               rv = bond_create(ifname, &bonding_defaults);
                if (rv) {
                        printk(KERN_INFO DRV_NAME ": Bond creation failed.\n");
                        res = rv;
@@ -134,7 +134,7 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t
                rtnl_lock();
                down_write(&bonding_rwsem);
 
-               list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list)
+               list_for_each_entry(bond, &bond_dev_list, bond_list)
                        if (strnicmp(bond->dev->name, ifname, IFNAMSIZ) == 0) {
                                /* check the ref count on the bond's kobject.
                                 * If it's > expected, then there's a file open,
@@ -548,42 +548,37 @@ static ssize_t bonding_show_fail_over_mac(struct device *d, struct device_attrib
 {
        struct bonding *bond = to_bond(d);
 
-       return sprintf(buf, "%d\n", bond->params.fail_over_mac) + 1;
+       return sprintf(buf, "%s %d\n",
+                      fail_over_mac_tbl[bond->params.fail_over_mac].modename,
+                      bond->params.fail_over_mac);
 }
 
 static ssize_t bonding_store_fail_over_mac(struct device *d, struct device_attribute *attr, const char *buf, size_t count)
 {
        int new_value;
-       int ret = count;
        struct bonding *bond = to_bond(d);
 
        if (bond->slave_cnt != 0) {
                printk(KERN_ERR DRV_NAME
                       ": %s: Can't alter fail_over_mac with slaves in bond.\n",
                       bond->dev->name);
-               ret = -EPERM;
-               goto out;
+               return -EPERM;
        }
 
-       if (sscanf(buf, "%d", &new_value) != 1) {
+       new_value = bond_parse_parm(buf, fail_over_mac_tbl);
+       if (new_value < 0) {
                printk(KERN_ERR DRV_NAME
-                      ": %s: no fail_over_mac value specified.\n",
-                      bond->dev->name);
-               ret = -EINVAL;
-               goto out;
+                      ": %s: Ignoring invalid fail_over_mac value %s.\n",
+                      bond->dev->name, buf);
+               return -EINVAL;
        }
 
-       if ((new_value == 0) || (new_value == 1)) {
-               bond->params.fail_over_mac = new_value;
-               printk(KERN_INFO DRV_NAME ": %s: Setting fail_over_mac to %d.\n",
-                      bond->dev->name, new_value);
-       } else {
-               printk(KERN_INFO DRV_NAME
-                      ": %s: Ignoring invalid fail_over_mac value %d.\n",
-                      bond->dev->name, new_value);
-       }
-out:
-       return ret;
+       bond->params.fail_over_mac = new_value;
+       printk(KERN_INFO DRV_NAME ": %s: Setting fail_over_mac to %s (%d).\n",
+              bond->dev->name, fail_over_mac_tbl[new_value].modename,
+              new_value);
+
+       return count;
 }
 
 static DEVICE_ATTR(fail_over_mac, S_IRUGO | S_IWUSR, bonding_show_fail_over_mac, bonding_store_fail_over_mac);
@@ -951,6 +946,45 @@ out:
 }
 static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp);
 
+/*
+ * Show and set the number of grat ARP to send after a failover event.
+ */
+static ssize_t bonding_show_n_grat_arp(struct device *d,
+                                  struct device_attribute *attr,
+                                  char *buf)
+{
+       struct bonding *bond = to_bond(d);
+
+       return sprintf(buf, "%d\n", bond->params.num_grat_arp);
+}
+
+static ssize_t bonding_store_n_grat_arp(struct device *d,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t count)
+{
+       int new_value, ret = count;
+       struct bonding *bond = to_bond(d);
+
+       if (sscanf(buf, "%d", &new_value) != 1) {
+               printk(KERN_ERR DRV_NAME
+                      ": %s: no num_grat_arp value specified.\n",
+                      bond->dev->name);
+               ret = -EINVAL;
+               goto out;
+       }
+       if (new_value < 0 || new_value > 255) {
+               printk(KERN_ERR DRV_NAME
+                      ": %s: Invalid num_grat_arp value %d not in range 0-255; rejected.\n",
+                      bond->dev->name, new_value);
+               ret = -EINVAL;
+               goto out;
+       } else {
+               bond->params.num_grat_arp = new_value;
+       }
+out:
+       return ret;
+}
+static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, bonding_show_n_grat_arp, bonding_store_n_grat_arp);
 /*
  * Show and set the MII monitor interval.  There are two tricky bits
  * here.  First, if MII monitoring is activated, then we must disable
@@ -1388,6 +1422,7 @@ static struct attribute *per_bond_attrs[] = {
        &dev_attr_updelay.attr,
        &dev_attr_lacp_rate.attr,
        &dev_attr_xmit_hash_policy.attr,
+       &dev_attr_num_grat_arp.attr,
        &dev_attr_miimon.attr,
        &dev_attr_primary.attr,
        &dev_attr_use_carrier.attr,
index a3c74e20aa538523df633effbeaa46aaa1b0bb27..89fd9963db7ae6fea3f2623445a5c5a422837690 100644 (file)
@@ -125,6 +125,7 @@ struct bond_params {
        int mode;
        int xmit_policy;
        int miimon;
+       int num_grat_arp;
        int arp_interval;
        int arp_validate;
        int use_carrier;
@@ -157,6 +158,7 @@ struct slave {
        unsigned long jiffies;
        unsigned long last_arp_rx;
        s8     link;    /* one of BOND_LINK_XXXX */
+       s8     new_link;
        s8     state;   /* one of BOND_STATE_XXXX */
        u32    original_flags;
        u32    original_mtu;
@@ -168,6 +170,11 @@ struct slave {
        struct tlb_slave_info tlb_info;
 };
 
+/*
+ * Link pseudo-state only used internally by monitors
+ */
+#define BOND_LINK_NOCHANGE -1
+
 /*
  * Here are the locking policies for the two bonding locks:
  *
@@ -241,6 +248,10 @@ static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
        return (struct bonding *)slave->dev->master->priv;
 }
 
+#define BOND_FOM_NONE                  0
+#define BOND_FOM_ACTIVE                        1
+#define BOND_FOM_FOLLOW                        2
+
 #define BOND_ARP_VALIDATE_NONE         0
 #define BOND_ARP_VALIDATE_ACTIVE       (1 << BOND_STATE_ACTIVE)
 #define BOND_ARP_VALIDATE_BACKUP       (1 << BOND_STATE_BACKUP)
@@ -301,7 +312,7 @@ static inline void bond_unset_master_alb_flags(struct bonding *bond)
 
 struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr);
 int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev);
-int bond_create(char *name, struct bond_params *params, struct bonding **newbond);
+int bond_create(char *name, struct bond_params *params);
 void bond_destroy(struct bonding *bond);
 int  bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev);
 int bond_create_sysfs(void);
index acebe431d06897bd06ac7ca1ffd978cfaf757383..271140433b09a68eaa7219873185e21cb3bd27b0 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/cache.h>
 #include <linux/mutex.h>
 #include <linux/bitops.h>
+#include <linux/inet_lro.h>
 #include "t3cdev.h"
 #include <asm/io.h>
 
@@ -92,6 +93,7 @@ struct sge_fl {                     /* SGE per free-buffer list state */
        unsigned int gen;           /* free list generation */
        struct fl_pg_chunk pg_chunk;/* page chunk cache */
        unsigned int use_pages;     /* whether FL uses pages or sk_buffs */
+       unsigned int order;         /* order of page allocations */
        struct rx_desc *desc;       /* address of HW Rx descriptor ring */
        struct rx_sw_desc *sdesc;   /* address of SW Rx descriptor ring */
        dma_addr_t   phys_addr;     /* physical address of HW ring start */
@@ -116,12 +118,15 @@ struct sge_rspq {         /* state for an SGE response queue */
        unsigned int polling;   /* is the queue serviced through NAPI? */
        unsigned int holdoff_tmr;       /* interrupt holdoff timer in 100ns */
        unsigned int next_holdoff;      /* holdoff time for next interrupt */
+       unsigned int rx_recycle_buf; /* whether recycling occurred
+                                       within current sop-eop */
        struct rsp_desc *desc;  /* address of HW response ring */
        dma_addr_t phys_addr;   /* physical address of the ring */
        unsigned int cntxt_id;  /* SGE context id for the response q */
        spinlock_t lock;        /* guards response processing */
        struct sk_buff *rx_head;        /* offload packet receive queue head */
        struct sk_buff *rx_tail;        /* offload packet receive queue tail */
+       struct sk_buff *pg_skb; /* used to build frag list in napi handler */
 
        unsigned long offload_pkts;
        unsigned long offload_bundles;
@@ -169,16 +174,29 @@ enum {                            /* per port SGE statistics */
        SGE_PSTAT_TX_CSUM,      /* # of TX checksum offloads */
        SGE_PSTAT_VLANEX,       /* # of VLAN tag extractions */
        SGE_PSTAT_VLANINS,      /* # of VLAN tag insertions */
+       SGE_PSTAT_LRO_AGGR,     /* # of page chunks added to LRO sessions */
+       SGE_PSTAT_LRO_FLUSHED,  /* # of flushed LRO sessions */
+       SGE_PSTAT_LRO_NO_DESC,  /* # of overflown LRO sessions */
 
        SGE_PSTAT_MAX           /* must be last */
 };
 
+#define T3_MAX_LRO_SES 8
+#define T3_MAX_LRO_MAX_PKTS 64
+
 struct sge_qset {              /* an SGE queue set */
        struct adapter *adap;
        struct napi_struct napi;
        struct sge_rspq rspq;
        struct sge_fl fl[SGE_RXQ_PER_SET];
        struct sge_txq txq[SGE_TXQ_PER_SET];
+       struct net_lro_mgr lro_mgr;
+       struct net_lro_desc lro_desc[T3_MAX_LRO_SES];
+       struct skb_frag_struct *lro_frag_tbl;
+       int lro_nfrags;
+       int lro_enabled;
+       int lro_frag_len;
+       void *lro_va;
        struct net_device *netdev;
        unsigned long txq_stopped;      /* which Tx queues are stopped */
        struct timer_list tx_reclaim_timer;     /* reclaims TX buffers */
index 579bee42a5cb9ee10fcd945ba5c4f4b1d937d397..d444f5881f56691ccf5e2e9276ad5f4694714791 100644 (file)
@@ -351,6 +351,7 @@ struct tp_params {
 
 struct qset_params {           /* SGE queue set parameters */
        unsigned int polling;   /* polling/interrupt service for rspq */
+       unsigned int lro;       /* large receive offload */
        unsigned int coalesce_usecs;    /* irq coalescing timer */
        unsigned int rspq_size; /* # of entries in response queue */
        unsigned int fl_size;   /* # of entries in regular free list */
index 0a82fcddf2d8a9d49b014b21a3662349464fa484..68200a14065ebc12b07879f4ecde8f491aa9570e 100644 (file)
@@ -90,6 +90,7 @@ struct ch_qset_params {
        int32_t fl_size[2];
        int32_t intr_lat;
        int32_t polling;
+       int32_t lro;
        int32_t cong_thres;
 };
 
index 3a31272167913dc4b7a621d7c07e2f08b70a3a6d..5447f3e60f07cfca4af049d63cf0bf8cb836f4b1 100644 (file)
@@ -1212,6 +1212,9 @@ static char stats_strings[][ETH_GSTRING_LEN] = {
        "VLANinsertions     ",
        "TxCsumOffload      ",
        "RxCsumGood         ",
+       "LroAggregated      ",
+       "LroFlushed         ",
+       "LroNoDesc          ",
        "RxDrops            ",
 
        "CheckTXEnToggled   ",
@@ -1340,6 +1343,9 @@ static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
        *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANINS);
        *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TX_CSUM);
        *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_RX_CSUM_GOOD);
+       *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_LRO_AGGR);
+       *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_LRO_FLUSHED);
+       *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_LRO_NO_DESC);
        *data++ = s->rx_cong_drops;
 
        *data++ = s->num_toggled;
@@ -1558,6 +1564,13 @@ static int set_rx_csum(struct net_device *dev, u32 data)
        struct port_info *p = netdev_priv(dev);
 
        p->rx_csum_offload = data;
+       if (!data) {
+               struct adapter *adap = p->adapter;
+               int i;
+
+               for (i = p->first_qset; i < p->first_qset + p->nqsets; i++)
+                       adap->sge.qs[i].lro_enabled = 0;
+       }
        return 0;
 }
 
@@ -1830,6 +1843,11 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
                                }
                        }
                }
+               if (t.lro >= 0) {
+                       struct sge_qset *qs = &adapter->sge.qs[t.qset_idx];
+                       q->lro = t.lro;
+                       qs->lro_enabled = t.lro;
+               }
                break;
        }
        case CHELSIO_GET_QSET_PARAMS:{
@@ -1849,6 +1867,7 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
                t.fl_size[0] = q->fl_size;
                t.fl_size[1] = q->jumbo_size;
                t.polling = q->polling;
+               t.lro = q->lro;
                t.intr_lat = q->coalesce_usecs;
                t.cong_thres = q->cong_thres;
 
index 796eb305cdc3ccb7348492818a128c7e69105006..a96331c875e69cf0d07a9398cf4f74692c06faae 100644 (file)
@@ -55,6 +55,9 @@
  * directly.
  */
 #define FL0_PG_CHUNK_SIZE  2048
+#define FL0_PG_ORDER 0
+#define FL1_PG_CHUNK_SIZE (PAGE_SIZE > 8192 ? 16384 : 8192)
+#define FL1_PG_ORDER (PAGE_SIZE > 8192 ? 0 : 1)
 
 #define SGE_RX_DROP_THRES 16
 
@@ -359,7 +362,7 @@ static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q)
        }
 
        if (q->pg_chunk.page) {
-               __free_page(q->pg_chunk.page);
+               __free_pages(q->pg_chunk.page, q->order);
                q->pg_chunk.page = NULL;
        }
 }
@@ -376,13 +379,16 @@ static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q)
  *     Add a buffer of the given length to the supplied HW and SW Rx
  *     descriptors.
  */
-static inline void add_one_rx_buf(void *va, unsigned int len,
-                                 struct rx_desc *d, struct rx_sw_desc *sd,
-                                 unsigned int gen, struct pci_dev *pdev)
+static inline int add_one_rx_buf(void *va, unsigned int len,
+                                struct rx_desc *d, struct rx_sw_desc *sd,
+                                unsigned int gen, struct pci_dev *pdev)
 {
        dma_addr_t mapping;
 
        mapping = pci_map_single(pdev, va, len, PCI_DMA_FROMDEVICE);
+       if (unlikely(pci_dma_mapping_error(mapping)))
+               return -ENOMEM;
+
        pci_unmap_addr_set(sd, dma_addr, mapping);
 
        d->addr_lo = cpu_to_be32(mapping);
@@ -390,12 +396,14 @@ static inline void add_one_rx_buf(void *va, unsigned int len,
        wmb();
        d->len_gen = cpu_to_be32(V_FLD_GEN1(gen));
        d->gen2 = cpu_to_be32(V_FLD_GEN2(gen));
+       return 0;
 }
 
-static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp)
+static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp,
+                         unsigned int order)
 {
        if (!q->pg_chunk.page) {
-               q->pg_chunk.page = alloc_page(gfp);
+               q->pg_chunk.page = alloc_pages(gfp, order);
                if (unlikely(!q->pg_chunk.page))
                        return -ENOMEM;
                q->pg_chunk.va = page_address(q->pg_chunk.page);
@@ -404,7 +412,7 @@ static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp)
        sd->pg_chunk = q->pg_chunk;
 
        q->pg_chunk.offset += q->buf_size;
-       if (q->pg_chunk.offset == PAGE_SIZE)
+       if (q->pg_chunk.offset == (PAGE_SIZE << order))
                q->pg_chunk.page = NULL;
        else {
                q->pg_chunk.va += q->buf_size;
@@ -424,15 +432,18 @@ static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp)
  *     allocated with the supplied gfp flags.  The caller must assure that
  *     @n does not exceed the queue's capacity.
  */
-static void refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp)
+static int refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp)
 {
        void *buf_start;
        struct rx_sw_desc *sd = &q->sdesc[q->pidx];
        struct rx_desc *d = &q->desc[q->pidx];
+       unsigned int count = 0;
 
        while (n--) {
+               int err;
+
                if (q->use_pages) {
-                       if (unlikely(alloc_pg_chunk(q, sd, gfp))) {
+                       if (unlikely(alloc_pg_chunk(q, sd, gfp, q->order))) {
 nomem:                         q->alloc_failed++;
                                break;
                        }
@@ -447,8 +458,16 @@ nomem:                             q->alloc_failed++;
                        buf_start = skb->data;
                }
 
-               add_one_rx_buf(buf_start, q->buf_size, d, sd, q->gen,
-                              adap->pdev);
+               err = add_one_rx_buf(buf_start, q->buf_size, d, sd, q->gen,
+                                    adap->pdev);
+               if (unlikely(err)) {
+                       if (!q->use_pages) {
+                               kfree_skb(sd->skb);
+                               sd->skb = NULL;
+                       }
+                       break;
+               }
+
                d++;
                sd++;
                if (++q->pidx == q->size) {
@@ -458,14 +477,19 @@ nomem:                            q->alloc_failed++;
                        d = q->desc;
                }
                q->credits++;
+               count++;
        }
        wmb();
-       t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id));
+       if (likely(count))
+               t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id));
+
+       return count;
 }
 
 static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl)
 {
-       refill_fl(adap, fl, min(16U, fl->size - fl->credits), GFP_ATOMIC);
+       refill_fl(adap, fl, min(16U, fl->size - fl->credits),
+                 GFP_ATOMIC | __GFP_COMP);
 }
 
 /**
@@ -560,6 +584,8 @@ static void t3_reset_qset(struct sge_qset *q)
        memset(q->txq, 0, sizeof(struct sge_txq) * SGE_TXQ_PER_SET);
        q->txq_stopped = 0;
        memset(&q->tx_reclaim_timer, 0, sizeof(q->tx_reclaim_timer));
+       kfree(q->lro_frag_tbl);
+       q->lro_nfrags = q->lro_frag_len = 0;
 }
 
 
@@ -740,19 +766,22 @@ use_orig_buf:
  *     that are page chunks rather than sk_buffs.
  */
 static struct sk_buff *get_packet_pg(struct adapter *adap, struct sge_fl *fl,
-                                    unsigned int len, unsigned int drop_thres)
+                                    struct sge_rspq *q, unsigned int len,
+                                    unsigned int drop_thres)
 {
-       struct sk_buff *skb = NULL;
+       struct sk_buff *newskb, *skb;
        struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
 
-       if (len <= SGE_RX_COPY_THRES) {
-               skb = alloc_skb(len, GFP_ATOMIC);
-               if (likely(skb != NULL)) {
-                       __skb_put(skb, len);
+       newskb = skb = q->pg_skb;
+
+       if (!skb && (len <= SGE_RX_COPY_THRES)) {
+               newskb = alloc_skb(len, GFP_ATOMIC);
+               if (likely(newskb != NULL)) {
+                       __skb_put(newskb, len);
                        pci_dma_sync_single_for_cpu(adap->pdev,
                                            pci_unmap_addr(sd, dma_addr), len,
                                            PCI_DMA_FROMDEVICE);
-                       memcpy(skb->data, sd->pg_chunk.va, len);
+                       memcpy(newskb->data, sd->pg_chunk.va, len);
                        pci_dma_sync_single_for_device(adap->pdev,
                                            pci_unmap_addr(sd, dma_addr), len,
                                            PCI_DMA_FROMDEVICE);
@@ -761,14 +790,16 @@ static struct sk_buff *get_packet_pg(struct adapter *adap, struct sge_fl *fl,
 recycle:
                fl->credits--;
                recycle_rx_buf(adap, fl, fl->cidx);
-               return skb;
+               q->rx_recycle_buf++;
+               return newskb;
        }
 
-       if (unlikely(fl->credits <= drop_thres))
+       if (unlikely(q->rx_recycle_buf || (!skb && fl->credits <= drop_thres)))
                goto recycle;
 
-       skb = alloc_skb(SGE_RX_PULL_LEN, GFP_ATOMIC);
-       if (unlikely(!skb)) {
+       if (!skb)
+               newskb = alloc_skb(SGE_RX_PULL_LEN, GFP_ATOMIC);
+       if (unlikely(!newskb)) {
                if (!drop_thres)
                        return NULL;
                goto recycle;
@@ -776,21 +807,29 @@ recycle:
 
        pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr),
                         fl->buf_size, PCI_DMA_FROMDEVICE);
-       __skb_put(skb, SGE_RX_PULL_LEN);
-       memcpy(skb->data, sd->pg_chunk.va, SGE_RX_PULL_LEN);
-       skb_fill_page_desc(skb, 0, sd->pg_chunk.page,
-                          sd->pg_chunk.offset + SGE_RX_PULL_LEN,
-                          len - SGE_RX_PULL_LEN);
-       skb->len = len;
-       skb->data_len = len - SGE_RX_PULL_LEN;
-       skb->truesize += skb->data_len;
+       if (!skb) {
+               __skb_put(newskb, SGE_RX_PULL_LEN);
+               memcpy(newskb->data, sd->pg_chunk.va, SGE_RX_PULL_LEN);
+               skb_fill_page_desc(newskb, 0, sd->pg_chunk.page,
+                                  sd->pg_chunk.offset + SGE_RX_PULL_LEN,
+                                  len - SGE_RX_PULL_LEN);
+               newskb->len = len;
+               newskb->data_len = len - SGE_RX_PULL_LEN;
+       } else {
+               skb_fill_page_desc(newskb, skb_shinfo(newskb)->nr_frags,
+                                  sd->pg_chunk.page,
+                                  sd->pg_chunk.offset, len);
+               newskb->len += len;
+               newskb->data_len += len;
+       }
+       newskb->truesize += newskb->data_len;
 
        fl->credits--;
        /*
         * We do not refill FLs here, we let the caller do it to overlap a
         * prefetch.
         */
-       return skb;
+       return newskb;
 }
 
 /**
@@ -1831,9 +1870,10 @@ static void restart_tx(struct sge_qset *qs)
  *     if it was immediate data in a response.
  */
 static void rx_eth(struct adapter *adap, struct sge_rspq *rq,
-                  struct sk_buff *skb, int pad)
+                  struct sk_buff *skb, int pad, int lro)
 {
        struct cpl_rx_pkt *p = (struct cpl_rx_pkt *)(skb->data + pad);
+       struct sge_qset *qs = rspq_to_qset(rq);
        struct port_info *pi;
 
        skb_pull(skb, sizeof(*p) + pad);
@@ -1850,18 +1890,202 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq,
        if (unlikely(p->vlan_valid)) {
                struct vlan_group *grp = pi->vlan_grp;
 
-               rspq_to_qset(rq)->port_stats[SGE_PSTAT_VLANEX]++;
+               qs->port_stats[SGE_PSTAT_VLANEX]++;
                if (likely(grp))
-                       __vlan_hwaccel_rx(skb, grp, ntohs(p->vlan),
-                                         rq->polling);
+                       if (lro)
+                               lro_vlan_hwaccel_receive_skb(&qs->lro_mgr, skb,
+                                                            grp,
+                                                            ntohs(p->vlan),
+                                                            p);
+                       else
+                               __vlan_hwaccel_rx(skb, grp, ntohs(p->vlan),
+                                                 rq->polling);
                else
                        dev_kfree_skb_any(skb);
-       } else if (rq->polling)
-               netif_receive_skb(skb);
-       else
+       } else if (rq->polling) {
+               if (lro)
+                       lro_receive_skb(&qs->lro_mgr, skb, p);
+               else
+                       netif_receive_skb(skb);
+       } else
                netif_rx(skb);
 }
 
+static inline int is_eth_tcp(u32 rss)
+{
+       return G_HASHTYPE(ntohl(rss)) == RSS_HASH_4_TUPLE;
+}
+
+/**
+ *     lro_frame_ok - check if an ingress packet is eligible for LRO
+ *     @p: the CPL header of the packet
+ *
+ *     Returns true if a received packet is eligible for LRO.
+ *     The following conditions must be true:
+ *     - packet is TCP/IP Ethernet II (checked elsewhere)
+ *     - not an IP fragment
+ *     - no IP options
+ *     - TCP/IP checksums are correct
+ *     - the packet is for this host
+ */
+static inline int lro_frame_ok(const struct cpl_rx_pkt *p)
+{
+       const struct ethhdr *eh = (struct ethhdr *)(p + 1);
+       const struct iphdr *ih = (struct iphdr *)(eh + 1);
+
+       return (*((u8 *)p + 1) & 0x90) == 0x10 && p->csum == htons(0xffff) &&
+               eh->h_proto == htons(ETH_P_IP) && ih->ihl == (sizeof(*ih) >> 2);
+}
+
+#define TCP_FLAG_MASK (TCP_FLAG_CWR | TCP_FLAG_ECE | TCP_FLAG_URG |\
+                       TCP_FLAG_ACK | TCP_FLAG_PSH | TCP_FLAG_RST |\
+                                      TCP_FLAG_SYN | TCP_FLAG_FIN)
+#define TSTAMP_WORD ((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |\
+                     (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)
+
+/**
+ *     lro_segment_ok - check if a TCP segment is eligible for LRO
+ *     @tcph: the TCP header of the packet
+ *
+ *     Returns true if a TCP packet is eligible for LRO.  This requires that
+ *     the packet have only the ACK flag set and no TCP options besides
+ *     time stamps.
+ */
+static inline int lro_segment_ok(const struct tcphdr *tcph)
+{
+       int optlen;
+
+       if (unlikely((tcp_flag_word(tcph) & TCP_FLAG_MASK) != TCP_FLAG_ACK))
+               return 0;
+
+       optlen = (tcph->doff << 2) - sizeof(*tcph);
+       if (optlen) {
+               const u32 *opt = (const u32 *)(tcph + 1);
+
+               if (optlen != TCPOLEN_TSTAMP_ALIGNED ||
+                   *opt != htonl(TSTAMP_WORD) || !opt[2])
+                       return 0;
+       }
+       return 1;
+}
+
+static int t3_get_lro_header(void **eh,  void **iph, void **tcph,
+                            u64 *hdr_flags, void *priv)
+{
+       const struct cpl_rx_pkt *cpl = priv;
+
+       if (!lro_frame_ok(cpl))
+               return -1;
+
+       *eh = (struct ethhdr *)(cpl + 1);
+       *iph = (struct iphdr *)((struct ethhdr *)*eh + 1);
+       *tcph = (struct tcphdr *)((struct iphdr *)*iph + 1);
+
+        if (!lro_segment_ok(*tcph))
+               return -1;
+
+       *hdr_flags = LRO_IPV4 | LRO_TCP;
+       return 0;
+}
+
+static int t3_get_skb_header(struct sk_buff *skb,
+                             void **iph, void **tcph, u64 *hdr_flags,
+                             void *priv)
+{
+       void *eh;
+
+       return t3_get_lro_header(&eh, iph, tcph, hdr_flags, priv);
+}
+
+static int t3_get_frag_header(struct skb_frag_struct *frag, void **eh,
+                             void **iph, void **tcph, u64 *hdr_flags,
+                             void *priv)
+{
+       return t3_get_lro_header(eh, iph, tcph, hdr_flags, priv);
+}
+
+/**
+ *     lro_add_page - add a page chunk to an LRO session
+ *     @adap: the adapter
+ *     @qs: the associated queue set
+ *     @fl: the free list containing the page chunk to add
+ *     @len: packet length
+ *     @complete: Indicates the last fragment of a frame
+ *
+ *     Add a received packet contained in a page chunk to an existing LRO
+ *     session.
+ */
+static void lro_add_page(struct adapter *adap, struct sge_qset *qs,
+                        struct sge_fl *fl, int len, int complete)
+{
+       struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
+       struct cpl_rx_pkt *cpl;
+       struct skb_frag_struct *rx_frag = qs->lro_frag_tbl;
+       int nr_frags = qs->lro_nfrags, frag_len = qs->lro_frag_len;
+       int offset = 0;
+
+       if (!nr_frags) {
+               offset = 2 + sizeof(struct cpl_rx_pkt);
+               qs->lro_va = cpl = sd->pg_chunk.va + 2;
+       }
+
+       fl->credits--;
+
+       len -= offset;
+       pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr),
+                        fl->buf_size, PCI_DMA_FROMDEVICE);
+
+       rx_frag += nr_frags;
+       rx_frag->page = sd->pg_chunk.page;
+       rx_frag->page_offset = sd->pg_chunk.offset + offset;
+       rx_frag->size = len;
+       frag_len += len;
+       qs->lro_nfrags++;
+       qs->lro_frag_len = frag_len;
+
+       if (!complete)
+               return;
+
+       qs->lro_nfrags = qs->lro_frag_len = 0;
+       cpl = qs->lro_va;
+
+       if (unlikely(cpl->vlan_valid)) {
+               struct net_device *dev = qs->netdev;
+               struct port_info *pi = netdev_priv(dev);
+               struct vlan_group *grp = pi->vlan_grp;
+
+               if (likely(grp != NULL)) {
+                       lro_vlan_hwaccel_receive_frags(&qs->lro_mgr,
+                                                      qs->lro_frag_tbl,
+                                                      frag_len, frag_len,
+                                                      grp, ntohs(cpl->vlan),
+                                                      cpl, 0);
+                       return;
+               }
+       }
+       lro_receive_frags(&qs->lro_mgr, qs->lro_frag_tbl,
+                         frag_len, frag_len, cpl, 0);
+}
+
+/**
+ *     init_lro_mgr - initialize a LRO manager object
+ *     @lro_mgr: the LRO manager object
+ */
+static void init_lro_mgr(struct sge_qset *qs, struct net_lro_mgr *lro_mgr)
+{
+       lro_mgr->dev = qs->netdev;
+       lro_mgr->features = LRO_F_NAPI;
+       lro_mgr->ip_summed = CHECKSUM_UNNECESSARY;
+       lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY;
+       lro_mgr->max_desc = T3_MAX_LRO_SES;
+       lro_mgr->lro_arr = qs->lro_desc;
+       lro_mgr->get_frag_header = t3_get_frag_header;
+       lro_mgr->get_skb_header = t3_get_skb_header;
+       lro_mgr->max_aggr = T3_MAX_LRO_MAX_PKTS;
+       if (lro_mgr->max_aggr > MAX_SKB_FRAGS)
+               lro_mgr->max_aggr = MAX_SKB_FRAGS;
+}
+
 /**
  *     handle_rsp_cntrl_info - handles control information in a response
  *     @qs: the queue set corresponding to the response
@@ -1947,6 +2171,12 @@ static inline int is_new_response(const struct rsp_desc *r,
        return (r->intr_gen & F_RSPD_GEN2) == q->gen;
 }
 
+static inline void clear_rspq_bufstate(struct sge_rspq * const q)
+{
+       q->pg_skb = NULL;
+       q->rx_recycle_buf = 0;
+}
+
 #define RSPD_GTS_MASK  (F_RSPD_TXQ0_GTS | F_RSPD_TXQ1_GTS)
 #define RSPD_CTRL_MASK (RSPD_GTS_MASK | \
                        V_RSPD_TXQ0_CR(M_RSPD_TXQ0_CR) | \
@@ -1984,10 +2214,11 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs,
        q->next_holdoff = q->holdoff_tmr;
 
        while (likely(budget_left && is_new_response(r, q))) {
-               int eth, ethpad = 2;
+               int packet_complete, eth, ethpad = 2, lro = qs->lro_enabled;
                struct sk_buff *skb = NULL;
                u32 len, flags = ntohl(r->flags);
-               __be32 rss_hi = *(const __be32 *)r, rss_lo = r->rss_hdr.rss_hash_val;
+               __be32 rss_hi = *(const __be32 *)r,
+                      rss_lo = r->rss_hdr.rss_hash_val;
 
                eth = r->rss_hdr.opcode == CPL_RX_PKT;
 
@@ -2015,6 +2246,9 @@ no_mem:
                } else if ((len = ntohl(r->len_cq)) != 0) {
                        struct sge_fl *fl;
 
+                       if (eth)
+                               lro = qs->lro_enabled && is_eth_tcp(rss_hi);
+
                        fl = (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0];
                        if (fl->use_pages) {
                                void *addr = fl->sdesc[fl->cidx].pg_chunk.va;
@@ -2024,9 +2258,18 @@ no_mem:
                                prefetch(addr + L1_CACHE_BYTES);
 #endif
                                __refill_fl(adap, fl);
+                               if (lro > 0) {
+                                       lro_add_page(adap, qs, fl,
+                                                    G_RSPD_LEN(len),
+                                                    flags & F_RSPD_EOP);
+                                        goto next_fl;
+                               }
 
-                               skb = get_packet_pg(adap, fl, G_RSPD_LEN(len),
-                                                eth ? SGE_RX_DROP_THRES : 0);
+                               skb = get_packet_pg(adap, fl, q,
+                                                   G_RSPD_LEN(len),
+                                                   eth ?
+                                                   SGE_RX_DROP_THRES : 0);
+                               q->pg_skb = skb;
                        } else
                                skb = get_packet(adap, fl, G_RSPD_LEN(len),
                                                 eth ? SGE_RX_DROP_THRES : 0);
@@ -2036,7 +2279,7 @@ no_mem:
                                q->rx_drops++;
                        } else if (unlikely(r->rss_hdr.opcode == CPL_TRACE_PKT))
                                __skb_pull(skb, 2);
-
+next_fl:
                        if (++fl->cidx == fl->size)
                                fl->cidx = 0;
                } else
@@ -2060,9 +2303,13 @@ no_mem:
                        q->credits = 0;
                }
 
-               if (likely(skb != NULL)) {
+               packet_complete = flags &
+                                 (F_RSPD_EOP | F_RSPD_IMM_DATA_VALID |
+                                  F_RSPD_ASYNC_NOTIF);
+
+               if (skb != NULL && packet_complete) {
                        if (eth)
-                               rx_eth(adap, q, skb, ethpad);
+                               rx_eth(adap, q, skb, ethpad, lro);
                        else {
                                q->offload_pkts++;
                                /* Preserve the RSS info in csum & priority */
@@ -2072,11 +2319,19 @@ no_mem:
                                                       offload_skbs,
                                                       ngathered);
                        }
+
+                       if (flags & F_RSPD_EOP)
+                               clear_rspq_bufstate(q);
                }
                --budget_left;
        }
 
        deliver_partial_bundle(&adap->tdev, q, offload_skbs, ngathered);
+       lro_flush_all(&qs->lro_mgr);
+       qs->port_stats[SGE_PSTAT_LRO_AGGR] = qs->lro_mgr.stats.aggregated;
+       qs->port_stats[SGE_PSTAT_LRO_FLUSHED] = qs->lro_mgr.stats.flushed;
+       qs->port_stats[SGE_PSTAT_LRO_NO_DESC] = qs->lro_mgr.stats.no_desc;
+
        if (sleeping)
                check_ring_db(adap, qs, sleeping);
 
@@ -2618,8 +2873,9 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
                      int irq_vec_idx, const struct qset_params *p,
                      int ntxq, struct net_device *dev)
 {
-       int i, ret = -ENOMEM;
+       int i, avail, ret = -ENOMEM;
        struct sge_qset *q = &adapter->sge.qs[id];
+       struct net_lro_mgr *lro_mgr = &q->lro_mgr;
 
        init_qset_cntxt(q, id);
        init_timer(&q->tx_reclaim_timer);
@@ -2687,11 +2943,23 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
 #else
        q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + sizeof(struct cpl_rx_data);
 #endif
-       q->fl[0].use_pages = FL0_PG_CHUNK_SIZE > 0;
+#if FL1_PG_CHUNK_SIZE > 0
+       q->fl[1].buf_size = FL1_PG_CHUNK_SIZE;
+#else
        q->fl[1].buf_size = is_offload(adapter) ?
                (16 * 1024) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) :
                MAX_FRAME_SIZE + 2 + sizeof(struct cpl_rx_pkt);
+#endif
 
+       q->fl[0].use_pages = FL0_PG_CHUNK_SIZE > 0;
+       q->fl[1].use_pages = FL1_PG_CHUNK_SIZE > 0;
+       q->fl[0].order = FL0_PG_ORDER;
+       q->fl[1].order = FL1_PG_ORDER;
+
+       q->lro_frag_tbl = kcalloc(MAX_FRAME_SIZE / FL1_PG_CHUNK_SIZE + 1,
+                                 sizeof(struct skb_frag_struct),
+                                 GFP_KERNEL);
+       q->lro_nfrags = q->lro_frag_len = 0;
        spin_lock_irq(&adapter->sge.reg_lock);
 
        /* FL threshold comparison uses < */
@@ -2742,8 +3010,23 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
        q->netdev = dev;
        t3_update_qset_coalesce(q, p);
 
-       refill_fl(adapter, &q->fl[0], q->fl[0].size, GFP_KERNEL);
-       refill_fl(adapter, &q->fl[1], q->fl[1].size, GFP_KERNEL);
+       init_lro_mgr(q, lro_mgr);
+
+       avail = refill_fl(adapter, &q->fl[0], q->fl[0].size,
+                         GFP_KERNEL | __GFP_COMP);
+       if (!avail) {
+               CH_ALERT(adapter, "free list queue 0 initialization failed\n");
+               goto err;
+       }
+       if (avail < q->fl[0].size)
+               CH_WARN(adapter, "free list queue 0 enabled with %d credits\n",
+                       avail);
+
+       avail = refill_fl(adapter, &q->fl[1], q->fl[1].size,
+                         GFP_KERNEL | __GFP_COMP);
+       if (avail < q->fl[1].size)
+               CH_WARN(adapter, "free list queue 1 enabled with %d credits\n",
+                       avail);
        refill_rspq(adapter, &q->rspq, q->rspq.size - 1);
 
        t3_write_reg(adapter, A_SG_GTS, V_RSPQ(q->rspq.cntxt_id) |
@@ -2752,9 +3035,9 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
        mod_timer(&q->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD);
        return 0;
 
-      err_unlock:
+err_unlock:
        spin_unlock_irq(&adapter->sge.reg_lock);
-      err:
+err:
        t3_free_qset(adapter, q);
        return ret;
 }
@@ -2876,7 +3159,7 @@ void t3_sge_prep(struct adapter *adap, struct sge_params *p)
                q->coalesce_usecs = 5;
                q->rspq_size = 1024;
                q->fl_size = 1024;
-               q->jumbo_size = 512;
+               q->jumbo_size = 512;
                q->txq_size[TXQ_ETH] = 1024;
                q->txq_size[TXQ_OFLD] = 1024;
                q->txq_size[TXQ_CTRL] = 256;
index b7a1a310dfd4e3b615cfcfb9096ba830a4008119..a666c5d51cc0656bdf449cdd6d34f1fc8d2852c5 100644 (file)
@@ -174,6 +174,13 @@ enum {                             /* TCP congestion control algorithms */
        CONG_ALG_HIGHSPEED
 };
 
+enum {                 /* RSS hash type */
+       RSS_HASH_NONE = 0,
+       RSS_HASH_2_TUPLE = 1,
+       RSS_HASH_4_TUPLE = 2,
+       RSS_HASH_TCPV6 = 3
+};
+
 union opcode_tid {
        __be32 opcode_tid;
        __u8 opcode;
@@ -184,6 +191,10 @@ union opcode_tid {
 #define G_OPCODE(x) (((x) >> S_OPCODE) & 0xFF)
 #define G_TID(x)    ((x) & 0xFFFFFF)
 
+#define S_HASHTYPE 22
+#define M_HASHTYPE 0x3
+#define G_HASHTYPE(x) (((x) >> S_HASHTYPE) & M_HASHTYPE)
+
 /* tid is assumed to be 24-bits */
 #define MK_OPCODE_TID(opcode, tid) (V_OPCODE(opcode) | (tid))
 
index e233d04a2132fcca328f3000dd546df963b7a356..8277e89e552d076c200539c4c52da49f983fa27c 100644 (file)
@@ -499,7 +499,7 @@ rio_timer (unsigned long data)
                        entry = np->old_rx % RX_RING_SIZE;
                        /* Dropped packets don't need to re-allocate */
                        if (np->rx_skbuff[entry] == NULL) {
-                               skb = dev_alloc_skb (np->rx_buf_sz);
+                               skb = netdev_alloc_skb (dev, np->rx_buf_sz);
                                if (skb == NULL) {
                                        np->rx_ring[entry].fraginfo = 0;
                                        printk (KERN_INFO
@@ -570,7 +570,7 @@ alloc_list (struct net_device *dev)
        /* Allocate the rx buffers */
        for (i = 0; i < RX_RING_SIZE; i++) {
                /* Allocated fixed size of skbuff */
-               struct sk_buff *skb = dev_alloc_skb (np->rx_buf_sz);
+               struct sk_buff *skb = netdev_alloc_skb (dev, np->rx_buf_sz);
                np->rx_skbuff[i] = skb;
                if (skb == NULL) {
                        printk (KERN_ERR
@@ -867,7 +867,7 @@ receive_packet (struct net_device *dev)
                                                  PCI_DMA_FROMDEVICE);
                                skb_put (skb = np->rx_skbuff[entry], pkt_len);
                                np->rx_skbuff[entry] = NULL;
-                       } else if ((skb = dev_alloc_skb (pkt_len + 2)) != NULL) {
+                       } else if ((skb = netdev_alloc_skb(dev, pkt_len + 2))) {
                                pci_dma_sync_single_for_cpu(np->pdev,
                                                            desc_to_dma(desc),
                                                            np->rx_buf_sz,
@@ -904,7 +904,7 @@ receive_packet (struct net_device *dev)
                struct sk_buff *skb;
                /* Dropped packets don't need to re-allocate */
                if (np->rx_skbuff[entry] == NULL) {
-                       skb = dev_alloc_skb (np->rx_buf_sz);
+                       skb = netdev_alloc_skb(dev, np->rx_buf_sz);
                        if (skb == NULL) {
                                np->rx_ring[entry].fraginfo = 0;
                                printk (KERN_INFO
index 864295e081b6756ae5ab5dec094db909235a5ae1..08a7365a7d1051268c0b9b63cd3e410119a55d26 100644 (file)
@@ -718,7 +718,7 @@ dm9000_probe(struct platform_device *pdev)
 
        if (!is_valid_ether_addr(ndev->dev_addr)) {
                /* try reading from mac */
-               
+
                mac_src = "chip";
                for (i = 0; i < 6; i++)
                        ndev->dev_addr[i] = ior(db, i+DM9000_PAR);
@@ -768,7 +768,7 @@ dm9000_open(struct net_device *dev)
                dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");
                irqflags = DEFAULT_TRIGGER;
        }
-       
+
        irqflags |= IRQF_SHARED;
 
        if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev))
@@ -1115,7 +1115,7 @@ static int dm9000_wait_eeprom(board_info_t *db)
        /* The DM9000 data sheets say we should be able to
         * poll the ERRE bit in EPCR to wait for the EEPROM
         * operation. From testing several chips, this bit
-        * does not seem to work. 
+        * does not seem to work.
         *
         * We attempt to use the bit, but fall back to the
         * timeout (which is why we do not return an error
index 9eca97fb0a54ab58b35eba4ae3aff614e7d4233d..e4d697894364cc247ec4413a627c9c66668d16eb 100644 (file)
@@ -426,6 +426,7 @@ union ring_type {
 #define NV_PCI_REGSZ_VER1              0x270
 #define NV_PCI_REGSZ_VER2              0x2d4
 #define NV_PCI_REGSZ_VER3              0x604
+#define NV_PCI_REGSZ_MAX               0x604
 
 /* various timeout delays: all in usec */
 #define NV_TXRX_RESET_DELAY    4
@@ -784,6 +785,9 @@ struct fe_priv {
 
        /* flow control */
        u32 pause_flags;
+
+       /* power saved state */
+       u32 saved_config_space[NV_PCI_REGSZ_MAX/4];
 };
 
 /*
@@ -5785,50 +5789,66 @@ static int nv_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
        struct fe_priv *np = netdev_priv(dev);
+       u8 __iomem *base = get_hwbase(dev);
+       int i;
 
-       if (!netif_running(dev))
-               goto out;
-
+       if (netif_running(dev)) {
+               // Gross.
+               nv_close(dev);
+       }
        netif_device_detach(dev);
 
-       // Gross.
-       nv_close(dev);
+       /* save non-pci configuration space */
+       for (i = 0;i <= np->register_size/sizeof(u32); i++)
+               np->saved_config_space[i] = readl(base + i*sizeof(u32));
 
        pci_save_state(pdev);
        pci_enable_wake(pdev, pci_choose_state(pdev, state), np->wolenabled);
+       pci_disable_device(pdev);
        pci_set_power_state(pdev, pci_choose_state(pdev, state));
-out:
        return 0;
 }
 
 static int nv_resume(struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
+       struct fe_priv *np = netdev_priv(dev);
        u8 __iomem *base = get_hwbase(dev);
-       int rc = 0;
-       u32 txreg;
-
-       if (!netif_running(dev))
-               goto out;
-
-       netif_device_attach(dev);
+       int i, rc = 0;
 
        pci_set_power_state(pdev, PCI_D0);
        pci_restore_state(pdev);
+       /* ack any pending wake events, disable PME */
        pci_enable_wake(pdev, PCI_D0, 0);
 
-       /* restore mac address reverse flag */
-       txreg = readl(base + NvRegTransmitPoll);
-       txreg |= NVREG_TRANSMITPOLL_MAC_ADDR_REV;
-       writel(txreg, base + NvRegTransmitPoll);
+       /* restore non-pci configuration space */
+       for (i = 0;i <= np->register_size/sizeof(u32); i++)
+               writel(np->saved_config_space[i], base+i*sizeof(u32));
 
-       rc = nv_open(dev);
-       nv_set_multicast(dev);
-out:
+       netif_device_attach(dev);
+       if (netif_running(dev)) {
+               rc = nv_open(dev);
+               nv_set_multicast(dev);
+       }
        return rc;
 }
+
+static void nv_shutdown(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct fe_priv *np = netdev_priv(dev);
+
+       if (netif_running(dev))
+               nv_close(dev);
+
+       pci_enable_wake(pdev, PCI_D3hot, np->wolenabled);
+       pci_enable_wake(pdev, PCI_D3cold, np->wolenabled);
+       pci_disable_device(pdev);
+       pci_set_power_state(pdev, PCI_D3hot);
+}
 #else
 #define nv_suspend NULL
+#define nv_shutdown NULL
 #define nv_resume NULL
 #endif /* CONFIG_PM */
 
@@ -5999,6 +6019,7 @@ static struct pci_driver driver = {
        .remove         = __devexit_p(nv_remove),
        .suspend        = nv_suspend,
        .resume         = nv_resume,
+       .shutdown       = nv_shutdown,
 };
 
 static int __init init_nic(void)
index a5baaf59ff6660ded12ed97117fb164f3d71bf3d..fb7c47790bd6269ca4149dbc168bbcaf606f3f88 100644 (file)
@@ -43,6 +43,7 @@
 #include <asm/uaccess.h>
 
 #ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <linux/of_gpio.h>
 #include <asm/of_platform.h>
 #endif
 
@@ -1172,8 +1173,7 @@ static int __devinit find_phy(struct device_node *np,
                               struct fs_platform_info *fpi)
 {
        struct device_node *phynode, *mdionode;
-       struct resource res;
-       int ret = 0, len;
+       int ret = 0, len, bus_id;
        const u32 *data;
 
        data  = of_get_property(np, "fixed-link", NULL);
@@ -1190,19 +1190,28 @@ static int __devinit find_phy(struct device_node *np,
        if (!phynode)
                return -EINVAL;
 
-       mdionode = of_get_parent(phynode);
-       if (!mdionode)
+       data = of_get_property(phynode, "reg", &len);
+       if (!data || len != 4) {
+               ret = -EINVAL;
                goto out_put_phy;
+       }
 
-       ret = of_address_to_resource(mdionode, 0, &res);
-       if (ret)
-               goto out_put_mdio;
+       mdionode = of_get_parent(phynode);
+       if (!mdionode) {
+               ret = -EINVAL;
+               goto out_put_phy;
+       }
 
-       data = of_get_property(phynode, "reg", &len);
-       if (!data || len != 4)
-               goto out_put_mdio;
+       bus_id = of_get_gpio(mdionode, 0);
+       if (bus_id < 0) {
+               struct resource res;
+               ret = of_address_to_resource(mdionode, 0, &res);
+               if (ret)
+                       goto out_put_mdio;
+               bus_id = res.start;
+       }
 
-       snprintf(fpi->bus_id, 16, "%x:%02x", res.start, *data);
+       snprintf(fpi->bus_id, 16, "%x:%02x", bus_id, *data);
 
 out_put_mdio:
        of_node_put(mdionode);
index 25bdd0832df5752f4f0de2a23b8df710d0ee83ce..393a0f1753021f0d48164a75b410ce646f6095c0 100644 (file)
@@ -928,7 +928,7 @@ rx_irq_fail:
 tx_irq_fail:
        free_irq(priv->interruptError, dev);
 err_irq_fail:
-err_rxalloc_fail:      
+err_rxalloc_fail:
 rx_skb_fail:
        free_skb_resources(priv);
 tx_skb_fail:
index e5c2380f50ca0ef8c45d371a4eb69c69f671dbe4..3199526bcecbab3f879f9cd56507c570305a8c2f 100644 (file)
@@ -1140,11 +1140,11 @@ static void hamachi_tx_timeout(struct net_device *dev)
        }
        /* Fill in the Rx buffers.  Handle allocation failure gracefully. */
        for (i = 0; i < RX_RING_SIZE; i++) {
-               struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz);
+               struct sk_buff *skb = netdev_alloc_skb(dev, hmp->rx_buf_sz);
                hmp->rx_skbuff[i] = skb;
                if (skb == NULL)
                        break;
-               skb->dev = dev;         /* Mark as being used by this device. */
+
                skb_reserve(skb, 2); /* 16 byte align the IP header. */
                 hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev,
                        skb->data, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE));
@@ -1178,14 +1178,6 @@ static void hamachi_init_ring(struct net_device *dev)
        hmp->cur_rx = hmp->cur_tx = 0;
        hmp->dirty_rx = hmp->dirty_tx = 0;
 
-#if 0
-       /* This is wrong.  I'm not sure what the original plan was, but this
-        * is wrong.  An MTU of 1 gets you a buffer of 1536, while an MTU
-        * of 1501 gets a buffer of 1533? -KDU
-        */
-       hmp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
-#endif
-       /* My attempt at a reasonable correction */
        /* +26 gets the maximum ethernet encapsulation, +7 & ~7 because the
         * card needs room to do 8 byte alignment, +2 so we can reserve
         * the first 2 bytes, and +16 gets room for the status word from the
index 9d5721287d6f50d7030499e4470b41a36f4cb6b5..06ad9f302b5a757fd8d9ddad2600807cca54c422 100644 (file)
@@ -99,9 +99,6 @@ struct sixpack {
        unsigned int            rx_count;
        unsigned int            rx_count_cooked;
 
-       /* 6pack interface statistics. */
-       struct net_device_stats stats;
-
        int                     mtu;            /* Our mtu (to spot changes!) */
        int                     buffsize;       /* Max buffers sizes */
 
@@ -237,7 +234,7 @@ static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len)
        return;
 
 out_drop:
-       sp->stats.tx_dropped++;
+       sp->dev->stats.tx_dropped++;
        netif_start_queue(sp->dev);
        if (net_ratelimit())
                printk(KERN_DEBUG "%s: %s - dropped.\n", sp->dev->name, msg);
@@ -252,7 +249,7 @@ static int sp_xmit(struct sk_buff *skb, struct net_device *dev)
        spin_lock_bh(&sp->lock);
        /* We were not busy, so we are now... :-) */
        netif_stop_queue(dev);
-       sp->stats.tx_bytes += skb->len;
+       dev->stats.tx_bytes += skb->len;
        sp_encaps(sp, skb->data, skb->len);
        spin_unlock_bh(&sp->lock);
 
@@ -298,12 +295,6 @@ static int sp_header(struct sk_buff *skb, struct net_device *dev,
        return 0;
 }
 
-static struct net_device_stats *sp_get_stats(struct net_device *dev)
-{
-       struct sixpack *sp = netdev_priv(dev);
-       return &sp->stats;
-}
-
 static int sp_set_mac_address(struct net_device *dev, void *addr)
 {
        struct sockaddr_ax25 *sa = addr;
@@ -338,7 +329,6 @@ static void sp_setup(struct net_device *dev)
        dev->destructor         = free_netdev;
        dev->stop               = sp_close;
 
-       dev->get_stats          = sp_get_stats;
        dev->set_mac_address    = sp_set_mac_address;
        dev->hard_header_len    = AX25_MAX_HEADER_LEN;
        dev->header_ops         = &sp_header_ops;
@@ -370,7 +360,7 @@ static void sp_bump(struct sixpack *sp, char cmd)
 
        count = sp->rcount + 1;
 
-       sp->stats.rx_bytes += count;
+       sp->dev->stats.rx_bytes += count;
 
        if ((skb = dev_alloc_skb(count)) == NULL)
                goto out_mem;
@@ -382,12 +372,12 @@ static void sp_bump(struct sixpack *sp, char cmd)
        skb->protocol = ax25_type_trans(skb, sp->dev);
        netif_rx(skb);
        sp->dev->last_rx = jiffies;
-       sp->stats.rx_packets++;
+       sp->dev->stats.rx_packets++;
 
        return;
 
 out_mem:
-       sp->stats.rx_dropped++;
+       sp->dev->stats.rx_dropped++;
 }
 
 
@@ -436,7 +426,7 @@ static void sixpack_write_wakeup(struct tty_struct *tty)
        if (sp->xleft <= 0)  {
                /* Now serial buffer is almost free & we can start
                 * transmission of another packet */
-               sp->stats.tx_packets++;
+               sp->dev->stats.tx_packets++;
                clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
                sp->tx_enable = 0;
                netif_wake_queue(sp->dev);
@@ -484,7 +474,7 @@ static void sixpack_receive_buf(struct tty_struct *tty,
                count--;
                if (fp && *fp++) {
                        if (!test_and_set_bit(SIXPF_ERROR, &sp->flags))
-                               sp->stats.rx_errors++;
+                               sp->dev->stats.rx_errors++;
                        continue;
                }
        }
index 484cb2ba717f97d1df4f84b43701a9b7cf7b4bca..7111c65f0b30e4b2e3e77f999cf500e6304bba2b 100644 (file)
@@ -108,14 +108,14 @@ static int ixpdev_rx(struct net_device *dev, int processed, int budget)
                if (unlikely(!netif_running(nds[desc->channel])))
                        goto err;
 
-               skb = dev_alloc_skb(desc->pkt_length + 2);
+               skb = netdev_alloc_skb(dev, desc->pkt_length + 2);
                if (likely(skb != NULL)) {
                        skb_reserve(skb, 2);
                        skb_copy_to_linear_data(skb, buf, desc->pkt_length);
                        skb_put(skb, desc->pkt_length);
                        skb->protocol = eth_type_trans(skb, nds[desc->channel]);
 
-                       skb->dev->last_rx = jiffies;
+                       dev->last_rx = jiffies;
 
                        netif_receive_skb(skb);
                }
index 0c5447dac03b4a483c8294fe2cfb3b23fab7f1e4..ed495275b57756bcc39f3c2b0b34a22d23d1c362 100644 (file)
@@ -150,19 +150,19 @@ static void __NS8390_init(struct net_device *dev, int startp);
  *     card means that approach caused horrible problems like losing serial data
  *     at 38400 baud on some chips. Remember many 8390 nics on PCI were ISA
  *     chips with FPGA front ends.
- *     
+ *
  *     Ok the logic behind the 8390 is very simple:
- *     
+ *
  *     Things to know
  *             - IRQ delivery is asynchronous to the PCI bus
  *             - Blocking the local CPU IRQ via spin locks was too slow
  *             - The chip has register windows needing locking work
- *     
+ *
  *     So the path was once (I say once as people appear to have changed it
  *     in the mean time and it now looks rather bogus if the changes to use
  *     disable_irq_nosync_irqsave are disabling the local IRQ)
- *     
- *     
+ *
+ *
  *             Take the page lock
  *             Mask the IRQ on chip
  *             Disable the IRQ (but not mask locally- someone seems to have
@@ -170,22 +170,22 @@ static void __NS8390_init(struct net_device *dev, int startp);
  *                     [This must be _nosync as the page lock may otherwise
  *                             deadlock us]
  *             Drop the page lock and turn IRQs back on
- *             
+ *
  *             At this point an existing IRQ may still be running but we can't
  *             get a new one
- *     
+ *
  *             Take the lock (so we know the IRQ has terminated) but don't mask
  *     the IRQs on the processor
  *             Set irqlock [for debug]
- *     
+ *
  *             Transmit (slow as ****)
- *     
+ *
  *             re-enable the IRQ
- *     
- *     
+ *
+ *
  *     We have to use disable_irq because otherwise you will get delayed
  *     interrupts on the APIC bus deadlocking the transmit path.
- *     
+ *
  *     Quite hairy but the chip simply wasn't designed for SMP and you can't
  *     even ACK an interrupt without risking corrupting other parallel
  *     activities on the chip." [lkml, 25 Jul 2007]
@@ -265,7 +265,7 @@ static void ei_tx_timeout(struct net_device *dev)
        int txsr, isr, tickssofar = jiffies - dev->trans_start;
        unsigned long flags;
 
-       ei_local->stat.tx_errors++;
+       dev->stats.tx_errors++;
 
        spin_lock_irqsave(&ei_local->page_lock, flags);
        txsr = ei_inb(e8390_base+EN0_TSR);
@@ -276,7 +276,7 @@ static void ei_tx_timeout(struct net_device *dev)
                dev->name, (txsr & ENTSR_ABT) ? "excess collisions." :
                (isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar);
 
-       if (!isr && !ei_local->stat.tx_packets)
+       if (!isr && !dev->stats.tx_packets)
        {
                /* The 8390 probably hasn't gotten on the cable yet. */
                ei_local->interface_num ^= 1;   /* Try a different xcvr.  */
@@ -374,7 +374,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
                ei_outb_p(ENISR_ALL, e8390_base + EN0_IMR);
                spin_unlock(&ei_local->page_lock);
                enable_irq_lockdep_irqrestore(dev->irq, &flags);
-               ei_local->stat.tx_errors++;
+               dev->stats.tx_errors++;
                return 1;
        }
 
@@ -417,7 +417,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
        enable_irq_lockdep_irqrestore(dev->irq, &flags);
 
        dev_kfree_skb (skb);
-       ei_local->stat.tx_bytes += send_length;
+       dev->stats.tx_bytes += send_length;
 
        return 0;
 }
@@ -493,9 +493,9 @@ static irqreturn_t __ei_interrupt(int irq, void *dev_id)
 
                if (interrupts & ENISR_COUNTERS)
                {
-                       ei_local->stat.rx_frame_errors += ei_inb_p(e8390_base + EN0_COUNTER0);
-                       ei_local->stat.rx_crc_errors   += ei_inb_p(e8390_base + EN0_COUNTER1);
-                       ei_local->stat.rx_missed_errors+= ei_inb_p(e8390_base + EN0_COUNTER2);
+                       dev->stats.rx_frame_errors += ei_inb_p(e8390_base + EN0_COUNTER0);
+                       dev->stats.rx_crc_errors   += ei_inb_p(e8390_base + EN0_COUNTER1);
+                       dev->stats.rx_missed_errors+= ei_inb_p(e8390_base + EN0_COUNTER2);
                        ei_outb_p(ENISR_COUNTERS, e8390_base + EN0_ISR); /* Ack intr. */
                }
 
@@ -553,7 +553,6 @@ static void __ei_poll(struct net_device *dev)
 static void ei_tx_err(struct net_device *dev)
 {
        unsigned long e8390_base = dev->base_addr;
-       struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
        unsigned char txsr = ei_inb_p(e8390_base+EN0_TSR);
        unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU);
 
@@ -578,10 +577,10 @@ static void ei_tx_err(struct net_device *dev)
                ei_tx_intr(dev);
        else
        {
-               ei_local->stat.tx_errors++;
-               if (txsr & ENTSR_CRS) ei_local->stat.tx_carrier_errors++;
-               if (txsr & ENTSR_CDH) ei_local->stat.tx_heartbeat_errors++;
-               if (txsr & ENTSR_OWC) ei_local->stat.tx_window_errors++;
+               dev->stats.tx_errors++;
+               if (txsr & ENTSR_CRS) dev->stats.tx_carrier_errors++;
+               if (txsr & ENTSR_CDH) dev->stats.tx_heartbeat_errors++;
+               if (txsr & ENTSR_OWC) dev->stats.tx_window_errors++;
        }
 }
 
@@ -645,25 +644,25 @@ static void ei_tx_intr(struct net_device *dev)
 
        /* Minimize Tx latency: update the statistics after we restart TXing. */
        if (status & ENTSR_COL)
-               ei_local->stat.collisions++;
+               dev->stats.collisions++;
        if (status & ENTSR_PTX)
-               ei_local->stat.tx_packets++;
+               dev->stats.tx_packets++;
        else
        {
-               ei_local->stat.tx_errors++;
+               dev->stats.tx_errors++;
                if (status & ENTSR_ABT)
                {
-                       ei_local->stat.tx_aborted_errors++;
-                       ei_local->stat.collisions += 16;
+                       dev->stats.tx_aborted_errors++;
+                       dev->stats.collisions += 16;
                }
                if (status & ENTSR_CRS)
-                       ei_local->stat.tx_carrier_errors++;
+                       dev->stats.tx_carrier_errors++;
                if (status & ENTSR_FU)
-                       ei_local->stat.tx_fifo_errors++;
+                       dev->stats.tx_fifo_errors++;
                if (status & ENTSR_CDH)
-                       ei_local->stat.tx_heartbeat_errors++;
+                       dev->stats.tx_heartbeat_errors++;
                if (status & ENTSR_OWC)
-                       ei_local->stat.tx_window_errors++;
+                       dev->stats.tx_window_errors++;
        }
        netif_wake_queue(dev);
 }
@@ -730,7 +729,7 @@ static void ei_receive(struct net_device *dev)
                        && rx_frame.next != next_frame + 1 - num_rx_pages) {
                        ei_local->current_page = rxing_page;
                        ei_outb(ei_local->current_page-1, e8390_base+EN0_BOUNDARY);
-                       ei_local->stat.rx_errors++;
+                       dev->stats.rx_errors++;
                        continue;
                }
 
@@ -740,8 +739,8 @@ static void ei_receive(struct net_device *dev)
                                printk(KERN_DEBUG "%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n",
                                           dev->name, rx_frame.count, rx_frame.status,
                                           rx_frame.next);
-                       ei_local->stat.rx_errors++;
-                       ei_local->stat.rx_length_errors++;
+                       dev->stats.rx_errors++;
+                       dev->stats.rx_length_errors++;
                }
                 else if ((pkt_stat & 0x0F) == ENRSR_RXOK)
                {
@@ -753,7 +752,7 @@ static void ei_receive(struct net_device *dev)
                                if (ei_debug > 1)
                                        printk(KERN_DEBUG "%s: Couldn't allocate a sk_buff of size %d.\n",
                                                   dev->name, pkt_len);
-                               ei_local->stat.rx_dropped++;
+                               dev->stats.rx_dropped++;
                                break;
                        }
                        else
@@ -764,10 +763,10 @@ static void ei_receive(struct net_device *dev)
                                skb->protocol=eth_type_trans(skb,dev);
                                netif_rx(skb);
                                dev->last_rx = jiffies;
-                               ei_local->stat.rx_packets++;
-                               ei_local->stat.rx_bytes += pkt_len;
+                               dev->stats.rx_packets++;
+                               dev->stats.rx_bytes += pkt_len;
                                if (pkt_stat & ENRSR_PHY)
-                                       ei_local->stat.multicast++;
+                                       dev->stats.multicast++;
                        }
                }
                else
@@ -776,10 +775,10 @@ static void ei_receive(struct net_device *dev)
                                printk(KERN_DEBUG "%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n",
                                           dev->name, rx_frame.status, rx_frame.next,
                                           rx_frame.count);
-                       ei_local->stat.rx_errors++;
+                       dev->stats.rx_errors++;
                        /* NB: The NIC counts CRC, frame and missed errors. */
                        if (pkt_stat & ENRSR_FO)
-                               ei_local->stat.rx_fifo_errors++;
+                               dev->stats.rx_fifo_errors++;
                }
                next_frame = rx_frame.next;
 
@@ -816,7 +815,6 @@ static void ei_rx_overrun(struct net_device *dev)
 {
        unsigned long e8390_base = dev->base_addr;
        unsigned char was_txing, must_resend = 0;
-       struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
 
        /*
         * Record whether a Tx was in progress and then issue the
@@ -827,7 +825,7 @@ static void ei_rx_overrun(struct net_device *dev)
 
        if (ei_debug > 1)
                printk(KERN_DEBUG "%s: Receiver overrun.\n", dev->name);
-       ei_local->stat.rx_over_errors++;
+       dev->stats.rx_over_errors++;
 
        /*
         * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total.
@@ -889,16 +887,16 @@ static struct net_device_stats *get_stats(struct net_device *dev)
 
        /* If the card is stopped, just return the present stats. */
        if (!netif_running(dev))
-               return &ei_local->stat;
+               return &dev->stats;
 
        spin_lock_irqsave(&ei_local->page_lock,flags);
        /* Read the counter registers, assuming we are in page 0. */
-       ei_local->stat.rx_frame_errors += ei_inb_p(ioaddr + EN0_COUNTER0);
-       ei_local->stat.rx_crc_errors   += ei_inb_p(ioaddr + EN0_COUNTER1);
-       ei_local->stat.rx_missed_errors+= ei_inb_p(ioaddr + EN0_COUNTER2);
+       dev->stats.rx_frame_errors += ei_inb_p(ioaddr + EN0_COUNTER0);
+       dev->stats.rx_crc_errors   += ei_inb_p(ioaddr + EN0_COUNTER1);
+       dev->stats.rx_missed_errors+= ei_inb_p(ioaddr + EN0_COUNTER2);
        spin_unlock_irqrestore(&ei_local->page_lock, flags);
 
-       return &ei_local->stat;
+       return &dev->stats;
 }
 
 /*
index e0d76c75aea0f6af724da31864c1ab2c58a356c4..9a68d2ea5f3eb10902e067cf5fc5f4585094b038 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/if_ether.h>
 #include <linux/if_vlan.h>
 #include <linux/inet_lro.h>
+#include <linux/dca.h>
 #include <linux/ip.h>
 #include <linux/inet.h>
 #include <linux/in.h>
@@ -185,11 +186,18 @@ struct myri10ge_slice_state {
        dma_addr_t fw_stats_bus;
        int watchdog_tx_done;
        int watchdog_tx_req;
+#ifdef CONFIG_DCA
+       int cached_dca_tag;
+       int cpu;
+       __be32 __iomem *dca_tag;
+#endif
+       char irq_desc[32];
 };
 
 struct myri10ge_priv {
-       struct myri10ge_slice_state ss;
+       struct myri10ge_slice_state *ss;
        int tx_boundary;        /* boundary transmits cannot cross */
+       int num_slices;
        int running;            /* running?             */
        int csum_flag;          /* rx_csums?            */
        int small_bytes;
@@ -208,6 +216,11 @@ struct myri10ge_priv {
        dma_addr_t cmd_bus;
        struct pci_dev *pdev;
        int msi_enabled;
+       int msix_enabled;
+       struct msix_entry *msix_vectors;
+#ifdef CONFIG_DCA
+       int dca_enabled;
+#endif
        u32 link_state;
        unsigned int rdma_tags_available;
        int intr_coal_delay;
@@ -244,6 +257,8 @@ struct myri10ge_priv {
 
 static char *myri10ge_fw_unaligned = "myri10ge_ethp_z8e.dat";
 static char *myri10ge_fw_aligned = "myri10ge_eth_z8e.dat";
+static char *myri10ge_fw_rss_unaligned = "myri10ge_rss_ethp_z8e.dat";
+static char *myri10ge_fw_rss_aligned = "myri10ge_rss_eth_z8e.dat";
 
 static char *myri10ge_fw_name = NULL;
 module_param(myri10ge_fw_name, charp, S_IRUGO | S_IWUSR);
@@ -321,6 +336,18 @@ static int myri10ge_wcfifo = 0;
 module_param(myri10ge_wcfifo, int, S_IRUGO);
 MODULE_PARM_DESC(myri10ge_wcfifo, "Enable WC Fifo when WC is enabled");
 
+static int myri10ge_max_slices = 1;
+module_param(myri10ge_max_slices, int, S_IRUGO);
+MODULE_PARM_DESC(myri10ge_max_slices, "Max tx/rx queues");
+
+static int myri10ge_rss_hash = MXGEFW_RSS_HASH_TYPE_SRC_PORT;
+module_param(myri10ge_rss_hash, int, S_IRUGO);
+MODULE_PARM_DESC(myri10ge_rss_hash, "Type of RSS hashing to do");
+
+static int myri10ge_dca = 1;
+module_param(myri10ge_dca, int, S_IRUGO);
+MODULE_PARM_DESC(myri10ge_dca, "Enable DCA if possible");
+
 #define MYRI10GE_FW_OFFSET 1024*1024
 #define MYRI10GE_HIGHPART_TO_U32(X) \
 (sizeof (X) == 8) ? ((u32)((u64)(X) >> 32)) : (0)
@@ -657,7 +684,7 @@ static int myri10ge_get_firmware_capabilities(struct myri10ge_priv *mgp)
        return 0;
 }
 
-static int myri10ge_load_firmware(struct myri10ge_priv *mgp)
+static int myri10ge_load_firmware(struct myri10ge_priv *mgp, int adopt)
 {
        char __iomem *submit;
        __be32 buf[16] __attribute__ ((__aligned__(8)));
@@ -667,6 +694,8 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp)
        size = 0;
        status = myri10ge_load_hotplug_firmware(mgp, &size);
        if (status) {
+               if (!adopt)
+                       return status;
                dev_warn(&mgp->pdev->dev, "hotplug firmware loading failed\n");
 
                /* Do not attempt to adopt firmware if there
@@ -859,8 +888,12 @@ abort:
 static int myri10ge_reset(struct myri10ge_priv *mgp)
 {
        struct myri10ge_cmd cmd;
-       int status;
+       struct myri10ge_slice_state *ss;
+       int i, status;
        size_t bytes;
+#ifdef CONFIG_DCA
+       unsigned long dca_tag_off;
+#endif
 
        /* try to send a reset command to the card to see if it
         * is alive */
@@ -872,20 +905,74 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
        }
 
        (void)myri10ge_dma_test(mgp, MXGEFW_DMA_TEST);
+       /*
+        * Use non-ndis mcp_slot (eg, 4 bytes total,
+        * no toeplitz hash value returned.  Older firmware will
+        * not understand this command, but will use the correct
+        * sized mcp_slot, so we ignore error returns
+        */
+       cmd.data0 = MXGEFW_RSS_MCP_SLOT_TYPE_MIN;
+       (void)myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_RSS_MCP_SLOT_TYPE, &cmd, 0);
 
        /* Now exchange information about interrupts  */
 
-       bytes = mgp->max_intr_slots * sizeof(*mgp->ss.rx_done.entry);
-       memset(mgp->ss.rx_done.entry, 0, bytes);
+       bytes = mgp->max_intr_slots * sizeof(*mgp->ss[0].rx_done.entry);
        cmd.data0 = (u32) bytes;
        status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd, 0);
-       cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->ss.rx_done.bus);
-       cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->ss.rx_done.bus);
-       status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_DMA, &cmd, 0);
+
+       /*
+        * Even though we already know how many slices are supported
+        * via myri10ge_probe_slices() MXGEFW_CMD_GET_MAX_RSS_QUEUES
+        * has magic side effects, and must be called after a reset.
+        * It must be called prior to calling any RSS related cmds,
+        * including assigning an interrupt queue for anything but
+        * slice 0.  It must also be called *after*
+        * MXGEFW_CMD_SET_INTRQ_SIZE, since the intrq size is used by
+        * the firmware to compute offsets.
+        */
+
+       if (mgp->num_slices > 1) {
+
+               /* ask the maximum number of slices it supports */
+               status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_RSS_QUEUES,
+                                          &cmd, 0);
+               if (status != 0) {
+                       dev_err(&mgp->pdev->dev,
+                               "failed to get number of slices\n");
+               }
+
+               /*
+                * MXGEFW_CMD_ENABLE_RSS_QUEUES must be called prior
+                * to setting up the interrupt queue DMA
+                */
+
+               cmd.data0 = mgp->num_slices;
+               cmd.data1 = 1;  /* use MSI-X */
+               status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ENABLE_RSS_QUEUES,
+                                          &cmd, 0);
+               if (status != 0) {
+                       dev_err(&mgp->pdev->dev,
+                               "failed to set number of slices\n");
+
+                       return status;
+               }
+       }
+       for (i = 0; i < mgp->num_slices; i++) {
+               ss = &mgp->ss[i];
+               cmd.data0 = MYRI10GE_LOWPART_TO_U32(ss->rx_done.bus);
+               cmd.data1 = MYRI10GE_HIGHPART_TO_U32(ss->rx_done.bus);
+               cmd.data2 = i;
+               status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_DMA,
+                                           &cmd, 0);
+       };
 
        status |=
            myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd, 0);
-       mgp->ss.irq_claim = (__iomem __be32 *) (mgp->sram + cmd.data0);
+       for (i = 0; i < mgp->num_slices; i++) {
+               ss = &mgp->ss[i];
+               ss->irq_claim =
+                   (__iomem __be32 *) (mgp->sram + cmd.data0 + 8 * i);
+       }
        status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET,
                                    &cmd, 0);
        mgp->irq_deassert = (__iomem __be32 *) (mgp->sram + cmd.data0);
@@ -899,24 +986,116 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
        }
        put_be32(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr);
 
-       memset(mgp->ss.rx_done.entry, 0, bytes);
+#ifdef CONFIG_DCA
+       status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_DCA_OFFSET, &cmd, 0);
+       dca_tag_off = cmd.data0;
+       for (i = 0; i < mgp->num_slices; i++) {
+               ss = &mgp->ss[i];
+               if (status == 0) {
+                       ss->dca_tag = (__iomem __be32 *)
+                           (mgp->sram + dca_tag_off + 4 * i);
+               } else {
+                       ss->dca_tag = NULL;
+               }
+       }
+#endif                         /* CONFIG_DCA */
 
        /* reset mcp/driver shared state back to 0 */
-       mgp->ss.tx.req = 0;
-       mgp->ss.tx.done = 0;
-       mgp->ss.tx.pkt_start = 0;
-       mgp->ss.tx.pkt_done = 0;
-       mgp->ss.rx_big.cnt = 0;
-       mgp->ss.rx_small.cnt = 0;
-       mgp->ss.rx_done.idx = 0;
-       mgp->ss.rx_done.cnt = 0;
+
        mgp->link_changes = 0;
+       for (i = 0; i < mgp->num_slices; i++) {
+               ss = &mgp->ss[i];
+
+               memset(ss->rx_done.entry, 0, bytes);
+               ss->tx.req = 0;
+               ss->tx.done = 0;
+               ss->tx.pkt_start = 0;
+               ss->tx.pkt_done = 0;
+               ss->rx_big.cnt = 0;
+               ss->rx_small.cnt = 0;
+               ss->rx_done.idx = 0;
+               ss->rx_done.cnt = 0;
+               ss->tx.wake_queue = 0;
+               ss->tx.stop_queue = 0;
+       }
+
        status = myri10ge_update_mac_address(mgp, mgp->dev->dev_addr);
        myri10ge_change_pause(mgp, mgp->pause);
        myri10ge_set_multicast_list(mgp->dev);
        return status;
 }
 
+#ifdef CONFIG_DCA
+static void
+myri10ge_write_dca(struct myri10ge_slice_state *ss, int cpu, int tag)
+{
+       ss->cpu = cpu;
+       ss->cached_dca_tag = tag;
+       put_be32(htonl(tag), ss->dca_tag);
+}
+
+static inline void myri10ge_update_dca(struct myri10ge_slice_state *ss)
+{
+       int cpu = get_cpu();
+       int tag;
+
+       if (cpu != ss->cpu) {
+               tag = dca_get_tag(cpu);
+               if (ss->cached_dca_tag != tag)
+                       myri10ge_write_dca(ss, cpu, tag);
+       }
+       put_cpu();
+}
+
+static void myri10ge_setup_dca(struct myri10ge_priv *mgp)
+{
+       int err, i;
+       struct pci_dev *pdev = mgp->pdev;
+
+       if (mgp->ss[0].dca_tag == NULL || mgp->dca_enabled)
+               return;
+       if (!myri10ge_dca) {
+               dev_err(&pdev->dev, "dca disabled by administrator\n");
+               return;
+       }
+       err = dca_add_requester(&pdev->dev);
+       if (err) {
+               dev_err(&pdev->dev,
+                       "dca_add_requester() failed, err=%d\n", err);
+               return;
+       }
+       mgp->dca_enabled = 1;
+       for (i = 0; i < mgp->num_slices; i++)
+               myri10ge_write_dca(&mgp->ss[i], -1, 0);
+}
+
+static void myri10ge_teardown_dca(struct myri10ge_priv *mgp)
+{
+       struct pci_dev *pdev = mgp->pdev;
+       int err;
+
+       if (!mgp->dca_enabled)
+               return;
+       mgp->dca_enabled = 0;
+       err = dca_remove_requester(&pdev->dev);
+}
+
+static int myri10ge_notify_dca_device(struct device *dev, void *data)
+{
+       struct myri10ge_priv *mgp;
+       unsigned long event;
+
+       mgp = dev_get_drvdata(dev);
+       event = *(unsigned long *)data;
+
+       if (event == DCA_PROVIDER_ADD)
+               myri10ge_setup_dca(mgp);
+       else if (event == DCA_PROVIDER_REMOVE)
+               myri10ge_teardown_dca(mgp);
+       return 0;
+}
+#endif                         /* CONFIG_DCA */
+
 static inline void
 myri10ge_submit_8rx(struct mcp_kreq_ether_recv __iomem * dst,
                    struct mcp_kreq_ether_recv *src)
@@ -1095,9 +1274,10 @@ myri10ge_rx_done(struct myri10ge_slice_state *ss, struct myri10ge_rx_buf *rx,
                rx_frags[0].size -= MXGEFW_PAD;
                len -= MXGEFW_PAD;
                lro_receive_frags(&ss->rx_done.lro_mgr, rx_frags,
-                                 len, len,
                                  /* opaque, will come back in get_frag_header */
+                                 len, len,
                                  (void *)(__force unsigned long)csum, csum);
+
                return 1;
        }
 
@@ -1236,7 +1416,7 @@ myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget)
 
 static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp)
 {
-       struct mcp_irq_data *stats = mgp->ss.fw_stats;
+       struct mcp_irq_data *stats = mgp->ss[0].fw_stats;
 
        if (unlikely(stats->stats_updated)) {
                unsigned link_up = ntohl(stats->link_up);
@@ -1283,6 +1463,11 @@ static int myri10ge_poll(struct napi_struct *napi, int budget)
        struct net_device *netdev = ss->mgp->dev;
        int work_done;
 
+#ifdef CONFIG_DCA
+       if (ss->mgp->dca_enabled)
+               myri10ge_update_dca(ss);
+#endif
+
        /* process as many rx events as NAPI will allow */
        work_done = myri10ge_clean_rx_done(ss, budget);
 
@@ -1302,6 +1487,13 @@ static irqreturn_t myri10ge_intr(int irq, void *arg)
        u32 send_done_count;
        int i;
 
+       /* an interrupt on a non-zero slice is implicitly valid
+        * since MSI-X irqs are not shared */
+       if (ss != mgp->ss) {
+               netif_rx_schedule(ss->dev, &ss->napi);
+               return (IRQ_HANDLED);
+       }
+
        /* make sure it is our IRQ, and that the DMA has finished */
        if (unlikely(!stats->valid))
                return (IRQ_NONE);
@@ -1311,7 +1503,7 @@ static irqreturn_t myri10ge_intr(int irq, void *arg)
        if (stats->valid & 1)
                netif_rx_schedule(ss->dev, &ss->napi);
 
-       if (!mgp->msi_enabled) {
+       if (!mgp->msi_enabled && !mgp->msix_enabled) {
                put_be32(0, mgp->irq_deassert);
                if (!myri10ge_deassert_wait)
                        stats->valid = 0;
@@ -1446,10 +1638,10 @@ myri10ge_get_ringparam(struct net_device *netdev,
 {
        struct myri10ge_priv *mgp = netdev_priv(netdev);
 
-       ring->rx_mini_max_pending = mgp->ss.rx_small.mask + 1;
-       ring->rx_max_pending = mgp->ss.rx_big.mask + 1;
+       ring->rx_mini_max_pending = mgp->ss[0].rx_small.mask + 1;
+       ring->rx_max_pending = mgp->ss[0].rx_big.mask + 1;
        ring->rx_jumbo_max_pending = 0;
-       ring->tx_max_pending = mgp->ss.rx_small.mask + 1;
+       ring->tx_max_pending = mgp->ss[0].rx_small.mask + 1;
        ring->rx_mini_pending = ring->rx_mini_max_pending;
        ring->rx_pending = ring->rx_max_pending;
        ring->rx_jumbo_pending = ring->rx_jumbo_max_pending;
@@ -1497,9 +1689,12 @@ static const char myri10ge_gstrings_main_stats[][ETH_GSTRING_LEN] = {
        "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
        "tx_heartbeat_errors", "tx_window_errors",
        /* device-specific stats */
-       "tx_boundary", "WC", "irq", "MSI",
+       "tx_boundary", "WC", "irq", "MSI", "MSIX",
        "read_dma_bw_MBs", "write_dma_bw_MBs", "read_write_dma_bw_MBs",
        "serial_number", "watchdog_resets",
+#ifdef CONFIG_DCA
+       "dca_capable", "dca_enabled",
+#endif
        "link_changes", "link_up", "dropped_link_overflow",
        "dropped_link_error_or_filtered",
        "dropped_pause", "dropped_bad_phy", "dropped_bad_crc32",
@@ -1524,23 +1719,31 @@ static const char myri10ge_gstrings_slice_stats[][ETH_GSTRING_LEN] = {
 static void
 myri10ge_get_strings(struct net_device *netdev, u32 stringset, u8 * data)
 {
+       struct myri10ge_priv *mgp = netdev_priv(netdev);
+       int i;
+
        switch (stringset) {
        case ETH_SS_STATS:
                memcpy(data, *myri10ge_gstrings_main_stats,
                       sizeof(myri10ge_gstrings_main_stats));
                data += sizeof(myri10ge_gstrings_main_stats);
-               memcpy(data, *myri10ge_gstrings_slice_stats,
-                      sizeof(myri10ge_gstrings_slice_stats));
-               data += sizeof(myri10ge_gstrings_slice_stats);
+               for (i = 0; i < mgp->num_slices; i++) {
+                       memcpy(data, *myri10ge_gstrings_slice_stats,
+                              sizeof(myri10ge_gstrings_slice_stats));
+                       data += sizeof(myri10ge_gstrings_slice_stats);
+               }
                break;
        }
 }
 
 static int myri10ge_get_sset_count(struct net_device *netdev, int sset)
 {
+       struct myri10ge_priv *mgp = netdev_priv(netdev);
+
        switch (sset) {
        case ETH_SS_STATS:
-               return MYRI10GE_MAIN_STATS_LEN + MYRI10GE_SLICE_STATS_LEN;
+               return MYRI10GE_MAIN_STATS_LEN +
+                   mgp->num_slices * MYRI10GE_SLICE_STATS_LEN;
        default:
                return -EOPNOTSUPP;
        }
@@ -1552,6 +1755,7 @@ myri10ge_get_ethtool_stats(struct net_device *netdev,
 {
        struct myri10ge_priv *mgp = netdev_priv(netdev);
        struct myri10ge_slice_state *ss;
+       int slice;
        int i;
 
        for (i = 0; i < MYRI10GE_NET_STATS_LEN; i++)
@@ -1561,15 +1765,20 @@ myri10ge_get_ethtool_stats(struct net_device *netdev,
        data[i++] = (unsigned int)mgp->wc_enabled;
        data[i++] = (unsigned int)mgp->pdev->irq;
        data[i++] = (unsigned int)mgp->msi_enabled;
+       data[i++] = (unsigned int)mgp->msix_enabled;
        data[i++] = (unsigned int)mgp->read_dma;
        data[i++] = (unsigned int)mgp->write_dma;
        data[i++] = (unsigned int)mgp->read_write_dma;
        data[i++] = (unsigned int)mgp->serial_number;
        data[i++] = (unsigned int)mgp->watchdog_resets;
+#ifdef CONFIG_DCA
+       data[i++] = (unsigned int)(mgp->ss[0].dca_tag != NULL);
+       data[i++] = (unsigned int)(mgp->dca_enabled);
+#endif
        data[i++] = (unsigned int)mgp->link_changes;
 
        /* firmware stats are useful only in the first slice */
-       ss = &mgp->ss;
+       ss = &mgp->ss[0];
        data[i++] = (unsigned int)ntohl(ss->fw_stats->link_up);
        data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_link_overflow);
        data[i++] =
@@ -1585,24 +1794,27 @@ myri10ge_get_ethtool_stats(struct net_device *netdev,
        data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_no_small_buffer);
        data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_no_big_buffer);
 
-       data[i++] = 0;
-       data[i++] = (unsigned int)ss->tx.pkt_start;
-       data[i++] = (unsigned int)ss->tx.pkt_done;
-       data[i++] = (unsigned int)ss->tx.req;
-       data[i++] = (unsigned int)ss->tx.done;
-       data[i++] = (unsigned int)ss->rx_small.cnt;
-       data[i++] = (unsigned int)ss->rx_big.cnt;
-       data[i++] = (unsigned int)ss->tx.wake_queue;
-       data[i++] = (unsigned int)ss->tx.stop_queue;
-       data[i++] = (unsigned int)ss->tx.linearized;
-       data[i++] = ss->rx_done.lro_mgr.stats.aggregated;
-       data[i++] = ss->rx_done.lro_mgr.stats.flushed;
-       if (ss->rx_done.lro_mgr.stats.flushed)
-               data[i++] = ss->rx_done.lro_mgr.stats.aggregated /
-                   ss->rx_done.lro_mgr.stats.flushed;
-       else
-               data[i++] = 0;
-       data[i++] = ss->rx_done.lro_mgr.stats.no_desc;
+       for (slice = 0; slice < mgp->num_slices; slice++) {
+               ss = &mgp->ss[slice];
+               data[i++] = slice;
+               data[i++] = (unsigned int)ss->tx.pkt_start;
+               data[i++] = (unsigned int)ss->tx.pkt_done;
+               data[i++] = (unsigned int)ss->tx.req;
+               data[i++] = (unsigned int)ss->tx.done;
+               data[i++] = (unsigned int)ss->rx_small.cnt;
+               data[i++] = (unsigned int)ss->rx_big.cnt;
+               data[i++] = (unsigned int)ss->tx.wake_queue;
+               data[i++] = (unsigned int)ss->tx.stop_queue;
+               data[i++] = (unsigned int)ss->tx.linearized;
+               data[i++] = ss->rx_done.lro_mgr.stats.aggregated;
+               data[i++] = ss->rx_done.lro_mgr.stats.flushed;
+               if (ss->rx_done.lro_mgr.stats.flushed)
+                       data[i++] = ss->rx_done.lro_mgr.stats.aggregated /
+                           ss->rx_done.lro_mgr.stats.flushed;
+               else
+                       data[i++] = 0;
+               data[i++] = ss->rx_done.lro_mgr.stats.no_desc;
+       }
 }
 
 static void myri10ge_set_msglevel(struct net_device *netdev, u32 value)
@@ -1645,12 +1857,15 @@ static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss)
        struct net_device *dev = mgp->dev;
        int tx_ring_size, rx_ring_size;
        int tx_ring_entries, rx_ring_entries;
-       int i, status;
+       int i, slice, status;
        size_t bytes;
 
        /* get ring sizes */
+       slice = ss - mgp->ss;
+       cmd.data0 = slice;
        status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_RING_SIZE, &cmd, 0);
        tx_ring_size = cmd.data0;
+       cmd.data0 = slice;
        status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd, 0);
        if (status != 0)
                return status;
@@ -1715,15 +1930,17 @@ static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss)
                                mgp->small_bytes + MXGEFW_PAD, 0);
 
        if (ss->rx_small.fill_cnt < ss->rx_small.mask + 1) {
-               printk(KERN_ERR "myri10ge: %s: alloced only %d small bufs\n",
-                      dev->name, ss->rx_small.fill_cnt);
+               printk(KERN_ERR
+                      "myri10ge: %s:slice-%d: alloced only %d small bufs\n",
+                      dev->name, slice, ss->rx_small.fill_cnt);
                goto abort_with_rx_small_ring;
        }
 
        myri10ge_alloc_rx_pages(mgp, &ss->rx_big, mgp->big_bytes, 0);
        if (ss->rx_big.fill_cnt < ss->rx_big.mask + 1) {
-               printk(KERN_ERR "myri10ge: %s: alloced only %d big bufs\n",
-                      dev->name, ss->rx_big.fill_cnt);
+               printk(KERN_ERR
+                      "myri10ge: %s:slice-%d: alloced only %d big bufs\n",
+                      dev->name, slice, ss->rx_big.fill_cnt);
                goto abort_with_rx_big_ring;
        }
 
@@ -1775,6 +1992,10 @@ static void myri10ge_free_rings(struct myri10ge_slice_state *ss)
        struct myri10ge_tx_buf *tx;
        int i, len, idx;
 
+       /* If not allocated, skip it */
+       if (ss->tx.req_list == NULL)
+               return;
+
        for (i = ss->rx_big.cnt; i < ss->rx_big.fill_cnt; i++) {
                idx = i & ss->rx_big.mask;
                if (i == ss->rx_big.fill_cnt - 1)
@@ -1837,25 +2058,67 @@ static void myri10ge_free_rings(struct myri10ge_slice_state *ss)
 static int myri10ge_request_irq(struct myri10ge_priv *mgp)
 {
        struct pci_dev *pdev = mgp->pdev;
+       struct myri10ge_slice_state *ss;
+       struct net_device *netdev = mgp->dev;
+       int i;
        int status;
 
+       mgp->msi_enabled = 0;
+       mgp->msix_enabled = 0;
+       status = 0;
        if (myri10ge_msi) {
-               status = pci_enable_msi(pdev);
-               if (status != 0)
-                       dev_err(&pdev->dev,
-                               "Error %d setting up MSI; falling back to xPIC\n",
-                               status);
-               else
-                       mgp->msi_enabled = 1;
-       } else {
-               mgp->msi_enabled = 0;
+               if (mgp->num_slices > 1) {
+                       status =
+                           pci_enable_msix(pdev, mgp->msix_vectors,
+                                           mgp->num_slices);
+                       if (status == 0) {
+                               mgp->msix_enabled = 1;
+                       } else {
+                               dev_err(&pdev->dev,
+                                       "Error %d setting up MSI-X\n", status);
+                               return status;
+                       }
+               }
+               if (mgp->msix_enabled == 0) {
+                       status = pci_enable_msi(pdev);
+                       if (status != 0) {
+                               dev_err(&pdev->dev,
+                                       "Error %d setting up MSI; falling back to xPIC\n",
+                                       status);
+                       } else {
+                               mgp->msi_enabled = 1;
+                       }
+               }
        }
-       status = request_irq(pdev->irq, myri10ge_intr, IRQF_SHARED,
-                            mgp->dev->name, mgp);
-       if (status != 0) {
-               dev_err(&pdev->dev, "failed to allocate IRQ\n");
-               if (mgp->msi_enabled)
-                       pci_disable_msi(pdev);
+       if (mgp->msix_enabled) {
+               for (i = 0; i < mgp->num_slices; i++) {
+                       ss = &mgp->ss[i];
+                       snprintf(ss->irq_desc, sizeof(ss->irq_desc),
+                                "%s:slice-%d", netdev->name, i);
+                       status = request_irq(mgp->msix_vectors[i].vector,
+                                            myri10ge_intr, 0, ss->irq_desc,
+                                            ss);
+                       if (status != 0) {
+                               dev_err(&pdev->dev,
+                                       "slice %d failed to allocate IRQ\n", i);
+                               i--;
+                               while (i >= 0) {
+                                       free_irq(mgp->msix_vectors[i].vector,
+                                                &mgp->ss[i]);
+                                       i--;
+                               }
+                               pci_disable_msix(pdev);
+                               return status;
+                       }
+               }
+       } else {
+               status = request_irq(pdev->irq, myri10ge_intr, IRQF_SHARED,
+                                    mgp->dev->name, &mgp->ss[0]);
+               if (status != 0) {
+                       dev_err(&pdev->dev, "failed to allocate IRQ\n");
+                       if (mgp->msi_enabled)
+                               pci_disable_msi(pdev);
+               }
        }
        return status;
 }
@@ -1863,10 +2126,18 @@ static int myri10ge_request_irq(struct myri10ge_priv *mgp)
 static void myri10ge_free_irq(struct myri10ge_priv *mgp)
 {
        struct pci_dev *pdev = mgp->pdev;
+       int i;
 
-       free_irq(pdev->irq, mgp);
+       if (mgp->msix_enabled) {
+               for (i = 0; i < mgp->num_slices; i++)
+                       free_irq(mgp->msix_vectors[i].vector, &mgp->ss[i]);
+       } else {
+               free_irq(pdev->irq, &mgp->ss[0]);
+       }
        if (mgp->msi_enabled)
                pci_disable_msi(pdev);
+       if (mgp->msix_enabled)
+               pci_disable_msix(pdev);
 }
 
 static int
@@ -1928,12 +2199,82 @@ myri10ge_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr,
        return 0;
 }
 
+static int myri10ge_get_txrx(struct myri10ge_priv *mgp, int slice)
+{
+       struct myri10ge_cmd cmd;
+       struct myri10ge_slice_state *ss;
+       int status;
+
+       ss = &mgp->ss[slice];
+       cmd.data0 = 0;          /* single slice for now */
+       status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET, &cmd, 0);
+       ss->tx.lanai = (struct mcp_kreq_ether_send __iomem *)
+           (mgp->sram + cmd.data0);
+
+       cmd.data0 = slice;
+       status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SMALL_RX_OFFSET,
+                                   &cmd, 0);
+       ss->rx_small.lanai = (struct mcp_kreq_ether_recv __iomem *)
+           (mgp->sram + cmd.data0);
+
+       cmd.data0 = slice;
+       status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd, 0);
+       ss->rx_big.lanai = (struct mcp_kreq_ether_recv __iomem *)
+           (mgp->sram + cmd.data0);
+
+       if (myri10ge_wcfifo && mgp->wc_enabled) {
+               ss->tx.wc_fifo = (u8 __iomem *)
+                   mgp->sram + MXGEFW_ETH_SEND_4 + 64 * slice;
+               ss->rx_small.wc_fifo = (u8 __iomem *)
+                   mgp->sram + MXGEFW_ETH_RECV_SMALL + 64 * slice;
+               ss->rx_big.wc_fifo = (u8 __iomem *)
+                   mgp->sram + MXGEFW_ETH_RECV_BIG + 64 * slice;
+       } else {
+               ss->tx.wc_fifo = NULL;
+               ss->rx_small.wc_fifo = NULL;
+               ss->rx_big.wc_fifo = NULL;
+       }
+       return status;
+
+}
+
+static int myri10ge_set_stats(struct myri10ge_priv *mgp, int slice)
+{
+       struct myri10ge_cmd cmd;
+       struct myri10ge_slice_state *ss;
+       int status;
+
+       ss = &mgp->ss[slice];
+       cmd.data0 = MYRI10GE_LOWPART_TO_U32(ss->fw_stats_bus);
+       cmd.data1 = MYRI10GE_HIGHPART_TO_U32(ss->fw_stats_bus);
+       cmd.data2 = sizeof(struct mcp_irq_data);
+       status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd, 0);
+       if (status == -ENOSYS) {
+               dma_addr_t bus = ss->fw_stats_bus;
+               if (slice != 0)
+                       return -EINVAL;
+               bus += offsetof(struct mcp_irq_data, send_done_count);
+               cmd.data0 = MYRI10GE_LOWPART_TO_U32(bus);
+               cmd.data1 = MYRI10GE_HIGHPART_TO_U32(bus);
+               status = myri10ge_send_cmd(mgp,
+                                          MXGEFW_CMD_SET_STATS_DMA_OBSOLETE,
+                                          &cmd, 0);
+               /* Firmware cannot support multicast without STATS_DMA_V2 */
+               mgp->fw_multicast_support = 0;
+       } else {
+               mgp->fw_multicast_support = 1;
+       }
+       return 0;
+}
+
 static int myri10ge_open(struct net_device *dev)
 {
+       struct myri10ge_slice_state *ss;
        struct myri10ge_priv *mgp = netdev_priv(dev);
        struct myri10ge_cmd cmd;
+       int i, status, big_pow2, slice;
+       u8 *itable;
        struct net_lro_mgr *lro_mgr;
-       int status, big_pow2;
 
        if (mgp->running != MYRI10GE_ETH_STOPPED)
                return -EBUSY;
@@ -1945,6 +2286,48 @@ static int myri10ge_open(struct net_device *dev)
                goto abort_with_nothing;
        }
 
+       if (mgp->num_slices > 1) {
+               cmd.data0 = mgp->num_slices;
+               cmd.data1 = 1;  /* use MSI-X */
+               status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ENABLE_RSS_QUEUES,
+                                          &cmd, 0);
+               if (status != 0) {
+                       printk(KERN_ERR
+                              "myri10ge: %s: failed to set number of slices\n",
+                              dev->name);
+                       goto abort_with_nothing;
+               }
+               /* setup the indirection table */
+               cmd.data0 = mgp->num_slices;
+               status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_RSS_TABLE_SIZE,
+                                          &cmd, 0);
+
+               status |= myri10ge_send_cmd(mgp,
+                                           MXGEFW_CMD_GET_RSS_TABLE_OFFSET,
+                                           &cmd, 0);
+               if (status != 0) {
+                       printk(KERN_ERR
+                              "myri10ge: %s: failed to setup rss tables\n",
+                              dev->name);
+               }
+
+               /* just enable an identity mapping */
+               itable = mgp->sram + cmd.data0;
+               for (i = 0; i < mgp->num_slices; i++)
+                       __raw_writeb(i, &itable[i]);
+
+               cmd.data0 = 1;
+               cmd.data1 = myri10ge_rss_hash;
+               status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_RSS_ENABLE,
+                                          &cmd, 0);
+               if (status != 0) {
+                       printk(KERN_ERR
+                              "myri10ge: %s: failed to enable slices\n",
+                              dev->name);
+                       goto abort_with_nothing;
+               }
+       }
+
        status = myri10ge_request_irq(mgp);
        if (status != 0)
                goto abort_with_nothing;
@@ -1968,41 +2351,6 @@ static int myri10ge_open(struct net_device *dev)
        if (myri10ge_small_bytes > 0)
                mgp->small_bytes = myri10ge_small_bytes;
 
-       /* get the lanai pointers to the send and receive rings */
-
-       status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET, &cmd, 0);
-       mgp->ss.tx.lanai =
-           (struct mcp_kreq_ether_send __iomem *)(mgp->sram + cmd.data0);
-
-       status |=
-           myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SMALL_RX_OFFSET, &cmd, 0);
-       mgp->ss.rx_small.lanai =
-           (struct mcp_kreq_ether_recv __iomem *)(mgp->sram + cmd.data0);
-
-       status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd, 0);
-       mgp->ss.rx_big.lanai =
-           (struct mcp_kreq_ether_recv __iomem *)(mgp->sram + cmd.data0);
-
-       if (status != 0) {
-               printk(KERN_ERR
-                      "myri10ge: %s: failed to get ring sizes or locations\n",
-                      dev->name);
-               mgp->running = MYRI10GE_ETH_STOPPED;
-               goto abort_with_irq;
-       }
-
-       if (myri10ge_wcfifo && mgp->wc_enabled) {
-               mgp->ss.tx.wc_fifo = (u8 __iomem *) mgp->sram + MXGEFW_ETH_SEND_4;
-               mgp->ss.rx_small.wc_fifo =
-                   (u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_SMALL;
-               mgp->ss.rx_big.wc_fifo =
-                   (u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_BIG;
-       } else {
-               mgp->ss.tx.wc_fifo = NULL;
-               mgp->ss.rx_small.wc_fifo = NULL;
-               mgp->ss.rx_big.wc_fifo = NULL;
-       }
-
        /* Firmware needs the big buff size as a power of 2.  Lie and
         * tell him the buffer is larger, because we only use 1
         * buffer/pkt, and the mtu will prevent overruns.
@@ -2017,9 +2365,44 @@ static int myri10ge_open(struct net_device *dev)
                mgp->big_bytes = big_pow2;
        }
 
-       status = myri10ge_allocate_rings(&mgp->ss);
-       if (status != 0)
-               goto abort_with_irq;
+       /* setup the per-slice data structures */
+       for (slice = 0; slice < mgp->num_slices; slice++) {
+               ss = &mgp->ss[slice];
+
+               status = myri10ge_get_txrx(mgp, slice);
+               if (status != 0) {
+                       printk(KERN_ERR
+                              "myri10ge: %s: failed to get ring sizes or locations\n",
+                              dev->name);
+                       goto abort_with_rings;
+               }
+               status = myri10ge_allocate_rings(ss);
+               if (status != 0)
+                       goto abort_with_rings;
+               if (slice == 0)
+                       status = myri10ge_set_stats(mgp, slice);
+               if (status) {
+                       printk(KERN_ERR
+                              "myri10ge: %s: Couldn't set stats DMA\n",
+                              dev->name);
+                       goto abort_with_rings;
+               }
+
+               lro_mgr = &ss->rx_done.lro_mgr;
+               lro_mgr->dev = dev;
+               lro_mgr->features = LRO_F_NAPI;
+               lro_mgr->ip_summed = CHECKSUM_COMPLETE;
+               lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY;
+               lro_mgr->max_desc = MYRI10GE_MAX_LRO_DESCRIPTORS;
+               lro_mgr->lro_arr = ss->rx_done.lro_desc;
+               lro_mgr->get_frag_header = myri10ge_get_frag_header;
+               lro_mgr->max_aggr = myri10ge_lro_max_pkts;
+               if (lro_mgr->max_aggr > MAX_SKB_FRAGS)
+                       lro_mgr->max_aggr = MAX_SKB_FRAGS;
+
+               /* must happen prior to any irq */
+               napi_enable(&(ss)->napi);
+       }
 
        /* now give firmware buffers sizes, and MTU */
        cmd.data0 = dev->mtu + ETH_HLEN + VLAN_HLEN;
@@ -2036,25 +2419,15 @@ static int myri10ge_open(struct net_device *dev)
                goto abort_with_rings;
        }
 
-       cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->ss.fw_stats_bus);
-       cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->ss.fw_stats_bus);
-       cmd.data2 = sizeof(struct mcp_irq_data);
-       status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd, 0);
-       if (status == -ENOSYS) {
-               dma_addr_t bus = mgp->ss.fw_stats_bus;
-               bus += offsetof(struct mcp_irq_data, send_done_count);
-               cmd.data0 = MYRI10GE_LOWPART_TO_U32(bus);
-               cmd.data1 = MYRI10GE_HIGHPART_TO_U32(bus);
-               status = myri10ge_send_cmd(mgp,
-                                          MXGEFW_CMD_SET_STATS_DMA_OBSOLETE,
-                                          &cmd, 0);
-               /* Firmware cannot support multicast without STATS_DMA_V2 */
-               mgp->fw_multicast_support = 0;
-       } else {
-               mgp->fw_multicast_support = 1;
-       }
-       if (status) {
-               printk(KERN_ERR "myri10ge: %s: Couldn't set stats DMA\n",
+       /*
+        * Set Linux style TSO mode; this is needed only on newer
+        *  firmware versions.  Older versions default to Linux
+        *  style TSO
+        */
+       cmd.data0 = 0;
+       status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_TSO_MODE, &cmd, 0);
+       if (status && status != -ENOSYS) {
+               printk(KERN_ERR "myri10ge: %s: Couldn't set TSO mode\n",
                       dev->name);
                goto abort_with_rings;
        }
@@ -2062,21 +2435,6 @@ static int myri10ge_open(struct net_device *dev)
        mgp->link_state = ~0U;
        mgp->rdma_tags_available = 15;
 
-       lro_mgr = &mgp->ss.rx_done.lro_mgr;
-       lro_mgr->dev = dev;
-       lro_mgr->features = LRO_F_NAPI;
-       lro_mgr->ip_summed = CHECKSUM_COMPLETE;
-       lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY;
-       lro_mgr->max_desc = MYRI10GE_MAX_LRO_DESCRIPTORS;
-       lro_mgr->lro_arr = mgp->ss.rx_done.lro_desc;
-       lro_mgr->get_frag_header = myri10ge_get_frag_header;
-       lro_mgr->max_aggr = myri10ge_lro_max_pkts;
-       lro_mgr->frag_align_pad = 2;
-       if (lro_mgr->max_aggr > MAX_SKB_FRAGS)
-               lro_mgr->max_aggr = MAX_SKB_FRAGS;
-
-       napi_enable(&mgp->ss.napi);     /* must happen prior to any irq */
-
        status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_UP, &cmd, 0);
        if (status) {
                printk(KERN_ERR "myri10ge: %s: Couldn't bring up link\n",
@@ -2084,8 +2442,6 @@ static int myri10ge_open(struct net_device *dev)
                goto abort_with_rings;
        }
 
-       mgp->ss.tx.wake_queue = 0;
-       mgp->ss.tx.stop_queue = 0;
        mgp->running = MYRI10GE_ETH_RUNNING;
        mgp->watchdog_timer.expires = jiffies + myri10ge_watchdog_timeout * HZ;
        add_timer(&mgp->watchdog_timer);
@@ -2093,9 +2449,9 @@ static int myri10ge_open(struct net_device *dev)
        return 0;
 
 abort_with_rings:
-       myri10ge_free_rings(&mgp->ss);
+       for (i = 0; i < mgp->num_slices; i++)
+               myri10ge_free_rings(&mgp->ss[i]);
 
-abort_with_irq:
        myri10ge_free_irq(mgp);
 
 abort_with_nothing:
@@ -2108,16 +2464,19 @@ static int myri10ge_close(struct net_device *dev)
        struct myri10ge_priv *mgp = netdev_priv(dev);
        struct myri10ge_cmd cmd;
        int status, old_down_cnt;
+       int i;
 
        if (mgp->running != MYRI10GE_ETH_RUNNING)
                return 0;
 
-       if (mgp->ss.tx.req_bytes == NULL)
+       if (mgp->ss[0].tx.req_bytes == NULL)
                return 0;
 
        del_timer_sync(&mgp->watchdog_timer);
        mgp->running = MYRI10GE_ETH_STOPPING;
-       napi_disable(&mgp->ss.napi);
+       for (i = 0; i < mgp->num_slices; i++) {
+               napi_disable(&mgp->ss[i].napi);
+       }
        netif_carrier_off(dev);
        netif_stop_queue(dev);
        old_down_cnt = mgp->down_cnt;
@@ -2133,7 +2492,8 @@ static int myri10ge_close(struct net_device *dev)
 
        netif_tx_disable(dev);
        myri10ge_free_irq(mgp);
-       myri10ge_free_rings(&mgp->ss);
+       for (i = 0; i < mgp->num_slices; i++)
+               myri10ge_free_rings(&mgp->ss[i]);
 
        mgp->running = MYRI10GE_ETH_STOPPED;
        return 0;
@@ -2254,7 +2614,7 @@ static int myri10ge_xmit(struct sk_buff *skb, struct net_device *dev)
        u8 flags, odd_flag;
 
        /* always transmit through slot 0 */
-       ss = &mgp->ss;
+       ss = mgp->ss;
        tx = &ss->tx;
 again:
        req = tx->req_list;
@@ -2559,7 +2919,21 @@ drop:
 static struct net_device_stats *myri10ge_get_stats(struct net_device *dev)
 {
        struct myri10ge_priv *mgp = netdev_priv(dev);
-       return &mgp->stats;
+       struct myri10ge_slice_netstats *slice_stats;
+       struct net_device_stats *stats = &mgp->stats;
+       int i;
+
+       memset(stats, 0, sizeof(*stats));
+       for (i = 0; i < mgp->num_slices; i++) {
+               slice_stats = &mgp->ss[i].stats;
+               stats->rx_packets += slice_stats->rx_packets;
+               stats->tx_packets += slice_stats->tx_packets;
+               stats->rx_bytes += slice_stats->rx_bytes;
+               stats->tx_bytes += slice_stats->tx_bytes;
+               stats->rx_dropped += slice_stats->rx_dropped;
+               stats->tx_dropped += slice_stats->tx_dropped;
+       }
+       return stats;
 }
 
 static void myri10ge_set_multicast_list(struct net_device *dev)
@@ -2770,10 +3144,10 @@ static void myri10ge_enable_ecrc(struct myri10ge_priv *mgp)
  *
  * If the driver can neither enable ECRC nor verify that it has
  * already been enabled, then it must use a firmware image which works
- * around unaligned completion packets (myri10ge_ethp_z8e.dat), and it
+ * around unaligned completion packets (myri10ge_rss_ethp_z8e.dat), and it
  * should also ensure that it never gives the device a Read-DMA which is
  * larger than 2KB by setting the tx_boundary to 2KB.  If ECRC is
- * enabled, then the driver should use the aligned (myri10ge_eth_z8e.dat)
+ * enabled, then the driver should use the aligned (myri10ge_rss_eth_z8e.dat)
  * firmware image, and set tx_boundary to 4KB.
  */
 
@@ -2802,7 +3176,7 @@ static void myri10ge_firmware_probe(struct myri10ge_priv *mgp)
         * completions) in order to see if it works on this host.
         */
        mgp->fw_name = myri10ge_fw_aligned;
-       status = myri10ge_load_firmware(mgp);
+       status = myri10ge_load_firmware(mgp, 1);
        if (status != 0) {
                goto abort;
        }
@@ -2983,6 +3357,7 @@ static void myri10ge_watchdog(struct work_struct *work)
        struct myri10ge_tx_buf *tx;
        u32 reboot;
        int status;
+       int i;
        u16 cmd, vendor;
 
        mgp->watchdog_resets++;
@@ -3030,20 +3405,26 @@ static void myri10ge_watchdog(struct work_struct *work)
 
                printk(KERN_ERR "myri10ge: %s: device timeout, resetting\n",
                       mgp->dev->name);
-               tx = &mgp->ss.tx;
-               printk(KERN_INFO "myri10ge: %s: %d %d %d %d %d\n",
-                      mgp->dev->name, tx->req, tx->done,
-                      tx->pkt_start, tx->pkt_done,
-                      (int)ntohl(mgp->ss.fw_stats->send_done_count));
-               msleep(2000);
-               printk(KERN_INFO "myri10ge: %s: %d %d %d %d %d\n",
-                      mgp->dev->name, tx->req, tx->done,
-                      tx->pkt_start, tx->pkt_done,
-                      (int)ntohl(mgp->ss.fw_stats->send_done_count));
+               for (i = 0; i < mgp->num_slices; i++) {
+                       tx = &mgp->ss[i].tx;
+                       printk(KERN_INFO
+                              "myri10ge: %s: (%d): %d %d %d %d %d\n",
+                              mgp->dev->name, i, tx->req, tx->done,
+                              tx->pkt_start, tx->pkt_done,
+                              (int)ntohl(mgp->ss[i].fw_stats->
+                                         send_done_count));
+                       msleep(2000);
+                       printk(KERN_INFO
+                              "myri10ge: %s: (%d): %d %d %d %d %d\n",
+                              mgp->dev->name, i, tx->req, tx->done,
+                              tx->pkt_start, tx->pkt_done,
+                              (int)ntohl(mgp->ss[i].fw_stats->
+                                         send_done_count));
+               }
        }
        rtnl_lock();
        myri10ge_close(mgp->dev);
-       status = myri10ge_load_firmware(mgp);
+       status = myri10ge_load_firmware(mgp, 1);
        if (status != 0)
                printk(KERN_ERR "myri10ge: %s: failed to load firmware\n",
                       mgp->dev->name);
@@ -3063,47 +3444,241 @@ static void myri10ge_watchdog_timer(unsigned long arg)
 {
        struct myri10ge_priv *mgp;
        struct myri10ge_slice_state *ss;
+       int i, reset_needed;
        u32 rx_pause_cnt;
 
        mgp = (struct myri10ge_priv *)arg;
 
-       rx_pause_cnt = ntohl(mgp->ss.fw_stats->dropped_pause);
+       rx_pause_cnt = ntohl(mgp->ss[0].fw_stats->dropped_pause);
+       for (i = 0, reset_needed = 0;
+            i < mgp->num_slices && reset_needed == 0; ++i) {
+
+               ss = &mgp->ss[i];
+               if (ss->rx_small.watchdog_needed) {
+                       myri10ge_alloc_rx_pages(mgp, &ss->rx_small,
+                                               mgp->small_bytes + MXGEFW_PAD,
+                                               1);
+                       if (ss->rx_small.fill_cnt - ss->rx_small.cnt >=
+                           myri10ge_fill_thresh)
+                               ss->rx_small.watchdog_needed = 0;
+               }
+               if (ss->rx_big.watchdog_needed) {
+                       myri10ge_alloc_rx_pages(mgp, &ss->rx_big,
+                                               mgp->big_bytes, 1);
+                       if (ss->rx_big.fill_cnt - ss->rx_big.cnt >=
+                           myri10ge_fill_thresh)
+                               ss->rx_big.watchdog_needed = 0;
+               }
 
-       ss = &mgp->ss;
-       if (ss->rx_small.watchdog_needed) {
-               myri10ge_alloc_rx_pages(mgp, &ss->rx_small,
-                                       mgp->small_bytes + MXGEFW_PAD, 1);
-               if (ss->rx_small.fill_cnt - ss->rx_small.cnt >=
-                   myri10ge_fill_thresh)
-                       ss->rx_small.watchdog_needed = 0;
-       }
-       if (ss->rx_big.watchdog_needed) {
-               myri10ge_alloc_rx_pages(mgp, &ss->rx_big, mgp->big_bytes, 1);
-               if (ss->rx_big.fill_cnt - ss->rx_big.cnt >=
-                   myri10ge_fill_thresh)
-                       ss->rx_big.watchdog_needed = 0;
-       }
-
-       if (ss->tx.req != ss->tx.done &&
-           ss->tx.done == ss->watchdog_tx_done &&
-           ss->watchdog_tx_req != ss->watchdog_tx_done) {
-               /* nic seems like it might be stuck.. */
-               if (rx_pause_cnt != mgp->watchdog_pause) {
-                       if (net_ratelimit())
-                               printk(KERN_WARNING "myri10ge %s:"
-                                      "TX paused, check link partner\n",
-                                      mgp->dev->name);
-               } else {
-                       schedule_work(&mgp->watchdog_work);
-                       return;
+               if (ss->tx.req != ss->tx.done &&
+                   ss->tx.done == ss->watchdog_tx_done &&
+                   ss->watchdog_tx_req != ss->watchdog_tx_done) {
+                       /* nic seems like it might be stuck.. */
+                       if (rx_pause_cnt != mgp->watchdog_pause) {
+                               if (net_ratelimit())
+                                       printk(KERN_WARNING "myri10ge %s:"
+                                              "TX paused, check link partner\n",
+                                              mgp->dev->name);
+                       } else {
+                               reset_needed = 1;
+                       }
                }
+               ss->watchdog_tx_done = ss->tx.done;
+               ss->watchdog_tx_req = ss->tx.req;
        }
-       /* rearm timer */
-       mod_timer(&mgp->watchdog_timer,
-                 jiffies + myri10ge_watchdog_timeout * HZ);
-       ss->watchdog_tx_done = ss->tx.done;
-       ss->watchdog_tx_req = ss->tx.req;
        mgp->watchdog_pause = rx_pause_cnt;
+
+       if (reset_needed) {
+               schedule_work(&mgp->watchdog_work);
+       } else {
+               /* rearm timer */
+               mod_timer(&mgp->watchdog_timer,
+                         jiffies + myri10ge_watchdog_timeout * HZ);
+       }
+}
+
+static void myri10ge_free_slices(struct myri10ge_priv *mgp)
+{
+       struct myri10ge_slice_state *ss;
+       struct pci_dev *pdev = mgp->pdev;
+       size_t bytes;
+       int i;
+
+       if (mgp->ss == NULL)
+               return;
+
+       for (i = 0; i < mgp->num_slices; i++) {
+               ss = &mgp->ss[i];
+               if (ss->rx_done.entry != NULL) {
+                       bytes = mgp->max_intr_slots *
+                           sizeof(*ss->rx_done.entry);
+                       dma_free_coherent(&pdev->dev, bytes,
+                                         ss->rx_done.entry, ss->rx_done.bus);
+                       ss->rx_done.entry = NULL;
+               }
+               if (ss->fw_stats != NULL) {
+                       bytes = sizeof(*ss->fw_stats);
+                       dma_free_coherent(&pdev->dev, bytes,
+                                         ss->fw_stats, ss->fw_stats_bus);
+                       ss->fw_stats = NULL;
+               }
+       }
+       kfree(mgp->ss);
+       mgp->ss = NULL;
+}
+
+static int myri10ge_alloc_slices(struct myri10ge_priv *mgp)
+{
+       struct myri10ge_slice_state *ss;
+       struct pci_dev *pdev = mgp->pdev;
+       size_t bytes;
+       int i;
+
+       bytes = sizeof(*mgp->ss) * mgp->num_slices;
+       mgp->ss = kzalloc(bytes, GFP_KERNEL);
+       if (mgp->ss == NULL) {
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < mgp->num_slices; i++) {
+               ss = &mgp->ss[i];
+               bytes = mgp->max_intr_slots * sizeof(*ss->rx_done.entry);
+               ss->rx_done.entry = dma_alloc_coherent(&pdev->dev, bytes,
+                                                      &ss->rx_done.bus,
+                                                      GFP_KERNEL);
+               if (ss->rx_done.entry == NULL)
+                       goto abort;
+               memset(ss->rx_done.entry, 0, bytes);
+               bytes = sizeof(*ss->fw_stats);
+               ss->fw_stats = dma_alloc_coherent(&pdev->dev, bytes,
+                                                 &ss->fw_stats_bus,
+                                                 GFP_KERNEL);
+               if (ss->fw_stats == NULL)
+                       goto abort;
+               ss->mgp = mgp;
+               ss->dev = mgp->dev;
+               netif_napi_add(ss->dev, &ss->napi, myri10ge_poll,
+                              myri10ge_napi_weight);
+       }
+       return 0;
+abort:
+       myri10ge_free_slices(mgp);
+       return -ENOMEM;
+}
+
+/*
+ * This function determines the number of slices supported.
+ * The number slices is the minumum of the number of CPUS,
+ * the number of MSI-X irqs supported, the number of slices
+ * supported by the firmware
+ */
+static void myri10ge_probe_slices(struct myri10ge_priv *mgp)
+{
+       struct myri10ge_cmd cmd;
+       struct pci_dev *pdev = mgp->pdev;
+       char *old_fw;
+       int i, status, ncpus, msix_cap;
+
+       mgp->num_slices = 1;
+       msix_cap = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
+       ncpus = num_online_cpus();
+
+       if (myri10ge_max_slices == 1 || msix_cap == 0 ||
+           (myri10ge_max_slices == -1 && ncpus < 2))
+               return;
+
+       /* try to load the slice aware rss firmware */
+       old_fw = mgp->fw_name;
+       if (old_fw == myri10ge_fw_aligned)
+               mgp->fw_name = myri10ge_fw_rss_aligned;
+       else
+               mgp->fw_name = myri10ge_fw_rss_unaligned;
+       status = myri10ge_load_firmware(mgp, 0);
+       if (status != 0) {
+               dev_info(&pdev->dev, "Rss firmware not found\n");
+               return;
+       }
+
+       /* hit the board with a reset to ensure it is alive */
+       memset(&cmd, 0, sizeof(cmd));
+       status = myri10ge_send_cmd(mgp, MXGEFW_CMD_RESET, &cmd, 0);
+       if (status != 0) {
+               dev_err(&mgp->pdev->dev, "failed reset\n");
+               goto abort_with_fw;
+               return;
+       }
+
+       mgp->max_intr_slots = cmd.data0 / sizeof(struct mcp_slot);
+
+       /* tell it the size of the interrupt queues */
+       cmd.data0 = mgp->max_intr_slots * sizeof(struct mcp_slot);
+       status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd, 0);
+       if (status != 0) {
+               dev_err(&mgp->pdev->dev, "failed MXGEFW_CMD_SET_INTRQ_SIZE\n");
+               goto abort_with_fw;
+       }
+
+       /* ask the maximum number of slices it supports */
+       status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_RSS_QUEUES, &cmd, 0);
+       if (status != 0)
+               goto abort_with_fw;
+       else
+               mgp->num_slices = cmd.data0;
+
+       /* Only allow multiple slices if MSI-X is usable */
+       if (!myri10ge_msi) {
+               goto abort_with_fw;
+       }
+
+       /* if the admin did not specify a limit to how many
+        * slices we should use, cap it automatically to the
+        * number of CPUs currently online */
+       if (myri10ge_max_slices == -1)
+               myri10ge_max_slices = ncpus;
+
+       if (mgp->num_slices > myri10ge_max_slices)
+               mgp->num_slices = myri10ge_max_slices;
+
+       /* Now try to allocate as many MSI-X vectors as we have
+        * slices. We give up on MSI-X if we can only get a single
+        * vector. */
+
+       mgp->msix_vectors = kzalloc(mgp->num_slices *
+                                   sizeof(*mgp->msix_vectors), GFP_KERNEL);
+       if (mgp->msix_vectors == NULL)
+               goto disable_msix;
+       for (i = 0; i < mgp->num_slices; i++) {
+               mgp->msix_vectors[i].entry = i;
+       }
+
+       while (mgp->num_slices > 1) {
+               /* make sure it is a power of two */
+               while (!is_power_of_2(mgp->num_slices))
+                       mgp->num_slices--;
+               if (mgp->num_slices == 1)
+                       goto disable_msix;
+               status = pci_enable_msix(pdev, mgp->msix_vectors,
+                                        mgp->num_slices);
+               if (status == 0) {
+                       pci_disable_msix(pdev);
+                       return;
+               }
+               if (status > 0)
+                       mgp->num_slices = status;
+               else
+                       goto disable_msix;
+       }
+
+disable_msix:
+       if (mgp->msix_vectors != NULL) {
+               kfree(mgp->msix_vectors);
+               mgp->msix_vectors = NULL;
+       }
+
+abort_with_fw:
+       mgp->num_slices = 1;
+       mgp->fw_name = old_fw;
+       myri10ge_load_firmware(mgp, 0);
 }
 
 static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -3111,7 +3686,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        struct net_device *netdev;
        struct myri10ge_priv *mgp;
        struct device *dev = &pdev->dev;
-       size_t bytes;
        int i;
        int status = -ENXIO;
        int dac_enabled;
@@ -3126,7 +3700,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        mgp = netdev_priv(netdev);
        mgp->dev = netdev;
-       netif_napi_add(netdev, &mgp->ss.napi, myri10ge_poll, myri10ge_napi_weight);
        mgp->pdev = pdev;
        mgp->csum_flag = MXGEFW_FLAGS_CKSUM;
        mgp->pause = myri10ge_flow_control;
@@ -3172,11 +3745,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (mgp->cmd == NULL)
                goto abort_with_netdev;
 
-       mgp->ss.fw_stats = dma_alloc_coherent(&pdev->dev, sizeof(*mgp->ss.fw_stats),
-                                          &mgp->ss.fw_stats_bus, GFP_KERNEL);
-       if (mgp->ss.fw_stats == NULL)
-               goto abort_with_cmd;
-
        mgp->board_span = pci_resource_len(pdev, 0);
        mgp->iomem_base = pci_resource_start(pdev, 0);
        mgp->mtrr = -1;
@@ -3213,28 +3781,28 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        for (i = 0; i < ETH_ALEN; i++)
                netdev->dev_addr[i] = mgp->mac_addr[i];
 
-       /* allocate rx done ring */
-       bytes = mgp->max_intr_slots * sizeof(*mgp->ss.rx_done.entry);
-       mgp->ss.rx_done.entry = dma_alloc_coherent(&pdev->dev, bytes,
-                                               &mgp->ss.rx_done.bus, GFP_KERNEL);
-       if (mgp->ss.rx_done.entry == NULL)
-               goto abort_with_ioremap;
-       memset(mgp->ss.rx_done.entry, 0, bytes);
-
        myri10ge_select_firmware(mgp);
 
-       status = myri10ge_load_firmware(mgp);
+       status = myri10ge_load_firmware(mgp, 1);
        if (status != 0) {
                dev_err(&pdev->dev, "failed to load firmware\n");
-               goto abort_with_rx_done;
+               goto abort_with_ioremap;
+       }
+       myri10ge_probe_slices(mgp);
+       status = myri10ge_alloc_slices(mgp);
+       if (status != 0) {
+               dev_err(&pdev->dev, "failed to alloc slice state\n");
+               goto abort_with_firmware;
        }
 
        status = myri10ge_reset(mgp);
        if (status != 0) {
                dev_err(&pdev->dev, "failed reset\n");
-               goto abort_with_firmware;
+               goto abort_with_slices;
        }
-
+#ifdef CONFIG_DCA
+       myri10ge_setup_dca(mgp);
+#endif
        pci_set_drvdata(pdev, mgp);
        if ((myri10ge_initial_mtu + ETH_HLEN) > MYRI10GE_MAX_ETHER_MTU)
                myri10ge_initial_mtu = MYRI10GE_MAX_ETHER_MTU - ETH_HLEN;
@@ -3277,24 +3845,27 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                dev_err(&pdev->dev, "register_netdev failed: %d\n", status);
                goto abort_with_state;
        }
-       dev_info(dev, "%s IRQ %d, tx bndry %d, fw %s, WC %s\n",
-                (mgp->msi_enabled ? "MSI" : "xPIC"),
-                netdev->irq, mgp->tx_boundary, mgp->fw_name,
-                (mgp->wc_enabled ? "Enabled" : "Disabled"));
+       if (mgp->msix_enabled)
+               dev_info(dev, "%d MSI-X IRQs, tx bndry %d, fw %s, WC %s\n",
+                        mgp->num_slices, mgp->tx_boundary, mgp->fw_name,
+                        (mgp->wc_enabled ? "Enabled" : "Disabled"));
+       else
+               dev_info(dev, "%s IRQ %d, tx bndry %d, fw %s, WC %s\n",
+                        mgp->msi_enabled ? "MSI" : "xPIC",
+                        netdev->irq, mgp->tx_boundary, mgp->fw_name,
+                        (mgp->wc_enabled ? "Enabled" : "Disabled"));
 
        return 0;
 
 abort_with_state:
        pci_restore_state(pdev);
 
+abort_with_slices:
+       myri10ge_free_slices(mgp);
+
 abort_with_firmware:
        myri10ge_dummy_rdma(mgp, 0);
 
-abort_with_rx_done:
-       bytes = mgp->max_intr_slots * sizeof(*mgp->ss.rx_done.entry);
-       dma_free_coherent(&pdev->dev, bytes,
-                         mgp->ss.rx_done.entry, mgp->ss.rx_done.bus);
-
 abort_with_ioremap:
        iounmap(mgp->sram);
 
@@ -3303,10 +3874,6 @@ abort_with_wc:
        if (mgp->mtrr >= 0)
                mtrr_del(mgp->mtrr, mgp->iomem_base, mgp->board_span);
 #endif
-       dma_free_coherent(&pdev->dev, sizeof(*mgp->ss.fw_stats),
-                         mgp->ss.fw_stats, mgp->ss.fw_stats_bus);
-
-abort_with_cmd:
        dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd),
                          mgp->cmd, mgp->cmd_bus);
 
@@ -3327,7 +3894,6 @@ static void myri10ge_remove(struct pci_dev *pdev)
 {
        struct myri10ge_priv *mgp;
        struct net_device *netdev;
-       size_t bytes;
 
        mgp = pci_get_drvdata(pdev);
        if (mgp == NULL)
@@ -3337,24 +3903,23 @@ static void myri10ge_remove(struct pci_dev *pdev)
        netdev = mgp->dev;
        unregister_netdev(netdev);
 
+#ifdef CONFIG_DCA
+       myri10ge_teardown_dca(mgp);
+#endif
        myri10ge_dummy_rdma(mgp, 0);
 
        /* avoid a memory leak */
        pci_restore_state(pdev);
 
-       bytes = mgp->max_intr_slots * sizeof(*mgp->ss.rx_done.entry);
-       dma_free_coherent(&pdev->dev, bytes,
-                         mgp->ss.rx_done.entry, mgp->ss.rx_done.bus);
-
        iounmap(mgp->sram);
 
 #ifdef CONFIG_MTRR
        if (mgp->mtrr >= 0)
                mtrr_del(mgp->mtrr, mgp->iomem_base, mgp->board_span);
 #endif
-       dma_free_coherent(&pdev->dev, sizeof(*mgp->ss.fw_stats),
-                         mgp->ss.fw_stats, mgp->ss.fw_stats_bus);
-
+       myri10ge_free_slices(mgp);
+       if (mgp->msix_vectors != NULL)
+               kfree(mgp->msix_vectors);
        dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd),
                          mgp->cmd, mgp->cmd_bus);
 
@@ -3383,10 +3948,42 @@ static struct pci_driver myri10ge_driver = {
 #endif
 };
 
+#ifdef CONFIG_DCA
+static int
+myri10ge_notify_dca(struct notifier_block *nb, unsigned long event, void *p)
+{
+       int err = driver_for_each_device(&myri10ge_driver.driver,
+                                        NULL, &event,
+                                        myri10ge_notify_dca_device);
+
+       if (err)
+               return NOTIFY_BAD;
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block myri10ge_dca_notifier = {
+       .notifier_call = myri10ge_notify_dca,
+       .next = NULL,
+       .priority = 0,
+};
+#endif                         /* CONFIG_DCA */
+
 static __init int myri10ge_init_module(void)
 {
        printk(KERN_INFO "%s: Version %s\n", myri10ge_driver.name,
               MYRI10GE_VERSION_STR);
+
+       if (myri10ge_rss_hash > MXGEFW_RSS_HASH_TYPE_SRC_PORT ||
+           myri10ge_rss_hash < MXGEFW_RSS_HASH_TYPE_IPV4) {
+               printk(KERN_ERR
+                      "%s: Illegal rssh hash type %d, defaulting to source port\n",
+                      myri10ge_driver.name, myri10ge_rss_hash);
+               myri10ge_rss_hash = MXGEFW_RSS_HASH_TYPE_SRC_PORT;
+       }
+#ifdef CONFIG_DCA
+       dca_register_notify(&myri10ge_dca_notifier);
+#endif
+
        return pci_register_driver(&myri10ge_driver);
 }
 
@@ -3394,6 +3991,9 @@ module_init(myri10ge_init_module);
 
 static __exit void myri10ge_cleanup_module(void)
 {
+#ifdef CONFIG_DCA
+       dca_unregister_notify(&myri10ge_dca_notifier);
+#endif
        pci_unregister_driver(&myri10ge_driver);
 }
 
index 46119bb3770a65b19e1dc21c5301e1e2358bf879..b238ed0e8ace51485d7010f1a357e0075d9cf574 100644 (file)
@@ -664,7 +664,7 @@ static ssize_t natsemi_show_##_name(struct device *dev, \
 NATSEMI_ATTR(dspcfg_workaround);
 
 static ssize_t natsemi_show_dspcfg_workaround(struct device *dev,
-                                             struct device_attribute *attr, 
+                                             struct device_attribute *attr,
                                              char *buf)
 {
        struct netdev_private *np = netdev_priv(to_net_dev(dev));
@@ -687,7 +687,7 @@ static ssize_t natsemi_set_dspcfg_workaround(struct device *dev,
                  || !strncmp("0", buf, count - 1))
                new_setting = 0;
        else
-                 return count; 
+                 return count;
 
        spin_lock_irqsave(&np->lock, flags);
 
index 12fd570b9423905bb410da6f7c23b7490d834216..c6fa883daa2217574a54675834c91b40df9ab0d0 100644 (file)
 #define XMAC_ADDR1                     0x000a8UL
 #define  XMAC_ADDR1_ADDR1              0x000000000000ffffULL
 
-#define XMAC_ADDR2                     0x000b0UL 
+#define XMAC_ADDR2                     0x000b0UL
 #define  XMAC_ADDR2_ADDR2              0x000000000000ffffULL
 
 #define XMAC_ADDR_CMPEN                        0x00208UL
index b42c05f84be15d78d59600362f7e8f8f5e0837d0..ff449619f047e57fd36be41805b33bf6b66ec113 100644 (file)
@@ -585,16 +585,13 @@ static inline int rx_refill(struct net_device *ndev, gfp_t gfp)
        for (i=0; i<NR_RX_DESC; i++) {
                struct sk_buff *skb;
                long res;
+
                /* extra 16 bytes for alignment */
-               skb = __dev_alloc_skb(REAL_RX_BUF_SIZE+16, gfp);
+               skb = __netdev_alloc_skb(ndev, REAL_RX_BUF_SIZE+16, gfp);
                if (unlikely(!skb))
                        break;
 
-               res = (long)skb->data & 0xf;
-               res = 0x10 - res;
-               res &= 0xf;
-               skb_reserve(skb, res);
-
+               skb_reserve(skb, skb->data - PTR_ALIGN(skb->data, 16));
                if (gfp != GFP_ATOMIC)
                        spin_lock_irqsave(&dev->rx_info.lock, flags);
                res = ns83820_add_rx_skb(dev, skb);
index 3b78a3819bb3d2ae33cb47e1da8cbddb58739013..7112fd5e0e1ba8f76f9f0995695aed0f7749c212 100644 (file)
@@ -208,7 +208,6 @@ enum Window4 {              /* Window 4: Xcvr/media bits. */
 struct el3_private {
        struct pcmcia_device    *p_dev;
        dev_node_t node;
-       struct net_device_stats stats;
        u16 advertising, partner;               /* NWay media advertisement */
        unsigned char phys;                     /* MII device address */
        unsigned int autoselect:1, default_media:3;     /* Read from the EEPROM/Wn3_Config. */
@@ -741,12 +740,11 @@ static int el3_open(struct net_device *dev)
 
 static void el3_tx_timeout(struct net_device *dev)
 {
-       struct el3_private *lp = netdev_priv(dev);
        unsigned int ioaddr = dev->base_addr;
        
        printk(KERN_NOTICE "%s: Transmit timed out!\n", dev->name);
        dump_status(dev);
-       lp->stats.tx_errors++;
+       dev->stats.tx_errors++;
        dev->trans_start = jiffies;
        /* Issue TX_RESET and TX_START commands. */
        tc574_wait_for_completion(dev, TxReset);
@@ -756,7 +754,6 @@ static void el3_tx_timeout(struct net_device *dev)
 
 static void pop_tx_status(struct net_device *dev)
 {
-       struct el3_private *lp = netdev_priv(dev);
        unsigned int ioaddr = dev->base_addr;
        int i;
     
@@ -772,7 +769,7 @@ static void pop_tx_status(struct net_device *dev)
                        DEBUG(1, "%s: transmit error: status 0x%02x\n",
                                  dev->name, tx_status);
                        outw(TxEnable, ioaddr + EL3_CMD);
-                       lp->stats.tx_aborted_errors++;
+                       dev->stats.tx_aborted_errors++;
                }
                outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
        }
@@ -987,7 +984,7 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev)
                update_stats(dev);
                spin_unlock_irqrestore(&lp->window_lock, flags);
        }
-       return &lp->stats;
+       return &dev->stats;
 }
 
 /*  Update statistics.
@@ -996,7 +993,6 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev)
  */
 static void update_stats(struct net_device *dev)
 {
-       struct el3_private *lp = netdev_priv(dev);
        unsigned int ioaddr = dev->base_addr;
        u8 rx, tx, up;
 
@@ -1008,15 +1004,15 @@ static void update_stats(struct net_device *dev)
        /* Unlike the 3c509 we need not turn off stats updates while reading. */
        /* Switch to the stats window, and read everything. */
        EL3WINDOW(6);
-       lp->stats.tx_carrier_errors             += inb(ioaddr + 0);
-       lp->stats.tx_heartbeat_errors           += inb(ioaddr + 1);
+       dev->stats.tx_carrier_errors            += inb(ioaddr + 0);
+       dev->stats.tx_heartbeat_errors          += inb(ioaddr + 1);
        /* Multiple collisions. */              inb(ioaddr + 2);
-       lp->stats.collisions                    += inb(ioaddr + 3);
-       lp->stats.tx_window_errors              += inb(ioaddr + 4);
-       lp->stats.rx_fifo_errors                += inb(ioaddr + 5);
-       lp->stats.tx_packets                    += inb(ioaddr + 6);
+       dev->stats.collisions                   += inb(ioaddr + 3);
+       dev->stats.tx_window_errors             += inb(ioaddr + 4);
+       dev->stats.rx_fifo_errors               += inb(ioaddr + 5);
+       dev->stats.tx_packets                   += inb(ioaddr + 6);
        up                                       = inb(ioaddr + 9);
-       lp->stats.tx_packets                    += (up&0x30) << 4;
+       dev->stats.tx_packets                   += (up&0x30) << 4;
        /* Rx packets   */                         inb(ioaddr + 7);
        /* Tx deferrals */                         inb(ioaddr + 8);
        rx                                       = inw(ioaddr + 10);
@@ -1026,14 +1022,13 @@ static void update_stats(struct net_device *dev)
        /* BadSSD */                               inb(ioaddr + 12);
        up                                       = inb(ioaddr + 13);
 
-       lp->stats.tx_bytes                      += tx + ((up & 0xf0) << 12);
+       dev->stats.tx_bytes                     += tx + ((up & 0xf0) << 12);
 
        EL3WINDOW(1);
 }
 
 static int el3_rx(struct net_device *dev, int worklimit)
 {
-       struct el3_private *lp = netdev_priv(dev);
        unsigned int ioaddr = dev->base_addr;
        short rx_status;
        
@@ -1043,14 +1038,14 @@ static int el3_rx(struct net_device *dev, int worklimit)
                   (--worklimit >= 0)) {
                if (rx_status & 0x4000) { /* Error, update stats. */
                        short error = rx_status & 0x3800;
-                       lp->stats.rx_errors++;
+                       dev->stats.rx_errors++;
                        switch (error) {
-                       case 0x0000:    lp->stats.rx_over_errors++; break;
-                       case 0x0800:    lp->stats.rx_length_errors++; break;
-                       case 0x1000:    lp->stats.rx_frame_errors++; break;
-                       case 0x1800:    lp->stats.rx_length_errors++; break;
-                       case 0x2000:    lp->stats.rx_frame_errors++; break;
-                       case 0x2800:    lp->stats.rx_crc_errors++; break;
+                       case 0x0000:    dev->stats.rx_over_errors++; break;
+                       case 0x0800:    dev->stats.rx_length_errors++; break;
+                       case 0x1000:    dev->stats.rx_frame_errors++; break;
+                       case 0x1800:    dev->stats.rx_length_errors++; break;
+                       case 0x2000:    dev->stats.rx_frame_errors++; break;
+                       case 0x2800:    dev->stats.rx_crc_errors++; break;
                        }
                } else {
                        short pkt_len = rx_status & 0x7ff;
@@ -1067,12 +1062,12 @@ static int el3_rx(struct net_device *dev, int worklimit)
                                skb->protocol = eth_type_trans(skb, dev);
                                netif_rx(skb);
                                dev->last_rx = jiffies;
-                               lp->stats.rx_packets++;
-                               lp->stats.rx_bytes += pkt_len;
+                               dev->stats.rx_packets++;
+                               dev->stats.rx_bytes += pkt_len;
                        } else {
                                DEBUG(1, "%s: couldn't allocate a sk_buff of"
                                          " size %d.\n", dev->name, pkt_len);
-                               lp->stats.rx_dropped++;
+                               dev->stats.rx_dropped++;
                        }
                }
                tc574_wait_for_completion(dev, RxDiscard);
index 1b1abb19c911d1623e722a8ef18056adbfeb11a8..549a64558420dba22d81afc96f426bfe794e9b27 100644 (file)
@@ -107,7 +107,6 @@ enum RxFilter {
 struct el3_private {
        struct pcmcia_device    *p_dev;
     dev_node_t                 node;
-    struct net_device_stats stats;
     /* For transceiver monitoring */
     struct timer_list  media;
     u16                        media_status;
@@ -566,12 +565,11 @@ static int el3_open(struct net_device *dev)
 
 static void el3_tx_timeout(struct net_device *dev)
 {
-    struct el3_private *lp = netdev_priv(dev);
     unsigned int ioaddr = dev->base_addr;
     
     printk(KERN_WARNING "%s: Transmit timed out!\n", dev->name);
     dump_status(dev);
-    lp->stats.tx_errors++;
+    dev->stats.tx_errors++;
     dev->trans_start = jiffies;
     /* Issue TX_RESET and TX_START commands. */
     tc589_wait_for_completion(dev, TxReset);
@@ -581,7 +579,6 @@ static void el3_tx_timeout(struct net_device *dev)
 
 static void pop_tx_status(struct net_device *dev)
 {
-    struct el3_private *lp = netdev_priv(dev);
     unsigned int ioaddr = dev->base_addr;
     int i;
     
@@ -596,7 +593,7 @@ static void pop_tx_status(struct net_device *dev)
            DEBUG(1, "%s: transmit error: status 0x%02x\n",
                  dev->name, tx_status);
            outw(TxEnable, ioaddr + EL3_CMD);
-           lp->stats.tx_aborted_errors++;
+           dev->stats.tx_aborted_errors++;
        }
        outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
     }
@@ -614,7 +611,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
     spin_lock_irqsave(&priv->lock, flags);    
 
-    priv->stats.tx_bytes += skb->len;
+    dev->stats.tx_bytes += skb->len;
 
     /* Put out the doubleword header... */
     outw(skb->len, ioaddr + TX_FIFO);
@@ -764,7 +761,7 @@ static void media_check(unsigned long arg)
        outw(StatsDisable, ioaddr + EL3_CMD);
        errs = inb(ioaddr + 0);
        outw(StatsEnable, ioaddr + EL3_CMD);
-       lp->stats.tx_carrier_errors += errs;
+       dev->stats.tx_carrier_errors += errs;
        if (errs || (lp->media_status & 0x0010)) media |= 0x0010;
     }
 
@@ -814,7 +811,7 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev)
        update_stats(dev);
        spin_unlock_irqrestore(&lp->lock, flags);
     }
-    return &lp->stats;
+    return &dev->stats;
 }
 
 /*
@@ -827,7 +824,6 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev)
 */
 static void update_stats(struct net_device *dev)
 {
-    struct el3_private *lp = netdev_priv(dev);
     unsigned int ioaddr = dev->base_addr;
 
     DEBUG(2, "%s: updating the statistics.\n", dev->name);
@@ -835,13 +831,13 @@ static void update_stats(struct net_device *dev)
     outw(StatsDisable, ioaddr + EL3_CMD);
     /* Switch to the stats window, and read everything. */
     EL3WINDOW(6);
-    lp->stats.tx_carrier_errors        += inb(ioaddr + 0);
-    lp->stats.tx_heartbeat_errors      += inb(ioaddr + 1);
+    dev->stats.tx_carrier_errors       += inb(ioaddr + 0);
+    dev->stats.tx_heartbeat_errors     += inb(ioaddr + 1);
     /* Multiple collisions. */         inb(ioaddr + 2);
-    lp->stats.collisions               += inb(ioaddr + 3);
-    lp->stats.tx_window_errors         += inb(ioaddr + 4);
-    lp->stats.rx_fifo_errors           += inb(ioaddr + 5);
-    lp->stats.tx_packets               += inb(ioaddr + 6);
+    dev->stats.collisions              += inb(ioaddr + 3);
+    dev->stats.tx_window_errors                += inb(ioaddr + 4);
+    dev->stats.rx_fifo_errors          += inb(ioaddr + 5);
+    dev->stats.tx_packets              += inb(ioaddr + 6);
     /* Rx packets   */                 inb(ioaddr + 7);
     /* Tx deferrals */                 inb(ioaddr + 8);
     /* Rx octets */                    inw(ioaddr + 10);
@@ -854,7 +850,6 @@ static void update_stats(struct net_device *dev)
 
 static int el3_rx(struct net_device *dev)
 {
-    struct el3_private *lp = netdev_priv(dev);
     unsigned int ioaddr = dev->base_addr;
     int worklimit = 32;
     short rx_status;
@@ -865,14 +860,14 @@ static int el3_rx(struct net_device *dev)
           (--worklimit >= 0)) {
        if (rx_status & 0x4000) { /* Error, update stats. */
            short error = rx_status & 0x3800;
-           lp->stats.rx_errors++;
+           dev->stats.rx_errors++;
            switch (error) {
-           case 0x0000:        lp->stats.rx_over_errors++; break;
-           case 0x0800:        lp->stats.rx_length_errors++; break;
-           case 0x1000:        lp->stats.rx_frame_errors++; break;
-           case 0x1800:        lp->stats.rx_length_errors++; break;
-           case 0x2000:        lp->stats.rx_frame_errors++; break;
-           case 0x2800:        lp->stats.rx_crc_errors++; break;
+           case 0x0000:        dev->stats.rx_over_errors++; break;
+           case 0x0800:        dev->stats.rx_length_errors++; break;
+           case 0x1000:        dev->stats.rx_frame_errors++; break;
+           case 0x1800:        dev->stats.rx_length_errors++; break;
+           case 0x2000:        dev->stats.rx_frame_errors++; break;
+           case 0x2800:        dev->stats.rx_crc_errors++; break;
            }
        } else {
            short pkt_len = rx_status & 0x7ff;
@@ -889,12 +884,12 @@ static int el3_rx(struct net_device *dev)
                skb->protocol = eth_type_trans(skb, dev);
                netif_rx(skb);
                dev->last_rx = jiffies;
-               lp->stats.rx_packets++;
-               lp->stats.rx_bytes += pkt_len;
+               dev->stats.rx_packets++;
+               dev->stats.rx_bytes += pkt_len;
            } else {
                DEBUG(1, "%s: couldn't allocate a sk_buff of"
                      " size %d.\n", dev->name, pkt_len);
-               lp->stats.rx_dropped++;
+               dev->stats.rx_dropped++;
            }
        }
        /* Pop the top of the Rx FIFO */
@@ -929,7 +924,7 @@ static int el3_close(struct net_device *dev)
     DEBUG(1, "%s: shutting down ethercard.\n", dev->name);
 
     if (pcmcia_dev_present(link)) {
-       /* Turn off statistics ASAP.  We update lp->stats below. */
+       /* Turn off statistics ASAP.  We update dev->stats below. */
        outw(StatsDisable, ioaddr + EL3_CMD);
        
        /* Disable the receiver and transmitter. */
index ce95c5d168fe9922382726ce71e295392548f2a3..d7018ff9e171b58a925d15786cd6fffeb81d98ca 100644 (file)
@@ -1021,7 +1021,7 @@ static void ei_tx_timeout(struct net_device *dev)
        int txsr, isr, tickssofar = jiffies - dev->trans_start;
        unsigned long flags;
 
-       ei_local->stat.tx_errors++;
+       dev->stats.tx_errors++;
 
        spin_lock_irqsave(&ei_local->page_lock, flags);
        txsr = inb(e8390_base+EN0_TSR);
@@ -1032,7 +1032,7 @@ static void ei_tx_timeout(struct net_device *dev)
                dev->name, (txsr & ENTSR_ABT) ? "excess collisions." :
                (isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar);
 
-       if (!isr && !ei_local->stat.tx_packets) 
+       if (!isr && !dev->stats.tx_packets) 
        {
                /* The 8390 probably hasn't gotten on the cable yet. */
                ei_local->interface_num ^= 1;   /* Try a different xcvr.  */
@@ -1122,7 +1122,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
                netif_stop_queue(dev);
                outb_p(ENISR_ALL, e8390_base + EN0_IMR);
                spin_unlock_irqrestore(&ei_local->page_lock, flags);
-               ei_local->stat.tx_errors++;
+               dev->stats.tx_errors++;
                return 1;
        }
 
@@ -1170,7 +1170,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
        spin_unlock_irqrestore(&ei_local->page_lock, flags);
 
        dev_kfree_skb (skb);
-       ei_local->stat.tx_bytes += send_length;
+       dev->stats.tx_bytes += send_length;
     
        return 0;
 }
@@ -1262,9 +1262,9 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id)
 
                if (interrupts & ENISR_COUNTERS) 
                {
-                       ei_local->stat.rx_frame_errors += inb_p(e8390_base + EN0_COUNTER0);
-                       ei_local->stat.rx_crc_errors   += inb_p(e8390_base + EN0_COUNTER1);
-                       ei_local->stat.rx_missed_errors+= inb_p(e8390_base + EN0_COUNTER2);
+                       dev->stats.rx_frame_errors += inb_p(e8390_base + EN0_COUNTER0);
+                       dev->stats.rx_crc_errors   += inb_p(e8390_base + EN0_COUNTER1);
+                       dev->stats.rx_missed_errors+= inb_p(e8390_base + EN0_COUNTER2);
                }
        }
     
@@ -1309,7 +1309,6 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id)
 static void ei_tx_err(struct net_device *dev)
 {
        long e8390_base = dev->base_addr;
-       struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
        unsigned char txsr = inb_p(e8390_base+EN0_TSR);
        unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU);
 
@@ -1332,10 +1331,10 @@ static void ei_tx_err(struct net_device *dev)
                ei_tx_intr(dev);
        else 
        {
-               ei_local->stat.tx_errors++;
-               if (txsr & ENTSR_CRS) ei_local->stat.tx_carrier_errors++;
-               if (txsr & ENTSR_CDH) ei_local->stat.tx_heartbeat_errors++;
-               if (txsr & ENTSR_OWC) ei_local->stat.tx_window_errors++;
+               dev->stats.tx_errors++;
+               if (txsr & ENTSR_CRS) dev->stats.tx_carrier_errors++;
+               if (txsr & ENTSR_CDH) dev->stats.tx_heartbeat_errors++;
+               if (txsr & ENTSR_OWC) dev->stats.tx_window_errors++;
        }
 }
 
@@ -1397,25 +1396,25 @@ static void ei_tx_intr(struct net_device *dev)
 
        /* Minimize Tx latency: update the statistics after we restart TXing. */
        if (status & ENTSR_COL)
-               ei_local->stat.collisions++;
+               dev->stats.collisions++;
        if (status & ENTSR_PTX)
-               ei_local->stat.tx_packets++;
+               dev->stats.tx_packets++;
        else 
        {
-               ei_local->stat.tx_errors++;
+               dev->stats.tx_errors++;
                if (status & ENTSR_ABT) 
                {
-                       ei_local->stat.tx_aborted_errors++;
-                       ei_local->stat.collisions += 16;
+                       dev->stats.tx_aborted_errors++;
+                       dev->stats.collisions += 16;
                }
                if (status & ENTSR_CRS) 
-                       ei_local->stat.tx_carrier_errors++;
+                       dev->stats.tx_carrier_errors++;
                if (status & ENTSR_FU) 
-                       ei_local->stat.tx_fifo_errors++;
+                       dev->stats.tx_fifo_errors++;
                if (status & ENTSR_CDH)
-                       ei_local->stat.tx_heartbeat_errors++;
+                       dev->stats.tx_heartbeat_errors++;
                if (status & ENTSR_OWC)
-                       ei_local->stat.tx_window_errors++;
+                       dev->stats.tx_window_errors++;
        }
        netif_wake_queue(dev);
 }
@@ -1476,8 +1475,8 @@ static void ei_receive(struct net_device *dev)
                                printk(KERN_DEBUG "%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n",
                                           dev->name, rx_frame.count, rx_frame.status,
                                           rx_frame.next);
-                       ei_local->stat.rx_errors++;
-                       ei_local->stat.rx_length_errors++;
+                       dev->stats.rx_errors++;
+                       dev->stats.rx_length_errors++;
                }
                 else if ((pkt_stat & 0x0F) == ENRSR_RXOK) 
                {
@@ -1489,7 +1488,7 @@ static void ei_receive(struct net_device *dev)
                                if (ei_debug > 1)
                                        printk(KERN_DEBUG "%s: Couldn't allocate a sk_buff of size %d.\n",
                                                   dev->name, pkt_len);
-                               ei_local->stat.rx_dropped++;
+                               dev->stats.rx_dropped++;
                                break;
                        }
                        else
@@ -1500,10 +1499,10 @@ static void ei_receive(struct net_device *dev)
                                skb->protocol=eth_type_trans(skb,dev);
                                netif_rx(skb);
                                dev->last_rx = jiffies;
-                               ei_local->stat.rx_packets++;
-                               ei_local->stat.rx_bytes += pkt_len;
+                               dev->stats.rx_packets++;
+                               dev->stats.rx_bytes += pkt_len;
                                if (pkt_stat & ENRSR_PHY)
-                                       ei_local->stat.multicast++;
+                                       dev->stats.multicast++;
                        }
                } 
                else 
@@ -1512,10 +1511,10 @@ static void ei_receive(struct net_device *dev)
                                printk(KERN_DEBUG "%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n",
                                           dev->name, rx_frame.status, rx_frame.next,
                                           rx_frame.count);
-                       ei_local->stat.rx_errors++;
+                       dev->stats.rx_errors++;
                        /* NB: The NIC counts CRC, frame and missed errors. */
                        if (pkt_stat & ENRSR_FO)
-                               ei_local->stat.rx_fifo_errors++;
+                               dev->stats.rx_fifo_errors++;
                }
                next_frame = rx_frame.next;
                
@@ -1550,7 +1549,6 @@ static void ei_rx_overrun(struct net_device *dev)
        axnet_dev_t *info = PRIV(dev);
        long e8390_base = dev->base_addr;
        unsigned char was_txing, must_resend = 0;
-       struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
     
        /*
         * Record whether a Tx was in progress and then issue the
@@ -1561,7 +1559,7 @@ static void ei_rx_overrun(struct net_device *dev)
     
        if (ei_debug > 1)
                printk(KERN_DEBUG "%s: Receiver overrun.\n", dev->name);
-       ei_local->stat.rx_over_errors++;
+       dev->stats.rx_over_errors++;
     
        /* 
         * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total.
@@ -1622,16 +1620,16 @@ static struct net_device_stats *get_stats(struct net_device *dev)
     
        /* If the card is stopped, just return the present stats. */
        if (!netif_running(dev))
-               return &ei_local->stat;
+               return &dev->stats;
 
        spin_lock_irqsave(&ei_local->page_lock,flags);
        /* Read the counter registers, assuming we are in page 0. */
-       ei_local->stat.rx_frame_errors += inb_p(ioaddr + EN0_COUNTER0);
-       ei_local->stat.rx_crc_errors   += inb_p(ioaddr + EN0_COUNTER1);
-       ei_local->stat.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2);
+       dev->stats.rx_frame_errors += inb_p(ioaddr + EN0_COUNTER0);
+       dev->stats.rx_crc_errors   += inb_p(ioaddr + EN0_COUNTER1);
+       dev->stats.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2);
        spin_unlock_irqrestore(&ei_local->page_lock, flags);
     
-       return &ei_local->stat;
+       return &dev->stats;
 }
 
 /*
index 1c89b97f4e0931c02699bbac0efcaf26ec73c4cf..ca8c0e03740027980ded217605ea394f5c5c3ca0 100644 (file)
@@ -1973,7 +1973,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
       err_free_ring:
        pcnet32_free_ring(dev);
       err_free_consistent:
-       pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), 
+       pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block),
                            lp->init_block, lp->init_dma_addr);
       err_free_netdev:
        free_netdev(dev);
@@ -2953,7 +2953,7 @@ static void __devexit pcnet32_remove_one(struct pci_dev *pdev)
                unregister_netdev(dev);
                pcnet32_free_ring(dev);
                release_region(dev->base_addr, PCNET32_TOTAL_SIZE);
-               pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), 
+               pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block),
                                    lp->init_block, lp->init_dma_addr);
                free_netdev(dev);
                pci_disable_device(pdev);
@@ -3036,7 +3036,7 @@ static void __exit pcnet32_cleanup_module(void)
                unregister_netdev(pcnet32_dev);
                pcnet32_free_ring(pcnet32_dev);
                release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE);
-               pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), 
+               pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block),
                                    lp->init_block, lp->init_dma_addr);
                free_netdev(pcnet32_dev);
                pcnet32_dev = next_dev;
index 6eb2d31d1e3419fb07f26ccb1d197f2aa2a79f75..d55932acd887fc3b41c32a359c92077e9dfbd7b8 100644 (file)
@@ -53,7 +53,8 @@ config SMSC_PHY
 config BROADCOM_PHY
        tristate "Drivers for Broadcom PHYs"
        ---help---
-         Currently supports the BCM5411, BCM5421 and BCM5461 PHYs.
+         Currently supports the BCM5411, BCM5421, BCM5461, BCM5464, BCM5481
+         and BCM5482 PHYs.
 
 config ICPLUS_PHY
        tristate "Drivers for ICPlus PHYs"
@@ -83,4 +84,10 @@ config MDIO_BITBANG
 
          If in doubt, say N.
 
+config MDIO_OF_GPIO
+       tristate "Support for GPIO lib-based bitbanged MDIO buses"
+       depends on MDIO_BITBANG && OF_GPIO
+       ---help---
+         Supports GPIO lib-based MDIO busses.
+
 endif # PHYLIB
index 5997d6ef702b979742d30642099411bb6aea815c..eee329fa6f5355dfa1ef0817aa6ebc080553f8c5 100644 (file)
@@ -15,3 +15,4 @@ obj-$(CONFIG_ICPLUS_PHY)      += icplus.o
 obj-$(CONFIG_REALTEK_PHY)      += realtek.o
 obj-$(CONFIG_FIXED_PHY)                += fixed.o
 obj-$(CONFIG_MDIO_BITBANG)     += mdio-bitbang.o
+obj-$(CONFIG_MDIO_OF_GPIO)     += mdio-ofgpio.o
index 60c5cfe969186344b4e36021c6efd0fdd468313e..4b4dc98ad165df01b96dcd9753419d383132461d 100644 (file)
 #define MII_BCM54XX_ESR                0x11    /* BCM54xx extended status register */
 #define MII_BCM54XX_ESR_IS     0x1000  /* Interrupt status */
 
+#define MII_BCM54XX_EXP_DATA   0x15    /* Expansion register data */
+#define MII_BCM54XX_EXP_SEL    0x17    /* Expansion register select */
+#define MII_BCM54XX_EXP_SEL_SSD        0x0e00  /* Secondary SerDes select */
+#define MII_BCM54XX_EXP_SEL_ER 0x0f00  /* Expansion register select */
+
+#define MII_BCM54XX_AUX_CTL    0x18    /* Auxiliary control register */
 #define MII_BCM54XX_ISR                0x1a    /* BCM54xx interrupt status register */
 #define MII_BCM54XX_IMR                0x1b    /* BCM54xx interrupt mask register */
 #define MII_BCM54XX_INT_CRCERR 0x0001  /* CRC error */
 #define MII_BCM54XX_INT_MDIX   0x2000  /* MDIX status change */
 #define MII_BCM54XX_INT_PSERR  0x4000  /* Pair swap error */
 
+#define MII_BCM54XX_SHD                0x1c    /* 0x1c shadow registers */
+#define MII_BCM54XX_SHD_WRITE  0x8000
+#define MII_BCM54XX_SHD_VAL(x) ((x & 0x1f) << 10)
+#define MII_BCM54XX_SHD_DATA(x)        ((x & 0x3ff) << 0)
+
+/*
+ * Broadcom LED source encodings.  These are used in BCM5461, BCM5481,
+ * BCM5482, and possibly some others.
+ */
+#define BCM_LED_SRC_LINKSPD1   0x0
+#define BCM_LED_SRC_LINKSPD2   0x1
+#define BCM_LED_SRC_XMITLED    0x2
+#define BCM_LED_SRC_ACTIVITYLED        0x3
+#define BCM_LED_SRC_FDXLED     0x4
+#define BCM_LED_SRC_SLAVE      0x5
+#define BCM_LED_SRC_INTR       0x6
+#define BCM_LED_SRC_QUALITY    0x7
+#define BCM_LED_SRC_RCVLED     0x8
+#define BCM_LED_SRC_MULTICOLOR1        0xa
+#define BCM_LED_SRC_OPENSHORT  0xb
+#define BCM_LED_SRC_OFF                0xe     /* Tied high */
+#define BCM_LED_SRC_ON         0xf     /* Tied low */
+
+/*
+ * BCM5482: Shadow registers
+ * Shadow values go into bits [14:10] of register 0x1c to select a shadow
+ * register to access.
+ */
+#define BCM5482_SHD_LEDS1      0x0d    /* 01101: LED Selector 1 */
+                                       /* LED3 / ~LINKSPD[2] selector */
+#define BCM5482_SHD_LEDS1_LED3(src)    ((src & 0xf) << 4)
+                                       /* LED1 / ~LINKSPD[1] selector */
+#define BCM5482_SHD_LEDS1_LED1(src)    ((src & 0xf) << 0)
+#define BCM5482_SHD_SSD                0x14    /* 10100: Secondary SerDes control */
+#define BCM5482_SHD_SSD_LEDM   0x0008  /* SSD LED Mode enable */
+#define BCM5482_SHD_SSD_EN     0x0001  /* SSD enable */
+#define BCM5482_SHD_MODE       0x1f    /* 11111: Mode Control Register */
+#define BCM5482_SHD_MODE_1000BX        0x0001  /* Enable 1000BASE-X registers */
+
+/*
+ * BCM5482: Secondary SerDes registers
+ */
+#define BCM5482_SSD_1000BX_CTL         0x00    /* 1000BASE-X Control */
+#define BCM5482_SSD_1000BX_CTL_PWRDOWN 0x0800  /* Power-down SSD */
+#define BCM5482_SSD_SGMII_SLAVE                0x15    /* SGMII Slave Register */
+#define BCM5482_SSD_SGMII_SLAVE_EN     0x0002  /* Slave mode enable */
+#define BCM5482_SSD_SGMII_SLAVE_AD     0x0001  /* Slave auto-detection */
+
+/*
+ * Device flags for PHYs that can be configured for different operating
+ * modes.
+ */
+#define PHY_BCM_FLAGS_VALID            0x80000000
+#define PHY_BCM_FLAGS_INTF_XAUI                0x00000020
+#define PHY_BCM_FLAGS_INTF_SGMII       0x00000010
+#define PHY_BCM_FLAGS_MODE_1000BX      0x00000002
+#define PHY_BCM_FLAGS_MODE_COPPER      0x00000001
+
 MODULE_DESCRIPTION("Broadcom PHY driver");
 MODULE_AUTHOR("Maciej W. Rozycki");
 MODULE_LICENSE("GPL");
 
+/*
+ * Indirect register access functions for the 1000BASE-T/100BASE-TX/10BASE-T
+ * 0x1c shadow registers.
+ */
+static int bcm54xx_shadow_read(struct phy_device *phydev, u16 shadow)
+{
+       phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow));
+       return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD));
+}
+
+static int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow, u16 val)
+{
+       return phy_write(phydev, MII_BCM54XX_SHD,
+                        MII_BCM54XX_SHD_WRITE |
+                        MII_BCM54XX_SHD_VAL(shadow) |
+                        MII_BCM54XX_SHD_DATA(val));
+}
+
+/*
+ * Indirect register access functions for the Expansion Registers
+ * and Secondary SerDes registers (when sec_serdes=1).
+ */
+static int bcm54xx_exp_read(struct phy_device *phydev,
+                           int sec_serdes, u8 regnum)
+{
+       int val;
+
+       phy_write(phydev, MII_BCM54XX_EXP_SEL,
+                 (sec_serdes ? MII_BCM54XX_EXP_SEL_SSD :
+                               MII_BCM54XX_EXP_SEL_ER) |
+                 regnum);
+       val = phy_read(phydev, MII_BCM54XX_EXP_DATA);
+       phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
+
+       return val;
+}
+
+static int bcm54xx_exp_write(struct phy_device *phydev,
+                            int sec_serdes, u8 regnum, u16 val)
+{
+       int ret;
+
+       phy_write(phydev, MII_BCM54XX_EXP_SEL,
+                 (sec_serdes ? MII_BCM54XX_EXP_SEL_SSD :
+                               MII_BCM54XX_EXP_SEL_ER) |
+                 regnum);
+       ret = phy_write(phydev, MII_BCM54XX_EXP_DATA, val);
+       phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
+
+       return ret;
+}
+
 static int bcm54xx_config_init(struct phy_device *phydev)
 {
        int reg, err;
@@ -70,6 +186,87 @@ static int bcm54xx_config_init(struct phy_device *phydev)
        return 0;
 }
 
+static int bcm5482_config_init(struct phy_device *phydev)
+{
+       int err, reg;
+
+       err = bcm54xx_config_init(phydev);
+
+       if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
+               /*
+                * Enable secondary SerDes and its use as an LED source
+                */
+               reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_SSD);
+               bcm54xx_shadow_write(phydev, BCM5482_SHD_SSD,
+                                    reg |
+                                    BCM5482_SHD_SSD_LEDM |
+                                    BCM5482_SHD_SSD_EN);
+
+               /*
+                * Enable SGMII slave mode and auto-detection
+                */
+               reg = bcm54xx_exp_read(phydev, 1, BCM5482_SSD_SGMII_SLAVE);
+               bcm54xx_exp_write(phydev, 1, BCM5482_SSD_SGMII_SLAVE,
+                                 reg |
+                                 BCM5482_SSD_SGMII_SLAVE_EN |
+                                 BCM5482_SSD_SGMII_SLAVE_AD);
+
+               /*
+                * Disable secondary SerDes powerdown
+                */
+               reg = bcm54xx_exp_read(phydev, 1, BCM5482_SSD_1000BX_CTL);
+               bcm54xx_exp_write(phydev, 1, BCM5482_SSD_1000BX_CTL,
+                                 reg & ~BCM5482_SSD_1000BX_CTL_PWRDOWN);
+
+               /*
+                * Select 1000BASE-X register set (primary SerDes)
+                */
+               reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_MODE);
+               bcm54xx_shadow_write(phydev, BCM5482_SHD_MODE,
+                                    reg | BCM5482_SHD_MODE_1000BX);
+
+               /*
+                * LED1=ACTIVITYLED, LED3=LINKSPD[2]
+                * (Use LED1 as secondary SerDes ACTIVITY LED)
+                */
+               bcm54xx_shadow_write(phydev, BCM5482_SHD_LEDS1,
+                       BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) |
+                       BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2));
+
+               /*
+                * Auto-negotiation doesn't seem to work quite right
+                * in this mode, so we disable it and force it to the
+                * right speed/duplex setting.  Only 'link status'
+                * is important.
+                */
+               phydev->autoneg = AUTONEG_DISABLE;
+               phydev->speed = SPEED_1000;
+               phydev->duplex = DUPLEX_FULL;
+       }
+
+       return err;
+}
+
+static int bcm5482_read_status(struct phy_device *phydev)
+{
+       int err;
+
+       err = genphy_read_status(phydev);
+
+       if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
+               /*
+                * Only link status matters for 1000Base-X mode, so force
+                * 1000 Mbit/s full-duplex status
+                */
+               if (phydev->link) {
+                       phydev->speed = SPEED_1000;
+                       phydev->duplex = DUPLEX_FULL;
+               }
+       }
+
+       return err;
+}
+
 static int bcm54xx_ack_interrupt(struct phy_device *phydev)
 {
        int reg;
@@ -210,9 +407,9 @@ static struct phy_driver bcm5482_driver = {
        .name           = "Broadcom BCM5482",
        .features       = PHY_GBIT_FEATURES,
        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
-       .config_init    = bcm54xx_config_init,
+       .config_init    = bcm5482_config_init,
        .config_aneg    = genphy_config_aneg,
-       .read_status    = genphy_read_status,
+       .read_status    = bcm5482_read_status,
        .ack_interrupt  = bcm54xx_ack_interrupt,
        .config_intr    = bcm54xx_config_intr,
        .driver         = { .owner = THIS_MODULE },
diff --git a/drivers/net/phy/mdio-ofgpio.c b/drivers/net/phy/mdio-ofgpio.c
new file mode 100644 (file)
index 0000000..7edfc0c
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * OpenFirmware GPIO based MDIO bitbang driver.
+ *
+ * Copyright (c) 2008 CSE Semaphore Belgium.
+ *  by Laurent Pinchart <laurentp@cse-semaphore.com>
+ *
+ * Based on earlier work by
+ *
+ * Copyright (c) 2003 Intracom S.A.
+ *  by Pantelis Antoniou <panto@intracom.gr>
+ *
+ * 2005 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/mdio-bitbang.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+
+struct mdio_gpio_info {
+       struct mdiobb_ctrl ctrl;
+       int mdc, mdio;
+};
+
+static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
+{
+       struct mdio_gpio_info *bitbang =
+               container_of(ctrl, struct mdio_gpio_info, ctrl);
+
+       if (dir)
+               gpio_direction_output(bitbang->mdio, 1);
+       else
+               gpio_direction_input(bitbang->mdio);
+}
+
+static int mdio_read(struct mdiobb_ctrl *ctrl)
+{
+       struct mdio_gpio_info *bitbang =
+               container_of(ctrl, struct mdio_gpio_info, ctrl);
+
+       return gpio_get_value(bitbang->mdio);
+}
+
+static void mdio(struct mdiobb_ctrl *ctrl, int what)
+{
+       struct mdio_gpio_info *bitbang =
+               container_of(ctrl, struct mdio_gpio_info, ctrl);
+
+       gpio_set_value(bitbang->mdio, what);
+}
+
+static void mdc(struct mdiobb_ctrl *ctrl, int what)
+{
+       struct mdio_gpio_info *bitbang =
+               container_of(ctrl, struct mdio_gpio_info, ctrl);
+
+       gpio_set_value(bitbang->mdc, what);
+}
+
+static struct mdiobb_ops mdio_gpio_ops = {
+       .owner = THIS_MODULE,
+       .set_mdc = mdc,
+       .set_mdio_dir = mdio_dir,
+       .set_mdio_data = mdio,
+       .get_mdio_data = mdio_read,
+};
+
+static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus,
+                                         struct device_node *np)
+{
+       struct mdio_gpio_info *bitbang = bus->priv;
+
+       bitbang->mdc = of_get_gpio(np, 0);
+       bitbang->mdio = of_get_gpio(np, 1);
+
+       if (bitbang->mdc < 0 || bitbang->mdio < 0)
+               return -ENODEV;
+
+       snprintf(bus->id, MII_BUS_ID_SIZE, "%x", bitbang->mdc);
+       return 0;
+}
+
+static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
+{
+       const u32 *data;
+       int len, id, irq;
+
+       data = of_get_property(np, "reg", &len);
+       if (!data || len != 4)
+               return;
+
+       id = *data;
+       bus->phy_mask &= ~(1 << id);
+
+       irq = of_irq_to_resource(np, 0, NULL);
+       if (irq != NO_IRQ)
+               bus->irq[id] = irq;
+}
+
+static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
+                                        const struct of_device_id *match)
+{
+       struct device_node *np = NULL;
+       struct mii_bus *new_bus;
+       struct mdio_gpio_info *bitbang;
+       int ret = -ENOMEM;
+       int i;
+
+       bitbang = kzalloc(sizeof(struct mdio_gpio_info), GFP_KERNEL);
+       if (!bitbang)
+               goto out;
+
+       bitbang->ctrl.ops = &mdio_gpio_ops;
+
+       new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
+       if (!new_bus)
+               goto out_free_priv;
+
+       new_bus->name = "GPIO Bitbanged MII",
+
+       ret = mdio_ofgpio_bitbang_init(new_bus, ofdev->node);
+       if (ret)
+               goto out_free_bus;
+
+       new_bus->phy_mask = ~0;
+       new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+       if (!new_bus->irq)
+               goto out_free_bus;
+
+       for (i = 0; i < PHY_MAX_ADDR; i++)
+               new_bus->irq[i] = -1;
+
+       while ((np = of_get_next_child(ofdev->node, np)))
+               if (!strcmp(np->type, "ethernet-phy"))
+                       add_phy(new_bus, np);
+
+       new_bus->dev = &ofdev->dev;
+       dev_set_drvdata(&ofdev->dev, new_bus);
+
+       ret = mdiobus_register(new_bus);
+       if (ret)
+               goto out_free_irqs;
+
+       return 0;
+
+out_free_irqs:
+       dev_set_drvdata(&ofdev->dev, NULL);
+       kfree(new_bus->irq);
+out_free_bus:
+       kfree(new_bus);
+out_free_priv:
+       free_mdio_bitbang(new_bus);
+out:
+       return ret;
+}
+
+static int mdio_ofgpio_remove(struct of_device *ofdev)
+{
+       struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
+       struct mdio_gpio_info *bitbang = bus->priv;
+
+       mdiobus_unregister(bus);
+       free_mdio_bitbang(bus);
+       dev_set_drvdata(&ofdev->dev, NULL);
+       kfree(bus->irq);
+       kfree(bitbang);
+       kfree(bus);
+
+       return 0;
+}
+
+static struct of_device_id mdio_ofgpio_match[] = {
+       {
+               .compatible = "virtual,mdio-gpio",
+       },
+       {},
+};
+
+static struct of_platform_driver mdio_ofgpio_driver = {
+       .name = "mdio-gpio",
+       .match_table = mdio_ofgpio_match,
+       .probe = mdio_ofgpio_probe,
+       .remove = mdio_ofgpio_remove,
+};
+
+static int mdio_ofgpio_init(void)
+{
+       return of_register_platform_driver(&mdio_ofgpio_driver);
+}
+
+static void mdio_ofgpio_exit(void)
+{
+       of_unregister_platform_driver(&mdio_ofgpio_driver);
+}
+
+module_init(mdio_ofgpio_init);
+module_exit(mdio_ofgpio_exit);
index 1f4ca2b54a73370213d1ce162c5c048e00bfc732..c926bf0b190efd6d9abe3cba36a477102731f4f8 100644 (file)
@@ -361,7 +361,7 @@ static int ppp_open(struct inode *inode, struct file *file)
        return 0;
 }
 
-static int ppp_release(struct inode *inode, struct file *file)
+static int ppp_release(struct inode *unused, struct file *file)
 {
        struct ppp_file *pf = file->private_data;
        struct ppp *ppp;
@@ -545,8 +545,7 @@ static int get_filter(void __user *arg, struct sock_filter **p)
 }
 #endif /* CONFIG_PPP_FILTER */
 
-static int ppp_ioctl(struct inode *inode, struct file *file,
-                    unsigned int cmd, unsigned long arg)
+static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct ppp_file *pf = file->private_data;
        struct ppp *ppp;
@@ -574,24 +573,29 @@ static int ppp_ioctl(struct inode *inode, struct file *file,
                 * this fd and reopening /dev/ppp.
                 */
                err = -EINVAL;
+               lock_kernel();
                if (pf->kind == INTERFACE) {
                        ppp = PF_TO_PPP(pf);
                        if (file == ppp->owner)
                                ppp_shutdown_interface(ppp);
                }
                if (atomic_read(&file->f_count) <= 2) {
-                       ppp_release(inode, file);
+                       ppp_release(NULL, file);
                        err = 0;
                } else
                        printk(KERN_DEBUG "PPPIOCDETACH file->f_count=%d\n",
                               atomic_read(&file->f_count));
+               unlock_kernel();
                return err;
        }
 
        if (pf->kind == CHANNEL) {
-               struct channel *pch = PF_TO_CHANNEL(pf);
+               struct channel *pch;
                struct ppp_channel *chan;
 
+               lock_kernel();
+               pch = PF_TO_CHANNEL(pf);
+
                switch (cmd) {
                case PPPIOCCONNECT:
                        if (get_user(unit, p))
@@ -611,6 +615,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file,
                                err = chan->ops->ioctl(chan, cmd, arg);
                        up_read(&pch->chan_sem);
                }
+               unlock_kernel();
                return err;
        }
 
@@ -620,6 +625,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file,
                return -EINVAL;
        }
 
+       lock_kernel();
        ppp = PF_TO_PPP(pf);
        switch (cmd) {
        case PPPIOCSMRU:
@@ -767,7 +773,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file,
        default:
                err = -ENOTTY;
        }
-
+       unlock_kernel();
        return err;
 }
 
@@ -779,6 +785,7 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file,
        struct channel *chan;
        int __user *p = (int __user *)arg;
 
+       lock_kernel();
        switch (cmd) {
        case PPPIOCNEWUNIT:
                /* Create a new ppp unit */
@@ -827,6 +834,7 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file,
        default:
                err = -ENOTTY;
        }
+       unlock_kernel();
        return err;
 }
 
@@ -835,7 +843,7 @@ static const struct file_operations ppp_device_fops = {
        .read           = ppp_read,
        .write          = ppp_write,
        .poll           = ppp_poll,
-       .ioctl          = ppp_ioctl,
+       .unlocked_ioctl = ppp_ioctl,
        .open           = ppp_open,
        .release        = ppp_release
 };
index e365efb3c6275c6af7d7fc4fa9688e95a953b86c..2eb54fd7bed532153f4aafef049a97f5459caa02 100644 (file)
@@ -110,7 +110,7 @@ static void gelic_card_get_ether_port_status(struct gelic_card *card,
 void gelic_card_up(struct gelic_card *card)
 {
        pr_debug("%s: called\n", __func__);
-       down(&card->updown_lock);
+       mutex_lock(&card->updown_lock);
        if (atomic_inc_return(&card->users) == 1) {
                pr_debug("%s: real do\n", __func__);
                /* enable irq */
@@ -120,7 +120,7 @@ void gelic_card_up(struct gelic_card *card)
 
                napi_enable(&card->napi);
        }
-       up(&card->updown_lock);
+       mutex_unlock(&card->updown_lock);
        pr_debug("%s: done\n", __func__);
 }
 
@@ -128,7 +128,7 @@ void gelic_card_down(struct gelic_card *card)
 {
        u64 mask;
        pr_debug("%s: called\n", __func__);
-       down(&card->updown_lock);
+       mutex_lock(&card->updown_lock);
        if (atomic_dec_if_positive(&card->users) == 0) {
                pr_debug("%s: real do\n", __func__);
                napi_disable(&card->napi);
@@ -146,7 +146,7 @@ void gelic_card_down(struct gelic_card *card)
                /* stop tx */
                gelic_card_disable_txdmac(card);
        }
-       up(&card->updown_lock);
+       mutex_unlock(&card->updown_lock);
        pr_debug("%s: done\n", __func__);
 }
 
@@ -1534,7 +1534,7 @@ static struct gelic_card *gelic_alloc_card_net(struct net_device **netdev)
        INIT_WORK(&card->tx_timeout_task, gelic_net_tx_timeout_task);
        init_waitqueue_head(&card->waitq);
        atomic_set(&card->tx_timeout_task_counter, 0);
-       init_MUTEX(&card->updown_lock);
+       mutex_init(&card->updown_lock);
        atomic_set(&card->users, 0);
 
        return card;
index 520f143c2c09c39cde27ed7ee83275a211c60abe..8b413868bbe2a1b180b6295b9ab4e26f90251023 100644 (file)
@@ -298,7 +298,7 @@ struct gelic_card {
        wait_queue_head_t waitq;
 
        /* only first user should up the card */
-       struct semaphore updown_lock;
+       struct mutex updown_lock;
        atomic_t users;
 
        u64 ether_port_status;
index 1dae1f2ed813e6dc2ebdf818d9e9ef6084422dfc..aa963ac1e37b2086bc677724664f7a7368bef3d0 100644 (file)
@@ -45,7 +45,8 @@
 #include "ps3_gelic_wireless.h"
 
 
-static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan);
+static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan,
+                              u8 *essid, size_t essid_len);
 static int gelic_wl_try_associate(struct net_device *netdev);
 
 /*
@@ -105,6 +106,7 @@ static const struct eurus_cmd_arg_info cmd_info[GELIC_EURUS_CMD_MAX_INDEX] = {
        [GELIC_EURUS_CMD_GET_WEP_CFG]    = { .post_arg = 1},
        [GELIC_EURUS_CMD_GET_WPA_CFG]    = { .post_arg = 1},
        [GELIC_EURUS_CMD_GET_RSSI_CFG]   = { .post_arg = 1},
+       [GELIC_EURUS_CMD_START_SCAN]     = { .pre_arg = 1},
        [GELIC_EURUS_CMD_GET_SCAN]       = { .post_arg = 1},
 };
 
@@ -163,7 +165,9 @@ static void gelic_eurus_sync_cmd_worker(struct work_struct *work)
        card = port_to_card(wl_port(wl));
 
        if (cmd_info[cmd->cmd].pre_arg) {
-               arg1 = ps3_mm_phys_to_lpar(__pa(cmd->buffer));
+               arg1 = (cmd->buffer) ?
+                       ps3_mm_phys_to_lpar(__pa(cmd->buffer)) :
+                       0;
                arg2 = cmd->buf_size;
        } else {
                arg1 = 0;
@@ -240,12 +244,12 @@ static u32 gelic_wl_get_link(struct net_device *netdev)
        u32 ret;
 
        pr_debug("%s: <-\n", __func__);
-       down(&wl->assoc_stat_lock);
+       mutex_lock(&wl->assoc_stat_lock);
        if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED)
                ret = 1;
        else
                ret = 0;
-       up(&wl->assoc_stat_lock);
+       mutex_unlock(&wl->assoc_stat_lock);
        pr_debug("%s: ->\n", __func__);
        return ret;
 }
@@ -350,7 +354,8 @@ static int gelic_wl_get_range(struct net_device *netdev,
 
        /* encryption capability */
        range->enc_capa = IW_ENC_CAPA_WPA |
-               IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
+               IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP |
+               IW_ENC_CAPA_4WAY_HANDSHAKE;
        if (wpa2_capable())
                range->enc_capa |= IW_ENC_CAPA_WPA2;
        range->encoding_size[0] = 5;    /* 40bit WEP */
@@ -359,6 +364,9 @@ static int gelic_wl_get_range(struct net_device *netdev,
        range->num_encoding_sizes = 3;
        range->max_encoding_tokens = GELIC_WEP_KEYS;
 
+       /* scan capability */
+       range->scan_capa = IW_SCAN_CAPA_ESSID;
+
        pr_debug("%s: ->\n", __func__);
        return 0;
 
@@ -370,8 +378,18 @@ static int gelic_wl_set_scan(struct net_device *netdev,
                           union iwreq_data *wrqu, char *extra)
 {
        struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
-
-       return gelic_wl_start_scan(wl, 1);
+       struct iw_scan_req *req;
+       u8 *essid = NULL;
+       size_t essid_len = 0;
+
+       if (wrqu->data.length == sizeof(struct iw_scan_req) &&
+           wrqu->data.flags & IW_SCAN_THIS_ESSID) {
+               req = (struct iw_scan_req*)extra;
+               essid = req->essid;
+               essid_len = req->essid_len;
+               pr_debug("%s: ESSID scan =%s\n", __func__, essid);
+       }
+       return gelic_wl_start_scan(wl, 1, essid, essid_len);
 }
 
 #define OUI_LEN 3
@@ -695,7 +713,7 @@ static int gelic_wl_get_scan(struct net_device *netdev,
        unsigned long this_time = jiffies;
 
        pr_debug("%s: <-\n", __func__);
-       if (down_interruptible(&wl->scan_lock))
+       if (mutex_lock_interruptible(&wl->scan_lock))
                return -EAGAIN;
 
        switch (wl->scan_stat) {
@@ -733,7 +751,7 @@ static int gelic_wl_get_scan(struct net_device *netdev,
        wrqu->data.length = ev - extra;
        wrqu->data.flags = 0;
 out:
-       up(&wl->scan_lock);
+       mutex_unlock(&wl->scan_lock);
        pr_debug("%s: -> %d %d\n", __func__, ret, wrqu->data.length);
        return ret;
 }
@@ -979,7 +997,7 @@ static int gelic_wl_get_essid(struct net_device *netdev,
        unsigned long irqflag;
 
        pr_debug("%s: <- \n", __func__);
-       down(&wl->assoc_stat_lock);
+       mutex_lock(&wl->assoc_stat_lock);
        spin_lock_irqsave(&wl->lock, irqflag);
        if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat) ||
            wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) {
@@ -989,7 +1007,7 @@ static int gelic_wl_get_essid(struct net_device *netdev,
        } else
                data->essid.flags = 0;
 
-       up(&wl->assoc_stat_lock);
+       mutex_unlock(&wl->assoc_stat_lock);
        spin_unlock_irqrestore(&wl->lock, irqflag);
        pr_debug("%s: -> len=%d \n", __func__, data->essid.length);
 
@@ -1170,7 +1188,7 @@ static int gelic_wl_get_ap(struct net_device *netdev,
        unsigned long irqflag;
 
        pr_debug("%s: <-\n", __func__);
-       down(&wl->assoc_stat_lock);
+       mutex_lock(&wl->assoc_stat_lock);
        spin_lock_irqsave(&wl->lock, irqflag);
        if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) {
                data->ap_addr.sa_family = ARPHRD_ETHER;
@@ -1180,7 +1198,7 @@ static int gelic_wl_get_ap(struct net_device *netdev,
                memset(data->ap_addr.sa_data, 0, ETH_ALEN);
 
        spin_unlock_irqrestore(&wl->lock, irqflag);
-       up(&wl->assoc_stat_lock);
+       mutex_unlock(&wl->assoc_stat_lock);
        pr_debug("%s: ->\n", __func__);
        return 0;
 }
@@ -1256,42 +1274,19 @@ static int gelic_wl_set_encodeext(struct net_device *netdev,
                set_bit(key_index, &wl->key_enabled);
                /* remember wep info changed */
                set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
-       } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
-               pr_debug("%s: TKIP/CCMP requested alg=%d\n", __func__, alg);
-               /* check key length */
-               if (IW_ENCODING_TOKEN_MAX < ext->key_len) {
-                       pr_info("%s: key is too long %d\n", __func__,
-                               ext->key_len);
+       } else if (alg == IW_ENCODE_ALG_PMK) {
+               if (ext->key_len != WPA_PSK_LEN) {
+                       pr_err("%s: PSK length wrong %d\n", __func__,
+                              ext->key_len);
                        ret = -EINVAL;
                        goto done;
                }
-               if (alg == IW_ENCODE_ALG_CCMP) {
-                       pr_debug("%s: AES selected\n", __func__);
-                       wl->group_cipher_method = GELIC_WL_CIPHER_AES;
-                       wl->pairwise_cipher_method = GELIC_WL_CIPHER_AES;
-                       wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA2;
-               } else {
-                       pr_debug("%s: TKIP selected, WPA forced\n", __func__);
-                       wl->group_cipher_method = GELIC_WL_CIPHER_TKIP;
-                       wl->pairwise_cipher_method = GELIC_WL_CIPHER_TKIP;
-                       /* FIXME: how do we do if WPA2 + TKIP? */
-                       wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA;
-               }
-               if (flags & IW_ENCODE_RESTRICTED)
-                       BUG();
-               wl->auth_method = GELIC_EURUS_AUTH_OPEN;
-               /* We should use same key for both and unicast */
-               if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
-                       pr_debug("%s: group key \n", __func__);
-               else
-                       pr_debug("%s: unicast key \n", __func__);
-               /* OK, update the key */
-               wl->key_len[key_index] = ext->key_len;
-               memset(wl->key[key_index], 0, IW_ENCODING_TOKEN_MAX);
-               memcpy(wl->key[key_index], ext->key, ext->key_len);
-               set_bit(key_index, &wl->key_enabled);
-               /* remember info changed */
-               set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
+               memset(wl->psk, 0, sizeof(wl->psk));
+               memcpy(wl->psk, ext->key, ext->key_len);
+               wl->psk_len = ext->key_len;
+               wl->psk_type = GELIC_EURUS_WPA_PSK_BIN;
+               /* remember PSK configured */
+               set_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat);
        }
 done:
        spin_unlock_irqrestore(&wl->lock, irqflag);
@@ -1397,6 +1392,7 @@ static int gelic_wl_get_mode(struct net_device *netdev,
        return 0;
 }
 
+#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE
 /* SIOCIWFIRSTPRIV */
 static int hex2bin(u8 *str, u8 *bin, unsigned int len)
 {
@@ -1501,6 +1497,7 @@ static int gelic_wl_priv_get_psk(struct net_device *net_dev,
        pr_debug("%s:-> %d\n", __func__, data->data.length);
        return 0;
 }
+#endif
 
 /* SIOCGIWNICKN */
 static int gelic_wl_get_nick(struct net_device *net_dev,
@@ -1524,15 +1521,20 @@ static struct iw_statistics *gelic_wl_get_wireless_stats(
        struct gelic_eurus_cmd *cmd;
        struct iw_statistics *is;
        struct gelic_eurus_rssi_info *rssi;
+       void *buf;
 
        pr_debug("%s: <-\n", __func__);
 
+       buf = (void *)__get_free_page(GFP_KERNEL);
+       if (!buf)
+               return NULL;
+
        is = &wl->iwstat;
        memset(is, 0, sizeof(*is));
        cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_GET_RSSI_CFG,
-                                  wl->buf, sizeof(*rssi));
+                                  buf, sizeof(*rssi));
        if (cmd && !cmd->status && !cmd->cmd_status) {
-               rssi = wl->buf;
+               rssi = buf;
                is->qual.level = be16_to_cpu(rssi->rssi);
                is->qual.updated = IW_QUAL_LEVEL_UPDATED |
                        IW_QUAL_QUAL_INVALID | IW_QUAL_NOISE_INVALID;
@@ -1541,6 +1543,7 @@ static struct iw_statistics *gelic_wl_get_wireless_stats(
                is->qual.updated = IW_QUAL_ALL_INVALID;
 
        kfree(cmd);
+       free_page((unsigned long)buf);
        pr_debug("%s: ->\n", __func__);
        return is;
 }
@@ -1548,13 +1551,16 @@ static struct iw_statistics *gelic_wl_get_wireless_stats(
 /*
  *  scanning helpers
  */
-static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan)
+static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan,
+                              u8 *essid, size_t essid_len)
 {
        struct gelic_eurus_cmd *cmd;
        int ret = 0;
+       void *buf = NULL;
+       size_t len;
 
        pr_debug("%s: <- always=%d\n", __func__, always_scan);
-       if (down_interruptible(&wl->scan_lock))
+       if (mutex_lock_interruptible(&wl->scan_lock))
                return -ERESTARTSYS;
 
        /*
@@ -1574,12 +1580,27 @@ static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan)
                complete(&wl->scan_done);
                goto out;
        }
+
+       /* ESSID scan ? */
+       if (essid_len && essid) {
+               buf = (void *)__get_free_page(GFP_KERNEL);
+               if (!buf) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               len = IW_ESSID_MAX_SIZE; /* hypervisor always requires 32 */
+               memset(buf, 0, len);
+               memcpy(buf, essid, essid_len);
+               pr_debug("%s: essid scan='%s'\n", __func__, (char *)buf);
+       } else
+               len = 0;
+
        /*
         * issue start scan request
         */
        wl->scan_stat = GELIC_WL_SCAN_STAT_SCANNING;
        cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_START_SCAN,
-                                  NULL, 0);
+                                  buf, len);
        if (!cmd || cmd->status || cmd->cmd_status) {
                wl->scan_stat = GELIC_WL_SCAN_STAT_INIT;
                complete(&wl->scan_done);
@@ -1588,7 +1609,8 @@ static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan)
        }
        kfree(cmd);
 out:
-       up(&wl->scan_lock);
+       free_page((unsigned long)buf);
+       mutex_unlock(&wl->scan_lock);
        pr_debug("%s: ->\n", __func__);
        return ret;
 }
@@ -1607,10 +1629,17 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl)
        union iwreq_data data;
        unsigned long this_time = jiffies;
        unsigned int data_len, i, found, r;
+       void *buf;
        DECLARE_MAC_BUF(mac);
 
        pr_debug("%s:start\n", __func__);
-       down(&wl->scan_lock);
+       mutex_lock(&wl->scan_lock);
+
+       buf = (void *)__get_free_page(GFP_KERNEL);
+       if (!buf) {
+               pr_info("%s: scan buffer alloc failed\n", __func__);
+               goto out;
+       }
 
        if (wl->scan_stat != GELIC_WL_SCAN_STAT_SCANNING) {
                /*
@@ -1622,7 +1651,7 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl)
        }
 
        cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_GET_SCAN,
-                                  wl->buf, PAGE_SIZE);
+                                  buf, PAGE_SIZE);
        if (!cmd || cmd->status || cmd->cmd_status) {
                wl->scan_stat = GELIC_WL_SCAN_STAT_INIT;
                pr_info("%s:cmd failed\n", __func__);
@@ -1649,7 +1678,7 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl)
        }
 
        /* put them in the newtork_list */
-       for (i = 0, scan_info_size = 0, scan_info = wl->buf;
+       for (i = 0, scan_info_size = 0, scan_info = buf;
             scan_info_size < data_len;
             i++, scan_info_size += be16_to_cpu(scan_info->size),
             scan_info = (void *)scan_info + be16_to_cpu(scan_info->size)) {
@@ -1726,8 +1755,9 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl)
        wireless_send_event(port_to_netdev(wl_port(wl)), SIOCGIWSCAN, &data,
                            NULL);
 out:
+       free_page((unsigned long)buf);
        complete(&wl->scan_done);
-       up(&wl->scan_lock);
+       mutex_unlock(&wl->scan_lock);
        pr_debug("%s:end\n", __func__);
 }
 
@@ -1848,7 +1878,10 @@ static int gelic_wl_do_wep_setup(struct gelic_wl_info *wl)
 
        pr_debug("%s: <-\n", __func__);
        /* we can assume no one should uses the buffer */
-       wep = wl->buf;
+       wep = (struct gelic_eurus_wep_cfg *)__get_free_page(GFP_KERNEL);
+       if (!wep)
+               return -ENOMEM;
+
        memset(wep, 0, sizeof(*wep));
 
        if (wl->group_cipher_method == GELIC_WL_CIPHER_WEP) {
@@ -1898,6 +1931,7 @@ static int gelic_wl_do_wep_setup(struct gelic_wl_info *wl)
 
        kfree(cmd);
 out:
+       free_page((unsigned long)wep);
        pr_debug("%s: ->\n", __func__);
        return ret;
 }
@@ -1941,7 +1975,10 @@ static int gelic_wl_do_wpa_setup(struct gelic_wl_info *wl)
 
        pr_debug("%s: <-\n", __func__);
        /* we can assume no one should uses the buffer */
-       wpa = wl->buf;
+       wpa = (struct gelic_eurus_wpa_cfg *)__get_free_page(GFP_KERNEL);
+       if (!wpa)
+               return -ENOMEM;
+
        memset(wpa, 0, sizeof(*wpa));
 
        if (!test_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat))
@@ -2000,6 +2037,7 @@ static int gelic_wl_do_wpa_setup(struct gelic_wl_info *wl)
        else if (cmd->status || cmd->cmd_status)
                ret = -ENXIO;
        kfree(cmd);
+       free_page((unsigned long)wpa);
        pr_debug("%s: --> %d\n", __func__, ret);
        return ret;
 }
@@ -2018,7 +2056,10 @@ static int gelic_wl_associate_bss(struct gelic_wl_info *wl,
        pr_debug("%s: <-\n", __func__);
 
        /* do common config */
-       common = wl->buf;
+       common = (struct gelic_eurus_common_cfg *)__get_free_page(GFP_KERNEL);
+       if (!common)
+               return -ENOMEM;
+
        memset(common, 0, sizeof(*common));
        common->bss_type = cpu_to_be16(GELIC_EURUS_BSS_INFRA);
        common->op_mode = cpu_to_be16(GELIC_EURUS_OPMODE_11BG);
@@ -2104,6 +2145,7 @@ static int gelic_wl_associate_bss(struct gelic_wl_info *wl,
                pr_info("%s: connected\n", __func__);
        }
 out:
+       free_page((unsigned long)common);
        pr_debug("%s: ->\n", __func__);
        return ret;
 }
@@ -2151,7 +2193,7 @@ static void gelic_wl_disconnect_event(struct gelic_wl_info *wl,
         * As it waits with timeout, just leave assoc_done
         * uncompleted, then it terminates with timeout
         */
-       if (down_trylock(&wl->assoc_stat_lock)) {
+       if (!mutex_trylock(&wl->assoc_stat_lock)) {
                pr_debug("%s: already locked\n", __func__);
                lock = 0;
        } else {
@@ -2170,7 +2212,7 @@ static void gelic_wl_disconnect_event(struct gelic_wl_info *wl,
        netif_carrier_off(port_to_netdev(wl_port(wl)));
 
        if (lock)
-               up(&wl->assoc_stat_lock);
+               mutex_unlock(&wl->assoc_stat_lock);
 }
 /*
  * event worker
@@ -2255,15 +2297,30 @@ static void gelic_wl_assoc_worker(struct work_struct *work)
 
        struct gelic_wl_scan_info *best_bss;
        int ret;
+       unsigned long irqflag;
+       u8 *essid;
+       size_t essid_len;
 
        wl = container_of(work, struct gelic_wl_info, assoc_work.work);
 
-       down(&wl->assoc_stat_lock);
+       mutex_lock(&wl->assoc_stat_lock);
 
        if (wl->assoc_stat != GELIC_WL_ASSOC_STAT_DISCONN)
                goto out;
 
-       ret = gelic_wl_start_scan(wl, 0);
+       spin_lock_irqsave(&wl->lock, irqflag);
+       if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat)) {
+               pr_debug("%s: assoc ESSID configured %s\n", __func__,
+                        wl->essid);
+               essid = wl->essid;
+               essid_len = wl->essid_len;
+       } else {
+               essid = NULL;
+               essid_len = 0;
+       }
+       spin_unlock_irqrestore(&wl->lock, irqflag);
+
+       ret = gelic_wl_start_scan(wl, 0, essid, essid_len);
        if (ret == -ERESTARTSYS) {
                pr_debug("%s: scan start failed association\n", __func__);
                schedule_delayed_work(&wl->assoc_work, HZ/10); /*FIXME*/
@@ -2282,7 +2339,7 @@ static void gelic_wl_assoc_worker(struct work_struct *work)
        wait_for_completion(&wl->scan_done);
 
        pr_debug("%s: scan done\n", __func__);
-       down(&wl->scan_lock);
+       mutex_lock(&wl->scan_lock);
        if (wl->scan_stat != GELIC_WL_SCAN_STAT_GOT_LIST) {
                gelic_wl_send_iwap_event(wl, NULL);
                pr_info("%s: no scan list. association failed\n", __func__);
@@ -2302,9 +2359,9 @@ static void gelic_wl_assoc_worker(struct work_struct *work)
        if (ret)
                pr_info("%s: association failed %d\n", __func__, ret);
 scan_lock_out:
-       up(&wl->scan_lock);
+       mutex_unlock(&wl->scan_lock);
 out:
-       up(&wl->assoc_stat_lock);
+       mutex_unlock(&wl->assoc_stat_lock);
 }
 /*
  * Interrupt handler
@@ -2351,6 +2408,7 @@ static const iw_handler gelic_wl_wext_handler[] =
        IW_IOCTL(SIOCGIWNICKN)          = gelic_wl_get_nick,
 };
 
+#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE
 static struct iw_priv_args gelic_wl_private_args[] =
 {
        {
@@ -2372,15 +2430,18 @@ static const iw_handler gelic_wl_private_handler[] =
        gelic_wl_priv_set_psk,
        gelic_wl_priv_get_psk,
 };
+#endif
 
 static const struct iw_handler_def gelic_wl_wext_handler_def = {
        .num_standard           = ARRAY_SIZE(gelic_wl_wext_handler),
        .standard               = gelic_wl_wext_handler,
        .get_wireless_stats     = gelic_wl_get_wireless_stats,
+#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE
        .num_private            = ARRAY_SIZE(gelic_wl_private_handler),
        .num_private_args       = ARRAY_SIZE(gelic_wl_private_args),
        .private                = gelic_wl_private_handler,
        .private_args           = gelic_wl_private_args,
+#endif
 };
 
 static struct net_device *gelic_wl_alloc(struct gelic_card *card)
@@ -2431,8 +2492,8 @@ static struct net_device *gelic_wl_alloc(struct gelic_card *card)
 
        INIT_DELAYED_WORK(&wl->event_work, gelic_wl_event_worker);
        INIT_DELAYED_WORK(&wl->assoc_work, gelic_wl_assoc_worker);
-       init_MUTEX(&wl->scan_lock);
-       init_MUTEX(&wl->assoc_stat_lock);
+       mutex_init(&wl->scan_lock);
+       mutex_init(&wl->assoc_stat_lock);
 
        init_completion(&wl->scan_done);
        /* for the case that no scan request is issued and stop() is called */
@@ -2446,16 +2507,9 @@ static struct net_device *gelic_wl_alloc(struct gelic_card *card)
        BUILD_BUG_ON(PAGE_SIZE <
                     sizeof(struct gelic_eurus_scan_info) *
                     GELIC_EURUS_MAX_SCAN);
-       wl->buf = (void *)get_zeroed_page(GFP_KERNEL);
-       if (!wl->buf) {
-               pr_info("%s:buffer allocation failed\n", __func__);
-               goto fail_getpage;
-       }
        pr_debug("%s:end\n", __func__);
        return netdev;
 
-fail_getpage:
-       destroy_workqueue(wl->event_queue);
 fail_event_workqueue:
        destroy_workqueue(wl->eurus_cmd_queue);
 fail_cmd_workqueue:
@@ -2474,8 +2528,6 @@ static void gelic_wl_free(struct gelic_wl_info *wl)
 
        pr_debug("%s: <-\n", __func__);
 
-       free_page((unsigned long)wl->buf);
-
        pr_debug("%s: destroy queues\n", __func__);
        destroy_workqueue(wl->eurus_cmd_queue);
        destroy_workqueue(wl->event_queue);
index 103697166720eeff9b7cc35ab1d614c269812e85..5339e0078d180a885f53a622dddac4c4743c50ee 100644 (file)
@@ -241,7 +241,7 @@ enum gelic_wl_assoc_state {
 #define GELIC_WEP_KEYS 4
 struct gelic_wl_info {
        /* bss list */
-       struct semaphore scan_lock;
+       struct mutex scan_lock;
        struct list_head network_list;
        struct list_head network_free_list;
        struct gelic_wl_scan_info *networks;
@@ -266,7 +266,7 @@ struct gelic_wl_info {
        enum gelic_wl_wpa_level wpa_level; /* wpa/wpa2 */
 
        /* association handling */
-       struct semaphore assoc_stat_lock;
+       struct mutex assoc_stat_lock;
        struct delayed_work assoc_work;
        enum gelic_wl_assoc_state assoc_stat;
        struct completion assoc_done;
@@ -288,9 +288,6 @@ struct gelic_wl_info {
        u8 active_bssid[ETH_ALEN]; /* associated bssid */
        unsigned int essid_len;
 
-       /* buffer for hypervisor IO */
-       void *buf;
-
        struct iw_public_data wireless_data;
        struct iw_statistics iwstat;
 };
index b7f7b2227d5697df09413841074d143c5ef8ac88..5f608780c3e8aafee63c91f255a9bb57a2db9c17 100644 (file)
@@ -1437,9 +1437,9 @@ static void ql_phy_start_neg_ex(struct ql3_adapter *qdev)
        reg &= ~PHY_GIG_ALL_PARAMS;
 
        if(portConfiguration & PORT_CONFIG_1000MB_SPEED) {
-               if(portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED) 
+               if(portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED)
                        reg |= PHY_GIG_ADV_1000F;
-               else 
+               else
                        reg |= PHY_GIG_ADV_1000H;
        }
 
index a20693e09ae8cbfe8108d16c792e9640ed282eae..dcc953e57ab180b53ae47d9f5b114cf0e209c832 100644 (file)
@@ -2566,7 +2566,7 @@ static int fill_rx_buffers(struct ring_info *ring)
                if (block_no)
                        rxd_index += (block_no * ring->rxd_count);
 
-               if ((block_no == block_no1) && 
+               if ((block_no == block_no1) &&
                        (off == ring->rx_curr_get_info.offset) &&
                        (rxdp->Host_Control)) {
                        DBG_PRINT(INTR_DBG, "%s: Get and Put",
@@ -2612,7 +2612,7 @@ static int fill_rx_buffers(struct ring_info *ring)
                                first_rxdp->Control_1 |= RXD_OWN_XENA;
                        }
                        stats->mem_alloc_fail_cnt++;
-                               
+
                        return -ENOMEM ;
                }
                stats->mem_allocated += skb->truesize;
@@ -6997,7 +6997,7 @@ static  int rxd_owner_bit_reset(struct s2io_nic *sp)
                                                       &skb,(u64 *)&temp0_64,
                                                       (u64 *)&temp1_64,
                                                       (u64 *)&temp2_64,
-                                                       size) == ENOMEM) {
+                                                       size) == -ENOMEM) {
                                        return 0;
                                }
 
index 4706f7f9acb628b423834e90a467f273f2245fd7..d0a84ba887a53d81121e3a1a66789a4838a9686f 100644 (file)
@@ -752,7 +752,7 @@ struct ring_info {
 
        /* interface MTU value */
         unsigned mtu;
-    
+
        /* Buffer Address store. */
        struct buffAdd **ba;
 
index 33bb18f810fbf863a946d026f9bf38ae377b9f20..fe41e4ec21ec2141d63df1c291ebc1035c50d4b6 100644 (file)
@@ -1064,7 +1064,7 @@ static void sbmac_netpoll(struct net_device *netdev)
        ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0),
        sc->sbm_imr);
 #else
-       __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) | 
+       __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) |
        (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), sc->sbm_imr);
 #endif
 }
index dbad95c295bdd3ed37b7e5aafbd4f805de73fc97..3be13b592b4dbb0f7c1382ec745d8684f57c8cb6 100644 (file)
@@ -4,6 +4,8 @@ config SFC
        select MII
        select INET_LRO
        select CRC32
+       select I2C
+       select I2C_ALGOBIT
        help
          This driver supports 10-gigabit Ethernet cards based on
          the Solarflare Communications Solarstorm SFC4000 controller.
index 1d2daeec7ac11f5a0ba77376667be986fe5a5f95..c8f5704c8fb18adf946e8b1bc66afea50c76a12b 100644 (file)
@@ -1,5 +1,5 @@
 sfc-y                  += efx.o falcon.o tx.o rx.o falcon_xmac.o \
-                          i2c-direct.o selftest.o ethtool.o xfp_phy.o \
+                          selftest.o ethtool.o xfp_phy.o \
                           mdio_10g.o tenxpress.o boards.o sfe4001.o
 
 obj-$(CONFIG_SFC)      += sfc.o
index 7fc0328dc055d0bd143d5291264c2f0243804909..d3d3dd0a1170dea4e16b701ec46a4900b3c0b567 100644 (file)
@@ -109,7 +109,7 @@ static struct efx_board_data board_data[] = {
        [EFX_BOARD_INVALID] =
        {NULL,      NULL,                  dummy_init},
        [EFX_BOARD_SFE4001] =
-       {"SFE4001", "10GBASE-T adapter",   sfe4001_poweron},
+       {"SFE4001", "10GBASE-T adapter",   sfe4001_init},
        [EFX_BOARD_SFE4002] =
        {"SFE4002", "XFP adapter",         sfe4002_init},
 };
index 695764dc2e644a23e6c1f7071662e747348eacac..e5e844359ce7b058856594da7d4763dc1b4c57ac 100644 (file)
@@ -20,8 +20,7 @@ enum efx_board_type {
 };
 
 extern int efx_set_board_info(struct efx_nic *efx, u16 revision_info);
-extern int sfe4001_poweron(struct efx_nic *efx);
-extern void sfe4001_poweroff(struct efx_nic *efx);
+extern int sfe4001_init(struct efx_nic *efx);
 /* Are we putting the PHY into flash config mode */
 extern unsigned int sfe4001_phy_flash_cfg;
 
index 449760642e31b16040c33fbf0ba247fed834e6f9..74265d8553b8b58e76a50067fd17f50298cf5323 100644 (file)
@@ -1815,6 +1815,7 @@ static struct efx_board efx_dummy_board_info = {
        .init    = efx_nic_dummy_op_int,
        .init_leds = efx_port_dummy_op_int,
        .set_fault_led = efx_port_dummy_op_blink,
+       .fini   = efx_port_dummy_op_void,
 };
 
 /**************************************************************************
@@ -1941,6 +1942,7 @@ static void efx_pci_remove_main(struct efx_nic *efx)
        efx_fini_port(efx);
 
        /* Shutdown the board, then the NIC and board state */
+       efx->board_info.fini(efx);
        falcon_fini_interrupt(efx);
 
        efx_fini_napi(efx);
index d3f749c72d41d76f5291407b946fefd93217241e..8cb57987905ec0c1c78bcee7d12dffb2da817698 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/pci.h>
 #include <linux/module.h>
 #include <linux/seq_file.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
 #include "net_driver.h"
 #include "bitfield.h"
 #include "efx.h"
  * struct falcon_nic_data - Falcon NIC state
  * @next_buffer_table: First available buffer table id
  * @pci_dev2: The secondary PCI device if present
+ * @i2c_data: Operations and state for I2C bit-bashing algorithm
  */
 struct falcon_nic_data {
        unsigned next_buffer_table;
        struct pci_dev *pci_dev2;
+       struct i2c_algo_bit_data i2c_data;
 };
 
 /**************************************************************************
@@ -175,39 +179,57 @@ static inline int falcon_event_present(efx_qword_t *event)
  *
  **************************************************************************
  */
-static void falcon_setsdascl(struct efx_i2c_interface *i2c)
+static void falcon_setsda(void *data, int state)
 {
+       struct efx_nic *efx = (struct efx_nic *)data;
        efx_oword_t reg;
 
-       falcon_read(i2c->efx, &reg, GPIO_CTL_REG_KER);
-       EFX_SET_OWORD_FIELD(reg, GPIO0_OEN, (i2c->scl ? 0 : 1));
-       EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, (i2c->sda ? 0 : 1));
-       falcon_write(i2c->efx, &reg, GPIO_CTL_REG_KER);
+       falcon_read(efx, &reg, GPIO_CTL_REG_KER);
+       EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, !state);
+       falcon_write(efx, &reg, GPIO_CTL_REG_KER);
 }
 
-static int falcon_getsda(struct efx_i2c_interface *i2c)
+static void falcon_setscl(void *data, int state)
 {
+       struct efx_nic *efx = (struct efx_nic *)data;
        efx_oword_t reg;
 
-       falcon_read(i2c->efx, &reg, GPIO_CTL_REG_KER);
+       falcon_read(efx, &reg, GPIO_CTL_REG_KER);
+       EFX_SET_OWORD_FIELD(reg, GPIO0_OEN, !state);
+       falcon_write(efx, &reg, GPIO_CTL_REG_KER);
+}
+
+static int falcon_getsda(void *data)
+{
+       struct efx_nic *efx = (struct efx_nic *)data;
+       efx_oword_t reg;
+
+       falcon_read(efx, &reg, GPIO_CTL_REG_KER);
        return EFX_OWORD_FIELD(reg, GPIO3_IN);
 }
 
-static int falcon_getscl(struct efx_i2c_interface *i2c)
+static int falcon_getscl(void *data)
 {
+       struct efx_nic *efx = (struct efx_nic *)data;
        efx_oword_t reg;
 
-       falcon_read(i2c->efx, &reg, GPIO_CTL_REG_KER);
-       return EFX_DWORD_FIELD(reg, GPIO0_IN);
+       falcon_read(efx, &reg, GPIO_CTL_REG_KER);
+       return EFX_OWORD_FIELD(reg, GPIO0_IN);
 }
 
-static struct efx_i2c_bit_operations falcon_i2c_bit_operations = {
-       .setsda         = falcon_setsdascl,
-       .setscl         = falcon_setsdascl,
+static struct i2c_algo_bit_data falcon_i2c_bit_operations = {
+       .setsda         = falcon_setsda,
+       .setscl         = falcon_setscl,
        .getsda         = falcon_getsda,
        .getscl         = falcon_getscl,
-       .udelay         = 100,
-       .mdelay         = 10,
+       .udelay         = 5,
+       /*
+        * This is the number of system clock ticks after which
+        * i2c-algo-bit gives up waiting for SCL to become high.
+        * It must be at least 2 since the first tick can happen
+        * immediately after it starts waiting.
+        */
+       .timeout        = 2,
 };
 
 /**************************************************************************
@@ -2403,12 +2425,6 @@ int falcon_probe_nic(struct efx_nic *efx)
        struct falcon_nic_data *nic_data;
        int rc;
 
-       /* Initialise I2C interface state */
-       efx->i2c.efx = efx;
-       efx->i2c.op = &falcon_i2c_bit_operations;
-       efx->i2c.sda = 1;
-       efx->i2c.scl = 1;
-
        /* Allocate storage for hardware specific data */
        nic_data = kzalloc(sizeof(*nic_data), GFP_KERNEL);
        efx->nic_data = nic_data;
@@ -2459,6 +2475,18 @@ int falcon_probe_nic(struct efx_nic *efx)
        if (rc)
                goto fail5;
 
+       /* Initialise I2C adapter */
+       efx->i2c_adap.owner = THIS_MODULE;
+       efx->i2c_adap.class = I2C_CLASS_HWMON;
+       nic_data->i2c_data = falcon_i2c_bit_operations;
+       nic_data->i2c_data.data = efx;
+       efx->i2c_adap.algo_data = &nic_data->i2c_data;
+       efx->i2c_adap.dev.parent = &efx->pci_dev->dev;
+       strcpy(efx->i2c_adap.name, "SFC4000 GPIO");
+       rc = i2c_bit_add_bus(&efx->i2c_adap);
+       if (rc)
+               goto fail5;
+
        return 0;
 
  fail5:
@@ -2633,6 +2661,10 @@ int falcon_init_nic(struct efx_nic *efx)
 void falcon_remove_nic(struct efx_nic *efx)
 {
        struct falcon_nic_data *nic_data = efx->nic_data;
+       int rc;
+
+       rc = i2c_del_adapter(&efx->i2c_adap);
+       BUG_ON(rc);
 
        falcon_free_buffer(efx, &efx->irq_status);
 
diff --git a/drivers/net/sfc/i2c-direct.c b/drivers/net/sfc/i2c-direct.c
deleted file mode 100644 (file)
index b6c62d0..0000000
+++ /dev/null
@@ -1,381 +0,0 @@
-/****************************************************************************
- * Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2005 Fen Systems Ltd.
- * Copyright 2006-2008 Solarflare Communications Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation, incorporated herein by reference.
- */
-
-#include <linux/delay.h>
-#include "net_driver.h"
-#include "i2c-direct.h"
-
-/*
- * I2C data (SDA) and clock (SCL) line read/writes with appropriate
- * delays.
- */
-
-static inline void setsda(struct efx_i2c_interface *i2c, int state)
-{
-       udelay(i2c->op->udelay);
-       i2c->sda = state;
-       i2c->op->setsda(i2c);
-       udelay(i2c->op->udelay);
-}
-
-static inline void setscl(struct efx_i2c_interface *i2c, int state)
-{
-       udelay(i2c->op->udelay);
-       i2c->scl = state;
-       i2c->op->setscl(i2c);
-       udelay(i2c->op->udelay);
-}
-
-static inline int getsda(struct efx_i2c_interface *i2c)
-{
-       int sda;
-
-       udelay(i2c->op->udelay);
-       sda = i2c->op->getsda(i2c);
-       udelay(i2c->op->udelay);
-       return sda;
-}
-
-static inline int getscl(struct efx_i2c_interface *i2c)
-{
-       int scl;
-
-       udelay(i2c->op->udelay);
-       scl = i2c->op->getscl(i2c);
-       udelay(i2c->op->udelay);
-       return scl;
-}
-
-/*
- * I2C low-level protocol operations
- *
- */
-
-static inline void i2c_release(struct efx_i2c_interface *i2c)
-{
-       EFX_WARN_ON_PARANOID(!i2c->scl);
-       EFX_WARN_ON_PARANOID(!i2c->sda);
-       /* Devices may time out if operations do not end */
-       setscl(i2c, 1);
-       setsda(i2c, 1);
-       EFX_BUG_ON_PARANOID(getsda(i2c) != 1);
-       EFX_BUG_ON_PARANOID(getscl(i2c) != 1);
-}
-
-static inline void i2c_start(struct efx_i2c_interface *i2c)
-{
-       /* We may be restarting immediately after a {send,recv}_bit,
-        * so SCL will not necessarily already be high.
-        */
-       EFX_WARN_ON_PARANOID(!i2c->sda);
-       setscl(i2c, 1);
-       setsda(i2c, 0);
-       setscl(i2c, 0);
-       setsda(i2c, 1);
-}
-
-static inline void i2c_send_bit(struct efx_i2c_interface *i2c, int bit)
-{
-       EFX_WARN_ON_PARANOID(i2c->scl != 0);
-       setsda(i2c, bit);
-       setscl(i2c, 1);
-       setscl(i2c, 0);
-       setsda(i2c, 1);
-}
-
-static inline int i2c_recv_bit(struct efx_i2c_interface *i2c)
-{
-       int bit;
-
-       EFX_WARN_ON_PARANOID(i2c->scl != 0);
-       EFX_WARN_ON_PARANOID(!i2c->sda);
-       setscl(i2c, 1);
-       bit = getsda(i2c);
-       setscl(i2c, 0);
-       return bit;
-}
-
-static inline void i2c_stop(struct efx_i2c_interface *i2c)
-{
-       EFX_WARN_ON_PARANOID(i2c->scl != 0);
-       setsda(i2c, 0);
-       setscl(i2c, 1);
-       setsda(i2c, 1);
-}
-
-/*
- * I2C mid-level protocol operations
- *
- */
-
-/* Sends a byte via the I2C bus and checks for an acknowledgement from
- * the slave device.
- */
-static int i2c_send_byte(struct efx_i2c_interface *i2c, u8 byte)
-{
-       int i;
-
-       /* Send byte */
-       for (i = 0; i < 8; i++) {
-               i2c_send_bit(i2c, !!(byte & 0x80));
-               byte <<= 1;
-       }
-
-       /* Check for acknowledgement from slave */
-       return (i2c_recv_bit(i2c) == 0 ? 0 : -EIO);
-}
-
-/* Receives a byte via the I2C bus and sends ACK/NACK to the slave device. */
-static u8 i2c_recv_byte(struct efx_i2c_interface *i2c, int ack)
-{
-       u8 value = 0;
-       int i;
-
-       /* Receive byte */
-       for (i = 0; i < 8; i++)
-               value = (value << 1) | i2c_recv_bit(i2c);
-
-       /* Send ACK/NACK */
-       i2c_send_bit(i2c, (ack ? 0 : 1));
-
-       return value;
-}
-
-/* Calculate command byte for a read operation */
-static inline u8 i2c_read_cmd(u8 device_id)
-{
-       return ((device_id << 1) | 1);
-}
-
-/* Calculate command byte for a write operation */
-static inline u8 i2c_write_cmd(u8 device_id)
-{
-       return ((device_id << 1) | 0);
-}
-
-int efx_i2c_check_presence(struct efx_i2c_interface *i2c, u8 device_id)
-{
-       int rc;
-
-       /* If someone is driving the bus low we just give up. */
-       if (getsda(i2c) == 0 || getscl(i2c) == 0) {
-               EFX_ERR(i2c->efx, "%s someone is holding the I2C bus low."
-                       " Giving up.\n", __func__);
-               return -EFAULT;
-       }
-
-       /* Pretend to initiate a device write */
-       i2c_start(i2c);
-       rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
-       if (rc)
-               goto out;
-
- out:
-       i2c_stop(i2c);
-       i2c_release(i2c);
-
-       return rc;
-}
-
-/* This performs a fast read of one or more consecutive bytes from an
- * I2C device.  Not all devices support consecutive reads of more than
- * one byte; for these devices use efx_i2c_read() instead.
- */
-int efx_i2c_fast_read(struct efx_i2c_interface *i2c,
-                     u8 device_id, u8 offset, u8 *data, unsigned int len)
-{
-       int i;
-       int rc;
-
-       EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
-       EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
-       EFX_WARN_ON_PARANOID(data == NULL);
-       EFX_WARN_ON_PARANOID(len < 1);
-
-       /* Select device and starting offset */
-       i2c_start(i2c);
-       rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
-       if (rc)
-               goto out;
-       rc = i2c_send_byte(i2c, offset);
-       if (rc)
-               goto out;
-
-       /* Read data from device */
-       i2c_start(i2c);
-       rc = i2c_send_byte(i2c, i2c_read_cmd(device_id));
-       if (rc)
-               goto out;
-       for (i = 0; i < (len - 1); i++)
-               /* Read and acknowledge all but the last byte */
-               data[i] = i2c_recv_byte(i2c, 1);
-       /* Read last byte with no acknowledgement */
-       data[i] = i2c_recv_byte(i2c, 0);
-
- out:
-       i2c_stop(i2c);
-       i2c_release(i2c);
-
-       return rc;
-}
-
-/* This performs a fast write of one or more consecutive bytes to an
- * I2C device.  Not all devices support consecutive writes of more
- * than one byte; for these devices use efx_i2c_write() instead.
- */
-int efx_i2c_fast_write(struct efx_i2c_interface *i2c,
-                      u8 device_id, u8 offset,
-                      const u8 *data, unsigned int len)
-{
-       int i;
-       int rc;
-
-       EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
-       EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
-       EFX_WARN_ON_PARANOID(len < 1);
-
-       /* Select device and starting offset */
-       i2c_start(i2c);
-       rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
-       if (rc)
-               goto out;
-       rc = i2c_send_byte(i2c, offset);
-       if (rc)
-               goto out;
-
-       /* Write data to device */
-       for (i = 0; i < len; i++) {
-               rc = i2c_send_byte(i2c, data[i]);
-               if (rc)
-                       goto out;
-       }
-
- out:
-       i2c_stop(i2c);
-       i2c_release(i2c);
-
-       return rc;
-}
-
-/* I2C byte-by-byte read */
-int efx_i2c_read(struct efx_i2c_interface *i2c,
-                u8 device_id, u8 offset, u8 *data, unsigned int len)
-{
-       int rc;
-
-       /* i2c_fast_read with length 1 is a single byte read */
-       for (; len > 0; offset++, data++, len--) {
-               rc = efx_i2c_fast_read(i2c, device_id, offset, data, 1);
-               if (rc)
-                       return rc;
-       }
-
-       return 0;
-}
-
-/* I2C byte-by-byte write */
-int efx_i2c_write(struct efx_i2c_interface *i2c,
-                 u8 device_id, u8 offset, const u8 *data, unsigned int len)
-{
-       int rc;
-
-       /* i2c_fast_write with length 1 is a single byte write */
-       for (; len > 0; offset++, data++, len--) {
-               rc = efx_i2c_fast_write(i2c, device_id, offset, data, 1);
-               if (rc)
-                       return rc;
-               mdelay(i2c->op->mdelay);
-       }
-
-       return 0;
-}
-
-
-/* This is just a slightly neater wrapper round efx_i2c_fast_write
- * in the case where the target doesn't take an offset
- */
-int efx_i2c_send_bytes(struct efx_i2c_interface *i2c,
-                      u8 device_id, const u8 *data, unsigned int len)
-{
-       return efx_i2c_fast_write(i2c, device_id, data[0], data + 1, len - 1);
-}
-
-/* I2C receiving of bytes - does not send an offset byte */
-int efx_i2c_recv_bytes(struct efx_i2c_interface *i2c, u8 device_id,
-                      u8 *bytes, unsigned int len)
-{
-       int i;
-       int rc;
-
-       EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
-       EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
-       EFX_WARN_ON_PARANOID(len < 1);
-
-       /* Select device */
-       i2c_start(i2c);
-
-       /* Read data from device */
-       rc = i2c_send_byte(i2c, i2c_read_cmd(device_id));
-       if (rc)
-               goto out;
-
-       for (i = 0; i < (len - 1); i++)
-               /* Read and acknowledge all but the last byte */
-               bytes[i] = i2c_recv_byte(i2c, 1);
-       /* Read last byte with no acknowledgement */
-       bytes[i] = i2c_recv_byte(i2c, 0);
-
- out:
-       i2c_stop(i2c);
-       i2c_release(i2c);
-
-       return rc;
-}
-
-/* SMBus and some I2C devices will time out if the I2C clock is
- * held low for too long. This is most likely to happen in virtualised
- * systems (when the entire domain is descheduled) but could in
- * principle happen due to preemption on any busy system (and given the
- * potential length of an I2C operation turning preemption off is not
- * a sensible option). The following functions deal with the failure by
- * retrying up to a fixed number of times.
-  */
-
-#define I2C_MAX_RETRIES        (10)
-
-/* The timeout problem will result in -EIO. If the wrapped function
- * returns any other error, pass this up and do not retry. */
-#define RETRY_WRAPPER(_f) \
-       int retries = I2C_MAX_RETRIES; \
-       int rc; \
-       while (retries) { \
-               rc = _f; \
-               if (rc != -EIO) \
-                       return rc; \
-               retries--; \
-       } \
-       return rc; \
-
-int efx_i2c_check_presence_retry(struct efx_i2c_interface *i2c, u8 device_id)
-{
-       RETRY_WRAPPER(efx_i2c_check_presence(i2c, device_id))
-}
-
-int efx_i2c_read_retry(struct efx_i2c_interface *i2c,
-                u8 device_id, u8 offset, u8 *data, unsigned int len)
-{
-       RETRY_WRAPPER(efx_i2c_read(i2c, device_id, offset, data, len))
-}
-
-int efx_i2c_write_retry(struct efx_i2c_interface *i2c,
-                 u8 device_id, u8 offset, const u8 *data, unsigned int len)
-{
-       RETRY_WRAPPER(efx_i2c_write(i2c, device_id, offset, data, len))
-}
diff --git a/drivers/net/sfc/i2c-direct.h b/drivers/net/sfc/i2c-direct.h
deleted file mode 100644 (file)
index 291e561..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/****************************************************************************
- * Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2005 Fen Systems Ltd.
- * Copyright 2006 Solarflare Communications Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation, incorporated herein by reference.
- */
-
-#ifndef EFX_I2C_DIRECT_H
-#define EFX_I2C_DIRECT_H
-
-#include "net_driver.h"
-
-/*
- * Direct control of an I2C bus
- */
-
-struct efx_i2c_interface;
-
-/**
- * struct efx_i2c_bit_operations - I2C bus direct control methods
- *
- * I2C bus direct control methods.
- *
- * @setsda: Set state of SDA line
- * @setscl: Set state of SCL line
- * @getsda: Get state of SDA line
- * @getscl: Get state of SCL line
- * @udelay: Delay between each bit operation
- * @mdelay: Delay between each byte write
- */
-struct efx_i2c_bit_operations {
-       void (*setsda) (struct efx_i2c_interface *i2c);
-       void (*setscl) (struct efx_i2c_interface *i2c);
-       int (*getsda) (struct efx_i2c_interface *i2c);
-       int (*getscl) (struct efx_i2c_interface *i2c);
-       unsigned int udelay;
-       unsigned int mdelay;
-};
-
-/**
- * struct efx_i2c_interface - an I2C interface
- *
- * An I2C interface.
- *
- * @efx: Attached Efx NIC
- * @op: I2C bus control methods
- * @sda: Current output state of SDA line
- * @scl: Current output state of SCL line
- */
-struct efx_i2c_interface {
-       struct efx_nic *efx;
-       struct efx_i2c_bit_operations *op;
-       unsigned int sda:1;
-       unsigned int scl:1;
-};
-
-extern int efx_i2c_check_presence(struct efx_i2c_interface *i2c, u8 device_id);
-extern int efx_i2c_fast_read(struct efx_i2c_interface *i2c,
-                            u8 device_id, u8 offset,
-                            u8 *data, unsigned int len);
-extern int efx_i2c_fast_write(struct efx_i2c_interface *i2c,
-                             u8 device_id, u8 offset,
-                             const u8 *data, unsigned int len);
-extern int efx_i2c_read(struct efx_i2c_interface *i2c,
-                       u8 device_id, u8 offset, u8 *data, unsigned int len);
-extern int efx_i2c_write(struct efx_i2c_interface *i2c,
-                        u8 device_id, u8 offset,
-                        const u8 *data, unsigned int len);
-
-extern int efx_i2c_send_bytes(struct efx_i2c_interface *i2c, u8 device_id,
-                             const u8 *bytes, unsigned int len);
-
-extern int efx_i2c_recv_bytes(struct efx_i2c_interface *i2c, u8 device_id,
-                             u8 *bytes, unsigned int len);
-
-
-/* Versions of the API that retry on failure. */
-extern int efx_i2c_check_presence_retry(struct efx_i2c_interface *i2c,
-                                       u8 device_id);
-
-extern int efx_i2c_read_retry(struct efx_i2c_interface *i2c,
-                       u8 device_id, u8 offset, u8 *data, unsigned int len);
-
-extern int efx_i2c_write_retry(struct efx_i2c_interface *i2c,
-                        u8 device_id, u8 offset,
-                        const u8 *data, unsigned int len);
-
-#endif /* EFX_I2C_DIRECT_H */
index 5e20e7551daeda8e9642d8bd300623d8ee321a11..d803b86c647cd64dba5cb512b6686656d6a540df 100644 (file)
 #include <linux/highmem.h>
 #include <linux/workqueue.h>
 #include <linux/inet_lro.h>
+#include <linux/i2c.h>
 
 #include "enum.h"
 #include "bitfield.h"
-#include "i2c-direct.h"
 
 #define EFX_MAX_LRO_DESCRIPTORS 8
 #define EFX_MAX_LRO_AGGR MAX_SKB_FRAGS
@@ -418,7 +418,10 @@ struct efx_blinker {
  * @init_leds: Sets up board LEDs
  * @set_fault_led: Turns the fault LED on or off
  * @blink: Starts/stops blinking
+ * @fini: Cleanup function
  * @blinker: used to blink LEDs in software
+ * @hwmon_client: I2C client for hardware monitor
+ * @ioexp_client: I2C client for power/port control
  */
 struct efx_board {
        int type;
@@ -431,7 +434,9 @@ struct efx_board {
        int (*init_leds)(struct efx_nic *efx);
        void (*set_fault_led) (struct efx_nic *efx, int state);
        void (*blink) (struct efx_nic *efx, int start);
+       void (*fini) (struct efx_nic *nic);
        struct efx_blinker blinker;
+       struct i2c_client *hwmon_client, *ioexp_client;
 };
 
 #define STRING_TABLE_LOOKUP(val, member)       \
@@ -618,7 +623,7 @@ union efx_multicast_hash {
  * @membase: Memory BAR value
  * @biu_lock: BIU (bus interface unit) lock
  * @interrupt_mode: Interrupt mode
- * @i2c: I2C interface
+ * @i2c_adap: I2C adapter
  * @board_info: Board-level information
  * @state: Device state flag. Serialised by the rtnl_lock.
  * @reset_pending: Pending reset method (normally RESET_TYPE_NONE)
@@ -686,7 +691,7 @@ struct efx_nic {
        spinlock_t biu_lock;
        enum efx_int_mode interrupt_mode;
 
-       struct efx_i2c_interface i2c;
+       struct i2c_adapter i2c_adap;
        struct efx_board board_info;
 
        enum nic_state state;
index 66a0d1442aba26d33db0ab326c7da1b7f10d63a8..b27849523990e0d9e43f8ff2262dc7c843e955de 100644 (file)
 
 static const u8 xgphy_max_temperature = 90;
 
-void sfe4001_poweroff(struct efx_nic *efx)
+static void sfe4001_poweroff(struct efx_nic *efx)
 {
-       struct efx_i2c_interface *i2c = &efx->i2c;
+       struct i2c_client *ioexp_client = efx->board_info.ioexp_client;
+       struct i2c_client *hwmon_client = efx->board_info.hwmon_client;
 
-       u8 cfg, out, in;
+       /* Turn off all power rails and disable outputs */
+       i2c_smbus_write_byte_data(ioexp_client, P0_OUT, 0xff);
+       i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, 0xff);
+       i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0xff);
 
-       EFX_INFO(efx, "%s\n", __func__);
-
-       /* Turn off all power rails */
-       out = 0xff;
-       efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
-
-       /* Disable port 1 outputs on IO expander */
-       cfg = 0xff;
-       efx_i2c_write(i2c, PCA9539, P1_CONFIG, &cfg, 1);
+       /* Clear any over-temperature alert */
+       i2c_smbus_read_byte_data(hwmon_client, RSL);
+}
 
-       /* Disable port 0 outputs on IO expander */
-       cfg = 0xff;
-       efx_i2c_write(i2c, PCA9539, P0_CONFIG, &cfg, 1);
+static void sfe4001_fini(struct efx_nic *efx)
+{
+       EFX_INFO(efx, "%s\n", __func__);
 
-       /* Clear any over-temperature alert */
-       efx_i2c_read(i2c, MAX6647, RSL, &in, 1);
+       sfe4001_poweroff(efx);
+       i2c_unregister_device(efx->board_info.ioexp_client);
+       i2c_unregister_device(efx->board_info.hwmon_client);
 }
 
 /* The P0_EN_3V3X line on SFE4001 boards (from A2 onward) is connected
@@ -143,14 +142,26 @@ MODULE_PARM_DESC(phy_flash_cfg,
  * be turned on before the PHY can be used.
  * Context: Process context, rtnl lock held
  */
-int sfe4001_poweron(struct efx_nic *efx)
+int sfe4001_init(struct efx_nic *efx)
 {
-       struct efx_i2c_interface *i2c = &efx->i2c;
+       struct i2c_client *hwmon_client, *ioexp_client;
        unsigned int count;
        int rc;
-       u8 out, in, cfg;
+       u8 out;
        efx_dword_t reg;
 
+       hwmon_client = i2c_new_dummy(&efx->i2c_adap, MAX6647);
+       if (!hwmon_client)
+               return -EIO;
+       efx->board_info.hwmon_client = hwmon_client;
+
+       ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539);
+       if (!ioexp_client) {
+               rc = -EIO;
+               goto fail_hwmon;
+       }
+       efx->board_info.ioexp_client = ioexp_client;
+
        /* 10Xpress has fixed-function LED pins, so there is no board-specific
         * blink code. */
        efx->board_info.blink = tenxpress_phy_blink;
@@ -166,44 +177,45 @@ int sfe4001_poweron(struct efx_nic *efx)
        falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
        udelay(10);
 
+       efx->board_info.fini = sfe4001_fini;
+
        /* Set DSP over-temperature alert threshold */
        EFX_INFO(efx, "DSP cut-out at %dC\n", xgphy_max_temperature);
-       rc = efx_i2c_write(i2c, MAX6647, WLHO,
-                          &xgphy_max_temperature, 1);
+       rc = i2c_smbus_write_byte_data(hwmon_client, WLHO,
+                                      xgphy_max_temperature);
        if (rc)
-               goto fail1;
+               goto fail_ioexp;
 
        /* Read it back and verify */
-       rc = efx_i2c_read(i2c, MAX6647, RLHN, &in, 1);
-       if (rc)
-               goto fail1;
-       if (in != xgphy_max_temperature) {
+       rc = i2c_smbus_read_byte_data(hwmon_client, RLHN);
+       if (rc < 0)
+               goto fail_ioexp;
+       if (rc != xgphy_max_temperature) {
                rc = -EFAULT;
-               goto fail1;
+               goto fail_ioexp;
        }
 
        /* Clear any previous over-temperature alert */
-       rc = efx_i2c_read(i2c, MAX6647, RSL, &in, 1);
-       if (rc)
-               goto fail1;
+       rc = i2c_smbus_read_byte_data(hwmon_client, RSL);
+       if (rc < 0)
+               goto fail_ioexp;
 
        /* Enable port 0 and port 1 outputs on IO expander */
-       cfg = 0x00;
-       rc = efx_i2c_write(i2c, PCA9539, P0_CONFIG, &cfg, 1);
+       rc = i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0x00);
        if (rc)
-               goto fail1;
-       cfg = 0xff & ~(1 << P1_SPARE_LBN);
-       rc = efx_i2c_write(i2c, PCA9539, P1_CONFIG, &cfg, 1);
+               goto fail_ioexp;
+       rc = i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG,
+                                      0xff & ~(1 << P1_SPARE_LBN));
        if (rc)
-               goto fail2;
+               goto fail_on;
 
        /* Turn all power off then wait 1 sec. This ensures PHY is reset */
        out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) |
                       (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) |
                       (0 << P0_EN_1V0X_LBN));
-       rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
+       rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
        if (rc)
-               goto fail3;
+               goto fail_on;
 
        schedule_timeout_uninterruptible(HZ);
        count = 0;
@@ -215,26 +227,26 @@ int sfe4001_poweron(struct efx_nic *efx)
                if (sfe4001_phy_flash_cfg)
                        out |= 1 << P0_EN_3V3X_LBN;
 
-               rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
+               rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
                if (rc)
-                       goto fail3;
+                       goto fail_on;
                msleep(10);
 
                /* Turn on 1V power rail */
                out &= ~(1 << P0_EN_1V0X_LBN);
-               rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
+               rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
                if (rc)
-                       goto fail3;
+                       goto fail_on;
 
                EFX_INFO(efx, "waiting for power (attempt %d)...\n", count);
 
                schedule_timeout_uninterruptible(HZ);
 
                /* Check DSP is powered */
-               rc = efx_i2c_read(i2c, PCA9539, P1_IN, &in, 1);
-               if (rc)
-                       goto fail3;
-               if (in & (1 << P1_AFE_PWD_LBN))
+               rc = i2c_smbus_read_byte_data(ioexp_client, P1_IN);
+               if (rc < 0)
+                       goto fail_on;
+               if (rc & (1 << P1_AFE_PWD_LBN))
                        goto done;
 
                /* DSP doesn't look powered in flash config mode */
@@ -244,23 +256,17 @@ int sfe4001_poweron(struct efx_nic *efx)
 
        EFX_INFO(efx, "timed out waiting for power\n");
        rc = -ETIMEDOUT;
-       goto fail3;
+       goto fail_on;
 
 done:
        EFX_INFO(efx, "PHY is powered on\n");
        return 0;
 
-fail3:
-       /* Turn off all power rails */
-       out = 0xff;
-       efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
-       /* Disable port 1 outputs on IO expander */
-       out = 0xff;
-       efx_i2c_write(i2c, PCA9539, P1_CONFIG, &out, 1);
-fail2:
-       /* Disable port 0 outputs on IO expander */
-       out = 0xff;
-       efx_i2c_write(i2c, PCA9539, P0_CONFIG, &out, 1);
-fail1:
+fail_on:
+       sfe4001_poweroff(efx);
+fail_ioexp:
+       i2c_unregister_device(ioexp_client);
+fail_hwmon:
+       i2c_unregister_device(hwmon_client);
        return rc;
 }
index abc63b0663be9ec83854da1a5b79feeefe6d4e66..3fe01763760e917bb0d7f71c6a7eb00eaeb72f1b 100644 (file)
@@ -1656,7 +1656,7 @@ static inline void sis190_init_rxfilter(struct net_device *dev)
        SIS_PCI_COMMIT();
 }
 
-static int __devinit sis190_get_mac_addr(struct pci_dev *pdev, 
+static int __devinit sis190_get_mac_addr(struct pci_dev *pdev,
                                         struct net_device *dev)
 {
        int rc;
index ec95e493ac1c2ec45ee716cac4510c7b15ae1193..fa3a460f8e2f4ddd08d735c481e12466d86c6dca 100644 (file)
@@ -1766,7 +1766,7 @@ static int sis900_rx(struct net_device *net_dev)
                                skb = sis_priv->rx_skbuff[entry];
                                net_dev->stats.rx_dropped++;
                                goto refill_rx_ring;
-                       }       
+                       }
 
                        /* This situation should never happen, but due to
                           some unknow bugs, it is possible that
index 3bb60530d4d78528f2a93a349db764334c736bcc..c83406f4f2a7618afab72b2f7aaf488225bebc94 100644 (file)
@@ -284,6 +284,86 @@ static void sky2_power_aux(struct sky2_hw *hw)
                             PC_VAUX_ON | PC_VCC_OFF));
 }
 
+static void sky2_power_state(struct sky2_hw *hw, pci_power_t state)
+{
+       u16 power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_CTRL);
+       int pex = pci_find_capability(hw->pdev, PCI_CAP_ID_EXP);
+       u32 reg;
+
+       sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+
+       switch (state) {
+       case PCI_D0:
+               break;
+
+       case PCI_D1:
+               power_control |= 1;
+               break;
+
+       case PCI_D2:
+               power_control |= 2;
+               break;
+
+       case PCI_D3hot:
+       case PCI_D3cold:
+               power_control |= 3;
+               if (hw->flags & SKY2_HW_ADV_POWER_CTL) {
+                       /* additional power saving measurements */
+                       reg = sky2_pci_read32(hw, PCI_DEV_REG4);
+
+                       /* set gating core clock for LTSSM in L1 state */
+                       reg |= P_PEX_LTSSM_STAT(P_PEX_LTSSM_L1_STAT) |
+                               /* auto clock gated scheme controlled by CLKREQ */
+                               P_ASPM_A1_MODE_SELECT |
+                               /* enable Gate Root Core Clock */
+                               P_CLK_GATE_ROOT_COR_ENA;
+
+                       if (pex && (hw->flags & SKY2_HW_CLK_POWER)) {
+                               /* enable Clock Power Management (CLKREQ) */
+                               u16 ctrl = sky2_pci_read16(hw, pex + PCI_EXP_DEVCTL);
+
+                               ctrl |= PCI_EXP_DEVCTL_AUX_PME;
+                               sky2_pci_write16(hw, pex + PCI_EXP_DEVCTL, ctrl);
+                       } else
+                               /* force CLKREQ Enable in Our4 (A1b only) */
+                               reg |= P_ASPM_FORCE_CLKREQ_ENA;
+
+                       /* set Mask Register for Release/Gate Clock */
+                       sky2_pci_write32(hw, PCI_DEV_REG5,
+                                        P_REL_PCIE_EXIT_L1_ST | P_GAT_PCIE_ENTER_L1_ST |
+                                        P_REL_PCIE_RX_EX_IDLE | P_GAT_PCIE_RX_EL_IDLE |
+                                        P_REL_GPHY_LINK_UP | P_GAT_GPHY_LINK_DOWN);
+               } else
+                       sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_CLK_HALT);
+
+               /* put CPU into reset state */
+               sky2_write8(hw,  B28_Y2_ASF_STAT_CMD, HCU_CCSR_ASF_RESET);
+               if (hw->chip_id == CHIP_ID_YUKON_SUPR && hw->chip_rev == CHIP_REV_YU_SU_A0)
+                       /* put CPU into halt state */
+                       sky2_write8(hw, B28_Y2_ASF_STAT_CMD, HCU_CCSR_ASF_HALTED);
+
+               if (pex && !(hw->flags & SKY2_HW_RAM_BUFFER)) {
+                       reg = sky2_pci_read32(hw, PCI_DEV_REG1);
+                       /* force to PCIe L1 */
+                       reg |= PCI_FORCE_PEX_L1;
+                       sky2_pci_write32(hw, PCI_DEV_REG1, reg);
+               }
+               break;
+
+       default:
+               dev_warn(&hw->pdev->dev, PFX "Invalid power state (%d) ",
+                      state);
+               return;
+       }
+
+       power_control |= PCI_PM_CTRL_PME_ENABLE;
+       /* Finally, set the new power state. */
+       sky2_pci_write32(hw, hw->pm_cap + PCI_PM_CTRL, power_control);
+
+       sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+       sky2_pci_read32(hw, B0_CTST);
+}
+
 static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port)
 {
        u16 reg;
@@ -619,28 +699,71 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
                gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
 }
 
-static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff)
+static const u32 phy_power[] = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD };
+static const u32 coma_mode[] = { PCI_Y2_PHY1_COMA, PCI_Y2_PHY2_COMA };
+
+static void sky2_phy_power_up(struct sky2_hw *hw, unsigned port)
 {
        u32 reg1;
-       static const u32 phy_power[] = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD };
-       static const u32 coma_mode[] = { PCI_Y2_PHY1_COMA, PCI_Y2_PHY2_COMA };
 
        sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
        reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
-       /* Turn on/off phy power saving */
-       if (onoff)
-               reg1 &= ~phy_power[port];
-       else
-               reg1 |= phy_power[port];
+       reg1 &= ~phy_power[port];
 
-       if (onoff && hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+       if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
                reg1 |= coma_mode[port];
 
        sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
        sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
        sky2_pci_read32(hw, PCI_DEV_REG1);
+}
+
+static void sky2_phy_power_down(struct sky2_hw *hw, unsigned port)
+{
+       u32 reg1;
+       u16 ctrl;
+
+       /* release GPHY Control reset */
+       sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR);
 
-       udelay(100);
+       /* release GMAC reset */
+       sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR);
+
+       if (hw->flags & SKY2_HW_NEWER_PHY) {
+               /* select page 2 to access MAC control register */
+               gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 2);
+
+               ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
+               /* allow GMII Power Down */
+               ctrl &= ~PHY_M_MAC_GMIF_PUP;
+               gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
+
+               /* set page register back to 0 */
+               gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 0);
+       }
+
+       /* setup General Purpose Control Register */
+       gma_write16(hw, port, GM_GP_CTRL,
+                   GM_GPCR_FL_PASS | GM_GPCR_SPEED_100 | GM_GPCR_AU_ALL_DIS);
+
+       if (hw->chip_id != CHIP_ID_YUKON_EC) {
+               if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
+                       ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
+
+                       /* enable Power Down */
+                       ctrl |= PHY_M_PC_POW_D_ENA;
+                       gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
+               }
+
+               /* set IEEE compatible Power Down Mode (dev. #4.99) */
+               gm_phy_write(hw, port, PHY_MARV_CTRL, PHY_CT_PDOWN);
+       }
+
+       sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+       reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
+       reg1 |= phy_power[port];                /* set PHY to PowerDown/COMA Mode */
+       sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
+       sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
 }
 
 /* Force a renegotiation */
@@ -675,8 +798,11 @@ static void sky2_wol_init(struct sky2_port *sky2)
 
        sky2->advertising &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full);
        sky2->flow_mode = FC_NONE;
-       sky2_phy_power(hw, port, 1);
-       sky2_phy_reinit(sky2);
+
+       spin_lock_bh(&sky2->phy_lock);
+       sky2_phy_power_up(hw, port);
+       sky2_phy_init(hw, port);
+       spin_unlock_bh(&sky2->phy_lock);
 
        sky2->flow_mode = save_mode;
        sky2->advertising = ctrl;
@@ -781,6 +907,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
        sky2_write8(hw, SK_REG(port, GMAC_IRQ_MSK), GMAC_DEF_MSK);
 
        spin_lock_bh(&sky2->phy_lock);
+       sky2_phy_power_up(hw, port);
        sky2_phy_init(hw, port);
        spin_unlock_bh(&sky2->phy_lock);
 
@@ -1385,8 +1512,6 @@ static int sky2_up(struct net_device *dev)
        if (!sky2->rx_ring)
                goto err_out;
 
-       sky2_phy_power(hw, port, 1);
-
        sky2_mac_init(hw, port);
 
        /* Register is number of 4K blocks on internal RAM buffer. */
@@ -1767,7 +1892,7 @@ static int sky2_down(struct net_device *dev)
        sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
        sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET);
 
-       sky2_phy_power(hw, port, 0);
+       sky2_phy_power_down(hw, port);
 
        netif_carrier_off(dev);
 
@@ -2741,6 +2866,10 @@ static int __devinit sky2_init(struct sky2_hw *hw)
                hw->flags = SKY2_HW_GIGABIT
                        | SKY2_HW_NEWER_PHY
                        | SKY2_HW_ADV_POWER_CTL;
+
+               /* check for Rev. A1 dev 4200 */
+               if (sky2_read16(hw, Q_ADDR(Q_XA1, Q_WM)) == 0)
+                       hw->flags |= SKY2_HW_CLK_POWER;
                break;
 
        case CHIP_ID_YUKON_EX:
@@ -2791,6 +2920,11 @@ static int __devinit sky2_init(struct sky2_hw *hw)
        if (hw->pmd_type == 'L' || hw->pmd_type == 'S' || hw->pmd_type == 'P')
                hw->flags |= SKY2_HW_FIBRE_PHY;
 
+       hw->pm_cap = pci_find_capability(hw->pdev, PCI_CAP_ID_PM);
+       if (hw->pm_cap == 0) {
+               dev_err(&hw->pdev->dev, "cannot find PowerManagement capability\n");
+               return -EIO;
+       }
 
        hw->ports = 1;
        t8 = sky2_read8(hw, B2_Y2_HW_RES);
@@ -3378,7 +3512,7 @@ static void sky2_led(struct sky2_port *sky2, enum led_mode mode)
 
                gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
        } else
-               gm_phy_write(hw, port, PHY_MARV_LED_OVER, 
+               gm_phy_write(hw, port, PHY_MARV_LED_OVER,
                                     PHY_M_LED_MO_DUP(mode) |
                                     PHY_M_LED_MO_10(mode) |
                                     PHY_M_LED_MO_100(mode) |
@@ -4362,7 +4496,7 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
 
        pci_save_state(pdev);
        pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
-       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+       sky2_power_state(hw, pci_choose_state(pdev, state));
 
        return 0;
 }
@@ -4375,9 +4509,7 @@ static int sky2_resume(struct pci_dev *pdev)
        if (!hw)
                return 0;
 
-       err = pci_set_power_state(pdev, PCI_D0);
-       if (err)
-               goto out;
+       sky2_power_state(hw, PCI_D0);
 
        err = pci_restore_state(pdev);
        if (err)
@@ -4445,8 +4577,7 @@ static void sky2_shutdown(struct pci_dev *pdev)
        pci_enable_wake(pdev, PCI_D3cold, wol);
 
        pci_disable_device(pdev);
-       pci_set_power_state(pdev, PCI_D3hot);
-
+       sky2_power_state(hw, PCI_D3hot);
 }
 
 static struct pci_driver sky2_driver = {
index c0a5eea20007d461660d79f176d2eed00c7e7903..1fa82bf029d9a312c507c4dd0df1798cd4e718e6 100644 (file)
@@ -28,6 +28,11 @@ enum pci_dev_reg_1 {
        PCI_Y2_PHY2_POWD = 1<<27, /* Set PHY 2 to Power Down (YUKON-2) */
        PCI_Y2_PHY1_POWD = 1<<26, /* Set PHY 1 to Power Down (YUKON-2) */
        PCI_Y2_PME_LEGACY= 1<<15, /* PCI Express legacy power management mode */
+
+       PCI_PHY_LNK_TIM_MSK= 3L<<8,/* Bit  9.. 8:       GPHY Link Trigger Timer */
+       PCI_ENA_L1_EVENT = 1<<7, /* Enable PEX L1 Event */
+       PCI_ENA_GPHY_LNK = 1<<6, /* Enable PEX L1 on GPHY Link down */
+       PCI_FORCE_PEX_L1 = 1<<5, /* Force to PEX L1 */
 };
 
 enum pci_dev_reg_2 {
@@ -45,7 +50,11 @@ enum pci_dev_reg_2 {
 
 /*     PCI_OUR_REG_4           32 bit  Our Register 4 (Yukon-ECU only) */
 enum pci_dev_reg_4 {
-                                       /* (Link Training & Status State Machine) */
+                               /* (Link Training & Status State Machine) */
+       P_PEX_LTSSM_STAT_MSK    = 0x7fL<<25,    /* Bit 31..25:  PEX LTSSM Mask */
+#define P_PEX_LTSSM_STAT(x)    ((x << 25) & P_PEX_LTSSM_STAT_MSK)
+       P_PEX_LTSSM_L1_STAT     = 0x34,
+       P_PEX_LTSSM_DET_STAT    = 0x01,
        P_TIMER_VALUE_MSK       = 0xffL<<16,    /* Bit 23..16:  Timer Value Mask */
                                        /* (Active State Power Management) */
        P_FORCE_ASPM_REQUEST    = 1<<15, /* Force ASPM Request (A1 only) */
@@ -454,6 +463,9 @@ enum yukon_ex_rev {
        CHIP_REV_YU_EX_A0    = 1,
        CHIP_REV_YU_EX_B0    = 2,
 };
+enum yukon_supr_rev {
+       CHIP_REV_YU_SU_A0    = 0,
+};
 
 
 /*     B2_Y2_CLK_GATE   8 bit  Clock Gating (Yukon-2 only) */
@@ -1143,6 +1155,12 @@ enum {
        PHY_M_PC_ENA_AUTO       = 3, /* 11 = Enable Automatic Crossover */
 };
 
+/* for Yukon-EC Ultra Gigabit Ethernet PHY (88E1149 only) */
+enum {
+       PHY_M_PC_COP_TX_DIS     = 1<<3, /* Copper Transmitter Disable */
+       PHY_M_PC_POW_D_ENA      = 1<<2, /* Power Down Enable */
+};
+
 /* for 10/100 Fast Ethernet PHY (88E3082 only) */
 enum {
        PHY_M_PC_ENA_DTE_DT     = 1<<15, /* Enable Data Terminal Equ. (DTE) Detect */
@@ -1411,6 +1429,7 @@ enum {
 /*****  PHY_MARV_PHY_CTRL (page 2)             16 bit r/w      MAC Specific Ctrl *****/
 enum {
        PHY_M_MAC_MD_MSK        = 7<<7, /* Bit  9.. 7: Mode Select Mask */
+       PHY_M_MAC_GMIF_PUP      = 1<<3, /* GMII Power Up (88E1149 only) */
        PHY_M_MAC_MD_AUTO       = 3,/* Auto Copper/1000Base-X */
        PHY_M_MAC_MD_COPPER     = 5,/* Copper only */
        PHY_M_MAC_MD_1000BX     = 7,/* 1000Base-X only */
@@ -2052,7 +2071,9 @@ struct sky2_hw {
 #define SKY2_HW_NEW_LE         0x00000020      /* new LSOv2 format */
 #define SKY2_HW_AUTO_TX_SUM    0x00000040      /* new IP decode for Tx */
 #define SKY2_HW_ADV_POWER_CTL  0x00000080      /* additional PHY power regs */
+#define SKY2_HW_CLK_POWER      0x00000100      /* clock power management */
 
+       int                  pm_cap;
        u8                   chip_id;
        u8                   chip_rev;
        u8                   pmd_type;
index 477671606273ee411a6e701cc9b6b4154d827f03..00aa0b108cb9691982991bd819c53b1ac9b3252f 100644 (file)
@@ -1704,7 +1704,7 @@ spider_net_poll_controller(struct net_device *netdev)
  *
  * spider_net_enable_interrupt enables several interrupts
  */
-static void 
+static void
 spider_net_enable_interrupts(struct spider_net_card *card)
 {
        spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK,
@@ -1721,7 +1721,7 @@ spider_net_enable_interrupts(struct spider_net_card *card)
  *
  * spider_net_disable_interrupts disables all the interrupts
  */
-static void 
+static void
 spider_net_disable_interrupts(struct spider_net_card *card)
 {
        spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, 0);
index cc4bde8525421e614c90a49acd60ef8bed66f30c..633c128a622868ac91b9cde33b41baf6c4e8e219 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/skbuff.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/brcmphy.h>
 #include <linux/if_vlan.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
@@ -64,8 +66,8 @@
 
 #define DRV_MODULE_NAME                "tg3"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "3.92.1"
-#define DRV_MODULE_RELDATE     "June 9, 2008"
+#define DRV_MODULE_VERSION     "3.93"
+#define DRV_MODULE_RELDATE     "May 22, 2008"
 
 #define TG3_DEF_MAC_MODE       0
 #define TG3_DEF_RX_MODE                0
@@ -203,6 +205,7 @@ static struct pci_device_id tg3_pci_tbl[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5723)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761E)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5785)},
        {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)},
        {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)},
        {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)},
@@ -804,6 +807,569 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
        return ret;
 }
 
+static int tg3_bmcr_reset(struct tg3 *tp)
+{
+       u32 phy_control;
+       int limit, err;
+
+       /* OK, reset it, and poll the BMCR_RESET bit until it
+        * clears or we time out.
+        */
+       phy_control = BMCR_RESET;
+       err = tg3_writephy(tp, MII_BMCR, phy_control);
+       if (err != 0)
+               return -EBUSY;
+
+       limit = 5000;
+       while (limit--) {
+               err = tg3_readphy(tp, MII_BMCR, &phy_control);
+               if (err != 0)
+                       return -EBUSY;
+
+               if ((phy_control & BMCR_RESET) == 0) {
+                       udelay(40);
+                       break;
+               }
+               udelay(10);
+       }
+       if (limit <= 0)
+               return -EBUSY;
+
+       return 0;
+}
+
+static int tg3_mdio_read(struct mii_bus *bp, int mii_id, int reg)
+{
+       struct tg3 *tp = (struct tg3 *)bp->priv;
+       u32 val;
+
+       if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_PAUSED)
+               return -EAGAIN;
+
+       if (tg3_readphy(tp, reg, &val))
+               return -EIO;
+
+       return val;
+}
+
+static int tg3_mdio_write(struct mii_bus *bp, int mii_id, int reg, u16 val)
+{
+       struct tg3 *tp = (struct tg3 *)bp->priv;
+
+       if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_PAUSED)
+               return -EAGAIN;
+
+       if (tg3_writephy(tp, reg, val))
+               return -EIO;
+
+       return 0;
+}
+
+static int tg3_mdio_reset(struct mii_bus *bp)
+{
+       return 0;
+}
+
+static void tg3_mdio_config(struct tg3 *tp)
+{
+       u32 val;
+
+       if (tp->mdio_bus.phy_map[PHY_ADDR]->interface !=
+           PHY_INTERFACE_MODE_RGMII)
+               return;
+
+       val = tr32(MAC_PHYCFG1) & ~(MAC_PHYCFG1_RGMII_EXT_RX_DEC |
+                                   MAC_PHYCFG1_RGMII_SND_STAT_EN);
+       if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE) {
+               if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN)
+                       val |= MAC_PHYCFG1_RGMII_EXT_RX_DEC;
+               if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN)
+                       val |= MAC_PHYCFG1_RGMII_SND_STAT_EN;
+       }
+       tw32(MAC_PHYCFG1, val | MAC_PHYCFG1_RGMII_INT | MAC_PHYCFG1_TXC_DRV);
+
+       val = tr32(MAC_PHYCFG2) & ~(MAC_PHYCFG2_INBAND_ENABLE);
+       if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE))
+               val |= MAC_PHYCFG2_INBAND_ENABLE;
+       tw32(MAC_PHYCFG2, val);
+
+       val = tr32(MAC_EXT_RGMII_MODE);
+       val &= ~(MAC_RGMII_MODE_RX_INT_B |
+                MAC_RGMII_MODE_RX_QUALITY |
+                MAC_RGMII_MODE_RX_ACTIVITY |
+                MAC_RGMII_MODE_RX_ENG_DET |
+                MAC_RGMII_MODE_TX_ENABLE |
+                MAC_RGMII_MODE_TX_LOWPWR |
+                MAC_RGMII_MODE_TX_RESET);
+       if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE) {
+               if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN)
+                       val |= MAC_RGMII_MODE_RX_INT_B |
+                              MAC_RGMII_MODE_RX_QUALITY |
+                              MAC_RGMII_MODE_RX_ACTIVITY |
+                              MAC_RGMII_MODE_RX_ENG_DET;
+               if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN)
+                       val |= MAC_RGMII_MODE_TX_ENABLE |
+                              MAC_RGMII_MODE_TX_LOWPWR |
+                              MAC_RGMII_MODE_TX_RESET;
+       }
+       tw32(MAC_EXT_RGMII_MODE, val);
+}
+
+static void tg3_mdio_start(struct tg3 *tp)
+{
+       if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) {
+               mutex_lock(&tp->mdio_bus.mdio_lock);
+               tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_PAUSED;
+               mutex_unlock(&tp->mdio_bus.mdio_lock);
+       }
+
+       tp->mi_mode &= ~MAC_MI_MODE_AUTO_POLL;
+       tw32_f(MAC_MI_MODE, tp->mi_mode);
+       udelay(80);
+
+       if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED)
+               tg3_mdio_config(tp);
+}
+
+static void tg3_mdio_stop(struct tg3 *tp)
+{
+       if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) {
+               mutex_lock(&tp->mdio_bus.mdio_lock);
+               tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_PAUSED;
+               mutex_unlock(&tp->mdio_bus.mdio_lock);
+       }
+}
+
+static int tg3_mdio_init(struct tg3 *tp)
+{
+       int i;
+       u32 reg;
+       struct phy_device *phydev;
+       struct mii_bus *mdio_bus = &tp->mdio_bus;
+
+       tg3_mdio_start(tp);
+
+       if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) ||
+           (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED))
+               return 0;
+
+       memset(mdio_bus, 0, sizeof(*mdio_bus));
+
+       mdio_bus->name     = "tg3 mdio bus";
+       snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%x",
+                (tp->pdev->bus->number << 8) | tp->pdev->devfn);
+       mdio_bus->priv     = tp;
+       mdio_bus->dev      = &tp->pdev->dev;
+       mdio_bus->read     = &tg3_mdio_read;
+       mdio_bus->write    = &tg3_mdio_write;
+       mdio_bus->reset    = &tg3_mdio_reset;
+       mdio_bus->phy_mask = ~(1 << PHY_ADDR);
+       mdio_bus->irq      = &tp->mdio_irq[0];
+
+       for (i = 0; i < PHY_MAX_ADDR; i++)
+               mdio_bus->irq[i] = PHY_POLL;
+
+       /* The bus registration will look for all the PHYs on the mdio bus.
+        * Unfortunately, it does not ensure the PHY is powered up before
+        * accessing the PHY ID registers.  A chip reset is the
+        * quickest way to bring the device back to an operational state..
+        */
+       if (tg3_readphy(tp, MII_BMCR, &reg) || (reg & BMCR_PDOWN))
+               tg3_bmcr_reset(tp);
+
+       i = mdiobus_register(mdio_bus);
+       if (i) {
+               printk(KERN_WARNING "%s: mdiobus_reg failed (0x%x)\n",
+                       tp->dev->name, i);
+               return i;
+       }
+
+       tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_INITED;
+
+       phydev = tp->mdio_bus.phy_map[PHY_ADDR];
+
+       switch (phydev->phy_id) {
+       case TG3_PHY_ID_BCM50610:
+               phydev->interface = PHY_INTERFACE_MODE_RGMII;
+               if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE)
+                       phydev->dev_flags |= PHY_BRCM_STD_IBND_DISABLE;
+               if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN)
+                       phydev->dev_flags |= PHY_BRCM_EXT_IBND_RX_ENABLE;
+               if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN)
+                       phydev->dev_flags |= PHY_BRCM_EXT_IBND_TX_ENABLE;
+               break;
+       case TG3_PHY_ID_BCMAC131:
+               phydev->interface = PHY_INTERFACE_MODE_MII;
+               break;
+       }
+
+       tg3_mdio_config(tp);
+
+       return 0;
+}
+
+static void tg3_mdio_fini(struct tg3 *tp)
+{
+       if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) {
+               tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_INITED;
+               mdiobus_unregister(&tp->mdio_bus);
+               tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_PAUSED;
+       }
+}
+
+/* tp->lock is held. */
+static void tg3_wait_for_event_ack(struct tg3 *tp)
+{
+       int i;
+
+       /* Wait for up to 2.5 milliseconds */
+       for (i = 0; i < 250000; i++) {
+               if (!(tr32(GRC_RX_CPU_EVENT) & GRC_RX_CPU_DRIVER_EVENT))
+                       break;
+               udelay(10);
+       }
+}
+
+/* tp->lock is held. */
+static void tg3_ump_link_report(struct tg3 *tp)
+{
+       u32 reg;
+       u32 val;
+
+       if (!(tp->tg3_flags2 & TG3_FLG2_5780_CLASS) ||
+           !(tp->tg3_flags  & TG3_FLAG_ENABLE_ASF))
+               return;
+
+       tg3_wait_for_event_ack(tp);
+
+       tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_LINK_UPDATE);
+
+       tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 14);
+
+       val = 0;
+       if (!tg3_readphy(tp, MII_BMCR, &reg))
+               val = reg << 16;
+       if (!tg3_readphy(tp, MII_BMSR, &reg))
+               val |= (reg & 0xffff);
+       tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, val);
+
+       val = 0;
+       if (!tg3_readphy(tp, MII_ADVERTISE, &reg))
+               val = reg << 16;
+       if (!tg3_readphy(tp, MII_LPA, &reg))
+               val |= (reg & 0xffff);
+       tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 4, val);
+
+       val = 0;
+       if (!(tp->tg3_flags2 & TG3_FLG2_MII_SERDES)) {
+               if (!tg3_readphy(tp, MII_CTRL1000, &reg))
+                       val = reg << 16;
+               if (!tg3_readphy(tp, MII_STAT1000, &reg))
+                       val |= (reg & 0xffff);
+       }
+       tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 8, val);
+
+       if (!tg3_readphy(tp, MII_PHYADDR, &reg))
+               val = reg << 16;
+       else
+               val = 0;
+       tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 12, val);
+
+       val = tr32(GRC_RX_CPU_EVENT);
+       val |= GRC_RX_CPU_DRIVER_EVENT;
+       tw32_f(GRC_RX_CPU_EVENT, val);
+}
+
+static void tg3_link_report(struct tg3 *tp)
+{
+       if (!netif_carrier_ok(tp->dev)) {
+               if (netif_msg_link(tp))
+                       printk(KERN_INFO PFX "%s: Link is down.\n",
+                              tp->dev->name);
+               tg3_ump_link_report(tp);
+       } else if (netif_msg_link(tp)) {
+               printk(KERN_INFO PFX "%s: Link is up at %d Mbps, %s duplex.\n",
+                      tp->dev->name,
+                      (tp->link_config.active_speed == SPEED_1000 ?
+                       1000 :
+                       (tp->link_config.active_speed == SPEED_100 ?
+                        100 : 10)),
+                      (tp->link_config.active_duplex == DUPLEX_FULL ?
+                       "full" : "half"));
+
+               printk(KERN_INFO PFX
+                      "%s: Flow control is %s for TX and %s for RX.\n",
+                      tp->dev->name,
+                      (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_TX) ?
+                      "on" : "off",
+                      (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX) ?
+                      "on" : "off");
+               tg3_ump_link_report(tp);
+       }
+}
+
+static u16 tg3_advert_flowctrl_1000T(u8 flow_ctrl)
+{
+       u16 miireg;
+
+       if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX))
+               miireg = ADVERTISE_PAUSE_CAP;
+       else if (flow_ctrl & TG3_FLOW_CTRL_TX)
+               miireg = ADVERTISE_PAUSE_ASYM;
+       else if (flow_ctrl & TG3_FLOW_CTRL_RX)
+               miireg = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+       else
+               miireg = 0;
+
+       return miireg;
+}
+
+static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl)
+{
+       u16 miireg;
+
+       if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX))
+               miireg = ADVERTISE_1000XPAUSE;
+       else if (flow_ctrl & TG3_FLOW_CTRL_TX)
+               miireg = ADVERTISE_1000XPSE_ASYM;
+       else if (flow_ctrl & TG3_FLOW_CTRL_RX)
+               miireg = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
+       else
+               miireg = 0;
+
+       return miireg;
+}
+
+static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv)
+{
+       u8 cap = 0;
+
+       if (lcladv & ADVERTISE_PAUSE_CAP) {
+               if (lcladv & ADVERTISE_PAUSE_ASYM) {
+                       if (rmtadv & LPA_PAUSE_CAP)
+                               cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+                       else if (rmtadv & LPA_PAUSE_ASYM)
+                               cap = TG3_FLOW_CTRL_RX;
+               } else {
+                       if (rmtadv & LPA_PAUSE_CAP)
+                               cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+               }
+       } else if (lcladv & ADVERTISE_PAUSE_ASYM) {
+               if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM))
+                       cap = TG3_FLOW_CTRL_TX;
+       }
+
+       return cap;
+}
+
+static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv)
+{
+       u8 cap = 0;
+
+       if (lcladv & ADVERTISE_1000XPAUSE) {
+               if (lcladv & ADVERTISE_1000XPSE_ASYM) {
+                       if (rmtadv & LPA_1000XPAUSE)
+                               cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+                       else if (rmtadv & LPA_1000XPAUSE_ASYM)
+                               cap = TG3_FLOW_CTRL_RX;
+               } else {
+                       if (rmtadv & LPA_1000XPAUSE)
+                               cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+               }
+       } else if (lcladv & ADVERTISE_1000XPSE_ASYM) {
+               if ((rmtadv & LPA_1000XPAUSE) && (rmtadv & LPA_1000XPAUSE_ASYM))
+                       cap = TG3_FLOW_CTRL_TX;
+       }
+
+       return cap;
+}
+
+static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv)
+{
+       u8 autoneg;
+       u8 flowctrl = 0;
+       u32 old_rx_mode = tp->rx_mode;
+       u32 old_tx_mode = tp->tx_mode;
+
+       if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)
+               autoneg = tp->mdio_bus.phy_map[PHY_ADDR]->autoneg;
+       else
+               autoneg = tp->link_config.autoneg;
+
+       if (autoneg == AUTONEG_ENABLE &&
+           (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) {
+               if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)
+                       flowctrl = tg3_resolve_flowctrl_1000X(lcladv, rmtadv);
+               else
+                       flowctrl = tg3_resolve_flowctrl_1000T(lcladv, rmtadv);
+       } else
+               flowctrl = tp->link_config.flowctrl;
+
+       tp->link_config.active_flowctrl = flowctrl;
+
+       if (flowctrl & TG3_FLOW_CTRL_RX)
+               tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE;
+       else
+               tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE;
+
+       if (old_rx_mode != tp->rx_mode)
+               tw32_f(MAC_RX_MODE, tp->rx_mode);
+
+       if (flowctrl & TG3_FLOW_CTRL_TX)
+               tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE;
+       else
+               tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE;
+
+       if (old_tx_mode != tp->tx_mode)
+               tw32_f(MAC_TX_MODE, tp->tx_mode);
+}
+
+static void tg3_adjust_link(struct net_device *dev)
+{
+       u8 oldflowctrl, linkmesg = 0;
+       u32 mac_mode, lcl_adv, rmt_adv;
+       struct tg3 *tp = netdev_priv(dev);
+       struct phy_device *phydev = tp->mdio_bus.phy_map[PHY_ADDR];
+
+       spin_lock(&tp->lock);
+
+       mac_mode = tp->mac_mode & ~(MAC_MODE_PORT_MODE_MASK |
+                                   MAC_MODE_HALF_DUPLEX);
+
+       oldflowctrl = tp->link_config.active_flowctrl;
+
+       if (phydev->link) {
+               lcl_adv = 0;
+               rmt_adv = 0;
+
+               if (phydev->speed == SPEED_100 || phydev->speed == SPEED_10)
+                       mac_mode |= MAC_MODE_PORT_MODE_MII;
+               else
+                       mac_mode |= MAC_MODE_PORT_MODE_GMII;
+
+               if (phydev->duplex == DUPLEX_HALF)
+                       mac_mode |= MAC_MODE_HALF_DUPLEX;
+               else {
+                       lcl_adv = tg3_advert_flowctrl_1000T(
+                                 tp->link_config.flowctrl);
+
+                       if (phydev->pause)
+                               rmt_adv = LPA_PAUSE_CAP;
+                       if (phydev->asym_pause)
+                               rmt_adv |= LPA_PAUSE_ASYM;
+               }
+
+               tg3_setup_flow_control(tp, lcl_adv, rmt_adv);
+       } else
+               mac_mode |= MAC_MODE_PORT_MODE_GMII;
+
+       if (mac_mode != tp->mac_mode) {
+               tp->mac_mode = mac_mode;
+               tw32_f(MAC_MODE, tp->mac_mode);
+               udelay(40);
+       }
+
+       if (phydev->speed == SPEED_1000 && phydev->duplex == DUPLEX_HALF)
+               tw32(MAC_TX_LENGTHS,
+                    ((2 << TX_LENGTHS_IPG_CRS_SHIFT) |
+                     (6 << TX_LENGTHS_IPG_SHIFT) |
+                     (0xff << TX_LENGTHS_SLOT_TIME_SHIFT)));
+       else
+               tw32(MAC_TX_LENGTHS,
+                    ((2 << TX_LENGTHS_IPG_CRS_SHIFT) |
+                     (6 << TX_LENGTHS_IPG_SHIFT) |
+                     (32 << TX_LENGTHS_SLOT_TIME_SHIFT)));
+
+       if ((phydev->link && tp->link_config.active_speed == SPEED_INVALID) ||
+           (!phydev->link && tp->link_config.active_speed != SPEED_INVALID) ||
+           phydev->speed != tp->link_config.active_speed ||
+           phydev->duplex != tp->link_config.active_duplex ||
+           oldflowctrl != tp->link_config.active_flowctrl)
+           linkmesg = 1;
+
+       tp->link_config.active_speed = phydev->speed;
+       tp->link_config.active_duplex = phydev->duplex;
+
+       spin_unlock(&tp->lock);
+
+       if (linkmesg)
+               tg3_link_report(tp);
+}
+
+static int tg3_phy_init(struct tg3 *tp)
+{
+       struct phy_device *phydev;
+
+       if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)
+               return 0;
+
+       /* Bring the PHY back to a known state. */
+       tg3_bmcr_reset(tp);
+
+       phydev = tp->mdio_bus.phy_map[PHY_ADDR];
+
+       /* Attach the MAC to the PHY. */
+       phydev = phy_connect(tp->dev, phydev->dev.bus_id, tg3_adjust_link,
+                            phydev->dev_flags, phydev->interface);
+       if (IS_ERR(phydev)) {
+               printk(KERN_ERR "%s: Could not attach to PHY\n", tp->dev->name);
+               return PTR_ERR(phydev);
+       }
+
+       tp->tg3_flags3 |= TG3_FLG3_PHY_CONNECTED;
+
+       /* Mask with MAC supported features. */
+       phydev->supported &= (PHY_GBIT_FEATURES |
+                             SUPPORTED_Pause |
+                             SUPPORTED_Asym_Pause);
+
+       phydev->advertising = phydev->supported;
+
+       printk(KERN_INFO
+              "%s: attached PHY driver [%s] (mii_bus:phy_addr=%s)\n",
+              tp->dev->name, phydev->drv->name, phydev->dev.bus_id);
+
+       return 0;
+}
+
+static void tg3_phy_start(struct tg3 *tp)
+{
+       struct phy_device *phydev;
+
+       if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+               return;
+
+       phydev = tp->mdio_bus.phy_map[PHY_ADDR];
+
+       if (tp->link_config.phy_is_low_power) {
+               tp->link_config.phy_is_low_power = 0;
+               phydev->speed = tp->link_config.orig_speed;
+               phydev->duplex = tp->link_config.orig_duplex;
+               phydev->autoneg = tp->link_config.orig_autoneg;
+               phydev->advertising = tp->link_config.orig_advertising;
+       }
+
+       phy_start(phydev);
+
+       phy_start_aneg(phydev);
+}
+
+static void tg3_phy_stop(struct tg3 *tp)
+{
+       if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+               return;
+
+       phy_stop(tp->mdio_bus.phy_map[PHY_ADDR]);
+}
+
+static void tg3_phy_fini(struct tg3 *tp)
+{
+       if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) {
+               phy_disconnect(tp->mdio_bus.phy_map[PHY_ADDR]);
+               tp->tg3_flags3 &= ~TG3_FLG3_PHY_CONNECTED;
+       }
+}
+
 static void tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val)
 {
        tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg);
@@ -861,37 +1427,6 @@ static void tg3_phy_set_wirespeed(struct tg3 *tp)
                             (val | (1 << 15) | (1 << 4)));
 }
 
-static int tg3_bmcr_reset(struct tg3 *tp)
-{
-       u32 phy_control;
-       int limit, err;
-
-       /* OK, reset it, and poll the BMCR_RESET bit until it
-        * clears or we time out.
-        */
-       phy_control = BMCR_RESET;
-       err = tg3_writephy(tp, MII_BMCR, phy_control);
-       if (err != 0)
-               return -EBUSY;
-
-       limit = 5000;
-       while (limit--) {
-               err = tg3_readphy(tp, MII_BMCR, &phy_control);
-               if (err != 0)
-                       return -EBUSY;
-
-               if ((phy_control & BMCR_RESET) == 0) {
-                       udelay(40);
-                       break;
-               }
-               udelay(10);
-       }
-       if (limit <= 0)
-               return -EBUSY;
-
-       return 0;
-}
-
 static void tg3_phy_apply_otp(struct tg3 *tp)
 {
        u32 otp, phy;
@@ -1115,8 +1650,6 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp)
        return err;
 }
 
-static void tg3_link_report(struct tg3 *);
-
 /* This will reset the tigon3 PHY if there is no valid
  * link unless the FORCE argument is non-zero.
  */
@@ -1421,7 +1954,7 @@ static void tg3_power_down_phy(struct tg3 *tp)
                tw32_f(GRC_MISC_CFG, val | GRC_MISC_CFG_EPHY_IDDQ);
                udelay(40);
                return;
-       } else {
+       } else if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) {
                tg3_writephy(tp, MII_TG3_EXT_CTRL,
                             MII_TG3_EXT_CTRL_FORCE_LED_OFF);
                tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x01b2);
@@ -1495,7 +2028,7 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
                       "requested.\n",
                       tp->dev->name, state);
                return -EINVAL;
-       };
+       }
 
        power_control |= PCI_PM_CTRL_PME_ENABLE;
 
@@ -1503,18 +2036,55 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
        tw32(TG3PCI_MISC_HOST_CTRL,
             misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT);
 
-       if (tp->link_config.phy_is_low_power == 0) {
-               tp->link_config.phy_is_low_power = 1;
-               tp->link_config.orig_speed = tp->link_config.speed;
-               tp->link_config.orig_duplex = tp->link_config.duplex;
-               tp->link_config.orig_autoneg = tp->link_config.autoneg;
-       }
+       if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+               if ((tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) &&
+                   !tp->link_config.phy_is_low_power) {
+                       struct phy_device *phydev;
+                       u32 advertising;
+
+                       phydev = tp->mdio_bus.phy_map[PHY_ADDR];
+
+                       tp->link_config.phy_is_low_power = 1;
+
+                       tp->link_config.orig_speed = phydev->speed;
+                       tp->link_config.orig_duplex = phydev->duplex;
+                       tp->link_config.orig_autoneg = phydev->autoneg;
+                       tp->link_config.orig_advertising = phydev->advertising;
+
+                       advertising = ADVERTISED_TP |
+                                     ADVERTISED_Pause |
+                                     ADVERTISED_Autoneg |
+                                     ADVERTISED_10baseT_Half;
+
+                       if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
+                           (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)) {
+                               if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB)
+                                       advertising |=
+                                               ADVERTISED_100baseT_Half |
+                                               ADVERTISED_100baseT_Full |
+                                               ADVERTISED_10baseT_Full;
+                               else
+                                       advertising |= ADVERTISED_10baseT_Full;
+                       }
 
-       if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) {
-               tp->link_config.speed = SPEED_10;
-               tp->link_config.duplex = DUPLEX_HALF;
-               tp->link_config.autoneg = AUTONEG_ENABLE;
-               tg3_setup_phy(tp, 0);
+                       phydev->advertising = advertising;
+
+                       phy_start_aneg(phydev);
+               }
+       } else {
+               if (tp->link_config.phy_is_low_power == 0) {
+                       tp->link_config.phy_is_low_power = 1;
+                       tp->link_config.orig_speed = tp->link_config.speed;
+                       tp->link_config.orig_duplex = tp->link_config.duplex;
+                       tp->link_config.orig_autoneg = tp->link_config.autoneg;
+               }
+
+               if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) {
+                       tp->link_config.speed = SPEED_10;
+                       tp->link_config.duplex = DUPLEX_HALF;
+                       tp->link_config.autoneg = AUTONEG_ENABLE;
+                       tg3_setup_phy(tp, 0);
+               }
        }
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
@@ -1545,8 +2115,10 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
                u32 mac_mode;
 
                if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
-                       tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a);
-                       udelay(40);
+                       if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) {
+                               tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a);
+                               udelay(40);
+                       }
 
                        if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
                                mac_mode = MAC_MODE_PORT_MODE_GMII;
@@ -1607,274 +2179,68 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
                                    CLOCK_CTRL_TXCLK_DISABLE |
                                    CLOCK_CTRL_ALTCLK);
                        newbits2 = newbits1 | CLOCK_CTRL_44MHZ_CORE;
-               } else if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
-                       newbits1 = CLOCK_CTRL_625_CORE;
-                       newbits2 = newbits1 | CLOCK_CTRL_ALTCLK;
-               } else {
-                       newbits1 = CLOCK_CTRL_ALTCLK;
-                       newbits2 = newbits1 | CLOCK_CTRL_44MHZ_CORE;
-               }
-
-               tw32_wait_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl | newbits1,
-                           40);
-
-               tw32_wait_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl | newbits2,
-                           40);
-
-               if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
-                       u32 newbits3;
-
-                       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
-                           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
-                               newbits3 = (CLOCK_CTRL_RXCLK_DISABLE |
-                                           CLOCK_CTRL_TXCLK_DISABLE |
-                                           CLOCK_CTRL_44MHZ_CORE);
-                       } else {
-                               newbits3 = CLOCK_CTRL_44MHZ_CORE;
-                       }
-
-                       tw32_wait_f(TG3PCI_CLOCK_CTRL,
-                                   tp->pci_clock_ctrl | newbits3, 40);
-               }
-       }
-
-       if (!(tp->tg3_flags & TG3_FLAG_WOL_ENABLE) &&
-           !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
-           !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
-               tg3_power_down_phy(tp);
-
-       tg3_frob_aux_power(tp);
-
-       /* Workaround for unstable PLL clock */
-       if ((GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX) ||
-           (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_BX)) {
-               u32 val = tr32(0x7d00);
-
-               val &= ~((1 << 16) | (1 << 4) | (1 << 2) | (1 << 1) | 1);
-               tw32(0x7d00, val);
-               if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
-                       int err;
-
-                       err = tg3_nvram_lock(tp);
-                       tg3_halt_cpu(tp, RX_CPU_BASE);
-                       if (!err)
-                               tg3_nvram_unlock(tp);
-               }
-       }
-
-       tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN);
-
-       /* Finally, set the new power state. */
-       pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control);
-       udelay(100);    /* Delay after power state change */
-
-       return 0;
-}
-
-/* tp->lock is held. */
-static void tg3_wait_for_event_ack(struct tg3 *tp)
-{
-       int i;
-
-       /* Wait for up to 2.5 milliseconds */
-       for (i = 0; i < 250000; i++) {
-               if (!(tr32(GRC_RX_CPU_EVENT) & GRC_RX_CPU_DRIVER_EVENT))
-                       break;
-               udelay(10);
-       }
-}
-
-/* tp->lock is held. */
-static void tg3_ump_link_report(struct tg3 *tp)
-{
-       u32 reg;
-       u32 val;
-
-       if (!(tp->tg3_flags2 & TG3_FLG2_5780_CLASS) ||
-           !(tp->tg3_flags  & TG3_FLAG_ENABLE_ASF))
-               return;
-
-       tg3_wait_for_event_ack(tp);
-
-       tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_LINK_UPDATE);
-
-       tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 14);
-
-       val = 0;
-       if (!tg3_readphy(tp, MII_BMCR, &reg))
-               val = reg << 16;
-       if (!tg3_readphy(tp, MII_BMSR, &reg))
-               val |= (reg & 0xffff);
-       tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, val);
-
-       val = 0;
-       if (!tg3_readphy(tp, MII_ADVERTISE, &reg))
-               val = reg << 16;
-       if (!tg3_readphy(tp, MII_LPA, &reg))
-               val |= (reg & 0xffff);
-       tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 4, val);
-
-       val = 0;
-       if (!(tp->tg3_flags2 & TG3_FLG2_MII_SERDES)) {
-               if (!tg3_readphy(tp, MII_CTRL1000, &reg))
-                       val = reg << 16;
-               if (!tg3_readphy(tp, MII_STAT1000, &reg))
-                       val |= (reg & 0xffff);
-       }
-       tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 8, val);
-
-       if (!tg3_readphy(tp, MII_PHYADDR, &reg))
-               val = reg << 16;
-       else
-               val = 0;
-       tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 12, val);
-
-       val = tr32(GRC_RX_CPU_EVENT);
-       val |= GRC_RX_CPU_DRIVER_EVENT;
-       tw32_f(GRC_RX_CPU_EVENT, val);
-}
-
-static void tg3_link_report(struct tg3 *tp)
-{
-       if (!netif_carrier_ok(tp->dev)) {
-               if (netif_msg_link(tp))
-                       printk(KERN_INFO PFX "%s: Link is down.\n",
-                              tp->dev->name);
-               tg3_ump_link_report(tp);
-       } else if (netif_msg_link(tp)) {
-               printk(KERN_INFO PFX "%s: Link is up at %d Mbps, %s duplex.\n",
-                      tp->dev->name,
-                      (tp->link_config.active_speed == SPEED_1000 ?
-                       1000 :
-                       (tp->link_config.active_speed == SPEED_100 ?
-                        100 : 10)),
-                      (tp->link_config.active_duplex == DUPLEX_FULL ?
-                       "full" : "half"));
-
-               printk(KERN_INFO PFX
-                      "%s: Flow control is %s for TX and %s for RX.\n",
-                      tp->dev->name,
-                      (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_TX) ?
-                      "on" : "off",
-                      (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX) ?
-                      "on" : "off");
-               tg3_ump_link_report(tp);
-       }
-}
-
-static u16 tg3_advert_flowctrl_1000T(u8 flow_ctrl)
-{
-       u16 miireg;
-
-       if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX))
-               miireg = ADVERTISE_PAUSE_CAP;
-       else if (flow_ctrl & TG3_FLOW_CTRL_TX)
-               miireg = ADVERTISE_PAUSE_ASYM;
-       else if (flow_ctrl & TG3_FLOW_CTRL_RX)
-               miireg = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
-       else
-               miireg = 0;
-
-       return miireg;
-}
-
-static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl)
-{
-       u16 miireg;
-
-       if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX))
-               miireg = ADVERTISE_1000XPAUSE;
-       else if (flow_ctrl & TG3_FLOW_CTRL_TX)
-               miireg = ADVERTISE_1000XPSE_ASYM;
-       else if (flow_ctrl & TG3_FLOW_CTRL_RX)
-               miireg = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
-       else
-               miireg = 0;
-
-       return miireg;
-}
-
-static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv)
-{
-       u8 cap = 0;
-
-       if (lcladv & ADVERTISE_PAUSE_CAP) {
-               if (lcladv & ADVERTISE_PAUSE_ASYM) {
-                       if (rmtadv & LPA_PAUSE_CAP)
-                               cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
-                       else if (rmtadv & LPA_PAUSE_ASYM)
-                               cap = TG3_FLOW_CTRL_RX;
+               } else if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
+                       newbits1 = CLOCK_CTRL_625_CORE;
+                       newbits2 = newbits1 | CLOCK_CTRL_ALTCLK;
                } else {
-                       if (rmtadv & LPA_PAUSE_CAP)
-                               cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+                       newbits1 = CLOCK_CTRL_ALTCLK;
+                       newbits2 = newbits1 | CLOCK_CTRL_44MHZ_CORE;
                }
-       } else if (lcladv & ADVERTISE_PAUSE_ASYM) {
-               if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM))
-                       cap = TG3_FLOW_CTRL_TX;
-       }
 
-       return cap;
-}
+               tw32_wait_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl | newbits1,
+                           40);
 
-static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv)
-{
-       u8 cap = 0;
+               tw32_wait_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl | newbits2,
+                           40);
 
-       if (lcladv & ADVERTISE_1000XPAUSE) {
-               if (lcladv & ADVERTISE_1000XPSE_ASYM) {
-                       if (rmtadv & LPA_1000XPAUSE)
-                               cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
-                       else if (rmtadv & LPA_1000XPAUSE_ASYM)
-                               cap = TG3_FLOW_CTRL_RX;
-               } else {
-                       if (rmtadv & LPA_1000XPAUSE)
-                               cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+               if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
+                       u32 newbits3;
+
+                       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+                           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
+                               newbits3 = (CLOCK_CTRL_RXCLK_DISABLE |
+                                           CLOCK_CTRL_TXCLK_DISABLE |
+                                           CLOCK_CTRL_44MHZ_CORE);
+                       } else {
+                               newbits3 = CLOCK_CTRL_44MHZ_CORE;
+                       }
+
+                       tw32_wait_f(TG3PCI_CLOCK_CTRL,
+                                   tp->pci_clock_ctrl | newbits3, 40);
                }
-       } else if (lcladv & ADVERTISE_1000XPSE_ASYM) {
-               if ((rmtadv & LPA_1000XPAUSE) && (rmtadv & LPA_1000XPAUSE_ASYM))
-                       cap = TG3_FLOW_CTRL_TX;
        }
 
-       return cap;
-}
-
-static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv)
-{
-       u8 new_tg3_flags = 0;
-       u32 old_rx_mode = tp->rx_mode;
-       u32 old_tx_mode = tp->tx_mode;
+       if (!(tp->tg3_flags & TG3_FLAG_WOL_ENABLE) &&
+           !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
+           !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
+               tg3_power_down_phy(tp);
 
-       if (tp->link_config.autoneg == AUTONEG_ENABLE &&
-           (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) {
-               if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)
-                       new_tg3_flags = tg3_resolve_flowctrl_1000X(local_adv,
-                                                                  remote_adv);
-               else
-                       new_tg3_flags = tg3_resolve_flowctrl_1000T(local_adv,
-                                                                  remote_adv);
-       } else {
-               new_tg3_flags = tp->link_config.flowctrl;
-       }
+       tg3_frob_aux_power(tp);
 
-       tp->link_config.active_flowctrl = new_tg3_flags;
+       /* Workaround for unstable PLL clock */
+       if ((GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX) ||
+           (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_BX)) {
+               u32 val = tr32(0x7d00);
 
-       if (new_tg3_flags & TG3_FLOW_CTRL_RX)
-               tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE;
-       else
-               tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE;
+               val &= ~((1 << 16) | (1 << 4) | (1 << 2) | (1 << 1) | 1);
+               tw32(0x7d00, val);
+               if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
+                       int err;
 
-       if (old_rx_mode != tp->rx_mode) {
-               tw32_f(MAC_RX_MODE, tp->rx_mode);
+                       err = tg3_nvram_lock(tp);
+                       tg3_halt_cpu(tp, RX_CPU_BASE);
+                       if (!err)
+                               tg3_nvram_unlock(tp);
+               }
        }
 
-       if (new_tg3_flags & TG3_FLOW_CTRL_TX)
-               tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE;
-       else
-               tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE;
+       tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN);
 
-       if (old_tx_mode != tp->tx_mode) {
-               tw32_f(MAC_TX_MODE, tp->tx_mode);
-       }
+       /* Finally, set the new power state. */
+       pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control);
+       udelay(100);    /* Delay after power state change */
+
+       return 0;
 }
 
 static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8 *duplex)
@@ -1921,7 +2287,7 @@ static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8
                *speed = SPEED_INVALID;
                *duplex = DUPLEX_INVALID;
                break;
-       };
+       }
 }
 
 static void tg3_phy_copper_begin(struct tg3 *tp)
@@ -2033,7 +2399,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
                case SPEED_1000:
                        bmcr |= TG3_BMCR_SPEED1000;
                        break;
-               };
+               }
 
                if (tp->link_config.duplex == DUPLEX_FULL)
                        bmcr |= BMCR_FULLDPLX;
@@ -2731,7 +3097,7 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
        default:
                ret = ANEG_FAILED;
                break;
-       };
+       }
 
        return ret;
 }
@@ -3572,7 +3938,7 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key,
 
        default:
                return -EINVAL;
-       };
+       }
 
        /* Do not overwrite any of the map or rp information
         * until we are sure we can commit to a new buffer.
@@ -3632,7 +3998,7 @@ static void tg3_recycle_rx(struct tg3 *tp, u32 opaque_key,
 
        default:
                return;
-       };
+       }
 
        dest_map->skb = src_map->skb;
        pci_unmap_addr_set(dest_map, mapping,
@@ -3842,7 +4208,15 @@ static int tg3_poll_work(struct tg3 *tp, int work_done, int budget)
                        sblk->status = SD_STATUS_UPDATED |
                                (sblk->status & ~SD_STATUS_LINK_CHG);
                        spin_lock(&tp->lock);
-                       tg3_setup_phy(tp, 0);
+                       if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+                               tw32_f(MAC_STATUS,
+                                    (MAC_STATUS_SYNC_CHANGED |
+                                     MAC_STATUS_CFG_CHANGED |
+                                     MAC_STATUS_MI_COMPLETION |
+                                     MAC_STATUS_LNKSTATE_CHANGED));
+                               udelay(40);
+                       } else
+                               tg3_setup_phy(tp, 0);
                        spin_unlock(&tp->lock);
                }
        }
@@ -4130,6 +4504,7 @@ static void tg3_poll_controller(struct net_device *dev)
 static void tg3_reset_task(struct work_struct *work)
 {
        struct tg3 *tp = container_of(work, struct tg3, reset_task);
+       int err;
        unsigned int restart_timer;
 
        tg3_full_lock(tp, 0);
@@ -4141,6 +4516,8 @@ static void tg3_reset_task(struct work_struct *work)
 
        tg3_full_unlock(tp);
 
+       tg3_phy_stop(tp);
+
        tg3_netif_stop(tp);
 
        tg3_full_lock(tp, 1);
@@ -4156,7 +4533,8 @@ static void tg3_reset_task(struct work_struct *work)
        }
 
        tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
-       if (tg3_init_hw(tp, 1))
+       err = tg3_init_hw(tp, 1);
+       if (err)
                goto out;
 
        tg3_netif_start(tp);
@@ -4166,6 +4544,9 @@ static void tg3_reset_task(struct work_struct *work)
 
 out:
        tg3_full_unlock(tp);
+
+       if (!err)
+               tg3_phy_start(tp);
 }
 
 static void tg3_dump_short_state(struct tg3 *tp)
@@ -4669,6 +5050,8 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
                return 0;
        }
 
+       tg3_phy_stop(tp);
+
        tg3_netif_stop(tp);
 
        tg3_full_lock(tp, 1);
@@ -4684,6 +5067,9 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
 
        tg3_full_unlock(tp);
 
+       if (!err)
+               tg3_phy_start(tp);
+
        return err;
 }
 
@@ -4975,7 +5361,7 @@ static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit, int
 
                default:
                        break;
-               };
+               }
        }
 
        val = tr32(ofs);
@@ -5217,7 +5603,7 @@ static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind)
 
                default:
                        break;
-               };
+               }
        }
 
        if (kind == RESET_KIND_INIT ||
@@ -5242,7 +5628,7 @@ static void tg3_write_sig_post_reset(struct tg3 *tp, int kind)
 
                default:
                        break;
-               };
+               }
        }
 
        if (kind == RESET_KIND_SHUTDOWN)
@@ -5271,7 +5657,7 @@ static void tg3_write_sig_legacy(struct tg3 *tp, int kind)
 
                default:
                        break;
-               };
+               }
        }
 }
 
@@ -5393,6 +5779,8 @@ static int tg3_chip_reset(struct tg3 *tp)
 
        tg3_nvram_lock(tp);
 
+       tg3_mdio_stop(tp);
+
        /* No matching tg3_nvram_unlock() after this because
         * chip reset below will undo the nvram lock.
         */
@@ -5408,7 +5796,8 @@ static int tg3_chip_reset(struct tg3 *tp)
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
                tw32(GRC_FASTBOOT_PC, 0);
 
        /*
@@ -5544,6 +5933,8 @@ static int tg3_chip_reset(struct tg3 *tp)
                tw32_f(MAC_MODE, 0);
        udelay(40);
 
+       tg3_mdio_start(tp);
+
        err = tg3_poll_fw(tp);
        if (err)
                return err;
@@ -6623,7 +7014,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                tg3_abort_hw(tp, 1);
        }
 
-       if (reset_phy)
+       if (reset_phy &&
+           !(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB))
                tg3_phy_reset(tp);
 
        err = tg3_chip_reset(tp);
@@ -6699,7 +7091,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                return err;
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) {
+           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761 &&
+           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) {
                /* This value is determined during the probe time DMA
                 * engine test, tg3_test_dma.
                 */
@@ -6938,7 +7331,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                      RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
                      RDMAC_MODE_LNGREAD_ENAB);
 
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784)
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
                rdmac_mode |= RDMAC_MODE_BD_SBD_CRPT_ENAB |
                              RDMAC_MODE_MBUF_RBD_CRPT_ENAB |
                              RDMAC_MODE_MBUF_SBD_CRPT_ENAB;
@@ -7106,8 +7500,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
        if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) ||
            (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) ||
            (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) ||
-           (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761))
-               val |= (1 << 29);
+           (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) ||
+           (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785))
+               val |= WDMAC_MODE_STATUS_TAG_FIX;
 
        tw32_f(WDMAC_MODE, val);
        udelay(40);
@@ -7168,23 +7563,14 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
 
        tp->rx_mode = RX_MODE_ENABLE;
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
                tp->rx_mode |= RX_MODE_IPV6_CSUM_ENABLE;
 
        tw32_f(MAC_RX_MODE, tp->rx_mode);
        udelay(10);
 
-       if (tp->link_config.phy_is_low_power) {
-               tp->link_config.phy_is_low_power = 0;
-               tp->link_config.speed = tp->link_config.orig_speed;
-               tp->link_config.duplex = tp->link_config.orig_duplex;
-               tp->link_config.autoneg = tp->link_config.orig_autoneg;
-       }
-
-       tp->mi_mode &= ~MAC_MI_MODE_AUTO_POLL;
-       tw32_f(MAC_MI_MODE, tp->mi_mode);
-       udelay(80);
-
        tw32(MAC_LED_CTRL, tp->led_ctrl);
 
        tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB);
@@ -7231,19 +7617,28 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
        }
 
-       err = tg3_setup_phy(tp, 0);
-       if (err)
-               return err;
+       if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) {
+               if (tp->link_config.phy_is_low_power) {
+                       tp->link_config.phy_is_low_power = 0;
+                       tp->link_config.speed = tp->link_config.orig_speed;
+                       tp->link_config.duplex = tp->link_config.orig_duplex;
+                       tp->link_config.autoneg = tp->link_config.orig_autoneg;
+               }
 
-       if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) {
-               u32 tmp;
+               err = tg3_setup_phy(tp, 0);
+               if (err)
+                       return err;
 
-               /* Clear CRC stats. */
-               if (!tg3_readphy(tp, MII_TG3_TEST1, &tmp)) {
-                       tg3_writephy(tp, MII_TG3_TEST1,
-                                    tmp | MII_TG3_TEST1_CRC_EN);
-                       tg3_readphy(tp, 0x14, &tmp);
+               if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
+                   GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) {
+                       u32 tmp;
+
+                       /* Clear CRC stats. */
+                       if (!tg3_readphy(tp, MII_TG3_TEST1, &tmp)) {
+                               tg3_writephy(tp, MII_TG3_TEST1,
+                                            tmp | MII_TG3_TEST1_CRC_EN);
+                               tg3_readphy(tp, 0x14, &tmp);
+                       }
                }
        }
 
@@ -7296,7 +7691,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
 
        default:
                break;
-       };
+       }
 
        if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
                /* Write our heartbeat update interval to APE. */
@@ -7758,6 +8153,8 @@ static int tg3_open(struct net_device *dev)
                }
        }
 
+       tg3_phy_start(tp);
+
        tg3_full_lock(tp, 0);
 
        add_timer(&tp->timer);
@@ -8559,7 +8956,13 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 
 static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-       struct tg3 *tp = netdev_priv(dev);
+       struct tg3 *tp = netdev_priv(dev);
+
+       if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+               if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+                       return -EAGAIN;
+               return phy_ethtool_gset(tp->mdio_bus.phy_map[PHY_ADDR], cmd);
+       }
 
        cmd->supported = (SUPPORTED_Autoneg);
 
@@ -8596,6 +8999,12 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
        struct tg3 *tp = netdev_priv(dev);
 
+       if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+               if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+                       return -EAGAIN;
+               return phy_ethtool_sset(tp->mdio_bus.phy_map[PHY_ADDR], cmd);
+       }
+
        if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) {
                /* These are the only valid advertisement bits allowed.  */
                if (cmd->autoneg == AUTONEG_ENABLE &&
@@ -8628,7 +9037,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                tp->link_config.advertising = 0;
                tp->link_config.speed = cmd->speed;
                tp->link_config.duplex = cmd->duplex;
-       }
+       }
 
        tp->link_config.orig_speed = tp->link_config.speed;
        tp->link_config.orig_duplex = tp->link_config.duplex;
@@ -8711,7 +9120,10 @@ static int tg3_set_tso(struct net_device *dev, u32 value)
            (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) {
                if (value) {
                        dev->features |= NETIF_F_TSO6;
-                       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+                       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+                           (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
+                            GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) ||
+                           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
                                dev->features |= NETIF_F_TSO_ECN;
                } else
                        dev->features &= ~(NETIF_F_TSO6 | NETIF_F_TSO_ECN);
@@ -8722,7 +9134,6 @@ static int tg3_set_tso(struct net_device *dev, u32 value)
 static int tg3_nway_reset(struct net_device *dev)
 {
        struct tg3 *tp = netdev_priv(dev);
-       u32 bmcr;
        int r;
 
        if (!netif_running(dev))
@@ -8731,17 +9142,25 @@ static int tg3_nway_reset(struct net_device *dev)
        if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
                return -EINVAL;
 
-       spin_lock_bh(&tp->lock);
-       r = -EINVAL;
-       tg3_readphy(tp, MII_BMCR, &bmcr);
-       if (!tg3_readphy(tp, MII_BMCR, &bmcr) &&
-           ((bmcr & BMCR_ANENABLE) ||
-            (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT))) {
-               tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART |
-                                          BMCR_ANENABLE);
-               r = 0;
+       if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+               if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+                       return -EAGAIN;
+               r = phy_start_aneg(tp->mdio_bus.phy_map[PHY_ADDR]);
+       } else {
+               u32 bmcr;
+
+               spin_lock_bh(&tp->lock);
+               r = -EINVAL;
+               tg3_readphy(tp, MII_BMCR, &bmcr);
+               if (!tg3_readphy(tp, MII_BMCR, &bmcr) &&
+                   ((bmcr & BMCR_ANENABLE) ||
+                    (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT))) {
+                       tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART |
+                                                  BMCR_ANENABLE);
+                       r = 0;
+               }
+               spin_unlock_bh(&tp->lock);
        }
-       spin_unlock_bh(&tp->lock);
 
        return r;
 }
@@ -8783,6 +9202,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
                return -EINVAL;
 
        if (netif_running(dev)) {
+               tg3_phy_stop(tp);
                tg3_netif_stop(tp);
                irq_sync = 1;
        }
@@ -8806,6 +9226,9 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
 
        tg3_full_unlock(tp);
 
+       if (irq_sync && !err)
+               tg3_phy_start(tp);
+
        return err;
 }
 
@@ -8829,36 +9252,92 @@ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam
 static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
 {
        struct tg3 *tp = netdev_priv(dev);
-       int irq_sync = 0, err = 0;
+       int err = 0;
 
-       if (netif_running(dev)) {
-               tg3_netif_stop(tp);
-               irq_sync = 1;
-       }
+       if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+               if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+                       return -EAGAIN;
 
-       tg3_full_lock(tp, irq_sync);
+               if (epause->autoneg) {
+                       u32 newadv;
+                       struct phy_device *phydev;
 
-       if (epause->autoneg)
-               tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
-       else
-               tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG;
-       if (epause->rx_pause)
-               tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX;
-       else
-               tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX;
-       if (epause->tx_pause)
-               tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX;
-       else
-               tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX;
+                       phydev = tp->mdio_bus.phy_map[PHY_ADDR];
 
-       if (netif_running(dev)) {
-               tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
-               err = tg3_restart_hw(tp, 1);
-               if (!err)
-                       tg3_netif_start(tp);
-       }
+                       if (epause->rx_pause) {
+                               if (epause->tx_pause)
+                                       newadv = ADVERTISED_Pause;
+                               else
+                                       newadv = ADVERTISED_Pause |
+                                                ADVERTISED_Asym_Pause;
+                       } else if (epause->tx_pause) {
+                               newadv = ADVERTISED_Asym_Pause;
+                       } else
+                               newadv = 0;
+
+                       if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) {
+                               u32 oldadv = phydev->advertising &
+                                            (ADVERTISED_Pause |
+                                             ADVERTISED_Asym_Pause);
+                               if (oldadv != newadv) {
+                                       phydev->advertising &=
+                                               ~(ADVERTISED_Pause |
+                                                 ADVERTISED_Asym_Pause);
+                                       phydev->advertising |= newadv;
+                                       err = phy_start_aneg(phydev);
+                               }
+                       } else {
+                               tp->link_config.advertising &=
+                                               ~(ADVERTISED_Pause |
+                                                 ADVERTISED_Asym_Pause);
+                               tp->link_config.advertising |= newadv;
+                       }
+               } else {
+                       if (epause->rx_pause)
+                               tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX;
+                       else
+                               tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX;
 
-       tg3_full_unlock(tp);
+                       if (epause->tx_pause)
+                               tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX;
+                       else
+                               tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX;
+
+                       if (netif_running(dev))
+                               tg3_setup_flow_control(tp, 0, 0);
+               }
+       } else {
+               int irq_sync = 0;
+
+               if (netif_running(dev)) {
+                       tg3_netif_stop(tp);
+                       irq_sync = 1;
+               }
+
+               tg3_full_lock(tp, irq_sync);
+
+               if (epause->autoneg)
+                       tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
+               else
+                       tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG;
+               if (epause->rx_pause)
+                       tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX;
+               else
+                       tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX;
+               if (epause->tx_pause)
+                       tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX;
+               else
+                       tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX;
+
+               if (netif_running(dev)) {
+                       tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
+                       err = tg3_restart_hw(tp, 1);
+                       if (!err)
+                               tg3_netif_start(tp);
+               }
+
+               tg3_full_unlock(tp);
+       }
 
        return err;
 }
@@ -8902,7 +9381,8 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data)
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
                ethtool_op_set_tx_ipv6_csum(dev, data);
        else
                ethtool_op_set_tx_csum(dev, data);
@@ -9423,7 +9903,8 @@ static int tg3_test_memory(struct tg3 *tp)
                if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
                    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
                    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
                        mem_tbl = mem_tbl_5755;
                else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
                        mem_tbl = mem_tbl_5906;
@@ -9630,7 +10111,8 @@ static int tg3_test_loopback(struct tg3 *tp)
                return TG3_LOOPBACK_FAILED;
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) {
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
                int i;
                u32 status;
 
@@ -9658,14 +10140,16 @@ static int tg3_test_loopback(struct tg3 *tp)
                err |= TG3_MAC_LOOPBACK_FAILED;
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) {
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
                tw32(TG3_CPMU_CTRL, cpmuctrl);
 
                /* Release the mutex */
                tw32(TG3_CPMU_MUTEX_GNT, CPMU_MUTEX_GNT_DRIVER);
        }
 
-       if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
+       if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
+           !(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) {
                if (tg3_run_loopback(tp, TG3_PHY_LOOPBACK))
                        err |= TG3_PHY_LOOPBACK_FAILED;
        }
@@ -9692,9 +10176,10 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
                data[1] = 1;
        }
        if (etest->flags & ETH_TEST_FL_OFFLINE) {
-               int err, irq_sync = 0;
+               int err, err2 = 0, irq_sync = 0;
 
                if (netif_running(dev)) {
+                       tg3_phy_stop(tp);
                        tg3_netif_stop(tp);
                        irq_sync = 1;
                }
@@ -9735,11 +10220,15 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
                tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
                if (netif_running(dev)) {
                        tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
-                       if (!tg3_restart_hw(tp, 1))
+                       err2 = tg3_restart_hw(tp, 1);
+                       if (!err2)
                                tg3_netif_start(tp);
                }
 
                tg3_full_unlock(tp);
+
+               if (irq_sync && !err2)
+                       tg3_phy_start(tp);
        }
        if (tp->link_config.phy_is_low_power)
                tg3_set_power_state(tp, PCI_D3hot);
@@ -9752,6 +10241,12 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        struct tg3 *tp = netdev_priv(dev);
        int err;
 
+       if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+               if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+                       return -EAGAIN;
+               return phy_mii_ioctl(tp->mdio_bus.phy_map[PHY_ADDR], data, cmd);
+       }
+
        switch(cmd) {
        case SIOCGMIIPHY:
                data->phy_id = PHY_ADDR;
@@ -10294,7 +10789,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp)
                else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
                        tg3_get_5755_nvram_info(tp);
                else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
-                        GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784)
+                        GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+                        GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
                        tg3_get_5787_nvram_info(tp);
                else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
                        tg3_get_5761_nvram_info(tp);
@@ -10625,6 +11121,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len,
                    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) &&
                    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784) &&
                    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) &&
+                   (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) &&
                    (tp->nvram_jedecnum == JEDEC_ST) &&
                    (nvram_cmd & NVRAM_CMD_FIRST)) {
 
@@ -10807,7 +11304,7 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
        tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val);
        if (val == NIC_SRAM_DATA_SIG_MAGIC) {
                u32 nic_cfg, led_cfg;
-               u32 nic_phy_id, ver, cfg2 = 0, eeprom_phy_id;
+               u32 nic_phy_id, ver, cfg2 = 0, cfg4 = 0, eeprom_phy_id;
                int eeprom_phy_serdes = 0;
 
                tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg);
@@ -10821,6 +11318,9 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
                    (ver > 0) && (ver < 0x100))
                        tg3_read_mem(tp, NIC_SRAM_DATA_CFG_2, &cfg2);
 
+               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+                       tg3_read_mem(tp, NIC_SRAM_DATA_CFG_4, &cfg4);
+
                if ((nic_cfg & NIC_SRAM_DATA_CFG_PHY_TYPE_MASK) ==
                    NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER)
                        eeprom_phy_serdes = 1;
@@ -10893,7 +11393,7 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
                                                 LED_CTRL_MODE_PHY_2);
                        break;
 
-               };
+               }
 
                if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
                     GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) &&
@@ -10945,6 +11445,13 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
                        if (cfg3 & NIC_SRAM_ASPM_DEBOUNCE)
                                tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND;
                }
+
+               if (cfg4 & NIC_SRAM_RGMII_STD_IBND_DISABLE)
+                       tp->tg3_flags3 |= TG3_FLG3_RGMII_STD_IBND_DISABLE;
+               if (cfg4 & NIC_SRAM_RGMII_EXT_IBND_RX_EN)
+                       tp->tg3_flags3 |= TG3_FLG3_RGMII_EXT_IBND_RX_EN;
+               if (cfg4 & NIC_SRAM_RGMII_EXT_IBND_TX_EN)
+                       tp->tg3_flags3 |= TG3_FLG3_RGMII_EXT_IBND_TX_EN;
        }
 }
 
@@ -11003,6 +11510,9 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
        u32 hw_phy_id, hw_phy_id_masked;
        int err;
 
+       if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)
+               return tg3_phy_init(tp);
+
        /* Reading the PHY ID register can conflict with ASF
         * firwmare access to the PHY hardware.
         */
@@ -11525,6 +12035,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 ||
            (tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
                tp->tg3_flags2 |= TG3_FLG2_5750_PLUS;
@@ -11546,6 +12057,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
                    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
                    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
                    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
                        tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2;
                        tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI;
@@ -11558,14 +12070,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                }
        }
 
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755 &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787 &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761 &&
-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
+       if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
+            (tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
                tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE;
 
        pcie_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_EXP);
@@ -11754,7 +12260,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        }
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) {
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
                tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT;
 
                if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 ||
@@ -11847,7 +12354,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                                tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG;
                        if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5755M)
                                tp->tg3_flags2 |= TG3_FLG2_PHY_ADJUST_TRIM;
-               } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
+               } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906 &&
+                          GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785)
                        tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG;
        }
 
@@ -11858,8 +12366,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                        tp->phy_otp = TG3_OTP_DEFAULT;
        }
 
-       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+       if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT)
                tp->mi_mode = MAC_MI_MODE_500KHZ_CONST;
        else
                tp->mi_mode = MAC_MI_MODE_BASE;
@@ -11869,9 +12376,12 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
            GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX)
                tp->coalesce_mode |= HOSTCC_MODE_32BYTE;
 
-       /* Initialize MAC MI mode, polling disabled. */
-       tw32_f(MAC_MI_MODE, tp->mi_mode);
-       udelay(80);
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+               tp->tg3_flags3 |= TG3_FLG3_USE_PHYLIB;
+
+       err = tg3_mdio_init(tp);
+       if (err)
+               return err;
 
        /* Initialize data/descriptor byte/word swapping. */
        val = tr32(GRC_MODE);
@@ -11952,6 +12462,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                printk(KERN_ERR PFX "(%s) phy probe failed, err %d\n",
                       pci_name(tp->pdev), err);
                /* ... but do not return immediately ... */
+               tg3_mdio_fini(tp);
        }
 
        tg3_read_partno(tp);
@@ -11999,6 +12510,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
                tp->dev->hard_start_xmit = tg3_start_xmit;
        else
@@ -12201,7 +12713,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val)
                        val |= (DMA_RWCTRL_READ_BNDRY_384_PCIX |
                                DMA_RWCTRL_WRITE_BNDRY_384_PCIX);
                        break;
-               };
+               }
        } else if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
                switch (cacheline_size) {
                case 16:
@@ -12218,7 +12730,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val)
                        val &= ~DMA_RWCTRL_WRITE_BNDRY_DISAB_PCIE;
                        val |= DMA_RWCTRL_WRITE_BNDRY_128_PCIE;
                        break;
-               };
+               }
        } else {
                switch (cacheline_size) {
                case 16:
@@ -12262,7 +12774,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val)
                        val |= (DMA_RWCTRL_READ_BNDRY_1024 |
                                DMA_RWCTRL_WRITE_BNDRY_1024);
                        break;
-               };
+               }
        }
 
 out:
@@ -12622,7 +13134,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp)
        case PHY_ID_BCM8002:    return "8002/serdes";
        case 0:                 return "serdes";
        default:                return "unknown";
-       };
+       }
 }
 
 static char * __devinit tg3_bus_string(struct tg3 *tp, char *str)
@@ -12923,7 +13435,10 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
                if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) &&
                    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906))
                        dev->features |= NETIF_F_TSO6;
-               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+                   (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
+                    GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) ||
+                       GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
                        dev->features |= NETIF_F_TSO_ECN;
        }
 
@@ -12989,7 +13504,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
                if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
                    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
                    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
-                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+                   GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
                        dev->features |= NETIF_F_IPV6_CSUM;
 
                tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
@@ -13071,6 +13587,12 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
                struct tg3 *tp = netdev_priv(dev);
 
                flush_scheduled_work();
+
+               if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+                       tg3_phy_fini(tp);
+                       tg3_mdio_fini(tp);
+               }
+
                unregister_netdev(dev);
                if (tp->aperegs) {
                        iounmap(tp->aperegs);
@@ -13103,6 +13625,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
                return 0;
 
        flush_scheduled_work();
+       tg3_phy_stop(tp);
        tg3_netif_stop(tp);
 
        del_timer_sync(&tp->timer);
@@ -13120,10 +13643,13 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
 
        err = tg3_set_power_state(tp, pci_choose_state(pdev, state));
        if (err) {
+               int err2;
+
                tg3_full_lock(tp, 0);
 
                tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
-               if (tg3_restart_hw(tp, 1))
+               err2 = tg3_restart_hw(tp, 1);
+               if (err2)
                        goto out;
 
                tp->timer.expires = jiffies + tp->timer_offset;
@@ -13134,6 +13660,9 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
 
 out:
                tg3_full_unlock(tp);
+
+               if (!err2)
+                       tg3_phy_start(tp);
        }
 
        return err;
@@ -13171,6 +13700,9 @@ static int tg3_resume(struct pci_dev *pdev)
 out:
        tg3_full_unlock(tp);
 
+       if (!err)
+               tg3_phy_start(tp);
+
        return err;
 }
 
index 0404f93baa290c77a7b39c55754ccd23ace126fa..df07842172b7dff8c479d9795bc39afb6c87f5a6 100644 (file)
 #define   ASIC_REV_USE_PROD_ID_REG      0x0f
 #define   ASIC_REV_5784                         0x5784
 #define   ASIC_REV_5761                         0x5761
+#define   ASIC_REV_5785                         0x5785
 #define  GET_CHIP_REV(CHIP_REV_ID)     ((CHIP_REV_ID) >> 8)
 #define   CHIPREV_5700_AX               0x70
 #define   CHIPREV_5700_BX               0x71
 #define MAC_SERDES_CFG                 0x00000590
 #define  MAC_SERDES_CFG_EDGE_SELECT     0x00001000
 #define MAC_SERDES_STAT                        0x00000594
-/* 0x598 --> 0x5b0 unused */
+/* 0x598 --> 0x5a0 unused */
+#define MAC_PHYCFG1                    0x000005a0
+#define  MAC_PHYCFG1_RGMII_INT          0x00000001
+#define  MAC_PHYCFG1_RGMII_EXT_RX_DEC   0x02000000
+#define  MAC_PHYCFG1_RGMII_SND_STAT_EN  0x04000000
+#define  MAC_PHYCFG1_TXC_DRV            0x20000000
+#define MAC_PHYCFG2                    0x000005a4
+#define  MAC_PHYCFG2_INBAND_ENABLE      0x00000001
+#define MAC_EXT_RGMII_MODE             0x000005a8
+#define  MAC_RGMII_MODE_TX_ENABLE       0x00000001
+#define  MAC_RGMII_MODE_TX_LOWPWR       0x00000002
+#define  MAC_RGMII_MODE_TX_RESET        0x00000004
+#define  MAC_RGMII_MODE_RX_INT_B        0x00000100
+#define  MAC_RGMII_MODE_RX_QUALITY      0x00000200
+#define  MAC_RGMII_MODE_RX_ACTIVITY     0x00000400
+#define  MAC_RGMII_MODE_RX_ENG_DET      0x00000800
+/* 0x5ac --> 0x5b0 unused */
 #define SERDES_RX_CTRL                 0x000005b0      /* 5780/5714 only */
 #define  SERDES_RX_SIG_DETECT           0x00000400
 #define SG_DIG_CTRL                    0x000005b0
 #define  WDMAC_MODE_FIFOOREAD_ENAB      0x00000100
 #define  WDMAC_MODE_LNGREAD_ENAB        0x00000200
 #define  WDMAC_MODE_RX_ACCEL            0x00000400
+#define  WDMAC_MODE_STATUS_TAG_FIX      0x20000000
 #define WDMAC_STATUS                   0x00004c04
 #define  WDMAC_STATUS_TGTABORT          0x00000004
 #define  WDMAC_STATUS_MSTABORT          0x00000008
 #define NIC_SRAM_DATA_CFG_3            0x00000d3c
 #define  NIC_SRAM_ASPM_DEBOUNCE                 0x00000002
 
+#define NIC_SRAM_DATA_CFG_4            0x00000d60
+#define  NIC_SRAM_GMII_MODE             0x00000002
+#define  NIC_SRAM_RGMII_STD_IBND_DISABLE 0x00000004
+#define  NIC_SRAM_RGMII_EXT_IBND_RX_EN  0x00000008
+#define  NIC_SRAM_RGMII_EXT_IBND_TX_EN  0x00000010
+
 #define NIC_SRAM_RX_MINI_BUFFER_DESC   0x00001000
 
 #define NIC_SRAM_DMA_DESC_POOL_BASE    0x00002000
@@ -2204,6 +2228,7 @@ struct tg3_link_config {
        u16                             orig_speed;
        u8                              orig_duplex;
        u8                              orig_autoneg;
+       u32                             orig_advertising;
 };
 
 struct tg3_bufmgr_config {
@@ -2479,6 +2504,13 @@ struct tg3 {
 #define TG3_FLG3_ENABLE_APE            0x00000002
 #define TG3_FLG3_5761_5784_AX_FIXES    0x00000004
 #define TG3_FLG3_5701_DMA_BUG          0x00000008
+#define TG3_FLG3_USE_PHYLIB            0x00000010
+#define TG3_FLG3_MDIOBUS_INITED                0x00000020
+#define TG3_FLG3_MDIOBUS_PAUSED                0x00000040
+#define TG3_FLG3_PHY_CONNECTED         0x00000080
+#define TG3_FLG3_RGMII_STD_IBND_DISABLE        0x00000100
+#define TG3_FLG3_RGMII_EXT_IBND_RX_EN  0x00000200
+#define TG3_FLG3_RGMII_EXT_IBND_TX_EN  0x00000400
 
        struct timer_list               timer;
        u16                             timer_counter;
@@ -2519,6 +2551,9 @@ struct tg3 {
        int                             msi_cap;
        int                             pcix_cap;
 
+       struct mii_bus                  mdio_bus;
+       int                             mdio_irq[PHY_MAX_ADDR];
+
        /* PHY info */
        u32                             phy_id;
 #define PHY_ID_MASK                    0xfffffff0
@@ -2546,6 +2581,9 @@ struct tg3 {
 #define PHY_REV_BCM5401_B2             0x3
 #define PHY_REV_BCM5401_C0             0x6
 #define PHY_REV_BCM5411_X0             0x1 /* Found on Netgear GA302T */
+#define TG3_PHY_ID_BCM50610            0x143bd60
+#define TG3_PHY_ID_BCMAC131            0x143bc70
+
 
        u32                             led_ctrl;
        u32                             phy_otp;
index 0166407d7061b417f9d4276dfea49b15043ee39a..85246ed7cb9c4059307ab5807a2178c0e031f515 100644 (file)
@@ -13,8 +13,6 @@
  *  This software may be used and distributed according to the terms
  *  of the GNU General Public License, incorporated herein by reference.
  *
- ** This file is best viewed/edited with columns>=132.
- *
  ** Useful (if not required) reading:
  *
  *             Texas Instruments, ThunderLAN Programmer's Guide,
@@ -218,9 +216,7 @@ static      int             bbuf;
 module_param(bbuf, int, 0);
 MODULE_PARM_DESC(bbuf, "ThunderLAN use big buffer (0-1)");
 
-static u8              *TLanPadBuffer;
-static  dma_addr_t     TLanPadBufferDMA;
-static char            TLanSignature[] = "TLAN";
+static const char TLanSignature[] = "TLAN";
 static  const char tlan_banner[] = "ThunderLAN driver v1.15\n";
 static  int tlan_have_pci;
 static  int tlan_have_eisa;
@@ -238,9 +234,11 @@ static struct board {
        { "Compaq Netelligent 10 T PCI UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 },
        { "Compaq Netelligent 10/100 TX PCI UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 },
        { "Compaq Integrated NetFlex-3/P", TLAN_ADAPTER_NONE, 0x83 },
-       { "Compaq NetFlex-3/P", TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 },
+       { "Compaq NetFlex-3/P",
+         TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 },
        { "Compaq NetFlex-3/P", TLAN_ADAPTER_NONE, 0x83 },
-       { "Compaq Netelligent Integrated 10/100 TX UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 },
+       { "Compaq Netelligent Integrated 10/100 TX UTP",
+         TLAN_ADAPTER_ACTIVITY_LED, 0x83 },
        { "Compaq Netelligent Dual 10/100 TX PCI UTP", TLAN_ADAPTER_NONE, 0x83 },
        { "Compaq Netelligent 10/100 TX Embedded UTP", TLAN_ADAPTER_NONE, 0x83 },
        { "Olicom OC-2183/2185", TLAN_ADAPTER_USE_INTERN_10, 0x83 },
@@ -248,8 +246,9 @@ static struct board {
        { "Olicom OC-2326", TLAN_ADAPTER_USE_INTERN_10, 0xF8 },
        { "Compaq Netelligent 10/100 TX UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 },
        { "Compaq Netelligent 10 T/2 PCI UTP/Coax", TLAN_ADAPTER_NONE, 0x83 },
-       { "Compaq NetFlex-3/E", TLAN_ADAPTER_ACTIVITY_LED |     /* EISA card */
-                               TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 },
+       { "Compaq NetFlex-3/E",
+         TLAN_ADAPTER_ACTIVITY_LED |   /* EISA card */
+         TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 },
        { "Compaq NetFlex-3/E", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, /* EISA card */
 };
 
@@ -294,12 +293,12 @@ static int        TLan_Close( struct net_device *);
 static struct  net_device_stats *TLan_GetStats( struct net_device *);
 static void    TLan_SetMulticastList( struct net_device *);
 static int     TLan_ioctl( struct net_device *dev, struct ifreq *rq, int cmd);
-static int      TLan_probe1( struct pci_dev *pdev, long ioaddr, int irq, int rev, const struct pci_device_id *ent);
+static int      TLan_probe1( struct pci_dev *pdev, long ioaddr,
+                            int irq, int rev, const struct pci_device_id *ent);
 static void    TLan_tx_timeout( struct net_device *dev);
 static void    TLan_tx_timeout_work(struct work_struct *work);
 static int     tlan_init_one( struct pci_dev *pdev, const struct pci_device_id *ent);
 
-static u32     TLan_HandleInvalid( struct net_device *, u16 );
 static u32     TLan_HandleTxEOF( struct net_device *, u16 );
 static u32     TLan_HandleStatOverflow( struct net_device *, u16 );
 static u32     TLan_HandleRxEOF( struct net_device *, u16 );
@@ -348,29 +347,27 @@ static void       TLan_EeReceiveByte( u16, u8 *, int );
 static int     TLan_EeReadByte( struct net_device *, u8, u8 * );
 
 
-static void
+static inline void
 TLan_StoreSKB( struct tlan_list_tag *tag, struct sk_buff *skb)
 {
        unsigned long addr = (unsigned long)skb;
-       tag->buffer[9].address = (u32)addr;
-       addr >>= 31;    /* >>= 32 is undefined for 32bit arch, stupid C */
-       addr >>= 1;
-       tag->buffer[8].address = (u32)addr;
+       tag->buffer[9].address = addr;
+       tag->buffer[8].address = upper_32_bits(addr);
 }
 
-static struct sk_buff *
-TLan_GetSKB( struct tlan_list_tag *tag)
+static inline struct sk_buff *
+TLan_GetSKB( const struct tlan_list_tag *tag)
 {
-       unsigned long addr = tag->buffer[8].address;
-       addr <<= 31;
-       addr <<= 1;
-       addr |= tag->buffer[9].address;
+       unsigned long addr;
+
+       addr = tag->buffer[8].address;
+       addr |= (tag->buffer[9].address << 16) << 16;
        return (struct sk_buff *) addr;
 }
 
 
 static TLanIntVectorFunc *TLanIntVector[TLAN_INT_NUMBER_OF_INTS] = {
-       TLan_HandleInvalid,
+       NULL,
        TLan_HandleTxEOF,
        TLan_HandleStatOverflow,
        TLan_HandleRxEOF,
@@ -444,7 +441,9 @@ static void __devexit tlan_remove_one( struct pci_dev *pdev)
        unregister_netdev( dev );
 
        if ( priv->dmaStorage ) {
-               pci_free_consistent(priv->pciDev, priv->dmaSize, priv->dmaStorage, priv->dmaStorageDMA );
+               pci_free_consistent(priv->pciDev,
+                                   priv->dmaSize, priv->dmaStorage,
+                                   priv->dmaStorageDMA );
        }
 
 #ifdef CONFIG_PCI
@@ -469,16 +468,6 @@ static int __init tlan_probe(void)
 
        printk(KERN_INFO "%s", tlan_banner);
 
-       TLanPadBuffer = (u8 *) pci_alloc_consistent(NULL, TLAN_MIN_FRAME_SIZE, &TLanPadBufferDMA);
-
-       if (TLanPadBuffer == NULL) {
-               printk(KERN_ERR "TLAN: Could not allocate memory for pad buffer.\n");
-               rc = -ENOMEM;
-               goto err_out;
-       }
-
-       memset(TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE);
-
        TLAN_DBG(TLAN_DEBUG_PROBE, "Starting PCI Probe....\n");
 
        /* Use new style PCI probing. Now the kernel will
@@ -506,8 +495,6 @@ static int __init tlan_probe(void)
 err_out_pci_unreg:
        pci_unregister_driver(&tlan_driver);
 err_out_pci_free:
-       pci_free_consistent(NULL, TLAN_MIN_FRAME_SIZE, TLanPadBuffer, TLanPadBufferDMA);
-err_out:
        return rc;
 }
 
@@ -539,7 +526,8 @@ static int __devinit tlan_init_one( struct pci_dev *pdev,
         **************************************************************/
 
 static int __devinit TLan_probe1(struct pci_dev *pdev,
-                               long ioaddr, int irq, int rev, const struct pci_device_id *ent )
+                                long ioaddr, int irq, int rev,
+                                const struct pci_device_id *ent )
 {
 
        struct net_device  *dev;
@@ -625,8 +613,10 @@ static int __devinit TLan_probe1(struct pci_dev *pdev,
        /* Kernel parameters */
        if (dev->mem_start) {
                priv->aui    = dev->mem_start & 0x01;
-               priv->duplex = ((dev->mem_start & 0x06) == 0x06) ? 0 : (dev->mem_start & 0x06) >> 1;
-               priv->speed  = ((dev->mem_start & 0x18) == 0x18) ? 0 : (dev->mem_start & 0x18) >> 3;
+               priv->duplex = ((dev->mem_start & 0x06) == 0x06) ? 0
+                       : (dev->mem_start & 0x06) >> 1;
+               priv->speed  = ((dev->mem_start & 0x18) == 0x18) ? 0
+                       : (dev->mem_start & 0x18) >> 3;
 
                if (priv->speed == 0x1) {
                        priv->speed = TLAN_SPEED_10;
@@ -706,7 +696,8 @@ static void TLan_Eisa_Cleanup(void)
                dev = TLan_Eisa_Devices;
                priv = netdev_priv(dev);
                if (priv->dmaStorage) {
-                       pci_free_consistent(priv->pciDev, priv->dmaSize, priv->dmaStorage, priv->dmaStorageDMA );
+                       pci_free_consistent(priv->pciDev, priv->dmaSize,
+                                           priv->dmaStorage, priv->dmaStorageDMA );
                }
                release_region( dev->base_addr, 0x10);
                unregister_netdev( dev );
@@ -724,8 +715,6 @@ static void __exit tlan_exit(void)
        if (tlan_have_eisa)
                TLan_Eisa_Cleanup();
 
-       pci_free_consistent(NULL, TLAN_MIN_FRAME_SIZE, TLanPadBuffer, TLanPadBufferDMA);
-
 }
 
 
@@ -763,8 +752,10 @@ static void  __init TLan_EisaProbe (void)
        /* Loop through all slots of the EISA bus */
        for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
 
-       TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n", (int) ioaddr + 0xC80, inw(ioaddr + EISA_ID));
-       TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n", (int) ioaddr + 0xC82, inw(ioaddr + EISA_ID2));
+       TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n",
+                (int) ioaddr + 0xC80, inw(ioaddr + EISA_ID));
+       TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n",
+                (int) ioaddr + 0xC82, inw(ioaddr + EISA_ID2));
 
 
                TLAN_DBG(TLAN_DEBUG_PROBE, "Probing for EISA adapter at IO: 0x%4x : ",
@@ -874,7 +865,8 @@ static int TLan_Init( struct net_device *dev )
                dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS )
                   * ( sizeof(TLanList) );
        }
-       priv->dmaStorage = pci_alloc_consistent(priv->pciDev, dma_size, &priv->dmaStorageDMA);
+       priv->dmaStorage = pci_alloc_consistent(priv->pciDev,
+                                               dma_size, &priv->dmaStorageDMA);
        priv->dmaSize = dma_size;
 
        if ( priv->dmaStorage == NULL ) {
@@ -883,16 +875,19 @@ static int TLan_Init( struct net_device *dev )
                return -ENOMEM;
        }
        memset( priv->dmaStorage, 0, dma_size );
-       priv->rxList = (TLanList *)
-                      ( ( ( (u32) priv->dmaStorage ) + 7 ) & 0xFFFFFFF8 );
-       priv->rxListDMA = ( ( ( (u32) priv->dmaStorageDMA ) + 7 ) & 0xFFFFFFF8 );
+       priv->rxList = (TLanList *) ALIGN((unsigned long)priv->dmaStorage, 8);
+       priv->rxListDMA = ALIGN(priv->dmaStorageDMA, 8);
        priv->txList = priv->rxList + TLAN_NUM_RX_LISTS;
        priv->txListDMA = priv->rxListDMA + sizeof(TLanList) * TLAN_NUM_RX_LISTS;
+
        if ( bbuf ) {
                priv->rxBuffer = (u8 *) ( priv->txList + TLAN_NUM_TX_LISTS );
-               priv->rxBufferDMA =priv->txListDMA + sizeof(TLanList) * TLAN_NUM_TX_LISTS;
-               priv->txBuffer = priv->rxBuffer + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE );
-               priv->txBufferDMA = priv->rxBufferDMA + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE );
+               priv->rxBufferDMA =priv->txListDMA
+                       + sizeof(TLanList) * TLAN_NUM_TX_LISTS;
+               priv->txBuffer = priv->rxBuffer
+                       + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE );
+               priv->txBufferDMA = priv->rxBufferDMA
+                       + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE );
        }
 
        err = 0;
@@ -952,10 +947,12 @@ static int TLan_Open( struct net_device *dev )
        int             err;
 
        priv->tlanRev = TLan_DioRead8( dev->base_addr, TLAN_DEF_REVISION );
-       err = request_irq( dev->irq, TLan_HandleInterrupt, IRQF_SHARED, TLanSignature, dev );
+       err = request_irq( dev->irq, TLan_HandleInterrupt, IRQF_SHARED,
+                          dev->name, dev );
 
        if ( err ) {
-               printk(KERN_ERR "TLAN:  Cannot open %s because IRQ %d is already in use.\n", dev->name, dev->irq );
+               pr_err("TLAN:  Cannot open %s because IRQ %d is already in use.\n",
+                      dev->name, dev->irq );
                return err;
        }
 
@@ -969,7 +966,8 @@ static int TLan_Open( struct net_device *dev )
        TLan_ReadAndClearStats( dev, TLAN_IGNORE );
        TLan_ResetAdapter( dev );
 
-       TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Opened.  TLAN Chip Rev: %x\n", dev->name, priv->tlanRev );
+       TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Opened.  TLAN Chip Rev: %x\n",
+                 dev->name, priv->tlanRev );
 
        return 0;
 
@@ -1007,14 +1005,16 @@ static int TLan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 
 
        case SIOCGMIIREG:               /* Read MII PHY register. */
-                       TLan_MiiReadReg(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, &data->val_out);
+                       TLan_MiiReadReg(dev, data->phy_id & 0x1f,
+                                       data->reg_num & 0x1f, &data->val_out);
                        return 0;
 
 
        case SIOCSMIIREG:               /* Write MII PHY register. */
                        if (!capable(CAP_NET_ADMIN))
                                return -EPERM;
-                       TLan_MiiWriteReg(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
+                       TLan_MiiWriteReg(dev, data->phy_id & 0x1f,
+                                        data->reg_num & 0x1f, data->val_in);
                        return 0;
                default:
                        return -EOPNOTSUPP;
@@ -1096,20 +1096,25 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev )
        TLanList        *tail_list;
        dma_addr_t      tail_list_phys;
        u8              *tail_buffer;
-       int             pad;
        unsigned long   flags;
 
        if ( ! priv->phyOnline ) {
-               TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  %s PHY is not ready\n", dev->name );
+               TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  %s PHY is not ready\n",
+                         dev->name );
                dev_kfree_skb_any(skb);
                return 0;
        }
 
+       if (skb_padto(skb, TLAN_MIN_FRAME_SIZE))
+               return 0;
+
        tail_list = priv->txList + priv->txTail;
        tail_list_phys = priv->txListDMA + sizeof(TLanList) * priv->txTail;
 
        if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) {
-               TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  %s is busy (Head=%d Tail=%d)\n", dev->name, priv->txHead, priv->txTail );
+               TLAN_DBG( TLAN_DEBUG_TX,
+                         "TRANSMIT:  %s is busy (Head=%d Tail=%d)\n",
+                         dev->name, priv->txHead, priv->txTail );
                netif_stop_queue(dev);
                priv->txBusyCount++;
                return 1;
@@ -1121,37 +1126,34 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev )
                tail_buffer = priv->txBuffer + ( priv->txTail * TLAN_MAX_FRAME_SIZE );
                skb_copy_from_linear_data(skb, tail_buffer, skb->len);
        } else {
-               tail_list->buffer[0].address = pci_map_single(priv->pciDev, skb->data, skb->len, PCI_DMA_TODEVICE);
+               tail_list->buffer[0].address = pci_map_single(priv->pciDev,
+                                                             skb->data, skb->len,
+                                                             PCI_DMA_TODEVICE);
                TLan_StoreSKB(tail_list, skb);
        }
 
-       pad = TLAN_MIN_FRAME_SIZE - skb->len;
-
-       if ( pad > 0 ) {
-               tail_list->frameSize = (u16) skb->len + pad;
-               tail_list->buffer[0].count = (u32) skb->len;
-               tail_list->buffer[1].count = TLAN_LAST_BUFFER | (u32) pad;
-               tail_list->buffer[1].address = TLanPadBufferDMA;
-       } else {
-               tail_list->frameSize = (u16) skb->len;
-               tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) skb->len;
-               tail_list->buffer[1].count = 0;
-               tail_list->buffer[1].address = 0;
-       }
+       tail_list->frameSize = (u16) skb->len;
+       tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) skb->len;
+       tail_list->buffer[1].count = 0;
+       tail_list->buffer[1].address = 0;
 
        spin_lock_irqsave(&priv->lock, flags);
        tail_list->cStat = TLAN_CSTAT_READY;
        if ( ! priv->txInProgress ) {
                priv->txInProgress = 1;
-               TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  Starting TX on buffer %d\n", priv->txTail );
+               TLAN_DBG( TLAN_DEBUG_TX,
+                         "TRANSMIT:  Starting TX on buffer %d\n", priv->txTail );
                outl( tail_list_phys, dev->base_addr + TLAN_CH_PARM );
                outl( TLAN_HC_GO, dev->base_addr + TLAN_HOST_CMD );
        } else {
-               TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  Adding buffer %d to TX channel\n", priv->txTail );
+               TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  Adding buffer %d to TX channel\n",
+                         priv->txTail );
                if ( priv->txTail == 0 ) {
-                       ( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward = tail_list_phys;
+                       ( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward
+                               = tail_list_phys;
                } else {
-                       ( priv->txList + ( priv->txTail - 1 ) )->forward = tail_list_phys;
+                       ( priv->txList + ( priv->txTail - 1 ) )->forward
+                               = tail_list_phys;
                }
        }
        spin_unlock_irqrestore(&priv->lock, flags);
@@ -1191,33 +1193,31 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev )
 
 static irqreturn_t TLan_HandleInterrupt(int irq, void *dev_id)
 {
-       u32             ack;
-       struct net_device       *dev;
-       u32             host_cmd;
+       struct net_device       *dev = dev_id;
+       TLanPrivateInfo *priv = netdev_priv(dev);
        u16             host_int;
-       int             type;
-       TLanPrivateInfo *priv;
-
-       dev = dev_id;
-       priv = netdev_priv(dev);
+       u16             type;
 
        spin_lock(&priv->lock);
 
        host_int = inw( dev->base_addr + TLAN_HOST_INT );
-       outw( host_int, dev->base_addr + TLAN_HOST_INT );
-
        type = ( host_int & TLAN_HI_IT_MASK ) >> 2;
+       if ( type ) {
+               u32     ack;
+               u32     host_cmd;
 
-       ack = TLanIntVector[type]( dev, host_int );
+               outw( host_int, dev->base_addr + TLAN_HOST_INT );
+               ack = TLanIntVector[type]( dev, host_int );
 
-       if ( ack ) {
-               host_cmd = TLAN_HC_ACK | ack | ( type << 18 );
-               outl( host_cmd, dev->base_addr + TLAN_HOST_CMD );
+               if ( ack ) {
+                       host_cmd = TLAN_HC_ACK | ack | ( type << 18 );
+                       outl( host_cmd, dev->base_addr + TLAN_HOST_CMD );
+               }
        }
 
        spin_unlock(&priv->lock);
 
-       return IRQ_HANDLED;
+       return IRQ_RETVAL(type);
 } /* TLan_HandleInterrupts */
 
 
@@ -1286,8 +1286,10 @@ static struct net_device_stats *TLan_GetStats( struct net_device *dev )
        /* Should only read stats if open ? */
        TLan_ReadAndClearStats( dev, TLAN_RECORD );
 
-       TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE:  %s EOC count = %d\n", dev->name, priv->rxEocCount );
-       TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  %s Busy count = %d\n", dev->name, priv->txBusyCount );
+       TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE:  %s EOC count = %d\n", dev->name,
+                 priv->rxEocCount );
+       TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  %s Busy count = %d\n", dev->name,
+                 priv->txBusyCount );
        if ( debug & TLAN_DEBUG_GNRL ) {
                TLan_PrintDio( dev->base_addr );
                TLan_PhyPrint( dev );
@@ -1299,7 +1301,7 @@ static struct net_device_stats *TLan_GetStats( struct net_device *dev )
                        TLan_PrintList( priv->txList + i, "TX", i );
        }
 
-       return ( &( (TLanPrivateInfo *) netdev_priv(dev) )->stats );
+       return &dev->stats;
 
 } /* TLan_GetStats */
 
@@ -1337,10 +1339,12 @@ static void TLan_SetMulticastList( struct net_device *dev )
 
        if ( dev->flags & IFF_PROMISC ) {
                tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD );
-               TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp | TLAN_NET_CMD_CAF );
+               TLan_DioWrite8( dev->base_addr,
+                               TLAN_NET_CMD, tmp | TLAN_NET_CMD_CAF );
        } else {
                tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD );
-               TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp & ~TLAN_NET_CMD_CAF );
+               TLan_DioWrite8( dev->base_addr,
+                               TLAN_NET_CMD, tmp & ~TLAN_NET_CMD_CAF );
                if ( dev->flags & IFF_ALLMULTI ) {
                        for ( i = 0; i < 3; i++ )
                                TLan_SetMac( dev, i + 1, NULL );
@@ -1349,7 +1353,8 @@ static void TLan_SetMulticastList( struct net_device *dev )
                } else {
                        for ( i = 0; i < dev->mc_count; i++ ) {
                                if ( i < 3 ) {
-                                       TLan_SetMac( dev, i + 1, (char *) &dmi->dmi_addr );
+                                       TLan_SetMac( dev, i + 1,
+                                                    (char *) &dmi->dmi_addr );
                                } else {
                                        offset = TLan_HashFunc( (u8 *) &dmi->dmi_addr );
                                        if ( offset < 32 )
@@ -1383,31 +1388,6 @@ static void TLan_SetMulticastList( struct net_device *dev )
 *****************************************************************************/
 
 
-       /***************************************************************
-        *      TLan_HandleInvalid
-        *
-        *      Returns:
-        *              0
-        *      Parms:
-        *              dev             Device assigned the IRQ that was
-        *                              raised.
-        *              host_int        The contents of the HOST_INT
-        *                              port.
-        *
-        *      This function handles invalid interrupts.  This should
-        *      never happen unless some other adapter is trying to use
-        *      the IRQ line assigned to the device.
-        *
-        **************************************************************/
-
-static u32 TLan_HandleInvalid( struct net_device *dev, u16 host_int )
-{
-       /* printk( "TLAN:  Invalid interrupt on %s.\n", dev->name ); */
-       return 0;
-
-} /* TLan_HandleInvalid */
-
-
 
 
        /***************************************************************
@@ -1441,14 +1421,16 @@ static u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int )
        u32             ack = 0;
        u16             tmpCStat;
 
-       TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  Handling TX EOF (Head=%d Tail=%d)\n", priv->txHead, priv->txTail );
+       TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  Handling TX EOF (Head=%d Tail=%d)\n",
+                 priv->txHead, priv->txTail );
        head_list = priv->txList + priv->txHead;
 
        while (((tmpCStat = head_list->cStat ) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) {
                ack++;
                if ( ! bbuf ) {
                        struct sk_buff *skb = TLan_GetSKB(head_list);
-                       pci_unmap_single(priv->pciDev, head_list->buffer[0].address, skb->len, PCI_DMA_TODEVICE);
+                       pci_unmap_single(priv->pciDev, head_list->buffer[0].address,
+                                        skb->len, PCI_DMA_TODEVICE);
                        dev_kfree_skb_any(skb);
                        head_list->buffer[8].address = 0;
                        head_list->buffer[9].address = 0;
@@ -1457,7 +1439,7 @@ static u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int )
                if ( tmpCStat & TLAN_CSTAT_EOC )
                        eoc = 1;
 
-               priv->stats.tx_bytes += head_list->frameSize;
+               dev->stats.tx_bytes += head_list->frameSize;
 
                head_list->cStat = TLAN_CSTAT_UNUSED;
                netif_start_queue(dev);
@@ -1469,7 +1451,9 @@ static u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int )
                printk(KERN_INFO "TLAN: Received interrupt for uncompleted TX frame.\n");
 
        if ( eoc ) {
-               TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  Handling TX EOC (Head=%d Tail=%d)\n", priv->txHead, priv->txTail );
+               TLAN_DBG( TLAN_DEBUG_TX,
+                         "TRANSMIT:  Handling TX EOC (Head=%d Tail=%d)\n",
+                         priv->txHead, priv->txTail );
                head_list = priv->txList + priv->txHead;
                head_list_phys = priv->txListDMA + sizeof(TLanList) * priv->txHead;
                if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) {
@@ -1481,7 +1465,8 @@ static u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int )
        }
 
        if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) {
-               TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
+               TLan_DioWrite8( dev->base_addr,
+                               TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
                if ( priv->timer.function == NULL ) {
                         priv->timer.function = &TLan_Timer;
                         priv->timer.data = (unsigned long) dev;
@@ -1563,66 +1548,65 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int )
        TLanList        *head_list;
        struct sk_buff  *skb;
        TLanList        *tail_list;
-       void            *t;
-       u32             frameSize;
        u16             tmpCStat;
        dma_addr_t      head_list_phys;
 
-       TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE:  Handling RX EOF (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail );
+       TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE:  Handling RX EOF (Head=%d Tail=%d)\n",
+                 priv->rxHead, priv->rxTail );
        head_list = priv->rxList + priv->rxHead;
        head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead;
 
        while (((tmpCStat = head_list->cStat) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) {
-               frameSize = head_list->frameSize;
+               dma_addr_t frameDma = head_list->buffer[0].address;
+               u32 frameSize = head_list->frameSize;
                ack++;
                if (tmpCStat & TLAN_CSTAT_EOC)
                        eoc = 1;
 
                if (bbuf) {
-                       skb = dev_alloc_skb(frameSize + 7);
-                       if (skb == NULL)
-                               printk(KERN_INFO "TLAN: Couldn't allocate memory for received data.\n");
-                       else {
-                               head_buffer = priv->rxBuffer + (priv->rxHead * TLAN_MAX_FRAME_SIZE);
-                               skb_reserve(skb, 2);
-                               t = (void *) skb_put(skb, frameSize);
-
-                               priv->stats.rx_bytes += head_list->frameSize;
-
-                               memcpy( t, head_buffer, frameSize );
-                               skb->protocol = eth_type_trans( skb, dev );
-                               netif_rx( skb );
-                       }
+                       skb = netdev_alloc_skb(dev, frameSize + 7);
+                       if ( !skb )
+                               goto drop_and_reuse;
+
+                       head_buffer = priv->rxBuffer
+                               + (priv->rxHead * TLAN_MAX_FRAME_SIZE);
+                       skb_reserve(skb, 2);
+                       pci_dma_sync_single_for_cpu(priv->pciDev,
+                                                   frameDma, frameSize,
+                                                   PCI_DMA_FROMDEVICE);
+                       skb_copy_from_linear_data(skb, head_buffer, frameSize);
+                       skb_put(skb, frameSize);
+                       dev->stats.rx_bytes += frameSize;
+
+                       skb->protocol = eth_type_trans( skb, dev );
+                       netif_rx( skb );
                } else {
                        struct sk_buff *new_skb;
 
-                       /*
-                        *      I changed the algorithm here. What we now do
-                        *      is allocate the new frame. If this fails we
-                        *      simply recycle the frame.
-                        */
+                       new_skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 );
+                       if ( !new_skb )
+                               goto drop_and_reuse;
 
-                       new_skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 );
+                       skb = TLan_GetSKB(head_list);
+                       pci_unmap_single(priv->pciDev, frameDma,
+                                        TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE);
+                       skb_put( skb, frameSize );
 
-                       if ( new_skb != NULL ) {
-                               skb = TLan_GetSKB(head_list);
-                               pci_unmap_single(priv->pciDev, head_list->buffer[0].address, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE);
-                               skb_trim( skb, frameSize );
+                       dev->stats.rx_bytes += frameSize;
 
-                               priv->stats.rx_bytes += frameSize;
+                       skb->protocol = eth_type_trans( skb, dev );
+                       netif_rx( skb );
 
-                               skb->protocol = eth_type_trans( skb, dev );
-                               netif_rx( skb );
+                       skb_reserve( new_skb, NET_IP_ALIGN );
+                       head_list->buffer[0].address = pci_map_single(priv->pciDev,
+                                                                     new_skb->data,
+                                                                     TLAN_MAX_FRAME_SIZE,
+                                                                     PCI_DMA_FROMDEVICE);
 
-                               skb_reserve( new_skb, 2 );
-                               t = (void *) skb_put( new_skb, TLAN_MAX_FRAME_SIZE );
-                               head_list->buffer[0].address = pci_map_single(priv->pciDev, new_skb->data, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE);
-                               head_list->buffer[8].address = (u32) t;
-                               TLan_StoreSKB(head_list, new_skb);
-                       } else
-                               printk(KERN_WARNING "TLAN:  Couldn't allocate memory for received data.\n" );
-               }
+                       TLan_StoreSKB(head_list, new_skb);
 
+               }
+drop_and_reuse:
                head_list->forward = 0;
                head_list->cStat = 0;
                tail_list = priv->rxList + priv->rxTail;
@@ -1638,10 +1622,10 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int )
                printk(KERN_INFO "TLAN: Received interrupt for uncompleted RX frame.\n");
 
 
-
-
        if ( eoc ) {
-               TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE:  Handling RX EOC (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail );
+               TLAN_DBG( TLAN_DEBUG_RX,
+                         "RECEIVE:  Handling RX EOC (Head=%d Tail=%d)\n",
+                         priv->rxHead, priv->rxTail );
                head_list = priv->rxList + priv->rxHead;
                head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead;
                outl(head_list_phys, dev->base_addr + TLAN_CH_PARM );
@@ -1650,7 +1634,8 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int )
        }
 
        if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) {
-               TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
+               TLan_DioWrite8( dev->base_addr,
+                               TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
                if ( priv->timer.function == NULL )  {
                        priv->timer.function = &TLan_Timer;
                        priv->timer.data = (unsigned long) dev;
@@ -1728,7 +1713,9 @@ static u32 TLan_HandleTxEOC( struct net_device *dev, u16 host_int )
 
        host_int = 0;
        if ( priv->tlanRev < 0x30 ) {
-               TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  Handling TX EOC (Head=%d Tail=%d) -- IRQ\n", priv->txHead, priv->txTail );
+               TLAN_DBG( TLAN_DEBUG_TX,
+                         "TRANSMIT:  Handling TX EOC (Head=%d Tail=%d) -- IRQ\n",
+                         priv->txHead, priv->txTail );
                head_list = priv->txList + priv->txHead;
                head_list_phys = priv->txListDMA + sizeof(TLanList) * priv->txHead;
                if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) {
@@ -1796,15 +1783,18 @@ static u32 TLan_HandleStatusCheck( struct net_device *dev, u16 host_int )
                net_sts = TLan_DioRead8( dev->base_addr, TLAN_NET_STS );
                if ( net_sts ) {
                        TLan_DioWrite8( dev->base_addr, TLAN_NET_STS, net_sts );
-                       TLAN_DBG( TLAN_DEBUG_GNRL, "%s:    Net_Sts = %x\n", dev->name, (unsigned) net_sts );
+                       TLAN_DBG( TLAN_DEBUG_GNRL, "%s:    Net_Sts = %x\n",
+                                 dev->name, (unsigned) net_sts );
                }
                if ( ( net_sts & TLAN_NET_STS_MIRQ ) &&  ( priv->phyNum == 0 ) ) {
                        TLan_MiiReadReg( dev, phy, TLAN_TLPHY_STS, &tlphy_sts );
                        TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tlphy_ctl );
-                       if ( ! ( tlphy_sts & TLAN_TS_POLOK ) && ! ( tlphy_ctl & TLAN_TC_SWAPOL ) ) {
+                       if ( ! ( tlphy_sts & TLAN_TS_POLOK ) &&
+                            ! ( tlphy_ctl & TLAN_TC_SWAPOL ) ) {
                                tlphy_ctl |= TLAN_TC_SWAPOL;
                                TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl);
-                       } else if ( ( tlphy_sts & TLAN_TS_POLOK ) && ( tlphy_ctl & TLAN_TC_SWAPOL ) ) {
+                       } else if ( ( tlphy_sts & TLAN_TS_POLOK )
+                                   && ( tlphy_ctl & TLAN_TC_SWAPOL ) ) {
                                tlphy_ctl &= ~TLAN_TC_SWAPOL;
                                TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl);
                        }
@@ -1849,7 +1839,9 @@ static u32 TLan_HandleRxEOC( struct net_device *dev, u16 host_int )
        u32             ack = 1;
 
        if (  priv->tlanRev < 0x30 ) {
-               TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE:  Handling RX EOC (Head=%d Tail=%d) -- IRQ\n", priv->rxHead, priv->rxTail );
+               TLAN_DBG( TLAN_DEBUG_RX,
+                         "RECEIVE:  Handling RX EOC (Head=%d Tail=%d) -- IRQ\n",
+                         priv->rxHead, priv->rxTail );
                head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead;
                outl( head_list_phys, dev->base_addr + TLAN_CH_PARM );
                ack |= TLAN_HC_GO | TLAN_HC_RT;
@@ -1940,10 +1932,12 @@ static void TLan_Timer( unsigned long data )
                        if ( priv->timer.function == NULL ) {
                                elapsed = jiffies - priv->timerSetAt;
                                if ( elapsed >= TLAN_TIMER_ACT_DELAY ) {
-                                       TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK );
+                                       TLan_DioWrite8( dev->base_addr,
+                                                       TLAN_LED_REG, TLAN_LED_LINK );
                                } else  {
                                        priv->timer.function = &TLan_Timer;
-                                       priv->timer.expires = priv->timerSetAt + TLAN_TIMER_ACT_DELAY;
+                                       priv->timer.expires = priv->timerSetAt
+                                               + TLAN_TIMER_ACT_DELAY;
                                        spin_unlock_irqrestore(&priv->lock, flags);
                                        add_timer( &priv->timer );
                                        break;
@@ -1998,7 +1992,8 @@ static void TLan_ResetLists( struct net_device *dev )
                list = priv->txList + i;
                list->cStat = TLAN_CSTAT_UNUSED;
                if ( bbuf ) {
-                       list->buffer[0].address = priv->txBufferDMA + ( i * TLAN_MAX_FRAME_SIZE );
+                       list->buffer[0].address = priv->txBufferDMA
+                               + ( i * TLAN_MAX_FRAME_SIZE );
                } else {
                        list->buffer[0].address = 0;
                }
@@ -2017,28 +2012,32 @@ static void TLan_ResetLists( struct net_device *dev )
                list->frameSize = TLAN_MAX_FRAME_SIZE;
                list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER;
                if ( bbuf ) {
-                       list->buffer[0].address = priv->rxBufferDMA + ( i * TLAN_MAX_FRAME_SIZE );
+                       list->buffer[0].address = priv->rxBufferDMA
+                               + ( i * TLAN_MAX_FRAME_SIZE );
                } else {
-                       skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 );
-                       if ( skb == NULL ) {
-                               printk( "TLAN:  Couldn't allocate memory for received data.\n" );
-                               /* If this ever happened it would be a problem */
-                       } else {
-                               skb->dev = dev;
-                               skb_reserve( skb, 2 );
-                               t = (void *) skb_put( skb, TLAN_MAX_FRAME_SIZE );
+                       skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 );
+                       if ( !skb ) {
+                               pr_err("TLAN: out of memory for received data.\n" );
+                               break;
                        }
-                       list->buffer[0].address = pci_map_single(priv->pciDev, t, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE);
-                       list->buffer[8].address = (u32) t;
+
+                       skb_reserve( skb, NET_IP_ALIGN );
+                       list->buffer[0].address = pci_map_single(priv->pciDev, t,
+                                                                TLAN_MAX_FRAME_SIZE,
+                                                                PCI_DMA_FROMDEVICE);
                        TLan_StoreSKB(list, skb);
                }
                list->buffer[1].count = 0;
                list->buffer[1].address = 0;
-               if ( i < TLAN_NUM_RX_LISTS - 1 )
-                       list->forward = list_phys + sizeof(TLanList);
-               else
-                       list->forward = 0;
+               list->forward = list_phys + sizeof(TLanList);
+       }
+
+       /* in case ran out of memory early, clear bits */
+       while (i < TLAN_NUM_RX_LISTS) {
+               TLan_StoreSKB(priv->rxList + i, NULL);
+               ++i;
        }
+       list->forward = 0;
 
 } /* TLan_ResetLists */
 
@@ -2055,7 +2054,9 @@ static void TLan_FreeLists( struct net_device *dev )
                        list = priv->txList + i;
                        skb = TLan_GetSKB(list);
                        if ( skb ) {
-                               pci_unmap_single(priv->pciDev, list->buffer[0].address, skb->len, PCI_DMA_TODEVICE);
+                               pci_unmap_single(priv->pciDev,
+                                                list->buffer[0].address, skb->len,
+                                                PCI_DMA_TODEVICE);
                                dev_kfree_skb_any( skb );
                                list->buffer[8].address = 0;
                                list->buffer[9].address = 0;
@@ -2066,7 +2067,10 @@ static void TLan_FreeLists( struct net_device *dev )
                        list = priv->rxList + i;
                        skb = TLan_GetSKB(list);
                        if ( skb ) {
-                               pci_unmap_single(priv->pciDev, list->buffer[0].address, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE);
+                               pci_unmap_single(priv->pciDev,
+                                                list->buffer[0].address,
+                                                TLAN_MAX_FRAME_SIZE,
+                                                PCI_DMA_FROMDEVICE);
                                dev_kfree_skb_any( skb );
                                list->buffer[8].address = 0;
                                list->buffer[9].address = 0;
@@ -2097,7 +2101,8 @@ static void TLan_PrintDio( u16 io_base )
        u32 data0, data1;
        int     i;
 
-       printk( "TLAN:   Contents of internal registers for io base 0x%04hx.\n", io_base );
+       printk( "TLAN:   Contents of internal registers for io base 0x%04hx.\n",
+               io_base );
        printk( "TLAN:      Off.  +0         +4\n" );
        for ( i = 0; i < 0x4C; i+= 8 ) {
                data0 = TLan_DioRead32( io_base, i );
@@ -2131,13 +2136,14 @@ static void TLan_PrintList( TLanList *list, char *type, int num)
 {
        int i;
 
-       printk( "TLAN:   %s List %d at 0x%08x\n", type, num, (u32) list );
+       printk( "TLAN:   %s List %d at %p\n", type, num, list );
        printk( "TLAN:      Forward    = 0x%08x\n",  list->forward );
        printk( "TLAN:      CSTAT      = 0x%04hx\n", list->cStat );
        printk( "TLAN:      Frame Size = 0x%04hx\n", list->frameSize );
        /* for ( i = 0; i < 10; i++ ) { */
        for ( i = 0; i < 2; i++ ) {
-               printk( "TLAN:      Buffer[%d].count, addr = 0x%08x, 0x%08x\n", i, list->buffer[i].count, list->buffer[i].address );
+               printk( "TLAN:      Buffer[%d].count, addr = 0x%08x, 0x%08x\n",
+                       i, list->buffer[i].count, list->buffer[i].address );
        }
 
 } /* TLan_PrintList */
@@ -2165,7 +2171,6 @@ static void TLan_PrintList( TLanList *list, char *type, int num)
 
 static void TLan_ReadAndClearStats( struct net_device *dev, int record )
 {
-       TLanPrivateInfo *priv = netdev_priv(dev);
        u32             tx_good, tx_under;
        u32             rx_good, rx_over;
        u32             def_tx, crc, code;
@@ -2202,18 +2207,18 @@ static void TLan_ReadAndClearStats( struct net_device *dev, int record )
        loss       = inb( dev->base_addr + TLAN_DIO_DATA + 2 );
 
        if ( record ) {
-               priv->stats.rx_packets += rx_good;
-               priv->stats.rx_errors  += rx_over + crc + code;
-               priv->stats.tx_packets += tx_good;
-               priv->stats.tx_errors  += tx_under + loss;
-               priv->stats.collisions += multi_col + single_col + excess_col + late_col;
+               dev->stats.rx_packets += rx_good;
+               dev->stats.rx_errors  += rx_over + crc + code;
+               dev->stats.tx_packets += tx_good;
+               dev->stats.tx_errors  += tx_under + loss;
+               dev->stats.collisions += multi_col + single_col + excess_col + late_col;
 
-               priv->stats.rx_over_errors    += rx_over;
-               priv->stats.rx_crc_errors     += crc;
-               priv->stats.rx_frame_errors   += code;
+               dev->stats.rx_over_errors    += rx_over;
+               dev->stats.rx_crc_errors     += crc;
+               dev->stats.rx_frame_errors   += code;
 
-               priv->stats.tx_aborted_errors += tx_under;
-               priv->stats.tx_carrier_errors += loss;
+               dev->stats.tx_aborted_errors += tx_under;
+               dev->stats.tx_carrier_errors += loss;
        }
 
 } /* TLan_ReadAndClearStats */
@@ -2354,14 +2359,16 @@ TLan_FinishReset( struct net_device *dev )
        TLan_MiiReadReg( dev, phy, MII_GEN_ID_HI, &tlphy_id1 );
        TLan_MiiReadReg( dev, phy, MII_GEN_ID_LO, &tlphy_id2 );
 
-       if ( ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) || ( priv->aui ) ) {
+       if ( ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) ||
+            ( priv->aui ) ) {
                status = MII_GS_LINK;
                printk( "TLAN:  %s: Link forced.\n", dev->name );
        } else {
                TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
                udelay( 1000 );
                TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
-               if ( (status & MII_GS_LINK) &&   /* We only support link info on Nat.Sem. PHY's */
+               if ( (status & MII_GS_LINK) &&
+                    /* We only support link info on Nat.Sem. PHY's */
                        (tlphy_id1 == NAT_SEM_ID1) &&
                        (tlphy_id2 == NAT_SEM_ID2) ) {
                        TLan_MiiReadReg( dev, phy, MII_AN_LPA, &partner );
@@ -2370,12 +2377,12 @@ TLan_FinishReset( struct net_device *dev )
                        printk( "TLAN: %s: Link active with ", dev->name );
                        if (!(tlphy_par & TLAN_PHY_AN_EN_STAT)) {
                                 printk( "forced 10%sMbps %s-Duplex\n",
-                                               tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0",
-                                               tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half");
+                                        tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0",
+                                        tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half");
                        } else {
                                printk( "AutoNegotiation enabled, at 10%sMbps %s-Duplex\n",
-                                               tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0",
-                                               tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half");
+                                       tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0",
+                                       tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half");
                                printk("TLAN: Partner capability: ");
                                        for (i = 5; i <= 10; i++)
                                                if (partner & (1<<i))
@@ -2416,7 +2423,8 @@ TLan_FinishReset( struct net_device *dev )
                outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD );
                netif_carrier_on(dev);
        } else {
-               printk( "TLAN: %s: Link inactive, will retry in 10 secs...\n", dev->name );
+               printk( "TLAN: %s: Link inactive, will retry in 10 secs...\n",
+                       dev->name );
                TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_FINISH_RESET );
                return;
        }
@@ -2456,10 +2464,12 @@ static void TLan_SetMac( struct net_device *dev, int areg, char *mac )
 
        if ( mac != NULL ) {
                for ( i = 0; i < 6; i++ )
-                       TLan_DioWrite8( dev->base_addr, TLAN_AREG_0 + areg + i, mac[i] );
+                       TLan_DioWrite8( dev->base_addr,
+                                       TLAN_AREG_0 + areg + i, mac[i] );
        } else {
                for ( i = 0; i < 6; i++ )
-                       TLan_DioWrite8( dev->base_addr, TLAN_AREG_0 + areg + i, 0 );
+                       TLan_DioWrite8( dev->base_addr,
+                                       TLAN_AREG_0 + areg + i, 0 );
        }
 
 } /* TLan_SetMac */
@@ -2565,9 +2575,13 @@ static void TLan_PhyDetect( struct net_device *dev )
                TLan_MiiReadReg( dev, phy, MII_GEN_CTL, &control );
                TLan_MiiReadReg( dev, phy, MII_GEN_ID_HI, &hi );
                TLan_MiiReadReg( dev, phy, MII_GEN_ID_LO, &lo );
-               if ( ( control != 0xFFFF ) || ( hi != 0xFFFF ) || ( lo != 0xFFFF ) ) {
-                       TLAN_DBG( TLAN_DEBUG_GNRL, "PHY found at %02x %04x %04x %04x\n", phy, control, hi, lo );
-                       if ( ( priv->phy[1] == TLAN_PHY_NONE ) && ( phy != TLAN_PHY_MAX_ADDR ) ) {
+               if ( ( control != 0xFFFF ) ||
+                    ( hi != 0xFFFF ) || ( lo != 0xFFFF ) ) {
+                       TLAN_DBG( TLAN_DEBUG_GNRL,
+                                 "PHY found at %02x %04x %04x %04x\n",
+                                 phy, control, hi, lo );
+                       if ( ( priv->phy[1] == TLAN_PHY_NONE ) &&
+                            ( phy != TLAN_PHY_MAX_ADDR ) ) {
                                priv->phy[1] = phy;
                        }
                }
@@ -2595,7 +2609,9 @@ static void TLan_PhyPowerDown( struct net_device *dev )
        value = MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE;
        TLan_MiiSync( dev->base_addr );
        TLan_MiiWriteReg( dev, priv->phy[priv->phyNum], MII_GEN_CTL, value );
-       if ( ( priv->phyNum == 0 ) && ( priv->phy[1] != TLAN_PHY_NONE ) && ( ! ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) ) ) {
+       if ( ( priv->phyNum == 0 ) &&
+            ( priv->phy[1] != TLAN_PHY_NONE ) &&
+            ( ! ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) ) ) {
                TLan_MiiSync( dev->base_addr );
                TLan_MiiWriteReg( dev, priv->phy[1], MII_GEN_CTL, value );
        }
@@ -2768,10 +2784,10 @@ static void TLan_PhyFinishAutoNeg( struct net_device *dev )
                 * more time.  Perhaps we should fail after a while.
                 */
                 if (!priv->neg_be_verbose++) {
-                        printk(KERN_INFO "TLAN:  Giving autonegotiation more time.\n");
-                        printk(KERN_INFO "TLAN:  Please check that your adapter has\n");
-                        printk(KERN_INFO "TLAN:  been properly connected to a HUB or Switch.\n");
-                        printk(KERN_INFO "TLAN:  Trying to establish link in the background...\n");
+                        pr_info("TLAN:  Giving autonegotiation more time.\n");
+                        pr_info("TLAN:  Please check that your adapter has\n");
+                        pr_info("TLAN:  been properly connected to a HUB or Switch.\n");
+                        pr_info("TLAN:  Trying to establish link in the background...\n");
                 }
                TLan_SetTimer( dev, (8*HZ), TLAN_TIMER_PHY_FINISH_AN );
                return;
@@ -2787,7 +2803,9 @@ static void TLan_PhyFinishAutoNeg( struct net_device *dev )
                priv->tlanFullDuplex = TRUE;
        }
 
-       if ( ( ! ( mode & 0x0180 ) ) && ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) && ( priv->phyNum != 0 ) ) {
+       if ( ( ! ( mode & 0x0180 ) ) &&
+            ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) &&
+            ( priv->phyNum != 0 ) ) {
                priv->phyNum = 0;
                data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN;
                TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, data );
@@ -2796,12 +2814,14 @@ static void TLan_PhyFinishAutoNeg( struct net_device *dev )
        }
 
        if ( priv->phyNum == 0 ) {
-               if ( ( priv->duplex == TLAN_DUPLEX_FULL ) || ( an_adv & an_lpa & 0x0040 ) ) {
-                       TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, MII_GC_AUTOENB | MII_GC_DUPLEX );
-                       printk( "TLAN:  Starting internal PHY with FULL-DUPLEX\n" );
+               if ( ( priv->duplex == TLAN_DUPLEX_FULL ) ||
+                    ( an_adv & an_lpa & 0x0040 ) ) {
+                       TLan_MiiWriteReg( dev, phy, MII_GEN_CTL,
+                                         MII_GC_AUTOENB | MII_GC_DUPLEX );
+                       pr_info("TLAN:  Starting internal PHY with FULL-DUPLEX\n" );
                } else {
                        TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, MII_GC_AUTOENB );
-                       printk( "TLAN:  Starting internal PHY with HALF-DUPLEX\n" );
+                       pr_info( "TLAN:  Starting internal PHY with HALF-DUPLEX\n" );
                }
        }
 
@@ -3209,7 +3229,8 @@ static int TLan_EeSendByte( u16 io_base, u8 data, int stop )
        TLan_SetBit( TLAN_NET_SIO_ETXEN, sio );
 
        if ( ( ! err ) && stop ) {
-               TLan_ClearBit( TLAN_NET_SIO_EDATA, sio );       /* STOP, raise data while clock is high */
+               /* STOP, raise data while clock is high */
+               TLan_ClearBit( TLAN_NET_SIO_EDATA, sio );
                TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
                TLan_SetBit( TLAN_NET_SIO_EDATA, sio );
        }
@@ -3272,7 +3293,8 @@ static void TLan_EeReceiveByte( u16 io_base, u8 *data, int stop )
                TLan_SetBit( TLAN_NET_SIO_EDATA, sio );         /* No ack = 1 (?) */
                TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
                TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio );
-               TLan_ClearBit( TLAN_NET_SIO_EDATA, sio );       /* STOP, raise data while clock is high */
+               /* STOP, raise data while clock is high */
+               TLan_ClearBit( TLAN_NET_SIO_EDATA, sio );
                TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
                TLan_SetBit( TLAN_NET_SIO_EDATA, sio );
        }
index 41ce0b6659378833863f3d176c7ec55183c7814a..4b82f283e98552cfb975bc30a3b461d091e6cd54 100644 (file)
@@ -13,8 +13,6 @@
  *  This software may be used and distributed according to the terms
  *  of the GNU General Public License, incorporated herein by reference.
  *
- ** This file is best viewed/edited with tabstop=4, colums>=132
- *
  *
  *  Dec 10, 1999       Torben Mathiasen <torben.mathiasen@compaq.com>
  *                     New Maintainer
@@ -45,7 +43,9 @@
 #define TLAN_IGNORE            0
 #define TLAN_RECORD            1
 
-#define TLAN_DBG(lvl, format, args...) if (debug&lvl) printk(KERN_DEBUG "TLAN: " format, ##args );
+#define TLAN_DBG(lvl, format, args...) \
+       do { if (debug&lvl) printk(KERN_DEBUG "TLAN: " format, ##args ); } while(0)
+
 #define TLAN_DEBUG_GNRL                0x0001
 #define TLAN_DEBUG_TX          0x0002
 #define TLAN_DEBUG_RX          0x0004
@@ -194,7 +194,6 @@ typedef struct tlan_private_tag {
        u32                     timerSetAt;
        u32                     timerType;
        struct timer_list       timer;
-       struct net_device_stats stats;
        struct board            *adapter;
        u32                     adapterRev;
        u32                     aui;
@@ -205,7 +204,6 @@ typedef struct tlan_private_tag {
        u32                     speed;
        u8                      tlanRev;
        u8                      tlanFullDuplex;
-       char                    devName[8];
        spinlock_t              lock;
        u8                      link;
        u8                      is_eisa;
@@ -517,12 +515,18 @@ static inline void TLan_DioWrite32(u16 base_addr, u16 internal_addr, u32 data)
  *     xor( a, xor( b, xor( c, xor( d, xor( e, xor( f, xor( g, h ) ) ) ) ) ) )
  * #define DA( a, bit )                ( ( (u8) a[bit/8] ) & ( (u8) ( 1 << bit%8 ) ) )
  *
- *     hash  = XOR8( DA(a,0), DA(a, 6), DA(a,12), DA(a,18), DA(a,24), DA(a,30), DA(a,36), DA(a,42) );
- *     hash |= XOR8( DA(a,1), DA(a, 7), DA(a,13), DA(a,19), DA(a,25), DA(a,31), DA(a,37), DA(a,43) ) << 1;
- *     hash |= XOR8( DA(a,2), DA(a, 8), DA(a,14), DA(a,20), DA(a,26), DA(a,32), DA(a,38), DA(a,44) ) << 2;
- *     hash |= XOR8( DA(a,3), DA(a, 9), DA(a,15), DA(a,21), DA(a,27), DA(a,33), DA(a,39), DA(a,45) ) << 3;
- *     hash |= XOR8( DA(a,4), DA(a,10), DA(a,16), DA(a,22), DA(a,28), DA(a,34), DA(a,40), DA(a,46) ) << 4;
- *     hash |= XOR8( DA(a,5), DA(a,11), DA(a,17), DA(a,23), DA(a,29), DA(a,35), DA(a,41), DA(a,47) ) << 5;
+ *     hash  = XOR8( DA(a,0), DA(a, 6), DA(a,12), DA(a,18), DA(a,24),
+ *                   DA(a,30), DA(a,36), DA(a,42) );
+ *     hash |= XOR8( DA(a,1), DA(a, 7), DA(a,13), DA(a,19), DA(a,25),
+ *                   DA(a,31), DA(a,37), DA(a,43) ) << 1;
+ *     hash |= XOR8( DA(a,2), DA(a, 8), DA(a,14), DA(a,20), DA(a,26),
+ *                   DA(a,32), DA(a,38), DA(a,44) ) << 2;
+ *     hash |= XOR8( DA(a,3), DA(a, 9), DA(a,15), DA(a,21), DA(a,27),
+ *                   DA(a,33), DA(a,39), DA(a,45) ) << 3;
+ *     hash |= XOR8( DA(a,4), DA(a,10), DA(a,16), DA(a,22), DA(a,28),
+ *                   DA(a,34), DA(a,40), DA(a,46) ) << 4;
+ *     hash |= XOR8( DA(a,5), DA(a,11), DA(a,17), DA(a,23), DA(a,29),
+ *                   DA(a,35), DA(a,41), DA(a,47) ) << 5;
  *
  */
 static inline u32 TLan_HashFunc( const u8 *a )
index 45208a0e69a095b876f2ba3fe3301f83cefcf985..7766cde0d63d99edb91da8b13e5dee6633efd6f5 100644 (file)
@@ -132,7 +132,6 @@ static void xl_dn_comp(struct net_device *dev);
 static int xl_close(struct net_device *dev);
 static void xl_set_rx_mode(struct net_device *dev);
 static irqreturn_t xl_interrupt(int irq, void *dev_id);
-static struct net_device_stats * xl_get_stats(struct net_device *dev);
 static int xl_set_mac_address(struct net_device *dev, void *addr) ; 
 static void xl_arb_cmd(struct net_device *dev);
 static void xl_asb_cmd(struct net_device *dev) ; 
@@ -343,7 +342,6 @@ static int __devinit xl_probe(struct pci_dev *pdev,
        dev->stop=&xl_close;
        dev->do_ioctl=NULL;
        dev->set_multicast_list=&xl_set_rx_mode;
-       dev->get_stats=&xl_get_stats ;
        dev->set_mac_address=&xl_set_mac_address ; 
        SET_NETDEV_DEV(dev, &pdev->dev);
 
@@ -921,7 +919,7 @@ static void xl_rx(struct net_device *dev)
                                        adv_rx_ring(dev) ; 
                                
                                adv_rx_ring(dev) ; /* One more time just for luck :) */ 
-                               xl_priv->xl_stats.rx_dropped++ ; 
+                               dev->stats.rx_dropped++ ; 
 
                                writel(ACK_INTERRUPT | UPCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; 
                                return ;                                
@@ -957,7 +955,7 @@ static void xl_rx(struct net_device *dev)
                        if (skb==NULL) { /* Still need to fix the rx ring */
                                printk(KERN_WARNING "%s: dev_alloc_skb failed in rx, single buffer \n",dev->name) ; 
                                adv_rx_ring(dev) ; 
-                               xl_priv->xl_stats.rx_dropped++ ; 
+                               dev->stats.rx_dropped++ ; 
                                writel(ACK_INTERRUPT | UPCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; 
                                return ; 
                        }
@@ -971,8 +969,8 @@ static void xl_rx(struct net_device *dev)
                        xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr = cpu_to_le32(pci_map_single(xl_priv->pdev,skb->data,xl_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE));
                        xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfraglen = cpu_to_le32(xl_priv->pkt_buf_sz) | RXUPLASTFRAG;
                        adv_rx_ring(dev) ; 
-                       xl_priv->xl_stats.rx_packets++ ; 
-                       xl_priv->xl_stats.rx_bytes += frame_length ;    
+                       dev->stats.rx_packets++ ; 
+                       dev->stats.rx_bytes += frame_length ;   
 
                        netif_rx(skb2) ;                
                 } /* if multiple buffers */
@@ -1182,8 +1180,8 @@ static int xl_xmit(struct sk_buff *skb, struct net_device *dev)
                txd->buffer = cpu_to_le32(pci_map_single(xl_priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE));
                txd->buffer_length = cpu_to_le32(skb->len) | TXDNFRAGLAST;
                xl_priv->tx_ring_skb[tx_head] = skb ; 
-               xl_priv->xl_stats.tx_packets++ ; 
-               xl_priv->xl_stats.tx_bytes += skb->len ;
+               dev->stats.tx_packets++ ; 
+               dev->stats.tx_bytes += skb->len ;
 
                /* 
                 * Set the nextptr of the previous descriptor equal to this descriptor, add XL_TX_RING_SIZE -1 
@@ -1463,12 +1461,6 @@ static void xl_srb_bh(struct net_device *dev)
        return ;        
 } 
 
-static struct net_device_stats * xl_get_stats(struct net_device *dev)
-{
-       struct xl_private *xl_priv = netdev_priv(dev);
-       return (struct net_device_stats *) &xl_priv->xl_stats; 
-}
-
 static int xl_set_mac_address (struct net_device *dev, void *addr) 
 {
        struct sockaddr *saddr = addr ; 
index 74cf8e1a181bd12e245449e197ba5c4e5d59e671..66b1ff603234774b1b4a1247af34dc4486afce9c 100644 (file)
@@ -273,8 +273,6 @@ struct xl_private {
        struct wait_queue *srb_wait;
        volatile int asb_queued;   
 
-       struct net_device_stats xl_stats ;
-
        u16 mac_buffer ;        
        u16 xl_lan_status ;
        u8 xl_ring_speed ;
index 6017d5267d08f4c80939834385cc7d3c591ca8be..febfaee44fe9474b58c1b3d695fa036940ff74a6 100644 (file)
@@ -803,7 +803,8 @@ static int tsi108_refill_rx(struct net_device *dev, int budget)
                int rx = data->rxhead;
                struct sk_buff *skb;
 
-               data->rxskbs[rx] = skb = dev_alloc_skb(TSI108_RXBUF_SIZE + 2);
+               data->rxskbs[rx] = skb = netdev_alloc_skb(dev,
+                                                         TSI108_RXBUF_SIZE + 2);
                if (!skb)
                        break;
 
@@ -1352,8 +1353,9 @@ static int tsi108_open(struct net_device *dev)
        data->rxhead = 0;
 
        for (i = 0; i < TSI108_RXRING_LEN; i++) {
-               struct sk_buff *skb = dev_alloc_skb(TSI108_RXBUF_SIZE + NET_IP_ALIGN);
+               struct sk_buff *skb;
 
+               skb = netdev_alloc_skb(dev, TSI108_RXBUF_SIZE + NET_IP_ALIGN);
                if (!skb) {
                        /* Bah.  No memory for now, but maybe we'll get
                         * some more later.
@@ -1526,7 +1528,7 @@ static int tsi108_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        struct tsi108_prv_data *data = netdev_priv(dev);
        unsigned long flags;
        int rc;
-       
+
        spin_lock_irqsave(&data->txlock, flags);
        rc = mii_ethtool_gset(&data->mii_if, cmd);
        spin_unlock_irqrestore(&data->txlock, flags);
@@ -1543,7 +1545,7 @@ static int tsi108_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        spin_lock_irqsave(&data->txlock, flags);
        rc = mii_ethtool_sset(&data->mii_if, cmd);
        spin_unlock_irqrestore(&data->txlock, flags);
-       
+
        return rc;
 }
 
index f5839c4a5cbd4760cf7e8d79b38fad49fad3dd42..cfbbfee55836b2f951ffafe304bdfc18e4ab7a45 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Author: Li Yang <leoli@freescale.com>
  *
- * Limitation: 
+ * Limitation:
  * Can only get/set setttings of the first queue.
  * Need to re-open the interface manually after changing some paramters.
  *
@@ -160,7 +160,7 @@ uec_set_pauseparam(struct net_device *netdev,
 
        ugeth->ug_info->receiveFlowControl = pause->rx_pause;
        ugeth->ug_info->transmitFlowControl = pause->tx_pause;
-       
+
        if (ugeth->phydev->autoneg) {
                if (netif_running(netdev)) {
                        /* FIXME: automatically restart */
index 6b8d882d197b4c450e25c302e238d462718226c8..bcbf2fa9b94abd4a700ba843e0148d18d7c58ef4 100644 (file)
@@ -1495,24 +1495,18 @@ static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb)
  *     enough. This function returns a negative value if the received
  *     packet is too big or if memory is exhausted.
  */
-static inline int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size,
-                                  struct velocity_info *vptr)
+static int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size,
+                           struct velocity_info *vptr)
 {
        int ret = -1;
-
        if (pkt_size < rx_copybreak) {
                struct sk_buff *new_skb;
 
-               new_skb = dev_alloc_skb(pkt_size + 2);
+               new_skb = netdev_alloc_skb(vptr->dev, pkt_size + 2);
                if (new_skb) {
-                       new_skb->dev = vptr->dev;
                        new_skb->ip_summed = rx_skb[0]->ip_summed;
-
-                       if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN)
-                               skb_reserve(new_skb, 2);
-
-                       skb_copy_from_linear_data(rx_skb[0], new_skb->data,
-                                                 pkt_size);
+                       skb_reserve(new_skb, 2);
+                       skb_copy_from_linear_data(*rx_skb, new_skb->data, pkt_size);
                        *rx_skb = new_skb;
                        ret = 0;
                }
@@ -1533,12 +1527,8 @@ static inline int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size,
 static inline void velocity_iph_realign(struct velocity_info *vptr,
                                        struct sk_buff *skb, int pkt_size)
 {
-       /* FIXME - memmove ? */
        if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) {
-               int i;
-
-               for (i = pkt_size; i >= 0; i--)
-                       *(skb->data + i + 2) = *(skb->data + i);
+               memmove(skb->data + 2, skb->data, pkt_size);
                skb_reserve(skb, 2);
        }
 }
@@ -1629,7 +1619,7 @@ static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx)
        struct rx_desc *rd = &(vptr->rd_ring[idx]);
        struct velocity_rd_info *rd_info = &(vptr->rd_info[idx]);
 
-       rd_info->skb = dev_alloc_skb(vptr->rx_buf_sz + 64);
+       rd_info->skb = netdev_alloc_skb(vptr->dev, vptr->rx_buf_sz + 64);
        if (rd_info->skb == NULL)
                return -ENOMEM;
 
@@ -1638,7 +1628,6 @@ static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx)
         *      64byte alignment.
         */
        skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->data & 63);
-       rd_info->skb->dev = vptr->dev;
        rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->data, vptr->rx_buf_sz, PCI_DMA_FROMDEVICE);
 
        /*
index 5c0d2b082750d550d7025b3e6716179ea6ea274a..0ba55ba9395884570a795632bcd34c1156716d5c 100644 (file)
@@ -306,11 +306,10 @@ static int adm8211_get_tx_stats(struct ieee80211_hw *dev,
                                struct ieee80211_tx_queue_stats *stats)
 {
        struct adm8211_priv *priv = dev->priv;
-       struct ieee80211_tx_queue_stats_data *data = &stats->data[0];
 
-       data->len = priv->cur_tx - priv->dirty_tx;
-       data->limit = priv->tx_ring_size - 2;
-       data->count = priv->dirty_tx;
+       stats[0].len = priv->cur_tx - priv->dirty_tx;
+       stats[0].limit = priv->tx_ring_size - 2;
+       stats[0].count = priv->dirty_tx;
 
        return 0;
 }
@@ -325,7 +324,7 @@ static void adm8211_interrupt_tci(struct ieee80211_hw *dev)
        for (dirty_tx = priv->dirty_tx; priv->cur_tx - dirty_tx; dirty_tx++) {
                unsigned int entry = dirty_tx % priv->tx_ring_size;
                u32 status = le32_to_cpu(priv->tx_ring[entry].status);
-               struct ieee80211_tx_status tx_status;
+               struct ieee80211_tx_info *txi;
                struct adm8211_tx_ring_info *info;
                struct sk_buff *skb;
 
@@ -335,24 +334,23 @@ static void adm8211_interrupt_tci(struct ieee80211_hw *dev)
 
                info = &priv->tx_buffers[entry];
                skb = info->skb;
+               txi = IEEE80211_SKB_CB(skb);
 
                /* TODO: check TDES0_STATUS_TUF and TDES0_STATUS_TRO */
 
                pci_unmap_single(priv->pdev, info->mapping,
                                 info->skb->len, PCI_DMA_TODEVICE);
 
-               memset(&tx_status, 0, sizeof(tx_status));
+               memset(&txi->status, 0, sizeof(txi->status));
                skb_pull(skb, sizeof(struct adm8211_tx_hdr));
                memcpy(skb_push(skb, info->hdrlen), skb->cb, info->hdrlen);
-               memcpy(&tx_status.control, &info->tx_control,
-                      sizeof(tx_status.control));
-               if (!(tx_status.control.flags & IEEE80211_TXCTL_NO_ACK)) {
+               if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) {
                        if (status & TDES0_STATUS_ES)
-                               tx_status.excessive_retries = 1;
+                               txi->status.excessive_retries = 1;
                        else
-                               tx_status.flags |= IEEE80211_TX_STATUS_ACK;
+                               txi->flags |= IEEE80211_TX_STAT_ACK;
                }
-               ieee80211_tx_status_irqsafe(dev, skb, &tx_status);
+               ieee80211_tx_status_irqsafe(dev, skb);
 
                info->skb = NULL;
        }
@@ -446,9 +444,9 @@ static void adm8211_interrupt_rci(struct ieee80211_hw *dev)
                        struct ieee80211_rx_status rx_status = {0};
 
                        if (priv->pdev->revision < ADM8211_REV_CA)
-                               rx_status.ssi = rssi;
+                               rx_status.signal = rssi;
                        else
-                               rx_status.ssi = 100 - rssi;
+                               rx_status.signal = 100 - rssi;
 
                        rx_status.rate_idx = rate;
 
@@ -1639,7 +1637,6 @@ static void adm8211_calc_durations(int *dur, int *plcp, size_t payload_len, int
 /* Transmit skb w/adm8211_tx_hdr (802.11 header created by hardware) */
 static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb,
                           u16 plcp_signal,
-                          struct ieee80211_tx_control *control,
                           size_t hdrlen)
 {
        struct adm8211_priv *priv = dev->priv;
@@ -1665,7 +1662,6 @@ static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb,
 
        priv->tx_buffers[entry].skb = skb;
        priv->tx_buffers[entry].mapping = mapping;
-       memcpy(&priv->tx_buffers[entry].tx_control, control, sizeof(*control));
        priv->tx_buffers[entry].hdrlen = hdrlen;
        priv->tx_ring[entry].buffer1 = cpu_to_le32(mapping);
 
@@ -1686,18 +1682,18 @@ static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb,
 }
 
 /* Put adm8211_tx_hdr on skb and transmit */
-static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
-                     struct ieee80211_tx_control *control)
+static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
        struct adm8211_tx_hdr *txhdr;
        u16 fc;
        size_t payload_len, hdrlen;
        int plcp, dur, len, plcp_signal, short_preamble;
        struct ieee80211_hdr *hdr;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, info);
 
-       short_preamble = !!(control->tx_rate->flags &
-                                       IEEE80211_TXCTL_SHORT_PREAMBLE);
-       plcp_signal = control->tx_rate->bitrate;
+       short_preamble = !!(txrate->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE);
+       plcp_signal = txrate->bitrate;
 
        hdr = (struct ieee80211_hdr *)skb->data;
        fc = le16_to_cpu(hdr->frame_control) & ~IEEE80211_FCTL_PROTECTED;
@@ -1731,15 +1727,15 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
        if (short_preamble)
                txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE);
 
-       if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
+       if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
                txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS);
 
        if (fc & IEEE80211_FCTL_PROTECTED)
                txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE);
 
-       txhdr->retry_limit = control->retry_limit;
+       txhdr->retry_limit = info->control.retry_limit;
 
-       adm8211_tx_raw(dev, skb, plcp_signal, control, hdrlen);
+       adm8211_tx_raw(dev, skb, plcp_signal, hdrlen);
 
        return NETDEV_TX_OK;
 }
@@ -1894,9 +1890,10 @@ static int __devinit adm8211_probe(struct pci_dev *pdev,
 
        dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr);
        /* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */
+       dev->flags = IEEE80211_HW_SIGNAL_UNSPEC;
 
        dev->channel_change_time = 1000;
-       dev->max_rssi = 100;    /* FIXME: find better value */
+       dev->max_signal = 100;    /* FIXME: find better value */
 
        dev->queues = 1; /* ADM8211C supports more, maybe ADM8211B too */
 
@@ -2015,7 +2012,7 @@ static int adm8211_resume(struct pci_dev *pdev)
 
        if (priv->mode != IEEE80211_IF_TYPE_INVALID) {
                adm8211_start(dev);
-               ieee80211_start_queues(dev);
+               ieee80211_wake_queues(dev);
        }
 
        return 0;
index 8d7c564b3b04209df209b3b415113d238a6e6fef..9b190ee26e903c291fa54aaa0c51e5153ace4d67 100644 (file)
@@ -443,7 +443,6 @@ struct adm8211_rx_ring_info {
 struct adm8211_tx_ring_info {
        struct sk_buff *skb;
        dma_addr_t mapping;
-       struct ieee80211_tx_control tx_control;
        size_t hdrlen;
 };
 
index 32019fb878d824c604fa84dcbc6082fee99bca87..1e1446bf4b488891dcfb1bd56bf82e2a60ffede9 100644 (file)
@@ -1148,7 +1148,6 @@ static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm);
 static void airo_networks_free(struct airo_info *ai);
 
 struct airo_info {
-       struct net_device_stats stats;
        struct net_device             *dev;
        struct list_head              dev_list;
        /* Note, we can have MAX_FIDS outstanding.  FIDs are 16-bits, so we
@@ -1924,7 +1923,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
        if (npacks >= MAXTXQ - 1) {
                netif_stop_queue (dev);
                if (npacks > MAXTXQ) {
-                       ai->stats.tx_fifo_errors++;
+                       dev->stats.tx_fifo_errors++;
                        return 1;
                }
                skb_queue_tail (&ai->txq, skb);
@@ -2044,13 +2043,13 @@ static void get_tx_error(struct airo_info *ai, s32 fid)
                bap_read(ai, &status, 2, BAP0);
        }
        if (le16_to_cpu(status) & 2) /* Too many retries */
-               ai->stats.tx_aborted_errors++;
+               ai->dev->stats.tx_aborted_errors++;
        if (le16_to_cpu(status) & 4) /* Transmit lifetime exceeded */
-               ai->stats.tx_heartbeat_errors++;
+               ai->dev->stats.tx_heartbeat_errors++;
        if (le16_to_cpu(status) & 8) /* Aid fail */
                { }
        if (le16_to_cpu(status) & 0x10) /* MAC disabled */
-               ai->stats.tx_carrier_errors++;
+               ai->dev->stats.tx_carrier_errors++;
        if (le16_to_cpu(status) & 0x20) /* Association lost */
                { }
        /* We produce a TXDROP event only for retry or lifetime
@@ -2102,7 +2101,7 @@ static void airo_end_xmit(struct net_device *dev) {
                for (; i < MAX_FIDS / 2 && (priv->fids[i] & 0xffff0000); i++);
        } else {
                priv->fids[fid] &= 0xffff;
-               priv->stats.tx_window_errors++;
+               dev->stats.tx_window_errors++;
        }
        if (i < MAX_FIDS / 2)
                netif_wake_queue(dev);
@@ -2128,7 +2127,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
                netif_stop_queue(dev);
 
                if (i == MAX_FIDS / 2) {
-                       priv->stats.tx_fifo_errors++;
+                       dev->stats.tx_fifo_errors++;
                        return 1;
                }
        }
@@ -2167,7 +2166,7 @@ static void airo_end_xmit11(struct net_device *dev) {
                for (; i < MAX_FIDS && (priv->fids[i] & 0xffff0000); i++);
        } else {
                priv->fids[fid] &= 0xffff;
-               priv->stats.tx_window_errors++;
+               dev->stats.tx_window_errors++;
        }
        if (i < MAX_FIDS)
                netif_wake_queue(dev);
@@ -2199,7 +2198,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
                netif_stop_queue(dev);
 
                if (i == MAX_FIDS) {
-                       priv->stats.tx_fifo_errors++;
+                       dev->stats.tx_fifo_errors++;
                        return 1;
                }
        }
@@ -2219,8 +2218,9 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
        return 0;
 }
 
-static void airo_read_stats(struct airo_info *ai)
+static void airo_read_stats(struct net_device *dev)
 {
+       struct airo_info *ai = dev->priv;
        StatsRid stats_rid;
        __le32 *vals = stats_rid.vals;
 
@@ -2232,23 +2232,24 @@ static void airo_read_stats(struct airo_info *ai)
        readStatsRid(ai, &stats_rid, RID_STATS, 0);
        up(&ai->sem);
 
-       ai->stats.rx_packets = le32_to_cpu(vals[43]) + le32_to_cpu(vals[44]) +
+       dev->stats.rx_packets = le32_to_cpu(vals[43]) + le32_to_cpu(vals[44]) +
                               le32_to_cpu(vals[45]);
-       ai->stats.tx_packets = le32_to_cpu(vals[39]) + le32_to_cpu(vals[40]) +
+       dev->stats.tx_packets = le32_to_cpu(vals[39]) + le32_to_cpu(vals[40]) +
                               le32_to_cpu(vals[41]);
-       ai->stats.rx_bytes = le32_to_cpu(vals[92]);
-       ai->stats.tx_bytes = le32_to_cpu(vals[91]);
-       ai->stats.rx_errors = le32_to_cpu(vals[0]) + le32_to_cpu(vals[2]) +
+       dev->stats.rx_bytes = le32_to_cpu(vals[92]);
+       dev->stats.tx_bytes = le32_to_cpu(vals[91]);
+       dev->stats.rx_errors = le32_to_cpu(vals[0]) + le32_to_cpu(vals[2]) +
                              le32_to_cpu(vals[3]) + le32_to_cpu(vals[4]);
-       ai->stats.tx_errors = le32_to_cpu(vals[42]) + ai->stats.tx_fifo_errors;
-       ai->stats.multicast = le32_to_cpu(vals[43]);
-       ai->stats.collisions = le32_to_cpu(vals[89]);
+       dev->stats.tx_errors = le32_to_cpu(vals[42]) +
+                             dev->stats.tx_fifo_errors;
+       dev->stats.multicast = le32_to_cpu(vals[43]);
+       dev->stats.collisions = le32_to_cpu(vals[89]);
 
        /* detailed rx_errors: */
-       ai->stats.rx_length_errors = le32_to_cpu(vals[3]);
-       ai->stats.rx_crc_errors = le32_to_cpu(vals[4]);
-       ai->stats.rx_frame_errors = le32_to_cpu(vals[2]);
-       ai->stats.rx_fifo_errors = le32_to_cpu(vals[0]);
+       dev->stats.rx_length_errors = le32_to_cpu(vals[3]);
+       dev->stats.rx_crc_errors = le32_to_cpu(vals[4]);
+       dev->stats.rx_frame_errors = le32_to_cpu(vals[2]);
+       dev->stats.rx_fifo_errors = le32_to_cpu(vals[0]);
 }
 
 static struct net_device_stats *airo_get_stats(struct net_device *dev)
@@ -2261,10 +2262,10 @@ static struct net_device_stats *airo_get_stats(struct net_device *dev)
                        set_bit(JOB_STATS, &local->jobs);
                        wake_up_interruptible(&local->thr_wait);
                } else
-                       airo_read_stats(local);
+                       airo_read_stats(dev);
        }
 
-       return &local->stats;
+       return &dev->stats;
 }
 
 static void airo_set_promisc(struct airo_info *ai) {
@@ -3093,7 +3094,7 @@ static int airo_thread(void *data) {
                else if (test_bit(JOB_XMIT11, &ai->jobs))
                        airo_end_xmit11(dev);
                else if (test_bit(JOB_STATS, &ai->jobs))
-                       airo_read_stats(ai);
+                       airo_read_stats(dev);
                else if (test_bit(JOB_WSTATS, &ai->jobs))
                        airo_read_wireless_stats(ai);
                else if (test_bit(JOB_PROMISC, &ai->jobs))
@@ -3289,7 +3290,7 @@ static irqreturn_t airo_interrupt(int irq, void *dev_id)
 
                        skb = dev_alloc_skb( len + hdrlen + 2 + 2 );
                        if ( !skb ) {
-                               apriv->stats.rx_dropped++;
+                               dev->stats.rx_dropped++;
                                goto badrx;
                        }
                        skb_reserve(skb, 2); /* This way the IP header is aligned */
@@ -3557,7 +3558,7 @@ static void mpi_receive_802_3(struct airo_info *ai)
 
                skb = dev_alloc_skb(len);
                if (!skb) {
-                       ai->stats.rx_dropped++;
+                       ai->dev->stats.rx_dropped++;
                        goto badrx;
                }
                buffer = skb_put(skb,len);
@@ -3650,7 +3651,7 @@ void mpi_receive_802_11 (struct airo_info *ai)
 
        skb = dev_alloc_skb( len + hdrlen + 2 );
        if ( !skb ) {
-               ai->stats.rx_dropped++;
+               ai->dev->stats.rx_dropped++;
                goto badrx;
        }
        buffer = (u16*)skb_put (skb, len + hdrlen);
index dbdfc9e39d20eec73f0e9424570010f9ac3022b0..dec5e874a54db0aef692c1a4c6966631ad144121 100644 (file)
@@ -125,7 +125,7 @@ static inline int arlan_drop_tx(struct net_device *dev)
 {
        struct arlan_private *priv = netdev_priv(dev);
 
-       priv->stats.tx_errors++;
+       dev->stats.tx_errors++;
        if (priv->Conf->tx_delay_ms)
        {
                priv->tx_done_delayed = jiffies + priv->Conf->tx_delay_ms * HZ / 1000 + 1;
@@ -1269,7 +1269,7 @@ static void arlan_tx_done_interrupt(struct net_device *dev, int status)
                {
                        IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
                                printk("arlan intr: transmit OK\n");
-                       priv->stats.tx_packets++;
+                       dev->stats.tx_packets++;
                        priv->bad = 0;
                        priv->reset = 0;
                        priv->retransmissions = 0;
@@ -1496,7 +1496,7 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short
                        if (skb == NULL)
                        {
                                printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name);
-                               priv->stats.rx_dropped++;
+                               dev->stats.rx_dropped++;
                                break;
                        }
                        skb_reserve(skb, 2);
@@ -1536,14 +1536,14 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short
                                }
                        netif_rx(skb);
                        dev->last_rx = jiffies;
-                       priv->stats.rx_packets++;
-                       priv->stats.rx_bytes += pkt_len;
+                       dev->stats.rx_packets++;
+                       dev->stats.rx_bytes += pkt_len;
                }
                break;
                
                default:
                        printk(KERN_ERR "arlan intr: received unknown status\n");
-                       priv->stats.rx_crc_errors++;
+                       dev->stats.rx_crc_errors++;
                        break;
        }
        ARLAN_DEBUG_EXIT("arlan_rx_interrupt");
@@ -1719,23 +1719,23 @@ static struct net_device_stats *arlan_statistics(struct net_device *dev)
 
        /* Update the statistics from the device registers. */
 
-       READSHM(priv->stats.collisions, arlan->numReTransmissions, u_int);
-       READSHM(priv->stats.rx_crc_errors, arlan->numCRCErrors, u_int);
-       READSHM(priv->stats.rx_dropped, arlan->numFramesDiscarded, u_int);
-       READSHM(priv->stats.rx_fifo_errors, arlan->numRXBufferOverflows, u_int);
-       READSHM(priv->stats.rx_frame_errors, arlan->numReceiveFramesLost, u_int);
-       READSHM(priv->stats.rx_over_errors, arlan->numRXOverruns, u_int);
-       READSHM(priv->stats.rx_packets, arlan->numDatagramsReceived, u_int);
-       READSHM(priv->stats.tx_aborted_errors, arlan->numAbortErrors, u_int);
-       READSHM(priv->stats.tx_carrier_errors, arlan->numStatusTimeouts, u_int);
-       READSHM(priv->stats.tx_dropped, arlan->numDatagramsDiscarded, u_int);
-       READSHM(priv->stats.tx_fifo_errors, arlan->numTXUnderruns, u_int);
-       READSHM(priv->stats.tx_packets, arlan->numDatagramsTransmitted, u_int);
-       READSHM(priv->stats.tx_window_errors, arlan->numHoldOffs, u_int);
+       READSHM(dev->stats.collisions, arlan->numReTransmissions, u_int);
+       READSHM(dev->stats.rx_crc_errors, arlan->numCRCErrors, u_int);
+       READSHM(dev->stats.rx_dropped, arlan->numFramesDiscarded, u_int);
+       READSHM(dev->stats.rx_fifo_errors, arlan->numRXBufferOverflows, u_int);
+       READSHM(dev->stats.rx_frame_errors, arlan->numReceiveFramesLost, u_int);
+       READSHM(dev->stats.rx_over_errors, arlan->numRXOverruns, u_int);
+       READSHM(dev->stats.rx_packets, arlan->numDatagramsReceived, u_int);
+       READSHM(dev->stats.tx_aborted_errors, arlan->numAbortErrors, u_int);
+       READSHM(dev->stats.tx_carrier_errors, arlan->numStatusTimeouts, u_int);
+       READSHM(dev->stats.tx_dropped, arlan->numDatagramsDiscarded, u_int);
+       READSHM(dev->stats.tx_fifo_errors, arlan->numTXUnderruns, u_int);
+       READSHM(dev->stats.tx_packets, arlan->numDatagramsTransmitted, u_int);
+       READSHM(dev->stats.tx_window_errors, arlan->numHoldOffs, u_int);
 
        ARLAN_DEBUG_EXIT("arlan_statistics");
 
-       return &priv->stats;
+       return &dev->stats;
 }
 
 
index 3ed1df75900f49f47d7ae163c3c9dddeabf9ac65..fb3ad51a1caf2a01817c8a1531d98f468a912367 100644 (file)
@@ -330,7 +330,6 @@ struct TxParam
 #define TX_RING_SIZE 2
 /* Information that need to be kept for each board. */
 struct arlan_private {
-      struct net_device_stats stats;
       struct arlan_shmem __iomem * card;
       struct arlan_shmem * conf;
 
index 635b9ac9aaa17589e40f41e7c455ecffc2558357..85045afc1ba718fbc2794f2c896af6c26fbe1032 100644 (file)
@@ -167,8 +167,7 @@ static struct pci_driver ath5k_pci_driver = {
 /*
  * Prototypes - MAC 802.11 stack related functions
  */
-static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
-               struct ieee80211_tx_control *ctl);
+static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
 static int ath5k_reset(struct ieee80211_hw *hw);
 static int ath5k_start(struct ieee80211_hw *hw);
 static void ath5k_stop(struct ieee80211_hw *hw);
@@ -196,8 +195,7 @@ static int ath5k_get_tx_stats(struct ieee80211_hw *hw,
 static u64 ath5k_get_tsf(struct ieee80211_hw *hw);
 static void ath5k_reset_tsf(struct ieee80211_hw *hw);
 static int ath5k_beacon_update(struct ieee80211_hw *hw,
-               struct sk_buff *skb,
-               struct ieee80211_tx_control *ctl);
+               struct sk_buff *skb);
 
 static struct ieee80211_ops ath5k_hw_ops = {
        .tx             = ath5k_tx,
@@ -251,9 +249,7 @@ static void ath5k_desc_free(struct ath5k_softc *sc,
 static int     ath5k_rxbuf_setup(struct ath5k_softc *sc,
                                struct ath5k_buf *bf);
 static int     ath5k_txbuf_setup(struct ath5k_softc *sc,
-                               struct ath5k_buf *bf,
-                               struct ieee80211_tx_control *ctl);
-
+                               struct ath5k_buf *bf);
 static inline void ath5k_txbuf_free(struct ath5k_softc *sc,
                                struct ath5k_buf *bf)
 {
@@ -289,8 +285,7 @@ static void         ath5k_tx_processq(struct ath5k_softc *sc,
 static void    ath5k_tasklet_tx(unsigned long data);
 /* Beacon handling */
 static int     ath5k_beacon_setup(struct ath5k_softc *sc,
-                               struct ath5k_buf *bf,
-                               struct ieee80211_tx_control *ctl);
+                                       struct ath5k_buf *bf);
 static void    ath5k_beacon_send(struct ath5k_softc *sc);
 static void    ath5k_beacon_config(struct ath5k_softc *sc);
 static void    ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf);
@@ -458,13 +453,11 @@ ath5k_pci_probe(struct pci_dev *pdev,
 
        /* Initialize driver private data */
        SET_IEEE80211_DEV(hw, &pdev->dev);
-       hw->flags = IEEE80211_HW_RX_INCLUDES_FCS;
+       hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+                   IEEE80211_HW_SIGNAL_DBM |
+                   IEEE80211_HW_NOISE_DBM;
        hw->extra_tx_headroom = 2;
        hw->channel_change_time = 5000;
-       /* these names are misleading */
-       hw->max_rssi = -110; /* signal in dBm */
-       hw->max_noise = -110; /* noise in dBm */
-       hw->max_signal = 100; /* we will provide a percentage based on rssi */
        sc = hw->priv;
        sc->hw = hw;
        sc->pdev = pdev;
@@ -1297,36 +1290,36 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
 }
 
 static int
-ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
-               struct ieee80211_tx_control *ctl)
+ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
 {
        struct ath5k_hw *ah = sc->ah;
        struct ath5k_txq *txq = sc->txq;
        struct ath5k_desc *ds = bf->desc;
        struct sk_buff *skb = bf->skb;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID;
        int ret;
 
        flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK;
-       bf->ctl = *ctl;
+
        /* XXX endianness */
        bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len,
                        PCI_DMA_TODEVICE);
 
-       if (ctl->flags & IEEE80211_TXCTL_NO_ACK)
+       if (info->flags & IEEE80211_TX_CTL_NO_ACK)
                flags |= AR5K_TXDESC_NOACK;
 
        pktlen = skb->len;
 
-       if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) {
-               keyidx = ctl->key_idx;
-               pktlen += ctl->icv_len;
+       if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) {
+               keyidx = info->control.hw_key->hw_key_idx;
+               pktlen += info->control.icv_len;
        }
-
        ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
                ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL,
-               (sc->power_level * 2), ctl->tx_rate->hw_value,
-               ctl->retry_limit, keyidx, 0, flags, 0, 0);
+               (sc->power_level * 2),
+               ieee80211_get_tx_rate(sc->hw, info)->hw_value,
+               info->control.retry_limit, keyidx, 0, flags, 0, 0);
        if (ret)
                goto err_unmap;
 
@@ -1335,7 +1328,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
 
        spin_lock_bh(&txq->lock);
        list_add_tail(&bf->list, &txq->q);
-       sc->tx_stats.data[txq->qnum].len++;
+       sc->tx_stats[txq->qnum].len++;
        if (txq->link == NULL) /* is this first packet? */
                ath5k_hw_put_tx_buf(ah, txq->qnum, bf->daddr);
        else /* no, so only link it */
@@ -1566,7 +1559,7 @@ ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq)
                ath5k_txbuf_free(sc, bf);
 
                spin_lock_bh(&sc->txbuflock);
-               sc->tx_stats.data[txq->qnum].len--;
+               sc->tx_stats[txq->qnum].len--;
                list_move_tail(&bf->list, &sc->txbuf);
                sc->txbuf_len++;
                spin_unlock_bh(&sc->txbuflock);
@@ -1601,7 +1594,7 @@ ath5k_txq_cleanup(struct ath5k_softc *sc)
                                        sc->txqs[i].link);
                        }
        }
-       ieee80211_start_queues(sc->hw); /* XXX move to callers */
+       ieee80211_wake_queues(sc->hw); /* XXX move to callers */
 
        for (i = 0; i < ARRAY_SIZE(sc->txqs); i++)
                if (sc->txqs[i].setup)
@@ -1895,20 +1888,9 @@ accept:
                rxs.freq = sc->curchan->center_freq;
                rxs.band = sc->curband->band;
 
-               /*
-                * signal quality:
-                * the names here are misleading and the usage of these
-                * values by iwconfig makes it even worse
-                */
-               /* noise floor in dBm, from the last noise calibration */
                rxs.noise = sc->ah->ah_noise_floor;
-               /* signal level in dBm */
-               rxs.ssi = rxs.noise + rs.rs_rssi;
-               /*
-                * "signal" is actually displayed as Link Quality by iwconfig
-                * we provide a percentage based on rssi (assuming max rssi 64)
-                */
-               rxs.signal = rs.rs_rssi * 100 / 64;
+               rxs.signal = rxs.noise + rs.rs_rssi;
+               rxs.qual = rs.rs_rssi * 100 / 64;
 
                rxs.antenna = rs.rs_antenna;
                rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);
@@ -1939,11 +1921,11 @@ next:
 static void
 ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
 {
-       struct ieee80211_tx_status txs = {};
        struct ath5k_tx_status ts = {};
        struct ath5k_buf *bf, *bf0;
        struct ath5k_desc *ds;
        struct sk_buff *skb;
+       struct ieee80211_tx_info *info;
        int ret;
 
        spin_lock(&txq->lock);
@@ -1963,28 +1945,29 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
                }
 
                skb = bf->skb;
+               info = IEEE80211_SKB_CB(skb);
                bf->skb = NULL;
+
                pci_unmap_single(sc->pdev, bf->skbaddr, skb->len,
                                PCI_DMA_TODEVICE);
 
-               txs.control = bf->ctl;
-               txs.retry_count = ts.ts_shortretry + ts.ts_longretry / 6;
+               info->status.retry_count = ts.ts_shortretry + ts.ts_longretry / 6;
                if (unlikely(ts.ts_status)) {
                        sc->ll_stats.dot11ACKFailureCount++;
                        if (ts.ts_status & AR5K_TXERR_XRETRY)
-                               txs.excessive_retries = 1;
+                               info->status.excessive_retries = 1;
                        else if (ts.ts_status & AR5K_TXERR_FILT)
-                               txs.flags |= IEEE80211_TX_STATUS_TX_FILTERED;
+                               info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
                } else {
-                       txs.flags |= IEEE80211_TX_STATUS_ACK;
-                       txs.ack_signal = ts.ts_rssi;
+                       info->flags |= IEEE80211_TX_STAT_ACK;
+                       info->status.ack_signal = ts.ts_rssi;
                }
 
-               ieee80211_tx_status(sc->hw, skb, &txs);
-               sc->tx_stats.data[txq->qnum].count++;
+               ieee80211_tx_status(sc->hw, skb);
+               sc->tx_stats[txq->qnum].count++;
 
                spin_lock(&sc->txbuflock);
-               sc->tx_stats.data[txq->qnum].len--;
+               sc->tx_stats[txq->qnum].len--;
                list_move_tail(&bf->list, &sc->txbuf);
                sc->txbuf_len++;
                spin_unlock(&sc->txbuflock);
@@ -2017,10 +2000,10 @@ ath5k_tasklet_tx(unsigned long data)
  * Setup the beacon frame for transmit.
  */
 static int
-ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
-               struct ieee80211_tx_control *ctl)
+ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
 {
        struct sk_buff *skb = bf->skb;
+       struct  ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ath5k_hw *ah = sc->ah;
        struct ath5k_desc *ds;
        int ret, antenna = 0;
@@ -2059,7 +2042,8 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
        ret = ah->ah_setup_tx_desc(ah, ds, skb->len,
                        ieee80211_get_hdrlen_from_skb(skb),
                        AR5K_PKT_TYPE_BEACON, (sc->power_level * 2),
-                       ctl->tx_rate->hw_value, 1, AR5K_TXKEYIX_INVALID,
+                       ieee80211_get_tx_rate(sc->hw, info)->hw_value,
+                       1, AR5K_TXKEYIX_INVALID,
                        antenna, flags, 0, 0);
        if (ret)
                goto err_unmap;
@@ -2637,11 +2621,11 @@ ath5k_led_event(struct ath5k_softc *sc, int event)
 \********************/
 
 static int
-ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
-                       struct ieee80211_tx_control *ctl)
+ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct ath5k_softc *sc = hw->priv;
        struct ath5k_buf *bf;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        unsigned long flags;
        int hdrlen;
        int pad;
@@ -2667,13 +2651,13 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
                memmove(skb->data, skb->data+pad, hdrlen);
        }
 
-       sc->led_txrate = ctl->tx_rate->hw_value;
+       sc->led_txrate = ieee80211_get_tx_rate(hw, info)->hw_value;
 
        spin_lock_irqsave(&sc->txbuflock, flags);
        if (list_empty(&sc->txbuf)) {
                ATH5K_ERR(sc, "no further txbuf available, dropping packet\n");
                spin_unlock_irqrestore(&sc->txbuflock, flags);
-               ieee80211_stop_queue(hw, ctl->queue);
+               ieee80211_stop_queue(hw, skb_get_queue_mapping(skb));
                return -1;
        }
        bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list);
@@ -2685,7 +2669,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
 
        bf->skb = skb;
 
-       if (ath5k_txbuf_setup(sc, bf, ctl)) {
+       if (ath5k_txbuf_setup(sc, bf)) {
                bf->skb = NULL;
                spin_lock_irqsave(&sc->txbuflock, flags);
                list_add_tail(&bf->list, &sc->txbuf);
@@ -3063,8 +3047,7 @@ ath5k_reset_tsf(struct ieee80211_hw *hw)
 }
 
 static int
-ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
-                       struct ieee80211_tx_control *ctl)
+ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct ath5k_softc *sc = hw->priv;
        int ret;
@@ -3080,7 +3063,7 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
 
        ath5k_txbuf_free(sc, sc->bbuf);
        sc->bbuf->skb = skb;
-       ret = ath5k_beacon_setup(sc, sc->bbuf, ctl);
+       ret = ath5k_beacon_setup(sc, sc->bbuf);
        if (ret)
                sc->bbuf->skb = NULL;
        else
index 3a97558930188302bdd00f61df9b6fe2bb29da28..bb4b26d523ab06177c695c9ed3fe1ec546344472 100644 (file)
@@ -60,7 +60,6 @@ struct ath5k_buf {
        dma_addr_t              daddr;  /* physical addr of desc */
        struct sk_buff          *skb;   /* skbuff for buf */
        dma_addr_t              skbaddr;/* physical addr of skb data */
-       struct ieee80211_tx_control ctl;
 };
 
 /*
@@ -92,7 +91,8 @@ struct ath5k_softc {
        struct pci_dev          *pdev;          /* for dma mapping */
        void __iomem            *iobase;        /* address of the device */
        struct mutex            lock;           /* dev-level lock */
-       struct ieee80211_tx_queue_stats tx_stats;
+       /* FIXME: how many does it really need? */
+       struct ieee80211_tx_queue_stats tx_stats[16];
        struct ieee80211_low_level_stats ll_stats;
        struct ieee80211_hw     *hw;            /* IEEE 802.11 common */
        struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
index 438e63ecccf1038f6402d1ee433b39dbfa3a8f73..7bb2646ae0ef4bb67ea9b651bfedd1ad5a7d8070 100644 (file)
@@ -433,7 +433,6 @@ struct atmel_private {
        struct net_device *dev;
        struct device *sys_dev;
        struct iw_statistics wstats;
-       struct net_device_stats stats;  // device stats
        spinlock_t irqlock, timerlock;  // spinlocks
        enum { BUS_TYPE_PCCARD, BUS_TYPE_PCI } bus_type;
        enum {
@@ -694,9 +693,9 @@ static void tx_done_irq(struct atmel_private *priv)
 
                if (type == TX_PACKET_TYPE_DATA) {
                        if (status == TX_STATUS_SUCCESS)
-                               priv->stats.tx_packets++;
+                               priv->dev->stats.tx_packets++;
                        else
-                               priv->stats.tx_errors++;
+                               priv->dev->stats.tx_errors++;
                        netif_wake_queue(priv->dev);
                }
        }
@@ -792,13 +791,13 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
 
        if (priv->card && priv->present_callback &&
            !(*priv->present_callback)(priv->card)) {
-               priv->stats.tx_errors++;
+               dev->stats.tx_errors++;
                dev_kfree_skb(skb);
                return 0;
        }
 
        if (priv->station_state != STATION_STATE_READY) {
-               priv->stats.tx_errors++;
+               dev->stats.tx_errors++;
                dev_kfree_skb(skb);
                return 0;
        }
@@ -815,7 +814,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
           initial + 18 (+30-12) */
 
        if (!(buff = find_tx_buff(priv, len + 18))) {
-               priv->stats.tx_dropped++;
+               dev->stats.tx_dropped++;
                spin_unlock_irqrestore(&priv->irqlock, flags);
                spin_unlock_bh(&priv->timerlock);
                netif_stop_queue(dev);
@@ -851,7 +850,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
        /* low bit of first byte of destination tells us if broadcast */
        tx_update_descriptor(priv, *(skb->data) & 0x01, len + 18, buff, TX_PACKET_TYPE_DATA);
        dev->trans_start = jiffies;
-       priv->stats.tx_bytes += len;
+       dev->stats.tx_bytes += len;
 
        spin_unlock_irqrestore(&priv->irqlock, flags);
        spin_unlock_bh(&priv->timerlock);
@@ -895,7 +894,7 @@ static void fast_rx_path(struct atmel_private *priv,
        }
 
        if (!(skb = dev_alloc_skb(msdu_size + 14))) {
-               priv->stats.rx_dropped++;
+               priv->dev->stats.rx_dropped++;
                return;
        }
 
@@ -908,7 +907,7 @@ static void fast_rx_path(struct atmel_private *priv,
                crc = crc32_le(crc, skbp + 12, msdu_size);
                atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + 30 + msdu_size, 4);
                if ((crc ^ 0xffffffff) != netcrc) {
-                       priv->stats.rx_crc_errors++;
+                       priv->dev->stats.rx_crc_errors++;
                        dev_kfree_skb(skb);
                        return;
                }
@@ -924,8 +923,8 @@ static void fast_rx_path(struct atmel_private *priv,
        skb->protocol = eth_type_trans(skb, priv->dev);
        skb->ip_summed = CHECKSUM_NONE;
        netif_rx(skb);
-       priv->stats.rx_bytes += 12 + msdu_size;
-       priv->stats.rx_packets++;
+       priv->dev->stats.rx_bytes += 12 + msdu_size;
+       priv->dev->stats.rx_packets++;
 }
 
 /* Test to see if the packet in card memory at packet_loc has a valid CRC
@@ -991,7 +990,7 @@ static void frag_rx_path(struct atmel_private *priv,
                        crc = crc32_le(crc, &priv->rx_buf[12], msdu_size);
                        atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4);
                        if ((crc ^ 0xffffffff) != netcrc) {
-                               priv->stats.rx_crc_errors++;
+                               priv->dev->stats.rx_crc_errors++;
                                memset(priv->frag_source, 0xff, 6);
                        }
                }
@@ -1009,7 +1008,7 @@ static void frag_rx_path(struct atmel_private *priv,
                                       msdu_size);
                        atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4);
                        if ((crc ^ 0xffffffff) != netcrc) {
-                               priv->stats.rx_crc_errors++;
+                               priv->dev->stats.rx_crc_errors++;
                                memset(priv->frag_source, 0xff, 6);
                                more_frags = 1; /* don't send broken assembly */
                        }
@@ -1021,7 +1020,7 @@ static void frag_rx_path(struct atmel_private *priv,
                if (!more_frags) { /* last one */
                        memset(priv->frag_source, 0xff, 6);
                        if (!(skb = dev_alloc_skb(priv->frag_len + 14))) {
-                               priv->stats.rx_dropped++;
+                               priv->dev->stats.rx_dropped++;
                        } else {
                                skb_reserve(skb, 2);
                                memcpy(skb_put(skb, priv->frag_len + 12),
@@ -1031,8 +1030,8 @@ static void frag_rx_path(struct atmel_private *priv,
                                skb->protocol = eth_type_trans(skb, priv->dev);
                                skb->ip_summed = CHECKSUM_NONE;
                                netif_rx(skb);
-                               priv->stats.rx_bytes += priv->frag_len + 12;
-                               priv->stats.rx_packets++;
+                               priv->dev->stats.rx_bytes += priv->frag_len + 12;
+                               priv->dev->stats.rx_packets++;
                        }
                }
        } else
@@ -1057,7 +1056,7 @@ static void rx_done_irq(struct atmel_private *priv)
                        if (status == 0xc1) /* determined by experiment */
                                priv->wstats.discard.nwid++;
                        else
-                               priv->stats.rx_errors++;
+                               priv->dev->stats.rx_errors++;
                        goto next;
                }
 
@@ -1065,7 +1064,7 @@ static void rx_done_irq(struct atmel_private *priv)
                rx_packet_loc = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_POS_OFFSET, priv->rx_desc_head));
 
                if (msdu_size < 30) {
-                       priv->stats.rx_errors++;
+                       priv->dev->stats.rx_errors++;
                        goto next;
                }
 
@@ -1123,7 +1122,7 @@ static void rx_done_irq(struct atmel_private *priv)
                                msdu_size -= 4;
                                crc = crc32_le(crc, (unsigned char *)&priv->rx_buf, msdu_size);
                                if ((crc ^ 0xffffffff) != (*((u32 *)&priv->rx_buf[msdu_size]))) {
-                                       priv->stats.rx_crc_errors++;
+                                       priv->dev->stats.rx_crc_errors++;
                                        goto next;
                                }
                        }
@@ -1250,12 +1249,6 @@ static irqreturn_t service_interrupt(int irq, void *dev_id)
        }
 }
 
-static struct net_device_stats *atmel_get_stats(struct net_device *dev)
-{
-       struct atmel_private *priv = netdev_priv(dev);
-       return &priv->stats;
-}
-
 static struct iw_statistics *atmel_get_wireless_stats(struct net_device *dev)
 {
        struct atmel_private *priv = netdev_priv(dev);
@@ -1518,8 +1511,6 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
                priv->crc_ok_cnt = priv->crc_ko_cnt = 0;
        } else
                priv->probe_crc = 0;
-       memset(&priv->stats, 0, sizeof(priv->stats));
-       memset(&priv->wstats, 0, sizeof(priv->wstats));
        priv->last_qual = jiffies;
        priv->last_beacon_timestamp = 0;
        memset(priv->frag_source, 0xff, sizeof(priv->frag_source));
@@ -1568,7 +1559,6 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
        dev->change_mtu = atmel_change_mtu;
        dev->set_mac_address = atmel_set_mac_address;
        dev->hard_start_xmit = start_tx;
-       dev->get_stats = atmel_get_stats;
        dev->wireless_handlers = (struct iw_handler_def *)&atmel_handler_def;
        dev->do_ioctl = atmel_ioctl;
        dev->irq = irq;
index dfa4bdd5597c6a6909b6d11a08d25188f06af9e3..239e71c3d1b1106fae7377e8b49ba965af29e080 100644 (file)
@@ -410,8 +410,7 @@ enum {
 #define B43_IRQ_TIMEOUT                        0x80000000
 
 #define B43_IRQ_ALL                    0xFFFFFFFF
-#define B43_IRQ_MASKTEMPLATE           (B43_IRQ_MAC_SUSPENDED | \
-                                        B43_IRQ_TBTT_INDI | \
+#define B43_IRQ_MASKTEMPLATE           (B43_IRQ_TBTT_INDI | \
                                         B43_IRQ_ATIM_END | \
                                         B43_IRQ_PMQ | \
                                         B43_IRQ_MAC_TXERR | \
@@ -423,6 +422,26 @@ enum {
                                         B43_IRQ_RFKILL | \
                                         B43_IRQ_TX_OK)
 
+/* The firmware register to fetch the debug-IRQ reason from. */
+#define B43_DEBUGIRQ_REASON_REG                63
+/* Debug-IRQ reasons. */
+#define B43_DEBUGIRQ_PANIC             0       /* The firmware panic'ed */
+#define B43_DEBUGIRQ_DUMP_SHM          1       /* Dump shared SHM */
+#define B43_DEBUGIRQ_DUMP_REGS         2       /* Dump the microcode registers */
+#define B43_DEBUGIRQ_MARKER            3       /* A "marker" was thrown by the firmware. */
+#define B43_DEBUGIRQ_ACK               0xFFFF  /* The host writes that to ACK the IRQ */
+
+/* The firmware register that contains the "marker" line. */
+#define B43_MARKER_ID_REG              2
+#define B43_MARKER_LINE_REG            3
+
+/* The firmware register to fetch the panic reason from. */
+#define B43_FWPANIC_REASON_REG         3
+/* Firmware panic reason codes */
+#define B43_FWPANIC_DIE                        0 /* Firmware died. Don't auto-restart it. */
+#define B43_FWPANIC_RESTART            1 /* Firmware died. Schedule a controller reset. */
+
+
 /* Device specific rate values.
  * The actual values defined here are (rate_in_mbps * 2).
  * Some code depends on this. Don't change it. */
@@ -734,7 +753,6 @@ struct b43_wl {
        /* The beacon we are currently using (AP or IBSS mode).
         * This beacon stuff is protected by the irq_lock. */
        struct sk_buff *current_beacon;
-       struct ieee80211_tx_control beacon_txctl;
        bool beacon0_uploaded;
        bool beacon1_uploaded;
        bool beacon_templates_virgin; /* Never wrote the templates? */
@@ -768,6 +786,13 @@ struct b43_firmware {
        u16 rev;
        /* Firmware patchlevel */
        u16 patch;
+
+       /* Set to true, if we are using an opensource firmware. */
+       bool opensource;
+       /* Set to true, if the core needs a PCM firmware, but
+        * we failed to load one. This is always false for
+        * core rev > 10, as these don't need PCM firmware. */
+       bool pcm_request_failed;
 };
 
 /* Device (802.11 core) initialization status. */
@@ -941,22 +966,6 @@ static inline bool __b43_warn_on_dummy(bool x) { return x; }
 # define B43_WARN_ON(x)        __b43_warn_on_dummy(unlikely(!!(x)))
 #endif
 
-/** Limit a value between two limits */
-#ifdef limit_value
-# undef limit_value
-#endif
-#define limit_value(value, min, max)  \
-       ({                                              \
-               typeof(value) __value = (value);        \
-               typeof(value) __min = (min);            \
-               typeof(value) __max = (max);            \
-               if (__value < __min)                    \
-                       __value = __min;                \
-               else if (__value > __max)               \
-                       __value = __max;                \
-               __value;                                \
-       })
-
 /* Convert an integer to a Q5.2 value */
 #define INT_TO_Q52(i)  ((i) << 2)
 /* Convert a Q5.2 value to an integer (precision loss!) */
index 7fca2ebc747f09b11e017bca3834b4eb73c7fd3f..210e2789c1c366fe116092f49720c1072ce80480 100644 (file)
@@ -270,24 +270,22 @@ static int restart_write_file(struct b43_wldev *dev,
        return err;
 }
 
-static ssize_t append_lo_table(ssize_t count, char *buf, const size_t bufsize,
-                              struct b43_loctl table[B43_NR_BB][B43_NR_RF])
+static unsigned long calc_expire_secs(unsigned long now,
+                                     unsigned long time,
+                                     unsigned long expire)
 {
-       unsigned int i, j;
-       struct b43_loctl *ctl;
-
-       for (i = 0; i < B43_NR_BB; i++) {
-               for (j = 0; j < B43_NR_RF; j++) {
-                       ctl = &(table[i][j]);
-                       fappend("(bbatt %2u, rfatt %2u)  ->  "
-                               "(I %+3d, Q %+3d, Used: %d, Calibrated: %d)\n",
-                               i, j, ctl->i, ctl->q,
-                               ctl->used,
-                               b43_loctl_is_calibrated(ctl));
-               }
+       expire = time + expire;
+
+       if (time_after(now, expire))
+               return 0; /* expired */
+       if (expire < now) {
+               /* jiffies wrapped */
+               expire -= MAX_JIFFY_OFFSET;
+               now -= MAX_JIFFY_OFFSET;
        }
+       B43_WARN_ON(expire < now);
 
-       return count;
+       return (expire - now) / HZ;
 }
 
 static ssize_t loctls_read_file(struct b43_wldev *dev,
@@ -296,27 +294,45 @@ static ssize_t loctls_read_file(struct b43_wldev *dev,
        ssize_t count = 0;
        struct b43_txpower_lo_control *lo;
        int i, err = 0;
+       struct b43_lo_calib *cal;
+       unsigned long now = jiffies;
+       struct b43_phy *phy = &dev->phy;
 
-       if (dev->phy.type != B43_PHYTYPE_G) {
+       if (phy->type != B43_PHYTYPE_G) {
                fappend("Device is not a G-PHY\n");
                err = -ENODEV;
                goto out;
        }
-       lo = dev->phy.lo_control;
+       lo = phy->lo_control;
        fappend("-- Local Oscillator calibration data --\n\n");
-       fappend("Measured: %d,  Rebuild: %d,  HW-power-control: %d\n",
-               lo->lo_measured,
-               lo->rebuild,
+       fappend("HW-power-control enabled: %d\n",
                dev->phy.hardware_power_control);
-       fappend("TX Bias: 0x%02X,  TX Magn: 0x%02X\n",
-               lo->tx_bias, lo->tx_magn);
-       fappend("Power Vector: 0x%08X%08X\n",
+       fappend("TX Bias: 0x%02X,  TX Magn: 0x%02X  (expire in %lu sec)\n",
+               lo->tx_bias, lo->tx_magn,
+               calc_expire_secs(now, lo->txctl_measured_time,
+                                B43_LO_TXCTL_EXPIRE));
+       fappend("Power Vector: 0x%08X%08X  (expires in %lu sec)\n",
                (unsigned int)((lo->power_vector & 0xFFFFFFFF00000000ULL) >> 32),
-               (unsigned int)(lo->power_vector & 0x00000000FFFFFFFFULL));
-       fappend("\nControl table WITH PADMIX:\n");
-       count = append_lo_table(count, buf, bufsize, lo->with_padmix);
-       fappend("\nControl table WITHOUT PADMIX:\n");
-       count = append_lo_table(count, buf, bufsize, lo->no_padmix);
+               (unsigned int)(lo->power_vector & 0x00000000FFFFFFFFULL),
+               calc_expire_secs(now, lo->pwr_vec_read_time,
+                                B43_LO_PWRVEC_EXPIRE));
+
+       fappend("\nCalibrated settings:\n");
+       list_for_each_entry(cal, &lo->calib_list, list) {
+               bool active;
+
+               active = (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) &&
+                         b43_compare_rfatt(&cal->rfatt, &phy->rfatt));
+               fappend("BB(%d), RF(%d,%d)  ->  I=%d, Q=%d  "
+                       "(expires in %lu sec)%s\n",
+                       cal->bbatt.att,
+                       cal->rfatt.att, cal->rfatt.with_padmix,
+                       cal->ctl.i, cal->ctl.q,
+                       calc_expire_secs(now, cal->calib_time,
+                                        B43_LO_CALIB_EXPIRE),
+                       active ? "  ACTIVE" : "");
+       }
+
        fappend("\nUsed RF attenuation values:  Value(WithPadmix flag)\n");
        for (i = 0; i < lo->rfatt_list.len; i++) {
                fappend("%u(%d), ",
@@ -351,7 +367,7 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
        struct b43_dfs_file *dfile;
        ssize_t uninitialized_var(ret);
        char *buf;
-       const size_t bufsize = 1024 * 128;
+       const size_t bufsize = 1024 * 16; /* 16 kiB buffer */
        const size_t buforder = get_order(bufsize);
        int err = 0;
 
@@ -380,8 +396,6 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
                        err = -ENOMEM;
                        goto out_unlock;
                }
-               /* Sparse warns about the following memset, because it has a big
-                * size value. That warning is bogus, so I will ignore it. --mb */
                memset(buf, 0, bufsize);
                if (dfops->take_irqlock) {
                        spin_lock_irq(&dev->wl->irq_lock);
@@ -523,6 +537,7 @@ static void b43_add_dynamic_debug(struct b43_wldev *dev)
        add_dyn_dbg("debug_dmaverbose", B43_DBG_DMAVERBOSE, 0);
        add_dyn_dbg("debug_pwork_fast", B43_DBG_PWORK_FAST, 0);
        add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0);
+       add_dyn_dbg("debug_lo", B43_DBG_LO, 0);
 
 #undef add_dyn_dbg
 }
index 6eebe858db5af265d51dbfb884ab0cf2e7110b57..c75cff4151d9a7609b05ffcbcf42262eaa3b654b 100644 (file)
@@ -10,6 +10,7 @@ enum b43_dyndbg {             /* Dynamic debugging features */
        B43_DBG_DMAVERBOSE,
        B43_DBG_PWORK_FAST,
        B43_DBG_PWORK_STOP,
+       B43_DBG_LO,
        __B43_NR_DYNDBG,
 };
 
index 6dcbb3c87e7207a01cf64f2269f3cea1438cfe04..b4eadd908beabc46675dd356b0cdc373a8010224 100644 (file)
@@ -1131,10 +1131,10 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot)
 }
 
 static int dma_tx_fragment(struct b43_dmaring *ring,
-                          struct sk_buff *skb,
-                          struct ieee80211_tx_control *ctl)
+                          struct sk_buff *skb)
 {
        const struct b43_dma_ops *ops = ring->ops;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        u8 *header;
        int slot, old_top_slot, old_used_slots;
        int err;
@@ -1158,7 +1158,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
        header = &(ring->txhdr_cache[slot * hdrsize]);
        cookie = generate_cookie(ring, slot);
        err = b43_generate_txhdr(ring->dev, header,
-                                skb->data, skb->len, ctl, cookie);
+                                skb->data, skb->len, info, cookie);
        if (unlikely(err)) {
                ring->current_slot = old_top_slot;
                ring->used_slots = old_used_slots;
@@ -1180,7 +1180,6 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
        desc = ops->idx2desc(ring, slot, &meta);
        memset(meta, 0, sizeof(*meta));
 
-       memcpy(&meta->txstat.control, ctl, sizeof(*ctl));
        meta->skb = skb;
        meta->is_last_fragment = 1;
 
@@ -1210,7 +1209,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
 
        ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1);
 
-       if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) {
+       if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
                /* Tell the firmware about the cookie of the last
                 * mcast frame, so it can clear the more-data bit in it. */
                b43_shm_write16(ring->dev, B43_SHM_SHARED,
@@ -1281,16 +1280,16 @@ static struct b43_dmaring * select_ring_by_priority(struct b43_wldev *dev,
        return ring;
 }
 
-int b43_dma_tx(struct b43_wldev *dev,
-              struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb)
 {
        struct b43_dmaring *ring;
        struct ieee80211_hdr *hdr;
        int err = 0;
        unsigned long flags;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
        hdr = (struct ieee80211_hdr *)skb->data;
-       if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) {
+       if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
                /* The multicast ring will be sent after the DTIM */
                ring = dev->dma.tx_ring_mcast;
                /* Set the more-data bit. Ucode will clear it on
@@ -1298,7 +1297,8 @@ int b43_dma_tx(struct b43_wldev *dev,
                hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
        } else {
                /* Decide by priority where to put this frame. */
-               ring = select_ring_by_priority(dev, ctl->queue);
+               ring = select_ring_by_priority(
+                       dev, skb_get_queue_mapping(skb));
        }
 
        spin_lock_irqsave(&ring->lock, flags);
@@ -1316,9 +1316,9 @@ int b43_dma_tx(struct b43_wldev *dev,
        /* Assign the queue number to the ring (if not already done before)
         * so TX status handling can use it. The queue to ring mapping is
         * static, so we don't need to store it per frame. */
-       ring->queue_prio = ctl->queue;
+       ring->queue_prio = skb_get_queue_mapping(skb);
 
-       err = dma_tx_fragment(ring, skb, ctl);
+       err = dma_tx_fragment(ring, skb);
        if (unlikely(err == -ENOKEY)) {
                /* Drop this packet, as we don't have the encryption key
                 * anymore and must not transmit it unencrypted. */
@@ -1334,7 +1334,7 @@ int b43_dma_tx(struct b43_wldev *dev,
        if ((free_slots(ring) < SLOTS_PER_PACKET) ||
            should_inject_overflow(ring)) {
                /* This TX ring is full. */
-               ieee80211_stop_queue(dev->wl->hw, ctl->queue);
+               ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb));
                ring->stopped = 1;
                if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {
                        b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index);
@@ -1377,13 +1377,19 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
                                         b43_txhdr_size(dev), 1);
 
                if (meta->is_last_fragment) {
-                       B43_WARN_ON(!meta->skb);
-                       /* Call back to inform the ieee80211 subsystem about the
-                        * status of the transmission.
-                        * Some fields of txstat are already filled in dma_tx().
+                       struct ieee80211_tx_info *info;
+
+                       BUG_ON(!meta->skb);
+
+                       info = IEEE80211_SKB_CB(meta->skb);
+
+                       memset(&info->status, 0, sizeof(info->status));
+
+                       /*
+                        * Call back to inform the ieee80211 subsystem about
+                        * the status of the transmission.
                         */
-                       frame_succeed = b43_fill_txstatus_report(
-                                               &(meta->txstat), status);
+                       frame_succeed = b43_fill_txstatus_report(info, status);
 #ifdef CONFIG_B43_DEBUG
                        if (frame_succeed)
                                ring->nr_succeed_tx_packets++;
@@ -1391,8 +1397,8 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
                                ring->nr_failed_tx_packets++;
                        ring->nr_total_packet_tries += status->frame_count;
 #endif /* DEBUG */
-                       ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb,
-                                                   &(meta->txstat));
+                       ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb);
+
                        /* skb is freed by ieee80211_tx_status_irqsafe() */
                        meta->skb = NULL;
                } else {
@@ -1427,18 +1433,16 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev,
 {
        const int nr_queues = dev->wl->hw->queues;
        struct b43_dmaring *ring;
-       struct ieee80211_tx_queue_stats_data *data;
        unsigned long flags;
        int i;
 
        for (i = 0; i < nr_queues; i++) {
-               data = &(stats->data[i]);
                ring = select_ring_by_priority(dev, i);
 
                spin_lock_irqsave(&ring->lock, flags);
-               data->len = ring->used_slots / SLOTS_PER_PACKET;
-               data->limit = ring->nr_slots / SLOTS_PER_PACKET;
-               data->count = ring->nr_tx_packets;
+               stats[i].len = ring->used_slots / SLOTS_PER_PACKET;
+               stats[i].limit = ring->nr_slots / SLOTS_PER_PACKET;
+               stats[i].count = ring->nr_tx_packets;
                spin_unlock_irqrestore(&ring->lock, flags);
        }
 }
index 20acf885dba5aa1d215452039226a665da055689..d1eb5c0848a522edb6a9348366070e4e46980ddd 100644 (file)
@@ -181,7 +181,6 @@ struct b43_dmadesc_meta {
        dma_addr_t dmaaddr;
        /* ieee80211 TX status. Only used once per 802.11 frag. */
        bool is_last_fragment;
-       struct ieee80211_tx_status txstat;
 };
 
 struct b43_dmaring;
@@ -285,7 +284,7 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev,
                          struct ieee80211_tx_queue_stats *stats);
 
 int b43_dma_tx(struct b43_wldev *dev,
-              struct sk_buff *skb, struct ieee80211_tx_control *ctl);
+              struct sk_buff *skb);
 void b43_dma_handle_txstatus(struct b43_wldev *dev,
                             const struct b43_txstatus *status);
 
index d890f366a23b76a021a18807238c54fdf09b9d31..9c854d6aae36662b33f36c7d0bc3c45c002e7eef 100644 (file)
 #include <linux/sched.h>
 
 
-/* Define to 1 to always calibrate all possible LO control pairs.
- * This is a workaround until we fix the partial LO calibration optimization. */
-#define B43_CALIB_ALL_LOCTLS   1
+static struct b43_lo_calib * b43_find_lo_calib(struct b43_txpower_lo_control *lo,
+                                              const struct b43_bbatt *bbatt,
+                                              const struct b43_rfatt *rfatt)
+{
+       struct b43_lo_calib *c;
+
+       list_for_each_entry(c, &lo->calib_list, list) {
+               if (!b43_compare_bbatt(&c->bbatt, bbatt))
+                       continue;
+               if (!b43_compare_rfatt(&c->rfatt, rfatt))
+                       continue;
+               return c;
+       }
 
+       return NULL;
+}
 
 /* Write the LocalOscillator Control (adjust) value-pair. */
 static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control)
 {
        struct b43_phy *phy = &dev->phy;
        u16 value;
-       u16 reg;
 
        if (B43_DEBUG) {
                if (unlikely(abs(control->i) > 16 || abs(control->q) > 16)) {
@@ -56,189 +67,11 @@ static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control)
                        return;
                }
        }
+       B43_WARN_ON(phy->type != B43_PHYTYPE_G);
 
        value = (u8) (control->q);
        value |= ((u8) (control->i)) << 8;
-
-       reg = (phy->type == B43_PHYTYPE_B) ? 0x002F : B43_PHY_LO_CTL;
-       b43_phy_write(dev, reg, value);
-}
-
-static int assert_rfatt_and_bbatt(const struct b43_rfatt *rfatt,
-                                 const struct b43_bbatt *bbatt,
-                                 struct b43_wldev *dev)
-{
-       int err = 0;
-
-       /* Check the attenuation values against the LO control array sizes. */
-       if (unlikely(rfatt->att >= B43_NR_RF)) {
-               b43err(dev->wl, "rfatt(%u) >= size of LO array\n", rfatt->att);
-               err = -EINVAL;
-       }
-       if (unlikely(bbatt->att >= B43_NR_BB)) {
-               b43err(dev->wl, "bbatt(%u) >= size of LO array\n", bbatt->att);
-               err = -EINVAL;
-       }
-
-       return err;
-}
-
-#if !B43_CALIB_ALL_LOCTLS
-static
-struct b43_loctl *b43_get_lo_g_ctl_nopadmix(struct b43_wldev *dev,
-                                           const struct b43_rfatt *rfatt,
-                                           const struct b43_bbatt *bbatt)
-{
-       struct b43_phy *phy = &dev->phy;
-       struct b43_txpower_lo_control *lo = phy->lo_control;
-
-       if (assert_rfatt_and_bbatt(rfatt, bbatt, dev))
-               return &(lo->no_padmix[0][0]);  /* Just prevent a crash */
-       return &(lo->no_padmix[bbatt->att][rfatt->att]);
-}
-#endif /* !B43_CALIB_ALL_LOCTLS */
-
-struct b43_loctl *b43_get_lo_g_ctl(struct b43_wldev *dev,
-                                  const struct b43_rfatt *rfatt,
-                                  const struct b43_bbatt *bbatt)
-{
-       struct b43_phy *phy = &dev->phy;
-       struct b43_txpower_lo_control *lo = phy->lo_control;
-
-       if (assert_rfatt_and_bbatt(rfatt, bbatt, dev))
-               return &(lo->no_padmix[0][0]);  /* Just prevent a crash */
-       if (rfatt->with_padmix)
-               return &(lo->with_padmix[bbatt->att][rfatt->att]);
-       return &(lo->no_padmix[bbatt->att][rfatt->att]);
-}
-
-/* Call a function for every possible LO control value-pair. */
-static void b43_call_for_each_loctl(struct b43_wldev *dev,
-                                   void (*func) (struct b43_wldev *,
-                                                 struct b43_loctl *))
-{
-       struct b43_phy *phy = &dev->phy;
-       struct b43_txpower_lo_control *ctl = phy->lo_control;
-       int i, j;
-
-       for (i = 0; i < B43_NR_BB; i++) {
-               for (j = 0; j < B43_NR_RF; j++)
-                       func(dev, &(ctl->with_padmix[i][j]));
-       }
-       for (i = 0; i < B43_NR_BB; i++) {
-               for (j = 0; j < B43_NR_RF; j++)
-                       func(dev, &(ctl->no_padmix[i][j]));
-       }
-}
-
-static u16 lo_b_r15_loop(struct b43_wldev *dev)
-{
-       int i;
-       u16 ret = 0;
-
-       for (i = 0; i < 10; i++) {
-               b43_phy_write(dev, 0x0015, 0xAFA0);
-               udelay(1);
-               b43_phy_write(dev, 0x0015, 0xEFA0);
-               udelay(10);
-               b43_phy_write(dev, 0x0015, 0xFFA0);
-               udelay(40);
-               ret += b43_phy_read(dev, 0x002C);
-       }
-
-       return ret;
-}
-
-void b43_lo_b_measure(struct b43_wldev *dev)
-{
-       struct b43_phy *phy = &dev->phy;
-       u16 regstack[12] = { 0 };
-       u16 mls;
-       u16 fval;
-       int i, j;
-
-       regstack[0] = b43_phy_read(dev, 0x0015);
-       regstack[1] = b43_radio_read16(dev, 0x0052) & 0xFFF0;
-
-       if (phy->radio_ver == 0x2053) {
-               regstack[2] = b43_phy_read(dev, 0x000A);
-               regstack[3] = b43_phy_read(dev, 0x002A);
-               regstack[4] = b43_phy_read(dev, 0x0035);
-               regstack[5] = b43_phy_read(dev, 0x0003);
-               regstack[6] = b43_phy_read(dev, 0x0001);
-               regstack[7] = b43_phy_read(dev, 0x0030);
-
-               regstack[8] = b43_radio_read16(dev, 0x0043);
-               regstack[9] = b43_radio_read16(dev, 0x007A);
-               regstack[10] = b43_read16(dev, 0x03EC);
-               regstack[11] = b43_radio_read16(dev, 0x0052) & 0x00F0;
-
-               b43_phy_write(dev, 0x0030, 0x00FF);
-               b43_write16(dev, 0x03EC, 0x3F3F);
-               b43_phy_write(dev, 0x0035, regstack[4] & 0xFF7F);
-               b43_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0);
-       }
-       b43_phy_write(dev, 0x0015, 0xB000);
-       b43_phy_write(dev, 0x002B, 0x0004);
-
-       if (phy->radio_ver == 0x2053) {
-               b43_phy_write(dev, 0x002B, 0x0203);
-               b43_phy_write(dev, 0x002A, 0x08A3);
-       }
-
-       phy->minlowsig[0] = 0xFFFF;
-
-       for (i = 0; i < 4; i++) {
-               b43_radio_write16(dev, 0x0052, regstack[1] | i);
-               lo_b_r15_loop(dev);
-       }
-       for (i = 0; i < 10; i++) {
-               b43_radio_write16(dev, 0x0052, regstack[1] | i);
-               mls = lo_b_r15_loop(dev) / 10;
-               if (mls < phy->minlowsig[0]) {
-                       phy->minlowsig[0] = mls;
-                       phy->minlowsigpos[0] = i;
-               }
-       }
-       b43_radio_write16(dev, 0x0052, regstack[1] | phy->minlowsigpos[0]);
-
-       phy->minlowsig[1] = 0xFFFF;
-
-       for (i = -4; i < 5; i += 2) {
-               for (j = -4; j < 5; j += 2) {
-                       if (j < 0)
-                               fval = (0x0100 * i) + j + 0x0100;
-                       else
-                               fval = (0x0100 * i) + j;
-                       b43_phy_write(dev, 0x002F, fval);
-                       mls = lo_b_r15_loop(dev) / 10;
-                       if (mls < phy->minlowsig[1]) {
-                               phy->minlowsig[1] = mls;
-                               phy->minlowsigpos[1] = fval;
-                       }
-               }
-       }
-       phy->minlowsigpos[1] += 0x0101;
-
-       b43_phy_write(dev, 0x002F, phy->minlowsigpos[1]);
-       if (phy->radio_ver == 0x2053) {
-               b43_phy_write(dev, 0x000A, regstack[2]);
-               b43_phy_write(dev, 0x002A, regstack[3]);
-               b43_phy_write(dev, 0x0035, regstack[4]);
-               b43_phy_write(dev, 0x0003, regstack[5]);
-               b43_phy_write(dev, 0x0001, regstack[6]);
-               b43_phy_write(dev, 0x0030, regstack[7]);
-
-               b43_radio_write16(dev, 0x0043, regstack[8]);
-               b43_radio_write16(dev, 0x007A, regstack[9]);
-
-               b43_radio_write16(dev, 0x0052,
-                                 (b43_radio_read16(dev, 0x0052) & 0x000F)
-                                 | regstack[11]);
-
-               b43_write16(dev, 0x03EC, regstack[10]);
-       }
-       b43_phy_write(dev, 0x0015, regstack[0]);
+       b43_phy_write(dev, B43_PHY_LO_CTL, value);
 }
 
 static u16 lo_measure_feedthrough(struct b43_wldev *dev,
@@ -366,7 +199,7 @@ static void lo_measure_txctl_values(struct b43_wldev *dev)
                if (lb_gain > 10) {
                        radio_pctl_reg = 0;
                        pga = abs(10 - lb_gain) / 6;
-                       pga = limit_value(pga, 0, 15);
+                       pga = clamp_val(pga, 0, 15);
                } else {
                        int cmp_val;
                        int tmp;
@@ -438,48 +271,26 @@ static void lo_measure_txctl_values(struct b43_wldev *dev)
                b43_radio_write16(dev, 0x52, b43_radio_read16(dev, 0x52)
                                  & 0xFFF0);    /* TX bias == 0 */
        }
+       lo->txctl_measured_time = jiffies;
 }
 
 static void lo_read_power_vector(struct b43_wldev *dev)
 {
        struct b43_phy *phy = &dev->phy;
        struct b43_txpower_lo_control *lo = phy->lo_control;
-       u16 i;
+       int i;
        u64 tmp;
        u64 power_vector = 0;
-       int rf_offset, bb_offset;
-       struct b43_loctl *loctl;
 
        for (i = 0; i < 8; i += 2) {
                tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x310 + i);
-               /* Clear the top byte. We get holes in the bitmap... */
-               tmp &= 0xFF;
                power_vector |= (tmp << (i * 8));
                /* Clear the vector on the device. */
                b43_shm_write16(dev, B43_SHM_SHARED, 0x310 + i, 0);
        }
-
        if (power_vector)
                lo->power_vector = power_vector;
-       power_vector = lo->power_vector;
-
-       for (i = 0; i < 64; i++) {
-               if (power_vector & ((u64) 1ULL << i)) {
-                       /* Now figure out which b43_loctl corresponds
-                        * to this bit.
-                        */
-                       rf_offset = i / lo->rfatt_list.len;
-                       bb_offset = i % lo->rfatt_list.len;     //FIXME?
-                       loctl =
-                           b43_get_lo_g_ctl(dev,
-                                            &lo->rfatt_list.list[rf_offset],
-                                            &lo->bbatt_list.list[bb_offset]);
-                       /* And mark it as "used", as the device told us
-                        * through the bitmap it is using it.
-                        */
-                       loctl->used = 1;
-               }
-       }
+       lo->pwr_vec_read_time = jiffies;
 }
 
 /* 802.11/LO/GPHY/MeasuringGains */
@@ -510,7 +321,7 @@ static void lo_measure_gain_values(struct b43_wldev *dev,
                        phy->lna_lod_gain = 1;
                        trsw_rx_gain -= 8;
                }
-               trsw_rx_gain = limit_value(trsw_rx_gain, 0, 0x2D);
+               trsw_rx_gain = clamp_val(trsw_rx_gain, 0, 0x2D);
                phy->pga_gain = trsw_rx_gain / 3;
                if (phy->pga_gain >= 5) {
                        phy->pga_gain -= 5;
@@ -609,8 +420,6 @@ static void lo_measure_setup(struct b43_wldev *dev,
                b43_phy_write(dev, B43_PHY_CCK(0x16), 0x410);
                b43_phy_write(dev, B43_PHY_CCK(0x17), 0x820);
        }
-       if (!lo->rebuild && b43_has_hardware_pctl(phy))
-               lo_read_power_vector(dev);
        if (phy->rev >= 2) {
                sav->phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER);
                sav->phy_analogoverval =
@@ -691,8 +500,12 @@ static void lo_measure_setup(struct b43_wldev *dev,
        b43_radio_read16(dev, 0x51);    /* dummy read */
        if (phy->type == B43_PHYTYPE_G)
                b43_phy_write(dev, B43_PHY_CCK(0x2F), 0);
-       if (lo->rebuild)
+
+       /* Re-measure the txctl values, if needed. */
+       if (time_before(lo->txctl_measured_time,
+                       jiffies - B43_LO_TXCTL_EXPIRE))
                lo_measure_txctl_values(dev);
+
        if (phy->type == B43_PHYTYPE_G && phy->rev >= 3) {
                b43_phy_write(dev, B43_PHY_LO_MASK, 0xC078);
        } else {
@@ -707,7 +520,6 @@ static void lo_measure_restore(struct b43_wldev *dev,
                               struct lo_g_saved_values *sav)
 {
        struct b43_phy *phy = &dev->phy;
-       struct b43_txpower_lo_control *lo = phy->lo_control;
        u16 tmp;
 
        if (phy->rev >= 2) {
@@ -722,14 +534,6 @@ static void lo_measure_restore(struct b43_wldev *dev,
                tmp = (phy->pga_gain | 0xEFA0);
                b43_phy_write(dev, B43_PHY_PGACTL, tmp);
        }
-       if (b43_has_hardware_pctl(phy)) {
-               b43_gphy_dc_lt_init(dev);
-       } else {
-               if (lo->rebuild)
-                       b43_lo_g_adjust_to(dev, 3, 2, 0);
-               else
-                       b43_lo_g_adjust(dev);
-       }
        if (phy->type == B43_PHYTYPE_G) {
                if (phy->rev >= 3)
                        b43_phy_write(dev, B43_PHY_CCK(0x2E), 0xC078);
@@ -793,7 +597,6 @@ static int lo_probe_possible_loctls(struct b43_wldev *dev,
                                    struct b43_lo_g_statemachine *d)
 {
        struct b43_phy *phy = &dev->phy;
-       struct b43_txpower_lo_control *lo = phy->lo_control;
        struct b43_loctl test_loctl;
        struct b43_loctl orig_loctl;
        struct b43_loctl prev_loctl = {
@@ -852,7 +655,7 @@ static int lo_probe_possible_loctls(struct b43_wldev *dev,
                                found_lower = 1;
                                d->lowest_feedth = feedth;
                                if ((d->nr_measured < 2) &&
-                                   (!has_loopback_gain(phy) || lo->rebuild))
+                                   !has_loopback_gain(phy))
                                        break;
                        }
                }
@@ -874,7 +677,6 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev,
                                         int *max_rx_gain)
 {
        struct b43_phy *phy = &dev->phy;
-       struct b43_txpower_lo_control *lo = phy->lo_control;
        struct b43_lo_g_statemachine d;
        u16 feedth;
        int found_lower;
@@ -883,18 +685,18 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev,
 
        d.nr_measured = 0;
        d.state_val_multiplier = 1;
-       if (has_loopback_gain(phy) && !lo->rebuild)
+       if (has_loopback_gain(phy))
                d.state_val_multiplier = 3;
 
        memcpy(&d.min_loctl, loctl, sizeof(struct b43_loctl));
-       if (has_loopback_gain(phy) && lo->rebuild)
+       if (has_loopback_gain(phy))
                max_repeat = 4;
        do {
                b43_lo_write(dev, &d.min_loctl);
                feedth = lo_measure_feedthrough(dev, phy->lna_gain,
                                                phy->pga_gain,
                                                phy->trsw_rx_gain);
-               if (!lo->rebuild && feedth < 0x258) {
+               if (feedth < 0x258) {
                        if (feedth >= 0x12C)
                                *max_rx_gain += 6;
                        else
@@ -944,278 +746,188 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev,
        } while (++repeat_cnt < max_repeat);
 }
 
-#if B43_CALIB_ALL_LOCTLS
-static const struct b43_rfatt b43_full_rfatt_list_items[] = {
-       { .att = 0, .with_padmix = 0, },
-       { .att = 1, .with_padmix = 0, },
-       { .att = 2, .with_padmix = 0, },
-       { .att = 3, .with_padmix = 0, },
-       { .att = 4, .with_padmix = 0, },
-       { .att = 5, .with_padmix = 0, },
-       { .att = 6, .with_padmix = 0, },
-       { .att = 7, .with_padmix = 0, },
-       { .att = 8, .with_padmix = 0, },
-       { .att = 9, .with_padmix = 0, },
-       { .att = 10, .with_padmix = 0, },
-       { .att = 11, .with_padmix = 0, },
-       { .att = 12, .with_padmix = 0, },
-       { .att = 13, .with_padmix = 0, },
-       { .att = 14, .with_padmix = 0, },
-       { .att = 15, .with_padmix = 0, },
-       { .att = 0, .with_padmix = 1, },
-       { .att = 1, .with_padmix = 1, },
-       { .att = 2, .with_padmix = 1, },
-       { .att = 3, .with_padmix = 1, },
-       { .att = 4, .with_padmix = 1, },
-       { .att = 5, .with_padmix = 1, },
-       { .att = 6, .with_padmix = 1, },
-       { .att = 7, .with_padmix = 1, },
-       { .att = 8, .with_padmix = 1, },
-       { .att = 9, .with_padmix = 1, },
-       { .att = 10, .with_padmix = 1, },
-       { .att = 11, .with_padmix = 1, },
-       { .att = 12, .with_padmix = 1, },
-       { .att = 13, .with_padmix = 1, },
-       { .att = 14, .with_padmix = 1, },
-       { .att = 15, .with_padmix = 1, },
-};
-static const struct b43_rfatt_list b43_full_rfatt_list = {
-       .list           = b43_full_rfatt_list_items,
-       .len            = ARRAY_SIZE(b43_full_rfatt_list_items),
-};
-
-static const struct b43_bbatt b43_full_bbatt_list_items[] = {
-       { .att = 0, },
-       { .att = 1, },
-       { .att = 2, },
-       { .att = 3, },
-       { .att = 4, },
-       { .att = 5, },
-       { .att = 6, },
-       { .att = 7, },
-       { .att = 8, },
-       { .att = 9, },
-       { .att = 10, },
-       { .att = 11, },
-};
-static const struct b43_bbatt_list b43_full_bbatt_list = {
-       .list           = b43_full_bbatt_list_items,
-       .len            = ARRAY_SIZE(b43_full_bbatt_list_items),
-};
-#endif /* B43_CALIB_ALL_LOCTLS */
-
-static void lo_measure(struct b43_wldev *dev)
+static
+struct b43_lo_calib * b43_calibrate_lo_setting(struct b43_wldev *dev,
+                                              const struct b43_bbatt *bbatt,
+                                              const struct b43_rfatt *rfatt)
 {
        struct b43_phy *phy = &dev->phy;
-       struct b43_txpower_lo_control *lo = phy->lo_control;
        struct b43_loctl loctl = {
                .i = 0,
                .q = 0,
        };
-       struct b43_loctl *ploctl;
        int max_rx_gain;
-       int rfidx, bbidx;
-       const struct b43_bbatt_list *bbatt_list;
-       const struct b43_rfatt_list *rfatt_list;
-
+       struct b43_lo_calib *cal;
+       struct lo_g_saved_values uninitialized_var(saved_regs);
        /* Values from the "TXCTL Register and Value Table" */
        u16 txctl_reg;
        u16 txctl_value;
        u16 pad_mix_gain;
 
-       bbatt_list = &lo->bbatt_list;
-       rfatt_list = &lo->rfatt_list;
-#if B43_CALIB_ALL_LOCTLS
-       bbatt_list = &b43_full_bbatt_list;
-       rfatt_list = &b43_full_rfatt_list;
-#endif
+       saved_regs.old_channel = phy->channel;
+       b43_mac_suspend(dev);
+       lo_measure_setup(dev, &saved_regs);
 
        txctl_reg = lo_txctl_register_table(dev, &txctl_value, &pad_mix_gain);
 
-       for (rfidx = 0; rfidx < rfatt_list->len; rfidx++) {
-
-               b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
-                                             & 0xFFF0) |
-                                 rfatt_list->list[rfidx].att);
-               b43_radio_write16(dev, txctl_reg,
-                                 (b43_radio_read16(dev, txctl_reg)
-                                  & ~txctl_value)
-                                 | (rfatt_list->list[rfidx].with_padmix ?
-                                    txctl_value : 0));
-
-               for (bbidx = 0; bbidx < bbatt_list->len; bbidx++) {
-                       if (lo->rebuild) {
-#if B43_CALIB_ALL_LOCTLS
-                               ploctl = b43_get_lo_g_ctl(dev,
-                                                         &rfatt_list->list[rfidx],
-                                                         &bbatt_list->list[bbidx]);
-#else
-                               ploctl = b43_get_lo_g_ctl_nopadmix(dev,
-                                                                  &rfatt_list->
-                                                                  list[rfidx],
-                                                                  &bbatt_list->
-                                                                  list[bbidx]);
-#endif
-                       } else {
-                               ploctl = b43_get_lo_g_ctl(dev,
-                                                         &rfatt_list->list[rfidx],
-                                                         &bbatt_list->list[bbidx]);
-                               if (!ploctl->used)
-                                       continue;
-                       }
-                       memcpy(&loctl, ploctl, sizeof(loctl));
-                       loctl.i = 0;
-                       loctl.q = 0;
-
-                       max_rx_gain = rfatt_list->list[rfidx].att * 2;
-                       max_rx_gain += bbatt_list->list[bbidx].att / 2;
-                       if (rfatt_list->list[rfidx].with_padmix)
-                               max_rx_gain -= pad_mix_gain;
-                       if (has_loopback_gain(phy))
-                               max_rx_gain += phy->max_lb_gain;
-                       lo_measure_gain_values(dev, max_rx_gain,
-                                              has_loopback_gain(phy));
-
-                       b43_phy_set_baseband_attenuation(dev,
-                                                        bbatt_list->list[bbidx].att);
-                       lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain);
-                       if (phy->type == B43_PHYTYPE_B) {
-                               loctl.i++;
-                               loctl.q++;
-                       }
-                       b43_loctl_set_calibrated(&loctl, 1);
-                       memcpy(ploctl, &loctl, sizeof(loctl));
-               }
-       }
-}
-
-#if B43_DEBUG
-static void do_validate_loctl(struct b43_wldev *dev, struct b43_loctl *control)
-{
-       const int is_initializing = (b43_status(dev) == B43_STAT_UNINIT);
-       int i = control->i;
-       int q = control->q;
+       b43_radio_write16(dev, 0x43,
+                         (b43_radio_read16(dev, 0x43) & 0xFFF0)
+                         | rfatt->att);
+       b43_radio_write16(dev, txctl_reg,
+                         (b43_radio_read16(dev, txctl_reg) & ~txctl_value)
+                         | (rfatt->with_padmix) ? txctl_value : 0);
 
-       if (b43_loctl_is_calibrated(control)) {
-               if ((abs(i) > 16) || (abs(q) > 16))
-                       goto error;
-       } else {
-               if (control->used)
-                       goto error;
-               if (dev->phy.lo_control->rebuild) {
-                       control->i = 0;
-                       control->q = 0;
-                       if ((i != B43_LOCTL_POISON) ||
-                           (q != B43_LOCTL_POISON))
-                               goto error;
-               }
+       max_rx_gain = rfatt->att * 2;
+       max_rx_gain += bbatt->att / 2;
+       if (rfatt->with_padmix)
+               max_rx_gain -= pad_mix_gain;
+       if (has_loopback_gain(phy))
+               max_rx_gain += phy->max_lb_gain;
+       lo_measure_gain_values(dev, max_rx_gain,
+                              has_loopback_gain(phy));
+
+       b43_phy_set_baseband_attenuation(dev, bbatt->att);
+       lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain);
+
+       lo_measure_restore(dev, &saved_regs);
+       b43_mac_enable(dev);
+
+       if (b43_debug(dev, B43_DBG_LO)) {
+               b43dbg(dev->wl, "LO: Calibrated for BB(%u), RF(%u,%u) "
+                      "=> I=%d Q=%d\n",
+                      bbatt->att, rfatt->att, rfatt->with_padmix,
+                      loctl.i, loctl.q);
        }
-       if (is_initializing && control->used)
-               goto error;
-
-       return;
-error:
-       b43err(dev->wl, "LO control pair validation failed "
-              "(I: %d, Q: %d, used %u, calib: %u, initing: %d)\n",
-              i, q, control->used,
-              b43_loctl_is_calibrated(control),
-              is_initializing);
-}
 
-static void validate_all_loctls(struct b43_wldev *dev)
-{
-       b43_call_for_each_loctl(dev, do_validate_loctl);
-}
-
-static void do_reset_calib(struct b43_wldev *dev, struct b43_loctl *control)
-{
-       if (dev->phy.lo_control->rebuild ||
-           control->used) {
-               b43_loctl_set_calibrated(control, 0);
-               control->i = B43_LOCTL_POISON;
-               control->q = B43_LOCTL_POISON;
+       cal = kmalloc(sizeof(*cal), GFP_KERNEL);
+       if (!cal) {
+               b43warn(dev->wl, "LO calib: out of memory\n");
+               return NULL;
        }
+       memcpy(&cal->bbatt, bbatt, sizeof(*bbatt));
+       memcpy(&cal->rfatt, rfatt, sizeof(*rfatt));
+       memcpy(&cal->ctl, &loctl, sizeof(loctl));
+       cal->calib_time = jiffies;
+       INIT_LIST_HEAD(&cal->list);
+
+       return cal;
 }
 
-static void reset_all_loctl_calibration_states(struct b43_wldev *dev)
+/* Get a calibrated LO setting for the given attenuation values.
+ * Might return a NULL pointer under OOM! */
+static
+struct b43_lo_calib * b43_get_calib_lo_settings(struct b43_wldev *dev,
+                                               const struct b43_bbatt *bbatt,
+                                               const struct b43_rfatt *rfatt)
 {
-       b43_call_for_each_loctl(dev, do_reset_calib);
+       struct b43_txpower_lo_control *lo = dev->phy.lo_control;
+       struct b43_lo_calib *c;
+
+       c = b43_find_lo_calib(lo, bbatt, rfatt);
+       if (c)
+               return c;
+       /* Not in the list of calibrated LO settings.
+        * Calibrate it now. */
+       c = b43_calibrate_lo_setting(dev, bbatt, rfatt);
+       if (!c)
+               return NULL;
+       list_add(&c->list, &lo->calib_list);
+
+       return c;
 }
 
-#else /* B43_DEBUG */
-static inline void validate_all_loctls(struct b43_wldev *dev) { }
-static inline void reset_all_loctl_calibration_states(struct b43_wldev *dev) { }
-#endif /* B43_DEBUG */
-
-void b43_lo_g_measure(struct b43_wldev *dev)
+void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all)
 {
        struct b43_phy *phy = &dev->phy;
-       struct lo_g_saved_values uninitialized_var(sav);
-
-       B43_WARN_ON((phy->type != B43_PHYTYPE_B) &&
-                   (phy->type != B43_PHYTYPE_G));
-
-       sav.old_channel = phy->channel;
-       lo_measure_setup(dev, &sav);
-       reset_all_loctl_calibration_states(dev);
-       lo_measure(dev);
-       lo_measure_restore(dev, &sav);
-
-       validate_all_loctls(dev);
+       struct b43_txpower_lo_control *lo = phy->lo_control;
+       int i;
+       int rf_offset, bb_offset;
+       const struct b43_rfatt *rfatt;
+       const struct b43_bbatt *bbatt;
+       u64 power_vector;
+       bool table_changed = 0;
 
-       phy->lo_control->lo_measured = 1;
-       phy->lo_control->rebuild = 0;
-}
+       BUILD_BUG_ON(B43_DC_LT_SIZE != 32);
+       B43_WARN_ON(lo->rfatt_list.len * lo->bbatt_list.len > 64);
 
-#if B43_DEBUG
-static void validate_loctl_calibration(struct b43_wldev *dev,
-                                      struct b43_loctl *loctl,
-                                      struct b43_rfatt *rfatt,
-                                      struct b43_bbatt *bbatt)
-{
-       if (b43_loctl_is_calibrated(loctl))
-               return;
-       if (!dev->phy.lo_control->lo_measured) {
-               /* On init we set the attenuation values before we
-                * calibrated the LO. I guess that's OK. */
-               return;
+       power_vector = lo->power_vector;
+       if (!update_all && !power_vector)
+               return; /* Nothing to do. */
+
+       /* Suspend the MAC now to avoid continuous suspend/enable
+        * cycles in the loop. */
+       b43_mac_suspend(dev);
+
+       for (i = 0; i < B43_DC_LT_SIZE * 2; i++) {
+               struct b43_lo_calib *cal;
+               int idx;
+               u16 val;
+
+               if (!update_all && !(power_vector & (((u64)1ULL) << i)))
+                       continue;
+               /* Update the table entry for this power_vector bit.
+                * The table rows are RFatt entries and columns are BBatt. */
+               bb_offset = i / lo->rfatt_list.len;
+               rf_offset = i % lo->rfatt_list.len;
+               bbatt = &(lo->bbatt_list.list[bb_offset]);
+               rfatt = &(lo->rfatt_list.list[rf_offset]);
+
+               cal = b43_calibrate_lo_setting(dev, bbatt, rfatt);
+               if (!cal) {
+                       b43warn(dev->wl, "LO: Could not "
+                               "calibrate DC table entry\n");
+                       continue;
+               }
+               /*FIXME: Is Q really in the low nibble? */
+               val = (u8)(cal->ctl.q);
+               val |= ((u8)(cal->ctl.i)) << 4;
+               kfree(cal);
+
+               /* Get the index into the hardware DC LT. */
+               idx = i / 2;
+               /* Change the table in memory. */
+               if (i % 2) {
+                       /* Change the high byte. */
+                       lo->dc_lt[idx] = (lo->dc_lt[idx] & 0x00FF)
+                                        | ((val & 0x00FF) << 8);
+               } else {
+                       /* Change the low byte. */
+                       lo->dc_lt[idx] = (lo->dc_lt[idx] & 0xFF00)
+                                        | (val & 0x00FF);
+               }
+               table_changed = 1;
        }
-       b43err(dev->wl, "Adjusting Local Oscillator to an uncalibrated "
-              "control pair: rfatt=%u,%spadmix bbatt=%u\n",
-              rfatt->att,
-              (rfatt->with_padmix) ? "" : "no-",
-              bbatt->att);
-}
-#else
-static inline void validate_loctl_calibration(struct b43_wldev *dev,
-                                             struct b43_loctl *loctl,
-                                             struct b43_rfatt *rfatt,
-                                             struct b43_bbatt *bbatt)
-{
+       if (table_changed) {
+               /* The table changed in memory. Update the hardware table. */
+               for (i = 0; i < B43_DC_LT_SIZE; i++)
+                       b43_phy_write(dev, 0x3A0 + i, lo->dc_lt[i]);
+       }
+       b43_mac_enable(dev);
 }
-#endif
 
-static inline void fixup_rfatt_for_txcontrol(struct b43_rfatt *rf,
-                                            u8 tx_control)
+/* Fixup the RF attenuation value for the case where we are
+ * using the PAD mixer. */
+static inline void b43_lo_fixup_rfatt(struct b43_rfatt *rf)
 {
-       if (tx_control & B43_TXCTL_TXMIX) {
-               if (rf->att < 5)
-                       rf->att = 4;
-       }
+       if (!rf->with_padmix)
+               return;
+       if ((rf->att != 1) && (rf->att != 2) && (rf->att != 3))
+               rf->att = 4;
 }
 
 void b43_lo_g_adjust(struct b43_wldev *dev)
 {
        struct b43_phy *phy = &dev->phy;
+       struct b43_lo_calib *cal;
        struct b43_rfatt rf;
-       struct b43_loctl *loctl;
 
        memcpy(&rf, &phy->rfatt, sizeof(rf));
-       fixup_rfatt_for_txcontrol(&rf, phy->tx_control);
+       b43_lo_fixup_rfatt(&rf);
 
-       loctl = b43_get_lo_g_ctl(dev, &rf, &phy->bbatt);
-       validate_loctl_calibration(dev, loctl, &rf, &phy->bbatt);
-       b43_lo_write(dev, loctl);
+       cal = b43_get_calib_lo_settings(dev, &phy->bbatt, &rf);
+       if (!cal)
+               return;
+       b43_lo_write(dev, &cal->ctl);
 }
 
 void b43_lo_g_adjust_to(struct b43_wldev *dev,
@@ -1223,39 +935,102 @@ void b43_lo_g_adjust_to(struct b43_wldev *dev,
 {
        struct b43_rfatt rf;
        struct b43_bbatt bb;
-       struct b43_loctl *loctl;
+       struct b43_lo_calib *cal;
 
        memset(&rf, 0, sizeof(rf));
        memset(&bb, 0, sizeof(bb));
        rf.att = rfatt;
        bb.att = bbatt;
-       fixup_rfatt_for_txcontrol(&rf, tx_control);
-       loctl = b43_get_lo_g_ctl(dev, &rf, &bb);
-       validate_loctl_calibration(dev, loctl, &rf, &bb);
-       b43_lo_write(dev, loctl);
+       b43_lo_fixup_rfatt(&rf);
+       cal = b43_get_calib_lo_settings(dev, &bb, &rf);
+       if (!cal)
+               return;
+       b43_lo_write(dev, &cal->ctl);
 }
 
-static void do_mark_unused(struct b43_wldev *dev, struct b43_loctl *control)
+/* Periodic LO maintanance work */
+void b43_lo_g_maintanance_work(struct b43_wldev *dev)
 {
-       control->used = 0;
+       struct b43_phy *phy = &dev->phy;
+       struct b43_txpower_lo_control *lo = phy->lo_control;
+       unsigned long now;
+       unsigned long expire;
+       struct b43_lo_calib *cal, *tmp;
+       bool current_item_expired = 0;
+       bool hwpctl;
+
+       if (!lo)
+               return;
+       now = jiffies;
+       hwpctl = b43_has_hardware_pctl(phy);
+
+       if (hwpctl) {
+               /* Read the power vector and update it, if needed. */
+               expire = now - B43_LO_PWRVEC_EXPIRE;
+               if (time_before(lo->pwr_vec_read_time, expire)) {
+                       lo_read_power_vector(dev);
+                       b43_gphy_dc_lt_init(dev, 0);
+               }
+               //FIXME Recalc the whole DC table from time to time?
+       }
+
+       if (hwpctl)
+               return;
+       /* Search for expired LO settings. Remove them.
+        * Recalibrate the current setting, if expired. */
+       expire = now - B43_LO_CALIB_EXPIRE;
+       list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) {
+               if (!time_before(cal->calib_time, expire))
+                       continue;
+               /* This item expired. */
+               if (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) &&
+                   b43_compare_rfatt(&cal->rfatt, &phy->rfatt)) {
+                       B43_WARN_ON(current_item_expired);
+                       current_item_expired = 1;
+               }
+               if (b43_debug(dev, B43_DBG_LO)) {
+                       b43dbg(dev->wl, "LO: Item BB(%u), RF(%u,%u), "
+                              "I=%d, Q=%d expired\n",
+                              cal->bbatt.att, cal->rfatt.att,
+                              cal->rfatt.with_padmix,
+                              cal->ctl.i, cal->ctl.q);
+               }
+               list_del(&cal->list);
+               kfree(cal);
+       }
+       if (current_item_expired || unlikely(list_empty(&lo->calib_list))) {
+               /* Recalibrate currently used LO setting. */
+               if (b43_debug(dev, B43_DBG_LO))
+                       b43dbg(dev->wl, "LO: Recalibrating current LO setting\n");
+               cal = b43_calibrate_lo_setting(dev, &phy->bbatt, &phy->rfatt);
+               if (cal) {
+                       list_add(&cal->list, &lo->calib_list);
+                       b43_lo_write(dev, &cal->ctl);
+               } else
+                       b43warn(dev->wl, "Failed to recalibrate current LO setting\n");
+       }
 }
 
-void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev)
+void b43_lo_g_cleanup(struct b43_wldev *dev)
 {
-       struct b43_phy *phy = &dev->phy;
-       struct b43_txpower_lo_control *lo = phy->lo_control;
+       struct b43_txpower_lo_control *lo = dev->phy.lo_control;
+       struct b43_lo_calib *cal, *tmp;
 
-       b43_call_for_each_loctl(dev, do_mark_unused);
-       lo->rebuild = 1;
+       if (!lo)
+               return;
+       list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) {
+               list_del(&cal->list);
+               kfree(cal);
+       }
 }
 
-void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev)
+/* LO Initialization */
+void b43_lo_g_init(struct b43_wldev *dev)
 {
        struct b43_phy *phy = &dev->phy;
-       struct b43_rfatt rf;
 
-       memcpy(&rf, &phy->rfatt, sizeof(rf));
-       fixup_rfatt_for_txcontrol(&rf, phy->tx_control);
-
-       b43_get_lo_g_ctl(dev, &rf, &phy->bbatt)->used = 1;
+       if (b43_has_hardware_pctl(phy)) {
+               lo_read_power_vector(dev);
+               b43_gphy_dc_lt_init(dev, 1);
+       }
 }
index 455615d1f8c657698b77dfbfbd14af8862e07438..1da321cabc12c85c7809bcf3e6d858165613f088 100644 (file)
@@ -10,82 +10,63 @@ struct b43_loctl {
        /* Control values. */
        s8 i;
        s8 q;
-       /* "Used by hardware" flag. */
-       bool used;
-#ifdef CONFIG_B43_DEBUG
-       /* Is this lo-control-array entry calibrated? */
-       bool calibrated;
-#endif
 };
-
 /* Debugging: Poison value for i and q values. */
 #define B43_LOCTL_POISON       111
 
-/* loctl->calibrated debugging mechanism */
-#ifdef CONFIG_B43_DEBUG
-static inline void b43_loctl_set_calibrated(struct b43_loctl *loctl,
-                                           bool calibrated)
-{
-       loctl->calibrated = calibrated;
-}
-static inline bool b43_loctl_is_calibrated(struct b43_loctl *loctl)
-{
-       return loctl->calibrated;
-}
-#else
-static inline void b43_loctl_set_calibrated(struct b43_loctl *loctl,
-                                           bool calibrated)
-{
-}
-static inline bool b43_loctl_is_calibrated(struct b43_loctl *loctl)
-{
-       return 1;
-}
-#endif
-
-/* TX Power LO Control Array.
- * Value-pairs to adjust the LocalOscillator are stored
- * in this structure.
- * There are two different set of values. One for "Flag is Set"
- * and one for "Flag is Unset".
- * By "Flag" the flag in struct b43_rfatt is meant.
- * The Value arrays are two-dimensional. The first index
- * is the baseband attenuation and the second index
- * is the radio attenuation.
- * Use b43_get_lo_g_ctl() to retrieve a value from the lists.
- */
+/* This struct holds calibrated LO settings for a set of
+ * Baseband and RF attenuation settings. */
+struct b43_lo_calib {
+       /* The set of attenuation values this set of LO
+        * control values is calibrated for. */
+       struct b43_bbatt bbatt;
+       struct b43_rfatt rfatt;
+       /* The set of control values for the LO. */
+       struct b43_loctl ctl;
+       /* The time when these settings were calibrated (in jiffies) */
+       unsigned long calib_time;
+       /* List. */
+       struct list_head list;
+};
+
+/* Size of the DC Lookup Table in 16bit words. */
+#define B43_DC_LT_SIZE         32
+
+/* Local Oscillator calibration information */
 struct b43_txpower_lo_control {
-#define B43_NR_BB      12
-#define B43_NR_RF      16
-       /* LO Control values, with PAD Mixer */
-       struct b43_loctl with_padmix[B43_NR_BB][B43_NR_RF];
-       /* LO Control values, without PAD Mixer */
-       struct b43_loctl no_padmix[B43_NR_BB][B43_NR_RF];
-
-       /* Flag to indicate a complete rebuild of the two tables above
-        * to the LO measuring code. */
-       bool rebuild;
-
-       /* Lists of valid RF and BB attenuation values for this device. */
+       /* Lists of RF and BB attenuation values for this device.
+        * Used for building hardware power control tables. */
        struct b43_rfatt_list rfatt_list;
        struct b43_bbatt_list bbatt_list;
 
+       /* The DC Lookup Table is cached in memory here.
+        * Note that this is only used for Hardware Power Control. */
+       u16 dc_lt[B43_DC_LT_SIZE];
+
+       /* List of calibrated control values (struct b43_lo_calib). */
+       struct list_head calib_list;
+       /* Last time the power vector was read (jiffies). */
+       unsigned long pwr_vec_read_time;
+       /* Last time the txctl values were measured (jiffies). */
+       unsigned long txctl_measured_time;
+
        /* Current TX Bias value */
        u8 tx_bias;
        /* Current TX Magnification Value (if used by the device) */
        u8 tx_magn;
 
-       /* GPHY LO is measured. */
-       bool lo_measured;
-
        /* Saved device PowerVector */
        u64 power_vector;
 };
 
-/* Measure the BPHY Local Oscillator. */
-void b43_lo_b_measure(struct b43_wldev *dev);
-/* Measure the BPHY/GPHY Local Oscillator. */
-void b43_lo_g_measure(struct b43_wldev *dev);
+/* Calibration expire timeouts.
+ * Timeouts must be multiple of 15 seconds. To make sure
+ * the item really expired when the 15 second timer hits, we
+ * subtract two additional seconds from the timeout. */
+#define B43_LO_CALIB_EXPIRE    (HZ * (30 - 2))
+#define B43_LO_PWRVEC_EXPIRE   (HZ * (30 - 2))
+#define B43_LO_TXCTL_EXPIRE    (HZ * (180 - 4))
+
 
 /* Adjust the Local Oscillator to the saved attenuation
  * and txctl values.
@@ -95,18 +76,10 @@ void b43_lo_g_adjust(struct b43_wldev *dev);
 void b43_lo_g_adjust_to(struct b43_wldev *dev,
                        u16 rfatt, u16 bbatt, u16 tx_control);
 
-/* Mark all possible b43_lo_g_ctl as "unused" */
-void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev);
-/* Mark the b43_lo_g_ctl corresponding to the current
- * attenuation values as used.
- */
-void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev);
+void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all);
 
-/* Get a reference to a LO Control value pair in the
- * TX Power LO Control Array.
- */
-struct b43_loctl *b43_get_lo_g_ctl(struct b43_wldev *dev,
-                                  const struct b43_rfatt *rfatt,
-                                  const struct b43_bbatt *bbatt);
+void b43_lo_g_maintanance_work(struct b43_wldev *dev);
+void b43_lo_g_cleanup(struct b43_wldev *dev);
+void b43_lo_g_init(struct b43_wldev *dev);
 
 #endif /* B43_LO_H_ */
index 6c3d9ea0a9f858461f54ffb0e148f1f567fb6a22..1e31e0bca744374b84b032c1e9de98ab63e01aaa 100644 (file)
@@ -1182,10 +1182,10 @@ static void handle_irq_noise(struct b43_wldev *dev)
        /* Get the noise samples. */
        B43_WARN_ON(dev->noisecalc.nr_samples >= 8);
        i = dev->noisecalc.nr_samples;
-       noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
-       noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
-       noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
-       noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+       noise[0] = clamp_val(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+       noise[1] = clamp_val(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+       noise[2] = clamp_val(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+       noise[3] = clamp_val(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
        dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]];
        dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]];
        dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]];
@@ -1368,18 +1368,18 @@ static void b43_write_beacon_template(struct b43_wldev *dev,
        unsigned int rate;
        u16 ctl;
        int antenna;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon);
 
        bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);
        len = min((size_t) dev->wl->current_beacon->len,
                  0x200 - sizeof(struct b43_plcp_hdr6));
-       rate = dev->wl->beacon_txctl.tx_rate->hw_value;
+       rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value;
 
        b43_write_template_common(dev, (const u8 *)bcn,
                                  len, ram_offset, shm_size_offset, rate);
 
        /* Write the PHY TX control parameters. */
-       antenna = b43_antenna_from_ieee80211(dev,
-                       dev->wl->beacon_txctl.antenna_sel_tx);
+       antenna = b43_antenna_from_ieee80211(dev, info->antenna_sel_tx);
        antenna = b43_antenna_to_phyctl(antenna);
        ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
        /* We can't send beacons with short preamble. Would get PHY errors. */
@@ -1430,11 +1430,17 @@ static void b43_write_beacon_template(struct b43_wldev *dev,
                i += ie_len + 2;
        }
        if (!tim_found) {
-               b43warn(dev->wl, "Did not find a valid TIM IE in "
-                       "the beacon template packet. AP or IBSS operation "
-                       "may be broken.\n");
-       } else
-               b43dbg(dev->wl, "Updated beacon template\n");
+               /*
+                * If ucode wants to modify TIM do it behind the beacon, this
+                * will happen, for example, when doing mesh networking.
+                */
+               b43_shm_write16(dev, B43_SHM_SHARED,
+                               B43_SHM_SH_TIMBPOS,
+                               len + sizeof(struct b43_plcp_hdr6));
+               b43_shm_write16(dev, B43_SHM_SHARED,
+                               B43_SHM_SH_DTIMPER, 0);
+       }
+       b43dbg(dev->wl, "Updated beacon template at 0x%x\n", ram_offset);
 }
 
 static void b43_write_probe_resp_plcp(struct b43_wldev *dev,
@@ -1573,7 +1579,8 @@ static void handle_irq_beacon(struct b43_wldev *dev)
        struct b43_wl *wl = dev->wl;
        u32 cmd, beacon0_valid, beacon1_valid;
 
-       if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP))
+       if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP) &&
+           !b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT))
                return;
 
        /* This is the bottom half of the asynchronous beacon update. */
@@ -1640,8 +1647,7 @@ static void b43_beacon_update_trigger_work(struct work_struct *work)
 
 /* Asynchronously update the packet templates in template RAM.
  * Locking: Requires wl->irq_lock to be locked. */
-static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon,
-                                const struct ieee80211_tx_control *txctl)
+static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon)
 {
        /* This is the top half of the ansynchronous beacon update.
         * The bottom half is the beacon IRQ.
@@ -1652,7 +1658,6 @@ static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon,
        if (wl->current_beacon)
                dev_kfree_skb_any(wl->current_beacon);
        wl->current_beacon = beacon;
-       memcpy(&wl->beacon_txctl, txctl, sizeof(wl->beacon_txctl));
        wl->beacon0_uploaded = 0;
        wl->beacon1_uploaded = 0;
        queue_work(wl->hw->workqueue, &wl->beacon_update_trigger);
@@ -1691,9 +1696,100 @@ static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
        b43dbg(dev->wl, "Set beacon interval to %u\n", beacon_int);
 }
 
+static void b43_handle_firmware_panic(struct b43_wldev *dev)
+{
+       u16 reason;
+
+       /* Read the register that contains the reason code for the panic. */
+       reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_FWPANIC_REASON_REG);
+       b43err(dev->wl, "Whoopsy, firmware panic! Reason: %u\n", reason);
+
+       switch (reason) {
+       default:
+               b43dbg(dev->wl, "The panic reason is unknown.\n");
+               /* fallthrough */
+       case B43_FWPANIC_DIE:
+               /* Do not restart the controller or firmware.
+                * The device is nonfunctional from now on.
+                * Restarting would result in this panic to trigger again,
+                * so we avoid that recursion. */
+               break;
+       case B43_FWPANIC_RESTART:
+               b43_controller_restart(dev, "Microcode panic");
+               break;
+       }
+}
+
 static void handle_irq_ucode_debug(struct b43_wldev *dev)
 {
-       //TODO
+       unsigned int i, cnt;
+       u16 reason, marker_id, marker_line;
+       __le16 *buf;
+
+       /* The proprietary firmware doesn't have this IRQ. */
+       if (!dev->fw.opensource)
+               return;
+
+       /* Read the register that contains the reason code for this IRQ. */
+       reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_DEBUGIRQ_REASON_REG);
+
+       switch (reason) {
+       case B43_DEBUGIRQ_PANIC:
+               b43_handle_firmware_panic(dev);
+               break;
+       case B43_DEBUGIRQ_DUMP_SHM:
+               if (!B43_DEBUG)
+                       break; /* Only with driver debugging enabled. */
+               buf = kmalloc(4096, GFP_ATOMIC);
+               if (!buf) {
+                       b43dbg(dev->wl, "SHM-dump: Failed to allocate memory\n");
+                       goto out;
+               }
+               for (i = 0; i < 4096; i += 2) {
+                       u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, i);
+                       buf[i / 2] = cpu_to_le16(tmp);
+               }
+               b43info(dev->wl, "Shared memory dump:\n");
+               print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET,
+                              16, 2, buf, 4096, 1);
+               kfree(buf);
+               break;
+       case B43_DEBUGIRQ_DUMP_REGS:
+               if (!B43_DEBUG)
+                       break; /* Only with driver debugging enabled. */
+               b43info(dev->wl, "Microcode register dump:\n");
+               for (i = 0, cnt = 0; i < 64; i++) {
+                       u16 tmp = b43_shm_read16(dev, B43_SHM_SCRATCH, i);
+                       if (cnt == 0)
+                               printk(KERN_INFO);
+                       printk("r%02u: 0x%04X  ", i, tmp);
+                       cnt++;
+                       if (cnt == 6) {
+                               printk("\n");
+                               cnt = 0;
+                       }
+               }
+               printk("\n");
+               break;
+       case B43_DEBUGIRQ_MARKER:
+               if (!B43_DEBUG)
+                       break; /* Only with driver debugging enabled. */
+               marker_id = b43_shm_read16(dev, B43_SHM_SCRATCH,
+                                          B43_MARKER_ID_REG);
+               marker_line = b43_shm_read16(dev, B43_SHM_SCRATCH,
+                                            B43_MARKER_LINE_REG);
+               b43info(dev->wl, "The firmware just executed the MARKER(%u) "
+                       "at line number %u\n",
+                       marker_id, marker_line);
+               break;
+       default:
+               b43dbg(dev->wl, "Debug-IRQ triggered for unknown reason: %u\n",
+                      reason);
+       }
+out:
+       /* Acknowledge the debug-IRQ, so the firmware can continue. */
+       b43_shm_write16(dev, B43_SHM_SCRATCH,
+                       B43_DEBUGIRQ_REASON_REG, B43_DEBUGIRQ_ACK);
 }
 
 /* Interrupt handler bottom-half */
@@ -1880,7 +1976,8 @@ static void b43_print_fw_helptext(struct b43_wl *wl, bool error)
 
 static int do_request_fw(struct b43_wldev *dev,
                         const char *name,
-                        struct b43_firmware_file *fw)
+                        struct b43_firmware_file *fw,
+                        bool silent)
 {
        char path[sizeof(modparam_fwpostfix) + 32];
        const struct firmware *blob;
@@ -1904,9 +2001,15 @@ static int do_request_fw(struct b43_wldev *dev,
                 "b43%s/%s.fw",
                 modparam_fwpostfix, name);
        err = request_firmware(&blob, path, dev->dev->dev);
-       if (err) {
-               b43err(dev->wl, "Firmware file \"%s\" not found "
-                      "or load failed.\n", path);
+       if (err == -ENOENT) {
+               if (!silent) {
+                       b43err(dev->wl, "Firmware file \"%s\" not found\n",
+                              path);
+               }
+               return err;
+       } else if (err) {
+               b43err(dev->wl, "Firmware file \"%s\" request failed (err=%d)\n",
+                      path, err);
                return err;
        }
        if (blob->size < sizeof(struct b43_fw_header))
@@ -1957,7 +2060,7 @@ static int b43_request_firmware(struct b43_wldev *dev)
                filename = "ucode13";
        else
                goto err_no_ucode;
-       err = do_request_fw(dev, filename, &fw->ucode);
+       err = do_request_fw(dev, filename, &fw->ucode, 0);
        if (err)
                goto err_load;
 
@@ -1968,8 +2071,13 @@ static int b43_request_firmware(struct b43_wldev *dev)
                filename = NULL;
        else
                goto err_no_pcm;
-       err = do_request_fw(dev, filename, &fw->pcm);
-       if (err)
+       fw->pcm_request_failed = 0;
+       err = do_request_fw(dev, filename, &fw->pcm, 1);
+       if (err == -ENOENT) {
+               /* We did not find a PCM file? Not fatal, but
+                * core rev <= 10 must do without hwcrypto then. */
+               fw->pcm_request_failed = 1;
+       } else if (err)
                goto err_load;
 
        /* Get initvals */
@@ -1987,7 +2095,7 @@ static int b43_request_firmware(struct b43_wldev *dev)
                if ((rev >= 5) && (rev <= 10))
                        filename = "b0g0initvals5";
                else if (rev >= 13)
-                       filename = "lp0initvals13";
+                       filename = "b0g0initvals13";
                else
                        goto err_no_initvals;
                break;
@@ -2000,7 +2108,7 @@ static int b43_request_firmware(struct b43_wldev *dev)
        default:
                goto err_no_initvals;
        }
-       err = do_request_fw(dev, filename, &fw->initvals);
+       err = do_request_fw(dev, filename, &fw->initvals, 0);
        if (err)
                goto err_load;
 
@@ -2034,7 +2142,7 @@ static int b43_request_firmware(struct b43_wldev *dev)
        default:
                goto err_no_initvals;
        }
-       err = do_request_fw(dev, filename, &fw->initvals_band);
+       err = do_request_fw(dev, filename, &fw->initvals_band, 0);
        if (err)
                goto err_load;
 
@@ -2151,14 +2259,28 @@ static int b43_upload_microcode(struct b43_wldev *dev)
                err = -EOPNOTSUPP;
                goto error;
        }
-       b43info(dev->wl, "Loading firmware version %u.%u "
-               "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
-               fwrev, fwpatch,
-               (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
-               (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F);
-
        dev->fw.rev = fwrev;
        dev->fw.patch = fwpatch;
+       dev->fw.opensource = (fwdate == 0xFFFF);
+
+       if (dev->fw.opensource) {
+               /* 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)" : "");
+       } else {
+               b43info(dev->wl, "Loading firmware version %u.%u "
+                       "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
+                       fwrev, fwpatch,
+                       (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
+                       (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F);
+               if (dev->fw.pcm_request_failed) {
+                       b43warn(dev->wl, "No \"pcm5.fw\" firmware file found. "
+                               "Hardware accelerated cryptography is disabled.\n");
+                       b43_print_fw_helptext(dev->wl, 0);
+               }
+       }
 
        if (b43_is_old_txhdr_format(dev)) {
                b43warn(dev->wl, "You are using an old firmware image. "
@@ -2335,7 +2457,7 @@ static void b43_gpio_cleanup(struct b43_wldev *dev)
 }
 
 /* http://bcm-specs.sipsolutions.net/EnableMac */
-static void b43_mac_enable(struct b43_wldev *dev)
+void b43_mac_enable(struct b43_wldev *dev)
 {
        dev->mac_suspended--;
        B43_WARN_ON(dev->mac_suspended < 0);
@@ -2349,16 +2471,11 @@ static void b43_mac_enable(struct b43_wldev *dev)
                b43_read32(dev, B43_MMIO_MACCTL);
                b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
                b43_power_saving_ctl_bits(dev, 0);
-
-               /* Re-enable IRQs. */
-               spin_lock_irq(&dev->wl->irq_lock);
-               b43_interrupt_enable(dev, dev->irq_savedstate);
-               spin_unlock_irq(&dev->wl->irq_lock);
        }
 }
 
 /* http://bcm-specs.sipsolutions.net/SuspendMAC */
-static void b43_mac_suspend(struct b43_wldev *dev)
+void b43_mac_suspend(struct b43_wldev *dev)
 {
        int i;
        u32 tmp;
@@ -2367,14 +2484,6 @@ static void b43_mac_suspend(struct b43_wldev *dev)
        B43_WARN_ON(dev->mac_suspended < 0);
 
        if (dev->mac_suspended == 0) {
-               /* Mask IRQs before suspending MAC. Otherwise
-                * the MAC stays busy and won't suspend. */
-               spin_lock_irq(&dev->wl->irq_lock);
-               tmp = b43_interrupt_disable(dev, B43_IRQ_ALL);
-               spin_unlock_irq(&dev->wl->irq_lock);
-               b43_synchronize_irq(dev);
-               dev->irq_savedstate = tmp;
-
                b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
                b43_write32(dev, B43_MMIO_MACCTL,
                            b43_read32(dev, B43_MMIO_MACCTL)
@@ -2416,7 +2525,8 @@ static void b43_adjust_opmode(struct b43_wldev *dev)
        ctl &= ~B43_MACCTL_BEACPROMISC;
        ctl |= B43_MACCTL_INFRA;
 
-       if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP))
+       if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
+           b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT))
                ctl |= B43_MACCTL_AP;
        else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS))
                ctl &= ~B43_MACCTL_INFRA;
@@ -2530,6 +2640,7 @@ static void b43_chip_exit(struct b43_wldev *dev)
 {
        b43_radio_turn_off(dev, 1);
        b43_gpio_cleanup(dev);
+       b43_lo_g_cleanup(dev);
        /* firmware is released later */
 }
 
@@ -2636,28 +2747,12 @@ err_gpio_clean:
        return err;
 }
 
-static void b43_periodic_every120sec(struct b43_wldev *dev)
-{
-       struct b43_phy *phy = &dev->phy;
-
-       if (phy->type != B43_PHYTYPE_G || phy->rev < 2)
-               return;
-
-       b43_mac_suspend(dev);
-       b43_lo_g_measure(dev);
-       b43_mac_enable(dev);
-       if (b43_has_hardware_pctl(phy))
-               b43_lo_g_ctl_mark_all_unused(dev);
-}
-
 static void b43_periodic_every60sec(struct b43_wldev *dev)
 {
        struct b43_phy *phy = &dev->phy;
 
        if (phy->type != B43_PHYTYPE_G)
                return;
-       if (!b43_has_hardware_pctl(phy))
-               b43_lo_g_ctl_mark_all_unused(dev);
        if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
                b43_mac_suspend(dev);
                b43_calc_nrssi_slope(dev);
@@ -2709,6 +2804,7 @@ static void b43_periodic_every15sec(struct b43_wldev *dev)
                }
        }
        b43_phy_xmitpower(dev); //FIXME: unless scanning?
+       b43_lo_g_maintanance_work(dev);
        //TODO for APHY (temperature?)
 
        atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
@@ -2720,8 +2816,6 @@ static void do_periodic_work(struct b43_wldev *dev)
        unsigned int state;
 
        state = dev->periodic_state;
-       if (state % 8 == 0)
-               b43_periodic_every120sec(dev);
        if (state % 4 == 0)
                b43_periodic_every60sec(dev);
        if (state % 2 == 0)
@@ -2869,8 +2963,7 @@ static int b43_rng_init(struct b43_wl *wl)
 }
 
 static int b43_op_tx(struct ieee80211_hw *hw,
-                    struct sk_buff *skb,
-                    struct ieee80211_tx_control *ctl)
+                    struct sk_buff *skb)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev = wl->current_dev;
@@ -2892,9 +2985,9 @@ static int b43_op_tx(struct ieee80211_hw *hw,
        err = -ENODEV;
        if (likely(b43_status(dev) >= B43_STAT_STARTED)) {
                if (b43_using_pio_transfers(dev))
-                       err = b43_pio_tx(dev, skb, ctl);
+                       err = b43_pio_tx(dev, skb);
                else
-                       err = b43_dma_tx(dev, skb, ctl);
+                       err = b43_dma_tx(dev, skb);
        }
 
        read_unlock_irqrestore(&wl->tx_lock, flags);
@@ -3052,8 +3145,7 @@ static void b43_qos_update_work(struct work_struct *work)
        mutex_unlock(&wl->mutex);
 }
 
-static int b43_op_conf_tx(struct ieee80211_hw *hw,
-                         int _queue,
+static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue,
                          const struct ieee80211_tx_queue_params *params)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
@@ -3301,8 +3393,9 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
        antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx);
        b43_set_rx_antenna(dev, antenna);
 
-       /* Update templates for AP mode. */
-       if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP))
+       /* Update templates for AP/mesh mode. */
+       if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
+           b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT))
                b43_set_beacon_int(dev, conf->beacon_int);
 
        if (!!conf->radio_enabled != phy->radio_on) {
@@ -3353,6 +3446,13 @@ 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) {
+               /* We don't have firmware for the crypto engine.
+                * Must use software-crypto. */
+               err = -EOPNOTSUPP;
+               goto out_unlock;
+       }
+
        err = -EINVAL;
        switch (key->alg) {
        case ALG_WEP:
@@ -3483,13 +3583,12 @@ static int b43_op_config_interface(struct ieee80211_hw *hw,
        else
                memset(wl->bssid, 0, ETH_ALEN);
        if (b43_status(dev) >= B43_STAT_INITIALIZED) {
-               if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) {
-                       B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP);
+               if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
+                   b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) {
+                       B43_WARN_ON(conf->type != wl->if_type);
                        b43_set_ssid(dev, conf->ssid, conf->ssid_len);
-                       if (conf->beacon) {
-                               b43_update_templates(wl, conf->beacon,
-                                                    conf->beacon_control);
-                       }
+                       if (conf->beacon)
+                               b43_update_templates(wl, conf->beacon);
                }
                b43_write_mac_bssid_templates(dev);
        }
@@ -3554,7 +3653,6 @@ static int b43_wireless_core_start(struct b43_wldev *dev)
        /* Start data flow (TX/RX). */
        b43_mac_enable(dev);
        b43_interrupt_enable(dev, dev->irq_savedstate);
-       ieee80211_start_queues(dev->wl->hw);
 
        /* Start maintainance work */
        b43_periodic_tasks_setup(dev);
@@ -3695,8 +3793,8 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev,
        lo = phy->lo_control;
        if (lo) {
                memset(lo, 0, sizeof(*(phy->lo_control)));
-               lo->rebuild = 1;
                lo->tx_bias = 0xFF;
+               INIT_LIST_HEAD(&lo->calib_list);
        }
        phy->max_lb_gain = 0;
        phy->trsw_rx_gain = 0;
@@ -4027,6 +4125,7 @@ static int b43_op_add_interface(struct ieee80211_hw *hw,
        /* TODO: allow WDS/AP devices to coexist */
 
        if (conf->type != IEEE80211_IF_TYPE_AP &&
+           conf->type != IEEE80211_IF_TYPE_MESH_POINT &&
            conf->type != IEEE80211_IF_TYPE_STA &&
            conf->type != IEEE80211_IF_TYPE_WDS &&
            conf->type != IEEE80211_IF_TYPE_IBSS)
@@ -4179,31 +4278,29 @@ static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set)
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct sk_buff *beacon;
        unsigned long flags;
-       struct ieee80211_tx_control txctl;
 
        /* We could modify the existing beacon and set the aid bit in
         * the TIM field, but that would probably require resizing and
         * moving of data within the beacon template.
         * Simply request a new beacon and let mac80211 do the hard work. */
-       beacon = ieee80211_beacon_get(hw, wl->vif, &txctl);
+       beacon = ieee80211_beacon_get(hw, wl->vif);
        if (unlikely(!beacon))
                return -ENOMEM;
        spin_lock_irqsave(&wl->irq_lock, flags);
-       b43_update_templates(wl, beacon, &txctl);
+       b43_update_templates(wl, beacon);
        spin_unlock_irqrestore(&wl->irq_lock, flags);
 
        return 0;
 }
 
 static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw,
-                                    struct sk_buff *beacon,
-                                    struct ieee80211_tx_control *ctl)
+                                    struct sk_buff *beacon)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        unsigned long flags;
 
        spin_lock_irqsave(&wl->irq_lock, flags);
-       b43_update_templates(wl, beacon, ctl);
+       b43_update_templates(wl, beacon);
        spin_unlock_irqrestore(&wl->irq_lock, flags);
 
        return 0;
@@ -4530,10 +4627,10 @@ static int b43_wireless_init(struct ssb_device *dev)
 
        /* fill hw info */
        hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
-                   IEEE80211_HW_RX_INCLUDES_FCS;
-       hw->max_signal = 100;
-       hw->max_rssi = -110;
-       hw->max_noise = -110;
+                   IEEE80211_HW_RX_INCLUDES_FCS |
+                   IEEE80211_HW_SIGNAL_DBM |
+                   IEEE80211_HW_NOISE_DBM;
+
        hw->queues = b43_modparam_qos ? 4 : 1;
        SET_IEEE80211_DEV(hw, dev->dev);
        if (is_valid_ether_addr(sprom->et1mac))
index 5230aeca78bf97ed9a544ce73c08f0bb4e514600..dad23c42b42278482db447938b15118588abc1ca 100644 (file)
@@ -114,4 +114,7 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason);
 #define B43_PS_ASLEEP  (1 << 3)        /* Force device asleep */
 void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags);
 
+void b43_mac_suspend(struct b43_wldev *dev);
+void b43_mac_enable(struct b43_wldev *dev);
+
 #endif /* B43_MAIN_H_ */
index 8695eb2234763a6420e70b06e1149e1c1c73824b..644eed993bea15ef449da75a50f844f2e3a03c2c 100644 (file)
@@ -29,8 +29,6 @@
 #include "nphy.h"
 #include "tables_nphy.h"
 
-#include <linux/delay.h>
-
 
 void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
 {//TODO
index de024dc03718571296577a14bac34467b3ffd0f8..305d4cd6fd03cdefa6235f84fba3d1e698d8941e 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/types.h>
+#include <linux/bitrev.h>
 
 #include "b43.h"
 #include "phy.h"
@@ -83,25 +84,9 @@ const u8 b43_radio_channel_codes_bg[] = {
        72, 84,
 };
 
+#define bitrev4(tmp) (bitrev8(tmp) >> 4)
 static void b43_phy_initg(struct b43_wldev *dev);
 
-/* Reverse the bits of a 4bit value.
- * Example:  1101 is flipped 1011
- */
-static u16 flip_4bit(u16 value)
-{
-       u16 flipped = 0x0000;
-
-       B43_WARN_ON(value & ~0x000F);
-
-       flipped |= (value & 0x0001) << 3;
-       flipped |= (value & 0x0002) << 1;
-       flipped |= (value & 0x0004) >> 1;
-       flipped |= (value & 0x0008) >> 3;
-
-       return flipped;
-}
-
 static void generate_rfatt_list(struct b43_wldev *dev,
                                struct b43_rfatt_list *list)
 {
@@ -145,8 +130,7 @@ static void generate_rfatt_list(struct b43_wldev *dev,
                {.att = 9,.with_padmix = 1,},
        };
 
-       if ((phy->type == B43_PHYTYPE_A && phy->rev < 5) ||
-           (phy->type == B43_PHYTYPE_G && phy->rev < 6)) {
+       if (!b43_has_hardware_pctl(phy)) {
                /* Software pctl */
                list->list = rfatt_0;
                list->len = ARRAY_SIZE(rfatt_0);
@@ -158,7 +142,7 @@ static void generate_rfatt_list(struct b43_wldev *dev,
                /* Hardware pctl */
                list->list = rfatt_1;
                list->len = ARRAY_SIZE(rfatt_1);
-               list->min_val = 2;
+               list->min_val = 0;
                list->max_val = 14;
                return;
        }
@@ -346,6 +330,7 @@ void b43_set_txpower_g(struct b43_wldev *dev,
        /* Save the values for later */
        phy->tx_control = tx_control;
        memcpy(&phy->rfatt, rfatt, sizeof(*rfatt));
+       phy->rfatt.with_padmix = !!(tx_control & B43_TXCTL_TXMIX);
        memcpy(&phy->bbatt, bbatt, sizeof(*bbatt));
 
        if (b43_debug(dev, B43_DBG_XMITPOWER)) {
@@ -559,11 +544,6 @@ static void b43_gphy_gain_lt_init(struct b43_wldev *dev)
        u16 tmp;
        u8 rf, bb;
 
-       if (!lo->lo_measured) {
-               b43_phy_write(dev, 0x3FF, 0);
-               return;
-       }
-
        for (rf = 0; rf < lo->rfatt_list.len; rf++) {
                for (bb = 0; bb < lo->bbatt_list.len; bb++) {
                        if (nr_written >= 0x40)
@@ -581,42 +561,6 @@ static void b43_gphy_gain_lt_init(struct b43_wldev *dev)
        }
 }
 
-/* GPHY_DC_Lookup_Table */
-void b43_gphy_dc_lt_init(struct b43_wldev *dev)
-{
-       struct b43_phy *phy = &dev->phy;
-       struct b43_txpower_lo_control *lo = phy->lo_control;
-       struct b43_loctl *loctl0;
-       struct b43_loctl *loctl1;
-       int i;
-       int rf_offset, bb_offset;
-       u16 tmp;
-
-       for (i = 0; i < lo->rfatt_list.len + lo->bbatt_list.len; i += 2) {
-               rf_offset = i / lo->rfatt_list.len;
-               bb_offset = i % lo->rfatt_list.len;
-
-               loctl0 = b43_get_lo_g_ctl(dev, &lo->rfatt_list.list[rf_offset],
-                                         &lo->bbatt_list.list[bb_offset]);
-               if (i + 1 < lo->rfatt_list.len * lo->bbatt_list.len) {
-                       rf_offset = (i + 1) / lo->rfatt_list.len;
-                       bb_offset = (i + 1) % lo->rfatt_list.len;
-
-                       loctl1 =
-                           b43_get_lo_g_ctl(dev,
-                                            &lo->rfatt_list.list[rf_offset],
-                                            &lo->bbatt_list.list[bb_offset]);
-               } else
-                       loctl1 = loctl0;
-
-               tmp = ((u16) loctl0->q & 0xF);
-               tmp |= ((u16) loctl0->i & 0xF) << 4;
-               tmp |= ((u16) loctl1->q & 0xF) << 8;
-               tmp |= ((u16) loctl1->i & 0xF) << 12;   //FIXME?
-               b43_phy_write(dev, 0x3A0 + (i / 2), tmp);
-       }
-}
-
 static void hardware_pctl_init_aphy(struct b43_wldev *dev)
 {
        //TODO
@@ -643,7 +587,7 @@ static void hardware_pctl_init_gphy(struct b43_wldev *dev)
        b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801)
                      & 0xFFBF);
 
-       b43_gphy_dc_lt_init(dev);
+       b43_gphy_dc_lt_init(dev, 1);
 }
 
 /* HardwarePowerControl init for A and G PHY */
@@ -931,109 +875,6 @@ static void b43_phy_inita(struct b43_wldev *dev)
        }
 }
 
-static void b43_phy_initb2(struct b43_wldev *dev)
-{
-       struct b43_phy *phy = &dev->phy;
-       u16 offset, val;
-
-       b43_write16(dev, 0x03EC, 0x3F22);
-       b43_phy_write(dev, 0x0020, 0x301C);
-       b43_phy_write(dev, 0x0026, 0x0000);
-       b43_phy_write(dev, 0x0030, 0x00C6);
-       b43_phy_write(dev, 0x0088, 0x3E00);
-       val = 0x3C3D;
-       for (offset = 0x0089; offset < 0x00A7; offset++) {
-               b43_phy_write(dev, offset, val);
-               val -= 0x0202;
-       }
-       b43_phy_write(dev, 0x03E4, 0x3000);
-       b43_radio_selectchannel(dev, phy->channel, 0);
-       if (phy->radio_ver != 0x2050) {
-               b43_radio_write16(dev, 0x0075, 0x0080);
-               b43_radio_write16(dev, 0x0079, 0x0081);
-       }
-       b43_radio_write16(dev, 0x0050, 0x0020);
-       b43_radio_write16(dev, 0x0050, 0x0023);
-       if (phy->radio_ver == 0x2050) {
-               b43_radio_write16(dev, 0x0050, 0x0020);
-               b43_radio_write16(dev, 0x005A, 0x0070);
-               b43_radio_write16(dev, 0x005B, 0x007B);
-               b43_radio_write16(dev, 0x005C, 0x00B0);
-               b43_radio_write16(dev, 0x007A, 0x000F);
-               b43_phy_write(dev, 0x0038, 0x0677);
-               b43_radio_init2050(dev);
-       }
-       b43_phy_write(dev, 0x0014, 0x0080);
-       b43_phy_write(dev, 0x0032, 0x00CA);
-       b43_phy_write(dev, 0x0032, 0x00CC);
-       b43_phy_write(dev, 0x0035, 0x07C2);
-       b43_lo_b_measure(dev);
-       b43_phy_write(dev, 0x0026, 0xCC00);
-       if (phy->radio_ver != 0x2050)
-               b43_phy_write(dev, 0x0026, 0xCE00);
-       b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1000);
-       b43_phy_write(dev, 0x002A, 0x88A3);
-       if (phy->radio_ver != 0x2050)
-               b43_phy_write(dev, 0x002A, 0x88C2);
-       b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
-       b43_phy_init_pctl(dev);
-}
-
-static void b43_phy_initb4(struct b43_wldev *dev)
-{
-       struct b43_phy *phy = &dev->phy;
-       u16 offset, val;
-
-       b43_write16(dev, 0x03EC, 0x3F22);
-       b43_phy_write(dev, 0x0020, 0x301C);
-       b43_phy_write(dev, 0x0026, 0x0000);
-       b43_phy_write(dev, 0x0030, 0x00C6);
-       b43_phy_write(dev, 0x0088, 0x3E00);
-       val = 0x3C3D;
-       for (offset = 0x0089; offset < 0x00A7; offset++) {
-               b43_phy_write(dev, offset, val);
-               val -= 0x0202;
-       }
-       b43_phy_write(dev, 0x03E4, 0x3000);
-       b43_radio_selectchannel(dev, phy->channel, 0);
-       if (phy->radio_ver != 0x2050) {
-               b43_radio_write16(dev, 0x0075, 0x0080);
-               b43_radio_write16(dev, 0x0079, 0x0081);
-       }
-       b43_radio_write16(dev, 0x0050, 0x0020);
-       b43_radio_write16(dev, 0x0050, 0x0023);
-       if (phy->radio_ver == 0x2050) {
-               b43_radio_write16(dev, 0x0050, 0x0020);
-               b43_radio_write16(dev, 0x005A, 0x0070);
-               b43_radio_write16(dev, 0x005B, 0x007B);
-               b43_radio_write16(dev, 0x005C, 0x00B0);
-               b43_radio_write16(dev, 0x007A, 0x000F);
-               b43_phy_write(dev, 0x0038, 0x0677);
-               b43_radio_init2050(dev);
-       }
-       b43_phy_write(dev, 0x0014, 0x0080);
-       b43_phy_write(dev, 0x0032, 0x00CA);
-       if (phy->radio_ver == 0x2050)
-               b43_phy_write(dev, 0x0032, 0x00E0);
-       b43_phy_write(dev, 0x0035, 0x07C2);
-
-       b43_lo_b_measure(dev);
-
-       b43_phy_write(dev, 0x0026, 0xCC00);
-       if (phy->radio_ver == 0x2050)
-               b43_phy_write(dev, 0x0026, 0xCE00);
-       b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1100);
-       b43_phy_write(dev, 0x002A, 0x88A3);
-       if (phy->radio_ver == 0x2050)
-               b43_phy_write(dev, 0x002A, 0x88C2);
-       b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
-       if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
-               b43_calc_nrssi_slope(dev);
-               b43_calc_nrssi_threshold(dev);
-       }
-       b43_phy_init_pctl(dev);
-}
-
 static void b43_phy_initb5(struct b43_wldev *dev)
 {
        struct ssb_bus *bus = dev->dev->bus;
@@ -1259,19 +1100,9 @@ static void b43_phy_initb6(struct b43_wldev *dev)
                b43_phy_write(dev, 0x0002, (b43_phy_read(dev, 0x0002) & 0xFFC0)
                              | 0x0004);
        }
-       if (phy->type == B43_PHYTYPE_B) {
-               b43_write16(dev, 0x03E6, 0x8140);
-               b43_phy_write(dev, 0x0016, 0x0410);
-               b43_phy_write(dev, 0x0017, 0x0820);
-               b43_phy_write(dev, 0x0062, 0x0007);
-               b43_radio_init2050(dev);
-               b43_lo_g_measure(dev);
-               if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
-                       b43_calc_nrssi_slope(dev);
-                       b43_calc_nrssi_threshold(dev);
-               }
-               b43_phy_init_pctl(dev);
-       } else if (phy->type == B43_PHYTYPE_G)
+       if (phy->type == B43_PHYTYPE_B)
+               B43_WARN_ON(1);
+       else if (phy->type == B43_PHYTYPE_G)
                b43_write16(dev, 0x03E6, 0x0);
 }
 
@@ -1534,34 +1365,31 @@ static void b43_phy_initg(struct b43_wldev *dev)
                else
                        b43_radio_write16(dev, 0x0078, phy->initval);
        }
-       if (phy->lo_control->tx_bias == 0xFF) {
-               b43_lo_g_measure(dev);
+       b43_lo_g_init(dev);
+       if (has_tx_magnification(phy)) {
+               b43_radio_write16(dev, 0x52,
+                                 (b43_radio_read16(dev, 0x52) & 0xFF00)
+                                 | phy->lo_control->tx_bias | phy->
+                                 lo_control->tx_magn);
        } else {
-               if (has_tx_magnification(phy)) {
-                       b43_radio_write16(dev, 0x52,
-                                         (b43_radio_read16(dev, 0x52) & 0xFF00)
-                                         | phy->lo_control->tx_bias | phy->
-                                         lo_control->tx_magn);
-               } else {
-                       b43_radio_write16(dev, 0x52,
-                                         (b43_radio_read16(dev, 0x52) & 0xFFF0)
-                                         | phy->lo_control->tx_bias);
-               }
-               if (phy->rev >= 6) {
-                       b43_phy_write(dev, B43_PHY_CCK(0x36),
-                                     (b43_phy_read(dev, B43_PHY_CCK(0x36))
-                                      & 0x0FFF) | (phy->lo_control->
-                                                   tx_bias << 12));
-               }
-               if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
-                       b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075);
-               else
-                       b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F);
-               if (phy->rev < 2)
-                       b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101);
-               else
-                       b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202);
+               b43_radio_write16(dev, 0x52,
+                                 (b43_radio_read16(dev, 0x52) & 0xFFF0)
+                                 | phy->lo_control->tx_bias);
        }
+       if (phy->rev >= 6) {
+               b43_phy_write(dev, B43_PHY_CCK(0x36),
+                             (b43_phy_read(dev, B43_PHY_CCK(0x36))
+                              & 0x0FFF) | (phy->lo_control->
+                                           tx_bias << 12));
+       }
+       if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
+               b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075);
+       else
+               b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F);
+       if (phy->rev < 2)
+               b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101);
+       else
+               b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202);
        if (phy->gmode || phy->rev >= 2) {
                b43_lo_g_adjust(dev);
                b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
@@ -1572,7 +1400,7 @@ static void b43_phy_initg(struct b43_wldev *dev)
                 * the value 0x7FFFFFFF here. I think that is some weird
                 * compiler optimization in the original driver.
                 * Essentially, what we do here is resetting all NRSSI LT
-                * entries to -32 (see the limit_value() in nrssi_hw_update())
+                * entries to -32 (see the clamp_val() in nrssi_hw_update())
                 */
                b43_nrssi_hw_update(dev, 0xFFFF);       //FIXME?
                b43_calc_nrssi_threshold(dev);
@@ -1634,13 +1462,13 @@ static s8 b43_phy_estimate_power_out(struct b43_wldev *dev, s8 tssi)
        switch (phy->type) {
        case B43_PHYTYPE_A:
                tmp += 0x80;
-               tmp = limit_value(tmp, 0x00, 0xFF);
+               tmp = clamp_val(tmp, 0x00, 0xFF);
                dbm = phy->tssi2dbm[tmp];
                //TODO: There's a FIXME on the specs
                break;
        case B43_PHYTYPE_B:
        case B43_PHYTYPE_G:
-               tmp = limit_value(tmp, 0x00, 0x3F);
+               tmp = clamp_val(tmp, 0x00, 0x3F);
                dbm = phy->tssi2dbm[tmp];
                break;
        default:
@@ -1699,8 +1527,8 @@ void b43_put_attenuation_into_ranges(struct b43_wldev *dev,
                break;
        }
 
-       *_rfatt = limit_value(rfatt, rf_min, rf_max);
-       *_bbatt = limit_value(bbatt, bb_min, bb_max);
+       *_rfatt = clamp_val(rfatt, rf_min, rf_max);
+       *_bbatt = clamp_val(bbatt, bb_min, bb_max);
 }
 
 /* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */
@@ -1795,7 +1623,7 @@ void b43_phy_xmitpower(struct b43_wldev *dev)
                        /* Get desired power (in Q5.2) */
                        desired_pwr = INT_TO_Q52(phy->power_level);
                        /* And limit it. max_pwr already is Q5.2 */
-                       desired_pwr = limit_value(desired_pwr, 0, max_pwr);
+                       desired_pwr = clamp_val(desired_pwr, 0, max_pwr);
                        if (b43_debug(dev, B43_DBG_XMITPOWER)) {
                                b43dbg(dev->wl,
                                       "Current TX power output: " Q52_FMT
@@ -1821,10 +1649,8 @@ void b43_phy_xmitpower(struct b43_wldev *dev)
                        bbatt_delta -= 4 * rfatt_delta;
 
                        /* So do we finally need to adjust something? */
-                       if ((rfatt_delta == 0) && (bbatt_delta == 0)) {
-                               b43_lo_g_ctl_mark_cur_used(dev);
+                       if ((rfatt_delta == 0) && (bbatt_delta == 0))
                                return;
-                       }
 
                        /* Calculate the new attenuation values. */
                        bbatt = phy->bbatt.att;
@@ -1870,7 +1696,6 @@ void b43_phy_xmitpower(struct b43_wldev *dev)
                        b43_radio_lock(dev);
                        b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt,
                                          phy->tx_control);
-                       b43_lo_g_ctl_mark_cur_used(dev);
                        b43_radio_unlock(dev);
                        b43_phy_unlock(dev);
                        break;
@@ -1908,7 +1733,7 @@ static inline
                f = q;
                i++;
        } while (delta >= 2);
-       entry[index] = limit_value(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128);
+       entry[index] = clamp_val(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128);
        return 0;
 }
 
@@ -2007,24 +1832,6 @@ int b43_phy_init(struct b43_wldev *dev)
                else
                        unsupported = 1;
                break;
-       case B43_PHYTYPE_B:
-               switch (phy->rev) {
-               case 2:
-                       b43_phy_initb2(dev);
-                       break;
-               case 4:
-                       b43_phy_initb4(dev);
-                       break;
-               case 5:
-                       b43_phy_initb5(dev);
-                       break;
-               case 6:
-                       b43_phy_initb6(dev);
-                       break;
-               default:
-                       unsupported = 1;
-               }
-               break;
        case B43_PHYTYPE_G:
                b43_phy_initg(dev);
                break;
@@ -2452,7 +2259,7 @@ void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val)
        for (i = 0; i < 64; i++) {
                tmp = b43_nrssi_hw_read(dev, i);
                tmp -= val;
-               tmp = limit_value(tmp, -32, 31);
+               tmp = clamp_val(tmp, -32, 31);
                b43_nrssi_hw_write(dev, i, tmp);
        }
 }
@@ -2469,7 +2276,7 @@ void b43_nrssi_mem_update(struct b43_wldev *dev)
                tmp = (i - delta) * phy->nrssislope;
                tmp /= 0x10000;
                tmp += 0x3A;
-               tmp = limit_value(tmp, 0, 0x3F);
+               tmp = clamp_val(tmp, 0, 0x3F);
                phy->nrssi_lt[i] = tmp;
        }
 }
@@ -2906,7 +2713,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev)
                        } else
                                threshold = phy->nrssi[1] - 5;
 
-                       threshold = limit_value(threshold, 0, 0x3E);
+                       threshold = clamp_val(threshold, 0, 0x3E);
                        b43_phy_read(dev, 0x0020);      /* dummy read */
                        b43_phy_write(dev, 0x0020,
                                      (((u16) threshold) << 8) | 0x001C);
@@ -2957,7 +2764,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev)
                        else
                                a += 32;
                        a = a >> 6;
-                       a = limit_value(a, -31, 31);
+                       a = clamp_val(a, -31, 31);
 
                        b = b * (phy->nrssi[1] - phy->nrssi[0]);
                        b += (phy->nrssi[0] << 6);
@@ -2966,7 +2773,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev)
                        else
                                b += 32;
                        b = b >> 6;
-                       b = limit_value(b, -31, 31);
+                       b = clamp_val(b, -31, 31);
 
                        tmp_u16 = b43_phy_read(dev, 0x048A) & 0xF000;
                        tmp_u16 |= ((u32) b & 0x0000003F);
@@ -3069,13 +2876,13 @@ b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode)
                }
                radio_stacksave(0x0078);
                tmp = (b43_radio_read16(dev, 0x0078) & 0x001E);
-               flipped = flip_4bit(tmp);
+               B43_WARN_ON(tmp > 15);
+               flipped = bitrev4(tmp);
                if (flipped < 10 && flipped >= 8)
                        flipped = 7;
                else if (flipped >= 10)
                        flipped -= 3;
-               flipped = flip_4bit(flipped);
-               flipped = (flipped << 1) | 0x0020;
+               flipped = (bitrev4(flipped) << 1) | 0x0020;
                b43_radio_write16(dev, 0x0078, flipped);
 
                b43_calc_nrssi_threshold(dev);
@@ -3708,7 +3515,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
        tmp1 >>= 9;
 
        for (i = 0; i < 16; i++) {
-               radio78 = ((flip_4bit(i) << 1) | 0x20);
+               radio78 = (bitrev4(i) << 1) | 0x0020;
                b43_radio_write16(dev, 0x78, radio78);
                udelay(10);
                for (j = 0; j < 16; j++) {
index 6d165d8221757d98a957072d133c7683d7f66b3c..4aab109035294ece8908cd6aa00aafcca790d8cc 100644 (file)
@@ -225,7 +225,6 @@ int b43_phy_init(struct b43_wldev *dev);
 void b43_set_rx_antenna(struct b43_wldev *dev, int antenna);
 
 void b43_phy_xmitpower(struct b43_wldev *dev);
-void b43_gphy_dc_lt_init(struct b43_wldev *dev);
 
 /* Returns the boolean whether the board has HardwarePowerControl */
 bool b43_has_hardware_pctl(struct b43_phy *phy);
@@ -252,6 +251,14 @@ struct b43_rfatt_list {
        u8 max_val;
 };
 
+/* Returns true, if the values are the same. */
+static inline bool b43_compare_rfatt(const struct b43_rfatt *a,
+                                    const struct b43_rfatt *b)
+{
+       return ((a->att == b->att) &&
+               (a->with_padmix == b->with_padmix));
+}
+
 /* Baseband Attenuation */
 struct b43_bbatt {
        u8 att;                 /* Attenuation value */
@@ -265,6 +272,13 @@ struct b43_bbatt_list {
        u8 max_val;
 };
 
+/* Returns true, if the values are the same. */
+static inline bool b43_compare_bbatt(const struct b43_bbatt *a,
+                                    const struct b43_bbatt *b)
+{
+       return (a->att == b->att);
+}
+
 /* tx_control bits. */
 #define B43_TXCTL_PA3DB                0x40    /* PA Gain 3dB */
 #define B43_TXCTL_PA2DB                0x20    /* PA Gain 2dB */
index fcacafb043467559768582090a7c7586b51b1e06..8b1555d95f1c81654cafdbfc5fd3668203dd34a9 100644 (file)
@@ -446,29 +446,27 @@ static void pio_tx_frame_4byte_queue(struct b43_pio_txpacket *pack,
 }
 
 static int pio_tx_frame(struct b43_pio_txqueue *q,
-                       struct sk_buff *skb,
-                       struct ieee80211_tx_control *ctl)
+                       struct sk_buff *skb)
 {
        struct b43_pio_txpacket *pack;
        struct b43_txhdr txhdr;
        u16 cookie;
        int err;
        unsigned int hdrlen;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
        B43_WARN_ON(list_empty(&q->packets_list));
        pack = list_entry(q->packets_list.next,
                          struct b43_pio_txpacket, list);
-       memset(&pack->txstat, 0, sizeof(pack->txstat));
-       memcpy(&pack->txstat.control, ctl, sizeof(*ctl));
 
        cookie = generate_cookie(q, pack);
        hdrlen = b43_txhdr_size(q->dev);
        err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb->data,
-                                skb->len, ctl, cookie);
+                                skb->len, info, cookie);
        if (err)
                return err;
 
-       if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) {
+       if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
                /* Tell the firmware about the cookie of the last
                 * mcast frame, so it can clear the more-data bit in it. */
                b43_shm_write16(q->dev, B43_SHM_SHARED,
@@ -492,17 +490,18 @@ static int pio_tx_frame(struct b43_pio_txqueue *q,
        return 0;
 }
 
-int b43_pio_tx(struct b43_wldev *dev,
-              struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb)
 {
        struct b43_pio_txqueue *q;
        struct ieee80211_hdr *hdr;
        unsigned long flags;
        unsigned int hdrlen, total_len;
        int err = 0;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
        hdr = (struct ieee80211_hdr *)skb->data;
-       if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) {
+
+       if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
                /* The multicast queue will be sent after the DTIM. */
                q = dev->pio.tx_queue_mcast;
                /* Set the frame More-Data bit. Ucode will clear it
@@ -510,7 +509,7 @@ int b43_pio_tx(struct b43_wldev *dev,
                hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
        } else {
                /* Decide by priority where to put this frame. */
-               q = select_queue_by_priority(dev, ctl->queue);
+               q = select_queue_by_priority(dev, skb_get_queue_mapping(skb));
        }
 
        spin_lock_irqsave(&q->lock, flags);
@@ -533,7 +532,7 @@ int b43_pio_tx(struct b43_wldev *dev,
        if (total_len > (q->buffer_size - q->buffer_used)) {
                /* Not enough memory on the queue. */
                err = -EBUSY;
-               ieee80211_stop_queue(dev->wl->hw, ctl->queue);
+               ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb));
                q->stopped = 1;
                goto out_unlock;
        }
@@ -541,9 +540,9 @@ int b43_pio_tx(struct b43_wldev *dev,
        /* Assign the queue number to the ring (if not already done before)
         * so TX status handling can use it. The mac80211-queue to b43-queue
         * mapping is static, so we don't need to store it per frame. */
-       q->queue_prio = ctl->queue;
+       q->queue_prio = skb_get_queue_mapping(skb);
 
-       err = pio_tx_frame(q, skb, ctl);
+       err = pio_tx_frame(q, skb);
        if (unlikely(err == -ENOKEY)) {
                /* Drop this packet, as we don't have the encryption key
                 * anymore and must not transmit it unencrypted. */
@@ -561,7 +560,7 @@ int b43_pio_tx(struct b43_wldev *dev,
        if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) ||
            (q->free_packet_slots == 0)) {
                /* The queue is full. */
-               ieee80211_stop_queue(dev->wl->hw, ctl->queue);
+               ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb));
                q->stopped = 1;
        }
 
@@ -578,6 +577,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev,
        struct b43_pio_txqueue *q;
        struct b43_pio_txpacket *pack = NULL;
        unsigned int total_len;
+       struct ieee80211_tx_info *info;
 
        q = parse_cookie(dev, status->cookie, &pack);
        if (unlikely(!q))
@@ -586,15 +586,17 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev,
 
        spin_lock(&q->lock); /* IRQs are already disabled. */
 
-       b43_fill_txstatus_report(&(pack->txstat), status);
+       info = (void *)pack->skb;
+       memset(&info->status, 0, sizeof(info->status));
+
+       b43_fill_txstatus_report(info, status);
 
        total_len = pack->skb->len + b43_txhdr_size(dev);
        total_len = roundup(total_len, 4);
        q->buffer_used -= total_len;
        q->free_packet_slots += 1;
 
-       ieee80211_tx_status_irqsafe(dev->wl->hw, pack->skb,
-                                   &(pack->txstat));
+       ieee80211_tx_status_irqsafe(dev->wl->hw, pack->skb);
        pack->skb = NULL;
        list_add(&pack->list, &q->packets_list);
 
@@ -611,18 +613,16 @@ void b43_pio_get_tx_stats(struct b43_wldev *dev,
 {
        const int nr_queues = dev->wl->hw->queues;
        struct b43_pio_txqueue *q;
-       struct ieee80211_tx_queue_stats_data *data;
        unsigned long flags;
        int i;
 
        for (i = 0; i < nr_queues; i++) {
-               data = &(stats->data[i]);
                q = select_queue_by_priority(dev, i);
 
                spin_lock_irqsave(&q->lock, flags);
-               data->len = B43_PIO_MAX_NR_TXPACKETS - q->free_packet_slots;
-               data->limit = B43_PIO_MAX_NR_TXPACKETS;
-               data->count = q->nr_tx_packets;
+               stats[i].len = B43_PIO_MAX_NR_TXPACKETS - q->free_packet_slots;
+               stats[i].limit = B43_PIO_MAX_NR_TXPACKETS;
+               stats[i].count = q->nr_tx_packets;
                spin_unlock_irqrestore(&q->lock, flags);
        }
 }
index e2ec676cc9e489993e61cc613b4add18acd35f4e..6c174c91ca20fd454ccd1d79d6d68fffce57928d 100644 (file)
@@ -62,8 +62,6 @@ struct b43_pio_txpacket {
        struct b43_pio_txqueue *queue;
        /* The TX data packet. */
        struct sk_buff *skb;
-       /* The status meta data. */
-       struct ieee80211_tx_status txstat;
        /* Index in the (struct b43_pio_txqueue)->packets array. */
        u8 index;
 
@@ -167,8 +165,7 @@ int b43_pio_init(struct b43_wldev *dev);
 void b43_pio_stop(struct b43_wldev *dev);
 void b43_pio_free(struct b43_wldev *dev);
 
-int b43_pio_tx(struct b43_wldev *dev,
-              struct sk_buff *skb, struct ieee80211_tx_control *ctl);
+int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb);
 void b43_pio_handle_txstatus(struct b43_wldev *dev,
                             const struct b43_txstatus *status);
 void b43_pio_get_tx_stats(struct b43_wldev *dev,
@@ -193,8 +190,7 @@ static inline void b43_pio_stop(struct b43_wldev *dev)
 {
 }
 static inline int b43_pio_tx(struct b43_wldev *dev,
-                            struct sk_buff *skb,
-                            struct ieee80211_tx_control *ctl)
+                            struct sk_buff *skb)
 {
        return 0;
 }
index 19aefbfb2c930137d6ca8ea1d5a5532713a1f46f..f9e1cff2aecbec42752c3a4336288f86229c766d 100644 (file)
@@ -185,14 +185,14 @@ int b43_generate_txhdr(struct b43_wldev *dev,
                       u8 *_txhdr,
                       const unsigned char *fragment_data,
                       unsigned int fragment_len,
-                      const struct ieee80211_tx_control *txctl,
+                      const struct ieee80211_tx_info *info,
                       u16 cookie)
 {
        struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr;
        const struct b43_phy *phy = &dev->phy;
        const struct ieee80211_hdr *wlhdr =
            (const struct ieee80211_hdr *)fragment_data;
-       int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT));
+       int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT));
        u16 fctl = le16_to_cpu(wlhdr->frame_control);
        struct ieee80211_rate *fbrate;
        u8 rate, rate_fb;
@@ -201,13 +201,14 @@ int b43_generate_txhdr(struct b43_wldev *dev,
        u32 mac_ctl = 0;
        u16 phy_ctl = 0;
        u8 extra_ft = 0;
+       struct ieee80211_rate *txrate;
 
        memset(txhdr, 0, sizeof(*txhdr));
 
-       WARN_ON(!txctl->tx_rate);
-       rate = txctl->tx_rate ? txctl->tx_rate->hw_value : B43_CCK_RATE_1MB;
+       txrate = ieee80211_get_tx_rate(dev->wl->hw, info);
+       rate = txrate ? txrate->hw_value : B43_CCK_RATE_1MB;
        rate_ofdm = b43_is_ofdm_rate(rate);
-       fbrate = txctl->alt_retry_rate ? : txctl->tx_rate;
+       fbrate = ieee80211_get_alt_retry_rate(dev->wl->hw, info) ? : txrate;
        rate_fb = fbrate->hw_value;
        rate_fb_ofdm = b43_is_ofdm_rate(rate_fb);
 
@@ -227,15 +228,13 @@ int b43_generate_txhdr(struct b43_wldev *dev,
                 * use the original dur_id field. */
                txhdr->dur_fb = wlhdr->duration_id;
        } else {
-               txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
-                                                                txctl->vif,
-                                                                fragment_len,
-                                                                fbrate);
+               txhdr->dur_fb = ieee80211_generic_frame_duration(
+                       dev->wl->hw, info->control.vif, fragment_len, fbrate);
        }
 
        plcp_fragment_len = fragment_len + FCS_LEN;
        if (use_encryption) {
-               u8 key_idx = (u16) (txctl->key_idx);
+               u8 key_idx = info->control.hw_key->hw_key_idx;
                struct b43_key *key;
                int wlhdr_len;
                size_t iv_len;
@@ -253,7 +252,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
                }
 
                /* Hardware appends ICV. */
-               plcp_fragment_len += txctl->icv_len;
+               plcp_fragment_len += info->control.icv_len;
 
                key_idx = b43_kidx_to_fw(dev, key_idx);
                mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) &
@@ -261,7 +260,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
                mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) &
                           B43_TXH_MAC_KEYALG;
                wlhdr_len = ieee80211_get_hdrlen(fctl);
-               iv_len = min((size_t) txctl->iv_len,
+               iv_len = min((size_t) info->control.iv_len,
                             ARRAY_SIZE(txhdr->iv));
                memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
        }
@@ -292,10 +291,10 @@ int b43_generate_txhdr(struct b43_wldev *dev,
                phy_ctl |= B43_TXH_PHY_ENC_OFDM;
        else
                phy_ctl |= B43_TXH_PHY_ENC_CCK;
-       if (txctl->flags & IEEE80211_TXCTL_SHORT_PREAMBLE)
+       if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE)
                phy_ctl |= B43_TXH_PHY_SHORTPRMBL;
 
-       switch (b43_ieee80211_antenna_sanitize(dev, txctl->antenna_sel_tx)) {
+       switch (b43_ieee80211_antenna_sanitize(dev, info->antenna_sel_tx)) {
        case 0: /* Default */
                phy_ctl |= B43_TXH_PHY_ANT01AUTO;
                break;
@@ -316,34 +315,36 @@ int b43_generate_txhdr(struct b43_wldev *dev,
        }
 
        /* MAC control */
-       if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK))
+       if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
                mac_ctl |= B43_TXH_MAC_ACK;
        if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
              ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
                mac_ctl |= B43_TXH_MAC_HWSEQ;
-       if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)
+       if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
                mac_ctl |= B43_TXH_MAC_STMSDU;
        if (phy->type == B43_PHYTYPE_A)
                mac_ctl |= B43_TXH_MAC_5GHZ;
-       if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT)
+       if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
                mac_ctl |= B43_TXH_MAC_LONGFRAME;
 
        /* Generate the RTS or CTS-to-self frame */
-       if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
-           (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
+       if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
+           (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
                unsigned int len;
                struct ieee80211_hdr *hdr;
                int rts_rate, rts_rate_fb;
                int rts_rate_ofdm, rts_rate_fb_ofdm;
                struct b43_plcp_hdr6 *plcp;
+               struct ieee80211_rate *rts_cts_rate;
 
-               WARN_ON(!txctl->rts_cts_rate);
-               rts_rate = txctl->rts_cts_rate ? txctl->rts_cts_rate->hw_value : B43_CCK_RATE_1MB;
+               rts_cts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info);
+
+               rts_rate = rts_cts_rate ? rts_cts_rate->hw_value : B43_CCK_RATE_1MB;
                rts_rate_ofdm = b43_is_ofdm_rate(rts_rate);
                rts_rate_fb = b43_calc_fallback_rate(rts_rate);
                rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
 
-               if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
+               if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
                        struct ieee80211_cts *cts;
 
                        if (b43_is_old_txhdr_format(dev)) {
@@ -353,9 +354,9 @@ int b43_generate_txhdr(struct b43_wldev *dev,
                                cts = (struct ieee80211_cts *)
                                        (txhdr->new_format.rts_frame);
                        }
-                       ieee80211_ctstoself_get(dev->wl->hw, txctl->vif,
+                       ieee80211_ctstoself_get(dev->wl->hw, info->control.vif,
                                                fragment_data, fragment_len,
-                                               txctl, cts);
+                                               info, cts);
                        mac_ctl |= B43_TXH_MAC_SENDCTS;
                        len = sizeof(struct ieee80211_cts);
                } else {
@@ -368,9 +369,9 @@ int b43_generate_txhdr(struct b43_wldev *dev,
                                rts = (struct ieee80211_rts *)
                                        (txhdr->new_format.rts_frame);
                        }
-                       ieee80211_rts_get(dev->wl->hw, txctl->vif,
+                       ieee80211_rts_get(dev->wl->hw, info->control.vif,
                                          fragment_data, fragment_len,
-                                         txctl, rts);
+                                         info, rts);
                        mac_ctl |= B43_TXH_MAC_SENDRTS;
                        len = sizeof(struct ieee80211_rts);
                }
@@ -581,12 +582,11 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
                //      and also find out what the maximum possible value is.
                //      Fill status.ssi and status.signal fields.
        } else {
-               status.ssi = b43_rssi_postprocess(dev, rxhdr->jssi,
+               status.signal = b43_rssi_postprocess(dev, rxhdr->jssi,
                                                  (phystat0 & B43_RX_PHYST0_OFDM),
                                                  (phystat0 & B43_RX_PHYST0_GAINCTL),
                                                  (phystat3 & B43_RX_PHYST3_TRSTATE));
-               /* the next line looks wrong, but is what mac80211 wants */
-               status.signal = (rxhdr->jssi * 100) / B43_RX_MAX_SSI;
+               status.qual = (rxhdr->jssi * 100) / B43_RX_MAX_SSI;
        }
 
        if (phystat0 & B43_RX_PHYST0_OFDM)
@@ -685,27 +685,27 @@ void b43_handle_txstatus(struct b43_wldev *dev,
 /* Fill out the mac80211 TXstatus report based on the b43-specific
  * txstatus report data. This returns a boolean whether the frame was
  * successfully transmitted. */
-bool b43_fill_txstatus_report(struct ieee80211_tx_status *report,
+bool b43_fill_txstatus_report(struct ieee80211_tx_info *report,
                              const struct b43_txstatus *status)
 {
        bool frame_success = 1;
 
        if (status->acked) {
                /* The frame was ACKed. */
-               report->flags |= IEEE80211_TX_STATUS_ACK;
+               report->flags |= IEEE80211_TX_STAT_ACK;
        } else {
                /* The frame was not ACKed... */
-               if (!(report->control.flags & IEEE80211_TXCTL_NO_ACK)) {
+               if (!(report->flags & IEEE80211_TX_CTL_NO_ACK)) {
                        /* ...but we expected an ACK. */
                        frame_success = 0;
-                       report->excessive_retries = 1;
+                       report->status.excessive_retries = 1;
                }
        }
        if (status->frame_count == 0) {
                /* The frame was not transmitted at all. */
-               report->retry_count = 0;
+               report->status.retry_count = 0;
        } else
-               report->retry_count = status->frame_count - 1;
+               report->status.retry_count = status->frame_count - 1;
 
        return frame_success;
 }
index b05f44e0d626cfcb8eb8148df36327071325a4dc..0215faf4754181cb6069b4878349d3d4c48e88d6 100644 (file)
@@ -178,7 +178,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
                       u8 * txhdr,
                       const unsigned char *fragment_data,
                       unsigned int fragment_len,
-                      const struct ieee80211_tx_control *txctl, u16 cookie);
+                      const struct ieee80211_tx_info *txctl, u16 cookie);
 
 /* Transmit Status */
 struct b43_txstatus {
@@ -294,7 +294,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr);
 
 void b43_handle_txstatus(struct b43_wldev *dev,
                         const struct b43_txstatus *status);
-bool b43_fill_txstatus_report(struct ieee80211_tx_status *report,
+bool b43_fill_txstatus_report(struct ieee80211_tx_info *report,
                              const struct b43_txstatus *status);
 
 void b43_tx_suspend(struct b43_wldev *dev);
index ded3cd31b3df40bceac4a5208414eb8cc12f55ea..c40078e1fff9f3efabfa92f787dcb7217018669d 100644 (file)
@@ -823,23 +823,6 @@ void b43legacydbg(struct b43legacy_wl *wl, const char *fmt, ...)
 # define b43legacydbg(wl, fmt...) do { /* nothing */ } while (0)
 #endif /* DEBUG */
 
-
-/** Limit a value between two limits */
-#ifdef limit_value
-# undef limit_value
-#endif
-#define limit_value(value, min, max)  \
-       ({                                              \
-               typeof(value) __value = (value);        \
-               typeof(value) __min = (min);            \
-               typeof(value) __max = (max);            \
-               if (__value < __min)                    \
-                       __value = __min;                \
-               else if (__value > __max)               \
-                       __value = __max;                \
-               __value;                                \
-       })
-
 /* Macros for printing a value in Q5.2 format */
 #define Q52_FMT                "%u.%u"
 #define Q52_ARG(q52)   ((q52) / 4), (((q52) & 3) * 100 / 4)
index c990f87b107acff6603a24a70b8f402144f64d9c..33cc256c5baf5311a0f52b9d93ab3411ca95a316 100644 (file)
@@ -1205,10 +1205,10 @@ struct b43legacy_dmaring *parse_cookie(struct b43legacy_wldev *dev,
 }
 
 static int dma_tx_fragment(struct b43legacy_dmaring *ring,
-                           struct sk_buff *skb,
-                           struct ieee80211_tx_control *ctl)
+                           struct sk_buff *skb)
 {
        const struct b43legacy_dma_ops *ops = ring->ops;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        u8 *header;
        int slot, old_top_slot, old_used_slots;
        int err;
@@ -1231,7 +1231,7 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
        header = &(ring->txhdr_cache[slot * sizeof(
                               struct b43legacy_txhdr_fw3)]);
        err = b43legacy_generate_txhdr(ring->dev, header,
-                                skb->data, skb->len, ctl,
+                                skb->data, skb->len, info,
                                 generate_cookie(ring, slot));
        if (unlikely(err)) {
                ring->current_slot = old_top_slot;
@@ -1255,7 +1255,6 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring,
        desc = ops->idx2desc(ring, slot, &meta);
        memset(meta, 0, sizeof(*meta));
 
-       memcpy(&meta->txstat.control, ctl, sizeof(*ctl));
        meta->skb = skb;
        meta->is_last_fragment = 1;
 
@@ -1323,14 +1322,13 @@ int should_inject_overflow(struct b43legacy_dmaring *ring)
 }
 
 int b43legacy_dma_tx(struct b43legacy_wldev *dev,
-                    struct sk_buff *skb,
-                    struct ieee80211_tx_control *ctl)
+                    struct sk_buff *skb)
 {
        struct b43legacy_dmaring *ring;
        int err = 0;
        unsigned long flags;
 
-       ring = priority_to_txring(dev, ctl->queue);
+       ring = priority_to_txring(dev, skb_get_queue_mapping(skb));
        spin_lock_irqsave(&ring->lock, flags);
        B43legacy_WARN_ON(!ring->tx);
        if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) {
@@ -1343,7 +1341,7 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev,
         * That would be a mac80211 bug. */
        B43legacy_BUG_ON(ring->stopped);
 
-       err = dma_tx_fragment(ring, skb, ctl);
+       err = dma_tx_fragment(ring, skb);
        if (unlikely(err == -ENOKEY)) {
                /* Drop this packet, as we don't have the encryption key
                 * anymore and must not transmit it unencrypted. */
@@ -1401,26 +1399,29 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
                                         1);
 
                if (meta->is_last_fragment) {
-                       B43legacy_WARN_ON(!meta->skb);
+                       struct ieee80211_tx_info *info;
+                       BUG_ON(!meta->skb);
+                       info = IEEE80211_SKB_CB(meta->skb);
                        /* Call back to inform the ieee80211 subsystem about the
                         * status of the transmission.
                         * Some fields of txstat are already filled in dma_tx().
                         */
+
+                       memset(&info->status, 0, sizeof(info->status));
+
                        if (status->acked) {
-                               meta->txstat.flags |= IEEE80211_TX_STATUS_ACK;
+                               info->flags |= IEEE80211_TX_STAT_ACK;
                        } else {
-                               if (!(meta->txstat.control.flags
-                                     & IEEE80211_TXCTL_NO_ACK))
-                                        meta->txstat.excessive_retries = 1;
+                               if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
+                                        info->status.excessive_retries = 1;
                        }
                        if (status->frame_count == 0) {
                                /* The frame was not transmitted at all. */
-                               meta->txstat.retry_count = 0;
+                               info->status.retry_count = 0;
                        } else
-                               meta->txstat.retry_count = status->frame_count
+                               info->status.retry_count = status->frame_count
                                                           - 1;
-                       ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb,
-                                                   &(meta->txstat));
+                       ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb);
                        /* skb is freed by ieee80211_tx_status_irqsafe() */
                        meta->skb = NULL;
                } else {
@@ -1455,18 +1456,16 @@ void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev,
 {
        const int nr_queues = dev->wl->hw->queues;
        struct b43legacy_dmaring *ring;
-       struct ieee80211_tx_queue_stats_data *data;
        unsigned long flags;
        int i;
 
        for (i = 0; i < nr_queues; i++) {
-               data = &(stats->data[i]);
                ring = priority_to_txring(dev, i);
 
                spin_lock_irqsave(&ring->lock, flags);
-               data->len = ring->used_slots / SLOTS_PER_PACKET;
-               data->limit = ring->nr_slots / SLOTS_PER_PACKET;
-               data->count = ring->nr_tx_packets;
+               stats[i].len = ring->used_slots / SLOTS_PER_PACKET;
+               stats[i].limit = ring->nr_slots / SLOTS_PER_PACKET;
+               stats[i].count = ring->nr_tx_packets;
                spin_unlock_irqrestore(&ring->lock, flags);
        }
 }
index 2dd488c5be2da1bcf08d48f339a29ce4666755f1..2f186003c31e5c0ee6c3a88b1215e04703168720 100644 (file)
@@ -195,7 +195,6 @@ struct b43legacy_dmadesc_meta {
        dma_addr_t dmaaddr;
        /* ieee80211 TX status. Only used once per 802.11 frag. */
        bool is_last_fragment;
-       struct ieee80211_tx_status txstat;
 };
 
 struct b43legacy_dmaring;
@@ -297,8 +296,7 @@ void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev,
                                struct ieee80211_tx_queue_stats *stats);
 
 int b43legacy_dma_tx(struct b43legacy_wldev *dev,
-                    struct sk_buff *skb,
-                    struct ieee80211_tx_control *ctl);
+                    struct sk_buff *skb);
 void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
                                   const struct b43legacy_txstatus *status);
 
@@ -323,8 +321,7 @@ void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev,
 }
 static inline
 int b43legacy_dma_tx(struct b43legacy_wldev *dev,
-                    struct sk_buff *skb,
-                    struct ieee80211_tx_control *ctl)
+                    struct sk_buff *skb)
 {
        return 0;
 }
index 204077c13870c05b619f781154bcc942eb1cdf1d..5f533b93ad5df4c042f7103a2c0b371879419a32 100644 (file)
@@ -846,10 +846,10 @@ static void handle_irq_noise(struct b43legacy_wldev *dev)
        /* Get the noise samples. */
        B43legacy_WARN_ON(dev->noisecalc.nr_samples >= 8);
        i = dev->noisecalc.nr_samples;
-       noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
-       noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
-       noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
-       noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+       noise[0] = clamp_val(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+       noise[1] = clamp_val(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+       noise[2] = clamp_val(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+       noise[3] = clamp_val(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
        dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]];
        dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]];
        dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]];
@@ -2358,8 +2358,7 @@ static int b43legacy_rng_init(struct b43legacy_wl *wl)
 }
 
 static int b43legacy_op_tx(struct ieee80211_hw *hw,
-                          struct sk_buff *skb,
-                          struct ieee80211_tx_control *ctl)
+                          struct sk_buff *skb)
 {
        struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
        struct b43legacy_wldev *dev = wl->current_dev;
@@ -2373,18 +2372,17 @@ static int b43legacy_op_tx(struct ieee80211_hw *hw,
        /* DMA-TX is done without a global lock. */
        if (b43legacy_using_pio(dev)) {
                spin_lock_irqsave(&wl->irq_lock, flags);
-               err = b43legacy_pio_tx(dev, skb, ctl);
+               err = b43legacy_pio_tx(dev, skb);
                spin_unlock_irqrestore(&wl->irq_lock, flags);
        } else
-               err = b43legacy_dma_tx(dev, skb, ctl);
+               err = b43legacy_dma_tx(dev, skb);
 out:
        if (unlikely(err))
                return NETDEV_TX_BUSY;
        return NETDEV_TX_OK;
 }
 
-static int b43legacy_op_conf_tx(struct ieee80211_hw *hw,
-                               int queue,
+static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
                                const struct ieee80211_tx_queue_params *params)
 {
        return 0;
@@ -2795,7 +2793,6 @@ static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev)
        /* Start data flow (TX/RX) */
        b43legacy_mac_enable(dev);
        b43legacy_interrupt_enable(dev, dev->irq_savedstate);
-       ieee80211_start_queues(dev->wl->hw);
 
        /* Start maintenance work */
        b43legacy_periodic_tasks_setup(dev);
@@ -3404,7 +3401,7 @@ static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw,
         * field, but that would probably require resizing and moving of data
         * within the beacon template. Simply request a new beacon and let
         * mac80211 do the hard work. */
-       beacon = ieee80211_beacon_get(hw, wl->vif, NULL);
+       beacon = ieee80211_beacon_get(hw, wl->vif);
        if (unlikely(!beacon))
                return -ENOMEM;
        spin_lock_irqsave(&wl->irq_lock, flags);
@@ -3415,8 +3412,7 @@ static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw,
 }
 
 static int b43legacy_op_ibss_beacon_update(struct ieee80211_hw *hw,
-                                          struct sk_buff *beacon,
-                                          struct ieee80211_tx_control *ctl)
+                                          struct sk_buff *beacon)
 {
        struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
        unsigned long flags;
@@ -3716,10 +3712,9 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
 
        /* fill hw info */
        hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
-                   IEEE80211_HW_RX_INCLUDES_FCS;
-       hw->max_signal = 100;
-       hw->max_rssi = -110;
-       hw->max_noise = -110;
+                   IEEE80211_HW_RX_INCLUDES_FCS |
+                   IEEE80211_HW_SIGNAL_DBM |
+                   IEEE80211_HW_NOISE_DBM;
        hw->queues = 1; /* FIXME: hardware has more queues */
        SET_IEEE80211_DEV(hw, dev->dev);
        if (is_valid_ether_addr(sprom->et1mac))
index 8e5c09b818715e87baf89a3c012d2cf8a1110c32..768cccb9b1bafbb4a85d5c2ff77d71900e6b5a0b 100644 (file)
@@ -1088,7 +1088,7 @@ static void b43legacy_phy_initg(struct b43legacy_wldev *dev)
                 * the value 0x7FFFFFFF here. I think that is some weird
                 * compiler optimization in the original driver.
                 * Essentially, what we do here is resetting all NRSSI LT
-                * entries to -32 (see the limit_value() in nrssi_hw_update())
+                * entries to -32 (see the clamp_val() in nrssi_hw_update())
                 */
                b43legacy_nrssi_hw_update(dev, 0xFFFF);
                b43legacy_calc_nrssi_threshold(dev);
@@ -1756,7 +1756,7 @@ static s8 b43legacy_phy_estimate_power_out(struct b43legacy_wldev *dev, s8 tssi)
        switch (phy->type) {
        case B43legacy_PHYTYPE_B:
        case B43legacy_PHYTYPE_G:
-               tmp = limit_value(tmp, 0x00, 0x3F);
+               tmp = clamp_val(tmp, 0x00, 0x3F);
                dbm = phy->tssi2dbm[tmp];
                break;
        default:
@@ -1859,7 +1859,7 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev)
 
        /* find the desired power in Q5.2 - power_level is in dBm
         * and limit it - max_pwr is already in Q5.2 */
-       desired_pwr = limit_value(phy->power_level << 2, 0, max_pwr);
+       desired_pwr = clamp_val(phy->power_level << 2, 0, max_pwr);
        if (b43legacy_debug(dev, B43legacy_DBG_XMITPOWER))
                b43legacydbg(dev->wl, "Current TX power output: " Q52_FMT
                       " dBm, Desired TX power output: " Q52_FMT
@@ -1905,7 +1905,7 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev)
                        radio_attenuation++;
                }
        }
-       baseband_attenuation = limit_value(baseband_attenuation, 0, 11);
+       baseband_attenuation = clamp_val(baseband_attenuation, 0, 11);
 
        txpower = phy->txctl1;
        if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) {
@@ -1933,8 +1933,8 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev)
        }
        /* Save the control values */
        phy->txctl1 = txpower;
-       baseband_attenuation = limit_value(baseband_attenuation, 0, 11);
-       radio_attenuation = limit_value(radio_attenuation, 0, 9);
+       baseband_attenuation = clamp_val(baseband_attenuation, 0, 11);
+       radio_attenuation = clamp_val(radio_attenuation, 0, 9);
        phy->rfatt = radio_attenuation;
        phy->bbatt = baseband_attenuation;
 
@@ -1979,7 +1979,7 @@ s8 b43legacy_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2)
                f = q;
                i++;
        } while (delta >= 2);
-       entry[index] = limit_value(b43legacy_tssi2dbm_ad(m1 * f, 8192),
+       entry[index] = clamp_val(b43legacy_tssi2dbm_ad(m1 * f, 8192),
                                   -127, 128);
        return 0;
 }
index bcdd54eb2edb52683804712201f8ee78260c853b..a86c7647fa2d62caec9027d316f3ddd648f156a6 100644 (file)
@@ -196,7 +196,7 @@ static int pio_tx_write_fragment(struct b43legacy_pioqueue *queue,
        B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0);
        err = b43legacy_generate_txhdr(queue->dev,
                                 txhdr, skb->data, skb->len,
-                                &packet->txstat.control,
+                                IEEE80211_SKB_CB(skb),
                                 generate_cookie(queue, packet));
        if (err)
                return err;
@@ -463,8 +463,7 @@ err_destroy0:
 }
 
 int b43legacy_pio_tx(struct b43legacy_wldev *dev,
-                    struct sk_buff *skb,
-                    struct ieee80211_tx_control *ctl)
+                    struct sk_buff *skb)
 {
        struct b43legacy_pioqueue *queue = dev->pio.queue1;
        struct b43legacy_pio_txpacket *packet;
@@ -476,9 +475,6 @@ int b43legacy_pio_tx(struct b43legacy_wldev *dev,
                            list);
        packet->skb = skb;
 
-       memset(&packet->txstat, 0, sizeof(packet->txstat));
-       memcpy(&packet->txstat.control, ctl, sizeof(*ctl));
-
        list_move_tail(&packet->list, &queue->txqueue);
        queue->nr_txfree--;
        queue->nr_tx_packets++;
@@ -494,6 +490,7 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
 {
        struct b43legacy_pioqueue *queue;
        struct b43legacy_pio_txpacket *packet;
+       struct ieee80211_tx_info *info;
 
        queue = parse_cookie(dev, status->cookie, &packet);
        B43legacy_WARN_ON(!queue);
@@ -505,11 +502,13 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
        queue->tx_devq_used -= (packet->skb->len +
                                sizeof(struct b43legacy_txhdr_fw3));
 
+       info = IEEE80211_SKB_CB(packet->skb);
+       memset(&info->status, 0, sizeof(info->status));
+
        if (status->acked)
-               packet->txstat.flags |= IEEE80211_TX_STATUS_ACK;
-       packet->txstat.retry_count = status->frame_count - 1;
-       ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb,
-                                   &(packet->txstat));
+               info->flags |= IEEE80211_TX_STAT_ACK;
+       info->status.retry_count = status->frame_count - 1;
+       ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb);
        packet->skb = NULL;
 
        free_txpacket(packet, 1);
@@ -525,13 +524,11 @@ void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev,
 {
        struct b43legacy_pio *pio = &dev->pio;
        struct b43legacy_pioqueue *queue;
-       struct ieee80211_tx_queue_stats_data *data;
 
        queue = pio->queue1;
-       data = &(stats->data[0]);
-       data->len = B43legacy_PIO_MAXTXPACKETS - queue->nr_txfree;
-       data->limit = B43legacy_PIO_MAXTXPACKETS;
-       data->count = queue->nr_tx_packets;
+       stats[0].len = B43legacy_PIO_MAXTXPACKETS - queue->nr_txfree;
+       stats[0].limit = B43legacy_PIO_MAXTXPACKETS;
+       stats[0].count = queue->nr_tx_packets;
 }
 
 static void pio_rx_error(struct b43legacy_pioqueue *queue,
index 5bfed0c400307b777cb178926cc2e25cfef88139..464fec05a06d667ba9a3575abee51da12402e9b7 100644 (file)
@@ -41,7 +41,6 @@ struct b43legacy_xmitstatus;
 struct b43legacy_pio_txpacket {
        struct b43legacy_pioqueue *queue;
        struct sk_buff *skb;
-       struct ieee80211_tx_status txstat;
        struct list_head list;
 };
 
@@ -104,8 +103,7 @@ int b43legacy_pio_init(struct b43legacy_wldev *dev);
 void b43legacy_pio_free(struct b43legacy_wldev *dev);
 
 int b43legacy_pio_tx(struct b43legacy_wldev *dev,
-                  struct sk_buff *skb,
-                  struct ieee80211_tx_control *ctl);
+                  struct sk_buff *skb);
 void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
                                 const struct b43legacy_txstatus *status);
 void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev,
@@ -132,8 +130,7 @@ void b43legacy_pio_free(struct b43legacy_wldev *dev)
 }
 static inline
 int b43legacy_pio_tx(struct b43legacy_wldev *dev,
-                  struct sk_buff *skb,
-                  struct ieee80211_tx_control *ctl)
+                  struct sk_buff *skb)
 {
        return 0;
 }
index 955832e8654f18dd12e537a973a8345ee6bc1e1c..2df545cfad1435fbc966fbb47d3ab25c9f7e7c3a 100644 (file)
@@ -357,7 +357,7 @@ void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val)
        for (i = 0; i < 64; i++) {
                tmp = b43legacy_nrssi_hw_read(dev, i);
                tmp -= val;
-               tmp = limit_value(tmp, -32, 31);
+               tmp = clamp_val(tmp, -32, 31);
                b43legacy_nrssi_hw_write(dev, i, tmp);
        }
 }
@@ -375,7 +375,7 @@ void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev)
                tmp = (i - delta) * phy->nrssislope;
                tmp /= 0x10000;
                tmp += 0x3A;
-               tmp = limit_value(tmp, 0, 0x3F);
+               tmp = clamp_val(tmp, 0, 0x3F);
                phy->nrssi_lt[i] = tmp;
        }
 }
@@ -839,7 +839,7 @@ void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev)
                } else
                        threshold = phy->nrssi[1] - 5;
 
-               threshold = limit_value(threshold, 0, 0x3E);
+               threshold = clamp_val(threshold, 0, 0x3E);
                b43legacy_phy_read(dev, 0x0020); /* dummy read */
                b43legacy_phy_write(dev, 0x0020, (((u16)threshold) << 8)
                                    | 0x001C);
@@ -892,7 +892,7 @@ void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev)
                        else
                                a += 32;
                        a = a >> 6;
-                       a = limit_value(a, -31, 31);
+                       a = clamp_val(a, -31, 31);
 
                        b = b * (phy->nrssi[1] - phy->nrssi[0]);
                        b += (phy->nrssi[0] << 6);
@@ -901,7 +901,7 @@ void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev)
                        else
                                b += 32;
                        b = b >> 6;
-                       b = limit_value(b, -31, 31);
+                       b = clamp_val(b, -31, 31);
 
                        tmp_u16 = b43legacy_phy_read(dev, 0x048A) & 0xF000;
                        tmp_u16 |= ((u32)b & 0x0000003F);
@@ -1905,7 +1905,7 @@ void b43legacy_radio_set_txpower_a(struct b43legacy_wldev *dev, u16 txpower)
        u16 dac;
        u16 ilt;
 
-       txpower = limit_value(txpower, 0, 63);
+       txpower = clamp_val(txpower, 0, 63);
 
        pamp = b43legacy_get_txgain_freq_power_amp(txpower);
        pamp <<= 5;
index dcad2491a6066ca72d8b7e448494f41ea7936dc0..82dc04d59446979598a51f9d00a254ea5a3733f7 100644 (file)
@@ -188,11 +188,11 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
                               struct b43legacy_txhdr_fw3 *txhdr,
                               const unsigned char *fragment_data,
                               unsigned int fragment_len,
-                              const struct ieee80211_tx_control *txctl,
+                              const struct ieee80211_tx_info *info,
                               u16 cookie)
 {
        const struct ieee80211_hdr *wlhdr;
-       int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT));
+       int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT));
        u16 fctl;
        u8 rate;
        struct ieee80211_rate *rate_fb;
@@ -201,15 +201,18 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
        unsigned int plcp_fragment_len;
        u32 mac_ctl = 0;
        u16 phy_ctl = 0;
+       struct ieee80211_rate *tx_rate;
 
        wlhdr = (const struct ieee80211_hdr *)fragment_data;
        fctl = le16_to_cpu(wlhdr->frame_control);
 
        memset(txhdr, 0, sizeof(*txhdr));
 
-       rate = txctl->tx_rate->hw_value;
+       tx_rate = ieee80211_get_tx_rate(dev->wl->hw, info);
+
+       rate = tx_rate->hw_value;
        rate_ofdm = b43legacy_is_ofdm_rate(rate);
-       rate_fb = txctl->alt_retry_rate ? : txctl->tx_rate;
+       rate_fb = ieee80211_get_alt_retry_rate(dev->wl->hw, info) ? : tx_rate;
        rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb->hw_value);
 
        txhdr->mac_frame_ctl = wlhdr->frame_control;
@@ -225,14 +228,14 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
                txhdr->dur_fb = wlhdr->duration_id;
        } else {
                txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
-                                                        txctl->vif,
+                                                        info->control.vif,
                                                         fragment_len,
                                                         rate_fb);
        }
 
        plcp_fragment_len = fragment_len + FCS_LEN;
        if (use_encryption) {
-               u8 key_idx = (u16)(txctl->key_idx);
+               u8 key_idx = info->control.hw_key->hw_key_idx;
                struct b43legacy_key *key;
                int wlhdr_len;
                size_t iv_len;
@@ -242,7 +245,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
 
                if (key->enabled) {
                        /* Hardware appends ICV. */
-                       plcp_fragment_len += txctl->icv_len;
+                       plcp_fragment_len += info->control.icv_len;
 
                        key_idx = b43legacy_kidx_to_fw(dev, key_idx);
                        mac_ctl |= (key_idx << B43legacy_TX4_MAC_KEYIDX_SHIFT) &
@@ -251,7 +254,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
                                   B43legacy_TX4_MAC_KEYALG_SHIFT) &
                                   B43legacy_TX4_MAC_KEYALG;
                        wlhdr_len = ieee80211_get_hdrlen(fctl);
-                       iv_len = min((size_t)txctl->iv_len,
+                       iv_len = min((size_t)info->control.iv_len,
                                     ARRAY_SIZE(txhdr->iv));
                        memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len);
                } else {
@@ -275,7 +278,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
                phy_ctl |= B43legacy_TX4_PHY_OFDM;
        if (dev->short_preamble)
                phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL;
-       switch (txctl->antenna_sel_tx) {
+       switch (info->antenna_sel_tx) {
        case 0:
                phy_ctl |= B43legacy_TX4_PHY_ANTLAST;
                break;
@@ -290,21 +293,21 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
        }
 
        /* MAC control */
-       if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK))
+       if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
                mac_ctl |= B43legacy_TX4_MAC_ACK;
        if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
              ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
                mac_ctl |= B43legacy_TX4_MAC_HWSEQ;
-       if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)
+       if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
                mac_ctl |= B43legacy_TX4_MAC_STMSDU;
        if (rate_fb_ofdm)
                mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM;
-       if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT)
+       if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
                mac_ctl |= B43legacy_TX4_MAC_LONGFRAME;
 
        /* Generate the RTS or CTS-to-self frame */
-       if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
-           (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
+       if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
+           (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
                unsigned int len;
                struct ieee80211_hdr *hdr;
                int rts_rate;
@@ -312,26 +315,26 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
                int rts_rate_ofdm;
                int rts_rate_fb_ofdm;
 
-               rts_rate = txctl->rts_cts_rate->hw_value;
+               rts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info)->hw_value;
                rts_rate_ofdm = b43legacy_is_ofdm_rate(rts_rate);
                rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate);
                rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb);
                if (rts_rate_fb_ofdm)
                        mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM;
 
-               if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
+               if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
                        ieee80211_ctstoself_get(dev->wl->hw,
-                                               txctl->vif,
+                                               info->control.vif,
                                                fragment_data,
-                                               fragment_len, txctl,
+                                               fragment_len, info,
                                                (struct ieee80211_cts *)
                                                (txhdr->rts_frame));
                        mac_ctl |= B43legacy_TX4_MAC_SENDCTS;
                        len = sizeof(struct ieee80211_cts);
                } else {
                        ieee80211_rts_get(dev->wl->hw,
-                                         txctl->vif,
-                                         fragment_data, fragment_len, txctl,
+                                         info->control.vif,
+                                         fragment_data, fragment_len, info,
                                          (struct ieee80211_rts *)
                                          (txhdr->rts_frame));
                        mac_ctl |= B43legacy_TX4_MAC_SENDRTS;
@@ -362,12 +365,12 @@ int b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
                              u8 *txhdr,
                              const unsigned char *fragment_data,
                              unsigned int fragment_len,
-                             const struct ieee80211_tx_control *txctl,
+                             const struct ieee80211_tx_info *info,
                              u16 cookie)
 {
        return generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr,
                           fragment_data, fragment_len,
-                          txctl, cookie);
+                          info, cookie);
 }
 
 static s8 b43legacy_rssi_postprocess(struct b43legacy_wldev *dev,
@@ -532,12 +535,12 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
                }
        }
 
-       status.ssi = b43legacy_rssi_postprocess(dev, jssi,
+       status.signal = b43legacy_rssi_postprocess(dev, jssi,
                                      (phystat0 & B43legacy_RX_PHYST0_OFDM),
                                      (phystat0 & B43legacy_RX_PHYST0_GAINCTL),
                                      (phystat3 & B43legacy_RX_PHYST3_TRSTATE));
        status.noise = dev->stats.link_noise;
-       status.signal = (jssi * 100) / B43legacy_RX_MAX_SSI;
+       status.qual = (jssi * 100) / B43legacy_RX_MAX_SSI;
        /* change to support A PHY */
        if (phystat0 & B43legacy_RX_PHYST0_OFDM)
                status.rate_idx = b43legacy_plcp_get_bitrate_idx_ofdm(plcp, false);
index bab47928a0c9b776e5febd7b546e6da3d635827a..e56777e0feabf7f0e4552449e29daf91c8b11577 100644 (file)
@@ -80,7 +80,7 @@ int b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
                              u8 *txhdr,
                              const unsigned char *fragment_data,
                              unsigned int fragment_len,
-                             const struct ieee80211_tx_control *txctl,
+                             const struct ieee80211_tx_info *info,
                              u16 cookie);
 
 
index 62fb89d8231821637de3feb9f46862aa5b1da410..5f3e849043f7508140d77789ad0d4e72a129b38a 100644 (file)
@@ -14,6 +14,15 @@ config IWLWIFI_LEDS
        bool
        default n
 
+config IWLWIFI_RUN_TIME_CALIB
+       bool
+       depends on IWLCORE
+       default n
+       ---help---
+         This option will enable run time calibration for the iwlwifi driver.
+         These calibrations are Sensitivity and Chain Noise.
+
+
 config IWLWIFI_RFKILL
        boolean "IWLWIFI RF kill support"
        depends on IWLCORE
@@ -67,12 +76,14 @@ config IWL4965_SPECTRUM_MEASUREMENT
        ---help---
          This option will enable spectrum measurement for the iwl4965 driver.
 
-config IWL4965_SENSITIVITY
-       bool "Enable Sensitivity Calibration in iwl4965 driver"
+config IWL4965_RUN_TIME_CALIB
+       bool "Enable run time Calibration for 4965 NIC"
+       select IWLWIFI_RUN_TIME_CALIB
        depends on IWL4965
+       default y
        ---help---
-         This option will enable sensitivity calibration for the iwl4965
-         driver.
+         This option will enable run time calibration for the iwl4965 driver.
+         These calibrations are Sensitivity and Chain Noise. If unsure, say yes
 
 config IWLWIFI_DEBUG
        bool "Enable full debugging output in iwl4965 driver"
@@ -85,13 +96,13 @@ config IWLWIFI_DEBUG
          control which debug output is sent to the kernel log by setting the
          value in
 
-                 /sys/bus/pci/drivers/${DRIVER}/debug_level
+               /sys/class/net/wlan0/device/debug_level
 
          This entry will only exist if this option is enabled.
 
          To set a value, simply echo an 8-byte hex value to the same file:
 
-                 % echo 0x43fff > /sys/bus/pci/drivers/${DRIVER}/debug_level
+                 % echo 0x43fff > /sys/class/net/wlan0/device/debug_level
 
          You can find the list of debug mask values in:
                  drivers/net/wireless/iwlwifi/iwl-4965-debug.h
@@ -100,6 +111,23 @@ config IWLWIFI_DEBUG
          as the debug information can assist others in helping you resolve
          any problems you may encounter.
 
+config IWL5000
+       bool "Intel Wireless WiFi 5000AGN"
+       depends on IWL4965
+       ---help---
+         This option enables support for Intel Wireless WiFi Link 5000AGN Family
+         Dependency on 4965 is temporary
+
+config IWL5000_RUN_TIME_CALIB
+       bool "Enable run time Calibration for 5000 NIC"
+       select IWLWIFI_RUN_TIME_CALIB
+       depends on IWL5000
+       default y
+       ---help---
+         This option will enable run time calibration for the iwl5000 driver.
+         These calibrations are Sensitivity and Chain Noise. If unsure, say yes
+
+
 config IWLWIFI_DEBUGFS
         bool "Iwlwifi debugfs support"
         depends on IWLCORE && IWLWIFI_DEBUG && MAC80211_DEBUGFS
index ec6187b75c3bd62f2bf216c7ceadcb5428debb7f..5c73eede719307c549100fd4597283ad7658ce31 100644 (file)
@@ -1,13 +1,20 @@
 obj-$(CONFIG_IWLCORE)  += iwlcore.o
-iwlcore-objs           := iwl-core.o iwl-eeprom.o iwl-hcmd.o
+iwlcore-objs           := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o
+iwlcore-objs           += iwl-rx.o iwl-tx.o iwl-sta.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_RUN_TIME_CALIB) += iwl-calib.o
 
 obj-$(CONFIG_IWL3945)  += iwl3945.o
 iwl3945-objs           := iwl3945-base.o iwl-3945.o iwl-3945-rs.o
 iwl3945-$(CONFIG_IWL3945_LEDS) += iwl-3945-led.o
 
 obj-$(CONFIG_IWL4965)  += iwl4965.o
-iwl4965-objs           := iwl4965-base.o iwl-4965.o iwl-4965-rs.o iwl-sta.o
+iwl4965-objs           := iwl4965-base.o iwl-4965.o iwl-4965-rs.o
+
+ifeq ($(CONFIG_IWL5000),y)
+       iwl4965-objs += iwl-5000.o
+endif
+
 
index ad612a8719f447afb6f8b109e089e7d0da1fe17d..644bd9e0805217f2b399260a073487537f3de918 100644 (file)
@@ -126,7 +126,7 @@ enum {
        EEPROM_CHANNEL_ACTIVE = (1 << 3),       /* active scanning allowed */
        EEPROM_CHANNEL_RADAR = (1 << 4),        /* radar detection required */
        EEPROM_CHANNEL_WIDE = (1 << 5),         /* 20 MHz channel okay */
-       EEPROM_CHANNEL_NARROW = (1 << 6),       /* 10 MHz channel (not used) */
+       /* Bit 6 Reserved (was Narrow Channel) */
        EEPROM_CHANNEL_DFS = (1 << 7),  /* dynamic freq selection candidate */
 };
 
@@ -289,17 +289,6 @@ struct iwl3945_eeprom {
 #define PCI_REG_WUM8       0x0E8
 #define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT         (0x80000000)
 
-/* SCD (3945 Tx Frame Scheduler) */
-#define SCD_BASE                        (CSR_BASE + 0x2E00)
-
-#define SCD_MODE_REG                    (SCD_BASE + 0x000)
-#define SCD_ARASTAT_REG                 (SCD_BASE + 0x004)
-#define SCD_TXFACT_REG                  (SCD_BASE + 0x010)
-#define SCD_TXF4MF_REG                  (SCD_BASE + 0x014)
-#define SCD_TXF5MF_REG                  (SCD_BASE + 0x020)
-#define SCD_SBYP_MODE_1_REG             (SCD_BASE + 0x02C)
-#define SCD_SBYP_MODE_2_REG             (SCD_BASE + 0x030)
-
 /*=== FH (data Flow Handler) ===*/
 #define FH_BASE     (0x800)
 
index 85c22641542d6a8ed93226e2a3ee9b6c3f4e4b2c..10c64bdb314c8f0780991e0d53b3a0c58dfb4770 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/skbuff.h>
 #include <linux/wireless.h>
 #include <net/mac80211.h>
-#include <net/ieee80211.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -446,8 +445,7 @@ static int rs_adjust_next_rate(struct iwl3945_priv *priv, int rate)
  */
 static void rs_tx_status(void *priv_rate,
                         struct net_device *dev,
-                        struct sk_buff *skb,
-                        struct ieee80211_tx_status *tx_resp)
+                        struct sk_buff *skb)
 {
        u8 retries, current_count;
        int scale_rate_index, first_index, last_index;
@@ -458,14 +456,15 @@ static void rs_tx_status(void *priv_rate,
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct iwl3945_rs_sta *rs_sta;
        struct ieee80211_supported_band *sband;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
        IWL_DEBUG_RATE("enter\n");
 
        sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
 
-       retries = tx_resp->retry_count;
-       first_index = tx_resp->control.tx_rate->hw_value;
+       retries = info->status.retry_count;
+       first_index = sband->bitrates[info->tx_rate_idx].hw_value;
        if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) {
                IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index);
                return;
@@ -526,11 +525,11 @@ static void rs_tx_status(void *priv_rate,
        /* Update the last index window with success/failure based on ACK */
        IWL_DEBUG_RATE("Update rate %d with %s.\n",
                       last_index,
-                      (tx_resp->flags & IEEE80211_TX_STATUS_ACK) ?
+                      (info->flags & IEEE80211_TX_STAT_ACK) ?
                       "success" : "failure");
        iwl3945_collect_tx_data(rs_sta,
                            &rs_sta->win[last_index],
-                           tx_resp->flags & IEEE80211_TX_STATUS_ACK, 1);
+                           info->flags & IEEE80211_TX_STAT_ACK, 1);
 
        /* We updated the rate scale window -- if its been more than
         * flush_time since the last run, schedule the flush
@@ -670,7 +669,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
            is_multicast_ether_addr(hdr->addr1) ||
            !sta || !sta->rate_ctrl_priv) {
                IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
-               sel->rate = rate_lowest(local, sband, sta);
+               sel->rate_idx = rate_lowest_index(local, sband, sta);
                rcu_read_unlock();
                return;
        }
@@ -814,7 +813,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
 
        IWL_DEBUG_RATE("leave: %d\n", index);
 
-       sel->rate = &sband->bitrates[sta->txrate_idx];
+       sel->rate_idx = sta->txrate_idx;
 }
 
 static struct rate_control_ops rs_ops = {
index 62a3d8f8563ed07cbd7d6a743831dfdc66bf78cb..0ba6889dfd4169753d9e76508f42773c37bc1593 100644 (file)
@@ -283,8 +283,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl3945_priv *priv,
                q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
 
                tx_info = &txq->txb[txq->q.read_ptr];
-               ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0],
-                                           &tx_info->status);
+               ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]);
                tx_info->skb[0] = NULL;
                iwl3945_hw_txq_free_tfd(priv, txq);
        }
@@ -306,7 +305,7 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv,
        int txq_id = SEQ_TO_QUEUE(sequence);
        int index = SEQ_TO_INDEX(sequence);
        struct iwl3945_tx_queue *txq = &priv->txq[txq_id];
-       struct ieee80211_tx_status *tx_status;
+       struct ieee80211_tx_info *info;
        struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
        u32  status = le32_to_cpu(tx_resp->status);
        int rate_idx;
@@ -319,19 +318,22 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv,
                return;
        }
 
-       tx_status = &(txq->txb[txq->q.read_ptr].status);
+       info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
+       memset(&info->status, 0, sizeof(info->status));
 
-       tx_status->retry_count = tx_resp->failure_frame;
+       info->status.retry_count = tx_resp->failure_frame;
        /* tx_status->rts_retry_count = tx_resp->failure_rts; */
-       tx_status->flags = ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ?
-                               IEEE80211_TX_STATUS_ACK : 0;
+       info->flags |= ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ?
+                               IEEE80211_TX_STAT_ACK : 0;
 
        IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n",
                        txq_id, iwl3945_get_tx_fail_reason(status), status,
                        tx_resp->rate, tx_resp->failure_frame);
 
        rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate);
-       tx_status->control.tx_rate = &priv->ieee_rates[rate_idx];
+       if (info->band == IEEE80211_BAND_5GHZ)
+               rate_idx -= IWL_FIRST_OFDM_RATE;
+       info->tx_rate_idx = rate_idx;
        IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
        iwl3945_tx_queue_reclaim(priv, txq_id, index);
 
@@ -520,7 +522,7 @@ static void iwl3945_add_radiotap(struct iwl3945_priv *priv,
 {
        /* First cache any information we need before we overwrite
         * the information provided in the skb from the hardware */
-       s8 signal = stats->ssi;
+       s8 signal = stats->signal;
        s8 noise = 0;
        int rate = stats->rate_idx;
        u64 tsf = stats->mactime;
@@ -693,7 +695,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
        }
 
        /* Convert 3945's rssi indicator to dBm */
-       rx_status.ssi = rx_stats->rssi - IWL_RSSI_OFFSET;
+       rx_status.signal = rx_stats->rssi - IWL_RSSI_OFFSET;
 
        /* Set default noise value to -127 */
        if (priv->last_rx_noise == 0)
@@ -712,21 +714,21 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
         * Calculate rx_status.signal (quality indicator in %) based on SNR. */
        if (rx_stats_noise_diff) {
                snr = rx_stats_sig_avg / rx_stats_noise_diff;
-               rx_status.noise = rx_status.ssi -
+               rx_status.noise = rx_status.signal -
                                        iwl3945_calc_db_from_ratio(snr);
-               rx_status.signal = iwl3945_calc_sig_qual(rx_status.ssi,
+               rx_status.qual = iwl3945_calc_sig_qual(rx_status.signal,
                                                         rx_status.noise);
 
        /* If noise info not available, calculate signal quality indicator (%)
         *   using just the dBm signal level. */
        } else {
                rx_status.noise = priv->last_rx_noise;
-               rx_status.signal = iwl3945_calc_sig_qual(rx_status.ssi, 0);
+               rx_status.qual = iwl3945_calc_sig_qual(rx_status.signal, 0);
        }
 
 
        IWL_DEBUG_STATS("Rssi %d noise %d qual %d sig_avg %d noise_diff %d\n",
-                       rx_status.ssi, rx_status.noise, rx_status.signal,
+                       rx_status.signal, rx_status.noise, rx_status.qual,
                        rx_stats_sig_avg, rx_stats_noise_diff);
 
        header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
@@ -736,8 +738,8 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
        IWL_DEBUG_STATS_LIMIT("[%c] %d RSSI:%d Signal:%u, Noise:%u, Rate:%u\n",
                              network_packet ? '*' : ' ',
                              le16_to_cpu(rx_hdr->channel),
-                             rx_status.ssi, rx_status.ssi,
-                             rx_status.ssi, rx_status.rate_idx);
+                             rx_status.signal, rx_status.signal,
+                             rx_status.noise, rx_status.rate_idx);
 
 #ifdef CONFIG_IWL3945_DEBUG
        if (iwl3945_debug_level & (IWL_DL_RX))
@@ -748,7 +750,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
        if (network_packet) {
                priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp);
                priv->last_tsf = le64_to_cpu(rx_end->timestamp);
-               priv->last_rx_rssi = rx_status.ssi;
+               priv->last_rx_rssi = rx_status.signal;
                priv->last_rx_noise = rx_status.noise;
        }
 
@@ -958,11 +960,12 @@ u8 iwl3945_hw_find_station(struct iwl3945_priv *priv, const u8 *addr)
 */
 void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv,
                              struct iwl3945_cmd *cmd,
-                             struct ieee80211_tx_control *ctrl,
+                             struct ieee80211_tx_info *info,
                              struct ieee80211_hdr *hdr, int sta_id, int tx_id)
 {
        unsigned long flags;
-       u16 rate_index = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1);
+       u16 hw_value = ieee80211_get_tx_rate(priv->hw, info)->hw_value;
+       u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT - 1);
        u16 rate_mask;
        int rate;
        u8 rts_retry_limit;
@@ -974,7 +977,7 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv,
        tx_flags = cmd->cmd.tx.tx_flags;
 
        /* We need to figure out how to get the sta->supp_rates while
-        * in this running context; perhaps encoding into ctrl->tx_rate? */
+        * in this running context */
        rate_mask = IWL_RATES_MASK;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
@@ -1229,7 +1232,7 @@ int iwl3945_hw_nic_init(struct iwl3945_priv *priv)
        iwl3945_power_init_handle(priv);
 
        spin_lock_irqsave(&priv->lock, flags);
-       iwl3945_set_bit(priv, CSR_ANA_PLL_CFG, (1 << 24));
+       iwl3945_set_bit(priv, CSR_ANA_PLL_CFG, CSR39_ANA_PLL_CFG_VAL);
        iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS,
                    CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
 
index c7695a215a394a958074b45caaf4e6f4fb4b6d7b..a9b3edad38682bdd8239148e63f2f48b3b2e59a9 100644 (file)
@@ -124,7 +124,6 @@ int iwl3945_x2_queue_used(const struct iwl3945_queue *q, int i);
 
 /* One for each TFD */
 struct iwl3945_tx_info {
-       struct ieee80211_tx_status status;
        struct sk_buff *skb[MAX_NUM_OF_TBS];
 };
 
@@ -645,7 +644,7 @@ extern unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv,
 extern int iwl3945_hw_get_rx_read(struct iwl3945_priv *priv);
 extern void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv,
                                     struct iwl3945_cmd *cmd,
-                                    struct ieee80211_tx_control *ctrl,
+                                    struct ieee80211_tx_info *info,
                                     struct ieee80211_hdr *hdr,
                                     int sta_id, int tx_id);
 extern int iwl3945_hw_reg_send_txpower(struct iwl3945_priv *priv);
@@ -836,8 +835,6 @@ struct iwl3945_priv {
 
        u8 mac80211_registered;
 
-       u32 notif_missed_beacons;
-
        /* Rx'd packet timing information */
        u32 last_beacon_time;
        u64 last_tsf;
@@ -886,6 +883,7 @@ struct iwl3945_priv {
        struct work_struct report_work;
        struct work_struct request_scan;
        struct work_struct beacon_update;
+       struct work_struct set_monitor;
 
        struct tasklet_struct irq_tasklet;
 
@@ -924,11 +922,6 @@ static inline int is_channel_valid(const struct iwl3945_channel_info *ch_info)
        return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0;
 }
 
-static inline int is_channel_narrow(const struct iwl3945_channel_info *ch_info)
-{
-       return (ch_info->flags & EEPROM_CHANNEL_NARROW) ? 1 : 0;
-}
-
 static inline int is_channel_radar(const struct iwl3945_channel_info *ch_info)
 {
        return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0;
index 1a66b508a8eaf7efdec1e2c971205437422d64dd..fc118335b60f48579624aa668a1dafd1dad385af 100644 (file)
  *****************************************************************************/
 /*
  * Please use this file (iwl-4965-hw.h) only for hardware-related definitions.
- * Use iwl-4965-commands.h for uCode API definitions.
- * Use iwl-4965.h for driver implementation definitions.
+ * Use iwl-commands.h for uCode API definitions.
+ * Use iwl-dev.h for driver implementation definitions.
  */
 
 #ifndef __iwl_4965_hw_h__
 #define __iwl_4965_hw_h__
 
+#include "iwl-fh.h"
+
+/* EERPROM */
+#define IWL4965_EEPROM_IMG_SIZE                        1024
+
 /*
  * uCode queue management definitions ...
  * Queue #4 is the command queue for 3945 and 4965; map it to Tx FIFO chnl 4.
 #define IWL_RSSI_OFFSET        44
 
 
-#include "iwl-4965-commands.h"
+#include "iwl-commands.h"
 
-#define PCI_LINK_CTRL      0x0F0
+/* PCI registers */
+#define PCI_LINK_CTRL      0x0F0       /* 1 byte */
 #define PCI_POWER_SOURCE   0x0C8
 #define PCI_REG_WUM8       0x0E8
+
+/* PCI register values */
+#define PCI_LINK_VAL_L0S_EN    0x01
+#define PCI_LINK_VAL_L1_EN     0x02
 #define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT         (0x80000000)
 
 #define TFD_QUEUE_SIZE_MAX      (256)
 #define RTC_DATA_LOWER_BOUND                   (0x800000)
 #define IWL49_RTC_DATA_UPPER_BOUND             (0x80A000)
 
-#define IWL49_RTC_INST_SIZE    \
-                       (IWL49_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND)
-#define IWL49_RTC_DATA_SIZE    \
-                       (IWL49_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND)
+#define IWL49_RTC_INST_SIZE  (IWL49_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND)
+#define IWL49_RTC_DATA_SIZE  (IWL49_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND)
 
 #define IWL_MAX_INST_SIZE IWL49_RTC_INST_SIZE
 #define IWL_MAX_DATA_SIZE IWL49_RTC_DATA_SIZE
@@ -785,579 +793,13 @@ enum {
 
 /********************* END TXPOWER *****************************************/
 
-/****************************/
-/* Flow Handler Definitions */
-/****************************/
-
-/**
- * This I/O area is directly read/writable by driver (e.g. Linux uses writel())
- * Addresses are offsets from device's PCI hardware base address.
- */
-#define FH_MEM_LOWER_BOUND                   (0x1000)
-#define FH_MEM_UPPER_BOUND                   (0x1EF0)
-
-/**
- * Keep-Warm (KW) buffer base address.
- *
- * Driver must allocate a 4KByte buffer that is used by 4965 for keeping the
- * host DRAM powered on (via dummy accesses to DRAM) to maintain low-latency
- * DRAM access when 4965 is Txing or Rxing.  The dummy accesses prevent host
- * from going into a power-savings mode that would cause higher DRAM latency,
- * and possible data over/under-runs, before all Tx/Rx is complete.
- *
- * Driver loads IWL_FH_KW_MEM_ADDR_REG with the physical address (bits 35:4)
- * of the buffer, which must be 4K aligned.  Once this is set up, the 4965
- * automatically invokes keep-warm accesses when normal accesses might not
- * be sufficient to maintain fast DRAM response.
- *
- * Bit fields:
- *  31-0:  Keep-warm buffer physical base address [35:4], must be 4K aligned
- */
-#define IWL_FH_KW_MEM_ADDR_REG              (FH_MEM_LOWER_BOUND + 0x97C)
-
-
-/**
- * TFD Circular Buffers Base (CBBC) addresses
- *
- * 4965 has 16 base pointer registers, one for each of 16 host-DRAM-resident
- * circular buffers (CBs/queues) containing Transmit Frame Descriptors (TFDs)
- * (see struct iwl_tfd_frame).  These 16 pointer registers are offset by 0x04
- * bytes from one another.  Each TFD circular buffer in DRAM must be 256-byte
- * aligned (address bits 0-7 must be 0).
- *
- * Bit fields in each pointer register:
- *  27-0: TFD CB physical base address [35:8], must be 256-byte aligned
- */
-#define FH_MEM_CBBC_LOWER_BOUND              (FH_MEM_LOWER_BOUND + 0x9D0)
-#define FH_MEM_CBBC_UPPER_BOUND              (FH_MEM_LOWER_BOUND + 0xA10)
-
-/* Find TFD CB base pointer for given queue (range 0-15). */
-#define FH_MEM_CBBC_QUEUE(x)  (FH_MEM_CBBC_LOWER_BOUND + (x) * 0x4)
-
-
-/**
- * Rx SRAM Control and Status Registers (RSCSR)
- *
- * These registers provide handshake between driver and 4965 for the Rx queue
- * (this queue handles *all* command responses, notifications, Rx data, etc.
- * sent from 4965 uCode to host driver).  Unlike Tx, there is only one Rx
- * queue, and only one Rx DMA/FIFO channel.  Also unlike Tx, which can
- * concatenate up to 20 DRAM buffers to form a Tx frame, each Receive Buffer
- * Descriptor (RBD) points to only one Rx Buffer (RB); there is a 1:1
- * mapping between RBDs and RBs.
- *
- * Driver must allocate host DRAM memory for the following, and set the
- * physical address of each into 4965 registers:
- *
- * 1)  Receive Buffer Descriptor (RBD) circular buffer (CB), typically with 256
- *     entries (although any power of 2, up to 4096, is selectable by driver).
- *     Each entry (1 dword) points to a receive buffer (RB) of consistent size
- *     (typically 4K, although 8K or 16K are also selectable by driver).
- *     Driver sets up RB size and number of RBDs in the CB via Rx config
- *     register FH_MEM_RCSR_CHNL0_CONFIG_REG.
- *
- *     Bit fields within one RBD:
- *     27-0:  Receive Buffer physical address bits [35:8], 256-byte aligned
- *
- *     Driver sets physical address [35:8] of base of RBD circular buffer
- *     into FH_RSCSR_CHNL0_RBDCB_BASE_REG [27:0].
- *
- * 2)  Rx status buffer, 8 bytes, in which 4965 indicates which Rx Buffers
- *     (RBs) have been filled, via a "write pointer", actually the index of
- *     the RB's corresponding RBD within the circular buffer.  Driver sets
- *     physical address [35:4] into FH_RSCSR_CHNL0_STTS_WPTR_REG [31:0].
- *
- *     Bit fields in lower dword of Rx status buffer (upper dword not used
- *     by driver; see struct iwl4965_shared, val0):
- *     31-12:  Not used by driver
- *     11- 0:  Index of last filled Rx buffer descriptor
- *             (4965 writes, driver reads this value)
- *
- * As the driver prepares Receive Buffers (RBs) for 4965 to fill, driver must
- * enter pointers to these RBs into contiguous RBD circular buffer entries,
- * and update the 4965's "write" index register, FH_RSCSR_CHNL0_RBDCB_WPTR_REG.
- *
- * This "write" index corresponds to the *next* RBD that the driver will make
- * available, i.e. one RBD past the tail of the ready-to-fill RBDs within
- * the circular buffer.  This value should initially be 0 (before preparing any
- * RBs), should be 8 after preparing the first 8 RBs (for example), and must
- * wrap back to 0 at the end of the circular buffer (but don't wrap before
- * "read" index has advanced past 1!  See below).
- * NOTE:  4965 EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8.
- *
- * As the 4965 fills RBs (referenced from contiguous RBDs within the circular
- * buffer), it updates the Rx status buffer in host DRAM, 2) described above,
- * to tell the driver the index of the latest filled RBD.  The driver must
- * read this "read" index from DRAM after receiving an Rx interrupt from 4965.
- *
- * The driver must also internally keep track of a third index, which is the
- * next RBD to process.  When receiving an Rx interrupt, driver should process
- * all filled but unprocessed RBs up to, but not including, the RB
- * corresponding to the "read" index.  For example, if "read" index becomes "1",
- * driver may process the RB pointed to by RBD 0.  Depending on volume of
- * traffic, there may be many RBs to process.
- *
- * If read index == write index, 4965 thinks there is no room to put new data.
- * Due to this, the maximum number of filled RBs is 255, instead of 256.  To
- * be safe, make sure that there is a gap of at least 2 RBDs between "write"
- * and "read" indexes; that is, make sure that there are no more than 254
- * buffers waiting to be filled.
- */
-#define FH_MEM_RSCSR_LOWER_BOUND       (FH_MEM_LOWER_BOUND + 0xBC0)
-#define FH_MEM_RSCSR_UPPER_BOUND       (FH_MEM_LOWER_BOUND + 0xC00)
-#define FH_MEM_RSCSR_CHNL0             (FH_MEM_RSCSR_LOWER_BOUND)
-
-/**
- * Physical base address of 8-byte Rx Status buffer.
- * Bit fields:
- *  31-0: Rx status buffer physical base address [35:4], must 16-byte aligned.
- */
-#define FH_RSCSR_CHNL0_STTS_WPTR_REG           (FH_MEM_RSCSR_CHNL0)
-
-/**
- * Physical base address of Rx Buffer Descriptor Circular Buffer.
- * Bit fields:
- *  27-0:  RBD CD physical base address [35:8], must be 256-byte aligned.
- */
-#define FH_RSCSR_CHNL0_RBDCB_BASE_REG          (FH_MEM_RSCSR_CHNL0 + 0x004)
-
-/**
- * Rx write pointer (index, really!).
- * Bit fields:
- *  11-0:  Index of driver's most recent prepared-to-be-filled RBD, + 1.
- *         NOTE:  For 256-entry circular buffer, use only bits [7:0].
- */
-#define FH_RSCSR_CHNL0_RBDCB_WPTR_REG          (FH_MEM_RSCSR_CHNL0 + 0x008)
-#define FH_RSCSR_CHNL0_WPTR        (FH_RSCSR_CHNL0_RBDCB_WPTR_REG)
-
-
-/**
- * Rx Config/Status Registers (RCSR)
- * Rx Config Reg for channel 0 (only channel used)
- *
- * Driver must initialize FH_MEM_RCSR_CHNL0_CONFIG_REG as follows for
- * normal operation (see bit fields).
- *
- * Clearing FH_MEM_RCSR_CHNL0_CONFIG_REG to 0 turns off Rx DMA.
- * Driver should poll FH_MEM_RSSR_RX_STATUS_REG        for
- * FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (bit 24) before continuing.
- *
- * Bit fields:
- * 31-30: Rx DMA channel enable: '00' off/pause, '01' pause at end of frame,
- *        '10' operate normally
- * 29-24: reserved
- * 23-20: # RBDs in circular buffer = 2^value; use "8" for 256 RBDs (normal),
- *        min "5" for 32 RBDs, max "12" for 4096 RBDs.
- * 19-18: reserved
- * 17-16: size of each receive buffer; '00' 4K (normal), '01' 8K,
- *        '10' 12K, '11' 16K.
- * 15-14: reserved
- * 13-12: IRQ destination; '00' none, '01' host driver (normal operation)
- * 11- 4: timeout for closing Rx buffer and interrupting host (units 32 usec)
- *        typical value 0x10 (about 1/2 msec)
- *  3- 0: reserved
- */
-#define FH_MEM_RCSR_LOWER_BOUND      (FH_MEM_LOWER_BOUND + 0xC00)
-#define FH_MEM_RCSR_UPPER_BOUND      (FH_MEM_LOWER_BOUND + 0xCC0)
-#define FH_MEM_RCSR_CHNL0            (FH_MEM_RCSR_LOWER_BOUND)
-
-#define FH_MEM_RCSR_CHNL0_CONFIG_REG   (FH_MEM_RCSR_CHNL0)
-
-#define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MASK   (0x00000FF0) /* bit 4-11 */
-#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MASK     (0x00001000) /* bit 12 */
-#define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MASK (0x00008000) /* bit 15 */
-#define FH_RCSR_CHNL0_RX_CONFIG_RB_SIZE_MASK     (0x00030000) /* bits 16-17 */
-#define FH_RCSR_CHNL0_RX_CONFIG_RBDBC_SIZE_MASK   (0x00F00000) /* bits 20-23 */
-#define FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MASK  (0xC0000000) /* bits 30-31 */
-
-#define FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT  (20)
-#define FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_BITSHIFT        (4)
-#define RX_RB_TIMEOUT  (0x10)
-
-#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL         (0x00000000)
-#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_EOF_VAL     (0x40000000)
-#define FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL        (0x80000000)
-
-#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K    (0x00000000)
-#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K    (0x00010000)
-#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_12K   (0x00020000)
-#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_16K   (0x00030000)
-
-#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL       (0x00000000)
-#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL     (0x00001000)
-
-
-/**
- * Rx Shared Status Registers (RSSR)
- *
- * After stopping Rx DMA channel (writing 0 to FH_MEM_RCSR_CHNL0_CONFIG_REG),
- * driver must poll FH_MEM_RSSR_RX_STATUS_REG until Rx channel is idle.
- *
- * Bit fields:
- *  24:  1 = Channel 0 is idle
- *
- * FH_MEM_RSSR_SHARED_CTRL_REG and FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV contain
- * default values that should not be altered by the driver.
- */
-#define FH_MEM_RSSR_LOWER_BOUND                        (FH_MEM_LOWER_BOUND + 0xC40)
-#define FH_MEM_RSSR_UPPER_BOUND                (FH_MEM_LOWER_BOUND + 0xD00)
-
-#define FH_MEM_RSSR_SHARED_CTRL_REG            (FH_MEM_RSSR_LOWER_BOUND)
-#define FH_MEM_RSSR_RX_STATUS_REG      (FH_MEM_RSSR_LOWER_BOUND + 0x004)
-#define FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV  (FH_MEM_RSSR_LOWER_BOUND + 0x008)
-
-#define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE      (0x01000000)
-
-
-/**
- * Transmit DMA Channel Control/Status Registers (TCSR)
- *
- * 4965 has one configuration register for each of 8 Tx DMA/FIFO channels
- * supported in hardware (don't confuse these with the 16 Tx queues in DRAM,
- * which feed the DMA/FIFO channels); config regs are separated by 0x20 bytes.
- *
- * To use a Tx DMA channel, driver must initialize its
- * IWL_FH_TCSR_CHNL_TX_CONFIG_REG(chnl) with:
- *
- * IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
- * IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL
- *
- * All other bits should be 0.
- *
- * Bit fields:
- * 31-30: Tx DMA channel enable: '00' off/pause, '01' pause at end of frame,
- *        '10' operate normally
- * 29- 4: Reserved, set to "0"
- *     3: Enable internal DMA requests (1, normal operation), disable (0)
- *  2- 0: Reserved, set to "0"
- */
-#define IWL_FH_TCSR_LOWER_BOUND  (FH_MEM_LOWER_BOUND + 0xD00)
-#define IWL_FH_TCSR_UPPER_BOUND  (FH_MEM_LOWER_BOUND + 0xE60)
-
-/* Find Control/Status reg for given Tx DMA/FIFO channel */
-#define IWL_FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \
-       (IWL_FH_TCSR_LOWER_BOUND + 0x20 * _chnl)
-
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL    (0x00000000)
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL     (0x00000008)
-
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE            (0x00000000)
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF        (0x40000000)
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE           (0x80000000)
-
-/**
- * Tx Shared Status Registers (TSSR)
- *
- * After stopping Tx DMA channel (writing 0 to
- * IWL_FH_TCSR_CHNL_TX_CONFIG_REG(chnl)), driver must poll
- * IWL_FH_TSSR_TX_STATUS_REG until selected Tx channel is idle
- * (channel's buffers empty | no pending requests).
- *
- * Bit fields:
- * 31-24:  1 = Channel buffers empty (channel 7:0)
- * 23-16:  1 = No pending requests (channel 7:0)
- */
-#define IWL_FH_TSSR_LOWER_BOUND                (FH_MEM_LOWER_BOUND + 0xEA0)
-#define IWL_FH_TSSR_UPPER_BOUND                (FH_MEM_LOWER_BOUND + 0xEC0)
-
-#define IWL_FH_TSSR_TX_STATUS_REG      (IWL_FH_TSSR_LOWER_BOUND + 0x010)
-
-#define IWL_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl)        \
-       ((1 << (_chnl)) << 24)
-#define IWL_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl) \
-       ((1 << (_chnl)) << 16)
-
-#define IWL_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) \
-       (IWL_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \
-       IWL_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl))
-
-
-/********************* START TX SCHEDULER *************************************/
-
-/**
- * 4965 Tx Scheduler
- *
- * The Tx Scheduler selects the next frame to be transmitted, chosing TFDs
- * (Transmit Frame Descriptors) from up to 16 circular Tx queues resident in
- * host DRAM.  It steers each frame's Tx command (which contains the frame
- * data) into one of up to 7 prioritized Tx DMA FIFO channels within the
- * device.  A queue maps to only one (selectable by driver) Tx DMA channel,
- * but one DMA channel may take input from several queues.
- *
- * Tx DMA channels have dedicated purposes.  For 4965, they are used as follows:
- *
- * 0 -- EDCA BK (background) frames, lowest priority
- * 1 -- EDCA BE (best effort) frames, normal priority
- * 2 -- EDCA VI (video) frames, higher priority
- * 3 -- EDCA VO (voice) and management frames, highest priority
- * 4 -- Commands (e.g. RXON, etc.)
- * 5 -- HCCA short frames
- * 6 -- HCCA long frames
- * 7 -- not used by driver (device-internal only)
- *
- * Driver should normally map queues 0-6 to Tx DMA/FIFO channels 0-6.
- * In addition, driver can map queues 7-15 to Tx DMA/FIFO channels 0-3 to
- * support 11n aggregation via EDCA DMA channels.
- *
- * The driver sets up each queue to work in one of two modes:
- *
- * 1)  Scheduler-Ack, in which the scheduler automatically supports a
- *     block-ack (BA) window of up to 64 TFDs.  In this mode, each queue
- *     contains TFDs for a unique combination of Recipient Address (RA)
- *     and Traffic Identifier (TID), that is, traffic of a given
- *     Quality-Of-Service (QOS) priority, destined for a single station.
- *
- *     In scheduler-ack mode, the scheduler keeps track of the Tx status of
- *     each frame within the BA window, including whether it's been transmitted,
- *     and whether it's been acknowledged by the receiving station.  The device
- *     automatically processes block-acks received from the receiving STA,
- *     and reschedules un-acked frames to be retransmitted (successful
- *     Tx completion may end up being out-of-order).
- *
- *     The driver must maintain the queue's Byte Count table in host DRAM
- *     (struct iwl4965_sched_queue_byte_cnt_tbl) for this mode.
- *     This mode does not support fragmentation.
- *
- * 2)  FIFO (a.k.a. non-Scheduler-ACK), in which each TFD is processed in order.
- *     The device may automatically retry Tx, but will retry only one frame
- *     at a time, until receiving ACK from receiving station, or reaching
- *     retry limit and giving up.
- *
- *     The command queue (#4) must use this mode!
- *     This mode does not require use of the Byte Count table in host DRAM.
- *
- * Driver controls scheduler operation via 3 means:
- * 1)  Scheduler registers
- * 2)  Shared scheduler data base in internal 4956 SRAM
- * 3)  Shared data in host DRAM
- *
- * Initialization:
- *
- * When loading, driver should allocate memory for:
- * 1)  16 TFD circular buffers, each with space for (typically) 256 TFDs.
- * 2)  16 Byte Count circular buffers in 16 KBytes contiguous memory
- *     (1024 bytes for each queue).
- *
- * After receiving "Alive" response from uCode, driver must initialize
- * the scheduler (especially for queue #4, the command queue, otherwise
- * the driver can't issue commands!):
- */
-
-/**
- * Max Tx window size is the max number of contiguous TFDs that the scheduler
- * can keep track of at one time when creating block-ack chains of frames.
- * Note that "64" matches the number of ack bits in a block-ack packet.
- * Driver should use SCD_WIN_SIZE and SCD_FRAME_LIMIT values to initialize
- * SCD_CONTEXT_QUEUE_OFFSET(x) values.
- */
-#define SCD_WIN_SIZE                           64
-#define SCD_FRAME_LIMIT                                64
-
-/* SCD registers are internal, must be accessed via HBUS_TARG_PRPH regs */
-#define SCD_START_OFFSET               0xa02c00
-
-/*
- * 4965 tells driver SRAM address for internal scheduler structs via this reg.
- * Value is valid only after "Alive" response from uCode.
- */
-#define SCD_SRAM_BASE_ADDR           (SCD_START_OFFSET + 0x0)
-
-/*
- * Driver may need to update queue-empty bits after changing queue's
- * write and read pointers (indexes) during (re-)initialization (i.e. when
- * scheduler is not tracking what's happening).
- * Bit fields:
- * 31-16:  Write mask -- 1: update empty bit, 0: don't change empty bit
- * 15-00:  Empty state, one for each queue -- 1: empty, 0: non-empty
- * NOTE:  This register is not used by Linux driver.
- */
-#define SCD_EMPTY_BITS               (SCD_START_OFFSET + 0x4)
-
-/*
- * Physical base address of array of byte count (BC) circular buffers (CBs).
- * Each Tx queue has a BC CB in host DRAM to support Scheduler-ACK mode.
- * This register points to BC CB for queue 0, must be on 1024-byte boundary.
- * Others are spaced by 1024 bytes.
- * Each BC CB is 2 bytes * (256 + 64) = 740 bytes, followed by 384 bytes pad.
- * (Index into a queue's BC CB) = (index into queue's TFD CB) = (SSN & 0xff).
- * Bit fields:
- * 25-00:  Byte Count CB physical address [35:10], must be 1024-byte aligned.
- */
-#define SCD_DRAM_BASE_ADDR           (SCD_START_OFFSET + 0x10)
-
-/*
- * Enables any/all Tx DMA/FIFO channels.
- * Scheduler generates requests for only the active channels.
- * Set this to 0xff to enable all 8 channels (normal usage).
- * Bit fields:
- *  7- 0:  Enable (1), disable (0), one bit for each channel 0-7
- */
-#define SCD_TXFACT                   (SCD_START_OFFSET + 0x1c)
-
-/* Mask to enable contiguous Tx DMA/FIFO channels between "lo" and "hi". */
-#define SCD_TXFACT_REG_TXFIFO_MASK(lo, hi) \
-       ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
-
-/*
- * Queue (x) Write Pointers (indexes, really!), one for each Tx queue.
- * Initialized and updated by driver as new TFDs are added to queue.
- * NOTE:  If using Block Ack, index must correspond to frame's
- *        Start Sequence Number; index = (SSN & 0xff)
- * NOTE:  Alternative to HBUS_TARG_WRPTR, which is what Linux driver uses?
- */
-#define SCD_QUEUE_WRPTR(x)           (SCD_START_OFFSET + 0x24 + (x) * 4)
-
-/*
- * Queue (x) Read Pointers (indexes, really!), one for each Tx queue.
- * For FIFO mode, index indicates next frame to transmit.
- * For Scheduler-ACK mode, index indicates first frame in Tx window.
- * Initialized by driver, updated by scheduler.
- */
-#define SCD_QUEUE_RDPTR(x)           (SCD_START_OFFSET + 0x64 + (x) * 4)
-
-/*
- * Select which queues work in chain mode (1) vs. not (0).
- * Use chain mode to build chains of aggregated frames.
- * Bit fields:
- * 31-16:  Reserved
- * 15-00:  Mode, one bit for each queue -- 1: Chain mode, 0: one-at-a-time
- * NOTE:  If driver sets up queue for chain mode, it should be also set up
- *        Scheduler-ACK mode as well, via SCD_QUEUE_STATUS_BITS(x).
- */
-#define SCD_QUEUECHAIN_SEL           (SCD_START_OFFSET + 0xd0)
-
-/*
- * Select which queues interrupt driver when scheduler increments
- * a queue's read pointer (index).
- * Bit fields:
- * 31-16:  Reserved
- * 15-00:  Interrupt enable, one bit for each queue -- 1: enabled, 0: disabled
- * NOTE:  This functionality is apparently a no-op; driver relies on interrupts
- *        from Rx queue to read Tx command responses and update Tx queues.
- */
-#define SCD_INTERRUPT_MASK           (SCD_START_OFFSET + 0xe4)
-
-/*
- * Queue search status registers.  One for each queue.
- * Sets up queue mode and assigns queue to Tx DMA channel.
- * Bit fields:
- * 19-10: Write mask/enable bits for bits 0-9
- *     9: Driver should init to "0"
- *     8: Scheduler-ACK mode (1), non-Scheduler-ACK (i.e. FIFO) mode (0).
- *        Driver should init to "1" for aggregation mode, or "0" otherwise.
- *   7-6: Driver should init to "0"
- *     5: Window Size Left; indicates whether scheduler can request
- *        another TFD, based on window size, etc.  Driver should init
- *        this bit to "1" for aggregation mode, or "0" for non-agg.
- *   4-1: Tx FIFO to use (range 0-7).
- *     0: Queue is active (1), not active (0).
- * Other bits should be written as "0"
- *
- * NOTE:  If enabling Scheduler-ACK mode, chain mode should also be enabled
- *        via SCD_QUEUECHAIN_SEL.
- */
-#define SCD_QUEUE_STATUS_BITS(x)     (SCD_START_OFFSET + 0x104 + (x) * 4)
-
-/* Bit field positions */
-#define SCD_QUEUE_STTS_REG_POS_ACTIVE          (0)
-#define SCD_QUEUE_STTS_REG_POS_TXF             (1)
-#define SCD_QUEUE_STTS_REG_POS_WSL             (5)
-#define SCD_QUEUE_STTS_REG_POS_SCD_ACK         (8)
-
-/* Write masks */
-#define SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN      (10)
-#define SCD_QUEUE_STTS_REG_MSK                 (0x0007FC00)
-
-/**
- * 4965 internal SRAM structures for scheduler, shared with driver ...
- *
- * Driver should clear and initialize the following areas after receiving
- * "Alive" response from 4965 uCode, i.e. after initial
- * uCode load, or after a uCode load done for error recovery:
- *
- * SCD_CONTEXT_DATA_OFFSET (size 128 bytes)
- * SCD_TX_STTS_BITMAP_OFFSET (size 256 bytes)
- * SCD_TRANSLATE_TBL_OFFSET (size 32 bytes)
- *
- * Driver accesses SRAM via HBUS_TARG_MEM_* registers.
- * Driver reads base address of this scheduler area from SCD_SRAM_BASE_ADDR.
- * All OFFSET values must be added to this base address.
- */
-
-/*
- * Queue context.  One 8-byte entry for each of 16 queues.
- *
- * Driver should clear this entire area (size 0x80) to 0 after receiving
- * "Alive" notification from uCode.  Additionally, driver should init
- * each queue's entry as follows:
- *
- * LS Dword bit fields:
- *  0-06:  Max Tx window size for Scheduler-ACK.  Driver should init to 64.
- *
- * MS Dword bit fields:
- * 16-22:  Frame limit.  Driver should init to 10 (0xa).
- *
- * Driver should init all other bits to 0.
- *
- * Init must be done after driver receives "Alive" response from 4965 uCode,
- * and when setting up queue for aggregation.
- */
-#define SCD_CONTEXT_DATA_OFFSET                        0x380
-#define SCD_CONTEXT_QUEUE_OFFSET(x)    (SCD_CONTEXT_DATA_OFFSET + ((x) * 8))
-
-#define SCD_QUEUE_CTX_REG1_WIN_SIZE_POS                (0)
-#define SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK                (0x0000007F)
-#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS     (16)
-#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK     (0x007F0000)
-
-/*
- * Tx Status Bitmap
- *
- * Driver should clear this entire area (size 0x100) to 0 after receiving
- * "Alive" notification from uCode.  Area is used only by device itself;
- * no other support (besides clearing) is required from driver.
- */
-#define SCD_TX_STTS_BITMAP_OFFSET              0x400
-
-/*
- * RAxTID to queue translation mapping.
- *
- * When queue is in Scheduler-ACK mode, frames placed in a that queue must be
- * for only one combination of receiver address (RA) and traffic ID (TID), i.e.
- * one QOS priority level destined for one station (for this wireless link,
- * not final destination).  The SCD_TRANSLATE_TABLE area provides 16 16-bit
- * mappings, one for each of the 16 queues.  If queue is not in Scheduler-ACK
- * mode, the device ignores the mapping value.
- *
- * Bit fields, for each 16-bit map:
- * 15-9:  Reserved, set to 0
- *  8-4:  Index into device's station table for recipient station
- *  3-0:  Traffic ID (tid), range 0-15
- *
- * Driver should clear this entire area (size 32 bytes) to 0 after receiving
- * "Alive" notification from uCode.  To update a 16-bit map value, driver
- * must read a dword-aligned value from device SRAM, replace the 16-bit map
- * value of interest, and write the dword value back into device SRAM.
- */
-#define SCD_TRANSLATE_TBL_OFFSET               0x500
-
-/* Find translation table dword to read/write for given queue */
-#define SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \
-       ((SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc)
-
-#define SCD_TXFIFO_POS_TID                     (0)
-#define SCD_TXFIFO_POS_RA                      (4)
-#define SCD_QUEUE_RA_TID_MAP_RATID_MSK         (0x01FF)
-
-/*********************** END TX SCHEDULER *************************************/
-
 static inline u8 iwl4965_hw_get_rate(__le32 rate_n_flags)
 {
        return le32_to_cpu(rate_n_flags) & 0xFF;
 }
-static inline u16 iwl4965_hw_get_rate_n_flags(__le32 rate_n_flags)
+static inline u32 iwl4965_hw_get_rate_n_flags(__le32 rate_n_flags)
 {
-       return le32_to_cpu(rate_n_flags) & 0xFFFF;
+       return le32_to_cpu(rate_n_flags) & 0x1FFFF;
 }
 static inline __le32 iwl4965_hw_set_rate_n_flags(u8 rate, u16 flags)
 {
@@ -1385,14 +827,14 @@ static inline __le32 iwl4965_hw_set_rate_n_flags(u8 rate, u16 flags)
  * up to 7 DMA channels (FIFOs).  Each Tx queue is supported by a circular array
  * in DRAM containing 256 Transmit Frame Descriptors (TFDs).
  */
-#define IWL4965_MAX_WIN_SIZE   64
-#define IWL4965_QUEUE_SIZE     256
-#define IWL4965_NUM_FIFOS      7
-#define IWL4965_MAX_NUM_QUEUES 16
-
+#define IWL49_MAX_WIN_SIZE     64
+#define IWL49_QUEUE_SIZE       256
+#define IWL49_NUM_FIFOS        7
+#define IWL49_CMD_FIFO_NUM     4
+#define IWL49_NUM_QUEUES       16
 
 /**
- * struct iwl4965_tfd_frame_data
+ * struct iwl_tfd_frame_data
  *
  * Describes up to 2 buffers containing (contiguous) portions of a Tx frame.
  * Each buffer must be on dword boundary.
@@ -1411,7 +853,7 @@ static inline __le32 iwl4965_hw_set_rate_n_flags(u8 rate, u16 flags)
  * 31-20: Tx buffer 2 length (bytes)
  * 19- 0: Tx buffer 2 address bits [35:16]
  */
-struct iwl4965_tfd_frame_data {
+struct iwl_tfd_frame_data {
        __le32 tb1_addr;
 
        __le32 val1;
@@ -1441,7 +883,7 @@ struct iwl4965_tfd_frame_data {
 
 
 /**
- * struct iwl4965_tfd_frame
+ * struct iwl_tfd_frame
  *
  * Transmit Frame Descriptor (TFD)
  *
@@ -1468,7 +910,7 @@ struct iwl4965_tfd_frame_data {
  *
  * A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx.
  */
-struct iwl4965_tfd_frame {
+struct iwl_tfd_frame {
        __le32 val0;
        /* __le32 rsvd1:24; */
        /* __le32 num_tbs:5; */
@@ -1477,7 +919,7 @@ struct iwl4965_tfd_frame {
 #define IWL_num_tbs_SYM val0
        /* __le32 rsvd2:1; */
        /* __le32 padding:2; */
-       struct iwl4965_tfd_frame_data pa[10];
+       struct iwl_tfd_frame_data pa[10];
        __le32 reserved;
 } __attribute__ ((packed));
 
@@ -1520,10 +962,10 @@ struct iwl4965_queue_byte_cnt_entry {
  * 4965 assumes tables are separated by 1024 bytes.
  */
 struct iwl4965_sched_queue_byte_cnt_tbl {
-       struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL4965_QUEUE_SIZE +
-                                                      IWL4965_MAX_WIN_SIZE];
+       struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL49_QUEUE_SIZE +
+                                                      IWL49_MAX_WIN_SIZE];
        u8 dont_care[1024 -
-                    (IWL4965_QUEUE_SIZE + IWL4965_MAX_WIN_SIZE) *
+                    (IWL49_QUEUE_SIZE + IWL49_MAX_WIN_SIZE) *
                     sizeof(__le16)];
 } __attribute__ ((packed));
 
@@ -1553,7 +995,7 @@ struct iwl4965_sched_queue_byte_cnt_tbl {
  */
 struct iwl4965_shared {
        struct iwl4965_sched_queue_byte_cnt_tbl
-        queues_byte_cnt_tbls[IWL4965_MAX_NUM_QUEUES];
+        queues_byte_cnt_tbls[IWL49_NUM_QUEUES];
        __le32 rb_closed;
 
        /* __le32 rb_closed_stts_rb_num:12; */
index 3a7f0cb710ec62633df55c6609200612c4283ffc..d8f2b4d33fd9c3e50ee9f3f39037845b1b70ec8d 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/skbuff.h>
 #include <linux/wireless.h>
 #include <net/mac80211.h>
-#include <net/ieee80211.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 
 #include "../net/mac80211/rate.h"
 
-#include "iwl-4965.h"
+#include "iwl-dev.h"
 #include "iwl-core.h"
 #include "iwl-helpers.h"
 
 #define RS_NAME "iwl-4965-rs"
 
-#define NUM_TRY_BEFORE_ANTENNA_TOGGLE 1
+#define NUM_TRY_BEFORE_ANT_TOGGLE 1
 #define IWL_NUMBER_TRY      1
 #define IWL_HT_NUMBER_TRY   3
 
@@ -65,9 +64,16 @@ static u8 rs_ht_to_legacy[] = {
        IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX
 };
 
-struct iwl4965_rate {
-       u32 rate_n_flags;
-} __attribute__ ((packed));
+static const u8 ant_toggle_lookup[] = {
+       /*ANT_NONE -> */ ANT_NONE,
+       /*ANT_A    -> */ ANT_B,
+       /*ANT_B    -> */ ANT_C,
+       /*ANT_AB   -> */ ANT_BC,
+       /*ANT_C    -> */ ANT_A,
+       /*ANT_AC   -> */ ANT_AB,
+       /*ANT_BC   -> */ ANT_AC,
+       /*ANT_ABC  -> */ ANT_ABC,
+};
 
 /**
  * struct iwl4965_rate_scale_data -- tx success history for one rate
@@ -88,14 +94,14 @@ struct iwl4965_rate_scale_data {
  * one for "active", and one for "search".
  */
 struct iwl4965_scale_tbl_info {
-       enum iwl4965_table_type lq_type;
-       enum iwl4965_antenna_type antenna_type;
+       enum iwl_table_type lq_type;
+       u8 ant_type;
        u8 is_SGI;      /* 1 = short guard interval */
        u8 is_fat;      /* 1 = 40 MHz channel width */
        u8 is_dup;      /* 1 = duplicated data streams */
        u8 action;      /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
        s32 *expected_tpt;      /* throughput metrics; expected_tpt_G, etc. */
-       struct iwl4965_rate current_rate;  /* rate_n_flags, uCode API format */
+       u32 current_rate;  /* rate_n_flags, uCode API format */
        struct iwl4965_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
 };
 
@@ -136,8 +142,6 @@ struct iwl4965_lq_sta {
        u32 flush_timer;        /* time staying in mode before new search */
 
        u8 action_counter;      /* # mode-switch actions tried */
-       u8 antenna;
-       u8 valid_antenna;
        u8 is_green;
        u8 is_dup;
        enum ieee80211_band band;
@@ -145,9 +149,10 @@ struct iwl4965_lq_sta {
 
        /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
        u32 supp_rates;
-       u16 active_rate;
+       u16 active_legacy_rate;
        u16 active_siso_rate;
-       u16 active_mimo_rate;
+       u16 active_mimo2_rate;
+       u16 active_mimo3_rate;
        u16 active_rate_basic;
 
        struct iwl_link_quality_cmd lq;
@@ -162,7 +167,7 @@ struct iwl4965_lq_sta {
 #ifdef CONFIG_IWL4965_HT
        struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file;
 #endif
-       struct iwl4965_rate dbg_fixed;
+       u32 dbg_fixed_rate;
 #endif
        struct iwl_priv *drv;
 };
@@ -171,17 +176,17 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
                                   struct net_device *dev,
                                   struct ieee80211_hdr *hdr,
                                   struct sta_info *sta);
-static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta,
-                            struct iwl4965_rate *tx_mcs,
-                            struct iwl_link_quality_cmd *tbl);
+static void rs_fill_link_cmd(const struct iwl_priv *priv,
+                            struct iwl4965_lq_sta *lq_sta,
+                            u32 rate_n_flags);
 
 
 #ifdef CONFIG_MAC80211_DEBUGFS
 static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta,
-                               struct iwl4965_rate *mcs, int index);
+                                       u32 *rate_n_flags, int index);
 #else
 static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta,
-                               struct iwl4965_rate *mcs, int index)
+                                       u32 *rate_n_flags, int index)
 {}
 #endif
 
@@ -190,6 +195,7 @@ static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta,
  * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits
  * "G" is the only table that supports CCK (the first 4 rates).
  */
+/*FIXME:RS:need to spearate tables for MIMO2/MIMO3*/
 static s32 expected_tpt_A[IWL_RATE_COUNT] = {
        0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186
 };
@@ -230,7 +236,7 @@ static s32 expected_tpt_mimo40MHzSGI[IWL_RATE_COUNT] = {
        0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293
 };
 
-static inline u8 iwl4965_rate_get_rate(u32 rate_n_flags)
+static inline u8 rs_extract_rate(u32 rate_n_flags)
 {
        return (u8)(rate_n_flags & 0xFF);
 }
@@ -245,6 +251,11 @@ static void rs_rate_scale_clear_window(struct iwl4965_rate_scale_data *window)
        window->stamp = 0;
 }
 
+static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type)
+{
+       return ((ant_type & valid_antenna) == ant_type);
+}
+
 #ifdef CONFIG_IWL4965_HT
 /*
  *     removes the old data from the statistics. All data that is older than
@@ -271,14 +282,20 @@ static void rs_tl_rm_old_stats(struct iwl4965_traffic_load *tl, u32 curr_time)
  *     increment traffic load value for tid and also remove
  *     any old values if passed the certain time period
  */
-static void rs_tl_add_packet(struct iwl4965_lq_sta *lq_data, u8 tid)
+static void rs_tl_add_packet(struct iwl4965_lq_sta *lq_data,
+                            struct ieee80211_hdr *hdr)
 {
        u32 curr_time = jiffies_to_msecs(jiffies);
        u32 time_diff;
        s32 index;
        struct iwl4965_traffic_load *tl = NULL;
+       u16 fc = le16_to_cpu(hdr->frame_control);
+       u8 tid;
 
-       if (tid >= TID_MAX_LOAD_COUNT)
+       if (ieee80211_is_qos_data(fc)) {
+               u8 *qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc));
+               tid = qc[0] & 0xf;
+       } else
                return;
 
        tl = &lq_data->load[tid];
@@ -349,9 +366,9 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
        unsigned long state;
        DECLARE_MAC_BUF(mac);
 
-       spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+       spin_lock_bh(&sta->lock);
        state = sta->ampdu_mlme.tid_state_tx[tid];
-       spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+       spin_unlock_bh(&sta->lock);
 
        if (state == HT_AGG_STATE_IDLE &&
            rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) {
@@ -374,6 +391,13 @@ static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid,
 
 #endif /* CONFIG_IWLWIFI_HT */
 
+static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
+{
+       return (!!(rate_n_flags & RATE_MCS_ANT_A_MSK) +
+               !!(rate_n_flags & RATE_MCS_ANT_B_MSK) +
+               !!(rate_n_flags & RATE_MCS_ANT_C_MSK));
+}
+
 /**
  * rs_collect_tx_data - Update the success/failure sliding window
  *
@@ -386,8 +410,7 @@ static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows,
                              int successes)
 {
        struct iwl4965_rate_scale_data *window = NULL;
-       u64 mask;
-       u8 win_size = IWL_RATE_MAX_WINDOW;
+       static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1));
        s32 fail_count;
 
        if (scale_index < 0 || scale_index >= IWL_RATE_COUNT)
@@ -405,14 +428,14 @@ static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows,
         * we keep these bitmaps!).
         */
        while (retries > 0) {
-               if (window->counter >= win_size) {
-                       window->counter = win_size - 1;
-                       mask = 1;
-                       mask = (mask << (win_size - 1));
+               if (window->counter >= IWL_RATE_MAX_WINDOW) {
+
+                       /* remove earliest */
+                       window->counter = IWL_RATE_MAX_WINDOW - 1;
+
                        if (window->data & mask) {
                                window->data &= ~mask;
-                               window->success_counter =
-                                       window->success_counter - 1;
+                               window->success_counter--;
                        }
                }
 
@@ -422,10 +445,9 @@ static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows,
                /* Shift bitmap by one frame (throw away oldest history),
                 * OR in "1", and increment "success" if this
                 * frame was successful. */
-               mask = window->data;
-               window->data = (mask << 1);
+               window->data <<= 1;;
                if (successes > 0) {
-                       window->success_counter = window->success_counter + 1;
+                       window->success_counter++;
                        window->data |= 0x1;
                        successes--;
                }
@@ -458,170 +480,166 @@ static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows,
 /*
  * Fill uCode API rate_n_flags field, based on "search" or "active" table.
  */
-static void rs_mcs_from_tbl(struct iwl4965_rate *mcs_rate,
-                          struct iwl4965_scale_tbl_info *tbl,
-                          int index, u8 use_green)
+/* FIXME:RS:remove this function and put the flags statically in the table */
+static u32 rate_n_flags_from_tbl(struct iwl4965_scale_tbl_info *tbl,
+                                      int index, u8 use_green)
 {
+       u32 rate_n_flags = 0;
+
        if (is_legacy(tbl->lq_type)) {
-               mcs_rate->rate_n_flags = iwl4965_rates[index].plcp;
+               rate_n_flags = iwl_rates[index].plcp;
                if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE)
-                       mcs_rate->rate_n_flags |= RATE_MCS_CCK_MSK;
+                       rate_n_flags |= RATE_MCS_CCK_MSK;
 
-       } else if (is_siso(tbl->lq_type)) {
-               if (index > IWL_LAST_OFDM_RATE)
+       } else if (is_Ht(tbl->lq_type)) {
+               if (index > IWL_LAST_OFDM_RATE) {
+                       IWL_ERROR("invalid HT rate index %d\n", index);
                        index = IWL_LAST_OFDM_RATE;
-                mcs_rate->rate_n_flags = iwl4965_rates[index].plcp_siso |
-                                         RATE_MCS_HT_MSK;
-       } else {
-               if (index > IWL_LAST_OFDM_RATE)
-                       index = IWL_LAST_OFDM_RATE;
-               mcs_rate->rate_n_flags = iwl4965_rates[index].plcp_mimo |
-                                        RATE_MCS_HT_MSK;
-       }
-
-       switch (tbl->antenna_type) {
-       case ANT_BOTH:
-               mcs_rate->rate_n_flags |= RATE_MCS_ANT_AB_MSK;
-               break;
-       case ANT_MAIN:
-               mcs_rate->rate_n_flags |= RATE_MCS_ANT_A_MSK;
-               break;
-       case ANT_AUX:
-               mcs_rate->rate_n_flags |= RATE_MCS_ANT_B_MSK;
-               break;
-       case ANT_NONE:
-               break;
-       }
-
-       if (is_legacy(tbl->lq_type))
-               return;
+               }
+               rate_n_flags = RATE_MCS_HT_MSK;
 
-       if (tbl->is_fat) {
-               if (tbl->is_dup)
-                       mcs_rate->rate_n_flags |= RATE_MCS_DUP_MSK;
+               if (is_siso(tbl->lq_type))
+                       rate_n_flags |= iwl_rates[index].plcp_siso;
+               else if (is_mimo2(tbl->lq_type))
+                       rate_n_flags |= iwl_rates[index].plcp_mimo2;
                else
-                       mcs_rate->rate_n_flags |= RATE_MCS_FAT_MSK;
+                       rate_n_flags |= iwl_rates[index].plcp_mimo3;
+       } else {
+               IWL_ERROR("Invalid tbl->lq_type %d\n", tbl->lq_type);
        }
-       if (tbl->is_SGI)
-               mcs_rate->rate_n_flags |= RATE_MCS_SGI_MSK;
 
-       if (use_green) {
-               mcs_rate->rate_n_flags |= RATE_MCS_GF_MSK;
-               if (is_siso(tbl->lq_type))
-                       mcs_rate->rate_n_flags &= ~RATE_MCS_SGI_MSK;
+       rate_n_flags |= ((tbl->ant_type << RATE_MCS_ANT_POS) &
+                                                    RATE_MCS_ANT_ABC_MSK);
+
+       if (is_Ht(tbl->lq_type)) {
+               if (tbl->is_fat) {
+                       if (tbl->is_dup)
+                               rate_n_flags |= RATE_MCS_DUP_MSK;
+                       else
+                               rate_n_flags |= RATE_MCS_FAT_MSK;
+               }
+               if (tbl->is_SGI)
+                       rate_n_flags |= RATE_MCS_SGI_MSK;
+
+               if (use_green) {
+                       rate_n_flags |= RATE_MCS_GF_MSK;
+                       if (is_siso(tbl->lq_type) && tbl->is_SGI) {
+                               rate_n_flags &= ~RATE_MCS_SGI_MSK;
+                               IWL_ERROR("GF was set with SGI:SISO\n");
+                       }
+               }
        }
+       return rate_n_flags;
 }
 
 /*
  * Interpret uCode API's rate_n_flags format,
  * fill "search" or "active" tx mode table.
  */
-static int rs_get_tbl_info_from_mcs(const struct iwl4965_rate *mcs_rate,
+static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
                                    enum ieee80211_band band,
                                    struct iwl4965_scale_tbl_info *tbl,
                                    int *rate_idx)
 {
-       int index;
-       u32 ant_msk;
+       u32 ant_msk = (rate_n_flags & RATE_MCS_ANT_ABC_MSK);
+       u8 num_of_ant = get_num_of_ant_from_rate(rate_n_flags);
+       u8 mcs;
 
-       index = iwl4965_hwrate_to_plcp_idx(mcs_rate->rate_n_flags);
+       *rate_idx = iwl4965_hwrate_to_plcp_idx(rate_n_flags);
 
-       if (index  == IWL_RATE_INVALID) {
+       if (*rate_idx  == IWL_RATE_INVALID) {
                *rate_idx = -1;
                return -EINVAL;
        }
        tbl->is_SGI = 0;        /* default legacy setup */
        tbl->is_fat = 0;
        tbl->is_dup = 0;
-       tbl->antenna_type = ANT_BOTH;   /* default MIMO setup */
+       tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS);
+       tbl->lq_type = LQ_NONE;
 
        /* legacy rate format */
-       if (!(mcs_rate->rate_n_flags & RATE_MCS_HT_MSK)) {
-               ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK);
-
-               if (ant_msk == RATE_MCS_ANT_AB_MSK)
-                       tbl->lq_type = LQ_NONE;
-               else {
-
+       if (!(rate_n_flags & RATE_MCS_HT_MSK)) {
+               if (num_of_ant == 1) {
                        if (band == IEEE80211_BAND_5GHZ)
                                tbl->lq_type = LQ_A;
                        else
                                tbl->lq_type = LQ_G;
-
-                       if (mcs_rate->rate_n_flags & RATE_MCS_ANT_A_MSK)
-                               tbl->antenna_type = ANT_MAIN;
-                       else
-                               tbl->antenna_type = ANT_AUX;
                }
-               *rate_idx = index;
-
-       /* HT rate format, SISO (might be 20 MHz legacy or 40 MHz fat width) */
-       } else if (iwl4965_rate_get_rate(mcs_rate->rate_n_flags)
-                                       <= IWL_RATE_SISO_60M_PLCP) {
-               tbl->lq_type = LQ_SISO;
-
-               ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK);
-               if (ant_msk == RATE_MCS_ANT_AB_MSK)
-                       tbl->lq_type = LQ_NONE;
-               else {
-                       if (mcs_rate->rate_n_flags & RATE_MCS_ANT_A_MSK)
-                               tbl->antenna_type = ANT_MAIN;
-                       else
-                               tbl->antenna_type = ANT_AUX;
-               }
-               if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK)
-                       tbl->is_SGI = 1;
-
-               if ((mcs_rate->rate_n_flags & RATE_MCS_FAT_MSK) ||
-                   (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK))
-                       tbl->is_fat = 1;
-
-               if (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK)
-                       tbl->is_dup = 1;
-
-               *rate_idx = index;
-
-       /* HT rate format, MIMO (might be 20 MHz legacy or 40 MHz fat width) */
+       /* HT rate format */
        } else {
-               tbl->lq_type = LQ_MIMO;
-               if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK)
+               if (rate_n_flags & RATE_MCS_SGI_MSK)
                        tbl->is_SGI = 1;
 
-               if ((mcs_rate->rate_n_flags & RATE_MCS_FAT_MSK) ||
-                   (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK))
+               if ((rate_n_flags & RATE_MCS_FAT_MSK) ||
+                   (rate_n_flags & RATE_MCS_DUP_MSK))
                        tbl->is_fat = 1;
 
-               if (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK)
+               if (rate_n_flags & RATE_MCS_DUP_MSK)
                        tbl->is_dup = 1;
-               *rate_idx = index;
+
+               mcs = rs_extract_rate(rate_n_flags);
+
+               /* SISO */
+               if (mcs <= IWL_RATE_SISO_60M_PLCP) {
+                       if (num_of_ant == 1)
+                               tbl->lq_type = LQ_SISO; /*else NONE*/
+               /* MIMO2 */
+               } else if (mcs <= IWL_RATE_MIMO2_60M_PLCP) {
+                       if (num_of_ant == 2)
+                               tbl->lq_type = LQ_MIMO2;
+               /* MIMO3 */
+               } else {
+                       if (num_of_ant == 3)
+                               tbl->lq_type = LQ_MIMO3;
+               }
        }
        return 0;
 }
 
-static inline void rs_toggle_antenna(struct iwl4965_rate *new_rate,
-                                    struct iwl4965_scale_tbl_info *tbl)
+/* switch to another antenna/antennas and return 1 */
+/* if no other valid antenna found, return 0 */
+static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
+                             struct iwl4965_scale_tbl_info *tbl)
 {
-       if (tbl->antenna_type == ANT_AUX) {
-               tbl->antenna_type = ANT_MAIN;
-               new_rate->rate_n_flags &= ~RATE_MCS_ANT_B_MSK;
-               new_rate->rate_n_flags |= RATE_MCS_ANT_A_MSK;
-       } else {
-               tbl->antenna_type = ANT_AUX;
-               new_rate->rate_n_flags &= ~RATE_MCS_ANT_A_MSK;
-               new_rate->rate_n_flags |= RATE_MCS_ANT_B_MSK;
-       }
+       u8 new_ant_type;
+
+       if (!tbl->ant_type || tbl->ant_type > ANT_ABC)
+               return 0;
+
+       if (!rs_is_valid_ant(valid_ant, tbl->ant_type))
+               return 0;
+
+       new_ant_type = ant_toggle_lookup[tbl->ant_type];
+
+       while ((new_ant_type != tbl->ant_type) &&
+              !rs_is_valid_ant(valid_ant, new_ant_type))
+               new_ant_type = ant_toggle_lookup[new_ant_type];
+
+       if (new_ant_type == tbl->ant_type)
+               return 0;
+
+       tbl->ant_type = new_ant_type;
+       *rate_n_flags &= ~RATE_MCS_ANT_ABC_MSK;
+       *rate_n_flags |= new_ant_type << RATE_MCS_ANT_POS;
+       return 1;
 }
 
-static inline u8 rs_use_green(struct iwl_priv *priv,
-                             struct ieee80211_conf *conf)
+/* FIXME:RS: in 4965 we don't use greenfield at all */
+/* FIXME:RS: don't use greenfield for now in TX */
+/* #ifdef CONFIG_IWL4965_HT */
+#if 0
+static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf)
 {
-#ifdef CONFIG_IWL4965_HT
        return ((conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) &&
                priv->current_ht_config.is_green_field &&
                !priv->current_ht_config.non_GF_STA_present);
-#endif /* CONFIG_IWL4965_HT */
+}
+#else
+static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf)
+{
        return 0;
 }
+#endif /* CONFIG_IWL4965_HT */
 
 /**
  * rs_get_supported_rates - get the available rates
@@ -630,27 +648,28 @@ static inline u8 rs_use_green(struct iwl_priv *priv,
  * basic available rates.
  *
  */
-static void rs_get_supported_rates(struct iwl4965_lq_sta *lq_sta,
+static u16 rs_get_supported_rates(struct iwl4965_lq_sta *lq_sta,
                                   struct ieee80211_hdr *hdr,
-                                  enum iwl4965_table_type rate_type,
-                                  u16 *data_rate)
+                                  enum iwl_table_type rate_type)
 {
-       if (is_legacy(rate_type))
-               *data_rate = lq_sta->active_rate;
-       else {
+       if (hdr && is_multicast_ether_addr(hdr->addr1) &&
+           lq_sta->active_rate_basic)
+               return lq_sta->active_rate_basic;
+
+       if (is_legacy(rate_type)) {
+               return lq_sta->active_legacy_rate;
+       } else {
                if (is_siso(rate_type))
-                       *data_rate = lq_sta->active_siso_rate;
+                       return lq_sta->active_siso_rate;
+               else if (is_mimo2(rate_type))
+                       return lq_sta->active_mimo2_rate;
                else
-                       *data_rate = lq_sta->active_mimo_rate;
-       }
-
-       if (hdr && is_multicast_ether_addr(hdr->addr1) &&
-           lq_sta->active_rate_basic) {
-               *data_rate = lq_sta->active_rate_basic;
+                       return lq_sta->active_mimo3_rate;
        }
 }
 
-static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type)
+static u16 rs_get_adjacent_rate(struct iwl_priv *priv, u8 index, u16 rate_mask,
+                               int rate_type)
 {
        u8 high = IWL_RATE_INVALID;
        u8 low = IWL_RATE_INVALID;
@@ -684,7 +703,7 @@ static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type)
 
        low = index;
        while (low != IWL_RATE_INVALID) {
-               low = iwl4965_rates[low].prev_rs;
+               low = iwl_rates[low].prev_rs;
                if (low == IWL_RATE_INVALID)
                        break;
                if (rate_mask & (1 << low))
@@ -694,7 +713,7 @@ static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type)
 
        high = index;
        while (high != IWL_RATE_INVALID) {
-               high = iwl4965_rates[high].next_rs;
+               high = iwl_rates[high].next_rs;
                if (high == IWL_RATE_INVALID)
                        break;
                if (rate_mask & (1 << high))
@@ -705,9 +724,9 @@ static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type)
        return (high << 8) | low;
 }
 
-static void rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta,
+static u32 rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta,
                             struct iwl4965_scale_tbl_info *tbl, u8 scale_index,
-                            u8 ht_possible, struct iwl4965_rate *mcs_rate)
+                            u8 ht_possible)
 {
        s32 low;
        u16 rate_mask;
@@ -726,15 +745,14 @@ static void rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta,
                else
                        tbl->lq_type = LQ_G;
 
-               if ((tbl->antenna_type == ANT_BOTH) ||
-                   (tbl->antenna_type == ANT_NONE))
-                       tbl->antenna_type = ANT_MAIN;
+               if (num_of_ant(tbl->ant_type) > 1)
+                       tbl->ant_type = ANT_A;/*FIXME:RS*/
 
                tbl->is_fat = 0;
                tbl->is_SGI = 0;
        }
 
-       rs_get_supported_rates(lq_sta, NULL, tbl->lq_type, &rate_mask);
+       rate_mask = rs_get_supported_rates(lq_sta, NULL, tbl->lq_type);
 
        /* Mask with station rate restriction */
        if (is_legacy(tbl->lq_type)) {
@@ -748,25 +766,26 @@ static void rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta,
 
        /* If we switched from HT to legacy, check current rate */
        if (switch_to_legacy && (rate_mask & (1 << scale_index))) {
-               rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green);
-               return;
+               low = scale_index;
+               goto out;
        }
 
-       high_low = rs_get_adjacent_rate(scale_index, rate_mask, tbl->lq_type);
+       high_low = rs_get_adjacent_rate(lq_sta->drv, scale_index, rate_mask,
+                                       tbl->lq_type);
        low = high_low & 0xff;
 
-       if (low != IWL_RATE_INVALID)
-               rs_mcs_from_tbl(mcs_rate, tbl, low, is_green);
-       else
-               rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green);
+       if (low == IWL_RATE_INVALID)
+               low = scale_index;
+
+out:
+       return rate_n_flags_from_tbl(tbl, low, is_green);
 }
 
 /*
  * mac80211 sends us Tx status
  */
 static void rs_tx_status(void *priv_rate, struct net_device *dev,
-                        struct sk_buff *skb,
-                        struct ieee80211_tx_status *tx_resp)
+                        struct sk_buff *skb)
 {
        int status;
        u8 retries;
@@ -778,9 +797,10 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
        struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_hw *hw = local_to_hw(local);
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct iwl4965_rate_scale_data *window = NULL;
        struct iwl4965_rate_scale_data *search_win = NULL;
-       struct iwl4965_rate tx_mcs;
+       u32 tx_rate;
        struct iwl4965_scale_tbl_info tbl_type;
        struct iwl4965_scale_tbl_info *curr_tbl, *search_tbl;
        u8 active_index = 0;
@@ -793,11 +813,11 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
                return;
 
        /* This packet was aggregated but doesn't carry rate scale info */
-       if ((tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) &&
-           !(tx_resp->flags & IEEE80211_TX_STATUS_AMPDU))
+       if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
+           !(info->flags & IEEE80211_TX_STAT_AMPDU))
                return;
 
-       retries = tx_resp->retry_count;
+       retries = info->status.retry_count;
 
        if (retries > 15)
                retries = 15;
@@ -822,15 +842,6 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
        table = &lq_sta->lq;
        active_index = lq_sta->active_tbl;
 
-       /* Get mac80211 antenna info */
-       lq_sta->antenna =
-               (lq_sta->valid_antenna & local->hw.conf.antenna_sel_tx);
-       if (!lq_sta->antenna)
-               lq_sta->antenna = lq_sta->valid_antenna;
-
-       /* Ignore mac80211 antenna info for now */
-       lq_sta->antenna = lq_sta->valid_antenna;
-
        curr_tbl = &(lq_sta->lq_info[active_index]);
        search_tbl = &(lq_sta->lq_info[(1 - active_index)]);
        window = (struct iwl4965_rate_scale_data *)
@@ -846,28 +857,26 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
         * to check "search" mode, or a prior "search" mode after we've moved
         * to a new "search" mode (which might become the new "active" mode).
         */
-       tx_mcs.rate_n_flags = le32_to_cpu(table->rs_table[0].rate_n_flags);
-       rs_get_tbl_info_from_mcs(&tx_mcs, priv->band, &tbl_type, &rs_index);
+       tx_rate = le32_to_cpu(table->rs_table[0].rate_n_flags);
+       rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index);
        if (priv->band == IEEE80211_BAND_5GHZ)
                rs_index -= IWL_FIRST_OFDM_RATE;
 
-       if ((tx_resp->control.tx_rate == NULL) ||
+       if ((info->tx_rate_idx < 0) ||
            (tbl_type.is_SGI ^
-               !!(tx_resp->control.flags & IEEE80211_TXCTL_SHORT_GI)) ||
+               !!(info->flags & IEEE80211_TX_CTL_SHORT_GI)) ||
            (tbl_type.is_fat ^
-               !!(tx_resp->control.flags & IEEE80211_TXCTL_40_MHZ_WIDTH)) ||
+               !!(info->flags & IEEE80211_TX_CTL_40_MHZ_WIDTH)) ||
            (tbl_type.is_dup ^
-               !!(tx_resp->control.flags & IEEE80211_TXCTL_DUP_DATA)) ||
-           (tbl_type.antenna_type ^
-               tx_resp->control.antenna_sel_tx) ||
-           (!!(tx_mcs.rate_n_flags & RATE_MCS_HT_MSK) ^
-               !!(tx_resp->control.flags & IEEE80211_TXCTL_OFDM_HT)) ||
-           (!!(tx_mcs.rate_n_flags & RATE_MCS_GF_MSK) ^
-               !!(tx_resp->control.flags & IEEE80211_TXCTL_GREEN_FIELD)) ||
+               !!(info->flags & IEEE80211_TX_CTL_DUP_DATA)) ||
+           (tbl_type.ant_type ^ info->antenna_sel_tx) ||
+           (!!(tx_rate & RATE_MCS_HT_MSK) ^
+               !!(info->flags & IEEE80211_TX_CTL_OFDM_HT)) ||
+           (!!(tx_rate & RATE_MCS_GF_MSK) ^
+               !!(info->flags & IEEE80211_TX_CTL_GREEN_FIELD)) ||
            (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate !=
-               tx_resp->control.tx_rate->bitrate)) {
-               IWL_DEBUG_RATE("initial rate does not match 0x%x\n",
-                               tx_mcs.rate_n_flags);
+            hw->wiphy->bands[info->band]->bitrates[info->tx_rate_idx].bitrate)) {
+               IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate);
                goto out;
        }
 
@@ -875,15 +884,14 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
        while (retries) {
                /* Look up the rate and other info used for each tx attempt.
                 * Each tx attempt steps one entry deeper in the rate table. */
-               tx_mcs.rate_n_flags =
-                   le32_to_cpu(table->rs_table[index].rate_n_flags);
-               rs_get_tbl_info_from_mcs(&tx_mcs, priv->band,
+               tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags);
+               rs_get_tbl_info_from_mcs(tx_rate, priv->band,
                                          &tbl_type, &rs_index);
 
                /* If type matches "search" table,
                 * add failure to "search" history */
                if ((tbl_type.lq_type == search_tbl->lq_type) &&
-                   (tbl_type.antenna_type == search_tbl->antenna_type) &&
+                   (tbl_type.ant_type == search_tbl->ant_type) &&
                    (tbl_type.is_SGI == search_tbl->is_SGI)) {
                        if (search_tbl->expected_tpt)
                                tpt = search_tbl->expected_tpt[rs_index];
@@ -894,7 +902,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
                /* Else if type matches "current/active" table,
                 * add failure to "current/active" history */
                } else if ((tbl_type.lq_type == curr_tbl->lq_type) &&
-                          (tbl_type.antenna_type == curr_tbl->antenna_type) &&
+                          (tbl_type.ant_type == curr_tbl->ant_type) &&
                           (tbl_type.is_SGI == curr_tbl->is_SGI)) {
                        if (curr_tbl->expected_tpt)
                                tpt = curr_tbl->expected_tpt[rs_index];
@@ -917,44 +925,41 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
         * if Tx was successful first try, use original rate,
         * else look up the rate that was, finally, successful.
         */
-       tx_mcs.rate_n_flags = le32_to_cpu(table->rs_table[index].rate_n_flags);
-       rs_get_tbl_info_from_mcs(&tx_mcs, priv->band, &tbl_type, &rs_index);
+       tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags);
+       rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index);
 
        /* Update frame history window with "success" if Tx got ACKed ... */
-       if (tx_resp->flags & IEEE80211_TX_STATUS_ACK)
-               status = 1;
-       else
-               status = 0;
+       status = !!(info->flags & IEEE80211_TX_STAT_ACK);
 
        /* If type matches "search" table,
         * add final tx status to "search" history */
        if ((tbl_type.lq_type == search_tbl->lq_type) &&
-           (tbl_type.antenna_type == search_tbl->antenna_type) &&
+           (tbl_type.ant_type == search_tbl->ant_type) &&
            (tbl_type.is_SGI == search_tbl->is_SGI)) {
                if (search_tbl->expected_tpt)
                        tpt = search_tbl->expected_tpt[rs_index];
                else
                        tpt = 0;
-               if (tx_resp->control.flags & IEEE80211_TXCTL_AMPDU)
+               if (info->flags & IEEE80211_TX_CTL_AMPDU)
                        rs_collect_tx_data(search_win, rs_index, tpt,
-                                          tx_resp->ampdu_ack_len,
-                                          tx_resp->ampdu_ack_map);
+                                          info->status.ampdu_ack_len,
+                                          info->status.ampdu_ack_map);
                else
                        rs_collect_tx_data(search_win, rs_index, tpt,
                                           1, status);
        /* Else if type matches "current/active" table,
         * add final tx status to "current/active" history */
        } else if ((tbl_type.lq_type == curr_tbl->lq_type) &&
-                  (tbl_type.antenna_type == curr_tbl->antenna_type) &&
+                  (tbl_type.ant_type == curr_tbl->ant_type) &&
                   (tbl_type.is_SGI == curr_tbl->is_SGI)) {
                if (curr_tbl->expected_tpt)
                        tpt = curr_tbl->expected_tpt[rs_index];
                else
                        tpt = 0;
-               if (tx_resp->control.flags & IEEE80211_TXCTL_AMPDU)
+               if (info->flags & IEEE80211_TX_CTL_AMPDU)
                        rs_collect_tx_data(window, rs_index, tpt,
-                                          tx_resp->ampdu_ack_len,
-                                          tx_resp->ampdu_ack_map);
+                                          info->status.ampdu_ack_len,
+                                          info->status.ampdu_ack_map);
                else
                        rs_collect_tx_data(window, rs_index, tpt,
                                           1, status);
@@ -963,10 +968,10 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
        /* If not searching for new mode, increment success/failed counter
         * ... these help determine when to start searching again */
        if (lq_sta->stay_in_tbl) {
-               if (tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) {
-                       lq_sta->total_success += tx_resp->ampdu_ack_map;
+               if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+                       lq_sta->total_success += info->status.ampdu_ack_map;
                        lq_sta->total_failed +=
-                            (tx_resp->ampdu_ack_len - tx_resp->ampdu_ack_map);
+                            (info->status.ampdu_ack_len - info->status.ampdu_ack_map);
                } else {
                        if (status)
                                lq_sta->total_success++;
@@ -982,30 +987,6 @@ out:
        return;
 }
 
-static u8 rs_is_ant_connected(u8 valid_antenna,
-                             enum iwl4965_antenna_type antenna_type)
-{
-       if (antenna_type == ANT_AUX)
-               return ((valid_antenna & 0x2) ? 1:0);
-       else if (antenna_type == ANT_MAIN)
-               return ((valid_antenna & 0x1) ? 1:0);
-       else if (antenna_type == ANT_BOTH)
-               return ((valid_antenna & 0x3) == 0x3);
-
-       return 1;
-}
-
-static u8 rs_is_other_ant_connected(u8 valid_antenna,
-                                   enum iwl4965_antenna_type antenna_type)
-{
-       if (antenna_type == ANT_AUX)
-               return rs_is_ant_connected(valid_antenna, ANT_MAIN);
-       else
-               return rs_is_ant_connected(valid_antenna, ANT_AUX);
-
-       return 0;
-}
-
 /*
  * Begin a period of staying with a selected modulation mode.
  * Set "stay_in_tbl" flag to prevent any mode switches.
@@ -1014,10 +995,10 @@ static u8 rs_is_other_ant_connected(u8 valid_antenna,
  * These control how long we stay using same modulation mode before
  * searching for a new mode.
  */
-static void rs_set_stay_in_table(u8 is_legacy,
+static void rs_set_stay_in_table(struct iwl_priv *priv, u8 is_legacy,
                                 struct iwl4965_lq_sta *lq_sta)
 {
-       IWL_DEBUG_HT("we are staying in the same table\n");
+       IWL_DEBUG_RATE("we are staying in the same table\n");
        lq_sta->stay_in_tbl = 1;        /* only place this gets set */
        if (is_legacy) {
                lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT;
@@ -1036,7 +1017,7 @@ static void rs_set_stay_in_table(u8 is_legacy,
 /*
  * Find correct throughput table for given mode of modulation
  */
-static void rs_get_expected_tpt_table(struct iwl4965_lq_sta *lq_sta,
+static void rs_set_expected_tpt_table(struct iwl4965_lq_sta *lq_sta,
                                      struct iwl4965_scale_tbl_info *tbl)
 {
        if (is_legacy(tbl->lq_type)) {
@@ -1055,7 +1036,7 @@ static void rs_get_expected_tpt_table(struct iwl4965_lq_sta *lq_sta,
                else
                        tbl->expected_tpt = expected_tpt_siso20MHz;
 
-       } else if (is_mimo(tbl->lq_type)) {
+       } else if (is_mimo(tbl->lq_type)) { /* FIXME:need to separate mimo2/3 */
                if (tbl->is_fat && !lq_sta->is_dup)
                        if (tbl->is_SGI)
                                tbl->expected_tpt = expected_tpt_mimo40MHzSGI;
@@ -1085,7 +1066,7 @@ static void rs_get_expected_tpt_table(struct iwl4965_lq_sta *lq_sta,
 static s32 rs_get_best_rate(struct iwl_priv *priv,
                            struct iwl4965_lq_sta *lq_sta,
                            struct iwl4965_scale_tbl_info *tbl, /* "search" */
-                           u16 rate_mask, s8 index, s8 rate)
+                           u16 rate_mask, s8 index)
 {
        /* "active" values */
        struct iwl4965_scale_tbl_info *active_tbl =
@@ -1098,11 +1079,13 @@ static s32 rs_get_best_rate(struct iwl_priv *priv,
 
        s32 new_rate, high, low, start_hi;
        u16 high_low;
+       s8 rate = index;
 
        new_rate = high = low = start_hi = IWL_RATE_INVALID;
 
        for (; ;) {
-               high_low = rs_get_adjacent_rate(rate, rate_mask, tbl->lq_type);
+               high_low = rs_get_adjacent_rate(priv, rate, rate_mask,
+                                               tbl->lq_type);
 
                low = high_low & 0xff;
                high = (high_low >> 8) & 0xff;
@@ -1171,21 +1154,16 @@ static s32 rs_get_best_rate(struct iwl_priv *priv,
 }
 #endif                         /* CONFIG_IWL4965_HT */
 
-static inline u8 rs_is_both_ant_supp(u8 valid_antenna)
-{
-       return (rs_is_ant_connected(valid_antenna, ANT_BOTH));
-}
-
 /*
  * Set up search table for MIMO
  */
-static int rs_switch_to_mimo(struct iwl_priv *priv,
+#ifdef CONFIG_IWL4965_HT
+static int rs_switch_to_mimo2(struct iwl_priv *priv,
                             struct iwl4965_lq_sta *lq_sta,
                             struct ieee80211_conf *conf,
                             struct sta_info *sta,
                             struct iwl4965_scale_tbl_info *tbl, int index)
 {
-#ifdef CONFIG_IWL4965_HT
        u16 rate_mask;
        s32 rate;
        s8 is_green = lq_sta->is_green;
@@ -1194,26 +1172,27 @@ static int rs_switch_to_mimo(struct iwl_priv *priv,
            !sta->ht_info.ht_supported)
                return -1;
 
-       IWL_DEBUG_HT("LQ: try to switch to MIMO\n");
-       tbl->lq_type = LQ_MIMO;
-       rs_get_supported_rates(lq_sta, NULL, tbl->lq_type,
-                               &rate_mask);
-
        if (priv->current_ht_config.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC)
                return -1;
 
        /* Need both Tx chains/antennas to support MIMO */
-       if (!rs_is_both_ant_supp(lq_sta->antenna))
+       if (priv->hw_params.tx_chains_num < 2)
                return -1;
 
+       IWL_DEBUG_RATE("LQ: try to switch to MIMO2\n");
+
+       tbl->lq_type = LQ_MIMO2;
        tbl->is_dup = lq_sta->is_dup;
        tbl->action = 0;
+       rate_mask = lq_sta->active_mimo2_rate;
+
        if (priv->current_ht_config.supported_chan_width
-           == IWL_CHANNEL_WIDTH_40MHZ)
+                                       == IWL_CHANNEL_WIDTH_40MHZ)
                tbl->is_fat = 1;
        else
                tbl->is_fat = 0;
 
+       /* FIXME: - don't toggle SGI here
        if (tbl->is_fat) {
                if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY)
                        tbl->is_SGI = 1;
@@ -1223,23 +1202,35 @@ static int rs_switch_to_mimo(struct iwl_priv *priv,
                tbl->is_SGI = 1;
        else
                tbl->is_SGI = 0;
+       */
 
-       rs_get_expected_tpt_table(lq_sta, tbl);
+       rs_set_expected_tpt_table(lq_sta, tbl);
 
-       rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index, index);
+       rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index);
 
-       IWL_DEBUG_HT("LQ: MIMO best rate %d mask %X\n", rate, rate_mask);
-       if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask))
+       IWL_DEBUG_RATE("LQ: MIMO2 best rate %d mask %X\n", rate, rate_mask);
+
+       if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
+               IWL_DEBUG_RATE("Can't switch with index %d rate mask %x\n",
+                                               rate, rate_mask);
                return -1;
-       rs_mcs_from_tbl(&tbl->current_rate, tbl, rate, is_green);
+       }
+       tbl->current_rate = rate_n_flags_from_tbl(tbl, rate, is_green);
 
-       IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n",
-                    tbl->current_rate.rate_n_flags, is_green);
+       IWL_DEBUG_RATE("LQ: Switch to new mcs %X index is green %X\n",
+                    tbl->current_rate, is_green);
        return 0;
+}
 #else
+static int rs_switch_to_mimo2(struct iwl_priv *priv,
+                            struct iwl4965_lq_sta *lq_sta,
+                            struct ieee80211_conf *conf,
+                            struct sta_info *sta,
+                            struct iwl4965_scale_tbl_info *tbl, int index)
+{
        return -1;
-#endif /*CONFIG_IWL4965_HT */
 }
+#endif /*CONFIG_IWL4965_HT */
 
 /*
  * Set up search table for SISO
@@ -1255,16 +1246,16 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
        u8 is_green = lq_sta->is_green;
        s32 rate;
 
-       IWL_DEBUG_HT("LQ: try to switch to SISO\n");
        if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) ||
            !sta->ht_info.ht_supported)
                return -1;
 
+       IWL_DEBUG_RATE("LQ: try to switch to SISO\n");
+
        tbl->is_dup = lq_sta->is_dup;
        tbl->lq_type = LQ_SISO;
        tbl->action = 0;
-       rs_get_supported_rates(lq_sta, NULL, tbl->lq_type,
-                               &rate_mask);
+       rate_mask = lq_sta->active_siso_rate;
 
        if (priv->current_ht_config.supported_chan_width
            == IWL_CHANNEL_WIDTH_40MHZ)
@@ -1272,6 +1263,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
        else
                tbl->is_fat = 0;
 
+       /* FIXME: - don't toggle SGI here
        if (tbl->is_fat) {
                if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY)
                        tbl->is_SGI = 1;
@@ -1281,26 +1273,26 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
                tbl->is_SGI = 1;
        else
                tbl->is_SGI = 0;
+       */
 
        if (is_green)
-               tbl->is_SGI = 0;
+               tbl->is_SGI = 0; /*11n spec: no SGI in SISO+Greenfield*/
 
-       rs_get_expected_tpt_table(lq_sta, tbl);
-       rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index, index);
+       rs_set_expected_tpt_table(lq_sta, tbl);
+       rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index);
 
-       IWL_DEBUG_HT("LQ: get best rate %d mask %X\n", rate, rate_mask);
+       IWL_DEBUG_RATE("LQ: get best rate %d mask %X\n", rate, rate_mask);
        if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
-               IWL_DEBUG_HT("can not switch with index %d rate mask %x\n",
+               IWL_DEBUG_RATE("can not switch with index %d rate mask %x\n",
                             rate, rate_mask);
                return -1;
        }
-       rs_mcs_from_tbl(&tbl->current_rate, tbl, rate, is_green);
-       IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n",
-                    tbl->current_rate.rate_n_flags, is_green);
+       tbl->current_rate = rate_n_flags_from_tbl(tbl, rate, is_green);
+       IWL_DEBUG_RATE("LQ: Switch to new mcs %X index is green %X\n",
+                    tbl->current_rate, is_green);
        return 0;
 #else
        return -1;
-
 #endif /*CONFIG_IWL4965_HT */
 }
 
@@ -1313,7 +1305,6 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
                                struct sta_info *sta,
                                int index)
 {
-       int ret = 0;
        struct iwl4965_scale_tbl_info *tbl =
            &(lq_sta->lq_info[lq_sta->active_tbl]);
        struct iwl4965_scale_tbl_info *search_tbl =
@@ -1322,41 +1313,35 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
        u32 sz = (sizeof(struct iwl4965_scale_tbl_info) -
                  (sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT));
        u8 start_action = tbl->action;
+       u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
+       int ret = 0;
 
        for (; ;) {
                switch (tbl->action) {
                case IWL_LEGACY_SWITCH_ANTENNA:
-                       IWL_DEBUG_HT("LQ Legacy switch Antenna\n");
+                       IWL_DEBUG_RATE("LQ: Legacy toggle Antenna\n");
 
-                       search_tbl->lq_type = LQ_NONE;
                        lq_sta->action_counter++;
 
                        /* Don't change antenna if success has been great */
                        if (window->success_ratio >= IWL_RS_GOOD_RATIO)
                                break;
 
-                       /* Don't change antenna if other one is not connected */
-                       if (!rs_is_other_ant_connected(lq_sta->antenna,
-                                                       tbl->antenna_type))
-                               break;
-
                        /* Set up search table to try other antenna */
                        memcpy(search_tbl, tbl, sz);
 
-                       rs_toggle_antenna(&(search_tbl->current_rate),
-                                          search_tbl);
-                       rs_get_expected_tpt_table(lq_sta, search_tbl);
-                       lq_sta->search_better_tbl = 1;
-                       goto out;
-
+                       if (rs_toggle_antenna(valid_tx_ant,
+                               &search_tbl->current_rate, search_tbl)) {
+                               lq_sta->search_better_tbl = 1;
+                               goto out;
+                       }
+                       break;
                case IWL_LEGACY_SWITCH_SISO:
-                       IWL_DEBUG_HT("LQ: Legacy switch to SISO\n");
+                       IWL_DEBUG_RATE("LQ: Legacy switch to SISO\n");
 
                        /* Set up search table to try SISO */
                        memcpy(search_tbl, tbl, sz);
-                       search_tbl->lq_type = LQ_SISO;
                        search_tbl->is_SGI = 0;
-                       search_tbl->is_fat = 0;
                        ret = rs_switch_to_siso(priv, lq_sta, conf, sta,
                                                 search_tbl, index);
                        if (!ret) {
@@ -1366,16 +1351,15 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
                        }
 
                        break;
-               case IWL_LEGACY_SWITCH_MIMO:
-                       IWL_DEBUG_HT("LQ: Legacy switch MIMO\n");
+               case IWL_LEGACY_SWITCH_MIMO2:
+                       IWL_DEBUG_RATE("LQ: Legacy switch to MIMO2\n");
 
                        /* Set up search table to try MIMO */
                        memcpy(search_tbl, tbl, sz);
-                       search_tbl->lq_type = LQ_MIMO;
                        search_tbl->is_SGI = 0;
-                       search_tbl->is_fat = 0;
-                       search_tbl->antenna_type = ANT_BOTH;
-                       ret = rs_switch_to_mimo(priv, lq_sta, conf, sta,
+                       search_tbl->ant_type = ANT_AB;/*FIXME:RS*/
+                               /*FIXME:RS:need to check ant validity*/
+                       ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta,
                                                 search_tbl, index);
                        if (!ret) {
                                lq_sta->search_better_tbl = 1;
@@ -1385,7 +1369,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
                        break;
                }
                tbl->action++;
-               if (tbl->action > IWL_LEGACY_SWITCH_MIMO)
+               if (tbl->action > IWL_LEGACY_SWITCH_MIMO2)
                        tbl->action = IWL_LEGACY_SWITCH_ANTENNA;
 
                if (tbl->action == start_action)
@@ -1396,7 +1380,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
 
  out:
        tbl->action++;
-       if (tbl->action > IWL_LEGACY_SWITCH_MIMO)
+       if (tbl->action > IWL_LEGACY_SWITCH_MIMO2)
                tbl->action = IWL_LEGACY_SWITCH_ANTENNA;
        return 0;
 
@@ -1411,7 +1395,6 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
                                 struct sta_info *sta,
                                 int index)
 {
-       int ret;
        u8 is_green = lq_sta->is_green;
        struct iwl4965_scale_tbl_info *tbl =
            &(lq_sta->lq_info[lq_sta->active_tbl]);
@@ -1421,35 +1404,30 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
        u32 sz = (sizeof(struct iwl4965_scale_tbl_info) -
                  (sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT));
        u8 start_action = tbl->action;
+       u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
+       int ret;
 
        for (;;) {
                lq_sta->action_counter++;
                switch (tbl->action) {
                case IWL_SISO_SWITCH_ANTENNA:
-                       IWL_DEBUG_HT("LQ: SISO SWITCH ANTENNA SISO\n");
-                       search_tbl->lq_type = LQ_NONE;
+                       IWL_DEBUG_RATE("LQ: SISO toggle Antenna\n");
                        if (window->success_ratio >= IWL_RS_GOOD_RATIO)
                                break;
-                       if (!rs_is_other_ant_connected(lq_sta->antenna,
-                                                      tbl->antenna_type))
-                               break;
 
                        memcpy(search_tbl, tbl, sz);
-                       search_tbl->action = IWL_SISO_SWITCH_MIMO;
-                       rs_toggle_antenna(&(search_tbl->current_rate),
-                                          search_tbl);
-                       lq_sta->search_better_tbl = 1;
-
-                       goto out;
-
-               case IWL_SISO_SWITCH_MIMO:
-                       IWL_DEBUG_HT("LQ: SISO SWITCH TO MIMO FROM SISO\n");
+                       if (rs_toggle_antenna(valid_tx_ant,
+                                      &search_tbl->current_rate, search_tbl)) {
+                               lq_sta->search_better_tbl = 1;
+                               goto out;
+                       }
+                       break;
+               case IWL_SISO_SWITCH_MIMO2:
+                       IWL_DEBUG_RATE("LQ: SISO switch to MIMO2\n");
                        memcpy(search_tbl, tbl, sz);
-                       search_tbl->lq_type = LQ_MIMO;
                        search_tbl->is_SGI = 0;
-                       search_tbl->is_fat = 0;
-                       search_tbl->antenna_type = ANT_BOTH;
-                       ret = rs_switch_to_mimo(priv, lq_sta, conf, sta,
+                       search_tbl->ant_type = ANT_AB; /*FIXME:RS*/
+                       ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta,
                                                 search_tbl, index);
                        if (!ret) {
                                lq_sta->search_better_tbl = 1;
@@ -1457,29 +1435,34 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
                        }
                        break;
                case IWL_SISO_SWITCH_GI:
-                       IWL_DEBUG_HT("LQ: SISO SWITCH TO GI\n");
+                       if (!tbl->is_fat &&
+                               !(priv->current_ht_config.sgf &
+                                               HT_SHORT_GI_20MHZ))
+                               break;
+                       if (tbl->is_fat &&
+                               !(priv->current_ht_config.sgf &
+                                               HT_SHORT_GI_40MHZ))
+                               break;
+
+                       IWL_DEBUG_RATE("LQ: SISO toggle SGI/NGI\n");
 
                        memcpy(search_tbl, tbl, sz);
-                       search_tbl->action = 0;
-                       if (search_tbl->is_SGI)
-                               search_tbl->is_SGI = 0;
-                       else if (!is_green)
-                               search_tbl->is_SGI = 1;
-                       else
-                               break;
-                       lq_sta->search_better_tbl = 1;
-                       if ((tbl->lq_type == LQ_SISO) &&
-                           (tbl->is_SGI)) {
+                       if (is_green) {
+                               if (!tbl->is_SGI)
+                                       break;
+                               else
+                                       IWL_ERROR("SGI was set in GF+SISO\n");
+                       }
+                       search_tbl->is_SGI = !tbl->is_SGI;
+                       rs_set_expected_tpt_table(lq_sta, search_tbl);
+                       if (tbl->is_SGI) {
                                s32 tpt = lq_sta->last_tpt / 100;
-                               if (((!tbl->is_fat) &&
-                                    (tpt >= expected_tpt_siso20MHz[index])) ||
-                                   ((tbl->is_fat) &&
-                                    (tpt >= expected_tpt_siso40MHz[index])))
-                                       lq_sta->search_better_tbl = 0;
+                               if (tpt >= search_tbl->expected_tpt[index])
+                                       break;
                        }
-                       rs_get_expected_tpt_table(lq_sta, search_tbl);
-                       rs_mcs_from_tbl(&search_tbl->current_rate,
-                                            search_tbl, index, is_green);
+                       search_tbl->current_rate = rate_n_flags_from_tbl(
+                                               search_tbl, index, is_green);
+                       lq_sta->search_better_tbl = 1;
                        goto out;
                }
                tbl->action++;
@@ -1507,7 +1490,6 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv,
                                 struct sta_info *sta,
                                 int index)
 {
-       int ret;
        s8 is_green = lq_sta->is_green;
        struct iwl4965_scale_tbl_info *tbl =
            &(lq_sta->lq_info[lq_sta->active_tbl]);
@@ -1516,24 +1498,24 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv,
        u32 sz = (sizeof(struct iwl4965_scale_tbl_info) -
                  (sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT));
        u8 start_action = tbl->action;
+       /*u8 valid_tx_ant = priv->hw_params.valid_tx_ant;*/
+       int ret;
 
        for (;;) {
                lq_sta->action_counter++;
                switch (tbl->action) {
                case IWL_MIMO_SWITCH_ANTENNA_A:
                case IWL_MIMO_SWITCH_ANTENNA_B:
-                       IWL_DEBUG_HT("LQ: MIMO SWITCH TO SISO\n");
-
+                       IWL_DEBUG_RATE("LQ: MIMO2 switch to SISO\n");
 
                        /* Set up new search table for SISO */
                        memcpy(search_tbl, tbl, sz);
-                       search_tbl->lq_type = LQ_SISO;
-                       search_tbl->is_SGI = 0;
-                       search_tbl->is_fat = 0;
+
+                       /*FIXME:RS:need to check ant validity + C*/
                        if (tbl->action == IWL_MIMO_SWITCH_ANTENNA_A)
-                               search_tbl->antenna_type = ANT_MAIN;
+                               search_tbl->ant_type = ANT_A;
                        else
-                               search_tbl->antenna_type = ANT_AUX;
+                               search_tbl->ant_type = ANT_B;
 
                        ret = rs_switch_to_siso(priv, lq_sta, conf, sta,
                                                 search_tbl, index);
@@ -1544,37 +1526,35 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv,
                        break;
 
                case IWL_MIMO_SWITCH_GI:
-                       IWL_DEBUG_HT("LQ: MIMO SWITCH TO GI\n");
+                       if (!tbl->is_fat &&
+                               !(priv->current_ht_config.sgf &
+                                               HT_SHORT_GI_20MHZ))
+                               break;
+                       if (tbl->is_fat &&
+                               !(priv->current_ht_config.sgf &
+                                               HT_SHORT_GI_40MHZ))
+                               break;
+
+                       IWL_DEBUG_RATE("LQ: MIMO toggle SGI/NGI\n");
 
                        /* Set up new search table for MIMO */
                        memcpy(search_tbl, tbl, sz);
-                       search_tbl->lq_type = LQ_MIMO;
-                       search_tbl->antenna_type = ANT_BOTH;
-                       search_tbl->action = 0;
-                       if (search_tbl->is_SGI)
-                               search_tbl->is_SGI = 0;
-                       else
-                               search_tbl->is_SGI = 1;
-                       lq_sta->search_better_tbl = 1;
-
+                       search_tbl->is_SGI = !tbl->is_SGI;
+                       rs_set_expected_tpt_table(lq_sta, search_tbl);
                        /*
                         * If active table already uses the fastest possible
                         * modulation (dual stream with short guard interval),
                         * and it's working well, there's no need to look
                         * for a better type of modulation!
                         */
-                       if ((tbl->lq_type == LQ_MIMO) &&
-                           (tbl->is_SGI)) {
+                       if (tbl->is_SGI) {
                                s32 tpt = lq_sta->last_tpt / 100;
-                               if (((!tbl->is_fat) &&
-                                    (tpt >= expected_tpt_mimo20MHz[index])) ||
-                                   ((tbl->is_fat) &&
-                                    (tpt >= expected_tpt_mimo40MHz[index])))
-                                       lq_sta->search_better_tbl = 0;
+                               if (tpt >= search_tbl->expected_tpt[index])
+                                       break;
                        }
-                       rs_get_expected_tpt_table(lq_sta, search_tbl);
-                       rs_mcs_from_tbl(&search_tbl->current_rate,
-                                            search_tbl, index, is_green);
+                       search_tbl->current_rate = rate_n_flags_from_tbl(
+                                               search_tbl, index, is_green);
+                       lq_sta->search_better_tbl = 1;
                        goto out;
 
                }
@@ -1608,7 +1588,9 @@ static void rs_stay_in_table(struct iwl4965_lq_sta *lq_sta)
        int i;
        int active_tbl;
        int flush_interval_passed = 0;
+       struct iwl_priv *priv;
 
+       priv = lq_sta->drv;
        active_tbl = lq_sta->active_tbl;
 
        tbl = &(lq_sta->lq_info[active_tbl]);
@@ -1623,9 +1605,6 @@ static void rs_stay_in_table(struct iwl4965_lq_sta *lq_sta)
                                       (unsigned long)(lq_sta->flush_timer +
                                        IWL_RATE_SCALE_FLUSH_INTVL));
 
-               /* For now, disable the elapsed time criterion */
-               flush_interval_passed = 0;
-
                /*
                 * Check if we should allow search for new modulation mode.
                 * If many frames have failed or succeeded, or we've used
@@ -1638,7 +1617,7 @@ static void rs_stay_in_table(struct iwl4965_lq_sta *lq_sta)
                    (lq_sta->total_success > lq_sta->max_success_limit) ||
                    ((!lq_sta->search_better_tbl) && (lq_sta->flush_timer)
                     && (flush_interval_passed))) {
-                       IWL_DEBUG_HT("LQ: stay is expired %d %d %d\n:",
+                       IWL_DEBUG_RATE("LQ: stay is expired %d %d %d\n:",
                                     lq_sta->total_failed,
                                     lq_sta->total_success,
                                     flush_interval_passed);
@@ -1661,7 +1640,7 @@ static void rs_stay_in_table(struct iwl4965_lq_sta *lq_sta)
                            lq_sta->table_count_limit) {
                                lq_sta->table_count = 0;
 
-                               IWL_DEBUG_HT("LQ: stay in table clear win\n");
+                               IWL_DEBUG_RATE("LQ: stay in table clear win\n");
                                for (i = 0; i < IWL_RATE_COUNT; i++)
                                        rs_rate_scale_clear_window(
                                                &(tbl->win[i]));
@@ -1704,14 +1683,14 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
        struct iwl4965_lq_sta *lq_sta;
        struct iwl4965_scale_tbl_info *tbl, *tbl1;
        u16 rate_scale_index_msk = 0;
-       struct iwl4965_rate mcs_rate;
+       u32 rate;
        u8 is_green = 0;
        u8 active_tbl = 0;
        u8 done_search = 0;
        u16 high_low;
+       s32 sr;
 #ifdef CONFIG_IWL4965_HT
        u8 tid = MAX_TID_COUNT;
-       __le16 *qc;
 #endif
 
        IWL_DEBUG_RATE("rate scale calculate new rate for skb\n");
@@ -1734,11 +1713,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
        lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv;
 
 #ifdef CONFIG_IWL4965_HT
-       qc = ieee80211_get_qos_ctrl(hdr);
-       if (qc) {
-               tid = (u8)(le16_to_cpu(*qc) & 0xf);
-               rs_tl_add_packet(lq_sta, tid);
-       }
+       rs_tl_add_packet(lq_sta, hdr);
 #endif
        /*
         * Select rate-scale / modulation-mode table to work with in
@@ -1760,8 +1735,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
                       tbl->lq_type);
 
        /* rates available for this association, and for modulation mode */
-       rs_get_supported_rates(lq_sta, hdr, tbl->lq_type,
-                               &rate_mask);
+       rate_mask = rs_get_supported_rates(lq_sta, hdr, tbl->lq_type);
 
        IWL_DEBUG_RATE("mask 0x%04X \n", rate_mask);
 
@@ -1781,27 +1755,16 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
        if (!rate_scale_index_msk)
                rate_scale_index_msk = rate_mask;
 
-       /* If current rate is no longer supported on current association,
-        * or user changed preferences for rates, find a new supported rate. */
-       if (index < 0 || !((1 << index) & rate_scale_index_msk)) {
-               index = IWL_INVALID_VALUE;
-               update_lq = 1;
-
-               /* get the highest available rate */
-               for (i = 0; i <= IWL_RATE_COUNT; i++) {
-                       if ((1 << i) & rate_scale_index_msk)
-                               index = i;
-               }
-
-               if (index == IWL_INVALID_VALUE) {
-                       IWL_WARNING("Can not find a suitable rate\n");
-                       return;
-               }
+       if (!((1 << index) & rate_scale_index_msk)) {
+               IWL_ERROR("Current Rate is not valid\n");
+               return;
        }
 
        /* Get expected throughput table and history window for current rate */
-       if (!tbl->expected_tpt)
-               rs_get_expected_tpt_table(lq_sta, tbl);
+       if (!tbl->expected_tpt) {
+               IWL_ERROR("tbl->expected_tpt is NULL\n");
+               return;
+       }
 
        window = &(tbl->win[index]);
 
@@ -1813,10 +1776,9 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
         * in current association (use new rate found above).
         */
        fail_count = window->counter - window->success_counter;
-       if (((fail_count < IWL_RATE_MIN_FAILURE_TH) &&
-            (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))
-           || (tbl->expected_tpt == NULL)) {
-               IWL_DEBUG_RATE("LQ: still below TH succ %d total %d "
+       if ((fail_count < IWL_RATE_MIN_FAILURE_TH) &&
+                       (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) {
+               IWL_DEBUG_RATE("LQ: still below TH. succ=%d total=%d "
                               "for index %d\n",
                               window->success_counter, window->counter, index);
 
@@ -1827,44 +1789,51 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
                 * or search for a new one? */
                rs_stay_in_table(lq_sta);
 
-               /* Set up new rate table in uCode, if needed */
-               if (update_lq) {
-                       rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green);
-                       rs_fill_link_cmd(lq_sta, &mcs_rate, &lq_sta->lq);
-                       iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
-               }
                goto out;
 
        /* Else we have enough samples; calculate estimate of
         * actual average throughput */
-       } else
-               window->average_tpt = ((window->success_ratio *
+       } else {
+               /*FIXME:RS remove this else if we don't get this error*/
+               if (window->average_tpt != ((window->success_ratio *
+                               tbl->expected_tpt[index] + 64) / 128)) {
+                       IWL_ERROR("expected_tpt should have been calculated"
+                                                               " by now\n");
+                       window->average_tpt = ((window->success_ratio *
                                        tbl->expected_tpt[index] + 64) / 128);
+               }
+       }
 
        /* If we are searching for better modulation mode, check success. */
        if (lq_sta->search_better_tbl) {
-               int success_limit = IWL_RATE_SCALE_SWITCH;
 
                /* If good success, continue using the "search" mode;
                 * no need to send new link quality command, since we're
                 * continuing to use the setup that we've been trying. */
-               if ((window->success_ratio > success_limit) ||
-                   (window->average_tpt > lq_sta->last_tpt)) {
-                       if (!is_legacy(tbl->lq_type)) {
-                               IWL_DEBUG_HT("LQ: we are switching to HT"
-                                            " rate suc %d current tpt %d"
-                                            " old tpt %d\n",
-                                            window->success_ratio,
-                                            window->average_tpt,
-                                            lq_sta->last_tpt);
+               if (window->average_tpt > lq_sta->last_tpt) {
+
+                       IWL_DEBUG_RATE("LQ: SWITCHING TO CURRENT TABLE "
+                                       "suc=%d cur-tpt=%d old-tpt=%d\n",
+                                       window->success_ratio,
+                                       window->average_tpt,
+                                       lq_sta->last_tpt);
+
+                       if (!is_legacy(tbl->lq_type))
                                lq_sta->enable_counter = 1;
-                       }
+
                        /* Swap tables; "search" becomes "active" */
                        lq_sta->active_tbl = active_tbl;
                        current_tpt = window->average_tpt;
 
                /* Else poor success; go back to mode in "active" table */
                } else {
+
+                       IWL_DEBUG_RATE("LQ: GOING BACK TO THE OLD TABLE "
+                                       "suc=%d cur-tpt=%d old-tpt=%d\n",
+                                       window->success_ratio,
+                                       window->average_tpt,
+                                       lq_sta->last_tpt);
+
                        /* Nullify "search" table */
                        tbl->lq_type = LQ_NONE;
 
@@ -1874,12 +1843,11 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 
                        /* Revert to "active" rate and throughput info */
                        index = iwl4965_hwrate_to_plcp_idx(
-                               tbl->current_rate.rate_n_flags);
+                                                       tbl->current_rate);
                        current_tpt = lq_sta->last_tpt;
 
                        /* Need to set up a new rate table in uCode */
                        update_lq = 1;
-                       IWL_DEBUG_HT("XXY GO BACK TO OLD TABLE\n");
                }
 
                /* Either way, we've made a decision; modulation mode
@@ -1891,11 +1859,13 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 
        /* (Else) not in search of better modulation mode, try for better
         * starting rate, while staying in this mode. */
-       high_low = rs_get_adjacent_rate(index, rate_scale_index_msk,
+       high_low = rs_get_adjacent_rate(priv, index, rate_scale_index_msk,
                                        tbl->lq_type);
        low = high_low & 0xff;
        high = (high_low >> 8) & 0xff;
 
+       sr = window->success_ratio;
+
        /* Collect measured throughputs for current and adjacent rates */
        current_tpt = window->average_tpt;
        if (low != IWL_RATE_INVALID)
@@ -1903,19 +1873,22 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
        if (high != IWL_RATE_INVALID)
                high_tpt = tbl->win[high].average_tpt;
 
-       /* Assume rate increase */
-       scale_action = 1;
+       scale_action = 0;
 
        /* Too many failures, decrease rate */
-       if ((window->success_ratio <= IWL_RATE_DECREASE_TH) ||
-           (current_tpt == 0)) {
+       if ((sr <= IWL_RATE_DECREASE_TH) || (current_tpt == 0)) {
                IWL_DEBUG_RATE("decrease rate because of low success_ratio\n");
                scale_action = -1;
 
        /* No throughput measured yet for adjacent rates; try increase. */
        } else if ((low_tpt == IWL_INVALID_VALUE) &&
-                  (high_tpt == IWL_INVALID_VALUE))
-               scale_action = 1;
+                  (high_tpt == IWL_INVALID_VALUE)) {
+
+               if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH)
+                       scale_action = 1;
+               else if (low != IWL_RATE_INVALID)
+                       scale_action = -1;
+       }
 
        /* Both adjacent throughputs are measured, but neither one has better
         * throughput; we're using the best rate, don't change it! */
@@ -1931,9 +1904,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
                /* Higher adjacent rate's throughput is measured */
                if (high_tpt != IWL_INVALID_VALUE) {
                        /* Higher rate has better throughput */
-                       if (high_tpt > current_tpt)
+                       if (high_tpt > current_tpt &&
+                                       sr >= IWL_RATE_INCREASE_TH) {
                                scale_action = 1;
-                       else {
+                       else {
                                IWL_DEBUG_RATE
                                    ("decrease rate because of high tpt\n");
                                scale_action = -1;
@@ -1946,23 +1920,17 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
                                IWL_DEBUG_RATE
                                    ("decrease rate because of low tpt\n");
                                scale_action = -1;
-                       } else
+                       } else if (sr >= IWL_RATE_INCREASE_TH) {
                                scale_action = 1;
+                       }
                }
        }
 
        /* Sanity check; asked for decrease, but success rate or throughput
         * has been good at old rate.  Don't change it. */
-       if (scale_action == -1) {
-               if ((low != IWL_RATE_INVALID) &&
-                   ((window->success_ratio > IWL_RATE_HIGH_TH) ||
+       if ((scale_action == -1) && (low != IWL_RATE_INVALID) &&
+                   ((sr > IWL_RATE_HIGH_TH) ||
                     (current_tpt > (100 * tbl->expected_tpt[low]))))
-                       scale_action = 0;
-
-       /* Sanity check; asked for increase, but success rate has not been great
-        * even at old rate, higher rate will be worse.  Don't change it. */
-       } else if ((scale_action == 1) &&
-                  (window->success_ratio < IWL_RATE_INCREASE_TH))
                scale_action = 0;
 
        switch (scale_action) {
@@ -1987,15 +1955,15 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
                break;
        }
 
-       IWL_DEBUG_HT("choose rate scale index %d action %d low %d "
+       IWL_DEBUG_RATE("choose rate scale index %d action %d low %d "
                    "high %d type %d\n",
                     index, scale_action, low, high, tbl->lq_type);
 
- lq_update:
+lq_update:
        /* Replace uCode's rate table for the destination station. */
        if (update_lq) {
-               rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green);
-               rs_fill_link_cmd(lq_sta, &mcs_rate, &lq_sta->lq);
+               rate = rate_n_flags_from_tbl(tbl, index, is_green);
+               rs_fill_link_cmd(priv, lq_sta, rate);
                iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
        }
 
@@ -2030,12 +1998,11 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 
                        /* Use new "search" start rate */
                        index = iwl4965_hwrate_to_plcp_idx(
-                                       tbl->current_rate.rate_n_flags);
+                                                       tbl->current_rate);
 
-                       IWL_DEBUG_HT("Switch current  mcs: %X index: %d\n",
-                                    tbl->current_rate.rate_n_flags, index);
-                       rs_fill_link_cmd(lq_sta, &tbl->current_rate,
-                                        &lq_sta->lq);
+                       IWL_DEBUG_RATE("Switch current  mcs: %X index: %d\n",
+                                    tbl->current_rate, index);
+                       rs_fill_link_cmd(priv, lq_sta, tbl->current_rate);
                        iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
                }
 
@@ -2051,8 +2018,8 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 #endif
                    (lq_sta->action_counter >= 1)) {
                        lq_sta->action_counter = 0;
-                       IWL_DEBUG_HT("LQ: STAY in legacy table\n");
-                       rs_set_stay_in_table(1, lq_sta);
+                       IWL_DEBUG_RATE("LQ: STAY in legacy table\n");
+                       rs_set_stay_in_table(priv, 1, lq_sta);
                }
 
                /* If we're in an HT mode, and all 3 mode switch actions
@@ -2064,12 +2031,12 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
                        if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) &&
                            (lq_sta->tx_agg_tid_en & (1 << tid)) &&
                            (tid != MAX_TID_COUNT)) {
-                               IWL_DEBUG_HT("try to aggregate tid %d\n", tid);
+                               IWL_DEBUG_RATE("try to aggregate tid %d\n", tid);
                                rs_tl_turn_on_agg(priv, tid, lq_sta, sta);
                        }
 #endif /*CONFIG_IWL4965_HT */
                        lq_sta->action_counter = 0;
-                       rs_set_stay_in_table(0, lq_sta);
+                       rs_set_stay_in_table(priv, 0, lq_sta);
                }
 
        /*
@@ -2085,7 +2052,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
        }
 
 out:
-       rs_mcs_from_tbl(&tbl->current_rate, tbl, index, is_green);
+       tbl->current_rate = rate_n_flags_from_tbl(tbl, index, is_green);
        i = index;
        sta->last_txrate_idx = i;
 
@@ -2105,13 +2072,14 @@ static void rs_initialize_lq(struct iwl_priv *priv,
                             struct ieee80211_conf *conf,
                             struct sta_info *sta)
 {
-       int i;
        struct iwl4965_lq_sta *lq_sta;
        struct iwl4965_scale_tbl_info *tbl;
-       u8 active_tbl = 0;
        int rate_idx;
+       int i;
+       u32 rate;
        u8 use_green = rs_use_green(priv, conf);
-       struct iwl4965_rate mcs_rate;
+       u8 active_tbl = 0;
+       u8 valid_tx_ant;
 
        if (!sta || !sta->rate_ctrl_priv)
                goto out;
@@ -2123,6 +2091,8 @@ static void rs_initialize_lq(struct iwl_priv *priv,
            (priv->iw_mode == IEEE80211_IF_TYPE_IBSS))
                goto out;
 
+       valid_tx_ant = priv->hw_params.valid_tx_ant;
+
        if (!lq_sta->search_better_tbl)
                active_tbl = lq_sta->active_tbl;
        else
@@ -2133,22 +2103,23 @@ static void rs_initialize_lq(struct iwl_priv *priv,
        if ((i < 0) || (i >= IWL_RATE_COUNT))
                i = 0;
 
-       mcs_rate.rate_n_flags = iwl4965_rates[i].plcp ;
-       mcs_rate.rate_n_flags |= RATE_MCS_ANT_B_MSK;
-       mcs_rate.rate_n_flags &= ~RATE_MCS_ANT_A_MSK;
+       /* FIXME:RS: This is also wrong in 4965 */
+       rate = iwl_rates[i].plcp;
+       rate |= RATE_MCS_ANT_B_MSK;
+       rate &= ~RATE_MCS_ANT_A_MSK;
 
        if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE)
-               mcs_rate.rate_n_flags |= RATE_MCS_CCK_MSK;
+               rate |= RATE_MCS_CCK_MSK;
 
-       tbl->antenna_type = ANT_AUX;
-       rs_get_tbl_info_from_mcs(&mcs_rate, priv->band, tbl, &rate_idx);
-       if (!rs_is_ant_connected(priv->valid_antenna, tbl->antenna_type))
-           rs_toggle_antenna(&mcs_rate, tbl);
+       tbl->ant_type = ANT_B;
+       rs_get_tbl_info_from_mcs(rate, priv->band, tbl, &rate_idx);
+       if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type))
+           rs_toggle_antenna(valid_tx_ant, &rate, tbl);
 
-       rs_mcs_from_tbl(&mcs_rate, tbl, rate_idx, use_green);
-       tbl->current_rate.rate_n_flags = mcs_rate.rate_n_flags;
-       rs_get_expected_tpt_table(lq_sta, tbl);
-       rs_fill_link_cmd(lq_sta, &mcs_rate, &lq_sta->lq);
+       rate = rate_n_flags_from_tbl(tbl, rate_idx, use_green);
+       tbl->current_rate = rate;
+       rs_set_expected_tpt_table(lq_sta, tbl);
+       rs_fill_link_cmd(NULL, lq_sta, rate);
        iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
  out:
        return;
@@ -2180,7 +2151,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
        fc = le16_to_cpu(hdr->frame_control);
        if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) ||
            !sta || !sta->rate_ctrl_priv) {
-               sel->rate = rate_lowest(local, sband, sta);
+               sel->rate_idx = rate_lowest_index(local, sband, sta);
                goto out;
        }
 
@@ -2189,13 +2160,13 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
 
        if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
            !lq_sta->ibss_sta_added) {
-               u8 sta_id = iwl4965_hw_find_station(priv, hdr->addr1);
+               u8 sta_id = iwl_find_station(priv, hdr->addr1);
                DECLARE_MAC_BUF(mac);
 
                if (sta_id == IWL_INVALID_STATION) {
                        IWL_DEBUG_RATE("LQ: ADD station %s\n",
                                       print_mac(mac, hdr->addr1));
-                       sta_id = iwl4965_add_station_flags(priv, hdr->addr1,
+                       sta_id = iwl_add_station_flags(priv, hdr->addr1,
                                                        0, CMD_ASYNC, NULL);
                }
                if ((sta_id != IWL_INVALID_STATION)) {
@@ -2210,20 +2181,24 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
 
 done:
        if ((i < 0) || (i > IWL_RATE_COUNT)) {
-               sel->rate = rate_lowest(local, sband, sta);
+               sel->rate_idx = rate_lowest_index(local, sband, sta);
                goto out;
        }
 
-       sel->rate = &priv->ieee_rates[i];
+       if (sband->band == IEEE80211_BAND_5GHZ)
+               i -= IWL_FIRST_OFDM_RATE;
+       sel->rate_idx = i;
 out:
        rcu_read_unlock();
 }
 
-static void *rs_alloc_sta(void *priv, gfp_t gfp)
+static void *rs_alloc_sta(void *priv_rate, gfp_t gfp)
 {
        struct iwl4965_lq_sta *lq_sta;
+       struct iwl_priv *priv;
        int i, j;
 
+       priv = (struct iwl_priv *)priv_rate;
        IWL_DEBUG_RATE("create station rate scale window\n");
 
        lq_sta = kzalloc(sizeof(struct iwl4965_lq_sta), gfp);
@@ -2259,7 +2234,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
                for (i = 0; i < IWL_RATE_COUNT; i++)
                        rs_rate_scale_clear_window(&(lq_sta->lq_info[j].win[i]));
 
-       IWL_DEBUG_RATE("rate scale global init\n");
+       IWL_DEBUG_RATE("LQ: *** rate scale global init ***\n");
        /* TODO: what is a good starting rate for STA? About middle? Maybe not
         * the lowest or the highest rate.. Could consider using RSSI from
         * previous packets? Need to have IEEE 802.1X auth succeed immediately
@@ -2267,17 +2242,17 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
 
        lq_sta->ibss_sta_added = 0;
        if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
-               u8 sta_id = iwl4965_hw_find_station(priv, sta->addr);
+               u8 sta_id = iwl_find_station(priv, sta->addr);
                DECLARE_MAC_BUF(mac);
 
                /* for IBSS the call are from tasklet */
-               IWL_DEBUG_HT("LQ: ADD station %s\n",
+               IWL_DEBUG_RATE("LQ: ADD station %s\n",
                             print_mac(mac, sta->addr));
 
                if (sta_id == IWL_INVALID_STATION) {
                        IWL_DEBUG_RATE("LQ: ADD station %s\n",
                                       print_mac(mac, sta->addr));
-                       sta_id = iwl4965_add_station_flags(priv, sta->addr,
+                       sta_id = iwl_add_station_flags(priv, sta->addr,
                                                        0, CMD_ASYNC, NULL);
                }
                if ((sta_id != IWL_INVALID_STATION)) {
@@ -2300,11 +2275,8 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
                sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
 
        lq_sta->is_dup = 0;
-       lq_sta->valid_antenna = priv->valid_antenna;
-       lq_sta->antenna = priv->antenna;
        lq_sta->is_green = rs_use_green(priv, conf);
-       lq_sta->active_rate = priv->active_rate;
-       lq_sta->active_rate &= ~(0x1000);
+       lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000);
        lq_sta->active_rate_basic = priv->active_rate_basic;
        lq_sta->band = priv->band;
 #ifdef CONFIG_IWL4965_HT
@@ -2312,23 +2284,37 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
         * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3),
         * supp_rates[] does not; shift to convert format, force 9 MBits off.
         */
-       lq_sta->active_siso_rate = (priv->current_ht_config.supp_mcs_set[0] << 1);
+       lq_sta->active_siso_rate =
+               priv->current_ht_config.supp_mcs_set[0] << 1;
        lq_sta->active_siso_rate |=
-                       (priv->current_ht_config.supp_mcs_set[0] & 0x1);
+               priv->current_ht_config.supp_mcs_set[0] & 0x1;
        lq_sta->active_siso_rate &= ~((u16)0x2);
-       lq_sta->active_siso_rate =
-                       lq_sta->active_siso_rate << IWL_FIRST_OFDM_RATE;
+       lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE;
 
        /* Same here */
-       lq_sta->active_mimo_rate = (priv->current_ht_config.supp_mcs_set[1] << 1);
-       lq_sta->active_mimo_rate |=
-                       (priv->current_ht_config.supp_mcs_set[1] & 0x1);
-       lq_sta->active_mimo_rate &= ~((u16)0x2);
-       lq_sta->active_mimo_rate =
-                       lq_sta->active_mimo_rate << IWL_FIRST_OFDM_RATE;
-       IWL_DEBUG_HT("SISO RATE 0x%X MIMO RATE 0x%X\n",
+       lq_sta->active_mimo2_rate =
+               priv->current_ht_config.supp_mcs_set[1] << 1;
+       lq_sta->active_mimo2_rate |=
+               priv->current_ht_config.supp_mcs_set[1] & 0x1;
+       lq_sta->active_mimo2_rate &= ~((u16)0x2);
+       lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;
+
+       lq_sta->active_mimo3_rate =
+               priv->current_ht_config.supp_mcs_set[2] << 1;
+       lq_sta->active_mimo3_rate |=
+               priv->current_ht_config.supp_mcs_set[2] & 0x1;
+       lq_sta->active_mimo3_rate &= ~((u16)0x2);
+       lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE;
+
+       IWL_DEBUG_RATE("SISO-RATE=%X MIMO2-RATE=%X MIMO3-RATE=%X\n",
                     lq_sta->active_siso_rate,
-                    lq_sta->active_mimo_rate);
+                    lq_sta->active_mimo2_rate,
+                    lq_sta->active_mimo3_rate);
+
+       /* These values will be overriden later */
+       lq_sta->lq.general_params.single_stream_ant_msk = ANT_A;
+       lq_sta->lq.general_params.dual_stream_ant_msk = ANT_AB;
+
        /* as default allow aggregation for all tids */
        lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
 #endif /*CONFIG_IWL4965_HT*/
@@ -2342,50 +2328,55 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
        rs_initialize_lq(priv, conf, sta);
 }
 
-static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta,
-                           struct iwl4965_rate *tx_mcs,
-                           struct iwl_link_quality_cmd *lq_cmd)
+static void rs_fill_link_cmd(const struct iwl_priv *priv,
+                            struct iwl4965_lq_sta *lq_sta,
+                            u32 new_rate)
 {
+       struct iwl4965_scale_tbl_info tbl_type;
        int index = 0;
        int rate_idx;
        int repeat_rate = 0;
-       u8 ant_toggle_count = 0;
+       u8 ant_toggle_cnt = 0;
        u8 use_ht_possible = 1;
-       struct iwl4965_rate new_rate;
-       struct iwl4965_scale_tbl_info tbl_type = { 0 };
+       u8 valid_tx_ant = 0;
+       struct iwl_link_quality_cmd *lq_cmd = &lq_sta->lq;
 
        /* Override starting rate (index 0) if needed for debug purposes */
-       rs_dbgfs_set_mcs(lq_sta, tx_mcs, index);
+       rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
 
-       /* Interpret rate_n_flags */
-       rs_get_tbl_info_from_mcs(tx_mcs, lq_sta->band,
+       /* Interpret new_rate (rate_n_flags) */
+       memset(&tbl_type, 0, sizeof(tbl_type));
+       rs_get_tbl_info_from_mcs(new_rate, lq_sta->band,
                                  &tbl_type, &rate_idx);
 
        /* How many times should we repeat the initial rate? */
        if (is_legacy(tbl_type.lq_type)) {
-               ant_toggle_count = 1;
+               ant_toggle_cnt = 1;
                repeat_rate = IWL_NUMBER_TRY;
-       } else
+       } else {
                repeat_rate = IWL_HT_NUMBER_TRY;
+       }
 
        lq_cmd->general_params.mimo_delimiter =
                        is_mimo(tbl_type.lq_type) ? 1 : 0;
 
        /* Fill 1st table entry (index 0) */
-       lq_cmd->rs_table[index].rate_n_flags =
-                       cpu_to_le32(tx_mcs->rate_n_flags);
-       new_rate.rate_n_flags = tx_mcs->rate_n_flags;
+       lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate);
 
-       if (is_mimo(tbl_type.lq_type) || (tbl_type.antenna_type == ANT_MAIN))
-               lq_cmd->general_params.single_stream_ant_msk
-                       = LINK_QUAL_ANT_A_MSK;
-       else
-               lq_cmd->general_params.single_stream_ant_msk
-                       = LINK_QUAL_ANT_B_MSK;
+       if (num_of_ant(tbl_type.ant_type) == 1) {
+               lq_cmd->general_params.single_stream_ant_msk =
+                                               tbl_type.ant_type;
+       } else if (num_of_ant(tbl_type.ant_type) == 2) {
+               lq_cmd->general_params.dual_stream_ant_msk =
+                                               tbl_type.ant_type;
+       } /* otherwise we don't modify the existing value */
 
        index++;
        repeat_rate--;
 
+       if (priv)
+               valid_tx_ant = priv->hw_params.valid_tx_ant;
+
        /* Fill rest of rate table */
        while (index < LINK_QUAL_MAX_RETRY_NUM) {
                /* Repeat initial/next rate.
@@ -2393,26 +2384,25 @@ static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta,
                 * For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */
                while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) {
                        if (is_legacy(tbl_type.lq_type)) {
-                               if (ant_toggle_count <
-                                   NUM_TRY_BEFORE_ANTENNA_TOGGLE)
-                                       ant_toggle_count++;
-                               else {
-                                       rs_toggle_antenna(&new_rate, &tbl_type);
-                                       ant_toggle_count = 1;
-                               }
-                       }
+                               if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
+                                       ant_toggle_cnt++;
+                               else if (priv &&
+                                        rs_toggle_antenna(valid_tx_ant,
+                                                       &new_rate, &tbl_type))
+                                       ant_toggle_cnt = 1;
+}
 
                        /* Override next rate if needed for debug purposes */
                        rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
 
                        /* Fill next table entry */
                        lq_cmd->rs_table[index].rate_n_flags =
-                                       cpu_to_le32(new_rate.rate_n_flags);
+                                       cpu_to_le32(new_rate);
                        repeat_rate--;
                        index++;
                }
 
-               rs_get_tbl_info_from_mcs(&new_rate, lq_sta->band, &tbl_type,
+               rs_get_tbl_info_from_mcs(new_rate, lq_sta->band, &tbl_type,
                                                &rate_idx);
 
                /* Indicate to uCode which entries might be MIMO.
@@ -2422,20 +2412,22 @@ static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta,
                        lq_cmd->general_params.mimo_delimiter = index;
 
                /* Get next rate */
-               rs_get_lower_rate(lq_sta, &tbl_type, rate_idx,
-                                 use_ht_possible, &new_rate);
+               new_rate = rs_get_lower_rate(lq_sta, &tbl_type, rate_idx,
+                                            use_ht_possible);
 
                /* How many times should we repeat the next rate? */
                if (is_legacy(tbl_type.lq_type)) {
-                       if (ant_toggle_count < NUM_TRY_BEFORE_ANTENNA_TOGGLE)
-                               ant_toggle_count++;
-                       else {
-                               rs_toggle_antenna(&new_rate, &tbl_type);
-                               ant_toggle_count = 1;
-                       }
+                       if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
+                               ant_toggle_cnt++;
+                       else if (priv &&
+                                rs_toggle_antenna(valid_tx_ant,
+                                                  &new_rate, &tbl_type))
+                               ant_toggle_cnt = 1;
+
                        repeat_rate = IWL_NUMBER_TRY;
-               } else
+               } else {
                        repeat_rate = IWL_HT_NUMBER_TRY;
+               }
 
                /* Don't allow HT rates after next pass.
                 * rs_get_lower_rate() will change type to LQ_A or LQ_G. */
@@ -2445,14 +2437,13 @@ static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta,
                rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
 
                /* Fill next table entry */
-               lq_cmd->rs_table[index].rate_n_flags =
-                               cpu_to_le32(new_rate.rate_n_flags);
+               lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate);
 
                index++;
                repeat_rate--;
        }
 
-       lq_cmd->general_params.dual_stream_ant_msk = 3;
+       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);
 }
@@ -2478,10 +2469,12 @@ static void rs_clear(void *priv_rate)
        IWL_DEBUG_RATE("leave\n");
 }
 
-static void rs_free_sta(void *priv, void *priv_sta)
+static void rs_free_sta(void *priv_rate, void *priv_sta)
 {
        struct iwl4965_lq_sta *lq_sta = priv_sta;
+       struct iwl_priv *priv;
 
+       priv = (struct iwl_priv *)priv_rate;
        IWL_DEBUG_RATE("enter\n");
        kfree(lq_sta);
        IWL_DEBUG_RATE("leave\n");
@@ -2495,54 +2488,56 @@ static int open_file_generic(struct inode *inode, struct file *file)
        return 0;
 }
 static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta,
-                               struct iwl4965_rate *mcs, int index)
+                               u32 *rate_n_flags, int index)
 {
-       u32 base_rate;
+       struct iwl_priv *priv;
 
-       if (lq_sta->band == IEEE80211_BAND_5GHZ)
-               base_rate = 0x800D;
-       else
-               base_rate = 0x820A;
-
-       if (lq_sta->dbg_fixed.rate_n_flags) {
-               if (index < 12)
-                       mcs->rate_n_flags = lq_sta->dbg_fixed.rate_n_flags;
-               else
-                       mcs->rate_n_flags = base_rate;
+       priv = lq_sta->drv;
+       if (lq_sta->dbg_fixed_rate) {
+               if (index < 12) {
+                       *rate_n_flags = lq_sta->dbg_fixed_rate;
+               } else {
+                       if (lq_sta->band == IEEE80211_BAND_5GHZ)
+                               *rate_n_flags = 0x800D;
+                       else
+                               *rate_n_flags = 0x820A;
+               }
                IWL_DEBUG_RATE("Fixed rate ON\n");
-               return;
+       } else {
+               IWL_DEBUG_RATE("Fixed rate OFF\n");
        }
-
-       IWL_DEBUG_RATE("Fixed rate OFF\n");
 }
 
 static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
                        const char __user *user_buf, size_t count, loff_t *ppos)
 {
        struct iwl4965_lq_sta *lq_sta = file->private_data;
+       struct iwl_priv *priv;
        char buf[64];
        int buf_size;
        u32 parsed_rate;
 
+       priv = lq_sta->drv;
        memset(buf, 0, sizeof(buf));
        buf_size = min(count, sizeof(buf) -  1);
        if (copy_from_user(buf, user_buf, buf_size))
                return -EFAULT;
 
        if (sscanf(buf, "%x", &parsed_rate) == 1)
-               lq_sta->dbg_fixed.rate_n_flags = parsed_rate;
+               lq_sta->dbg_fixed_rate = parsed_rate;
        else
-               lq_sta->dbg_fixed.rate_n_flags = 0;
+               lq_sta->dbg_fixed_rate = 0;
 
-       lq_sta->active_rate = 0x0FFF;   /* 1 - 54 MBits, includes CCK */
-       lq_sta->active_siso_rate = 0x1FD0;      /* 6 - 60 MBits, no 9, no CCK */
-       lq_sta->active_mimo_rate = 0x1FD0;      /* 6 - 60 MBits, no 9, no CCK */
+       lq_sta->active_legacy_rate = 0x0FFF;    /* 1 - 54 MBits, includes CCK */
+       lq_sta->active_siso_rate   = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
+       lq_sta->active_mimo2_rate  = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
+       lq_sta->active_mimo3_rate  = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
 
        IWL_DEBUG_RATE("sta_id %d rate 0x%X\n",
-               lq_sta->lq.sta_id, lq_sta->dbg_fixed.rate_n_flags);
+               lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate);
 
-       if (lq_sta->dbg_fixed.rate_n_flags) {
-               rs_fill_link_cmd(lq_sta, &lq_sta->dbg_fixed, &lq_sta->lq);
+       if (lq_sta->dbg_fixed_rate) {
+               rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate);
                iwl_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC);
        }
 
@@ -2561,9 +2556,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
        desc += sprintf(buff+desc, "sta_id %d\n", lq_sta->lq.sta_id);
        desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n",
                        lq_sta->total_failed, lq_sta->total_success,
-                       lq_sta->active_rate);
+                       lq_sta->active_legacy_rate);
        desc += sprintf(buff+desc, "fixed rate 0x%X\n",
-                       lq_sta->dbg_fixed.rate_n_flags);
+                       lq_sta->dbg_fixed_rate);
        desc += sprintf(buff+desc, "general:"
                "flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n",
                lq_sta->lq.general_params.flags,
@@ -2613,7 +2608,7 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
                                lq_sta->lq_info[i].is_SGI,
                                lq_sta->lq_info[i].is_fat,
                                lq_sta->lq_info[i].is_dup,
-                               lq_sta->lq_info[i].current_rate.rate_n_flags);
+                               lq_sta->lq_info[i].current_rate);
                for (j = 0; j < IWL_RATE_COUNT; j++) {
                        desc += sprintf(buff+desc,
                                "counter=%d success=%d %%=%d\n",
@@ -2703,7 +2698,7 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
        lq_sta = (void *)sta->rate_ctrl_priv;
 
        lq_type = lq_sta->lq_info[lq_sta->active_tbl].lq_type;
-       antenna = lq_sta->lq_info[lq_sta->active_tbl].antenna_type;
+       antenna = lq_sta->lq_info[lq_sta->active_tbl].ant_type;
 
        if (is_legacy(lq_type))
                i = IWL_RATE_54M_INDEX;
@@ -2715,7 +2710,7 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
                int active = lq_sta->active_tbl;
 
                cnt +=
-                   sprintf(&buf[cnt], " %2dMbs: ", iwl4965_rates[i].ieee / 2);
+                   sprintf(&buf[cnt], " %2dMbs: ", iwl_rates[i].ieee / 2);
 
                mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1));
                for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1)
@@ -2726,7 +2721,7 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
                samples += lq_sta->lq_info[active].win[i].counter;
                good += lq_sta->lq_info[active].win[i].success_counter;
                success += lq_sta->lq_info[active].win[i].success_counter *
-                          iwl4965_rates[i].ieee;
+                          iwl_rates[i].ieee;
 
                if (lq_sta->lq_info[active].win[i].stamp) {
                        int delta =
@@ -2746,10 +2741,11 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
                i = j;
        }
 
-       /* Display the average rate of all samples taken.
-        *
-        * NOTE:  We multiply # of samples by 2 since the IEEE measurement
-        * added from iwl4965_rates is actually 2X the rate */
+       /*
+        * Display the average rate of all samples taken.
+        * NOTE: We multiply # of samples by 2 since the IEEE measurement
+        * added from iwl_rates is actually 2X the rate.
+        */
        if (samples)
                cnt += sprintf(&buf[cnt],
                         "\nAverage rate is %3d.%02dMbs over last %4dms\n"
index 866e378aa3852b3dc1dc9c5055312f789d4fe291..1dd4124227a5c470174049c1c07c35eb95602520 100644 (file)
 #ifndef __iwl_4965_rs_h__
 #define __iwl_4965_rs_h__
 
-#include "iwl-4965.h"
+#include "iwl-dev.h"
 
-struct iwl4965_rate_info {
+struct iwl_rate_info {
        u8 plcp;        /* uCode API:  IWL_RATE_6M_PLCP, etc. */
        u8 plcp_siso;   /* uCode API:  IWL_RATE_SISO_6M_PLCP, etc. */
-       u8 plcp_mimo;   /* uCode API:  IWL_RATE_MIMO_6M_PLCP, etc. */
+       u8 plcp_mimo2;  /* uCode API:  IWL_RATE_MIMO2_6M_PLCP, etc. */
+       u8 plcp_mimo3;  /* uCode API:  IWL_RATE_MIMO3_6M_PLCP, etc. */
        u8 ieee;        /* MAC header:  IWL_RATE_6M_IEEE, etc. */
        u8 prev_ieee;    /* previous rate in IEEE speeds */
        u8 next_ieee;    /* next rate in IEEE speeds */
@@ -44,7 +45,7 @@ struct iwl4965_rate_info {
 
 /*
  * These serve as indexes into
- * struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT];
+ * struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
  */
 enum {
        IWL_RATE_1M_INDEX = 0,
@@ -60,9 +61,9 @@ enum {
        IWL_RATE_48M_INDEX,
        IWL_RATE_54M_INDEX,
        IWL_RATE_60M_INDEX,
-       IWL_RATE_COUNT,
+       IWL_RATE_COUNT, /*FIXME:RS:change to IWL_RATE_INDEX_COUNT,*/
        IWL_RATE_INVM_INDEX = IWL_RATE_COUNT,
-       IWL_RATE_INVALID = IWL_RATE_INVM_INDEX
+       IWL_RATE_INVALID = IWL_RATE_COUNT,
 };
 
 enum {
@@ -97,11 +98,13 @@ enum {
        IWL_RATE_36M_PLCP = 11,
        IWL_RATE_48M_PLCP = 1,
        IWL_RATE_54M_PLCP = 3,
-       IWL_RATE_60M_PLCP = 3,
+       IWL_RATE_60M_PLCP = 3,/*FIXME:RS:should be removed*/
        IWL_RATE_1M_PLCP  = 10,
        IWL_RATE_2M_PLCP  = 20,
        IWL_RATE_5M_PLCP  = 55,
        IWL_RATE_11M_PLCP = 110,
+       /*FIXME:RS:change to IWL_RATE_LEGACY_??M_PLCP */
+       /*FIXME:RS:add IWL_RATE_LEGACY_INVM_PLCP = 0,*/
 };
 
 /* 4965 uCode API values for OFDM high-throughput (HT) bit rates */
@@ -114,16 +117,25 @@ enum {
        IWL_RATE_SISO_48M_PLCP = 5,
        IWL_RATE_SISO_54M_PLCP = 6,
        IWL_RATE_SISO_60M_PLCP = 7,
-       IWL_RATE_MIMO_6M_PLCP  = 0x8,
-       IWL_RATE_MIMO_12M_PLCP = 0x9,
-       IWL_RATE_MIMO_18M_PLCP = 0xa,
-       IWL_RATE_MIMO_24M_PLCP = 0xb,
-       IWL_RATE_MIMO_36M_PLCP = 0xc,
-       IWL_RATE_MIMO_48M_PLCP = 0xd,
-       IWL_RATE_MIMO_54M_PLCP = 0xe,
-       IWL_RATE_MIMO_60M_PLCP = 0xf,
+       IWL_RATE_MIMO2_6M_PLCP  = 0x8,
+       IWL_RATE_MIMO2_12M_PLCP = 0x9,
+       IWL_RATE_MIMO2_18M_PLCP = 0xa,
+       IWL_RATE_MIMO2_24M_PLCP = 0xb,
+       IWL_RATE_MIMO2_36M_PLCP = 0xc,
+       IWL_RATE_MIMO2_48M_PLCP = 0xd,
+       IWL_RATE_MIMO2_54M_PLCP = 0xe,
+       IWL_RATE_MIMO2_60M_PLCP = 0xf,
+       IWL_RATE_MIMO3_6M_PLCP  = 0x10,
+       IWL_RATE_MIMO3_12M_PLCP = 0x11,
+       IWL_RATE_MIMO3_18M_PLCP = 0x12,
+       IWL_RATE_MIMO3_24M_PLCP = 0x13,
+       IWL_RATE_MIMO3_36M_PLCP = 0x14,
+       IWL_RATE_MIMO3_48M_PLCP = 0x15,
+       IWL_RATE_MIMO3_54M_PLCP = 0x16,
+       IWL_RATE_MIMO3_60M_PLCP = 0x17,
        IWL_RATE_SISO_INVM_PLCP,
-       IWL_RATE_MIMO_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
+       IWL_RATE_MIMO2_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
+       IWL_RATE_MIMO3_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
 };
 
 /* MAC header values for bit rates */
@@ -196,11 +208,11 @@ enum {
 /* possible actions when in legacy mode */
 #define IWL_LEGACY_SWITCH_ANTENNA      0
 #define IWL_LEGACY_SWITCH_SISO         1
-#define IWL_LEGACY_SWITCH_MIMO         2
+#define IWL_LEGACY_SWITCH_MIMO2                2
 
 /* possible actions when in siso mode */
 #define IWL_SISO_SWITCH_ANTENNA                0
-#define IWL_SISO_SWITCH_MIMO           1
+#define IWL_SISO_SWITCH_MIMO2          1
 #define IWL_SISO_SWITCH_GI             2
 
 /* possible actions when in mimo mode */
@@ -208,6 +220,10 @@ enum {
 #define IWL_MIMO_SWITCH_ANTENNA_B      1
 #define IWL_MIMO_SWITCH_GI             2
 
+/*FIXME:RS:separate MIMO2/3 transitions*/
+
+/*FIXME:RS:add posible acctions for MIMO3*/
+
 #define IWL_ACTION_LIMIT               3       /* # possible actions */
 
 #define LQ_SIZE                2       /* 2 mode tables:  "Active" and "Search" */
@@ -224,35 +240,46 @@ enum {
 #define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING)
 #define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y))
 
-extern const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT];
+extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
 
-enum iwl4965_table_type {
+enum iwl_table_type {
        LQ_NONE,
        LQ_G,           /* legacy types */
        LQ_A,
        LQ_SISO,        /* high-throughput types */
-       LQ_MIMO,
+       LQ_MIMO2,
+       LQ_MIMO3,
        LQ_MAX,
 };
 
 #define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A))
-#define is_siso(tbl) (((tbl) == LQ_SISO))
-#define is_mimo(tbl) (((tbl) == LQ_MIMO))
+#define is_siso(tbl) ((tbl) == LQ_SISO)
+#define is_mimo2(tbl) ((tbl) == LQ_MIMO2)
+#define is_mimo3(tbl) ((tbl) == LQ_MIMO3)
+#define is_mimo(tbl) (is_mimo2(tbl) || is_mimo3(tbl))
 #define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl))
-#define is_a_band(tbl) (((tbl) == LQ_A))
-#define is_g_and(tbl) (((tbl) == LQ_G))
-
-/* 4965 has 2 antennas/chains for Tx (but 3 for Rx) */
-enum iwl4965_antenna_type {
-       ANT_NONE,
-       ANT_MAIN,
-       ANT_AUX,
-       ANT_BOTH,
-};
+#define is_a_band(tbl) ((tbl) == LQ_A)
+#define is_g_and(tbl) ((tbl) == LQ_G)
+
+#define        ANT_NONE        0x0
+#define        ANT_A           BIT(0)
+#define        ANT_B           BIT(1)
+#define        ANT_AB          (ANT_A | ANT_B)
+#define ANT_C          BIT(2)
+#define        ANT_AC          (ANT_A | ANT_C)
+#define ANT_BC         (ANT_B | ANT_C)
+#define ANT_ABC                (ANT_AB | ANT_C)
+
+static inline u8 num_of_ant(u8 mask)
+{
+       return  !!((mask) & ANT_A) +
+               !!((mask) & ANT_B) +
+               !!((mask) & ANT_C);
+}
 
 static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index)
 {
-       u8 rate = iwl4965_rates[rate_index].prev_ieee;
+       u8 rate = iwl_rates[rate_index].prev_ieee;
 
        if (rate == IWL_RATE_INVALID)
                rate = rate_index;
index bf19eb8aafd02f4db85e4d4f856d79f5ec2825fc..aee7014bcb94f5dd4eb1907bc9d81bff6ebaeb8b 100644 (file)
 #include <asm/unaligned.h>
 
 #include "iwl-eeprom.h"
-#include "iwl-4965.h"
+#include "iwl-dev.h"
 #include "iwl-core.h"
 #include "iwl-io.h"
 #include "iwl-helpers.h"
+#include "iwl-calib.h"
+#include "iwl-sta.h"
 
 /* module parameters */
 static struct iwl_mod_params iwl4965_mod_params = {
-       .num_of_queues = IWL4965_MAX_NUM_QUEUES,
+       .num_of_queues = IWL49_NUM_QUEUES,
        .enable_qos = 1,
        .amsdu_size_8K = 1,
+       .restart_fw = 1,
        /* the rest are 0 by default */
 };
 
-static void iwl4965_hw_card_show_info(struct iwl_priv *priv);
-
-#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np)    \
-       [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP,      \
-                                   IWL_RATE_SISO_##s##M_PLCP, \
-                                   IWL_RATE_MIMO_##s##M_PLCP, \
-                                   IWL_RATE_##r##M_IEEE,      \
-                                   IWL_RATE_##ip##M_INDEX,    \
-                                   IWL_RATE_##in##M_INDEX,    \
-                                   IWL_RATE_##rp##M_INDEX,    \
-                                   IWL_RATE_##rn##M_INDEX,    \
-                                   IWL_RATE_##pp##M_INDEX,    \
-                                   IWL_RATE_##np##M_INDEX }
-
-/*
- * Parameter order:
- *   rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate
- *
- * If there isn't a valid next or previous rate then INV is used which
- * maps to IWL_RATE_INVALID
- *
- */
-const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT] = {
-       IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2),    /*  1mbps */
-       IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5),          /*  2mbps */
-       IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11),        /*5.5mbps */
-       IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18),      /* 11mbps */
-       IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11),        /*  6mbps */
-       IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11),       /*  9mbps */
-       IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18),   /* 12mbps */
-       IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24),   /* 18mbps */
-       IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36),   /* 24mbps */
-       IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48),   /* 36mbps */
-       IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54),   /* 48mbps */
-       IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */
-       IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */
-};
-
-#ifdef CONFIG_IWL4965_HT
-
-static const u16 default_tid_to_tx_fifo[] = {
-       IWL_TX_FIFO_AC1,
-       IWL_TX_FIFO_AC0,
-       IWL_TX_FIFO_AC0,
-       IWL_TX_FIFO_AC1,
-       IWL_TX_FIFO_AC2,
-       IWL_TX_FIFO_AC2,
-       IWL_TX_FIFO_AC3,
-       IWL_TX_FIFO_AC3,
-       IWL_TX_FIFO_NONE,
-       IWL_TX_FIFO_NONE,
-       IWL_TX_FIFO_NONE,
-       IWL_TX_FIFO_NONE,
-       IWL_TX_FIFO_NONE,
-       IWL_TX_FIFO_NONE,
-       IWL_TX_FIFO_NONE,
-       IWL_TX_FIFO_NONE,
-       IWL_TX_FIFO_AC3
-};
-
-#endif /*CONFIG_IWL4965_HT */
-
 /* check contents of special bootstrap uCode SRAM */
 static int iwl4965_verify_bsm(struct iwl_priv *priv)
 {
@@ -192,15 +133,18 @@ static int iwl4965_load_bsm(struct iwl_priv *priv)
 
        IWL_DEBUG_INFO("Begin load bsm\n");
 
+       priv->ucode_type = UCODE_RT;
+
        /* make sure bootstrap program is no larger than BSM's SRAM size */
        if (len > IWL_MAX_BSM_SIZE)
                return -EINVAL;
 
        /* Tell bootstrap uCode where to find the "Initialize" uCode
         *   in host DRAM ... host DRAM physical address bits 35:4 for 4965.
-        * NOTE:  iwl4965_initialize_alive_start() will replace these values,
+        * NOTE:  iwl_init_alive_start() will replace these values,
         *        after the "initialize" uCode has run, to point to
-        *        runtime/protocol instructions and backup data cache. */
+        *        runtime/protocol instructions and backup data cache.
+        */
        pinst = priv->ucode_init.p_addr >> 4;
        pdata = priv->ucode_init_data.p_addr >> 4;
        inst_len = priv->ucode_init.len;
@@ -259,99 +203,100 @@ static int iwl4965_load_bsm(struct iwl_priv *priv)
        return 0;
 }
 
-static int iwl4965_init_drv(struct iwl_priv *priv)
+/**
+ * iwl4965_set_ucode_ptrs - Set uCode address location
+ *
+ * Tell initialization uCode where to find runtime uCode.
+ *
+ * BSM registers initially contain pointers to initialization uCode.
+ * We need to replace them to load runtime uCode inst and data,
+ * and to save runtime data when powering down.
+ */
+static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv)
 {
-       int ret;
-       int i;
-
-       priv->antenna = (enum iwl4965_antenna)priv->cfg->mod_params->antenna;
-       priv->retry_rate = 1;
-       priv->ibss_beacon = NULL;
-
-       spin_lock_init(&priv->lock);
-       spin_lock_init(&priv->power_data.lock);
-       spin_lock_init(&priv->sta_lock);
-       spin_lock_init(&priv->hcmd_lock);
-       spin_lock_init(&priv->lq_mngr.lock);
+       dma_addr_t pinst;
+       dma_addr_t pdata;
+       unsigned long flags;
+       int ret = 0;
 
-       priv->shared_virt = pci_alloc_consistent(priv->pci_dev,
-                                       sizeof(struct iwl4965_shared),
-                                       &priv->shared_phys);
+       /* bits 35:4 for 4965 */
+       pinst = priv->ucode_code.p_addr >> 4;
+       pdata = priv->ucode_data_backup.p_addr >> 4;
 
-       if (!priv->shared_virt) {
-               ret = -ENOMEM;
-               goto err;
+       spin_lock_irqsave(&priv->lock, flags);
+       ret = iwl_grab_nic_access(priv);
+       if (ret) {
+               spin_unlock_irqrestore(&priv->lock, flags);
+               return ret;
        }
 
-       memset(priv->shared_virt, 0, sizeof(struct iwl4965_shared));
-
-
-       for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++)
-               INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
-
-       INIT_LIST_HEAD(&priv->free_frames);
-
-       mutex_init(&priv->mutex);
-
-       /* Clear the driver's (not device's) station table */
-       iwlcore_clear_stations_table(priv);
-
-       priv->data_retry_limit = -1;
-       priv->ieee_channels = NULL;
-       priv->ieee_rates = NULL;
-       priv->band = IEEE80211_BAND_2GHZ;
-
-       priv->iw_mode = IEEE80211_IF_TYPE_STA;
-
-       priv->use_ant_b_for_management_frame = 1; /* start with ant B */
-       priv->valid_antenna = 0x7;      /* assume all 3 connected */
-       priv->ps_mode = IWL_MIMO_PS_NONE;
-
-       /* Choose which receivers/antennas to use */
-       iwl4965_set_rxon_chain(priv);
-
-       iwlcore_reset_qos(priv);
+       /* Tell bootstrap uCode where to find image to load */
+       iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
+       iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
+       iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG,
+                                priv->ucode_data.len);
 
-       priv->qos_data.qos_active = 0;
-       priv->qos_data.qos_cap.val = 0;
+       /* Inst bytecount must be last to set up, bit 31 signals uCode
+        *   that all new ptr/size info is in place */
+       iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG,
+                                priv->ucode_code.len | BSM_DRAM_INST_LOAD);
+       iwl_release_nic_access(priv);
 
-       iwlcore_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6);
+       spin_unlock_irqrestore(&priv->lock, flags);
 
-       priv->rates_mask = IWL_RATES_MASK;
-       /* If power management is turned on, default to AC mode */
-       priv->power_mode = IWL_POWER_AC;
-       priv->user_txpower_limit = IWL_DEFAULT_TX_POWER;
+       IWL_DEBUG_INFO("Runtime uCode pointers are set.\n");
 
-       ret = iwl_init_channel_map(priv);
-       if (ret) {
-               IWL_ERROR("initializing regulatory failed: %d\n", ret);
-               goto err;
-       }
-
-       ret = iwl4965_init_geos(priv);
-       if (ret) {
-               IWL_ERROR("initializing geos failed: %d\n", ret);
-               goto err_free_channel_map;
-       }
+       return ret;
+}
 
-       ret = ieee80211_register_hw(priv->hw);
-       if (ret) {
-               IWL_ERROR("Failed to register network device (error %d)\n",
-                               ret);
-               goto err_free_geos;
+/**
+ * iwl4965_init_alive_start - Called after REPLY_ALIVE notification received
+ *
+ * Called after REPLY_ALIVE notification received from "initialize" uCode.
+ *
+ * The 4965 "initialize" ALIVE reply contains calibration data for:
+ *   Voltage, temperature, and MIMO tx gain correction, now stored in priv
+ *   (3945 does not contain this data).
+ *
+ * Tell "initialize" uCode to go ahead and load the runtime uCode.
+*/
+static void iwl4965_init_alive_start(struct iwl_priv *priv)
+{
+       /* Check alive response for "valid" sign from uCode */
+       if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
+               /* We had an error bringing up the hardware, so take it
+                * all the way back down so we can try again */
+               IWL_DEBUG_INFO("Initialize Alive failed.\n");
+               goto restart;
+       }
+
+       /* Bootstrap uCode has loaded initialize uCode ... verify inst image.
+        * This is a paranoid check, because we would not have gotten the
+        * "initialize" alive if code weren't properly loaded.  */
+       if (iwl_verify_ucode(priv)) {
+               /* Runtime instruction load was bad;
+                * take it all the way back down so we can try again */
+               IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n");
+               goto restart;
+       }
+
+       /* Calculate temperature */
+       priv->temperature = iwl4965_get_temperature(priv);
+
+       /* Send pointers to protocol/runtime uCode image ... init code will
+        * load and launch runtime uCode, which will send us another "Alive"
+        * notification. */
+       IWL_DEBUG_INFO("Initialization Alive received.\n");
+       if (iwl4965_set_ucode_ptrs(priv)) {
+               /* Runtime instruction load won't happen;
+                * take it all the way back down so we can try again */
+               IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n");
+               goto restart;
        }
+       return;
 
-       priv->hw->conf.beacon_int = 100;
-       priv->mac80211_registered = 1;
-
-       return 0;
-
-err_free_geos:
-       iwl4965_free_geos(priv);
-err_free_channel_map:
-       iwl_free_channel_map(priv);
-err:
-       return ret;
+restart:
+       queue_work(priv->workqueue, &priv->restart);
 }
 
 static int is_fat_channel(__le32 rxon_flags)
@@ -360,19 +305,6 @@ static int is_fat_channel(__le32 rxon_flags)
                (rxon_flags & RXON_FLG_CHANNEL_MODE_MIXED_MSK);
 }
 
-static u8 is_single_stream(struct iwl_priv *priv)
-{
-#ifdef CONFIG_IWL4965_HT
-       if (!priv->current_ht_config.is_ht ||
-           (priv->current_ht_config.supp_mcs_set[1] == 0) ||
-           (priv->ps_mode == IWL_MIMO_PS_STATIC))
-               return 1;
-#else
-       return 1;
-#endif /*CONFIG_IWL4965_HT */
-       return 0;
-}
-
 int iwl4965_hwrate_to_plcp_idx(u32 rate_n_flags)
 {
        int idx = 0;
@@ -381,8 +313,8 @@ int iwl4965_hwrate_to_plcp_idx(u32 rate_n_flags)
        if (rate_n_flags & RATE_MCS_HT_MSK) {
                idx = (rate_n_flags & 0xff);
 
-               if (idx >= IWL_RATE_MIMO_6M_PLCP)
-                       idx = idx - IWL_RATE_MIMO_6M_PLCP;
+               if (idx >= IWL_RATE_MIMO2_6M_PLCP)
+                       idx = idx - IWL_RATE_MIMO2_6M_PLCP;
 
                idx += IWL_FIRST_OFDM_RATE;
                /* skip 9M not supported in ht*/
@@ -393,8 +325,8 @@ int iwl4965_hwrate_to_plcp_idx(u32 rate_n_flags)
 
        /* 4965 legacy rate format, search for match in table */
        } else {
-               for (idx = 0; idx < ARRAY_SIZE(iwl4965_rates); idx++)
-                       if (iwl4965_rates[idx].plcp == (rate_n_flags & 0xFF))
+               for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++)
+                       if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF))
                                return idx;
        }
 
@@ -405,125 +337,54 @@ int iwl4965_hwrate_to_plcp_idx(u32 rate_n_flags)
  * translate ucode response to mac80211 tx status control values
  */
 void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
-                                 struct ieee80211_tx_control *control)
+                                 struct ieee80211_tx_info *control)
 {
        int rate_index;
 
        control->antenna_sel_tx =
-               ((rate_n_flags & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS);
+               ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS);
        if (rate_n_flags & RATE_MCS_HT_MSK)
-               control->flags |= IEEE80211_TXCTL_OFDM_HT;
+               control->flags |= IEEE80211_TX_CTL_OFDM_HT;
        if (rate_n_flags & RATE_MCS_GF_MSK)
-               control->flags |= IEEE80211_TXCTL_GREEN_FIELD;
+               control->flags |= IEEE80211_TX_CTL_GREEN_FIELD;
        if (rate_n_flags & RATE_MCS_FAT_MSK)
-               control->flags |= IEEE80211_TXCTL_40_MHZ_WIDTH;
+               control->flags |= IEEE80211_TX_CTL_40_MHZ_WIDTH;
        if (rate_n_flags & RATE_MCS_DUP_MSK)
-               control->flags |= IEEE80211_TXCTL_DUP_DATA;
+               control->flags |= IEEE80211_TX_CTL_DUP_DATA;
        if (rate_n_flags & RATE_MCS_SGI_MSK)
-               control->flags |= IEEE80211_TXCTL_SHORT_GI;
-       /* since iwl4965_hwrate_to_plcp_idx is band indifferent, we always use
-        * IEEE80211_BAND_2GHZ band as it contains all the rates */
+               control->flags |= IEEE80211_TX_CTL_SHORT_GI;
        rate_index = iwl4965_hwrate_to_plcp_idx(rate_n_flags);
-       if (rate_index == -1)
-               control->tx_rate = NULL;
-       else
-               control->tx_rate =
-                       &priv->bands[IEEE80211_BAND_2GHZ].bitrates[rate_index];
+       if (control->band == IEEE80211_BAND_5GHZ)
+               rate_index -= IWL_FIRST_OFDM_RATE;
+       control->tx_rate_idx = rate_index;
 }
 
 /*
- * Determine how many receiver/antenna chains to use.
- * More provides better reception via diversity.  Fewer saves power.
- * MIMO (dual stream) requires at least 2, but works better with 3.
- * This does not determine *which* chains to use, just how many.
+ * EEPROM handlers
  */
-static int iwl4965_get_rx_chain_counter(struct iwl_priv *priv,
-                                       u8 *idle_state, u8 *rx_state)
-{
-       u8 is_single = is_single_stream(priv);
-       u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1;
 
-       /* # of Rx chains to use when expecting MIMO. */
-       if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC)))
-               *rx_state = 2;
-       else
-               *rx_state = 3;
-
-       /* # Rx chains when idling and maybe trying to save power */
-       switch (priv->ps_mode) {
-       case IWL_MIMO_PS_STATIC:
-       case IWL_MIMO_PS_DYNAMIC:
-               *idle_state = (is_cam) ? 2 : 1;
-               break;
-       case IWL_MIMO_PS_NONE:
-               *idle_state = (is_cam) ? *rx_state : 1;
-               break;
-       default:
-               *idle_state = 1;
-               break;
-       }
-
-       return 0;
-}
-
-int iwl4965_hw_rxq_stop(struct iwl_priv *priv)
+static int iwl4965_eeprom_check_version(struct iwl_priv *priv)
 {
-       int rc;
-       unsigned long flags;
+       u16 eeprom_ver;
+       u16 calib_ver;
 
-       spin_lock_irqsave(&priv->lock, flags);
-       rc = iwl_grab_nic_access(priv);
-       if (rc) {
-               spin_unlock_irqrestore(&priv->lock, flags);
-               return rc;
-       }
+       eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
 
-       /* stop Rx DMA */
-       iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
-       rc = iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
-                                    (1 << 24), 1000);
-       if (rc < 0)
-               IWL_ERROR("Can't stop Rx DMA.\n");
+       calib_ver = iwl_eeprom_query16(priv, EEPROM_4965_CALIB_VERSION_OFFSET);
 
-       iwl_release_nic_access(priv);
-       spin_unlock_irqrestore(&priv->lock, flags);
+       if (eeprom_ver < EEPROM_4965_EEPROM_VERSION ||
+           calib_ver < EEPROM_4965_TX_POWER_VERSION)
+               goto err;
 
        return 0;
-}
-
-u8 iwl4965_hw_find_station(struct iwl_priv *priv, const u8 *addr)
-{
-       int i;
-       int start = 0;
-       int ret = IWL_INVALID_STATION;
-       unsigned long flags;
-       DECLARE_MAC_BUF(mac);
-
-       if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) ||
-           (priv->iw_mode == IEEE80211_IF_TYPE_AP))
-               start = IWL_STA_ID;
-
-       if (is_broadcast_ether_addr(addr))
-               return priv->hw_params.bcast_sta_id;
-
-       spin_lock_irqsave(&priv->sta_lock, flags);
-       for (i = start; i < priv->hw_params.max_stations; i++)
-               if ((priv->stations[i].used) &&
-                   (!compare_ether_addr
-                    (priv->stations[i].sta.sta.addr, addr))) {
-                       ret = i;
-                       goto out;
-               }
-
-       IWL_DEBUG_ASSOC_LIMIT("can not find STA %s total %d\n",
-                       print_mac(mac, addr), priv->num_stations);
+err:
+       IWL_ERROR("Unsuported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n",
+                 eeprom_ver, EEPROM_4965_EEPROM_VERSION,
+                 calib_ver, EEPROM_4965_TX_POWER_VERSION);
+       return -EINVAL;
 
- out:
-       spin_unlock_irqrestore(&priv->sta_lock, flags);
-       return ret;
 }
-
-static int iwl4965_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max)
+int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
 {
        int ret;
        unsigned long flags;
@@ -535,340 +396,130 @@ static int iwl4965_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max)
                return ret;
        }
 
-       if (!pwr_max) {
+       if (src == IWL_PWR_SRC_VAUX) {
                u32 val;
-
                ret = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE,
-                                          &val);
+                                           &val);
 
-               if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT)
+               if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) {
                        iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
-                               APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
-                               ~APMG_PS_CTRL_MSK_PWR_SRC);
-       } else
+                                              APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
+                                              ~APMG_PS_CTRL_MSK_PWR_SRC);
+               }
+       } else {
                iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
-                       APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
-                       ~APMG_PS_CTRL_MSK_PWR_SRC);
-
-       iwl_release_nic_access(priv);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       return ret;
-}
-
-static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq)
-{
-       int ret;
-       unsigned long flags;
-       unsigned int rb_size;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       ret = iwl_grab_nic_access(priv);
-       if (ret) {
-               spin_unlock_irqrestore(&priv->lock, flags);
-               return ret;
+                                      APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
+                                      ~APMG_PS_CTRL_MSK_PWR_SRC);
        }
 
-       if (priv->cfg->mod_params->amsdu_size_8K)
-               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
-       else
-               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
-
-       /* Stop Rx DMA */
-       iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
-
-       /* Reset driver's Rx queue write index */
-       iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
-
-       /* Tell device where to find RBD circular buffer in DRAM */
-       iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
-                          rxq->dma_addr >> 8);
-
-       /* Tell device where in DRAM to update its Rx status */
-       iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
-                          (priv->shared_phys +
-                           offsetof(struct iwl4965_shared, rb_closed)) >> 4);
-
-       /* Enable Rx DMA, enable host interrupt, Rx buffer size 4k, 256 RBDs */
-       iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG,
-                          FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
-                          FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
-                          rb_size |
-                            /* 0x10 << 4 | */
-                          (RX_QUEUE_SIZE_LOG <<
-                             FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));
-
-       /*
-        * iwl_write32(priv,CSR_INT_COAL_REG,0);
-        */
-
-       iwl_release_nic_access(priv);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       return 0;
-}
-
-/* Tell 4965 where to find the "keep warm" buffer */
-static int iwl4965_kw_init(struct iwl_priv *priv)
-{
-       unsigned long flags;
-       int rc;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       rc = iwl_grab_nic_access(priv);
-       if (rc)
-               goto out;
-
-       iwl_write_direct32(priv, IWL_FH_KW_MEM_ADDR_REG,
-                            priv->kw.dma_addr >> 4);
        iwl_release_nic_access(priv);
-out:
        spin_unlock_irqrestore(&priv->lock, flags);
-       return rc;
-}
 
-static int iwl4965_kw_alloc(struct iwl_priv *priv)
-{
-       struct pci_dev *dev = priv->pci_dev;
-       struct iwl4965_kw *kw = &priv->kw;
-
-       kw->size = IWL4965_KW_SIZE;     /* TBW need set somewhere else */
-       kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr);
-       if (!kw->v_addr)
-               return -ENOMEM;
-
-       return 0;
-}
-
-/**
- * iwl4965_kw_free - Free the "keep warm" buffer
- */
-static void iwl4965_kw_free(struct iwl_priv *priv)
-{
-       struct pci_dev *dev = priv->pci_dev;
-       struct iwl4965_kw *kw = &priv->kw;
-
-       if (kw->v_addr) {
-               pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr);
-               memset(kw, 0, sizeof(*kw));
-       }
+       return ret;
 }
 
-/**
- * iwl4965_txq_ctx_reset - Reset TX queue context
- * Destroys all DMA structures and initialise them again
- *
- * @param priv
- * @return error code
+/*
+ * Activate/Deactivat Tx DMA/FIFO channels according tx fifos mask
+ * must be called under priv->lock and mac access
  */
-static int iwl4965_txq_ctx_reset(struct iwl_priv *priv)
+static void iwl4965_txq_set_sched(struct iwl_priv *priv, u32 mask)
 {
-       int rc = 0;
-       int txq_id, slots_num;
-       unsigned long flags;
-
-       iwl4965_kw_free(priv);
-
-       /* Free all tx/cmd queues and keep-warm buffer */
-       iwl4965_hw_txq_ctx_free(priv);
-
-       /* Alloc keep-warm buffer */
-       rc = iwl4965_kw_alloc(priv);
-       if (rc) {
-               IWL_ERROR("Keep Warm allocation failed");
-               goto error_kw;
-       }
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       rc = iwl_grab_nic_access(priv);
-       if (unlikely(rc)) {
-               IWL_ERROR("TX reset failed");
-               spin_unlock_irqrestore(&priv->lock, flags);
-               goto error_reset;
-       }
-
-       /* Turn off all Tx DMA channels */
-       iwl_write_prph(priv, IWL49_SCD_TXFACT, 0);
-       iwl_release_nic_access(priv);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       /* Tell 4965 where to find the keep-warm buffer */
-       rc = iwl4965_kw_init(priv);
-       if (rc) {
-               IWL_ERROR("kw_init failed\n");
-               goto error_reset;
-       }
-
-       /* Alloc and init all (default 16) Tx queues,
-        * including the command queue (#4) */
-       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
-               slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
-                                       TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-               rc = iwl4965_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
-                                      txq_id);
-               if (rc) {
-                       IWL_ERROR("Tx %d queue init failed\n", txq_id);
-                       goto error;
-               }
-       }
-
-       return rc;
-
- error:
-       iwl4965_hw_txq_ctx_free(priv);
- error_reset:
-       iwl4965_kw_free(priv);
- error_kw:
-       return rc;
+       iwl_write_prph(priv, IWL49_SCD_TXFACT, mask);
 }
 
-int iwl4965_hw_nic_init(struct iwl_priv *priv)
+static int iwl4965_apm_init(struct iwl_priv *priv)
 {
-       int rc;
-       unsigned long flags;
-       struct iwl4965_rx_queue *rxq = &priv->rxq;
-       u8 rev_id;
-       u32 val;
-       u8 val_link;
-
-       iwl4965_power_init_handle(priv);
+       int ret = 0;
 
-       /* nic_init */
-       spin_lock_irqsave(&priv->lock, flags);
+       iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+                         CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
 
+       /* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */
        iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
-                   CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+                         CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
 
+       /* set "initialization complete" bit to move adapter
+        * D0U* --> D0A* state */
        iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-       rc = iwl_poll_bit(priv, CSR_GP_CNTRL,
-                         CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
-                         CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
-       if (rc < 0) {
-               spin_unlock_irqrestore(&priv->lock, flags);
-               IWL_DEBUG_INFO("Failed to init the card\n");
-               return rc;
-       }
 
-       rc = iwl_grab_nic_access(priv);
-       if (rc) {
-               spin_unlock_irqrestore(&priv->lock, flags);
-               return rc;
+       /* wait for clock stabilization */
+       ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
+                          CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+                          CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+       if (ret < 0) {
+               IWL_DEBUG_INFO("Failed to init the card\n");
+               goto out;
        }
 
-       iwl_read_prph(priv, APMG_CLK_CTRL_REG);
+       ret = iwl_grab_nic_access(priv);
+       if (ret)
+               goto out;
 
-       iwl_write_prph(priv, APMG_CLK_CTRL_REG,
-                       APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT);
-       iwl_read_prph(priv, APMG_CLK_CTRL_REG);
+       /* enable DMA */
+       iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT |
+                                               APMG_CLK_VAL_BSM_CLK_RQT);
 
        udelay(20);
 
+       /* disable L1-Active */
        iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
-                               APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+                         APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
 
        iwl_release_nic_access(priv);
-       iwl_write32(priv, CSR_INT_COALESCING, 512 / 32);
-       spin_unlock_irqrestore(&priv->lock, flags);
+out:
+       return ret;
+}
 
-       /* Determine HW type */
-       rc = pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id);
-       if (rc)
-               return rc;
 
-       IWL_DEBUG_INFO("HW Revision ID = 0x%X\n", rev_id);
+static void iwl4965_nic_config(struct iwl_priv *priv)
+{
+       unsigned long flags;
+       u32 val;
+       u16 radio_cfg;
+       u8 val_link;
 
-       iwl4965_nic_set_pwr_src(priv, 1);
        spin_lock_irqsave(&priv->lock, flags);
 
-       if ((rev_id & 0x80) == 0x80 && (rev_id & 0x7f) < 8) {
+       if ((priv->rev_id & 0x80) == 0x80 && (priv->rev_id & 0x7f) < 8) {
                pci_read_config_dword(priv->pci_dev, PCI_REG_WUM8, &val);
                /* Enable No Snoop field */
                pci_write_config_dword(priv->pci_dev, PCI_REG_WUM8,
                                       val & ~(1 << 11));
        }
 
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       if (priv->eeprom.calib_version < EEPROM_TX_POWER_VERSION_NEW) {
-               IWL_ERROR("Older EEPROM detected!  Aborting.\n");
-               return -EINVAL;
-       }
-
        pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link);
 
-       /* disable L1 entry -- workaround for pre-B1 */
-       pci_write_config_byte(priv->pci_dev, PCI_LINK_CTRL, val_link & ~0x02);
+       /* L1 is enabled by BIOS */
+       if ((val_link & PCI_LINK_VAL_L1_EN) == PCI_LINK_VAL_L1_EN)
+               /* diable L0S disabled L1A enabled */
+               iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
+       else
+               /* L0S enabled L1A disabled */
+               iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
 
-       spin_lock_irqsave(&priv->lock, flags);
+       radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
 
-       /* set CSR_HW_CONFIG_REG for uCode use */
+       /* write radio config values to register */
+       if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) == EEPROM_4965_RF_CFG_TYPE_MAX)
+               iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+                           EEPROM_RF_CFG_TYPE_MSK(radio_cfg) |
+                           EEPROM_RF_CFG_STEP_MSK(radio_cfg) |
+                           EEPROM_RF_CFG_DASH_MSK(radio_cfg));
 
+       /* set CSR_HW_CONFIG_REG for uCode use */
        iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
-                   CSR49_HW_IF_CONFIG_REG_BIT_4965_R |
-                   CSR49_HW_IF_CONFIG_REG_BIT_RADIO_SI |
-                   CSR49_HW_IF_CONFIG_REG_BIT_MAC_SI);
-
-       rc = iwl_grab_nic_access(priv);
-       if (rc < 0) {
-               spin_unlock_irqrestore(&priv->lock, flags);
-               IWL_DEBUG_INFO("Failed to init the card\n");
-               return rc;
-       }
+                   CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
+                   CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
 
-       iwl_read_prph(priv, APMG_PS_CTRL_REG);
-       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);
+       priv->calib_info = (struct iwl_eeprom_calib_info *)
+               iwl_eeprom_query_addr(priv, EEPROM_4965_CALIB_TXPOWER_OFFSET);
 
-       iwl_release_nic_access(priv);
        spin_unlock_irqrestore(&priv->lock, flags);
-
-       iwl4965_hw_card_show_info(priv);
-
-       /* end nic_init */
-
-       /* Allocate the RX queue, or reset if it is already allocated */
-       if (!rxq->bd) {
-               rc = iwl4965_rx_queue_alloc(priv);
-               if (rc) {
-                       IWL_ERROR("Unable to initialize Rx queue\n");
-                       return -ENOMEM;
-               }
-       } else
-               iwl4965_rx_queue_reset(priv, rxq);
-
-       iwl4965_rx_replenish(priv);
-
-       iwl4965_rx_init(priv, rxq);
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       rxq->need_update = 1;
-       iwl4965_rx_queue_update_write_ptr(priv, rxq);
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       /* Allocate and init all Tx and Command queues */
-       rc = iwl4965_txq_ctx_reset(priv);
-       if (rc)
-               return rc;
-
-       if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_SW_RF_KILL_ENABLE)
-               IWL_DEBUG_RF_KILL("SW RF KILL supported in EEPROM.\n");
-
-       if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE)
-               IWL_DEBUG_RF_KILL("HW RF KILL supported in EEPROM.\n");
-
-       set_bit(STATUS_INIT, &priv->status);
-
-       return 0;
 }
 
-int iwl4965_hw_nic_stop_master(struct iwl_priv *priv)
+static int iwl4965_apm_stop_master(struct iwl_priv *priv)
 {
-       int rc = 0;
-       u32 reg_val;
+       int ret = 0;
        unsigned long flags;
 
        spin_lock_irqsave(&priv->lock, flags);
@@ -876,64 +527,24 @@ int iwl4965_hw_nic_stop_master(struct iwl_priv *priv)
        /* set stop master bit */
        iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
 
-       reg_val = iwl_read32(priv, CSR_GP_CNTRL);
-
-       if (CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE ==
-           (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE))
-               IWL_DEBUG_INFO("Card in power save, master is already "
-                              "stopped\n");
-       else {
-               rc = iwl_poll_bit(priv, CSR_RESET,
+       ret = iwl_poll_bit(priv, CSR_RESET,
                                  CSR_RESET_REG_FLAG_MASTER_DISABLED,
                                  CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
-               if (rc < 0) {
-                       spin_unlock_irqrestore(&priv->lock, flags);
-                       return rc;
-               }
-       }
+       if (ret < 0)
+               goto out;
 
+out:
        spin_unlock_irqrestore(&priv->lock, flags);
        IWL_DEBUG_INFO("stop master\n");
 
-       return rc;
-}
-
-/**
- * iwl4965_hw_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory
- */
-void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv)
-{
-
-       int txq_id;
-       unsigned long flags;
-
-       /* Stop each Tx DMA channel, and wait for it to be idle */
-       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
-               spin_lock_irqsave(&priv->lock, flags);
-               if (iwl_grab_nic_access(priv)) {
-                       spin_unlock_irqrestore(&priv->lock, flags);
-                       continue;
-               }
-
-               iwl_write_direct32(priv,
-                                  IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), 0x0);
-               iwl_poll_direct_bit(priv, IWL_FH_TSSR_TX_STATUS_REG,
-                                   IWL_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE
-                                   (txq_id), 200);
-               iwl_release_nic_access(priv);
-               spin_unlock_irqrestore(&priv->lock, flags);
-       }
-
-       /* Deallocate memory for all Tx queues */
-       iwl4965_hw_txq_ctx_free(priv);
+       return ret;
 }
 
-int iwl4965_hw_nic_reset(struct iwl_priv *priv)
+static void iwl4965_apm_stop(struct iwl_priv *priv)
 {
-       int rc = 0;
        unsigned long flags;
 
-       iwl4965_hw_nic_stop_master(priv);
+       iwl4965_apm_stop_master(priv);
 
        spin_lock_irqsave(&priv->lock, flags);
 
@@ -942,867 +553,192 @@ int iwl4965_hw_nic_reset(struct iwl_priv *priv)
        udelay(10);
 
        iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-       rc = iwl_poll_bit(priv, CSR_RESET,
-                         CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
-                         CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25);
-
-       udelay(10);
-
-       rc = iwl_grab_nic_access(priv);
-       if (!rc) {
-               iwl_write_prph(priv, APMG_CLK_EN_REG,
-                               APMG_CLK_VAL_DMA_CLK_RQT |
-                               APMG_CLK_VAL_BSM_CLK_RQT);
-
-               udelay(10);
-
-               iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
-                                       APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
-
-               iwl_release_nic_access(priv);
-       }
-
-       clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
-       wake_up_interruptible(&priv->wait_command_queue);
-
        spin_unlock_irqrestore(&priv->lock, flags);
-
-       return rc;
-
 }
 
-#define REG_RECALIB_PERIOD (60)
-
-/**
- * iwl4965_bg_statistics_periodic - Timer callback to queue statistics
- *
- * This callback is provided in order to send a statistics request.
- *
- * This timer function is continually reset to execute within
- * REG_RECALIB_PERIOD seconds since the last STATISTICS_NOTIFICATION
- * was received.  We need to ensure we receive the statistics in order
- * to update the temperature used for calibrating the TXPOWER.
- */
-static void iwl4965_bg_statistics_periodic(unsigned long data)
+static int iwl4965_apm_reset(struct iwl_priv *priv)
 {
-       struct iwl_priv *priv = (struct iwl_priv *)data;
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       iwl_send_statistics_request(priv, CMD_ASYNC);
-}
-
-#define CT_LIMIT_CONST         259
-#define TM_CT_KILL_THRESHOLD   110
-
-void iwl4965_rf_kill_ct_config(struct iwl_priv *priv)
-{
-       struct iwl4965_ct_kill_config cmd;
-       u32 R1, R2, R3;
-       u32 temp_th;
-       u32 crit_temperature;
-       unsigned long flags;
        int ret = 0;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
-                   CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       if (priv->statistics.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK) {
-               R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]);
-               R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]);
-               R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[1]);
-       } else {
-               R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[0]);
-               R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[0]);
-               R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[0]);
-       }
-
-       temp_th = CELSIUS_TO_KELVIN(TM_CT_KILL_THRESHOLD);
-
-       crit_temperature = ((temp_th * (R3-R1))/CT_LIMIT_CONST) + R2;
-       cmd.critical_temperature_R =  cpu_to_le32(crit_temperature);
-       ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
-                              sizeof(cmd), &cmd);
-       if (ret)
-               IWL_ERROR("REPLY_CT_KILL_CONFIG_CMD failed\n");
-       else
-               IWL_DEBUG_INFO("REPLY_CT_KILL_CONFIG_CMD succeeded\n");
-}
-
-#ifdef CONFIG_IWL4965_SENSITIVITY
-
-/* "false alarms" are signals that our DSP tries to lock onto,
- *   but then determines that they are either noise, or transmissions
- *   from a distant wireless network (also "noise", really) that get
- *   "stepped on" by stronger transmissions within our own network.
- * This algorithm attempts to set a sensitivity level that is high
- *   enough to receive all of our own network traffic, but not so
- *   high that our DSP gets too busy trying to lock onto non-network
- *   activity/noise. */
-static int iwl4965_sens_energy_cck(struct iwl_priv *priv,
-                                  u32 norm_fa,
-                                  u32 rx_enable_time,
-                                  struct statistics_general_data *rx_info)
-{
-       u32 max_nrg_cck = 0;
-       int i = 0;
-       u8 max_silence_rssi = 0;
-       u32 silence_ref = 0;
-       u8 silence_rssi_a = 0;
-       u8 silence_rssi_b = 0;
-       u8 silence_rssi_c = 0;
-       u32 val;
-
-       /* "false_alarms" values below are cross-multiplications to assess the
-        *   numbers of false alarms within the measured period of actual Rx
-        *   (Rx is off when we're txing), vs the min/max expected false alarms
-        *   (some should be expected if rx is sensitive enough) in a
-        *   hypothetical listening period of 200 time units (TU), 204.8 msec:
-        *
-        * MIN_FA/fixed-time < false_alarms/actual-rx-time < MAX_FA/beacon-time
-        *
-        * */
-       u32 false_alarms = norm_fa * 200 * 1024;
-       u32 max_false_alarms = MAX_FA_CCK * rx_enable_time;
-       u32 min_false_alarms = MIN_FA_CCK * rx_enable_time;
-       struct iwl4965_sensitivity_data *data = NULL;
-
-       data = &(priv->sensitivity_data);
-
-       data->nrg_auto_corr_silence_diff = 0;
-
-       /* Find max silence rssi among all 3 receivers.
-        * This is background noise, which may include transmissions from other
-        *    networks, measured during silence before our network's beacon */
-       silence_rssi_a = (u8)((rx_info->beacon_silence_rssi_a &
-                           ALL_BAND_FILTER) >> 8);
-       silence_rssi_b = (u8)((rx_info->beacon_silence_rssi_b &
-                           ALL_BAND_FILTER) >> 8);
-       silence_rssi_c = (u8)((rx_info->beacon_silence_rssi_c &
-                           ALL_BAND_FILTER) >> 8);
-
-       val = max(silence_rssi_b, silence_rssi_c);
-       max_silence_rssi = max(silence_rssi_a, (u8) val);
-
-       /* Store silence rssi in 20-beacon history table */
-       data->nrg_silence_rssi[data->nrg_silence_idx] = max_silence_rssi;
-       data->nrg_silence_idx++;
-       if (data->nrg_silence_idx >= NRG_NUM_PREV_STAT_L)
-               data->nrg_silence_idx = 0;
-
-       /* Find max silence rssi across 20 beacon history */
-       for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) {
-               val = data->nrg_silence_rssi[i];
-               silence_ref = max(silence_ref, val);
-       }
-       IWL_DEBUG_CALIB("silence a %u, b %u, c %u, 20-bcn max %u\n",
-                       silence_rssi_a, silence_rssi_b, silence_rssi_c,
-                       silence_ref);
-
-       /* Find max rx energy (min value!) among all 3 receivers,
-        *   measured during beacon frame.
-        * Save it in 10-beacon history table. */
-       i = data->nrg_energy_idx;
-       val = min(rx_info->beacon_energy_b, rx_info->beacon_energy_c);
-       data->nrg_value[i] = min(rx_info->beacon_energy_a, val);
-
-       data->nrg_energy_idx++;
-       if (data->nrg_energy_idx >= 10)
-               data->nrg_energy_idx = 0;
-
-       /* Find min rx energy (max value) across 10 beacon history.
-        * This is the minimum signal level that we want to receive well.
-        * Add backoff (margin so we don't miss slightly lower energy frames).
-        * This establishes an upper bound (min value) for energy threshold. */
-       max_nrg_cck = data->nrg_value[0];
-       for (i = 1; i < 10; i++)
-               max_nrg_cck = (u32) max(max_nrg_cck, (data->nrg_value[i]));
-       max_nrg_cck += 6;
-
-       IWL_DEBUG_CALIB("rx energy a %u, b %u, c %u, 10-bcn max/min %u\n",
-                       rx_info->beacon_energy_a, rx_info->beacon_energy_b,
-                       rx_info->beacon_energy_c, max_nrg_cck - 6);
-
-       /* Count number of consecutive beacons with fewer-than-desired
-        *   false alarms. */
-       if (false_alarms < min_false_alarms)
-               data->num_in_cck_no_fa++;
-       else
-               data->num_in_cck_no_fa = 0;
-       IWL_DEBUG_CALIB("consecutive bcns with few false alarms = %u\n",
-                       data->num_in_cck_no_fa);
-
-       /* If we got too many false alarms this time, reduce sensitivity */
-       if (false_alarms > max_false_alarms) {
-               IWL_DEBUG_CALIB("norm FA %u > max FA %u\n",
-                            false_alarms, max_false_alarms);
-               IWL_DEBUG_CALIB("... reducing sensitivity\n");
-               data->nrg_curr_state = IWL_FA_TOO_MANY;
-
-               if (data->auto_corr_cck > AUTO_CORR_MAX_TH_CCK) {
-                       /* Store for "fewer than desired" on later beacon */
-                       data->nrg_silence_ref = silence_ref;
-
-                       /* increase energy threshold (reduce nrg value)
-                        *   to decrease sensitivity */
-                       if (data->nrg_th_cck > (NRG_MAX_CCK + NRG_STEP_CCK))
-                               data->nrg_th_cck = data->nrg_th_cck
-                                                        - NRG_STEP_CCK;
-               }
-
-               /* increase auto_corr values to decrease sensitivity */
-               if (data->auto_corr_cck < AUTO_CORR_MAX_TH_CCK)
-                       data->auto_corr_cck = AUTO_CORR_MAX_TH_CCK + 1;
-               else {
-                       val = data->auto_corr_cck + AUTO_CORR_STEP_CCK;
-                       data->auto_corr_cck = min((u32)AUTO_CORR_MAX_CCK, val);
-               }
-               val = data->auto_corr_cck_mrc + AUTO_CORR_STEP_CCK;
-               data->auto_corr_cck_mrc = min((u32)AUTO_CORR_MAX_CCK_MRC, val);
-
-       /* Else if we got fewer than desired, increase sensitivity */
-       } else if (false_alarms < min_false_alarms) {
-               data->nrg_curr_state = IWL_FA_TOO_FEW;
-
-               /* Compare silence level with silence level for most recent
-                *   healthy number or too many false alarms */
-               data->nrg_auto_corr_silence_diff = (s32)data->nrg_silence_ref -
-                                                  (s32)silence_ref;
-
-               IWL_DEBUG_CALIB("norm FA %u < min FA %u, silence diff %d\n",
-                        false_alarms, min_false_alarms,
-                        data->nrg_auto_corr_silence_diff);
-
-               /* Increase value to increase sensitivity, but only if:
-                * 1a) previous beacon did *not* have *too many* false alarms
-                * 1b) AND there's a significant difference in Rx levels
-                *      from a previous beacon with too many, or healthy # FAs
-                * OR 2) We've seen a lot of beacons (100) with too few
-                *       false alarms */
-               if ((data->nrg_prev_state != IWL_FA_TOO_MANY) &&
-                       ((data->nrg_auto_corr_silence_diff > NRG_DIFF) ||
-                       (data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) {
-
-                       IWL_DEBUG_CALIB("... increasing sensitivity\n");
-                       /* Increase nrg value to increase sensitivity */
-                       val = data->nrg_th_cck + NRG_STEP_CCK;
-                       data->nrg_th_cck = min((u32)NRG_MIN_CCK, val);
-
-                       /* Decrease auto_corr values to increase sensitivity */
-                       val = data->auto_corr_cck - AUTO_CORR_STEP_CCK;
-                       data->auto_corr_cck = max((u32)AUTO_CORR_MIN_CCK, val);
-
-                       val = data->auto_corr_cck_mrc - AUTO_CORR_STEP_CCK;
-                       data->auto_corr_cck_mrc =
-                                        max((u32)AUTO_CORR_MIN_CCK_MRC, val);
-
-               } else
-                       IWL_DEBUG_CALIB("... but not changing sensitivity\n");
-
-       /* Else we got a healthy number of false alarms, keep status quo */
-       } else {
-               IWL_DEBUG_CALIB(" FA in safe zone\n");
-               data->nrg_curr_state = IWL_FA_GOOD_RANGE;
-
-               /* Store for use in "fewer than desired" with later beacon */
-               data->nrg_silence_ref = silence_ref;
-
-               /* If previous beacon had too many false alarms,
-                *   give it some extra margin by reducing sensitivity again
-                *   (but don't go below measured energy of desired Rx) */
-               if (IWL_FA_TOO_MANY == data->nrg_prev_state) {
-                       IWL_DEBUG_CALIB("... increasing margin\n");
-                       data->nrg_th_cck -= NRG_MARGIN;
-               }
-       }
-
-       /* Make sure the energy threshold does not go above the measured
-        * energy of the desired Rx signals (reduced by backoff margin),
-        * or else we might start missing Rx frames.
-        * Lower value is higher energy, so we use max()!
-        */
-       data->nrg_th_cck = max(max_nrg_cck, data->nrg_th_cck);
-       IWL_DEBUG_CALIB("new nrg_th_cck %u\n", data->nrg_th_cck);
-
-       data->nrg_prev_state = data->nrg_curr_state;
-
-       return 0;
-}
-
-
-static int iwl4965_sens_auto_corr_ofdm(struct iwl_priv *priv,
-                                      u32 norm_fa,
-                                      u32 rx_enable_time)
-{
-       u32 val;
-       u32 false_alarms = norm_fa * 200 * 1024;
-       u32 max_false_alarms = MAX_FA_OFDM * rx_enable_time;
-       u32 min_false_alarms = MIN_FA_OFDM * rx_enable_time;
-       struct iwl4965_sensitivity_data *data = NULL;
-
-       data = &(priv->sensitivity_data);
-
-       /* If we got too many false alarms this time, reduce sensitivity */
-       if (false_alarms > max_false_alarms) {
-
-               IWL_DEBUG_CALIB("norm FA %u > max FA %u)\n",
-                            false_alarms, max_false_alarms);
-
-               val = data->auto_corr_ofdm + AUTO_CORR_STEP_OFDM;
-               data->auto_corr_ofdm =
-                               min((u32)AUTO_CORR_MAX_OFDM, val);
-
-               val = data->auto_corr_ofdm_mrc + AUTO_CORR_STEP_OFDM;
-               data->auto_corr_ofdm_mrc =
-                               min((u32)AUTO_CORR_MAX_OFDM_MRC, val);
-
-               val = data->auto_corr_ofdm_x1 + AUTO_CORR_STEP_OFDM;
-               data->auto_corr_ofdm_x1 =
-                               min((u32)AUTO_CORR_MAX_OFDM_X1, val);
-
-               val = data->auto_corr_ofdm_mrc_x1 + AUTO_CORR_STEP_OFDM;
-               data->auto_corr_ofdm_mrc_x1 =
-                               min((u32)AUTO_CORR_MAX_OFDM_MRC_X1, val);
-       }
-
-       /* Else if we got fewer than desired, increase sensitivity */
-       else if (false_alarms < min_false_alarms) {
-
-               IWL_DEBUG_CALIB("norm FA %u < min FA %u\n",
-                            false_alarms, min_false_alarms);
-
-               val = data->auto_corr_ofdm - AUTO_CORR_STEP_OFDM;
-               data->auto_corr_ofdm =
-                               max((u32)AUTO_CORR_MIN_OFDM, val);
-
-               val = data->auto_corr_ofdm_mrc - AUTO_CORR_STEP_OFDM;
-               data->auto_corr_ofdm_mrc =
-                               max((u32)AUTO_CORR_MIN_OFDM_MRC, val);
-
-               val = data->auto_corr_ofdm_x1 - AUTO_CORR_STEP_OFDM;
-               data->auto_corr_ofdm_x1 =
-                               max((u32)AUTO_CORR_MIN_OFDM_X1, val);
-
-               val = data->auto_corr_ofdm_mrc_x1 - AUTO_CORR_STEP_OFDM;
-               data->auto_corr_ofdm_mrc_x1 =
-                               max((u32)AUTO_CORR_MIN_OFDM_MRC_X1, val);
-       }
-
-       else
-               IWL_DEBUG_CALIB("min FA %u < norm FA %u < max FA %u OK\n",
-                        min_false_alarms, false_alarms, max_false_alarms);
-
-       return 0;
-}
-
-static int iwl4965_sensitivity_callback(struct iwl_priv *priv,
-                                   struct iwl_cmd *cmd, struct sk_buff *skb)
-{
-       /* We didn't cache the SKB; let the caller free it */
-       return 1;
-}
-
-/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
-static int iwl4965_sensitivity_write(struct iwl_priv *priv, u8 flags)
-{
-       struct iwl4965_sensitivity_cmd cmd ;
-       struct iwl4965_sensitivity_data *data = NULL;
-       struct iwl_host_cmd cmd_out = {
-               .id = SENSITIVITY_CMD,
-               .len = sizeof(struct iwl4965_sensitivity_cmd),
-               .meta.flags = flags,
-               .data = &cmd,
-       };
-       int ret;
-
-       data = &(priv->sensitivity_data);
-
-       memset(&cmd, 0, sizeof(cmd));
-
-       cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX] =
-                               cpu_to_le16((u16)data->auto_corr_ofdm);
-       cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX] =
-                               cpu_to_le16((u16)data->auto_corr_ofdm_mrc);
-       cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX] =
-                               cpu_to_le16((u16)data->auto_corr_ofdm_x1);
-       cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX] =
-                               cpu_to_le16((u16)data->auto_corr_ofdm_mrc_x1);
-
-       cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX] =
-                               cpu_to_le16((u16)data->auto_corr_cck);
-       cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX] =
-                               cpu_to_le16((u16)data->auto_corr_cck_mrc);
-
-       cmd.table[HD_MIN_ENERGY_CCK_DET_INDEX] =
-                               cpu_to_le16((u16)data->nrg_th_cck);
-       cmd.table[HD_MIN_ENERGY_OFDM_DET_INDEX] =
-                               cpu_to_le16((u16)data->nrg_th_ofdm);
-
-       cmd.table[HD_BARKER_CORR_TH_ADD_MIN_INDEX] =
-                               __constant_cpu_to_le16(190);
-       cmd.table[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] =
-                               __constant_cpu_to_le16(390);
-       cmd.table[HD_OFDM_ENERGY_TH_IN_INDEX] =
-                               __constant_cpu_to_le16(62);
-
-       IWL_DEBUG_CALIB("ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n",
-                       data->auto_corr_ofdm, data->auto_corr_ofdm_mrc,
-                       data->auto_corr_ofdm_x1, data->auto_corr_ofdm_mrc_x1,
-                       data->nrg_th_ofdm);
-
-       IWL_DEBUG_CALIB("cck: ac %u mrc %u thresh %u\n",
-                       data->auto_corr_cck, data->auto_corr_cck_mrc,
-                       data->nrg_th_cck);
-
-       /* Update uCode's "work" table, and copy it to DSP */
-       cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE;
-
-       if (flags & CMD_ASYNC)
-               cmd_out.meta.u.callback = iwl4965_sensitivity_callback;
-
-       /* Don't send command to uCode if nothing has changed */
-       if (!memcmp(&cmd.table[0], &(priv->sensitivity_tbl[0]),
-                   sizeof(u16)*HD_TABLE_SIZE)) {
-               IWL_DEBUG_CALIB("No change in SENSITIVITY_CMD\n");
-               return 0;
-       }
-
-       /* Copy table for comparison next time */
-       memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]),
-              sizeof(u16)*HD_TABLE_SIZE);
-
-       ret = iwl_send_cmd(priv, &cmd_out);
-       if (ret)
-               IWL_ERROR("SENSITIVITY_CMD failed\n");
-
-       return ret;
-}
-
-void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, u8 force)
-{
-       struct iwl4965_sensitivity_data *data = NULL;
-       int i;
-       int ret  = 0;
-
-       IWL_DEBUG_CALIB("Start iwl4965_init_sensitivity\n");
-
-       if (force)
-               memset(&(priv->sensitivity_tbl[0]), 0,
-                       sizeof(u16)*HD_TABLE_SIZE);
-
-       /* Clear driver's sensitivity algo data */
-       data = &(priv->sensitivity_data);
-       memset(data, 0, sizeof(struct iwl4965_sensitivity_data));
-
-       data->num_in_cck_no_fa = 0;
-       data->nrg_curr_state = IWL_FA_TOO_MANY;
-       data->nrg_prev_state = IWL_FA_TOO_MANY;
-       data->nrg_silence_ref = 0;
-       data->nrg_silence_idx = 0;
-       data->nrg_energy_idx = 0;
-
-       for (i = 0; i < 10; i++)
-               data->nrg_value[i] = 0;
-
-       for (i = 0; i < NRG_NUM_PREV_STAT_L; i++)
-               data->nrg_silence_rssi[i] = 0;
-
-       data->auto_corr_ofdm = 90;
-       data->auto_corr_ofdm_mrc = 170;
-       data->auto_corr_ofdm_x1  = 105;
-       data->auto_corr_ofdm_mrc_x1 = 220;
-       data->auto_corr_cck = AUTO_CORR_CCK_MIN_VAL_DEF;
-       data->auto_corr_cck_mrc = 200;
-       data->nrg_th_cck = 100;
-       data->nrg_th_ofdm = 100;
-
-       data->last_bad_plcp_cnt_ofdm = 0;
-       data->last_fa_cnt_ofdm = 0;
-       data->last_bad_plcp_cnt_cck = 0;
-       data->last_fa_cnt_cck = 0;
-
-       /* Clear prior Sensitivity command data to force send to uCode */
-       if (force)
-               memset(&(priv->sensitivity_tbl[0]), 0,
-                   sizeof(u16)*HD_TABLE_SIZE);
-
-       ret |= iwl4965_sensitivity_write(priv, flags);
-       IWL_DEBUG_CALIB("<<return 0x%X\n", ret);
-
-       return;
-}
-
-
-/* Reset differential Rx gains in NIC to prepare for chain noise calibration.
- * Called after every association, but this runs only once!
- *  ... once chain noise is calibrated the first time, it's good forever.  */
-void iwl4965_chain_noise_reset(struct iwl_priv *priv)
-{
-       struct iwl4965_chain_noise_data *data = NULL;
-
-       data = &(priv->chain_noise_data);
-       if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
-               struct iwl4965_calibration_cmd cmd;
-
-               memset(&cmd, 0, sizeof(cmd));
-               cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD;
-               cmd.diff_gain_a = 0;
-               cmd.diff_gain_b = 0;
-               cmd.diff_gain_c = 0;
-               iwl_send_cmd_pdu_async(priv, REPLY_PHY_CALIBRATION_CMD,
-                                sizeof(cmd), &cmd, NULL);
-               msleep(4);
-               data->state = IWL_CHAIN_NOISE_ACCUMULATE;
-               IWL_DEBUG_CALIB("Run chain_noise_calibrate\n");
-       }
-       return;
-}
-
-/*
- * Accumulate 20 beacons of signal and noise statistics for each of
- *   3 receivers/antennas/rx-chains, then figure out:
- * 1)  Which antennas are connected.
- * 2)  Differential rx gain settings to balance the 3 receivers.
- */
-static void iwl4965_noise_calibration(struct iwl_priv *priv,
-                                     struct iwl4965_notif_statistics *stat_resp)
-{
-       struct iwl4965_chain_noise_data *data = NULL;
-       int ret = 0;
-
-       u32 chain_noise_a;
-       u32 chain_noise_b;
-       u32 chain_noise_c;
-       u32 chain_sig_a;
-       u32 chain_sig_b;
-       u32 chain_sig_c;
-       u32 average_sig[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
-       u32 average_noise[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
-       u32 max_average_sig;
-       u16 max_average_sig_antenna_i;
-       u32 min_average_noise = MIN_AVERAGE_NOISE_MAX_VALUE;
-       u16 min_average_noise_antenna_i = INITIALIZATION_VALUE;
-       u16 i = 0;
-       u16 chan_num = INITIALIZATION_VALUE;
-       u32 band = INITIALIZATION_VALUE;
-       u32 active_chains = 0;
        unsigned long flags;
-       struct statistics_rx_non_phy *rx_info = &(stat_resp->rx.general);
-
-       data = &(priv->chain_noise_data);
 
-       /* Accumulate just the first 20 beacons after the first association,
-        *   then we're done forever. */
-       if (data->state != IWL_CHAIN_NOISE_ACCUMULATE) {
-               if (data->state == IWL_CHAIN_NOISE_ALIVE)
-                       IWL_DEBUG_CALIB("Wait for noise calib reset\n");
-               return;
-       }
+       iwl4965_apm_stop_master(priv);
 
        spin_lock_irqsave(&priv->lock, flags);
-       if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
-               IWL_DEBUG_CALIB(" << Interference data unavailable\n");
-               spin_unlock_irqrestore(&priv->lock, flags);
-               return;
-       }
 
-       band = (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) ? 0 : 1;
-       chan_num = le16_to_cpu(priv->staging_rxon.channel);
+       iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
 
-       /* Make sure we accumulate data for just the associated channel
-        *   (even if scanning). */
-       if ((chan_num != (le32_to_cpu(stat_resp->flag) >> 16)) ||
-           ((STATISTICS_REPLY_FLG_BAND_24G_MSK ==
-            (stat_resp->flag & STATISTICS_REPLY_FLG_BAND_24G_MSK)) && band)) {
-               IWL_DEBUG_CALIB("Stats not from chan=%d, band=%d\n",
-                               chan_num, band);
-               spin_unlock_irqrestore(&priv->lock, flags);
-               return;
-       }
+       udelay(10);
 
-       /* Accumulate beacon statistics values across 20 beacons */
-       chain_noise_a = le32_to_cpu(rx_info->beacon_silence_rssi_a) &
-                               IN_BAND_FILTER;
-       chain_noise_b = le32_to_cpu(rx_info->beacon_silence_rssi_b) &
-                               IN_BAND_FILTER;
-       chain_noise_c = le32_to_cpu(rx_info->beacon_silence_rssi_c) &
-                               IN_BAND_FILTER;
+       /* FIXME: put here L1A -L0S w/a */
 
-       chain_sig_a = le32_to_cpu(rx_info->beacon_rssi_a) & IN_BAND_FILTER;
-       chain_sig_b = le32_to_cpu(rx_info->beacon_rssi_b) & IN_BAND_FILTER;
-       chain_sig_c = le32_to_cpu(rx_info->beacon_rssi_c) & IN_BAND_FILTER;
+       iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
 
-       spin_unlock_irqrestore(&priv->lock, flags);
+       ret = iwl_poll_bit(priv, CSR_RESET,
+                         CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+                         CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25);
 
-       data->beacon_count++;
-
-       data->chain_noise_a = (chain_noise_a + data->chain_noise_a);
-       data->chain_noise_b = (chain_noise_b + data->chain_noise_b);
-       data->chain_noise_c = (chain_noise_c + data->chain_noise_c);
-
-       data->chain_signal_a = (chain_sig_a + data->chain_signal_a);
-       data->chain_signal_b = (chain_sig_b + data->chain_signal_b);
-       data->chain_signal_c = (chain_sig_c + data->chain_signal_c);
-
-       IWL_DEBUG_CALIB("chan=%d, band=%d, beacon=%d\n", chan_num, band,
-                       data->beacon_count);
-       IWL_DEBUG_CALIB("chain_sig: a %d b %d c %d\n",
-                       chain_sig_a, chain_sig_b, chain_sig_c);
-       IWL_DEBUG_CALIB("chain_noise: a %d b %d c %d\n",
-                       chain_noise_a, chain_noise_b, chain_noise_c);
-
-       /* If this is the 20th beacon, determine:
-        * 1)  Disconnected antennas (using signal strengths)
-        * 2)  Differential gain (using silence noise) to balance receivers */
-       if (data->beacon_count == CAL_NUM_OF_BEACONS) {
-
-               /* Analyze signal for disconnected antenna */
-               average_sig[0] = (data->chain_signal_a) / CAL_NUM_OF_BEACONS;
-               average_sig[1] = (data->chain_signal_b) / CAL_NUM_OF_BEACONS;
-               average_sig[2] = (data->chain_signal_c) / CAL_NUM_OF_BEACONS;
-
-               if (average_sig[0] >= average_sig[1]) {
-                       max_average_sig = average_sig[0];
-                       max_average_sig_antenna_i = 0;
-                       active_chains = (1 << max_average_sig_antenna_i);
-               } else {
-                       max_average_sig = average_sig[1];
-                       max_average_sig_antenna_i = 1;
-                       active_chains = (1 << max_average_sig_antenna_i);
-               }
+       if (ret)
+               goto out;
 
-               if (average_sig[2] >= max_average_sig) {
-                       max_average_sig = average_sig[2];
-                       max_average_sig_antenna_i = 2;
-                       active_chains = (1 << max_average_sig_antenna_i);
-               }
+       udelay(10);
 
-               IWL_DEBUG_CALIB("average_sig: a %d b %d c %d\n",
-                            average_sig[0], average_sig[1], average_sig[2]);
-               IWL_DEBUG_CALIB("max_average_sig = %d, antenna %d\n",
-                            max_average_sig, max_average_sig_antenna_i);
-
-               /* Compare signal strengths for all 3 receivers. */
-               for (i = 0; i < NUM_RX_CHAINS; i++) {
-                       if (i != max_average_sig_antenna_i) {
-                               s32 rssi_delta = (max_average_sig -
-                                                 average_sig[i]);
-
-                               /* If signal is very weak, compared with
-                                * strongest, mark it as disconnected. */
-                               if (rssi_delta > MAXIMUM_ALLOWED_PATHLOSS)
-                                       data->disconn_array[i] = 1;
-                               else
-                                       active_chains |= (1 << i);
-                       IWL_DEBUG_CALIB("i = %d  rssiDelta = %d  "
-                                    "disconn_array[i] = %d\n",
-                                    i, rssi_delta, data->disconn_array[i]);
-                       }
-               }
+       ret = iwl_grab_nic_access(priv);
+       if (ret)
+               goto out;
+       /* Enable DMA and BSM Clock */
+       iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT |
+                                             APMG_CLK_VAL_BSM_CLK_RQT);
 
-               /*If both chains A & B are disconnected -
-                * connect B and leave A as is */
-               if (data->disconn_array[CHAIN_A] &&
-                   data->disconn_array[CHAIN_B]) {
-                       data->disconn_array[CHAIN_B] = 0;
-                       active_chains |= (1 << CHAIN_B);
-                       IWL_DEBUG_CALIB("both A & B chains are disconnected! "
-                                    "W/A - declare B as connected\n");
-               }
+       udelay(10);
 
-               IWL_DEBUG_CALIB("active_chains (bitwise) = 0x%x\n",
-                               active_chains);
+       /* disable L1A */
+       iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
+                         APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
 
-               /* Save for use within RXON, TX, SCAN commands, etc. */
-               priv->valid_antenna = active_chains;
+       iwl_release_nic_access(priv);
 
-               /* Analyze noise for rx balance */
-               average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS);
-               average_noise[1] = ((data->chain_noise_b)/CAL_NUM_OF_BEACONS);
-               average_noise[2] = ((data->chain_noise_c)/CAL_NUM_OF_BEACONS);
+       clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+       wake_up_interruptible(&priv->wait_command_queue);
 
-               for (i = 0; i < NUM_RX_CHAINS; i++) {
-                       if (!(data->disconn_array[i]) &&
-                          (average_noise[i] <= min_average_noise)) {
-                               /* This means that chain i is active and has
-                                * lower noise values so far: */
-                               min_average_noise = average_noise[i];
-                               min_average_noise_antenna_i = i;
-                       }
-               }
+out:
+       spin_unlock_irqrestore(&priv->lock, flags);
 
-               data->delta_gain_code[min_average_noise_antenna_i] = 0;
+       return ret;
+}
 
-               IWL_DEBUG_CALIB("average_noise: a %d b %d c %d\n",
-                               average_noise[0], average_noise[1],
-                               average_noise[2]);
+#define REG_RECALIB_PERIOD (60)
 
-               IWL_DEBUG_CALIB("min_average_noise = %d, antenna %d\n",
-                               min_average_noise, min_average_noise_antenna_i);
+/**
+ * iwl4965_bg_statistics_periodic - Timer callback to queue statistics
+ *
+ * This callback is provided in order to send a statistics request.
+ *
+ * This timer function is continually reset to execute within
+ * REG_RECALIB_PERIOD seconds since the last STATISTICS_NOTIFICATION
+ * was received.  We need to ensure we receive the statistics in order
+ * to update the temperature used for calibrating the TXPOWER.
+ */
+static void iwl4965_bg_statistics_periodic(unsigned long data)
+{
+       struct iwl_priv *priv = (struct iwl_priv *)data;
 
-               for (i = 0; i < NUM_RX_CHAINS; i++) {
-                       s32 delta_g = 0;
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
 
-                       if (!(data->disconn_array[i]) &&
-                           (data->delta_gain_code[i] ==
-                            CHAIN_NOISE_DELTA_GAIN_INIT_VAL)) {
-                               delta_g = average_noise[i] - min_average_noise;
-                               data->delta_gain_code[i] = (u8)((delta_g *
-                                                                   10) / 15);
-                               if (CHAIN_NOISE_MAX_DELTA_GAIN_CODE <
-                                  data->delta_gain_code[i])
-                                       data->delta_gain_code[i] =
-                                         CHAIN_NOISE_MAX_DELTA_GAIN_CODE;
-
-                               data->delta_gain_code[i] =
-                                       (data->delta_gain_code[i] | (1 << 2));
-                       } else
-                               data->delta_gain_code[i] = 0;
-               }
-               IWL_DEBUG_CALIB("delta_gain_codes: a %d b %d c %d\n",
-                            data->delta_gain_code[0],
-                            data->delta_gain_code[1],
-                            data->delta_gain_code[2]);
-
-               /* Differential gain gets sent to uCode only once */
-               if (!data->radio_write) {
-                       struct iwl4965_calibration_cmd cmd;
-                       data->radio_write = 1;
-
-                       memset(&cmd, 0, sizeof(cmd));
-                       cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD;
-                       cmd.diff_gain_a = data->delta_gain_code[0];
-                       cmd.diff_gain_b = data->delta_gain_code[1];
-                       cmd.diff_gain_c = data->delta_gain_code[2];
-                       ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
-                                             sizeof(cmd), &cmd);
-                       if (ret)
-                               IWL_DEBUG_CALIB("fail sending cmd "
-                                            "REPLY_PHY_CALIBRATION_CMD \n");
-
-                       /* TODO we might want recalculate
-                        * rx_chain in rxon cmd */
-
-                       /* Mark so we run this algo only once! */
-                       data->state = IWL_CHAIN_NOISE_CALIBRATED;
-               }
-               data->chain_noise_a = 0;
-               data->chain_noise_b = 0;
-               data->chain_noise_c = 0;
-               data->chain_signal_a = 0;
-               data->chain_signal_b = 0;
-               data->chain_signal_c = 0;
-               data->beacon_count = 0;
-       }
-       return;
+       iwl_send_statistics_request(priv, CMD_ASYNC);
 }
 
-static void iwl4965_sensitivity_calibration(struct iwl_priv *priv,
-                                           struct iwl4965_notif_statistics *resp)
+void iwl4965_rf_kill_ct_config(struct iwl_priv *priv)
 {
-       u32 rx_enable_time;
-       u32 fa_cck;
-       u32 fa_ofdm;
-       u32 bad_plcp_cck;
-       u32 bad_plcp_ofdm;
-       u32 norm_fa_ofdm;
-       u32 norm_fa_cck;
-       struct iwl4965_sensitivity_data *data = NULL;
-       struct statistics_rx_non_phy *rx_info = &(resp->rx.general);
-       struct statistics_rx *statistics = &(resp->rx);
+       struct iwl4965_ct_kill_config cmd;
        unsigned long flags;
-       struct statistics_general_data statis;
-       int ret;
-
-       data = &(priv->sensitivity_data);
-
-       if (!iwl_is_associated(priv)) {
-               IWL_DEBUG_CALIB("<< - not associated\n");
-               return;
-       }
+       int ret = 0;
 
        spin_lock_irqsave(&priv->lock, flags);
-       if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
-               IWL_DEBUG_CALIB("<< invalid data.\n");
-               spin_unlock_irqrestore(&priv->lock, flags);
-               return;
-       }
+       iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+                   CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+       spin_unlock_irqrestore(&priv->lock, flags);
 
-       /* Extract Statistics: */
-       rx_enable_time = le32_to_cpu(rx_info->channel_load);
-       fa_cck = le32_to_cpu(statistics->cck.false_alarm_cnt);
-       fa_ofdm = le32_to_cpu(statistics->ofdm.false_alarm_cnt);
-       bad_plcp_cck = le32_to_cpu(statistics->cck.plcp_err);
-       bad_plcp_ofdm = le32_to_cpu(statistics->ofdm.plcp_err);
-
-       statis.beacon_silence_rssi_a =
-                       le32_to_cpu(statistics->general.beacon_silence_rssi_a);
-       statis.beacon_silence_rssi_b =
-                       le32_to_cpu(statistics->general.beacon_silence_rssi_b);
-       statis.beacon_silence_rssi_c =
-                       le32_to_cpu(statistics->general.beacon_silence_rssi_c);
-       statis.beacon_energy_a =
-                       le32_to_cpu(statistics->general.beacon_energy_a);
-       statis.beacon_energy_b =
-                       le32_to_cpu(statistics->general.beacon_energy_b);
-       statis.beacon_energy_c =
-                       le32_to_cpu(statistics->general.beacon_energy_c);
+       cmd.critical_temperature_R =
+               cpu_to_le32(priv->hw_params.ct_kill_threshold);
 
-       spin_unlock_irqrestore(&priv->lock, flags);
+       ret = iwl_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD,
+                              sizeof(cmd), &cmd);
+       if (ret)
+               IWL_ERROR("REPLY_CT_KILL_CONFIG_CMD failed\n");
+       else
+               IWL_DEBUG_INFO("REPLY_CT_KILL_CONFIG_CMD succeeded, "
+                       "critical temperature is %d\n",
+                       cmd.critical_temperature_R);
+}
 
-       IWL_DEBUG_CALIB("rx_enable_time = %u usecs\n", rx_enable_time);
+#ifdef CONFIG_IWL4965_RUN_TIME_CALIB
 
-       if (!rx_enable_time) {
-               IWL_DEBUG_CALIB("<< RX Enable Time == 0! \n");
-               return;
-       }
+/* Reset differential Rx gains in NIC to prepare for chain noise calibration.
+ * Called after every association, but this runs only once!
+ *  ... once chain noise is calibrated the first time, it's good forever.  */
+static void iwl4965_chain_noise_reset(struct iwl_priv *priv)
+{
+       struct iwl_chain_noise_data *data = &(priv->chain_noise_data);
 
-       /* These statistics increase monotonically, and do not reset
-        *   at each beacon.  Calculate difference from last value, or just
-        *   use the new statistics value if it has reset or wrapped around. */
-       if (data->last_bad_plcp_cnt_cck > bad_plcp_cck)
-               data->last_bad_plcp_cnt_cck = bad_plcp_cck;
-       else {
-               bad_plcp_cck -= data->last_bad_plcp_cnt_cck;
-               data->last_bad_plcp_cnt_cck += bad_plcp_cck;
-       }
+       if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
+               struct iwl4965_calibration_cmd cmd;
 
-       if (data->last_bad_plcp_cnt_ofdm > bad_plcp_ofdm)
-               data->last_bad_plcp_cnt_ofdm = bad_plcp_ofdm;
-       else {
-               bad_plcp_ofdm -= data->last_bad_plcp_cnt_ofdm;
-               data->last_bad_plcp_cnt_ofdm += bad_plcp_ofdm;
+               memset(&cmd, 0, sizeof(cmd));
+               cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD;
+               cmd.diff_gain_a = 0;
+               cmd.diff_gain_b = 0;
+               cmd.diff_gain_c = 0;
+               if (iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
+                                sizeof(cmd), &cmd))
+                       IWL_ERROR("Could not send REPLY_PHY_CALIBRATION_CMD\n");
+               data->state = IWL_CHAIN_NOISE_ACCUMULATE;
+               IWL_DEBUG_CALIB("Run chain_noise_calibrate\n");
        }
+}
 
-       if (data->last_fa_cnt_ofdm > fa_ofdm)
-               data->last_fa_cnt_ofdm = fa_ofdm;
-       else {
-               fa_ofdm -= data->last_fa_cnt_ofdm;
-               data->last_fa_cnt_ofdm += fa_ofdm;
-       }
+static void iwl4965_gain_computation(struct iwl_priv *priv,
+               u32 *average_noise,
+               u16 min_average_noise_antenna_i,
+               u32 min_average_noise)
+{
+       int i, ret;
+       struct iwl_chain_noise_data *data = &priv->chain_noise_data;
 
-       if (data->last_fa_cnt_cck > fa_cck)
-               data->last_fa_cnt_cck = fa_cck;
-       else {
-               fa_cck -= data->last_fa_cnt_cck;
-               data->last_fa_cnt_cck += fa_cck;
-       }
+       data->delta_gain_code[min_average_noise_antenna_i] = 0;
 
-       /* Total aborted signal locks */
-       norm_fa_ofdm = fa_ofdm + bad_plcp_ofdm;
-       norm_fa_cck = fa_cck + bad_plcp_cck;
+       for (i = 0; i < NUM_RX_CHAINS; i++) {
+               s32 delta_g = 0;
 
-       IWL_DEBUG_CALIB("cck: fa %u badp %u  ofdm: fa %u badp %u\n", fa_cck,
-                       bad_plcp_cck, fa_ofdm, bad_plcp_ofdm);
+               if (!(data->disconn_array[i]) &&
+                   (data->delta_gain_code[i] ==
+                            CHAIN_NOISE_DELTA_GAIN_INIT_VAL)) {
+                       delta_g = average_noise[i] - min_average_noise;
+                       data->delta_gain_code[i] = (u8)((delta_g * 10) / 15);
+                       data->delta_gain_code[i] =
+                               min(data->delta_gain_code[i],
+                               (u8) CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
+
+                       data->delta_gain_code[i] =
+                               (data->delta_gain_code[i] | (1 << 2));
+               } else {
+                       data->delta_gain_code[i] = 0;
+               }
+       }
+       IWL_DEBUG_CALIB("delta_gain_codes: a %d b %d c %d\n",
+                    data->delta_gain_code[0],
+                    data->delta_gain_code[1],
+                    data->delta_gain_code[2]);
 
-       iwl4965_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time);
-       iwl4965_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis);
-       ret = iwl4965_sensitivity_write(priv, CMD_ASYNC);
+       /* Differential gain gets sent to uCode only once */
+       if (!data->radio_write) {
+               struct iwl4965_calibration_cmd cmd;
+               data->radio_write = 1;
 
-       return;
+               memset(&cmd, 0, sizeof(cmd));
+               cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD;
+               cmd.diff_gain_a = data->delta_gain_code[0];
+               cmd.diff_gain_b = data->delta_gain_code[1];
+               cmd.diff_gain_c = data->delta_gain_code[2];
+               ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
+                                     sizeof(cmd), &cmd);
+               if (ret)
+                       IWL_DEBUG_CALIB("fail sending cmd "
+                                    "REPLY_PHY_CALIBRATION_CMD \n");
+
+               /* TODO we might want recalculate
+                * rx_chain in rxon cmd */
+
+               /* Mark so we run this algo only once! */
+               data->state = IWL_CHAIN_NOISE_CALIBRATED;
+       }
+       data->chain_noise_a = 0;
+       data->chain_noise_b = 0;
+       data->chain_noise_c = 0;
+       data->chain_signal_a = 0;
+       data->chain_signal_b = 0;
+       data->chain_signal_c = 0;
+       data->beacon_count = 0;
 }
 
 static void iwl4965_bg_sensitivity_work(struct work_struct *work)
@@ -1819,21 +755,15 @@ static void iwl4965_bg_sensitivity_work(struct work_struct *work)
        }
 
        if (priv->start_calib) {
-               iwl4965_noise_calibration(priv, &priv->statistics);
-
-               if (priv->sensitivity_data.state ==
-                                       IWL_SENS_CALIB_NEED_REINIT) {
-                       iwl4965_init_sensitivity(priv, CMD_ASYNC, 0);
-                       priv->sensitivity_data.state = IWL_SENS_CALIB_ALLOWED;
-               } else
-                       iwl4965_sensitivity_calibration(priv,
-                                       &priv->statistics);
+               iwl_chain_noise_calibration(priv, &priv->statistics);
+
+               iwl_sensitivity_calibration(priv, &priv->statistics);
        }
 
        mutex_unlock(&priv->mutex);
        return;
 }
-#endif /*CONFIG_IWL4965_SENSITIVITY*/
+#endif /*CONFIG_IWL4965_RUN_TIME_CALIB*/
 
 static void iwl4965_bg_txpower_work(struct work_struct *work)
 {
@@ -1880,7 +810,7 @@ static void iwl4965_set_wr_ptrs(struct iwl_priv *priv, int txq_id, u32 index)
  * NOTE:  Acquire priv->lock before calling this function !
  */
 static void iwl4965_tx_queue_set_status(struct iwl_priv *priv,
-                                       struct iwl4965_tx_queue *txq,
+                                       struct iwl_tx_queue *txq,
                                        int tx_fifo_id, int scd_retry)
 {
        int txq_id = txq->q.id;
@@ -1890,11 +820,11 @@ static void iwl4965_tx_queue_set_status(struct iwl_priv *priv,
 
        /* Set up and activate */
        iwl_write_prph(priv, IWL49_SCD_QUEUE_STATUS_BITS(txq_id),
-                                (active << SCD_QUEUE_STTS_REG_POS_ACTIVE) |
-                                (tx_fifo_id << SCD_QUEUE_STTS_REG_POS_TXF) |
-                                (scd_retry << SCD_QUEUE_STTS_REG_POS_WSL) |
-                                (scd_retry << SCD_QUEUE_STTS_REG_POS_SCD_ACK) |
-                                SCD_QUEUE_STTS_REG_MSK);
+                        (active << IWL49_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
+                        (tx_fifo_id << IWL49_SCD_QUEUE_STTS_REG_POS_TXF) |
+                        (scd_retry << IWL49_SCD_QUEUE_STTS_REG_POS_WSL) |
+                        (scd_retry << IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACK) |
+                        IWL49_SCD_QUEUE_STTS_REG_MSK);
 
        txq->sched_retry = scd_retry;
 
@@ -1908,21 +838,11 @@ static const u16 default_queue_to_tx_fifo[] = {
        IWL_TX_FIFO_AC2,
        IWL_TX_FIFO_AC1,
        IWL_TX_FIFO_AC0,
-       IWL_CMD_FIFO_NUM,
+       IWL49_CMD_FIFO_NUM,
        IWL_TX_FIFO_HCCA_1,
        IWL_TX_FIFO_HCCA_2
 };
 
-static inline void iwl4965_txq_ctx_activate(struct iwl_priv *priv, int txq_id)
-{
-       set_bit(txq_id, &priv->txq_ctx_active_msk);
-}
-
-static inline void iwl4965_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id)
-{
-       clear_bit(txq_id, &priv->txq_ctx_active_msk);
-}
-
 int iwl4965_alive_notify(struct iwl_priv *priv)
 {
        u32 a;
@@ -1932,15 +852,6 @@ int iwl4965_alive_notify(struct iwl_priv *priv)
 
        spin_lock_irqsave(&priv->lock, flags);
 
-#ifdef CONFIG_IWL4965_SENSITIVITY
-       memset(&(priv->sensitivity_data), 0,
-              sizeof(struct iwl4965_sensitivity_data));
-       memset(&(priv->chain_noise_data), 0,
-              sizeof(struct iwl4965_chain_noise_data));
-       for (i = 0; i < NUM_RX_CHAINS; i++)
-               priv->chain_noise_data.delta_gain_code[i] =
-                               CHAIN_NOISE_DELTA_GAIN_INIT_VAL;
-#endif /* CONFIG_IWL4965_SENSITIVITY*/
        ret = iwl_grab_nic_access(priv);
        if (ret) {
                spin_unlock_irqrestore(&priv->lock, flags);
@@ -1949,10 +860,10 @@ int iwl4965_alive_notify(struct iwl_priv *priv)
 
        /* Clear 4965's internal Tx Scheduler data base */
        priv->scd_base_addr = iwl_read_prph(priv, IWL49_SCD_SRAM_BASE_ADDR);
-       a = priv->scd_base_addr + SCD_CONTEXT_DATA_OFFSET;
-       for (; a < priv->scd_base_addr + SCD_TX_STTS_BITMAP_OFFSET; a += 4)
+       a = priv->scd_base_addr + IWL49_SCD_CONTEXT_DATA_OFFSET;
+       for (; a < priv->scd_base_addr + IWL49_SCD_TX_STTS_BITMAP_OFFSET; a += 4)
                iwl_write_targ_mem(priv, a, 0);
-       for (; a < priv->scd_base_addr + SCD_TRANSLATE_TBL_OFFSET; a += 4)
+       for (; a < priv->scd_base_addr + IWL49_SCD_TRANSLATE_TBL_OFFSET; a += 4)
                iwl_write_targ_mem(priv, a, 0);
        for (; a < sizeof(u16) * priv->hw_params.max_txq_num; a += 4)
                iwl_write_targ_mem(priv, a, 0);
@@ -1974,45 +885,66 @@ int iwl4965_alive_notify(struct iwl_priv *priv)
 
                /* Max Tx Window size for Scheduler-ACK mode */
                iwl_write_targ_mem(priv, priv->scd_base_addr +
-                                       SCD_CONTEXT_QUEUE_OFFSET(i),
-                                       (SCD_WIN_SIZE <<
-                                       SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) &
-                                       SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK);
+                               IWL49_SCD_CONTEXT_QUEUE_OFFSET(i),
+                               (SCD_WIN_SIZE <<
+                               IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) &
+                               IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK);
 
                /* Frame limit */
                iwl_write_targ_mem(priv, priv->scd_base_addr +
-                                       SCD_CONTEXT_QUEUE_OFFSET(i) +
-                                       sizeof(u32),
-                                       (SCD_FRAME_LIMIT <<
-                                       SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
-                                       SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK);
+                               IWL49_SCD_CONTEXT_QUEUE_OFFSET(i) +
+                               sizeof(u32),
+                               (SCD_FRAME_LIMIT <<
+                               IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
+                               IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK);
 
        }
        iwl_write_prph(priv, IWL49_SCD_INTERRUPT_MASK,
                                 (1 << priv->hw_params.max_txq_num) - 1);
 
        /* Activate all Tx DMA/FIFO channels */
-       iwl_write_prph(priv, IWL49_SCD_TXFACT,
-                                SCD_TXFACT_REG_TXFIFO_MASK(0, 7));
+       priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7));
 
        iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
 
        /* Map each Tx/cmd queue to its corresponding fifo */
        for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) {
                int ac = default_queue_to_tx_fifo[i];
-               iwl4965_txq_ctx_activate(priv, i);
+               iwl_txq_ctx_activate(priv, i);
                iwl4965_tx_queue_set_status(priv, &priv->txq[i], ac, 0);
        }
 
        iwl_release_nic_access(priv);
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       /* Ask for statistics now, the uCode will send statistics notification
-        * periodically after association */
-       iwl_send_statistics_request(priv, CMD_ASYNC);
        return ret;
 }
 
+#ifdef CONFIG_IWL4965_RUN_TIME_CALIB
+static struct iwl_sensitivity_ranges iwl4965_sensitivity = {
+       .min_nrg_cck = 97,
+       .max_nrg_cck = 0,
+
+       .auto_corr_min_ofdm = 85,
+       .auto_corr_min_ofdm_mrc = 170,
+       .auto_corr_min_ofdm_x1 = 105,
+       .auto_corr_min_ofdm_mrc_x1 = 220,
+
+       .auto_corr_max_ofdm = 120,
+       .auto_corr_max_ofdm_mrc = 210,
+       .auto_corr_max_ofdm_x1 = 140,
+       .auto_corr_max_ofdm_mrc_x1 = 270,
+
+       .auto_corr_min_cck = 125,
+       .auto_corr_max_cck = 200,
+       .auto_corr_min_cck_mrc = 200,
+       .auto_corr_max_cck_mrc = 400,
+
+       .nrg_th_cck = 100,
+       .nrg_th_ofdm = 100,
+};
+#endif
+
 /**
  * iwl4965_hw_set_hw_params
  *
@@ -2021,15 +953,15 @@ int iwl4965_alive_notify(struct iwl_priv *priv)
 int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
 {
 
-       if ((priv->cfg->mod_params->num_of_queues > IWL4965_MAX_NUM_QUEUES) ||
+       if ((priv->cfg->mod_params->num_of_queues > IWL49_NUM_QUEUES) ||
            (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) {
                IWL_ERROR("invalid queues_num, should be between %d and %d\n",
-                         IWL_MIN_NUM_QUEUES, IWL4965_MAX_NUM_QUEUES);
+                         IWL_MIN_NUM_QUEUES, IWL49_NUM_QUEUES);
                return -EINVAL;
        }
 
        priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues;
-       priv->hw_params.tx_cmd_len = sizeof(struct iwl4965_tx_cmd);
+       priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto;
        priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
        priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
        if (priv->cfg->mod_params->amsdu_size_8K)
@@ -2040,90 +972,35 @@ int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
        priv->hw_params.max_stations = IWL4965_STATION_COUNT;
        priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID;
 
+       priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE;
+       priv->hw_params.max_inst_size = IWL49_RTC_INST_SIZE;
+       priv->hw_params.max_bsm_size = BSM_SRAM_SIZE;
+       priv->hw_params.fat_channel = BIT(IEEE80211_BAND_5GHZ);
+
        priv->hw_params.tx_chains_num = 2;
        priv->hw_params.rx_chains_num = 2;
-       priv->hw_params.valid_tx_ant = (IWL_ANTENNA_MAIN | IWL_ANTENNA_AUX);
-       priv->hw_params.valid_rx_ant = (IWL_ANTENNA_MAIN | IWL_ANTENNA_AUX);
-
-       return 0;
-}
-
-/**
- * iwl4965_hw_txq_ctx_free - Free TXQ Context
- *
- * Destroy all TX DMA queues and structures
- */
-void iwl4965_hw_txq_ctx_free(struct iwl_priv *priv)
-{
-       int txq_id;
+       priv->hw_params.valid_tx_ant = ANT_A | ANT_B;
+       priv->hw_params.valid_rx_ant = ANT_A | ANT_B;
+       priv->hw_params.ct_kill_threshold = CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD);
 
-       /* Tx queues */
-       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
-               iwl4965_tx_queue_free(priv, &priv->txq[txq_id]);
+#ifdef CONFIG_IWL4965_RUN_TIME_CALIB
+       priv->hw_params.sens = &iwl4965_sensitivity;
+#endif
 
-       /* Keep-warm buffer */
-       iwl4965_kw_free(priv);
+       return 0;
 }
 
-/**
- * iwl4965_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
- *
- * Does NOT advance any TFD circular buffer read/write indexes
- * Does NOT free the TFD itself (which is within circular buffer)
- */
-int iwl4965_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl4965_tx_queue *txq)
+/* set card power command */
+static int iwl4965_set_power(struct iwl_priv *priv,
+                     void *cmd)
 {
-       struct iwl4965_tfd_frame *bd_tmp = (struct iwl4965_tfd_frame *)&txq->bd[0];
-       struct iwl4965_tfd_frame *bd = &bd_tmp[txq->q.read_ptr];
-       struct pci_dev *dev = priv->pci_dev;
-       int i;
-       int counter = 0;
-       int index, is_odd;
-
-       /* Host command buffers stay mapped in memory, nothing to clean */
-       if (txq->q.id == IWL_CMD_QUEUE_NUM)
-               return 0;
-
-       /* Sanity check on number of chunks */
-       counter = IWL_GET_BITS(*bd, num_tbs);
-       if (counter > MAX_NUM_OF_TBS) {
-               IWL_ERROR("Too many chunks: %i\n", counter);
-               /* @todo issue fatal error, it is quite serious situation */
-               return 0;
-       }
+       int ret = 0;
 
-       /* Unmap chunks, if any.
-        * TFD info for odd chunks is different format than for even chunks. */
-       for (i = 0; i < counter; i++) {
-               index = i / 2;
-               is_odd = i & 0x1;
-
-               if (is_odd)
-                       pci_unmap_single(
-                               dev,
-                               IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) |
-                               (IWL_GET_BITS(bd->pa[index],
-                                             tb2_addr_hi20) << 16),
-                               IWL_GET_BITS(bd->pa[index], tb2_len),
-                               PCI_DMA_TODEVICE);
-
-               else if (i > 0)
-                       pci_unmap_single(dev,
-                                        le32_to_cpu(bd->pa[index].tb1_addr),
-                                        IWL_GET_BITS(bd->pa[index], tb1_len),
-                                        PCI_DMA_TODEVICE);
-
-               /* Free SKB, if any, for this chunk */
-               if (txq->txb[txq->q.read_ptr].skb[i]) {
-                       struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[i];
-
-                       dev_kfree_skb(skb);
-                       txq->txb[txq->q.read_ptr].skb[i] = NULL;
-               }
-       }
-       return 0;
+       ret = iwl_send_cmd_pdu_async(priv, POWER_TABLE_CMD,
+                                   sizeof(struct iwl4965_powertable_cmd),
+                                   cmd, NULL);
+       return ret;
 }
-
 int iwl4965_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
 {
        IWL_ERROR("TODO: Implement iwl4965_hw_reg_set_txpower!\n");
@@ -2224,11 +1101,11 @@ static u32 iwl4965_get_sub_band(const struct iwl_priv *priv, u32 channel)
        s32 b = -1;
 
        for (b = 0; b < EEPROM_TX_POWER_BANDS; b++) {
-               if (priv->eeprom.calib_info.band_info[b].ch_from == 0)
+               if (priv->calib_info->band_info[b].ch_from == 0)
                        continue;
 
-               if ((channel >= priv->eeprom.calib_info.band_info[b].ch_from)
-                   && (channel <= priv->eeprom.calib_info.band_info[b].ch_to))
+               if ((channel >= priv->calib_info->band_info[b].ch_from)
+                   && (channel <= priv->calib_info->band_info[b].ch_to))
                        break;
        }
 
@@ -2256,14 +1133,14 @@ static s32 iwl4965_interpolate_value(s32 x, s32 x1, s32 y1, s32 x2, s32 y2)
  * in channel number.
  */
 static int iwl4965_interpolate_chan(struct iwl_priv *priv, u32 channel,
-                                   struct iwl4965_eeprom_calib_ch_info *chan_info)
+                                   struct iwl_eeprom_calib_ch_info *chan_info)
 {
        s32 s = -1;
        u32 c;
        u32 m;
-       const struct iwl4965_eeprom_calib_measure *m1;
-       const struct iwl4965_eeprom_calib_measure *m2;
-       struct iwl4965_eeprom_calib_measure *omeas;
+       const struct iwl_eeprom_calib_measure *m1;
+       const struct iwl_eeprom_calib_measure *m2;
+       struct iwl_eeprom_calib_measure *omeas;
        u32 ch_i1;
        u32 ch_i2;
 
@@ -2273,8 +1150,8 @@ static int iwl4965_interpolate_chan(struct iwl_priv *priv, u32 channel,
                return -1;
        }
 
-       ch_i1 = priv->eeprom.calib_info.band_info[s].ch1.ch_num;
-       ch_i2 = priv->eeprom.calib_info.band_info[s].ch2.ch_num;
+       ch_i1 = priv->calib_info->band_info[s].ch1.ch_num;
+       ch_i2 = priv->calib_info->band_info[s].ch2.ch_num;
        chan_info->ch_num = (u8) channel;
 
        IWL_DEBUG_TXPOWER("channel %d subband %d factory cal ch %d & %d\n",
@@ -2282,9 +1159,9 @@ static int iwl4965_interpolate_chan(struct iwl_priv *priv, u32 channel,
 
        for (c = 0; c < EEPROM_TX_POWER_TX_CHAINS; c++) {
                for (m = 0; m < EEPROM_TX_POWER_MEASUREMENTS; m++) {
-                       m1 = &(priv->eeprom.calib_info.band_info[s].ch1.
+                       m1 = &(priv->calib_info->band_info[s].ch1.
                               measurements[c][m]);
-                       m2 = &(priv->eeprom.calib_info.band_info[s].ch2.
+                       m2 = &(priv->calib_info->band_info[s].ch2.
                               measurements[c][m]);
                        omeas = &(chan_info->measurements[c][m]);
 
@@ -2603,8 +1480,8 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
        int i;
        int c;
        const struct iwl_channel_info *ch_info = NULL;
-       struct iwl4965_eeprom_calib_ch_info ch_eeprom_info;
-       const struct iwl4965_eeprom_calib_measure *measurement;
+       struct iwl_eeprom_calib_ch_info ch_eeprom_info;
+       const struct iwl_eeprom_calib_measure *measurement;
        s16 voltage;
        s32 init_voltage;
        s32 voltage_compensation;
@@ -2661,9 +1538,9 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
        /* hardware txpower limits ...
         * saturation (clipping distortion) txpowers are in half-dBm */
        if (band)
-               saturation_power = priv->eeprom.calib_info.saturation_power24;
+               saturation_power = priv->calib_info->saturation_power24;
        else
-               saturation_power = priv->eeprom.calib_info.saturation_power52;
+               saturation_power = priv->calib_info->saturation_power52;
 
        if (saturation_power < IWL_TX_POWER_SATURATION_MIN ||
            saturation_power > IWL_TX_POWER_SATURATION_MAX) {
@@ -2693,7 +1570,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
        iwl4965_interpolate_chan(priv, channel, &ch_eeprom_info);
 
        /* calculate tx gain adjustment based on power supply voltage */
-       voltage = priv->eeprom.calib_info.voltage;
+       voltage = priv->calib_info->voltage;
        init_voltage = (s32)le32_to_cpu(priv->card_alive_init.voltage);
        voltage_compensation =
            iwl4965_get_voltage_compensation(voltage, init_voltage);
@@ -2888,8 +1765,8 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv)
 {
        int ret = 0;
        struct iwl4965_rxon_assoc_cmd rxon_assoc;
-       const struct iwl4965_rxon_cmd *rxon1 = &priv->staging_rxon;
-       const struct iwl4965_rxon_cmd *rxon2 = &priv->active_rxon;
+       const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
+       const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
 
        if ((rxon1->flags == rxon2->flags) &&
            (rxon1->filter_flags == rxon2->filter_flags) &&
@@ -2965,77 +1842,7 @@ int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
        return rc;
 }
 
-#define RTS_HCCA_RETRY_LIMIT           3
-#define RTS_DFAULT_RETRY_LIMIT         60
-
-void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv,
-                             struct iwl_cmd *cmd,
-                             struct ieee80211_tx_control *ctrl,
-                             struct ieee80211_hdr *hdr, int sta_id,
-                             int is_hcca)
-{
-       struct iwl4965_tx_cmd *tx = &cmd->cmd.tx;
-       u8 rts_retry_limit = 0;
-       u8 data_retry_limit = 0;
-       u16 fc = le16_to_cpu(hdr->frame_control);
-       u8 rate_plcp;
-       u16 rate_flags = 0;
-       int rate_idx = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1);
-
-       rate_plcp = iwl4965_rates[rate_idx].plcp;
-
-       rts_retry_limit = (is_hcca) ?
-           RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT;
-
-       if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
-               rate_flags |= RATE_MCS_CCK_MSK;
-
-
-       if (ieee80211_is_probe_response(fc)) {
-               data_retry_limit = 3;
-               if (data_retry_limit < rts_retry_limit)
-                       rts_retry_limit = data_retry_limit;
-       } else
-               data_retry_limit = IWL_DEFAULT_TX_RETRY;
-
-       if (priv->data_retry_limit != -1)
-               data_retry_limit = priv->data_retry_limit;
-
-
-       if (ieee80211_is_data(fc)) {
-               tx->initial_rate_index = 0;
-               tx->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
-       } else {
-               switch (fc & IEEE80211_FCTL_STYPE) {
-               case IEEE80211_STYPE_AUTH:
-               case IEEE80211_STYPE_DEAUTH:
-               case IEEE80211_STYPE_ASSOC_REQ:
-               case IEEE80211_STYPE_REASSOC_REQ:
-                       if (tx->tx_flags & TX_CMD_FLG_RTS_MSK) {
-                               tx->tx_flags &= ~TX_CMD_FLG_RTS_MSK;
-                               tx->tx_flags |= TX_CMD_FLG_CTS_MSK;
-                       }
-                       break;
-               default:
-                       break;
-               }
-
-               /* Alternate between antenna A and B for successive frames */
-               if (priv->use_ant_b_for_management_frame) {
-                       priv->use_ant_b_for_management_frame = 0;
-                       rate_flags |= RATE_MCS_ANT_B_MSK;
-               } else {
-                       priv->use_ant_b_for_management_frame = 1;
-                       rate_flags |= RATE_MCS_ANT_A_MSK;
-               }
-       }
-
-       tx->rts_retry_limit = rts_retry_limit;
-       tx->data_retry_limit = data_retry_limit;
-       tx->rate_n_flags = iwl4965_hw_set_rate_n_flags(rate_plcp, rate_flags);
-}
-
-int iwl4965_hw_get_rx_read(struct iwl_priv *priv)
+static int iwl4965_shared_mem_rx_idx(struct iwl_priv *priv)
 {
        struct iwl4965_shared *s = priv->shared_virt;
        return le32_to_cpu(s->rb_closed) & 0xFFF;
@@ -3047,7 +1854,7 @@ int iwl4965_hw_get_temperature(struct iwl_priv *priv)
 }
 
 unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
-                         struct iwl4965_frame *frame, u8 rate)
+                         struct iwl_frame *frame, u8 rate)
 {
        struct iwl4965_tx_beacon_cmd *tx_beacon_cmd;
        unsigned int frame_size;
@@ -3060,7 +1867,7 @@ unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
 
        frame_size = iwl4965_fill_beacon_frame(priv,
                                tx_beacon_cmd->frame,
-                               iwl4965_broadcast_addr,
+                               iwl_bcast_addr,
                                sizeof(frame->u) - sizeof(*tx_beacon_cmd));
 
        BUG_ON(frame_size > MAX_MPDU_SIZE);
@@ -3078,95 +1885,35 @@ unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
        return (sizeof(*tx_beacon_cmd) + frame_size);
 }
 
-/*
- * Tell 4965 where to find circular buffer of Tx Frame Descriptors for
- * given Tx queue, and enable the DMA channel used for that queue.
- *
- * 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA
- * channels supported in hardware.
- */
-int iwl4965_hw_tx_queue_init(struct iwl_priv *priv, struct iwl4965_tx_queue *txq)
-{
-       int rc;
-       unsigned long flags;
-       int txq_id = txq->q.id;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       rc = iwl_grab_nic_access(priv);
-       if (rc) {
-               spin_unlock_irqrestore(&priv->lock, flags);
-               return rc;
-       }
-
-       /* Circular buffer (TFD queue in DRAM) physical base address */
-       iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
-                            txq->q.dma_addr >> 8);
-
-       /* Enable DMA channel, using same id as for TFD queue */
-       iwl_write_direct32(
-               priv, IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id),
-               IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
-               IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL);
-       iwl_release_nic_access(priv);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       return 0;
-}
-
-int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,
-                                dma_addr_t addr, u16 len)
+static int iwl4965_alloc_shared_mem(struct iwl_priv *priv)
 {
-       int index, is_odd;
-       struct iwl4965_tfd_frame *tfd = ptr;
-       u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs);
-
-       /* Each TFD can point to a maximum 20 Tx buffers */
-       if ((num_tbs >= MAX_NUM_OF_TBS) || (num_tbs < 0)) {
-               IWL_ERROR("Error can not send more than %d chunks\n",
-                         MAX_NUM_OF_TBS);
-               return -EINVAL;
-       }
-
-       index = num_tbs / 2;
-       is_odd = num_tbs & 0x1;
+       priv->shared_virt = pci_alloc_consistent(priv->pci_dev,
+                                       sizeof(struct iwl4965_shared),
+                                       &priv->shared_phys);
+       if (!priv->shared_virt)
+               return -ENOMEM;
 
-       if (!is_odd) {
-               tfd->pa[index].tb1_addr = cpu_to_le32(addr);
-               IWL_SET_BITS(tfd->pa[index], tb1_addr_hi,
-                            iwl_get_dma_hi_address(addr));
-               IWL_SET_BITS(tfd->pa[index], tb1_len, len);
-       } else {
-               IWL_SET_BITS(tfd->pa[index], tb2_addr_lo16,
-                            (u32) (addr & 0xffff));
-               IWL_SET_BITS(tfd->pa[index], tb2_addr_hi20, addr >> 16);
-               IWL_SET_BITS(tfd->pa[index], tb2_len, len);
-       }
+       memset(priv->shared_virt, 0, sizeof(struct iwl4965_shared));
 
-       IWL_SET_BITS(*tfd, num_tbs, num_tbs + 1);
+       priv->rb_closed_offset = offsetof(struct iwl4965_shared, rb_closed);
 
        return 0;
 }
 
-static void iwl4965_hw_card_show_info(struct iwl_priv *priv)
+static void iwl4965_free_shared_mem(struct iwl_priv *priv)
 {
-       u16 hw_version = priv->eeprom.board_revision_4965;
-
-       IWL_DEBUG_INFO("4965ABGN HW Version %u.%u.%u\n",
-                      ((hw_version >> 8) & 0x0F),
-                      ((hw_version >> 8) >> 4), (hw_version & 0x00FF));
-
-       IWL_DEBUG_INFO("4965ABGN PBA Number %.16s\n",
-                      priv->eeprom.board_pba_number_4965);
+       if (priv->shared_virt)
+               pci_free_consistent(priv->pci_dev,
+                                   sizeof(struct iwl4965_shared),
+                                   priv->shared_virt,
+                                   priv->shared_phys);
 }
 
-#define IWL_TX_CRC_SIZE                4
-#define IWL_TX_DELIMITER_SIZE  4
-
 /**
  * iwl4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
  */
 static void iwl4965_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
-                                           struct iwl4965_tx_queue *txq,
+                                           struct iwl_tx_queue *txq,
                                            u16 byte_cnt)
 {
        int len;
@@ -3180,49 +1927,12 @@ static void iwl4965_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
                       tfd_offset[txq->q.write_ptr], byte_cnt, len);
 
        /* If within first 64 entries, duplicate at end */
-       if (txq->q.write_ptr < IWL4965_MAX_WIN_SIZE)
+       if (txq->q.write_ptr < IWL49_MAX_WIN_SIZE)
                IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
-                       tfd_offset[IWL4965_QUEUE_SIZE + txq->q.write_ptr],
+                       tfd_offset[IWL49_QUEUE_SIZE + txq->q.write_ptr],
                        byte_cnt, len);
 }
 
-/**
- * iwl4965_set_rxon_chain - Set up Rx chain usage in "staging" RXON image
- *
- * Selects how many and which Rx receivers/antennas/chains to use.
- * This should not be used for scan command ... it puts data in wrong place.
- */
-void iwl4965_set_rxon_chain(struct iwl_priv *priv)
-{
-       u8 is_single = is_single_stream(priv);
-       u8 idle_state, rx_state;
-
-       priv->staging_rxon.rx_chain = 0;
-       rx_state = idle_state = 3;
-
-       /* Tell uCode which antennas are actually connected.
-        * Before first association, we assume all antennas are connected.
-        * Just after first association, iwl4965_noise_calibration()
-        *    checks which antennas actually *are* connected. */
-       priv->staging_rxon.rx_chain |=
-           cpu_to_le16(priv->valid_antenna << RXON_RX_CHAIN_VALID_POS);
-
-       /* How many receivers should we use? */
-       iwl4965_get_rx_chain_counter(priv, &idle_state, &rx_state);
-       priv->staging_rxon.rx_chain |=
-               cpu_to_le16(rx_state << RXON_RX_CHAIN_MIMO_CNT_POS);
-       priv->staging_rxon.rx_chain |=
-               cpu_to_le16(idle_state << RXON_RX_CHAIN_CNT_POS);
-
-       if (!is_single && (rx_state >= 2) &&
-           !test_bit(STATUS_POWER_PMI, &priv->status))
-               priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
-       else
-               priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
-
-       IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain);
-}
-
 /**
  * sign_extend - Sign extend a value using specified bit as sign-bit
  *
@@ -3383,9 +2093,10 @@ static void iwl4965_rx_calc_noise(struct iwl_priv *priv)
                        priv->last_rx_noise);
 }
 
-void iwl4965_hw_rx_statistics(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb)
+void iwl4965_hw_rx_statistics(struct iwl_priv *priv,
+                             struct iwl_rx_mem_buffer *rxb)
 {
-       struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
        int change;
        s32 temp;
 
@@ -3412,7 +2123,7 @@ void iwl4965_hw_rx_statistics(struct iwl_priv *priv, struct iwl4965_rx_mem_buffe
        if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&
            (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {
                iwl4965_rx_calc_noise(priv);
-#ifdef CONFIG_IWL4965_SENSITIVITY
+#ifdef CONFIG_IWL4965_RUN_TIME_CALIB
                queue_work(priv->workqueue, &priv->sensitivity_work);
 #endif
        }
@@ -3455,7 +2166,7 @@ static void iwl4965_add_radiotap(struct iwl_priv *priv,
                                 struct ieee80211_rx_status *stats,
                                 u32 ampdu_status)
 {
-       s8 signal = stats->ssi;
+       s8 signal = stats->signal;
        s8 noise = 0;
        int rate = stats->rate_idx;
        u64 tsf = stats->mactime;
@@ -3529,7 +2240,7 @@ static void iwl4965_add_radiotap(struct iwl_priv *priv,
        if (rate == -1)
                iwl4965_rt->rt_rate = 0;
        else
-               iwl4965_rt->rt_rate = iwl4965_rates[rate].ieee;
+               iwl4965_rt->rt_rate = iwl_rates[rate].ieee;
 
        /*
         * "antenna number"
@@ -3562,7 +2273,54 @@ static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len)
        priv->rx_stats[idx].bytes += len;
 }
 
-static u32 iwl4965_translate_rx_status(u32 decrypt_in)
+/*
+ * returns non-zero if packet should be dropped
+ */
+static int iwl4965_set_decrypted_flag(struct iwl_priv *priv,
+                                     struct ieee80211_hdr *hdr,
+                                     u32 decrypt_res,
+                                     struct ieee80211_rx_status *stats)
+{
+       u16 fc = le16_to_cpu(hdr->frame_control);
+
+       if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK)
+               return 0;
+
+       if (!(fc & IEEE80211_FCTL_PROTECTED))
+               return 0;
+
+       IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res);
+       switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) {
+       case RX_RES_STATUS_SEC_TYPE_TKIP:
+               /* The uCode has got a bad phase 1 Key, pushes the packet.
+                * Decryption will be done in SW. */
+               if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+                   RX_RES_STATUS_BAD_KEY_TTAK)
+                       break;
+
+       case RX_RES_STATUS_SEC_TYPE_WEP:
+               if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+                   RX_RES_STATUS_BAD_ICV_MIC) {
+                       /* bad ICV, the packet is destroyed since the
+                        * decryption is inplace, drop it */
+                       IWL_DEBUG_RX("Packet destroyed\n");
+                       return -1;
+               }
+       case RX_RES_STATUS_SEC_TYPE_CCMP:
+               if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+                   RX_RES_STATUS_DECRYPT_OK) {
+                       IWL_DEBUG_RX("hw decrypt successfully!!!\n");
+                       stats->flag |= RX_FLAG_DECRYPTED;
+               }
+               break;
+
+       default:
+               break;
+       }
+       return 0;
+}
+
+static u32 iwl4965_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
 {
        u32 decrypt_out = 0;
 
@@ -3623,10 +2381,10 @@ static u32 iwl4965_translate_rx_status(u32 decrypt_in)
 
 static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
                                       int include_phy,
-                                      struct iwl4965_rx_mem_buffer *rxb,
+                                      struct iwl_rx_mem_buffer *rxb,
                                       struct ieee80211_rx_status *stats)
 {
-       struct iwl4965_rx_packet *pkt = (struct iwl4965_rx_packet *)rxb->skb->data;
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
        struct iwl4965_rx_phy_res *rx_start = (include_phy) ?
            (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : NULL;
        struct ieee80211_hdr *hdr;
@@ -3663,7 +2421,9 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
                rx_start->byte_count = amsdu->byte_count;
                rx_end = (__le32 *) (((u8 *) hdr) + len);
        }
-       if (len > priv->hw_params.max_pkt_size || len < 16) {
+       /* In monitor mode allow 802.11 ACk frames (10 bytes) */
+       if (len > priv->hw_params.max_pkt_size ||
+           len < ((priv->iw_mode == IEEE80211_IF_TYPE_MNTR) ? 10 : 16)) {
                IWL_WARNING("byte count out of range [16,4K] : %d\n", len);
                return;
        }
@@ -3674,7 +2434,7 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
        if (!include_phy) {
                /* New status scheme, need to translate */
                ampdu_status_legacy = ampdu_status;
-               ampdu_status = iwl4965_translate_rx_status(ampdu_status);
+               ampdu_status = iwl4965_translate_rx_status(priv, ampdu_status);
        }
 
        /* start from MAC */
@@ -3691,8 +2451,10 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
        stats->flag = 0;
        hdr = (struct ieee80211_hdr *)rxb->skb->data;
 
-       if (!priv->cfg->mod_params->sw_crypto)
-               iwl4965_set_decrypted_flag(priv, rxb->skb, ampdu_status, stats);
+       /*  in case of HW accelerated crypto and bad decryption, drop */
+       if (!priv->hw_params.sw_crypto &&
+           iwl4965_set_decrypted_flag(priv, hdr, ampdu_status, stats))
+               return;
 
        if (priv->add_radiotap)
                iwl4965_add_radiotap(priv, rxb->skb, rx_start, stats, ampdu_status);
@@ -3704,7 +2466,8 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
 }
 
 /* Calc max signal level (dBm) among 3 possible receivers */
-static int iwl4965_calc_rssi(struct iwl4965_rx_phy_res *rx_resp)
+static int iwl4965_calc_rssi(struct iwl_priv *priv,
+                            struct iwl4965_rx_phy_res *rx_resp)
 {
        /* data from PHY/DSP regarding signal strength, etc.,
         *   contents are always there, not configurable by host.  */
@@ -3737,38 +2500,6 @@ static int iwl4965_calc_rssi(struct iwl4965_rx_phy_res *rx_resp)
        return (max_rssi - agc - IWL_RSSI_OFFSET);
 }
 
-#ifdef CONFIG_IWL4965_HT
-
-void iwl4965_init_ht_hw_capab(struct iwl_priv *priv,
-                             struct ieee80211_ht_info *ht_info,
-                             enum ieee80211_band band)
-{
-       ht_info->cap = 0;
-       memset(ht_info->supp_mcs_set, 0, 16);
-
-       ht_info->ht_supported = 1;
-
-       if (band == IEEE80211_BAND_5GHZ) {
-               ht_info->cap |= (u16)IEEE80211_HT_CAP_SUP_WIDTH;
-               ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_40;
-               ht_info->supp_mcs_set[4] = 0x01;
-       }
-       ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD;
-       ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20;
-       ht_info->cap |= (u16)(IEEE80211_HT_CAP_MIMO_PS &
-                            (IWL_MIMO_PS_NONE << 2));
-
-       if (priv->cfg->mod_params->amsdu_size_8K)
-               ht_info->cap |= (u16)IEEE80211_HT_CAP_MAX_AMSDU;
-
-       ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
-       ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF;
-
-       ht_info->supp_mcs_set[0] = 0xFF;
-       ht_info->supp_mcs_set[1] = 0xFF;
-}
-#endif /* CONFIG_IWL4965_HT */
-
 static void iwl4965_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
 {
        unsigned long flags;
@@ -3780,13 +2511,13 @@ static void iwl4965_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
        priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-       iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+       iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
 }
 
 static void iwl4965_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
 {
        /* FIXME: need locking over ps_status ??? */
-       u8 sta_id = iwl4965_hw_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].
@@ -3813,7 +2544,7 @@ static void iwl4965_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
  *        proper operation with 4965.
  */
 static void iwl4965_dbg_report_frame(struct iwl_priv *priv,
-                     struct iwl4965_rx_packet *pkt,
+                     struct iwl_rx_packet *pkt,
                      struct ieee80211_hdr *header, int group100)
 {
        u32 to_us;
@@ -3840,7 +2571,7 @@ static void iwl4965_dbg_report_frame(struct iwl_priv *priv,
        struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt);
        u8 *data = IWL_RX_DATA(pkt);
 
-       if (likely(!(iwl_debug_level & IWL_DL_RX)))
+       if (likely(!(priv->debug_level & IWL_DL_RX)))
                return;
 
        /* MAC header */
@@ -3921,7 +2652,7 @@ static void iwl4965_dbg_report_frame(struct iwl_priv *priv,
                if (unlikely(rate_idx == -1))
                        bitrate = 0;
                else
-                       bitrate = iwl4965_rates[rate_idx].ieee / 2;
+                       bitrate = iwl_rates[rate_idx].ieee / 2;
 
                /* print frame summary.
                 * MAC addresses show just the last byte (for brevity),
@@ -3943,11 +2674,11 @@ static void iwl4965_dbg_report_frame(struct iwl_priv *priv,
                }
        }
        if (print_dump)
-               iwl_print_hex_dump(IWL_DL_RX, data, length);
+               iwl_print_hex_dump(priv, IWL_DL_RX, data, length);
 }
 #else
 static inline void iwl4965_dbg_report_frame(struct iwl_priv *priv,
-                                           struct iwl4965_rx_packet *pkt,
+                                           struct iwl_rx_packet *pkt,
                                            struct ieee80211_hdr *header,
                                            int group100)
 {
@@ -3958,12 +2689,12 @@ static inline void iwl4965_dbg_report_frame(struct iwl_priv *priv,
 
 /* Called for REPLY_RX (legacy ABG frames), or
  * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */
-static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
-                               struct iwl4965_rx_mem_buffer *rxb)
+void iwl4965_rx_reply_rx(struct iwl_priv *priv,
+                               struct iwl_rx_mem_buffer *rxb)
 {
        struct ieee80211_hdr *header;
        struct ieee80211_rx_status rx_status;
-       struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
        /* Use phy data (Rx signal strength, etc.) contained within
         *   this rx packet for legacy frames,
         *   or phy data cached from REPLY_RX_PHY_CMD for HT frames. */
@@ -4036,7 +2767,7 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
        priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp);
 
        /* Find max signal strength (dBm) among 3 antenna/receiver chains */
-       rx_status.ssi = iwl4965_calc_rssi(rx_start);
+       rx_status.signal = iwl4965_calc_rssi(priv, rx_start);
 
        /* Meaningful noise values are available only from beacon statistics,
         *   which are gathered only when associated, and indicate noise
@@ -4045,11 +2776,11 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
        if (iwl_is_associated(priv) &&
            !test_bit(STATUS_SCANNING, &priv->status)) {
                rx_status.noise = priv->last_rx_noise;
-               rx_status.signal = iwl4965_calc_sig_qual(rx_status.ssi,
+               rx_status.qual = iwl4965_calc_sig_qual(rx_status.signal,
                                                         rx_status.noise);
        } else {
                rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
-               rx_status.signal = iwl4965_calc_sig_qual(rx_status.ssi, 0);
+               rx_status.qual = iwl4965_calc_sig_qual(rx_status.signal, 0);
        }
 
        /* Reset beacon noise level if not associated. */
@@ -4061,12 +2792,19 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
        iwl4965_dbg_report_frame(priv, pkt, header, 1);
 
        IWL_DEBUG_STATS_LIMIT("Rssi %d, noise %d, qual %d, TSF %llu\n",
-                             rx_status.ssi, rx_status.noise, rx_status.signal,
+                             rx_status.signal, rx_status.noise, rx_status.signal,
                              (unsigned long long)rx_status.mactime);
 
+
+       if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
+               iwl4965_handle_data_packet(priv, 1, include_phy,
+                                                rxb, &rx_status);
+               return;
+       }
+
        network_packet = iwl4965_is_network_packet(priv, header);
        if (network_packet) {
-               priv->last_rx_rssi = rx_status.ssi;
+               priv->last_rx_rssi = rx_status.signal;
                priv->last_beacon_time =  priv->ucode_beacon_time;
                priv->last_tsf = le64_to_cpu(rx_start->timestamp);
        }
@@ -4125,57 +2863,8 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
        }
 }
 
-/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD).
- * This will be used later in iwl4965_rx_reply_rx() for REPLY_RX_MPDU_CMD. */
-static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv,
-                                   struct iwl4965_rx_mem_buffer *rxb)
-{
-       struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
-       priv->last_phy_res[0] = 1;
-       memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]),
-              sizeof(struct iwl4965_rx_phy_res));
-}
-static void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv,
-                                          struct iwl4965_rx_mem_buffer *rxb)
-
-{
-#ifdef CONFIG_IWL4965_SENSITIVITY
-       struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
-       struct iwl4965_missed_beacon_notif *missed_beacon;
-
-       missed_beacon = &pkt->u.missed_beacon;
-       if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) {
-               IWL_DEBUG_CALIB("missed bcn cnsq %d totl %d rcd %d expctd %d\n",
-                   le32_to_cpu(missed_beacon->consequtive_missed_beacons),
-                   le32_to_cpu(missed_beacon->total_missed_becons),
-                   le32_to_cpu(missed_beacon->num_recvd_beacons),
-                   le32_to_cpu(missed_beacon->num_expected_beacons));
-               priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT;
-               if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)))
-                       queue_work(priv->workqueue, &priv->sensitivity_work);
-       }
-#endif /*CONFIG_IWL4965_SENSITIVITY*/
-}
 #ifdef CONFIG_IWL4965_HT
 
-/**
- * iwl4965_sta_modify_enable_tid_tx - Enable Tx for this TID in station table
- */
-static void iwl4965_sta_modify_enable_tid_tx(struct iwl_priv *priv,
-                                        int sta_id, int tid)
-{
-       unsigned long flags;
-
-       /* Remove "disable" flag, to enable Tx for this TID */
-       spin_lock_irqsave(&priv->sta_lock, flags);
-       priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX;
-       priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid));
-       priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-       spin_unlock_irqrestore(&priv->sta_lock, flags);
-
-       iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
-}
-
 /**
  * iwl4965_tx_status_reply_compressed_ba - Update tx status from block-ack
  *
@@ -4183,7 +2872,7 @@ static void iwl4965_sta_modify_enable_tid_tx(struct iwl_priv *priv,
  * ACK vs. not.  This gets sent to mac80211, then to rate scaling algo.
  */
 static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv,
-                                                struct iwl4965_ht_agg *agg,
+                                                struct iwl_ht_agg *agg,
                                                 struct iwl4965_compressed_ba_resp*
                                                 ba_resp)
 
@@ -4193,7 +2882,7 @@ static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv,
        u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
        u64 bitmap;
        int successes = 0;
-       struct ieee80211_tx_status *tx_status;
+       struct ieee80211_tx_info *info;
 
        if (unlikely(!agg->wait_for_ba))  {
                IWL_ERROR("Received BA when not expected\n");
@@ -4231,13 +2920,13 @@ static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv,
                        agg->start_idx + i);
        }
 
-       tx_status = &priv->txq[scd_flow].txb[agg->start_idx].status;
-       tx_status->flags = IEEE80211_TX_STATUS_ACK;
-       tx_status->flags |= IEEE80211_TX_STATUS_AMPDU;
-       tx_status->ampdu_ack_map = successes;
-       tx_status->ampdu_ack_len = agg->frame_count;
-       iwl4965_hwrate_to_tx_control(priv, agg->rate_n_flags,
-                                    &tx_status->control);
+       info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]);
+       memset(&info->status, 0, sizeof(info->status));
+       info->flags = IEEE80211_TX_STAT_ACK;
+       info->flags |= IEEE80211_TX_STAT_AMPDU;
+       info->status.ampdu_ack_map = successes;
+       info->status.ampdu_ack_len = agg->frame_count;
+       iwl4965_hwrate_to_tx_control(priv, agg->rate_n_flags, info);
 
        IWL_DEBUG_TX_REPLY("Bitmap %llx\n", (unsigned long long)bitmap);
 
@@ -4254,16 +2943,16 @@ static void iwl4965_tx_queue_stop_scheduler(struct iwl_priv *priv,
         * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */
        iwl_write_prph(priv,
                IWL49_SCD_QUEUE_STATUS_BITS(txq_id),
-               (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
-               (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
+               (0 << IWL49_SCD_QUEUE_STTS_REG_POS_ACTIVE)|
+               (1 << IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
 }
 
 /**
  * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID
  * priv->lock must be held by the caller
  */
-static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id,
-                                       u16 ssn_idx, u8 tx_fifo)
+static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
+                                  u16 ssn_idx, u8 tx_fifo)
 {
        int ret = 0;
 
@@ -4287,7 +2976,7 @@ static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id,
        iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx);
 
        iwl_clear_bits_prph(priv, IWL49_SCD_INTERRUPT_MASK, (1 << txq_id));
-       iwl4965_txq_ctx_deactivate(priv, txq_id);
+       iwl_txq_ctx_deactivate(priv, txq_id);
        iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0);
 
        iwl_release_nic_access(priv);
@@ -4295,49 +2984,6 @@ static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id,
        return 0;
 }
 
-int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id,
-                                        u8 tid, int txq_id)
-{
-       struct iwl4965_queue *q = &priv->txq[txq_id].q;
-       u8 *addr = priv->stations[sta_id].sta.sta.addr;
-       struct iwl4965_tid_data *tid_data = &priv->stations[sta_id].tid[tid];
-
-       switch (priv->stations[sta_id].tid[tid].agg.state) {
-       case IWL_EMPTYING_HW_QUEUE_DELBA:
-               /* We are reclaiming the last packet of the */
-               /* aggregated HW queue */
-               if (txq_id  == tid_data->agg.txq_id &&
-                   q->read_ptr == q->write_ptr) {
-                       u16 ssn = SEQ_TO_SN(tid_data->seq_number);
-                       int tx_fifo = default_tid_to_tx_fifo[tid];
-                       IWL_DEBUG_HT("HW queue empty: continue DELBA flow\n");
-                       iwl4965_tx_queue_agg_disable(priv, txq_id,
-                                                    ssn, tx_fifo);
-                       tid_data->agg.state = IWL_AGG_OFF;
-                       ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, addr, tid);
-               }
-               break;
-       case IWL_EMPTYING_HW_QUEUE_ADDBA:
-               /* We are reclaiming the last packet of the queue */
-               if (tid_data->tfds_in_queue == 0) {
-                       IWL_DEBUG_HT("HW queue empty: continue ADDBA flow\n");
-                       tid_data->agg.state = IWL_AGG_ON;
-                       ieee80211_start_tx_ba_cb_irqsafe(priv->hw, addr, tid);
-               }
-               break;
-       }
-       return 0;
-}
-
-/**
- * iwl4965_queue_dec_wrap - Decrement queue index, wrap back to end if needed
- * @index -- current index
- * @n_bd -- total number of entries in queue (s/b power of 2)
- */
-static inline int iwl4965_queue_dec_wrap(int index, int n_bd)
-{
-       return (index == 0) ? n_bd - 1 : index - 1;
-}
 
 /**
  * iwl4965_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA
@@ -4346,13 +2992,13 @@ static inline int iwl4965_queue_dec_wrap(int index, int n_bd)
  * of frames sent via aggregation.
  */
 static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv,
-                                          struct iwl4965_rx_mem_buffer *rxb)
+                                          struct iwl_rx_mem_buffer *rxb)
 {
-       struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
        struct iwl4965_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba;
        int index;
-       struct iwl4965_tx_queue *txq = NULL;
-       struct iwl4965_ht_agg *agg;
+       struct iwl_tx_queue *txq = NULL;
+       struct iwl_ht_agg *agg;
        DECLARE_MAC_BUF(mac);
 
        /* "flow" corresponds to Tx queue */
@@ -4371,7 +3017,7 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv,
        agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg;
 
        /* Find index just before block-ack window */
-       index = iwl4965_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd);
+       index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd);
 
        /* TODO: Need to get this copy more safely - now good for debug */
 
@@ -4398,15 +3044,19 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv,
         * block-ack window (we assume that they've been successfully
         * transmitted ... if not, it's too late anyway). */
        if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) {
-               int freed = iwl4965_tx_queue_reclaim(priv, scd_flow, index);
+               /* calculate mac80211 ampdu sw queue to wake */
+               int ampdu_q =
+                  scd_flow - IWL_BACK_QUEUE_FIRST_ID + priv->hw->queues;
+               int freed = iwl_tx_queue_reclaim(priv, scd_flow, index);
                priv->stations[ba_resp->sta_id].
                        tid[ba_resp->tid].tfds_in_queue -= freed;
-               if (iwl4965_queue_space(&txq->q) > txq->q.low_mark &&
+               if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
                        priv->mac80211_registered &&
                        agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)
-                       ieee80211_wake_queue(priv->hw, scd_flow);
-               iwl4965_check_empty_hw_queue(priv, ba_resp->sta_id,
-                       ba_resp->tid, scd_flow);
+                       ieee80211_wake_queue(priv->hw, ampdu_q);
+
+               iwl_txq_check_empty(priv, ba_resp->sta_id,
+                                   ba_resp->tid, scd_flow);
        }
 }
 
@@ -4420,10 +3070,10 @@ static int iwl4965_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid,
        u32 tbl_dw;
        u16 scd_q2ratid;
 
-       scd_q2ratid = ra_tid & SCD_QUEUE_RA_TID_MAP_RATID_MSK;
+       scd_q2ratid = ra_tid & IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK;
 
        tbl_dw_addr = priv->scd_base_addr +
-                       SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id);
+                       IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id);
 
        tbl_dw = iwl_read_targ_mem(priv, tbl_dw_addr);
 
@@ -4444,12 +3094,11 @@ static int iwl4965_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid,
  * NOTE:  txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID,
  *        i.e. it must be one of the higher queues used for aggregation
  */
-static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id,
-                                      int tx_fifo, int sta_id, int tid,
-                                      u16 ssn_idx)
+static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id,
+                                 int tx_fifo, int sta_id, int tid, u16 ssn_idx)
 {
        unsigned long flags;
-       int rc;
+       int ret;
        u16 ra_tid;
 
        if (IWL_BACK_QUEUE_FIRST_ID > txq_id)
@@ -4459,13 +3108,13 @@ static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id,
        ra_tid = BUILD_RAxTID(sta_id, tid);
 
        /* Modify device's station table to Tx this TID */
-       iwl4965_sta_modify_enable_tid_tx(priv, sta_id, tid);
+       iwl_sta_modify_enable_tid_tx(priv, sta_id, tid);
 
        spin_lock_irqsave(&priv->lock, flags);
-       rc = iwl_grab_nic_access(priv);
-       if (rc) {
+       ret = iwl_grab_nic_access(priv);
+       if (ret) {
                spin_unlock_irqrestore(&priv->lock, flags);
-               return rc;
+               return ret;
        }
 
        /* Stop this Tx queue before configuring it */
@@ -4485,14 +3134,14 @@ static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id,
 
        /* Set up Tx window size and frame limit for this queue */
        iwl_write_targ_mem(priv,
-                       priv->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(txq_id),
-                       (SCD_WIN_SIZE << SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) &
-                       SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK);
+               priv->scd_base_addr + IWL49_SCD_CONTEXT_QUEUE_OFFSET(txq_id),
+               (SCD_WIN_SIZE << IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) &
+               IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK);
 
        iwl_write_targ_mem(priv, priv->scd_base_addr +
-                       SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32),
-                       (SCD_FRAME_LIMIT << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS)
-                       & SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK);
+               IWL49_SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32),
+               (SCD_FRAME_LIMIT << IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS)
+               & IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK);
 
        iwl_set_bits_prph(priv, IWL49_SCD_INTERRUPT_MASK, (1 << txq_id));
 
@@ -4507,209 +3156,17 @@ static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id,
 
 #endif /* CONFIG_IWL4965_HT */
 
-/**
- * iwl4965_add_station - Initialize a station's hardware rate table
- *
- * The uCode's station table contains a table of fallback rates
- * for automatic fallback during transmission.
- *
- * NOTE: This sets up a default set of values.  These will be replaced later
- *       if the driver's iwl-4965-rs rate scaling algorithm is used, instead of
- *       rc80211_simple.
- *
- * NOTE: Run REPLY_ADD_STA command to set up station table entry, before
- *       calling this function (which runs REPLY_TX_LINK_QUALITY_CMD,
- *       which requires station table entry to exist).
- */
-void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
-{
-       int i, r;
-       struct iwl_link_quality_cmd link_cmd = {
-               .reserved1 = 0,
-       };
-       u16 rate_flags;
-
-       /* Set up the rate scaling to start at selected rate, fall back
-        * all the way down to 1M in IEEE order, and then spin on 1M */
-       if (is_ap)
-               r = IWL_RATE_54M_INDEX;
-       else if (priv->band == IEEE80211_BAND_5GHZ)
-               r = IWL_RATE_6M_INDEX;
-       else
-               r = IWL_RATE_1M_INDEX;
-
-       for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
-               rate_flags = 0;
-               if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
-                       rate_flags |= RATE_MCS_CCK_MSK;
-
-               /* Use Tx antenna B only */
-               rate_flags |= RATE_MCS_ANT_B_MSK;
-               rate_flags &= ~RATE_MCS_ANT_A_MSK;
-
-               link_cmd.rs_table[i].rate_n_flags =
-                       iwl4965_hw_set_rate_n_flags(iwl4965_rates[r].plcp, rate_flags);
-               r = iwl4965_get_prev_ieee_rate(r);
-       }
-
-       link_cmd.general_params.single_stream_ant_msk = 2;
-       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);
-
-       /* Update the rate scaling for control frame Tx to AP */
-       link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id;
-
-       iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD,
-                              sizeof(link_cmd), &link_cmd, NULL);
-}
 
 #ifdef CONFIG_IWL4965_HT
-
-static u8 iwl4965_is_channel_extension(struct iwl_priv *priv,
-                                      enum ieee80211_band band,
-                                      u16 channel, u8 extension_chan_offset)
-{
-       const struct iwl_channel_info *ch_info;
-
-       ch_info = iwl_get_channel_info(priv, band, channel);
-       if (!is_channel_valid(ch_info))
-               return 0;
-
-       if (extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_NONE)
-               return 0;
-
-       if ((ch_info->fat_extension_channel == extension_chan_offset) ||
-           (ch_info->fat_extension_channel == HT_IE_EXT_CHANNEL_MAX))
-               return 1;
-
-       return 0;
-}
-
-static u8 iwl4965_is_fat_tx_allowed(struct iwl_priv *priv,
-                               struct ieee80211_ht_info *sta_ht_inf)
-{
-       struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config;
-
-       if ((!iwl_ht_conf->is_ht) ||
-          (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) ||
-          (iwl_ht_conf->extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_NONE))
-               return 0;
-
-       if (sta_ht_inf) {
-               if ((!sta_ht_inf->ht_supported) ||
-                  (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH)))
-                       return 0;
-       }
-
-       return (iwl4965_is_channel_extension(priv, priv->band,
-                                        iwl_ht_conf->control_channel,
-                                        iwl_ht_conf->extension_chan_offset));
-}
-
-void iwl4965_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
-{
-       struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon;
-       u32 val;
-
-       if (!ht_info->is_ht)
-               return;
-
-       /* Set up channel bandwidth:  20 MHz only, or 20/40 mixed if fat ok */
-       if (iwl4965_is_fat_tx_allowed(priv, NULL))
-               rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK;
-       else
-               rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
-                                RXON_FLG_CHANNEL_MODE_PURE_40_MSK);
-
-       if (le16_to_cpu(rxon->channel) != ht_info->control_channel) {
-               IWL_DEBUG_ASSOC("control diff than current %d %d\n",
-                               le16_to_cpu(rxon->channel),
-                               ht_info->control_channel);
-               rxon->channel = cpu_to_le16(ht_info->control_channel);
-               return;
-       }
-
-       /* Note: control channel is opposite of extension channel */
-       switch (ht_info->extension_chan_offset) {
-       case IWL_EXT_CHANNEL_OFFSET_ABOVE:
-               rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
-               break;
-       case IWL_EXT_CHANNEL_OFFSET_BELOW:
-               rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
-               break;
-       case IWL_EXT_CHANNEL_OFFSET_NONE:
-       default:
-               rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK;
-               break;
-       }
-
-       val = ht_info->ht_protection;
-
-       rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS);
-
-       iwl4965_set_rxon_chain(priv);
-
-       IWL_DEBUG_ASSOC("supported HT rate 0x%X %X "
-                       "rxon flags 0x%X operation mode :0x%X "
-                       "extension channel offset 0x%x "
-                       "control chan %d\n",
-                       ht_info->supp_mcs_set[0], ht_info->supp_mcs_set[1],
-                       le32_to_cpu(rxon->flags), ht_info->ht_protection,
-                       ht_info->extension_chan_offset,
-                       ht_info->control_channel);
-       return;
-}
-
-void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index,
-                               struct ieee80211_ht_info *sta_ht_inf)
-{
-       __le32 sta_flags;
-       u8 mimo_ps_mode;
-
-       if (!sta_ht_inf || !sta_ht_inf->ht_supported)
-               goto done;
-
-       mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2;
-
-       sta_flags = priv->stations[index].sta.station_flags;
-
-       sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK);
-
-       switch (mimo_ps_mode) {
-       case WLAN_HT_CAP_MIMO_PS_STATIC:
-               sta_flags |= STA_FLG_MIMO_DIS_MSK;
-               break;
-       case WLAN_HT_CAP_MIMO_PS_DYNAMIC:
-               sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK;
-               break;
-       case WLAN_HT_CAP_MIMO_PS_DISABLED:
-               break;
-       default:
-               IWL_WARNING("Invalid MIMO PS mode %d", mimo_ps_mode);
-               break;
-       }
-
-       sta_flags |= cpu_to_le32(
-             (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS);
-
-       sta_flags |= cpu_to_le32(
-             (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
-
-       if (iwl4965_is_fat_tx_allowed(priv, sta_ht_inf))
-               sta_flags |= STA_FLG_FAT_EN_MSK;
-       else
-               sta_flags &= ~STA_FLG_FAT_EN_MSK;
-
-       priv->stations[index].sta.station_flags = sta_flags;
- done:
-       return;
-}
-
-static void iwl4965_sta_modify_add_ba_tid(struct iwl_priv *priv,
-                                         int sta_id, int tid, u16 ssn)
+static int iwl4965_rx_agg_start(struct iwl_priv *priv,
+                               const u8 *addr, int tid, u16 ssn)
 {
        unsigned long flags;
+       int sta_id;
+
+       sta_id = iwl_find_station(priv, addr);
+       if (sta_id == IWL_INVALID_STATION)
+               return -ENXIO;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
        priv->stations[sta_id].sta.station_flags_msk = 0;
@@ -4719,13 +3176,19 @@ static void iwl4965_sta_modify_add_ba_tid(struct iwl_priv *priv,
        priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-       iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+       return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
+                                       CMD_ASYNC);
 }
 
-static void iwl4965_sta_modify_del_ba_tid(struct iwl_priv *priv,
-                                         int sta_id, int tid)
+static int iwl4965_rx_agg_stop(struct iwl_priv *priv,
+                              const u8 *addr, int tid)
 {
        unsigned long flags;
+       int sta_id;
+
+       sta_id = iwl_find_station(priv, addr);
+       if (sta_id == IWL_INVALID_STATION)
+               return -ENXIO;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
        priv->stations[sta_id].sta.station_flags_msk = 0;
@@ -4734,193 +3197,322 @@ static void iwl4965_sta_modify_del_ba_tid(struct iwl_priv *priv,
        priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-       iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
-}
-
-/*
- * Find first available (lowest unused) Tx Queue, mark it "active".
- * Called only when finding queue for aggregation.
- * Should never return anything < 7, because they should already
- * be in use as EDCA AC (0-3), Command (4), HCCA (5, 6).
- */
-static int iwl4965_txq_ctx_activate_free(struct iwl_priv *priv)
-{
-       int txq_id;
-
-       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
-               if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk))
-                       return txq_id;
-       return -1;
+       return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
+                                       CMD_ASYNC);
 }
 
-static int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, const u8 *da,
-                                      u16 tid, u16 *start_seq_num)
+int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
+                            enum ieee80211_ampdu_mlme_action action,
+                            const u8 *addr, u16 tid, u16 *ssn)
 {
        struct iwl_priv *priv = hw->priv;
-       int sta_id;
-       int tx_fifo;
-       int txq_id;
-       int ssn = -1;
-       int ret = 0;
-       unsigned long flags;
-       struct iwl4965_tid_data *tid_data;
        DECLARE_MAC_BUF(mac);
 
-       if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
-               tx_fifo = default_tid_to_tx_fifo[tid];
-       else
-               return -EINVAL;
+       IWL_DEBUG_HT("A-MPDU action on addr %s tid %d\n",
+                    print_mac(mac, addr), tid);
 
-       IWL_WARNING("%s on da = %s tid = %d\n",
-                       __func__, print_mac(mac, da), tid);
+       switch (action) {
+       case IEEE80211_AMPDU_RX_START:
+               IWL_DEBUG_HT("start Rx\n");
+               return iwl4965_rx_agg_start(priv, addr, tid, *ssn);
+       case IEEE80211_AMPDU_RX_STOP:
+               IWL_DEBUG_HT("stop Rx\n");
+               return iwl4965_rx_agg_stop(priv, addr, tid);
+       case IEEE80211_AMPDU_TX_START:
+               IWL_DEBUG_HT("start Tx\n");
+               return iwl_tx_agg_start(priv, addr, tid, ssn);
+       case IEEE80211_AMPDU_TX_STOP:
+               IWL_DEBUG_HT("stop Tx\n");
+               return iwl_tx_agg_stop(priv, addr, tid);
+       default:
+               IWL_DEBUG_HT("unknown\n");
+               return -EINVAL;
+               break;
+       }
+       return 0;
+}
+#endif /* CONFIG_IWL4965_HT */
 
-       sta_id = iwl4965_hw_find_station(priv, da);
-       if (sta_id == IWL_INVALID_STATION)
-               return -ENXIO;
 
-       if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) {
-               IWL_ERROR("Start AGG when state is not IWL_AGG_OFF !\n");
-               return -ENXIO;
+static u16 iwl4965_get_hcmd_size(u8 cmd_id, u16 len)
+{
+       switch (cmd_id) {
+       case REPLY_RXON:
+               return (u16) sizeof(struct iwl4965_rxon_cmd);
+       default:
+               return len;
        }
+}
 
-       txq_id = iwl4965_txq_ctx_activate_free(priv);
-       if (txq_id == -1)
-               return -ENXIO;
+static u16 iwl4965_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
+{
+       struct iwl4965_addsta_cmd *addsta = (struct iwl4965_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 = cmd->tid_disable_tx;
+       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;
+       addsta->reserved1 = __constant_cpu_to_le16(0);
+       addsta->reserved2 = __constant_cpu_to_le32(0);
 
-       spin_lock_irqsave(&priv->sta_lock, flags);
-       tid_data = &priv->stations[sta_id].tid[tid];
-       ssn = SEQ_TO_SN(tid_data->seq_number);
-       tid_data->agg.txq_id = txq_id;
-       spin_unlock_irqrestore(&priv->sta_lock, flags);
+       return (u16)sizeof(struct iwl4965_addsta_cmd);
+}
 
-       *start_seq_num = ssn;
-       ret = iwl4965_tx_queue_agg_enable(priv, txq_id, tx_fifo,
-                                         sta_id, tid, ssn);
-       if (ret)
-               return ret;
+#ifdef CONFIG_IWL4965_HT
+static inline u32 iwl4965_get_scd_ssn(struct iwl4965_tx_resp *tx_resp)
+{
+       __le32 *scd_ssn = (__le32 *)((u32 *)&tx_resp->status +
+                               tx_resp->frame_count);
+       return le32_to_cpu(*scd_ssn) & MAX_SN;
 
-       ret = 0;
-       if (tid_data->tfds_in_queue == 0) {
-               printk(KERN_ERR "HW queue is empty\n");
-               tid_data->agg.state = IWL_AGG_ON;
-               ieee80211_start_tx_ba_cb_irqsafe(hw, da, tid);
-       } else {
-               IWL_DEBUG_HT("HW queue is NOT empty: %d packets in HW queue\n",
-                               tid_data->tfds_in_queue);
-               tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
-       }
-       return ret;
 }
 
-static int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, const u8 *da,
-                                     u16 tid)
+/**
+ * iwl4965_tx_status_reply_tx - Handle Tx rspnse for frames in aggregation queue
+ */
+static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
+                                     struct iwl_ht_agg *agg,
+                                     struct iwl4965_tx_resp_agg *tx_resp,
+                                     u16 start_idx)
 {
+       u16 status;
+       struct agg_tx_status *frame_status = &tx_resp->status;
+       struct ieee80211_tx_info *info = NULL;
+       struct ieee80211_hdr *hdr = NULL;
+       int i, sh;
+       int txq_id, idx;
+       u16 seq;
+
+       if (agg->wait_for_ba)
+               IWL_DEBUG_TX_REPLY("got tx response w/o block-ack\n");
+
+       agg->frame_count = tx_resp->frame_count;
+       agg->start_idx = start_idx;
+       agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
+       agg->bitmap = 0;
+
+       /* # frames attempted by Tx command */
+       if (agg->frame_count == 1) {
+               /* Only one frame was attempted; no block-ack will arrive */
+               status = le16_to_cpu(frame_status[0].status);
+               seq  = le16_to_cpu(frame_status[0].sequence);
+               idx = SEQ_TO_INDEX(seq);
+               txq_id = SEQ_TO_QUEUE(seq);
+
+               /* FIXME: code repetition */
+               IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n",
+                                  agg->frame_count, agg->start_idx, idx);
+
+               info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
+               info->status.retry_count = tx_resp->failure_frame;
+               info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+               info->flags |= iwl_is_tx_success(status)?
+                       IEEE80211_TX_STAT_ACK : 0;
+               iwl4965_hwrate_to_tx_control(priv,
+                                            le32_to_cpu(tx_resp->rate_n_flags),
+                                            info);
+               /* FIXME: code repetition end */
+
+               IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n",
+                                   status & 0xff, tx_resp->failure_frame);
+               IWL_DEBUG_TX_REPLY("Rate Info rate_n_flags=%x\n",
+                       iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags));
+
+               agg->wait_for_ba = 0;
+       } else {
+               /* Two or more frames were attempted; expect block-ack */
+               u64 bitmap = 0;
+               int start = agg->start_idx;
+
+               /* Construct bit-map of pending frames within Tx window */
+               for (i = 0; i < agg->frame_count; i++) {
+                       u16 sc;
+                       status = le16_to_cpu(frame_status[i].status);
+                       seq  = le16_to_cpu(frame_status[i].sequence);
+                       idx = SEQ_TO_INDEX(seq);
+                       txq_id = SEQ_TO_QUEUE(seq);
+
+                       if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
+                                     AGG_TX_STATE_ABORT_MSK))
+                               continue;
+
+                       IWL_DEBUG_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n",
+                                          agg->frame_count, txq_id, idx);
+
+                       hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx);
+
+                       sc = le16_to_cpu(hdr->seq_ctrl);
+                       if (idx != (SEQ_TO_SN(sc) & 0xff)) {
+                               IWL_ERROR("BUG_ON idx doesn't match seq control"
+                                         " idx=%d, seq_idx=%d, seq=%d\n",
+                                         idx, SEQ_TO_SN(sc),
+                                         hdr->seq_ctrl);
+                               return -1;
+                       }
 
-       struct iwl_priv *priv = hw->priv;
-       int tx_fifo_id, txq_id, sta_id, ssn = -1;
-       struct iwl4965_tid_data *tid_data;
-       int ret, write_ptr, read_ptr;
-       unsigned long flags;
-       DECLARE_MAC_BUF(mac);
+                       IWL_DEBUG_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n",
+                                          i, idx, SEQ_TO_SN(sc));
+
+                       sh = idx - start;
+                       if (sh > 64) {
+                               sh = (start - idx) + 0xff;
+                               bitmap = bitmap << sh;
+                               sh = 0;
+                               start = idx;
+                       } else if (sh < -64)
+                               sh  = 0xff - (start - idx);
+                       else if (sh < 0) {
+                               sh = start - idx;
+                               start = idx;
+                               bitmap = bitmap << sh;
+                               sh = 0;
+                       }
+                       bitmap |= (1 << sh);
+                       IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%x\n",
+                                          start, (u32)(bitmap & 0xFFFFFFFF));
+               }
 
-       if (!da) {
-               IWL_ERROR("da = NULL\n");
-               return -EINVAL;
-       }
+               agg->bitmap = bitmap;
+               agg->start_idx = start;
+               agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
+               IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n",
+                                  agg->frame_count, agg->start_idx,
+                                  (unsigned long long)agg->bitmap);
 
-       if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
-               tx_fifo_id = default_tid_to_tx_fifo[tid];
-       else
-               return -EINVAL;
+               if (bitmap)
+                       agg->wait_for_ba = 1;
+       }
+       return 0;
+}
+#endif
 
-       sta_id = iwl4965_hw_find_station(priv, da);
+/**
+ * iwl4965_rx_reply_tx - Handle standard (non-aggregation) Tx response
+ */
+static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
+                               struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+       u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+       int txq_id = SEQ_TO_QUEUE(sequence);
+       int index = SEQ_TO_INDEX(sequence);
+       struct iwl_tx_queue *txq = &priv->txq[txq_id];
+       struct ieee80211_tx_info *info;
+       struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
+       u32  status = le32_to_cpu(tx_resp->status);
+#ifdef CONFIG_IWL4965_HT
+       int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION;
+       u16 fc;
+       struct ieee80211_hdr *hdr;
+       u8 *qc = NULL;
+#endif
 
-       if (sta_id == IWL_INVALID_STATION)
-               return -ENXIO;
+       if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
+               IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
+                         "is out of range [0-%d] %d %d\n", txq_id,
+                         index, txq->q.n_bd, txq->q.write_ptr,
+                         txq->q.read_ptr);
+               return;
+       }
 
-       if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON)
-               IWL_WARNING("Stopping AGG while state not IWL_AGG_ON\n");
+       info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
+       memset(&info->status, 0, sizeof(info->status));
 
-       tid_data = &priv->stations[sta_id].tid[tid];
-       ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4;
-       txq_id = tid_data->agg.txq_id;
-       write_ptr = priv->txq[txq_id].q.write_ptr;
-       read_ptr = priv->txq[txq_id].q.read_ptr;
+#ifdef CONFIG_IWL4965_HT
+       hdr = iwl_tx_queue_get_hdr(priv, txq_id, index);
+       fc = le16_to_cpu(hdr->frame_control);
+       if (ieee80211_is_qos_data(fc)) {
+               qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc));
+               tid = qc[0] & 0xf;
+       }
 
-       /* The queue is not empty */
-       if (write_ptr != read_ptr) {
-               IWL_DEBUG_HT("Stopping a non empty AGG HW QUEUE\n");
-               priv->stations[sta_id].tid[tid].agg.state =
-                               IWL_EMPTYING_HW_QUEUE_DELBA;
-               return 0;
+       sta_id = iwl_get_ra_sta_id(priv, hdr);
+       if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) {
+               IWL_ERROR("Station not known\n");
+               return;
        }
 
-       IWL_DEBUG_HT("HW queue empty\n");;
-       priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
+       if (txq->sched_retry) {
+               const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp);
+               struct iwl_ht_agg *agg = NULL;
 
-       spin_lock_irqsave(&priv->lock, flags);
-       ret = iwl4965_tx_queue_agg_disable(priv, txq_id, ssn, tx_fifo_id);
-       spin_unlock_irqrestore(&priv->lock, flags);
+               if (!qc)
+                       return;
 
-       if (ret)
-               return ret;
+               agg = &priv->stations[sta_id].tid[tid].agg;
 
-       ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, da, tid);
+               iwl4965_tx_status_reply_tx(priv, agg,
+                               (struct iwl4965_tx_resp_agg *)tx_resp, index);
 
-       IWL_DEBUG_INFO("iwl4965_mac_ht_tx_agg_stop on da=%s tid=%d\n",
-                       print_mac(mac, da), tid);
+               if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status)) {
+                       /* TODO: send BAR */
+               }
 
-       return 0;
-}
+               if (txq->q.read_ptr != (scd_ssn & 0xff)) {
+                       int freed, ampdu_q;
+                       index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
+                       IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn "
+                                          "%d index %d\n", scd_ssn , index);
+                       freed = iwl_tx_queue_reclaim(priv, txq_id, index);
+                       priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+
+                       if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
+                           txq_id >= 0 && priv->mac80211_registered &&
+                           agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) {
+                               /* calculate mac80211 ampdu sw queue to wake */
+                               ampdu_q = txq_id - IWL_BACK_QUEUE_FIRST_ID +
+                                         priv->hw->queues;
+                               if (agg->state == IWL_AGG_OFF)
+                                       ieee80211_wake_queue(priv->hw, txq_id);
+                               else
+                                       ieee80211_wake_queue(priv->hw, ampdu_q);
+                       }
+                       iwl_txq_check_empty(priv, sta_id, tid, txq_id);
+               }
+       } else {
+#endif /* CONFIG_IWL4965_HT */
 
-int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
-                            enum ieee80211_ampdu_mlme_action action,
-                            const u8 *addr, u16 tid, u16 *ssn)
-{
-       struct iwl_priv *priv = hw->priv;
-       int sta_id;
-       DECLARE_MAC_BUF(mac);
+       info->status.retry_count = tx_resp->failure_frame;
+       info->flags |= iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0;
+       iwl4965_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags),
+                                    info);
 
-       IWL_DEBUG_HT("A-MPDU action on da=%s tid=%d ",
-                       print_mac(mac, addr), tid);
-       sta_id = iwl4965_hw_find_station(priv, addr);
-       switch (action) {
-       case IEEE80211_AMPDU_RX_START:
-               IWL_DEBUG_HT("start Rx\n");
-               iwl4965_sta_modify_add_ba_tid(priv, sta_id, tid, *ssn);
-               break;
-       case IEEE80211_AMPDU_RX_STOP:
-               IWL_DEBUG_HT("stop Rx\n");
-               iwl4965_sta_modify_del_ba_tid(priv, sta_id, tid);
-               break;
-       case IEEE80211_AMPDU_TX_START:
-               IWL_DEBUG_HT("start Tx\n");
-               return iwl4965_mac_ht_tx_agg_start(hw, addr, tid, ssn);
-       case IEEE80211_AMPDU_TX_STOP:
-               IWL_DEBUG_HT("stop Tx\n");
-               return iwl4965_mac_ht_tx_agg_stop(hw, addr, tid);
-       default:
-               IWL_DEBUG_HT("unknown\n");
-               return -EINVAL;
-               break;
+       IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x "
+                    "retries %d\n", txq_id, iwl_get_tx_fail_reason(status),
+                    status, le32_to_cpu(tx_resp->rate_n_flags),
+                    tx_resp->failure_frame);
+
+       IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
+#ifdef CONFIG_IWL4965_HT
+       if (index != -1) {
+               int freed = iwl_tx_queue_reclaim(priv, txq_id, index);
+               if (tid != MAX_TID_COUNT)
+                       priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+               if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
+                       (txq_id >= 0) && priv->mac80211_registered)
+                       ieee80211_wake_queue(priv->hw, txq_id);
+               if (tid != MAX_TID_COUNT)
+                       iwl_txq_check_empty(priv, sta_id, tid, txq_id);
        }
-       return 0;
+       }
+#endif /* CONFIG_IWL4965_HT */
+
+       if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
+               IWL_ERROR("TODO:  Implement Tx ABORT REQUIRED!!!\n");
 }
 
-#endif /* CONFIG_IWL4965_HT */
 
 /* Set up 4965-specific Rx frame reply handlers */
-void iwl4965_hw_rx_handler_setup(struct iwl_priv *priv)
+static void iwl4965_rx_handler_setup(struct iwl_priv *priv)
 {
        /* Legacy Rx frames */
        priv->rx_handlers[REPLY_RX] = iwl4965_rx_reply_rx;
-
-       /* High-throughput (HT) Rx frames */
-       priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl4965_rx_reply_rx_phy;
-       priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl4965_rx_reply_rx;
-
-       priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] =
-           iwl4965_rx_missed_beacon_notif;
+       /* Tx response */
+       priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx;
 
 #ifdef CONFIG_IWL4965_HT
        priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl4965_rx_reply_compressed_ba;
@@ -4930,7 +3522,7 @@ void iwl4965_hw_rx_handler_setup(struct iwl_priv *priv)
 void iwl4965_hw_setup_deferred_work(struct iwl_priv *priv)
 {
        INIT_WORK(&priv->txpower_work, iwl4965_bg_txpower_work);
-#ifdef CONFIG_IWL4965_SENSITIVITY
+#ifdef CONFIG_IWL4965_RUN_TIME_CALIB
        INIT_WORK(&priv->sensitivity_work, iwl4965_bg_sensitivity_work);
 #endif
        init_timer(&priv->statistics_periodic);
@@ -4951,23 +3543,56 @@ static struct iwl_hcmd_ops iwl4965_hcmd = {
 };
 
 static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
-       .enqueue_hcmd = iwl4965_enqueue_hcmd,
+       .get_hcmd_size = iwl4965_get_hcmd_size,
+       .build_addsta_hcmd = iwl4965_build_addsta_hcmd,
+#ifdef CONFIG_IWL4965_RUN_TIME_CALIB
+       .chain_noise_reset = iwl4965_chain_noise_reset,
+       .gain_computation = iwl4965_gain_computation,
+#endif
 };
 
 static struct iwl_lib_ops iwl4965_lib = {
-       .init_drv = iwl4965_init_drv,
        .set_hw_params = iwl4965_hw_set_hw_params,
+       .alloc_shared_mem = iwl4965_alloc_shared_mem,
+       .free_shared_mem = iwl4965_free_shared_mem,
+       .shared_mem_rx_idx = iwl4965_shared_mem_rx_idx,
        .txq_update_byte_cnt_tbl = iwl4965_txq_update_byte_cnt_tbl,
-       .hw_nic_init = iwl4965_hw_nic_init,
+       .txq_set_sched = iwl4965_txq_set_sched,
+#ifdef CONFIG_IWL4965_HT
+       .txq_agg_enable = iwl4965_txq_agg_enable,
+       .txq_agg_disable = iwl4965_txq_agg_disable,
+#endif
+       .rx_handler_setup = iwl4965_rx_handler_setup,
        .is_valid_rtc_data_addr = iwl4965_hw_valid_rtc_data_addr,
        .alive_notify = iwl4965_alive_notify,
+       .init_alive_start = iwl4965_init_alive_start,
        .load_ucode = iwl4965_load_bsm,
+       .apm_ops = {
+               .init = iwl4965_apm_init,
+               .reset = iwl4965_apm_reset,
+               .stop = iwl4965_apm_stop,
+               .config = iwl4965_nic_config,
+               .set_pwr_src = iwl4965_set_pwr_src,
+       },
        .eeprom_ops = {
+               .regulatory_bands = {
+                       EEPROM_REGULATORY_BAND_1_CHANNELS,
+                       EEPROM_REGULATORY_BAND_2_CHANNELS,
+                       EEPROM_REGULATORY_BAND_3_CHANNELS,
+                       EEPROM_REGULATORY_BAND_4_CHANNELS,
+                       EEPROM_REGULATORY_BAND_5_CHANNELS,
+                       EEPROM_4965_REGULATORY_BAND_24_FAT_CHANNELS,
+                       EEPROM_4965_REGULATORY_BAND_52_FAT_CHANNELS
+               },
                .verify_signature  = iwlcore_eeprom_verify_signature,
                .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
                .release_semaphore = iwlcore_eeprom_release_semaphore,
+               .check_version = iwl4965_eeprom_check_version,
+               .query_addr = iwlcore_eeprom_query_addr,
        },
        .radio_kill_sw = iwl4965_radio_kill_sw,
+       .set_power = iwl4965_set_power,
+       .update_chain_flags = iwl4965_update_chain_flags,
 };
 
 static struct iwl_ops iwl4965_ops = {
@@ -4980,6 +3605,7 @@ struct iwl_cfg iwl4965_agn_cfg = {
        .name = "4965AGN",
        .fw_name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode",
        .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+       .eeprom_size = IWL4965_EEPROM_IMG_SIZE,
        .ops = &iwl4965_ops,
        .mod_params = &iwl4965_mod_params,
 };
@@ -5004,4 +3630,5 @@ module_param_named(qos_enable, iwl4965_mod_params.enable_qos, int, 0444);
 MODULE_PARM_DESC(qos_enable, "enable all QoS functionality");
 module_param_named(amsdu_size_8K, iwl4965_mod_params.amsdu_size_8K, int, 0444);
 MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size");
-
+module_param_named(fw_restart4965, iwl4965_mod_params.restart_fw, int, 0444);
+MODULE_PARM_DESC(fw_restart4965, "restart firmware in case of error");
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
new file mode 100644 (file)
index 0000000..9e557ce
--- /dev/null
@@ -0,0 +1,133 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+/*
+ * Please use this file (iwl-5000-hw.h) only for hardware-related definitions.
+ * Use iwl-5000-commands.h for uCode API definitions.
+ */
+
+#ifndef __iwl_5000_hw_h__
+#define __iwl_5000_hw_h__
+
+#define IWL50_RTC_INST_UPPER_BOUND             (0x020000)
+#define IWL50_RTC_DATA_UPPER_BOUND             (0x80C000)
+#define IWL50_RTC_INST_SIZE (IWL50_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND)
+#define IWL50_RTC_DATA_SIZE (IWL50_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND)
+
+/* EERPROM */
+#define IWL_5000_EEPROM_IMG_SIZE                       2048
+
+
+#define IWL50_MAX_WIN_SIZE                64
+#define IWL50_QUEUE_SIZE                 256
+#define IWL50_CMD_FIFO_NUM                 7
+#define IWL50_NUM_QUEUES                  20
+#define IWL50_BACK_QUEUE_FIRST_ID         10
+
+#define IWL_sta_id_POS 12
+#define IWL_sta_id_LEN 4
+#define IWL_sta_id_SYM val
+
+/* Fixed (non-configurable) rx data from phy */
+
+/* Base physical address of iwl5000_shared is provided to SCD_DRAM_BASE_ADDR
+ * and &iwl5000_shared.val0 is provided to FH_RSCSR_CHNL0_STTS_WPTR_REG */
+struct iwl5000_sched_queue_byte_cnt_tbl {
+       struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL50_QUEUE_SIZE +
+                                                      IWL50_MAX_WIN_SIZE];
+} __attribute__ ((packed));
+
+struct iwl5000_shared {
+       struct iwl5000_sched_queue_byte_cnt_tbl
+        queues_byte_cnt_tbls[IWL50_NUM_QUEUES];
+       __le32 rb_closed;
+
+       /* __le32 rb_closed_stts_rb_num:12; */
+#define IWL_rb_closed_stts_rb_num_POS 0
+#define IWL_rb_closed_stts_rb_num_LEN 12
+#define IWL_rb_closed_stts_rb_num_SYM rb_closed
+       /* __le32 rsrv1:4; */
+       /* __le32 rb_closed_stts_rx_frame_num:12; */
+#define IWL_rb_closed_stts_rx_frame_num_POS 16
+#define IWL_rb_closed_stts_rx_frame_num_LEN 12
+#define IWL_rb_closed_stts_rx_frame_num_SYM rb_closed
+       /* __le32 rsrv2:4; */
+
+       __le32 frm_finished;
+       /* __le32 frame_finished_stts_rb_num:12; */
+#define IWL_frame_finished_stts_rb_num_POS 0
+#define IWL_frame_finished_stts_rb_num_LEN 12
+#define IWL_frame_finished_stts_rb_num_SYM frm_finished
+       /* __le32 rsrv3:4; */
+       /* __le32 frame_finished_stts_rx_frame_num:12; */
+#define IWL_frame_finished_stts_rx_frame_num_POS 16
+#define IWL_frame_finished_stts_rx_frame_num_LEN 12
+#define IWL_frame_finished_stts_rx_frame_num_SYM frm_finished
+       /* __le32 rsrv4:4; */
+
+       __le32 padding1;  /* so that allocation will be aligned to 16B */
+       __le32 padding2;
+} __attribute__ ((packed));
+
+
+#endif /* __iwl_5000_hw_h__ */
+
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
new file mode 100644 (file)
index 0000000..7e525ad
--- /dev/null
@@ -0,0 +1,1417 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007-2008 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <net/mac80211.h>
+#include <linux/etherdevice.h>
+#include <asm/unaligned.h>
+
+#include "iwl-eeprom.h"
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-io.h"
+#include "iwl-helpers.h"
+#include "iwl-5000-hw.h"
+
+#define IWL5000_UCODE_API  "-1"
+
+static const u16 iwl5000_default_queue_to_tx_fifo[] = {
+       IWL_TX_FIFO_AC3,
+       IWL_TX_FIFO_AC2,
+       IWL_TX_FIFO_AC1,
+       IWL_TX_FIFO_AC0,
+       IWL50_CMD_FIFO_NUM,
+       IWL_TX_FIFO_HCCA_1,
+       IWL_TX_FIFO_HCCA_2
+};
+
+/* FIXME: same implementation as 4965 */
+static int iwl5000_apm_stop_master(struct iwl_priv *priv)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       /* set stop master bit */
+       iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
+
+       ret = iwl_poll_bit(priv, CSR_RESET,
+                                 CSR_RESET_REG_FLAG_MASTER_DISABLED,
+                                 CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
+       if (ret < 0)
+               goto out;
+
+out:
+       spin_unlock_irqrestore(&priv->lock, flags);
+       IWL_DEBUG_INFO("stop master\n");
+
+       return ret;
+}
+
+
+static int iwl5000_apm_init(struct iwl_priv *priv)
+{
+       int ret = 0;
+
+       iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+                   CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+
+       /* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */
+       iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+                   CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
+
+       iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL);
+
+       /* set "initialization complete" bit to move adapter
+        * D0U* --> D0A* state */
+       iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+
+       /* wait for clock stabilization */
+       ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
+                         CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+                         CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+       if (ret < 0) {
+               IWL_DEBUG_INFO("Failed to init the card\n");
+               return ret;
+       }
+
+       ret = iwl_grab_nic_access(priv);
+       if (ret)
+               return ret;
+
+       /* enable DMA */
+       iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
+
+       udelay(20);
+
+       /* disable L1-Active */
+       iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
+                         APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+
+       iwl_release_nic_access(priv);
+
+       return ret;
+}
+
+/* FIXME: this is indentical to 4965 */
+static void iwl5000_apm_stop(struct iwl_priv *priv)
+{
+       unsigned long flags;
+
+       iwl5000_apm_stop_master(priv);
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+
+       udelay(10);
+
+       iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+
+static int iwl5000_apm_reset(struct iwl_priv *priv)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       iwl5000_apm_stop_master(priv);
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+
+       udelay(10);
+
+
+       /* FIXME: put here L1A -L0S w/a */
+
+       iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL);
+
+       /* set "initialization complete" bit to move adapter
+        * D0U* --> D0A* state */
+       iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+
+       /* wait for clock stabilization */
+       ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
+                         CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+                         CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+       if (ret < 0) {
+               IWL_DEBUG_INFO("Failed to init the card\n");
+               goto out;
+       }
+
+       ret = iwl_grab_nic_access(priv);
+       if (ret)
+               goto out;
+
+       /* enable DMA */
+       iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
+
+       udelay(20);
+
+       /* disable L1-Active */
+       iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
+                         APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+
+       iwl_release_nic_access(priv);
+
+out:
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return ret;
+}
+
+
+static void iwl5000_nic_config(struct iwl_priv *priv)
+{
+       unsigned long flags;
+       u16 radio_cfg;
+       u8 val_link;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link);
+
+       /* L1 is enabled by BIOS */
+       if ((val_link & PCI_LINK_VAL_L1_EN) == PCI_LINK_VAL_L1_EN)
+               /* diable L0S disabled L1A enabled */
+               iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
+       else
+               /* L0S enabled L1A disabled */
+               iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
+
+       radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
+
+       /* write radio config values to register */
+       if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) < EEPROM_5000_RF_CFG_TYPE_MAX)
+               iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+                           EEPROM_RF_CFG_TYPE_MSK(radio_cfg) |
+                           EEPROM_RF_CFG_STEP_MSK(radio_cfg) |
+                           EEPROM_RF_CFG_DASH_MSK(radio_cfg));
+
+       /* set CSR_HW_CONFIG_REG for uCode use */
+       iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+                   CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
+                   CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+
+
+/*
+ * EEPROM
+ */
+static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address)
+{
+       u16 offset = 0;
+
+       if ((address & INDIRECT_ADDRESS) == 0)
+               return address;
+
+       switch (address & INDIRECT_TYPE_MSK) {
+       case INDIRECT_HOST:
+               offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_HOST);
+               break;
+       case INDIRECT_GENERAL:
+               offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_GENERAL);
+               break;
+       case INDIRECT_REGULATORY:
+               offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_REGULATORY);
+               break;
+       case INDIRECT_CALIBRATION:
+               offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_CALIBRATION);
+               break;
+       case INDIRECT_PROCESS_ADJST:
+               offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_PROCESS_ADJST);
+               break;
+       case INDIRECT_OTHERS:
+               offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_OTHERS);
+               break;
+       default:
+               IWL_ERROR("illegal indirect type: 0x%X\n",
+               address & INDIRECT_TYPE_MSK);
+               break;
+       }
+
+       /* translate the offset from words to byte */
+       return (address & ADDRESS_MSK) + (offset << 1);
+}
+
+static int iwl5000_eeprom_check_version(struct iwl_priv *priv)
+{
+       u16 eeprom_ver;
+       struct iwl_eeprom_calib_hdr {
+               u8 version;
+               u8 pa_type;
+               u16 voltage;
+       } *hdr;
+
+       eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
+
+       hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv,
+                                                       EEPROM_5000_CALIB_ALL);
+
+       if (eeprom_ver < EEPROM_5000_EEPROM_VERSION ||
+           hdr->version < EEPROM_5000_TX_POWER_VERSION)
+               goto err;
+
+       return 0;
+err:
+       IWL_ERROR("Unsuported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n",
+                 eeprom_ver, EEPROM_5000_EEPROM_VERSION,
+                 hdr->version, EEPROM_5000_TX_POWER_VERSION);
+       return -EINVAL;
+
+}
+
+#ifdef CONFIG_IWL5000_RUN_TIME_CALIB
+
+static void iwl5000_gain_computation(struct iwl_priv *priv,
+               u32 average_noise[NUM_RX_CHAINS],
+               u16 min_average_noise_antenna_i,
+               u32 min_average_noise)
+{
+       int i;
+       s32 delta_g;
+       struct iwl_chain_noise_data *data = &priv->chain_noise_data;
+
+       /* Find Gain Code for the antennas B and C */
+       for (i = 1; i < NUM_RX_CHAINS; i++) {
+               if ((data->disconn_array[i])) {
+                       data->delta_gain_code[i] = 0;
+                       continue;
+               }
+               delta_g = (1000 * ((s32)average_noise[0] -
+                       (s32)average_noise[i])) / 1500;
+               /* bound gain by 2 bits value max, 3rd bit is sign */
+               data->delta_gain_code[i] =
+                       min(abs(delta_g), CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
+
+               if (delta_g < 0)
+                       /* set negative sign */
+                       data->delta_gain_code[i] |= (1 << 2);
+       }
+
+       IWL_DEBUG_CALIB("Delta gains: ANT_B = %d  ANT_C = %d\n",
+                       data->delta_gain_code[1], data->delta_gain_code[2]);
+
+       if (!data->radio_write) {
+               struct iwl5000_calibration_chain_noise_gain_cmd cmd;
+               memset(&cmd, 0, sizeof(cmd));
+
+               cmd.op_code = IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD;
+               cmd.delta_gain_1 = data->delta_gain_code[1];
+               cmd.delta_gain_2 = data->delta_gain_code[2];
+               iwl_send_cmd_pdu_async(priv, REPLY_PHY_CALIBRATION_CMD,
+                       sizeof(cmd), &cmd, NULL);
+
+               data->radio_write = 1;
+               data->state = IWL_CHAIN_NOISE_CALIBRATED;
+       }
+
+       data->chain_noise_a = 0;
+       data->chain_noise_b = 0;
+       data->chain_noise_c = 0;
+       data->chain_signal_a = 0;
+       data->chain_signal_b = 0;
+       data->chain_signal_c = 0;
+       data->beacon_count = 0;
+}
+
+
+static void iwl5000_chain_noise_reset(struct iwl_priv *priv)
+{
+       struct iwl_chain_noise_data *data = &priv->chain_noise_data;
+
+       if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
+               struct iwl5000_calibration_chain_noise_reset_cmd cmd;
+
+               memset(&cmd, 0, sizeof(cmd));
+               cmd.op_code = IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD;
+               if (iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
+                       sizeof(cmd), &cmd))
+                       IWL_ERROR("Could not send REPLY_PHY_CALIBRATION_CMD\n");
+               data->state = IWL_CHAIN_NOISE_ACCUMULATE;
+               IWL_DEBUG_CALIB("Run chain_noise_calibrate\n");
+       }
+}
+
+static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
+       .min_nrg_cck = 95,
+       .max_nrg_cck = 0,
+       .auto_corr_min_ofdm = 90,
+       .auto_corr_min_ofdm_mrc = 170,
+       .auto_corr_min_ofdm_x1 = 120,
+       .auto_corr_min_ofdm_mrc_x1 = 240,
+
+       .auto_corr_max_ofdm = 120,
+       .auto_corr_max_ofdm_mrc = 210,
+       .auto_corr_max_ofdm_x1 = 155,
+       .auto_corr_max_ofdm_mrc_x1 = 290,
+
+       .auto_corr_min_cck = 125,
+       .auto_corr_max_cck = 200,
+       .auto_corr_min_cck_mrc = 170,
+       .auto_corr_max_cck_mrc = 400,
+       .nrg_th_cck = 95,
+       .nrg_th_ofdm = 95,
+};
+
+#endif /* CONFIG_IWL5000_RUN_TIME_CALIB */
+
+
+
+static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
+                                          size_t offset)
+{
+       u32 address = eeprom_indirect_address(priv, offset);
+       BUG_ON(address >= priv->cfg->eeprom_size);
+       return &priv->eeprom[address];
+}
+
+/*
+ *  Calibration
+ */
+static int iwl5000_send_Xtal_calib(struct iwl_priv *priv)
+{
+       u16 *xtal_calib = (u16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_XTAL);
+
+       struct iwl5000_calibration cal_cmd = {
+               .op_code = IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD,
+               .data = {
+                       (u8)xtal_calib[0],
+                       (u8)xtal_calib[1],
+               }
+       };
+
+       return iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
+                               sizeof(cal_cmd), &cal_cmd);
+}
+
+static int iwl5000_send_calib_results(struct iwl_priv *priv)
+{
+       int ret = 0;
+
+       struct iwl_host_cmd hcmd = {
+               .id = REPLY_PHY_CALIBRATION_CMD,
+               .meta.flags = CMD_SIZE_HUGE,
+       };
+
+       if (priv->calib_results.lo_res) {
+               hcmd.len = priv->calib_results.lo_res_len;
+               hcmd.data = priv->calib_results.lo_res;
+               ret = iwl_send_cmd_sync(priv, &hcmd);
+
+               if (ret)
+                       goto err;
+       }
+
+       if (priv->calib_results.tx_iq_res) {
+               hcmd.len = priv->calib_results.tx_iq_res_len;
+               hcmd.data = priv->calib_results.tx_iq_res;
+               ret = iwl_send_cmd_sync(priv, &hcmd);
+
+               if (ret)
+                       goto err;
+       }
+
+       if (priv->calib_results.tx_iq_perd_res) {
+               hcmd.len = priv->calib_results.tx_iq_perd_res_len;
+               hcmd.data = priv->calib_results.tx_iq_perd_res;
+               ret = iwl_send_cmd_sync(priv, &hcmd);
+
+               if (ret)
+                       goto err;
+       }
+
+       return 0;
+err:
+       IWL_ERROR("Error %d\n", ret);
+       return ret;
+}
+
+static int iwl5000_send_calib_cfg(struct iwl_priv *priv)
+{
+       struct iwl5000_calib_cfg_cmd calib_cfg_cmd;
+       struct iwl_host_cmd cmd = {
+               .id = CALIBRATION_CFG_CMD,
+               .len = sizeof(struct iwl5000_calib_cfg_cmd),
+               .data = &calib_cfg_cmd,
+       };
+
+       memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
+       calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_INIT_CFG_ALL;
+       calib_cfg_cmd.ucd_calib_cfg.once.start = IWL_CALIB_INIT_CFG_ALL;
+       calib_cfg_cmd.ucd_calib_cfg.once.send_res = IWL_CALIB_INIT_CFG_ALL;
+       calib_cfg_cmd.ucd_calib_cfg.flags = IWL_CALIB_INIT_CFG_ALL;
+
+       return iwl_send_cmd(priv, &cmd);
+}
+
+static void iwl5000_rx_calib_result(struct iwl_priv *priv,
+                            struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+       struct iwl5000_calib_hdr *hdr = (struct iwl5000_calib_hdr *)pkt->u.raw;
+       int len = le32_to_cpu(pkt->len) & FH_RSCSR_FRAME_SIZE_MSK;
+
+       iwl_free_calib_results(priv);
+
+       /* reduce the size of the length field itself */
+       len -= 4;
+
+       switch (hdr->op_code) {
+       case IWL5000_PHY_CALIBRATE_LO_CMD:
+               priv->calib_results.lo_res = kzalloc(len, GFP_ATOMIC);
+               priv->calib_results.lo_res_len = len;
+               memcpy(priv->calib_results.lo_res, pkt->u.raw, len);
+               break;
+       case IWL5000_PHY_CALIBRATE_TX_IQ_CMD:
+               priv->calib_results.tx_iq_res = kzalloc(len, GFP_ATOMIC);
+               priv->calib_results.tx_iq_res_len = len;
+               memcpy(priv->calib_results.tx_iq_res, pkt->u.raw, len);
+               break;
+       case IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD:
+               priv->calib_results.tx_iq_perd_res = kzalloc(len, GFP_ATOMIC);
+               priv->calib_results.tx_iq_perd_res_len = len;
+               memcpy(priv->calib_results.tx_iq_perd_res, pkt->u.raw, len);
+               break;
+       default:
+               IWL_ERROR("Unknown calibration notification %d\n",
+                         hdr->op_code);
+               return;
+       }
+}
+
+static void iwl5000_rx_calib_complete(struct iwl_priv *priv,
+                              struct iwl_rx_mem_buffer *rxb)
+{
+       IWL_DEBUG_INFO("Init. calibration is completed, restarting fw.\n");
+       queue_work(priv->workqueue, &priv->restart);
+}
+
+/*
+ * ucode
+ */
+static int iwl5000_load_section(struct iwl_priv *priv,
+                               struct fw_desc *image,
+                               u32 dst_addr)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       dma_addr_t phy_addr = image->p_addr;
+       u32 byte_cnt = image->len;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       ret = iwl_grab_nic_access(priv);
+       if (ret) {
+               spin_unlock_irqrestore(&priv->lock, flags);
+               return ret;
+       }
+
+       iwl_write_direct32(priv,
+               FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
+               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
+
+       iwl_write_direct32(priv,
+               FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr);
+
+       iwl_write_direct32(priv,
+               FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL),
+               phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
+
+       /* FIME: write the MSB of the phy_addr in CTRL1
+        * iwl_write_direct32(priv,
+               IWL_FH_TFDIB_CTRL1_REG(IWL_FH_SRVC_CHNL),
+               ((phy_addr & MSB_MSK)
+                       << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_count);
+        */
+       iwl_write_direct32(priv,
+               FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), byte_cnt);
+       iwl_write_direct32(priv,
+               FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL),
+               1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM |
+               1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX |
+               FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
+
+       iwl_write_direct32(priv,
+               FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
+               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE       |
+               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL |
+               FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
+
+       iwl_release_nic_access(priv);
+       spin_unlock_irqrestore(&priv->lock, flags);
+       return 0;
+}
+
+static int iwl5000_load_given_ucode(struct iwl_priv *priv,
+               struct fw_desc *inst_image,
+               struct fw_desc *data_image)
+{
+       int ret = 0;
+
+       ret = iwl5000_load_section(
+               priv, inst_image, RTC_INST_LOWER_BOUND);
+       if (ret)
+               return ret;
+
+       IWL_DEBUG_INFO("INST uCode section being loaded...\n");
+       ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+                               priv->ucode_write_complete, 5 * HZ);
+       if (ret == -ERESTARTSYS) {
+               IWL_ERROR("Could not load the INST uCode section due "
+                       "to interrupt\n");
+               return ret;
+       }
+       if (!ret) {
+               IWL_ERROR("Could not load the INST uCode section\n");
+               return -ETIMEDOUT;
+       }
+
+       priv->ucode_write_complete = 0;
+
+       ret = iwl5000_load_section(
+               priv, data_image, RTC_DATA_LOWER_BOUND);
+       if (ret)
+               return ret;
+
+       IWL_DEBUG_INFO("DATA uCode section being loaded...\n");
+
+       ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+                               priv->ucode_write_complete, 5 * HZ);
+       if (ret == -ERESTARTSYS) {
+               IWL_ERROR("Could not load the INST uCode section due "
+                       "to interrupt\n");
+               return ret;
+       } else if (!ret) {
+               IWL_ERROR("Could not load the DATA uCode section\n");
+               return -ETIMEDOUT;
+       } else
+               ret = 0;
+
+       priv->ucode_write_complete = 0;
+
+       return ret;
+}
+
+static int iwl5000_load_ucode(struct iwl_priv *priv)
+{
+       int ret = 0;
+
+       /* check whether init ucode should be loaded, or rather runtime ucode */
+       if (priv->ucode_init.len && (priv->ucode_type == UCODE_NONE)) {
+               IWL_DEBUG_INFO("Init ucode found. Loading init ucode...\n");
+               ret = iwl5000_load_given_ucode(priv,
+                       &priv->ucode_init, &priv->ucode_init_data);
+               if (!ret) {
+                       IWL_DEBUG_INFO("Init ucode load complete.\n");
+                       priv->ucode_type = UCODE_INIT;
+               }
+       } else {
+               IWL_DEBUG_INFO("Init ucode not found, or already loaded. "
+                       "Loading runtime ucode...\n");
+               ret = iwl5000_load_given_ucode(priv,
+                       &priv->ucode_code, &priv->ucode_data);
+               if (!ret) {
+                       IWL_DEBUG_INFO("Runtime ucode load complete.\n");
+                       priv->ucode_type = UCODE_RT;
+               }
+       }
+
+       return ret;
+}
+
+static void iwl5000_init_alive_start(struct iwl_priv *priv)
+{
+       int ret = 0;
+
+       /* Check alive response for "valid" sign from uCode */
+       if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
+               /* We had an error bringing up the hardware, so take it
+                * all the way back down so we can try again */
+               IWL_DEBUG_INFO("Initialize Alive failed.\n");
+               goto restart;
+       }
+
+       /* initialize uCode was loaded... verify inst image.
+        * This is a paranoid check, because we would not have gotten the
+        * "initialize" alive if code weren't properly loaded.  */
+       if (iwl_verify_ucode(priv)) {
+               /* Runtime instruction load was bad;
+                * take it all the way back down so we can try again */
+               IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n");
+               goto restart;
+       }
+
+       iwlcore_clear_stations_table(priv);
+       ret = priv->cfg->ops->lib->alive_notify(priv);
+       if (ret) {
+               IWL_WARNING("Could not complete ALIVE transition: %d\n", ret);
+               goto restart;
+       }
+
+       iwl5000_send_calib_cfg(priv);
+       return;
+
+restart:
+       /* real restart (first load init_ucode) */
+       queue_work(priv->workqueue, &priv->restart);
+}
+
+static void iwl5000_set_wr_ptrs(struct iwl_priv *priv,
+                               int txq_id, u32 index)
+{
+       iwl_write_direct32(priv, HBUS_TARG_WRPTR,
+                       (index & 0xff) | (txq_id << 8));
+       iwl_write_prph(priv, IWL50_SCD_QUEUE_RDPTR(txq_id), index);
+}
+
+static void iwl5000_tx_queue_set_status(struct iwl_priv *priv,
+                                       struct iwl_tx_queue *txq,
+                                       int tx_fifo_id, int scd_retry)
+{
+       int txq_id = txq->q.id;
+       int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0;
+
+       iwl_write_prph(priv, IWL50_SCD_QUEUE_STATUS_BITS(txq_id),
+                       (active << IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
+                       (tx_fifo_id << IWL50_SCD_QUEUE_STTS_REG_POS_TXF) |
+                       (1 << IWL50_SCD_QUEUE_STTS_REG_POS_WSL) |
+                       IWL50_SCD_QUEUE_STTS_REG_MSK);
+
+       txq->sched_retry = scd_retry;
+
+       IWL_DEBUG_INFO("%s %s Queue %d on AC %d\n",
+                      active ? "Activate" : "Deactivate",
+                      scd_retry ? "BA" : "AC", txq_id, tx_fifo_id);
+}
+
+static int iwl5000_send_wimax_coex(struct iwl_priv *priv)
+{
+       struct iwl_wimax_coex_cmd coex_cmd;
+
+       memset(&coex_cmd, 0, sizeof(coex_cmd));
+
+       return iwl_send_cmd_pdu(priv, COEX_PRIORITY_TABLE_CMD,
+                               sizeof(coex_cmd), &coex_cmd);
+}
+
+static int iwl5000_alive_notify(struct iwl_priv *priv)
+{
+       u32 a;
+       int i = 0;
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       ret = iwl_grab_nic_access(priv);
+       if (ret) {
+               spin_unlock_irqrestore(&priv->lock, flags);
+               return ret;
+       }
+
+       priv->scd_base_addr = iwl_read_prph(priv, IWL50_SCD_SRAM_BASE_ADDR);
+       a = priv->scd_base_addr + IWL50_SCD_CONTEXT_DATA_OFFSET;
+       for (; a < priv->scd_base_addr + IWL50_SCD_TX_STTS_BITMAP_OFFSET;
+               a += 4)
+               iwl_write_targ_mem(priv, a, 0);
+       for (; a < priv->scd_base_addr + IWL50_SCD_TRANSLATE_TBL_OFFSET;
+               a += 4)
+               iwl_write_targ_mem(priv, a, 0);
+       for (; a < sizeof(u16) * priv->hw_params.max_txq_num; a += 4)
+               iwl_write_targ_mem(priv, a, 0);
+
+       iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR,
+               (priv->shared_phys +
+                offsetof(struct iwl5000_shared, queues_byte_cnt_tbls)) >> 10);
+       iwl_write_prph(priv, IWL50_SCD_QUEUECHAIN_SEL,
+               IWL50_SCD_QUEUECHAIN_SEL_ALL(
+                       priv->hw_params.max_txq_num));
+       iwl_write_prph(priv, IWL50_SCD_AGGR_SEL, 0);
+
+       /* initiate the queues */
+       for (i = 0; i < priv->hw_params.max_txq_num; i++) {
+               iwl_write_prph(priv, IWL50_SCD_QUEUE_RDPTR(i), 0);
+               iwl_write_direct32(priv, HBUS_TARG_WRPTR, 0 | (i << 8));
+               iwl_write_targ_mem(priv, priv->scd_base_addr +
+                               IWL50_SCD_CONTEXT_QUEUE_OFFSET(i), 0);
+               iwl_write_targ_mem(priv, priv->scd_base_addr +
+                               IWL50_SCD_CONTEXT_QUEUE_OFFSET(i) +
+                               sizeof(u32),
+                               ((SCD_WIN_SIZE <<
+                               IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
+                               IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
+                               ((SCD_FRAME_LIMIT <<
+                               IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
+                               IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
+       }
+
+       iwl_write_prph(priv, IWL50_SCD_INTERRUPT_MASK,
+                       IWL_MASK(0, priv->hw_params.max_txq_num));
+
+       /* Activate all Tx DMA/FIFO channels */
+       priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7));
+
+       iwl5000_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
+       /* map qos queues to fifos one-to-one */
+       for (i = 0; i < ARRAY_SIZE(iwl5000_default_queue_to_tx_fifo); i++) {
+               int ac = iwl5000_default_queue_to_tx_fifo[i];
+               iwl_txq_ctx_activate(priv, i);
+               iwl5000_tx_queue_set_status(priv, &priv->txq[i], ac, 0);
+       }
+       /* TODO - need to initialize those FIFOs inside the loop above,
+        * not only mark them as active */
+       iwl_txq_ctx_activate(priv, 4);
+       iwl_txq_ctx_activate(priv, 7);
+       iwl_txq_ctx_activate(priv, 8);
+       iwl_txq_ctx_activate(priv, 9);
+
+       iwl_release_nic_access(priv);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+
+       iwl5000_send_wimax_coex(priv);
+
+       iwl5000_send_Xtal_calib(priv);
+
+       if (priv->ucode_type == UCODE_RT) {
+               iwl5000_send_calib_results(priv);
+               set_bit(STATUS_READY, &priv->status);
+               priv->is_open = 1;
+       }
+
+       return 0;
+}
+
+static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
+{
+       if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) ||
+           (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) {
+               IWL_ERROR("invalid queues_num, should be between %d and %d\n",
+                         IWL_MIN_NUM_QUEUES, IWL50_NUM_QUEUES);
+               return -EINVAL;
+       }
+
+       priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues;
+       priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto;
+       priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
+       priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
+       if (priv->cfg->mod_params->amsdu_size_8K)
+               priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_8K;
+       else
+               priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K;
+       priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256;
+       priv->hw_params.max_stations = IWL5000_STATION_COUNT;
+       priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
+       priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE;
+       priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE;
+       priv->hw_params.max_bsm_size = BSM_SRAM_SIZE;
+       priv->hw_params.fat_channel =  BIT(IEEE80211_BAND_2GHZ) |
+                                       BIT(IEEE80211_BAND_5GHZ);
+#ifdef CONFIG_IWL5000_RUN_TIME_CALIB
+       priv->hw_params.sens = &iwl5000_sensitivity;
+#endif
+
+       switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
+       case CSR_HW_REV_TYPE_5100:
+       case CSR_HW_REV_TYPE_5150:
+               priv->hw_params.tx_chains_num = 1;
+               priv->hw_params.rx_chains_num = 2;
+               /* FIXME: move to ANT_A, ANT_B, ANT_C enum */
+               priv->hw_params.valid_tx_ant = ANT_A;
+               priv->hw_params.valid_rx_ant = ANT_AB;
+               break;
+       case CSR_HW_REV_TYPE_5300:
+       case CSR_HW_REV_TYPE_5350:
+               priv->hw_params.tx_chains_num = 3;
+               priv->hw_params.rx_chains_num = 3;
+               priv->hw_params.valid_tx_ant = ANT_ABC;
+               priv->hw_params.valid_rx_ant = ANT_ABC;
+               break;
+       }
+
+       switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
+       case CSR_HW_REV_TYPE_5100:
+       case CSR_HW_REV_TYPE_5300:
+               /* 5X00 wants in Celsius */
+               priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
+               break;
+       case CSR_HW_REV_TYPE_5150:
+       case CSR_HW_REV_TYPE_5350:
+               /* 5X50 wants in Kelvin */
+               priv->hw_params.ct_kill_threshold =
+                               CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD);
+               break;
+       }
+
+       return 0;
+}
+
+static int iwl5000_alloc_shared_mem(struct iwl_priv *priv)
+{
+       priv->shared_virt = pci_alloc_consistent(priv->pci_dev,
+                                       sizeof(struct iwl5000_shared),
+                                       &priv->shared_phys);
+       if (!priv->shared_virt)
+               return -ENOMEM;
+
+       memset(priv->shared_virt, 0, sizeof(struct iwl5000_shared));
+
+       priv->rb_closed_offset = offsetof(struct iwl5000_shared, rb_closed);
+
+       return 0;
+}
+
+static void iwl5000_free_shared_mem(struct iwl_priv *priv)
+{
+       if (priv->shared_virt)
+               pci_free_consistent(priv->pci_dev,
+                                   sizeof(struct iwl5000_shared),
+                                   priv->shared_virt,
+                                   priv->shared_phys);
+}
+
+static int iwl5000_shared_mem_rx_idx(struct iwl_priv *priv)
+{
+       struct iwl5000_shared *s = priv->shared_virt;
+       return le32_to_cpu(s->rb_closed) & 0xFFF;
+}
+
+/**
+ * iwl5000_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
+ */
+static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
+                                           struct iwl_tx_queue *txq,
+                                           u16 byte_cnt)
+{
+       struct iwl5000_shared *shared_data = priv->shared_virt;
+       int txq_id = txq->q.id;
+       u8 sec_ctl = 0;
+       u8 sta = 0;
+       int len;
+
+       len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
+
+       if (txq_id != IWL_CMD_QUEUE_NUM) {
+               sta = txq->cmd[txq->q.write_ptr].cmd.tx.sta_id;
+               sec_ctl = txq->cmd[txq->q.write_ptr].cmd.tx.sec_ctl;
+
+               switch (sec_ctl & TX_CMD_SEC_MSK) {
+               case TX_CMD_SEC_CCM:
+                       len += CCMP_MIC_LEN;
+                       break;
+               case TX_CMD_SEC_TKIP:
+                       len += TKIP_ICV_LEN;
+                       break;
+               case TX_CMD_SEC_WEP:
+                       len += WEP_IV_LEN + WEP_ICV_LEN;
+                       break;
+               }
+       }
+
+       IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
+                      tfd_offset[txq->q.write_ptr], byte_cnt, len);
+
+       IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
+                      tfd_offset[txq->q.write_ptr], sta_id, sta);
+
+       if (txq->q.write_ptr < IWL50_MAX_WIN_SIZE) {
+               IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
+                       tfd_offset[IWL50_QUEUE_SIZE + txq->q.write_ptr],
+                       byte_cnt, len);
+               IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
+                       tfd_offset[IWL50_QUEUE_SIZE + txq->q.write_ptr],
+                       sta_id, sta);
+       }
+}
+
+static void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
+                                          struct iwl_tx_queue *txq)
+{
+       int txq_id = txq->q.id;
+       struct iwl5000_shared *shared_data = priv->shared_virt;
+       u8 sta = 0;
+
+       if (txq_id != IWL_CMD_QUEUE_NUM)
+               sta = txq->cmd[txq->q.read_ptr].cmd.tx.sta_id;
+
+       shared_data->queues_byte_cnt_tbls[txq_id].tfd_offset[txq->q.read_ptr].
+                                       val = cpu_to_le16(1 | (sta << 12));
+
+       if (txq->q.write_ptr < IWL50_MAX_WIN_SIZE) {
+               shared_data->queues_byte_cnt_tbls[txq_id].
+                       tfd_offset[IWL50_QUEUE_SIZE + txq->q.read_ptr].
+                               val = cpu_to_le16(1 | (sta << 12));
+       }
+}
+
+static 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);
+       return size;
+}
+
+
+/*
+ * Activate/Deactivat Tx DMA/FIFO channels according tx fifos mask
+ * must be called under priv->lock and mac access
+ */
+static void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask)
+{
+       iwl_write_prph(priv, IWL50_SCD_TXFACT, mask);
+}
+
+
+static inline u32 iwl5000_get_scd_ssn(struct iwl5000_tx_resp *tx_resp)
+{
+       __le32 *scd_ssn = (__le32 *)((u32 *)&tx_resp->status +
+                               tx_resp->frame_count);
+       return le32_to_cpu(*scd_ssn) & MAX_SN;
+
+}
+
+static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv,
+                                     struct iwl_ht_agg *agg,
+                                     struct iwl5000_tx_resp *tx_resp,
+                                     u16 start_idx)
+{
+       u16 status;
+       struct agg_tx_status *frame_status = &tx_resp->status;
+       struct ieee80211_tx_info *info = NULL;
+       struct ieee80211_hdr *hdr = NULL;
+       int i, sh;
+       int txq_id, idx;
+       u16 seq;
+
+       if (agg->wait_for_ba)
+               IWL_DEBUG_TX_REPLY("got tx response w/o block-ack\n");
+
+       agg->frame_count = tx_resp->frame_count;
+       agg->start_idx = start_idx;
+       agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
+       agg->bitmap = 0;
+
+       /* # frames attempted by Tx command */
+       if (agg->frame_count == 1) {
+               /* Only one frame was attempted; no block-ack will arrive */
+               status = le16_to_cpu(frame_status[0].status);
+               seq  = le16_to_cpu(frame_status[0].sequence);
+               idx = SEQ_TO_INDEX(seq);
+               txq_id = SEQ_TO_QUEUE(seq);
+
+               /* FIXME: code repetition */
+               IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n",
+                                  agg->frame_count, agg->start_idx, idx);
+
+               info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
+               info->status.retry_count = tx_resp->failure_frame;
+               info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+               info->flags |= iwl_is_tx_success(status)?
+                       IEEE80211_TX_STAT_ACK : 0;
+               iwl4965_hwrate_to_tx_control(priv,
+                                            le32_to_cpu(tx_resp->rate_n_flags),
+                                            info);
+               /* FIXME: code repetition end */
+
+               IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n",
+                                   status & 0xff, tx_resp->failure_frame);
+               IWL_DEBUG_TX_REPLY("Rate Info rate_n_flags=%x\n",
+                       iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags));
+
+               agg->wait_for_ba = 0;
+       } else {
+               /* Two or more frames were attempted; expect block-ack */
+               u64 bitmap = 0;
+               int start = agg->start_idx;
+
+               /* Construct bit-map of pending frames within Tx window */
+               for (i = 0; i < agg->frame_count; i++) {
+                       u16 sc;
+                       status = le16_to_cpu(frame_status[i].status);
+                       seq  = le16_to_cpu(frame_status[i].sequence);
+                       idx = SEQ_TO_INDEX(seq);
+                       txq_id = SEQ_TO_QUEUE(seq);
+
+                       if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
+                                     AGG_TX_STATE_ABORT_MSK))
+                               continue;
+
+                       IWL_DEBUG_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n",
+                                          agg->frame_count, txq_id, idx);
+
+                       hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx);
+
+                       sc = le16_to_cpu(hdr->seq_ctrl);
+                       if (idx != (SEQ_TO_SN(sc) & 0xff)) {
+                               IWL_ERROR("BUG_ON idx doesn't match seq control"
+                                         " idx=%d, seq_idx=%d, seq=%d\n",
+                                         idx, SEQ_TO_SN(sc),
+                                         hdr->seq_ctrl);
+                               return -1;
+                       }
+
+                       IWL_DEBUG_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n",
+                                          i, idx, SEQ_TO_SN(sc));
+
+                       sh = idx - start;
+                       if (sh > 64) {
+                               sh = (start - idx) + 0xff;
+                               bitmap = bitmap << sh;
+                               sh = 0;
+                               start = idx;
+                       } else if (sh < -64)
+                               sh  = 0xff - (start - idx);
+                       else if (sh < 0) {
+                               sh = start - idx;
+                               start = idx;
+                               bitmap = bitmap << sh;
+                               sh = 0;
+                       }
+                       bitmap |= (1 << sh);
+                       IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%x\n",
+                                          start, (u32)(bitmap & 0xFFFFFFFF));
+               }
+
+               agg->bitmap = bitmap;
+               agg->start_idx = start;
+               agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
+               IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n",
+                                  agg->frame_count, agg->start_idx,
+                                  (unsigned long long)agg->bitmap);
+
+               if (bitmap)
+                       agg->wait_for_ba = 1;
+       }
+       return 0;
+}
+
+static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
+                               struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+       u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+       int txq_id = SEQ_TO_QUEUE(sequence);
+       int index = SEQ_TO_INDEX(sequence);
+       struct iwl_tx_queue *txq = &priv->txq[txq_id];
+       struct ieee80211_tx_info *info;
+       struct iwl5000_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
+       u32  status = le16_to_cpu(tx_resp->status.status);
+#ifdef CONFIG_IWL4965_HT
+       int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION;
+       u16 fc;
+       struct ieee80211_hdr *hdr;
+       u8 *qc = NULL;
+#endif
+
+       if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
+               IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
+                         "is out of range [0-%d] %d %d\n", txq_id,
+                         index, txq->q.n_bd, txq->q.write_ptr,
+                         txq->q.read_ptr);
+               return;
+       }
+
+       info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
+       memset(&info->status, 0, sizeof(info->status));
+
+#ifdef CONFIG_IWL4965_HT
+       hdr = iwl_tx_queue_get_hdr(priv, txq_id, index);
+       fc = le16_to_cpu(hdr->frame_control);
+       if (ieee80211_is_qos_data(fc)) {
+               qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc));
+               tid = qc[0] & 0xf;
+       }
+
+       sta_id = iwl_get_ra_sta_id(priv, hdr);
+       if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) {
+               IWL_ERROR("Station not known\n");
+               return;
+       }
+
+       if (txq->sched_retry) {
+               const u32 scd_ssn = iwl5000_get_scd_ssn(tx_resp);
+               struct iwl_ht_agg *agg = NULL;
+
+               if (!qc)
+                       return;
+
+               agg = &priv->stations[sta_id].tid[tid].agg;
+
+               iwl5000_tx_status_reply_tx(priv, agg, tx_resp, index);
+
+               if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status)) {
+                       /* TODO: send BAR */
+               }
+
+               if (txq->q.read_ptr != (scd_ssn & 0xff)) {
+                       int freed, ampdu_q;
+                       index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
+                       IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn "
+                                          "%d index %d\n", scd_ssn , index);
+                       freed = iwl_tx_queue_reclaim(priv, txq_id, index);
+                       priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+
+                       if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
+                           txq_id >= 0 && priv->mac80211_registered &&
+                           agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) {
+                               /* calculate mac80211 ampdu sw queue to wake */
+                               ampdu_q = txq_id - IWL_BACK_QUEUE_FIRST_ID +
+                                         priv->hw->queues;
+                               if (agg->state == IWL_AGG_OFF)
+                                       ieee80211_wake_queue(priv->hw, txq_id);
+                               else
+                                       ieee80211_wake_queue(priv->hw, ampdu_q);
+                       }
+                       iwl_txq_check_empty(priv, sta_id, tid, txq_id);
+               }
+       } else {
+#endif /* CONFIG_IWL4965_HT */
+
+       info->status.retry_count = tx_resp->failure_frame;
+       info->flags = iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0;
+       iwl4965_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags),
+                                    info);
+
+       IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x "
+                    "retries %d\n", txq_id, iwl_get_tx_fail_reason(status),
+                    status, le32_to_cpu(tx_resp->rate_n_flags),
+                    tx_resp->failure_frame);
+
+       IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
+#ifdef CONFIG_IWL4965_HT
+       if (index != -1) {
+               int freed = iwl_tx_queue_reclaim(priv, txq_id, index);
+               if (tid != MAX_TID_COUNT)
+                       priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+               if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
+                       (txq_id >= 0) && priv->mac80211_registered)
+                       ieee80211_wake_queue(priv->hw, txq_id);
+               if (tid != MAX_TID_COUNT)
+                       iwl_txq_check_empty(priv, sta_id, tid, txq_id);
+       }
+       }
+#endif /* CONFIG_IWL4965_HT */
+
+       if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
+               IWL_ERROR("TODO:  Implement Tx ABORT REQUIRED!!!\n");
+}
+
+/* Currently 5000 is the supperset of everything */
+static u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len)
+{
+       return len;
+}
+
+static void iwl5000_rx_handler_setup(struct iwl_priv *priv)
+{
+       /* init calibration handlers */
+       priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] =
+                                       iwl5000_rx_calib_result;
+       priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] =
+                                       iwl5000_rx_calib_complete;
+       priv->rx_handlers[REPLY_TX] = iwl5000_rx_reply_tx;
+}
+
+
+static int iwl5000_hw_valid_rtc_data_addr(u32 addr)
+{
+       return (addr >= RTC_DATA_LOWER_BOUND) &&
+               (addr < IWL50_RTC_DATA_UPPER_BOUND);
+}
+
+static int iwl5000_send_rxon_assoc(struct iwl_priv *priv)
+{
+       int ret = 0;
+       struct iwl5000_rxon_assoc_cmd rxon_assoc;
+       const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
+       const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
+
+       if ((rxon1->flags == rxon2->flags) &&
+           (rxon1->filter_flags == rxon2->filter_flags) &&
+           (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
+           (rxon1->ofdm_ht_single_stream_basic_rates ==
+            rxon2->ofdm_ht_single_stream_basic_rates) &&
+           (rxon1->ofdm_ht_dual_stream_basic_rates ==
+            rxon2->ofdm_ht_dual_stream_basic_rates) &&
+           (rxon1->ofdm_ht_triple_stream_basic_rates ==
+            rxon2->ofdm_ht_triple_stream_basic_rates) &&
+           (rxon1->acquisition_data == rxon2->acquisition_data) &&
+           (rxon1->rx_chain == rxon2->rx_chain) &&
+           (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
+               IWL_DEBUG_INFO("Using current RXON_ASSOC.  Not resending.\n");
+               return 0;
+       }
+
+       rxon_assoc.flags = priv->staging_rxon.flags;
+       rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
+       rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
+       rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
+       rxon_assoc.reserved1 = 0;
+       rxon_assoc.reserved2 = 0;
+       rxon_assoc.reserved3 = 0;
+       rxon_assoc.ofdm_ht_single_stream_basic_rates =
+           priv->staging_rxon.ofdm_ht_single_stream_basic_rates;
+       rxon_assoc.ofdm_ht_dual_stream_basic_rates =
+           priv->staging_rxon.ofdm_ht_dual_stream_basic_rates;
+       rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain;
+       rxon_assoc.ofdm_ht_triple_stream_basic_rates =
+                priv->staging_rxon.ofdm_ht_triple_stream_basic_rates;
+       rxon_assoc.acquisition_data = priv->staging_rxon.acquisition_data;
+
+       ret = iwl_send_cmd_pdu_async(priv, REPLY_RXON_ASSOC,
+                                    sizeof(rxon_assoc), &rxon_assoc, NULL);
+       if (ret)
+               return ret;
+
+       return ret;
+}
+
+static struct iwl_hcmd_ops iwl5000_hcmd = {
+       .rxon_assoc = iwl5000_send_rxon_assoc,
+};
+
+static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
+       .get_hcmd_size = iwl5000_get_hcmd_size,
+       .build_addsta_hcmd = iwl5000_build_addsta_hcmd,
+#ifdef CONFIG_IWL5000_RUN_TIME_CALIB
+       .gain_computation = iwl5000_gain_computation,
+       .chain_noise_reset = iwl5000_chain_noise_reset,
+#endif
+};
+
+static struct iwl_lib_ops iwl5000_lib = {
+       .set_hw_params = iwl5000_hw_set_hw_params,
+       .alloc_shared_mem = iwl5000_alloc_shared_mem,
+       .free_shared_mem = iwl5000_free_shared_mem,
+       .shared_mem_rx_idx = iwl5000_shared_mem_rx_idx,
+       .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
+       .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
+       .txq_set_sched = iwl5000_txq_set_sched,
+       .rx_handler_setup = iwl5000_rx_handler_setup,
+       .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
+       .load_ucode = iwl5000_load_ucode,
+       .init_alive_start = iwl5000_init_alive_start,
+       .alive_notify = iwl5000_alive_notify,
+       .apm_ops = {
+               .init = iwl5000_apm_init,
+               .reset = iwl5000_apm_reset,
+               .stop = iwl5000_apm_stop,
+               .config = iwl5000_nic_config,
+               .set_pwr_src = iwl4965_set_pwr_src,
+       },
+       .eeprom_ops = {
+               .regulatory_bands = {
+                       EEPROM_5000_REG_BAND_1_CHANNELS,
+                       EEPROM_5000_REG_BAND_2_CHANNELS,
+                       EEPROM_5000_REG_BAND_3_CHANNELS,
+                       EEPROM_5000_REG_BAND_4_CHANNELS,
+                       EEPROM_5000_REG_BAND_5_CHANNELS,
+                       EEPROM_5000_REG_BAND_24_FAT_CHANNELS,
+                       EEPROM_5000_REG_BAND_52_FAT_CHANNELS
+               },
+               .verify_signature  = iwlcore_eeprom_verify_signature,
+               .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
+               .release_semaphore = iwlcore_eeprom_release_semaphore,
+               .check_version  = iwl5000_eeprom_check_version,
+               .query_addr = iwl5000_eeprom_query_addr,
+       },
+};
+
+static struct iwl_ops iwl5000_ops = {
+       .lib = &iwl5000_lib,
+       .hcmd = &iwl5000_hcmd,
+       .utils = &iwl5000_hcmd_utils,
+};
+
+static struct iwl_mod_params iwl50_mod_params = {
+       .num_of_queues = IWL50_NUM_QUEUES,
+       .enable_qos = 1,
+       .amsdu_size_8K = 1,
+       .restart_fw = 1,
+       /* the rest are 0 by default */
+};
+
+
+struct iwl_cfg iwl5300_agn_cfg = {
+       .name = "5300AGN",
+       .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
+       .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+       .ops = &iwl5000_ops,
+       .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+       .mod_params = &iwl50_mod_params,
+};
+
+struct iwl_cfg iwl5100_agn_cfg = {
+       .name = "5100AGN",
+       .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
+       .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+       .ops = &iwl5000_ops,
+       .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+       .mod_params = &iwl50_mod_params,
+};
+
+struct iwl_cfg iwl5350_agn_cfg = {
+       .name = "5350AGN",
+       .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
+       .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+       .ops = &iwl5000_ops,
+       .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+       .mod_params = &iwl50_mod_params,
+};
+
+module_param_named(disable50, iwl50_mod_params.disable, int, 0444);
+MODULE_PARM_DESC(disable50,
+                 "manually disable the 50XX radio (default 0 [radio on])");
+module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444);
+MODULE_PARM_DESC(swcrypto50,
+                 "using software crypto engine (default 0 [hardware])\n");
+module_param_named(debug50, iwl50_mod_params.debug, int, 0444);
+MODULE_PARM_DESC(debug50, "50XX debug output mask");
+module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444);
+MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series");
+module_param_named(qos_enable50, iwl50_mod_params.enable_qos, int, 0444);
+MODULE_PARM_DESC(qos_enable50, "enable all 50XX QoS functionality");
+module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K, int, 0444);
+MODULE_PARM_DESC(amsdu_size_8K50, "enable 8K amsdu size in 50XX series");
+module_param_named(fw_restart50, iwl50_mod_params.restart_fw, int, 0444);
+MODULE_PARM_DESC(fw_restart50, "restart firmware in case of error");
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c
new file mode 100644 (file)
index 0000000..a6c7f0d
--- /dev/null
@@ -0,0 +1,806 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * Tomas Winkler <tomas.winkler@intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <net/mac80211.h>
+
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-calib.h"
+#include "iwl-eeprom.h"
+
+/* "false alarms" are signals that our DSP tries to lock onto,
+ *   but then determines that they are either noise, or transmissions
+ *   from a distant wireless network (also "noise", really) that get
+ *   "stepped on" by stronger transmissions within our own network.
+ * This algorithm attempts to set a sensitivity level that is high
+ *   enough to receive all of our own network traffic, but not so
+ *   high that our DSP gets too busy trying to lock onto non-network
+ *   activity/noise. */
+static int iwl_sens_energy_cck(struct iwl_priv *priv,
+                                  u32 norm_fa,
+                                  u32 rx_enable_time,
+                                  struct statistics_general_data *rx_info)
+{
+       u32 max_nrg_cck = 0;
+       int i = 0;
+       u8 max_silence_rssi = 0;
+       u32 silence_ref = 0;
+       u8 silence_rssi_a = 0;
+       u8 silence_rssi_b = 0;
+       u8 silence_rssi_c = 0;
+       u32 val;
+
+       /* "false_alarms" values below are cross-multiplications to assess the
+        *   numbers of false alarms within the measured period of actual Rx
+        *   (Rx is off when we're txing), vs the min/max expected false alarms
+        *   (some should be expected if rx is sensitive enough) in a
+        *   hypothetical listening period of 200 time units (TU), 204.8 msec:
+        *
+        * MIN_FA/fixed-time < false_alarms/actual-rx-time < MAX_FA/beacon-time
+        *
+        * */
+       u32 false_alarms = norm_fa * 200 * 1024;
+       u32 max_false_alarms = MAX_FA_CCK * rx_enable_time;
+       u32 min_false_alarms = MIN_FA_CCK * rx_enable_time;
+       struct iwl_sensitivity_data *data = NULL;
+       const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
+
+       data = &(priv->sensitivity_data);
+
+       data->nrg_auto_corr_silence_diff = 0;
+
+       /* Find max silence rssi among all 3 receivers.
+        * This is background noise, which may include transmissions from other
+        *    networks, measured during silence before our network's beacon */
+       silence_rssi_a = (u8)((rx_info->beacon_silence_rssi_a &
+                           ALL_BAND_FILTER) >> 8);
+       silence_rssi_b = (u8)((rx_info->beacon_silence_rssi_b &
+                           ALL_BAND_FILTER) >> 8);
+       silence_rssi_c = (u8)((rx_info->beacon_silence_rssi_c &
+                           ALL_BAND_FILTER) >> 8);
+
+       val = max(silence_rssi_b, silence_rssi_c);
+       max_silence_rssi = max(silence_rssi_a, (u8) val);
+
+       /* Store silence rssi in 20-beacon history table */
+       data->nrg_silence_rssi[data->nrg_silence_idx] = max_silence_rssi;
+       data->nrg_silence_idx++;
+       if (data->nrg_silence_idx >= NRG_NUM_PREV_STAT_L)
+               data->nrg_silence_idx = 0;
+
+       /* Find max silence rssi across 20 beacon history */
+       for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) {
+               val = data->nrg_silence_rssi[i];
+               silence_ref = max(silence_ref, val);
+       }
+       IWL_DEBUG_CALIB("silence a %u, b %u, c %u, 20-bcn max %u\n",
+                       silence_rssi_a, silence_rssi_b, silence_rssi_c,
+                       silence_ref);
+
+       /* Find max rx energy (min value!) among all 3 receivers,
+        *   measured during beacon frame.
+        * Save it in 10-beacon history table. */
+       i = data->nrg_energy_idx;
+       val = min(rx_info->beacon_energy_b, rx_info->beacon_energy_c);
+       data->nrg_value[i] = min(rx_info->beacon_energy_a, val);
+
+       data->nrg_energy_idx++;
+       if (data->nrg_energy_idx >= 10)
+               data->nrg_energy_idx = 0;
+
+       /* Find min rx energy (max value) across 10 beacon history.
+        * This is the minimum signal level that we want to receive well.
+        * Add backoff (margin so we don't miss slightly lower energy frames).
+        * This establishes an upper bound (min value) for energy threshold. */
+       max_nrg_cck = data->nrg_value[0];
+       for (i = 1; i < 10; i++)
+               max_nrg_cck = (u32) max(max_nrg_cck, (data->nrg_value[i]));
+       max_nrg_cck += 6;
+
+       IWL_DEBUG_CALIB("rx energy a %u, b %u, c %u, 10-bcn max/min %u\n",
+                       rx_info->beacon_energy_a, rx_info->beacon_energy_b,
+                       rx_info->beacon_energy_c, max_nrg_cck - 6);
+
+       /* Count number of consecutive beacons with fewer-than-desired
+        *   false alarms. */
+       if (false_alarms < min_false_alarms)
+               data->num_in_cck_no_fa++;
+       else
+               data->num_in_cck_no_fa = 0;
+       IWL_DEBUG_CALIB("consecutive bcns with few false alarms = %u\n",
+                       data->num_in_cck_no_fa);
+
+       /* If we got too many false alarms this time, reduce sensitivity */
+       if ((false_alarms > max_false_alarms) &&
+               (data->auto_corr_cck > AUTO_CORR_MAX_TH_CCK)) {
+               IWL_DEBUG_CALIB("norm FA %u > max FA %u\n",
+                    false_alarms, max_false_alarms);
+               IWL_DEBUG_CALIB("... reducing sensitivity\n");
+               data->nrg_curr_state = IWL_FA_TOO_MANY;
+               /* Store for "fewer than desired" on later beacon */
+               data->nrg_silence_ref = silence_ref;
+
+               /* increase energy threshold (reduce nrg value)
+                *   to decrease sensitivity */
+               if (data->nrg_th_cck >
+                       (ranges->max_nrg_cck + NRG_STEP_CCK))
+                       data->nrg_th_cck = data->nrg_th_cck
+                                                - NRG_STEP_CCK;
+               else
+                       data->nrg_th_cck = ranges->max_nrg_cck;
+       /* Else if we got fewer than desired, increase sensitivity */
+       } else if (false_alarms < min_false_alarms) {
+               data->nrg_curr_state = IWL_FA_TOO_FEW;
+
+               /* Compare silence level with silence level for most recent
+                *   healthy number or too many false alarms */
+               data->nrg_auto_corr_silence_diff = (s32)data->nrg_silence_ref -
+                                                  (s32)silence_ref;
+
+               IWL_DEBUG_CALIB("norm FA %u < min FA %u, silence diff %d\n",
+                        false_alarms, min_false_alarms,
+                        data->nrg_auto_corr_silence_diff);
+
+               /* Increase value to increase sensitivity, but only if:
+                * 1a) previous beacon did *not* have *too many* false alarms
+                * 1b) AND there's a significant difference in Rx levels
+                *      from a previous beacon with too many, or healthy # FAs
+                * OR 2) We've seen a lot of beacons (100) with too few
+                *       false alarms */
+               if ((data->nrg_prev_state != IWL_FA_TOO_MANY) &&
+                       ((data->nrg_auto_corr_silence_diff > NRG_DIFF) ||
+                       (data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) {
+
+                       IWL_DEBUG_CALIB("... increasing sensitivity\n");
+                       /* Increase nrg value to increase sensitivity */
+                       val = data->nrg_th_cck + NRG_STEP_CCK;
+                       data->nrg_th_cck = min((u32)ranges->min_nrg_cck, val);
+               } else {
+                       IWL_DEBUG_CALIB("... but not changing sensitivity\n");
+               }
+
+       /* Else we got a healthy number of false alarms, keep status quo */
+       } else {
+               IWL_DEBUG_CALIB(" FA in safe zone\n");
+               data->nrg_curr_state = IWL_FA_GOOD_RANGE;
+
+               /* Store for use in "fewer than desired" with later beacon */
+               data->nrg_silence_ref = silence_ref;
+
+               /* If previous beacon had too many false alarms,
+                *   give it some extra margin by reducing sensitivity again
+                *   (but don't go below measured energy of desired Rx) */
+               if (IWL_FA_TOO_MANY == data->nrg_prev_state) {
+                       IWL_DEBUG_CALIB("... increasing margin\n");
+                       if (data->nrg_th_cck > (max_nrg_cck + NRG_MARGIN))
+                               data->nrg_th_cck -= NRG_MARGIN;
+                       else
+                               data->nrg_th_cck = max_nrg_cck;
+               }
+       }
+
+       /* Make sure the energy threshold does not go above the measured
+        * energy of the desired Rx signals (reduced by backoff margin),
+        * or else we might start missing Rx frames.
+        * Lower value is higher energy, so we use max()!
+        */
+       data->nrg_th_cck = max(max_nrg_cck, data->nrg_th_cck);
+       IWL_DEBUG_CALIB("new nrg_th_cck %u\n", data->nrg_th_cck);
+
+       data->nrg_prev_state = data->nrg_curr_state;
+
+       /* Auto-correlation CCK algorithm */
+       if (false_alarms > min_false_alarms) {
+
+               /* increase auto_corr values to decrease sensitivity
+                * so the DSP won't be disturbed by the noise
+                */
+               if (data->auto_corr_cck < AUTO_CORR_MAX_TH_CCK)
+                       data->auto_corr_cck = AUTO_CORR_MAX_TH_CCK + 1;
+               else {
+                       val = data->auto_corr_cck + AUTO_CORR_STEP_CCK;
+                       data->auto_corr_cck =
+                               min((u32)ranges->auto_corr_max_cck, val);
+               }
+               val = data->auto_corr_cck_mrc + AUTO_CORR_STEP_CCK;
+               data->auto_corr_cck_mrc =
+                       min((u32)ranges->auto_corr_max_cck_mrc, val);
+       } else if ((false_alarms < min_false_alarms) &&
+          ((data->nrg_auto_corr_silence_diff > NRG_DIFF) ||
+          (data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) {
+
+               /* Decrease auto_corr values to increase sensitivity */
+               val = data->auto_corr_cck - AUTO_CORR_STEP_CCK;
+               data->auto_corr_cck =
+                       max((u32)ranges->auto_corr_min_cck, val);
+               val = data->auto_corr_cck_mrc - AUTO_CORR_STEP_CCK;
+               data->auto_corr_cck_mrc =
+                       max((u32)ranges->auto_corr_min_cck_mrc, val);
+       }
+
+       return 0;
+}
+
+
+static int iwl_sens_auto_corr_ofdm(struct iwl_priv *priv,
+                                      u32 norm_fa,
+                                      u32 rx_enable_time)
+{
+       u32 val;
+       u32 false_alarms = norm_fa * 200 * 1024;
+       u32 max_false_alarms = MAX_FA_OFDM * rx_enable_time;
+       u32 min_false_alarms = MIN_FA_OFDM * rx_enable_time;
+       struct iwl_sensitivity_data *data = NULL;
+       const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
+
+       data = &(priv->sensitivity_data);
+
+       /* If we got too many false alarms this time, reduce sensitivity */
+       if (false_alarms > max_false_alarms) {
+
+               IWL_DEBUG_CALIB("norm FA %u > max FA %u)\n",
+                            false_alarms, max_false_alarms);
+
+               val = data->auto_corr_ofdm + AUTO_CORR_STEP_OFDM;
+               data->auto_corr_ofdm =
+                       min((u32)ranges->auto_corr_max_ofdm, val);
+
+               val = data->auto_corr_ofdm_mrc + AUTO_CORR_STEP_OFDM;
+               data->auto_corr_ofdm_mrc =
+                       min((u32)ranges->auto_corr_max_ofdm_mrc, val);
+
+               val = data->auto_corr_ofdm_x1 + AUTO_CORR_STEP_OFDM;
+               data->auto_corr_ofdm_x1 =
+                       min((u32)ranges->auto_corr_max_ofdm_x1, val);
+
+               val = data->auto_corr_ofdm_mrc_x1 + AUTO_CORR_STEP_OFDM;
+               data->auto_corr_ofdm_mrc_x1 =
+                       min((u32)ranges->auto_corr_max_ofdm_mrc_x1, val);
+       }
+
+       /* Else if we got fewer than desired, increase sensitivity */
+       else if (false_alarms < min_false_alarms) {
+
+               IWL_DEBUG_CALIB("norm FA %u < min FA %u\n",
+                            false_alarms, min_false_alarms);
+
+               val = data->auto_corr_ofdm - AUTO_CORR_STEP_OFDM;
+               data->auto_corr_ofdm =
+                       max((u32)ranges->auto_corr_min_ofdm, val);
+
+               val = data->auto_corr_ofdm_mrc - AUTO_CORR_STEP_OFDM;
+               data->auto_corr_ofdm_mrc =
+                       max((u32)ranges->auto_corr_min_ofdm_mrc, val);
+
+               val = data->auto_corr_ofdm_x1 - AUTO_CORR_STEP_OFDM;
+               data->auto_corr_ofdm_x1 =
+                       max((u32)ranges->auto_corr_min_ofdm_x1, val);
+
+               val = data->auto_corr_ofdm_mrc_x1 - AUTO_CORR_STEP_OFDM;
+               data->auto_corr_ofdm_mrc_x1 =
+                       max((u32)ranges->auto_corr_min_ofdm_mrc_x1, val);
+       } else {
+               IWL_DEBUG_CALIB("min FA %u < norm FA %u < max FA %u OK\n",
+                        min_false_alarms, false_alarms, max_false_alarms);
+       }
+       return 0;
+}
+
+/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
+static int iwl_sensitivity_write(struct iwl_priv *priv)
+{
+       int ret = 0;
+       struct iwl_sensitivity_cmd cmd ;
+       struct iwl_sensitivity_data *data = NULL;
+       struct iwl_host_cmd cmd_out = {
+               .id = SENSITIVITY_CMD,
+               .len = sizeof(struct iwl_sensitivity_cmd),
+               .meta.flags = CMD_ASYNC,
+               .data = &cmd,
+       };
+
+       data = &(priv->sensitivity_data);
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX] =
+                               cpu_to_le16((u16)data->auto_corr_ofdm);
+       cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX] =
+                               cpu_to_le16((u16)data->auto_corr_ofdm_mrc);
+       cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX] =
+                               cpu_to_le16((u16)data->auto_corr_ofdm_x1);
+       cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX] =
+                               cpu_to_le16((u16)data->auto_corr_ofdm_mrc_x1);
+
+       cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX] =
+                               cpu_to_le16((u16)data->auto_corr_cck);
+       cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX] =
+                               cpu_to_le16((u16)data->auto_corr_cck_mrc);
+
+       cmd.table[HD_MIN_ENERGY_CCK_DET_INDEX] =
+                               cpu_to_le16((u16)data->nrg_th_cck);
+       cmd.table[HD_MIN_ENERGY_OFDM_DET_INDEX] =
+                               cpu_to_le16((u16)data->nrg_th_ofdm);
+
+       cmd.table[HD_BARKER_CORR_TH_ADD_MIN_INDEX] =
+                               __constant_cpu_to_le16(190);
+       cmd.table[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] =
+                               __constant_cpu_to_le16(390);
+       cmd.table[HD_OFDM_ENERGY_TH_IN_INDEX] =
+                               __constant_cpu_to_le16(62);
+
+       IWL_DEBUG_CALIB("ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n",
+                       data->auto_corr_ofdm, data->auto_corr_ofdm_mrc,
+                       data->auto_corr_ofdm_x1, data->auto_corr_ofdm_mrc_x1,
+                       data->nrg_th_ofdm);
+
+       IWL_DEBUG_CALIB("cck: ac %u mrc %u thresh %u\n",
+                       data->auto_corr_cck, data->auto_corr_cck_mrc,
+                       data->nrg_th_cck);
+
+       /* Update uCode's "work" table, and copy it to DSP */
+       cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE;
+
+       /* Don't send command to uCode if nothing has changed */
+       if (!memcmp(&cmd.table[0], &(priv->sensitivity_tbl[0]),
+                   sizeof(u16)*HD_TABLE_SIZE)) {
+               IWL_DEBUG_CALIB("No change in SENSITIVITY_CMD\n");
+               return 0;
+       }
+
+       /* Copy table for comparison next time */
+       memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]),
+              sizeof(u16)*HD_TABLE_SIZE);
+
+       ret = iwl_send_cmd(priv, &cmd_out);
+       if (ret)
+               IWL_ERROR("SENSITIVITY_CMD failed\n");
+
+       return ret;
+}
+
+void iwl_init_sensitivity(struct iwl_priv *priv)
+{
+       int ret = 0;
+       int i;
+       struct iwl_sensitivity_data *data = NULL;
+       const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
+
+       if (priv->disable_sens_cal)
+               return;
+
+       IWL_DEBUG_CALIB("Start iwl_init_sensitivity\n");
+
+       /* Clear driver's sensitivity algo data */
+       data = &(priv->sensitivity_data);
+
+       if (ranges == NULL)
+               /* can happen if IWLWIFI_RUN_TIME_CALIB is selected
+                * but no IWLXXXX_RUN_TIME_CALIB for specific is selected */
+               return;
+
+       memset(data, 0, sizeof(struct iwl_sensitivity_data));
+
+       data->num_in_cck_no_fa = 0;
+       data->nrg_curr_state = IWL_FA_TOO_MANY;
+       data->nrg_prev_state = IWL_FA_TOO_MANY;
+       data->nrg_silence_ref = 0;
+       data->nrg_silence_idx = 0;
+       data->nrg_energy_idx = 0;
+
+       for (i = 0; i < 10; i++)
+               data->nrg_value[i] = 0;
+
+       for (i = 0; i < NRG_NUM_PREV_STAT_L; i++)
+               data->nrg_silence_rssi[i] = 0;
+
+       data->auto_corr_ofdm = 90;
+       data->auto_corr_ofdm_mrc = ranges->auto_corr_min_ofdm_mrc;
+       data->auto_corr_ofdm_x1  = ranges->auto_corr_min_ofdm_x1;
+       data->auto_corr_ofdm_mrc_x1 = ranges->auto_corr_min_ofdm_mrc_x1;
+       data->auto_corr_cck = AUTO_CORR_CCK_MIN_VAL_DEF;
+       data->auto_corr_cck_mrc = ranges->auto_corr_min_cck_mrc;
+       data->nrg_th_cck = ranges->nrg_th_cck;
+       data->nrg_th_ofdm = ranges->nrg_th_ofdm;
+
+       data->last_bad_plcp_cnt_ofdm = 0;
+       data->last_fa_cnt_ofdm = 0;
+       data->last_bad_plcp_cnt_cck = 0;
+       data->last_fa_cnt_cck = 0;
+
+       ret |= iwl_sensitivity_write(priv);
+       IWL_DEBUG_CALIB("<<return 0x%X\n", ret);
+}
+EXPORT_SYMBOL(iwl_init_sensitivity);
+
+void iwl_sensitivity_calibration(struct iwl_priv *priv,
+                                   struct iwl4965_notif_statistics *resp)
+{
+       u32 rx_enable_time;
+       u32 fa_cck;
+       u32 fa_ofdm;
+       u32 bad_plcp_cck;
+       u32 bad_plcp_ofdm;
+       u32 norm_fa_ofdm;
+       u32 norm_fa_cck;
+       struct iwl_sensitivity_data *data = NULL;
+       struct statistics_rx_non_phy *rx_info = &(resp->rx.general);
+       struct statistics_rx *statistics = &(resp->rx);
+       unsigned long flags;
+       struct statistics_general_data statis;
+
+       if (priv->disable_sens_cal)
+               return;
+
+       data = &(priv->sensitivity_data);
+
+       if (!iwl_is_associated(priv)) {
+               IWL_DEBUG_CALIB("<< - not associated\n");
+               return;
+       }
+
+       spin_lock_irqsave(&priv->lock, flags);
+       if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
+               IWL_DEBUG_CALIB("<< invalid data.\n");
+               spin_unlock_irqrestore(&priv->lock, flags);
+               return;
+       }
+
+       /* Extract Statistics: */
+       rx_enable_time = le32_to_cpu(rx_info->channel_load);
+       fa_cck = le32_to_cpu(statistics->cck.false_alarm_cnt);
+       fa_ofdm = le32_to_cpu(statistics->ofdm.false_alarm_cnt);
+       bad_plcp_cck = le32_to_cpu(statistics->cck.plcp_err);
+       bad_plcp_ofdm = le32_to_cpu(statistics->ofdm.plcp_err);
+
+       statis.beacon_silence_rssi_a =
+                       le32_to_cpu(statistics->general.beacon_silence_rssi_a);
+       statis.beacon_silence_rssi_b =
+                       le32_to_cpu(statistics->general.beacon_silence_rssi_b);
+       statis.beacon_silence_rssi_c =
+                       le32_to_cpu(statistics->general.beacon_silence_rssi_c);
+       statis.beacon_energy_a =
+                       le32_to_cpu(statistics->general.beacon_energy_a);
+       statis.beacon_energy_b =
+                       le32_to_cpu(statistics->general.beacon_energy_b);
+       statis.beacon_energy_c =
+                       le32_to_cpu(statistics->general.beacon_energy_c);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       IWL_DEBUG_CALIB("rx_enable_time = %u usecs\n", rx_enable_time);
+
+       if (!rx_enable_time) {
+               IWL_DEBUG_CALIB("<< RX Enable Time == 0! \n");
+               return;
+       }
+
+       /* These statistics increase monotonically, and do not reset
+        *   at each beacon.  Calculate difference from last value, or just
+        *   use the new statistics value if it has reset or wrapped around. */
+       if (data->last_bad_plcp_cnt_cck > bad_plcp_cck)
+               data->last_bad_plcp_cnt_cck = bad_plcp_cck;
+       else {
+               bad_plcp_cck -= data->last_bad_plcp_cnt_cck;
+               data->last_bad_plcp_cnt_cck += bad_plcp_cck;
+       }
+
+       if (data->last_bad_plcp_cnt_ofdm > bad_plcp_ofdm)
+               data->last_bad_plcp_cnt_ofdm = bad_plcp_ofdm;
+       else {
+               bad_plcp_ofdm -= data->last_bad_plcp_cnt_ofdm;
+               data->last_bad_plcp_cnt_ofdm += bad_plcp_ofdm;
+       }
+
+       if (data->last_fa_cnt_ofdm > fa_ofdm)
+               data->last_fa_cnt_ofdm = fa_ofdm;
+       else {
+               fa_ofdm -= data->last_fa_cnt_ofdm;
+               data->last_fa_cnt_ofdm += fa_ofdm;
+       }
+
+       if (data->last_fa_cnt_cck > fa_cck)
+               data->last_fa_cnt_cck = fa_cck;
+       else {
+               fa_cck -= data->last_fa_cnt_cck;
+               data->last_fa_cnt_cck += fa_cck;
+       }
+
+       /* Total aborted signal locks */
+       norm_fa_ofdm = fa_ofdm + bad_plcp_ofdm;
+       norm_fa_cck = fa_cck + bad_plcp_cck;
+
+       IWL_DEBUG_CALIB("cck: fa %u badp %u  ofdm: fa %u badp %u\n", fa_cck,
+                       bad_plcp_cck, fa_ofdm, bad_plcp_ofdm);
+
+       iwl_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time);
+       iwl_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis);
+       iwl_sensitivity_write(priv);
+
+       return;
+}
+EXPORT_SYMBOL(iwl_sensitivity_calibration);
+
+/*
+ * Accumulate 20 beacons of signal and noise statistics for each of
+ *   3 receivers/antennas/rx-chains, then figure out:
+ * 1)  Which antennas are connected.
+ * 2)  Differential rx gain settings to balance the 3 receivers.
+ */
+void iwl_chain_noise_calibration(struct iwl_priv *priv,
+                             struct iwl4965_notif_statistics *stat_resp)
+{
+       struct iwl_chain_noise_data *data = NULL;
+
+       u32 chain_noise_a;
+       u32 chain_noise_b;
+       u32 chain_noise_c;
+       u32 chain_sig_a;
+       u32 chain_sig_b;
+       u32 chain_sig_c;
+       u32 average_sig[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
+       u32 average_noise[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
+       u32 max_average_sig;
+       u16 max_average_sig_antenna_i;
+       u32 min_average_noise = MIN_AVERAGE_NOISE_MAX_VALUE;
+       u16 min_average_noise_antenna_i = INITIALIZATION_VALUE;
+       u16 i = 0;
+       u16 rxon_chnum = INITIALIZATION_VALUE;
+       u16 stat_chnum = INITIALIZATION_VALUE;
+       u8 rxon_band24;
+       u8 stat_band24;
+       u32 active_chains = 0;
+       u8 num_tx_chains;
+       unsigned long flags;
+       struct statistics_rx_non_phy *rx_info = &(stat_resp->rx.general);
+
+       if (priv->disable_chain_noise_cal)
+               return;
+
+       data = &(priv->chain_noise_data);
+
+       /* Accumulate just the first 20 beacons after the first association,
+        *   then we're done forever. */
+       if (data->state != IWL_CHAIN_NOISE_ACCUMULATE) {
+               if (data->state == IWL_CHAIN_NOISE_ALIVE)
+                       IWL_DEBUG_CALIB("Wait for noise calib reset\n");
+               return;
+       }
+
+       spin_lock_irqsave(&priv->lock, flags);
+       if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
+               IWL_DEBUG_CALIB(" << Interference data unavailable\n");
+               spin_unlock_irqrestore(&priv->lock, flags);
+               return;
+       }
+
+       rxon_band24 = !!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK);
+       rxon_chnum = le16_to_cpu(priv->staging_rxon.channel);
+       stat_band24 = !!(stat_resp->flag & STATISTICS_REPLY_FLG_BAND_24G_MSK);
+       stat_chnum = le32_to_cpu(stat_resp->flag) >> 16;
+
+       /* Make sure we accumulate data for just the associated channel
+        *   (even if scanning). */
+       if ((rxon_chnum != stat_chnum) || (rxon_band24 != stat_band24)) {
+               IWL_DEBUG_CALIB("Stats not from chan=%d, band24=%d\n",
+                               rxon_chnum, rxon_band24);
+               spin_unlock_irqrestore(&priv->lock, flags);
+               return;
+       }
+
+       /* Accumulate beacon statistics values across 20 beacons */
+       chain_noise_a = le32_to_cpu(rx_info->beacon_silence_rssi_a) &
+                               IN_BAND_FILTER;
+       chain_noise_b = le32_to_cpu(rx_info->beacon_silence_rssi_b) &
+                               IN_BAND_FILTER;
+       chain_noise_c = le32_to_cpu(rx_info->beacon_silence_rssi_c) &
+                               IN_BAND_FILTER;
+
+       chain_sig_a = le32_to_cpu(rx_info->beacon_rssi_a) & IN_BAND_FILTER;
+       chain_sig_b = le32_to_cpu(rx_info->beacon_rssi_b) & IN_BAND_FILTER;
+       chain_sig_c = le32_to_cpu(rx_info->beacon_rssi_c) & IN_BAND_FILTER;
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       data->beacon_count++;
+
+       data->chain_noise_a = (chain_noise_a + data->chain_noise_a);
+       data->chain_noise_b = (chain_noise_b + data->chain_noise_b);
+       data->chain_noise_c = (chain_noise_c + data->chain_noise_c);
+
+       data->chain_signal_a = (chain_sig_a + data->chain_signal_a);
+       data->chain_signal_b = (chain_sig_b + data->chain_signal_b);
+       data->chain_signal_c = (chain_sig_c + data->chain_signal_c);
+
+       IWL_DEBUG_CALIB("chan=%d, band24=%d, beacon=%d\n",
+                       rxon_chnum, rxon_band24, data->beacon_count);
+       IWL_DEBUG_CALIB("chain_sig: a %d b %d c %d\n",
+                       chain_sig_a, chain_sig_b, chain_sig_c);
+       IWL_DEBUG_CALIB("chain_noise: a %d b %d c %d\n",
+                       chain_noise_a, chain_noise_b, chain_noise_c);
+
+       /* If this is the 20th beacon, determine:
+        * 1)  Disconnected antennas (using signal strengths)
+        * 2)  Differential gain (using silence noise) to balance receivers */
+       if (data->beacon_count != CAL_NUM_OF_BEACONS)
+               return;
+
+       /* Analyze signal for disconnected antenna */
+       average_sig[0] = (data->chain_signal_a) / CAL_NUM_OF_BEACONS;
+       average_sig[1] = (data->chain_signal_b) / CAL_NUM_OF_BEACONS;
+       average_sig[2] = (data->chain_signal_c) / CAL_NUM_OF_BEACONS;
+
+       if (average_sig[0] >= average_sig[1]) {
+               max_average_sig = average_sig[0];
+               max_average_sig_antenna_i = 0;
+               active_chains = (1 << max_average_sig_antenna_i);
+       } else {
+               max_average_sig = average_sig[1];
+               max_average_sig_antenna_i = 1;
+               active_chains = (1 << max_average_sig_antenna_i);
+       }
+
+       if (average_sig[2] >= max_average_sig) {
+               max_average_sig = average_sig[2];
+               max_average_sig_antenna_i = 2;
+               active_chains = (1 << max_average_sig_antenna_i);
+       }
+
+       IWL_DEBUG_CALIB("average_sig: a %d b %d c %d\n",
+                    average_sig[0], average_sig[1], average_sig[2]);
+       IWL_DEBUG_CALIB("max_average_sig = %d, antenna %d\n",
+                    max_average_sig, max_average_sig_antenna_i);
+
+       /* Compare signal strengths for all 3 receivers. */
+       for (i = 0; i < NUM_RX_CHAINS; i++) {
+               if (i != max_average_sig_antenna_i) {
+                       s32 rssi_delta = (max_average_sig - average_sig[i]);
+
+                       /* If signal is very weak, compared with
+                        * strongest, mark it as disconnected. */
+                       if (rssi_delta > MAXIMUM_ALLOWED_PATHLOSS)
+                               data->disconn_array[i] = 1;
+                       else
+                               active_chains |= (1 << i);
+                       IWL_DEBUG_CALIB("i = %d  rssiDelta = %d  "
+                            "disconn_array[i] = %d\n",
+                            i, rssi_delta, data->disconn_array[i]);
+               }
+       }
+
+       num_tx_chains = 0;
+       for (i = 0; i < NUM_RX_CHAINS; i++) {
+               /* loops on all the bits of
+                * priv->hw_setting.valid_tx_ant */
+               u8 ant_msk = (1 << i);
+               if (!(priv->hw_params.valid_tx_ant & ant_msk))
+                       continue;
+
+               num_tx_chains++;
+               if (data->disconn_array[i] == 0)
+                       /* there is a Tx antenna connected */
+                       break;
+               if (num_tx_chains == priv->hw_params.tx_chains_num &&
+               data->disconn_array[i]) {
+                       /* This is the last TX antenna and is also
+                        * disconnected connect it anyway */
+                       data->disconn_array[i] = 0;
+                       active_chains |= ant_msk;
+                       IWL_DEBUG_CALIB("All Tx chains are disconnected W/A - "
+                               "declare %d as connected\n", i);
+                       break;
+               }
+       }
+
+       IWL_DEBUG_CALIB("active_chains (bitwise) = 0x%x\n",
+                       active_chains);
+
+       /* Save for use within RXON, TX, SCAN commands, etc. */
+       /*priv->valid_antenna = active_chains;*/
+       /*FIXME: should be reflected in RX chains in RXON */
+
+       /* Analyze noise for rx balance */
+       average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS);
+       average_noise[1] = ((data->chain_noise_b)/CAL_NUM_OF_BEACONS);
+       average_noise[2] = ((data->chain_noise_c)/CAL_NUM_OF_BEACONS);
+
+       for (i = 0; i < NUM_RX_CHAINS; i++) {
+               if (!(data->disconn_array[i]) &&
+                  (average_noise[i] <= min_average_noise)) {
+                       /* This means that chain i is active and has
+                        * lower noise values so far: */
+                       min_average_noise = average_noise[i];
+                       min_average_noise_antenna_i = i;
+               }
+       }
+
+       IWL_DEBUG_CALIB("average_noise: a %d b %d c %d\n",
+                       average_noise[0], average_noise[1],
+                       average_noise[2]);
+
+       IWL_DEBUG_CALIB("min_average_noise = %d, antenna %d\n",
+                       min_average_noise, min_average_noise_antenna_i);
+
+       priv->cfg->ops->utils->gain_computation(priv, average_noise,
+               min_average_noise_antenna_i, min_average_noise);
+}
+EXPORT_SYMBOL(iwl_chain_noise_calibration);
+
+
+void iwl_reset_run_time_calib(struct iwl_priv *priv)
+{
+       int i;
+       memset(&(priv->sensitivity_data), 0,
+              sizeof(struct iwl_sensitivity_data));
+       memset(&(priv->chain_noise_data), 0,
+              sizeof(struct iwl_chain_noise_data));
+       for (i = 0; i < NUM_RX_CHAINS; i++)
+               priv->chain_noise_data.delta_gain_code[i] =
+                               CHAIN_NOISE_DELTA_GAIN_INIT_VAL;
+
+       /* Ask for statistics now, the uCode will send notification
+        * periodically after association */
+       iwl_send_statistics_request(priv, CMD_ASYNC);
+}
+EXPORT_SYMBOL(iwl_reset_run_time_calib);
+
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.h b/drivers/net/wireless/iwlwifi/iwl-calib.h
new file mode 100644 (file)
index 0000000..b8e57c5
--- /dev/null
@@ -0,0 +1,109 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * Tomas Winkler <tomas.winkler@intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+#ifndef __iwl_calib_h__
+#define __iwl_calib_h__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <net/mac80211.h>
+#include "iwl-eeprom.h"
+#include "iwl-core.h"
+#include "iwl-dev.h"
+
+#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
+void iwl_chain_noise_calibration(struct iwl_priv *priv,
+                               struct iwl4965_notif_statistics *stat_resp);
+void iwl_sensitivity_calibration(struct iwl_priv *priv,
+                               struct iwl4965_notif_statistics *resp);
+
+void iwl_init_sensitivity(struct iwl_priv *priv);
+void iwl_reset_run_time_calib(struct iwl_priv *priv);
+static inline void iwl_chain_noise_reset(struct iwl_priv *priv)
+{
+
+       if (!priv->disable_chain_noise_cal &&
+           priv->cfg->ops->utils->chain_noise_reset)
+               priv->cfg->ops->utils->chain_noise_reset(priv);
+}
+#else
+static inline void iwl_chain_noise_calibration(struct iwl_priv *priv,
+                               struct iwl4965_notif_statistics *stat_resp)
+{
+}
+static inline void iwl_sensitivity_calibration(struct iwl_priv *priv,
+                               struct iwl4965_notif_statistics *resp)
+{
+}
+static inline void iwl_init_sensitivity(struct iwl_priv *priv)
+{
+}
+static inline void iwl_chain_noise_reset(struct iwl_priv *priv)
+{
+}
+static inline void iwl_reset_run_time_calib(struct iwl_priv *priv)
+{
+}
+#endif
+
+#endif /* __iwl_calib_h__ */
similarity index 91%
rename from drivers/net/wireless/iwlwifi/iwl-4965-commands.h
rename to drivers/net/wireless/iwlwifi/iwl-commands.h
index 3bcd107e2d71bf441c2b3840043ceffe0048525f..fb6f5ffb9f1d902dcf3040310c91c7c273dd3cec 100644 (file)
@@ -61,9 +61,9 @@
  *
  *****************************************************************************/
 /*
- * Please use this file (iwl-4965-commands.h) only for uCode API definitions.
+ * Please use this file (iwl-commands.h) only for uCode API definitions.
  * Please use iwl-4965-hw.h for hardware-related definitions.
- * Please use iwl-4965.h for driver implementation definitions.
+ * Please use iwl-dev.h for driver implementation definitions.
  */
 
 #ifndef __iwl4965_commands_h__
@@ -93,6 +93,11 @@ enum {
        REPLY_LEDS_CMD = 0x48,
        REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */
 
+       /* WiMAX coexistence */
+       COEX_PRIORITY_TABLE_CMD = 0x5a, /*5000 only */
+       COEX_MEDIUM_NOTIFICATION = 0x5b,
+       COEX_EVENT_CMD = 0x5c,
+
        /* 802.11h related */
        RADAR_NOTIFICATION = 0x70,      /* not used */
        REPLY_QUIET_CMD = 0x71,         /* not used */
@@ -269,10 +274,11 @@ struct iwl_cmd_header {
  *          10 B active, A inactive
  *          11 Both active
  */
-#define RATE_MCS_ANT_POS       14
-#define RATE_MCS_ANT_A_MSK     0x04000
-#define RATE_MCS_ANT_B_MSK     0x08000
-#define RATE_MCS_ANT_AB_MSK    0x0C000
+#define RATE_MCS_ANT_POS      14
+#define RATE_MCS_ANT_A_MSK    0x04000
+#define RATE_MCS_ANT_B_MSK    0x08000
+#define RATE_MCS_ANT_C_MSK    0x10000
+#define RATE_MCS_ANT_ABC_MSK  0x1C000
 
 
 /**
@@ -367,7 +373,7 @@ struct iwl4965_tx_power_db {
  * 3)  Tx gain compensation to balance 4965's 2 Tx chains for MIMO operation,
  *     for each of 5 frequency ranges.
  */
-struct iwl4965_init_alive_resp {
+struct iwl_init_alive_resp {
        u8 ucode_minor;
        u8 ucode_major;
        __le16 reserved1;
@@ -443,7 +449,7 @@ struct iwl4965_init_alive_resp {
  * The Linux driver can print both logs to the system log when a uCode error
  * occurs.
  */
-struct iwl4965_alive_resp {
+struct iwl_alive_resp {
        u8 ucode_minor;
        u8 ucode_major;
        __le16 reserved1;
@@ -467,7 +473,7 @@ union tsf {
 /*
  * REPLY_ERROR = 0x2 (response only, not a command)
  */
-struct iwl4965_error_resp {
+struct iwl_error_resp {
        __le32 error_type;
        u8 cmd_id;
        u8 reserved1;
@@ -599,6 +605,46 @@ struct iwl4965_rxon_cmd {
        u8 ofdm_ht_dual_stream_basic_rates;
 } __attribute__ ((packed));
 
+/* 5000 HW just extend this cmmand */
+struct iwl_rxon_cmd {
+       u8 node_addr[6];
+       __le16 reserved1;
+       u8 bssid_addr[6];
+       __le16 reserved2;
+       u8 wlap_bssid_addr[6];
+       __le16 reserved3;
+       u8 dev_type;
+       u8 air_propagation;
+       __le16 rx_chain;
+       u8 ofdm_basic_rates;
+       u8 cck_basic_rates;
+       __le16 assoc_id;
+       __le32 flags;
+       __le32 filter_flags;
+       __le16 channel;
+       u8 ofdm_ht_single_stream_basic_rates;
+       u8 ofdm_ht_dual_stream_basic_rates;
+       u8 ofdm_ht_triple_stream_basic_rates;
+       u8 reserved5;
+       __le16 acquisition_data;
+       __le16 reserved6;
+} __attribute__ ((packed));
+
+struct iwl5000_rxon_assoc_cmd {
+       __le32 flags;
+       __le32 filter_flags;
+       u8 ofdm_basic_rates;
+       u8 cck_basic_rates;
+       __le16 reserved1;
+       u8 ofdm_ht_single_stream_basic_rates;
+       u8 ofdm_ht_dual_stream_basic_rates;
+       u8 ofdm_ht_triple_stream_basic_rates;
+       u8 reserved2;
+       __le16 rx_chain_select_flags;
+       __le16 acquisition_data;
+       __le32 reserved3;
+} __attribute__ ((packed));
+
 /*
  * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response)
  */
@@ -613,6 +659,9 @@ struct iwl4965_rxon_assoc_cmd {
        __le16 reserved;
 } __attribute__ ((packed));
 
+
+
+
 /*
  * REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
  */
@@ -711,6 +760,8 @@ struct iwl4965_qosparam_cmd {
 #define        IWL_STA_ID              2
 #define IWL4965_BROADCAST_ID   31
 #define        IWL4965_STATION_COUNT   32
+#define IWL5000_BROADCAST_ID   15
+#define        IWL5000_STATION_COUNT   16
 
 #define        IWL_STATION_COUNT       32      /* MAX(3945,4965)*/
 #define        IWL_INVALID_STATION     255
@@ -766,6 +817,20 @@ struct iwl4965_keyinfo {
        u8 key[16];             /* 16-byte unicast decryption key */
 } __attribute__ ((packed));
 
+/* 5000 */
+struct iwl_keyinfo {
+       __le16 key_flags;
+       u8 tkip_rx_tsc_byte2;   /* TSC[2] for key mix ph1 detection */
+       u8 reserved1;
+       __le16 tkip_rx_ttak[5]; /* 10-byte unicast TKIP TTAK */
+       u8 key_offset;
+       u8 reserved2;
+       u8 key[16];             /* 16-byte unicast decryption key */
+       __le64 tx_secur_seq_cnt;
+       __le64 hw_tkip_mic_rx_key;
+       __le64 hw_tkip_mic_tx_key;
+} __attribute__ ((packed));
+
 /**
  * struct sta_id_modify
  * @addr[ETH_ALEN]: station's MAC address
@@ -841,6 +906,38 @@ struct iwl4965_addsta_cmd {
        __le32 reserved2;
 } __attribute__ ((packed));
 
+/* 5000 */
+struct iwl_addsta_cmd {
+       u8 mode;                /* 1: modify existing, 0: add new station */
+       u8 reserved[3];
+       struct sta_id_modify sta;
+       struct iwl_keyinfo key;
+       __le32 station_flags;           /* STA_FLG_* */
+       __le32 station_flags_msk;       /* STA_FLG_* */
+
+       /* bit field to disable (1) or enable (0) Tx for Traffic ID (TID)
+        * corresponding to bit (e.g. bit 5 controls TID 5).
+        * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */
+       __le16 tid_disable_tx;
+
+       __le16  reserved1;
+
+       /* TID for which to add block-ack support.
+        * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
+       u8 add_immediate_ba_tid;
+
+       /* TID for which to remove block-ack support.
+        * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */
+       u8 remove_immediate_ba_tid;
+
+       /* Starting Sequence Number for added block-ack support.
+        * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
+       __le16 add_immediate_ba_ssn;
+
+       __le32 reserved2;
+} __attribute__ ((packed));
+
+
 #define ADD_STA_SUCCESS_MSK            0x1
 #define ADD_STA_NO_ROOM_IN_TABLE       0x2
 #define ADD_STA_NO_BLOCK_ACK_RESOURCE  0x4
@@ -848,10 +945,28 @@ struct iwl4965_addsta_cmd {
 /*
  * REPLY_ADD_STA = 0x18 (response)
  */
-struct iwl4965_add_sta_resp {
+struct iwl_add_sta_resp {
        u8 status;      /* ADD_STA_* */
 } __attribute__ ((packed));
 
+#define REM_STA_SUCCESS_MSK              0x1
+/*
+ *  REPLY_REM_STA = 0x19 (response)
+ */
+struct iwl_rem_sta_resp {
+       u8 status;
+} __attribute__ ((packed));
+
+/*
+ *  REPLY_REM_STA = 0x19 (command)
+ */
+struct iwl_rem_sta_cmd {
+       u8 num_sta;     /* number of removed stations */
+       u8 reserved[3];
+       u8 addr[ETH_ALEN]; /* MAC addr of the first station */
+       u8 reserved2[2];
+} __attribute__ ((packed));
+
 /*
  * REPLY_WEP_KEY = 0x20
  */
@@ -1099,6 +1214,14 @@ struct iwl4965_rx_mpdu_res_start {
 #define TX_CMD_SEC_SHIFT       6
 #define TX_CMD_SEC_KEY128      0x08
 
+/*
+ * security overhead sizes
+ */
+#define WEP_IV_LEN 4
+#define WEP_ICV_LEN 4
+#define CCMP_MIC_LEN 8
+#define TKIP_ICV_LEN 4
+
 /*
  * 4965 uCode updates these Tx attempt count values in host DRAM.
  * Used for managing Tx retries when expecting block-acks.
@@ -1113,7 +1236,7 @@ struct iwl4965_dram_scratch {
 /*
  * REPLY_TX = 0x1c (command)
  */
-struct iwl4965_tx_cmd {
+struct iwl_tx_cmd {
        /*
         * MPDU byte count:
         * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size,
@@ -1259,6 +1382,15 @@ enum {
        TX_ABORT_REQUIRED_MSK = 0x80000000,     /* bits 31:31 */
 };
 
+static inline int iwl_is_tx_success(u32 status)
+{
+       status &= TX_STATUS_MSK;
+       return (status == TX_STATUS_SUCCESS)
+           || (status == TX_STATUS_DIRECT_DONE);
+}
+
+
+
 /* *******************************
  * TX aggregation status
  ******************************* */
@@ -1313,6 +1445,11 @@ enum {
  *     within the sending station (this 4965), rather than whether it was
  *     received successfully by the destination station.
  */
+struct agg_tx_status {
+       __le16 status;
+       __le16 sequence;
+} __attribute__ ((packed));
+
 struct iwl4965_tx_resp {
        u8 frame_count;         /* 1 no aggregation, >1 aggregation */
        u8 bt_kill_count;       /* # blocked by bluetooth (unused for agg) */
@@ -1347,11 +1484,6 @@ struct iwl4965_tx_resp {
        __le32 status;  /* TX status (for aggregation status of 1st frame) */
 } __attribute__ ((packed));
 
-struct agg_tx_status {
-       __le16 status;
-       __le16 sequence;
-} __attribute__ ((packed));
-
 struct iwl4965_tx_resp_agg {
        u8 frame_count;         /* 1 no aggregation, >1 aggregation */
        u8 reserved1;
@@ -1366,6 +1498,44 @@ struct iwl4965_tx_resp_agg {
                                        /* of 1st frame) */
 } __attribute__ ((packed));
 
+struct iwl5000_tx_resp {
+       u8 frame_count;         /* 1 no aggregation, >1 aggregation */
+       u8 bt_kill_count;       /* # blocked by bluetooth (unused for agg) */
+       u8 failure_rts;         /* # failures due to unsuccessful RTS */
+       u8 failure_frame;       /* # failures due to no ACK (unused for agg) */
+
+       /* For non-agg:  Rate at which frame was successful.
+        * For agg:  Rate at which all frames were transmitted. */
+       __le32 rate_n_flags;    /* RATE_MCS_*  */
+
+       /* For non-agg:  RTS + CTS + frame tx attempts time + ACK.
+        * For agg:  RTS + CTS + aggregation tx time + block-ack time. */
+       __le16 wireless_media_time;     /* uSecs */
+
+       __le16 reserved;
+       __le32 pa_power1;       /* RF power amplifier measurement (not used) */
+       __le32 pa_power2;
+
+       __le32 tfd_info;
+       __le16 seq_ctl;
+       __le16 byte_cnt;
+       __le32 tlc_info;
+       /*
+        * For non-agg:  frame status TX_STATUS_*
+        * For agg:  status of 1st frame, AGG_TX_STATE_*; other frame status
+        *           fields follow this one, up to frame_count.
+        *           Bit fields:
+        *           11- 0:  AGG_TX_STATE_* status code
+        *           15-12:  Retry count for 1st frame in aggregation (retries
+        *                   occur if tx failed for this frame when it was a
+        *                   member of a previous aggregation block).  If rate
+        *                   scaling is used, retry count indicates the rate
+        *                   table entry used for all frames in the new agg.
+        *           31-16:  Sequence # for this frame's Tx cmd (not SSN!)
+        */
+       struct agg_tx_status status;    /* TX status (in aggregation -
+                                        * status of 1st frame) */
+} __attribute__ ((packed));
 /*
  * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command)
  *
@@ -1853,6 +2023,7 @@ struct iwl4965_spectrum_notification {
 #define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK       __constant_cpu_to_le16(1 << 0)
 #define IWL_POWER_SLEEP_OVER_DTIM_MSK          __constant_cpu_to_le16(1 << 2)
 #define IWL_POWER_PCI_PM_MSK                   __constant_cpu_to_le16(1 << 3)
+#define IWL_POWER_FAST_PD                      __constant_cpu_to_le16(1 << 4)
 
 struct iwl4965_powertable_cmd {
        __le16 flags;
@@ -2051,7 +2222,7 @@ struct iwl4965_scan_cmd {
 
        /* For active scans (set to all-0s for passive scans).
         * Does not include payload.  Must specify Tx rate; no rate scaling. */
-       struct iwl4965_tx_cmd tx_cmd;
+       struct iwl_tx_cmd tx_cmd;
 
        /* For directed active scans (set to all-0s otherwise) */
        struct iwl4965_ssid_ie direct_scan[PROBE_OPTION_MAX];
@@ -2148,7 +2319,7 @@ struct iwl4965_beacon_notif {
  * REPLY_TX_BEACON = 0x91 (command, has simple generic response)
  */
 struct iwl4965_tx_beacon_cmd {
-       struct iwl4965_tx_cmd tx;
+       struct iwl_tx_cmd tx;
        __le16 tim_idx;
        u8 tim_size;
        u8 reserved1;
@@ -2559,7 +2730,7 @@ struct iwl4965_missed_beacon_notif {
  */
 
 /*
- * Table entries in SENSITIVITY_CMD (struct iwl4965_sensitivity_cmd)
+ * Table entries in SENSITIVITY_CMD (struct iwl_sensitivity_cmd)
  */
 #define HD_TABLE_SIZE  (11)    /* number of entries */
 #define HD_MIN_ENERGY_CCK_DET_INDEX                 (0)        /* table indexes */
@@ -2574,18 +2745,18 @@ struct iwl4965_missed_beacon_notif {
 #define HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX          (9)
 #define HD_OFDM_ENERGY_TH_IN_INDEX                  (10)
 
-/* Control field in struct iwl4965_sensitivity_cmd */
+/* Control field in struct iwl_sensitivity_cmd */
 #define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE  __constant_cpu_to_le16(0)
 #define SENSITIVITY_CMD_CONTROL_WORK_TABLE     __constant_cpu_to_le16(1)
 
 /**
- * struct iwl4965_sensitivity_cmd
+ * struct iwl_sensitivity_cmd
  * @control:  (1) updates working table, (0) updates default table
  * @table:  energy threshold values, use HD_* as index into table
  *
  * Always use "1" in "control" to update uCode's working table and DSP.
  */
-struct iwl4965_sensitivity_cmd {
+struct iwl_sensitivity_cmd {
        __le16 control;                 /* always use "1" */
        __le16 table[HD_TABLE_SIZE];    /* use HD_* as index */
 } __attribute__ ((packed));
@@ -2659,6 +2830,86 @@ struct iwl4965_calibration_cmd {
        u8 reserved1;
 } __attribute__ ((packed));
 
+/* Phy calibration command for 5000 series */
+
+enum {
+       IWL5000_PHY_CALIBRATE_DC_CMD            = 8,
+       IWL5000_PHY_CALIBRATE_LO_CMD            = 9,
+       IWL5000_PHY_CALIBRATE_RX_BB_CMD         = 10,
+       IWL5000_PHY_CALIBRATE_TX_IQ_CMD         = 11,
+       IWL5000_PHY_CALIBRATE_RX_IQ_CMD         = 12,
+       IWL5000_PHY_CALIBRATION_NOISE_CMD       = 13,
+       IWL5000_PHY_CALIBRATE_AGC_TABLE_CMD     = 14,
+       IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD   = 15,
+       IWL5000_PHY_CALIBRATE_BASE_BAND_CMD     = 16,
+       IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD    = 17,
+       IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD = 18,
+       IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD = 19,
+};
+
+enum {
+       CALIBRATION_CFG_CMD = 0x65,
+       CALIBRATION_RES_NOTIFICATION = 0x66,
+       CALIBRATION_COMPLETE_NOTIFICATION = 0x67
+};
+
+struct iwl_cal_crystal_freq_cmd {
+       u8 cap_pin1;
+       u8 cap_pin2;
+} __attribute__ ((packed));
+
+struct iwl5000_calibration {
+       u8 op_code;
+       u8 first_group;
+       u8 num_groups;
+       u8 all_data_valid;
+       struct iwl_cal_crystal_freq_cmd data;
+} __attribute__ ((packed));
+
+#define IWL_CALIB_INIT_CFG_ALL __constant_cpu_to_le32(0xffffffff)
+
+struct iwl_calib_cfg_elmnt_s {
+       __le32 is_enable;
+       __le32 start;
+       __le32 send_res;
+       __le32 apply_res;
+       __le32 reserved;
+} __attribute__ ((packed));
+
+struct iwl_calib_cfg_status_s {
+       struct iwl_calib_cfg_elmnt_s once;
+       struct iwl_calib_cfg_elmnt_s perd;
+       __le32 flags;
+} __attribute__ ((packed));
+
+struct iwl5000_calib_cfg_cmd {
+       struct iwl_calib_cfg_status_s ucd_calib_cfg;
+       struct iwl_calib_cfg_status_s drv_calib_cfg;
+       __le32 reserved1;
+} __attribute__ ((packed));
+
+struct iwl5000_calib_hdr {
+       u8 op_code;
+       u8 first_group;
+       u8 groups_num;
+       u8 data_valid;
+} __attribute__ ((packed));
+
+struct iwl5000_calibration_chain_noise_reset_cmd {
+       u8 op_code;     /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */
+       u8 flags;       /* not used */
+       __le16 reserved;
+} __attribute__ ((packed));
+
+struct iwl5000_calibration_chain_noise_gain_cmd {
+       u8 op_code;     /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */
+       u8 flags;       /* not used */
+       __le16 reserved;
+       u8 delta_gain_1;
+       u8 delta_gain_2;
+       __le16 reserved1;
+} __attribute__ ((packed));
+
 /******************************************************************************
  * (12)
  * Miscellaneous Commands:
@@ -2682,30 +2933,81 @@ struct iwl4965_led_cmd {
        u8 reserved;
 } __attribute__ ((packed));
 
+/*
+ * Coexistence WIFI/WIMAX  Command
+ * COEX_PRIORITY_TABLE_CMD = 0x5a
+ *
+ */
+enum {
+       COEX_UNASSOC_IDLE               = 0,
+       COEX_UNASSOC_MANUAL_SCAN        = 1,
+       COEX_UNASSOC_AUTO_SCAN          = 2,
+       COEX_CALIBRATION                = 3,
+       COEX_PERIODIC_CALIBRATION       = 4,
+       COEX_CONNECTION_ESTAB           = 5,
+       COEX_ASSOCIATED_IDLE            = 6,
+       COEX_ASSOC_MANUAL_SCAN          = 7,
+       COEX_ASSOC_AUTO_SCAN            = 8,
+       COEX_ASSOC_ACTIVE_LEVEL         = 9,
+       COEX_RF_ON                      = 10,
+       COEX_RF_OFF                     = 11,
+       COEX_STAND_ALONE_DEBUG          = 12,
+       COEX_IPAN_ASSOC_LEVEL           = 13,
+       COEX_RSRVD1                     = 14,
+       COEX_RSRVD2                     = 15,
+       COEX_NUM_OF_EVENTS              = 16
+};
+
+struct iwl_wimax_coex_event_entry {
+       u8 request_prio;
+       u8 win_medium_prio;
+       u8 reserved;
+       u8 flags;
+} __attribute__ ((packed));
+
+/* COEX flag masks */
+
+/* Staion table is valid */
+#define COEX_FLAGS_STA_TABLE_VALID_MSK      (0x1)
+/* UnMask wakeup src at unassociated sleep */
+#define COEX_FLAGS_UNASSOC_WA_UNMASK_MSK    (0x4)
+/* UnMask wakeup src at associated sleep */
+#define COEX_FLAGS_ASSOC_WA_UNMASK_MSK      (0x8)
+/* Enable CoEx feature. */
+#define COEX_FLAGS_COEX_ENABLE_MSK          (0x80)
+
+struct iwl_wimax_coex_cmd {
+       u8 flags;
+       u8 reserved[3];
+       struct iwl_wimax_coex_event_entry sta_prio[COEX_NUM_OF_EVENTS];
+} __attribute__ ((packed));
+
 /******************************************************************************
  * (13)
  * Union of all expected notifications/responses:
  *
  *****************************************************************************/
 
-struct iwl4965_rx_packet {
+struct iwl_rx_packet {
        __le32 len;
        struct iwl_cmd_header hdr;
        union {
-               struct iwl4965_alive_resp alive_frame;
+               struct iwl_alive_resp alive_frame;
                struct iwl4965_rx_frame rx_frame;
                struct iwl4965_tx_resp tx_resp;
                struct iwl4965_spectrum_notification spectrum_notif;
                struct iwl4965_csa_notification csa_notif;
-               struct iwl4965_error_resp err_resp;
+               struct iwl_error_resp err_resp;
                struct iwl4965_card_state_notif card_state_notif;
                struct iwl4965_beacon_notif beacon_status;
-               struct iwl4965_add_sta_resp add_sta;
+               struct iwl_add_sta_resp add_sta;
+               struct iwl_rem_sta_resp rem_sta;
                struct iwl4965_sleep_notification sleep_notif;
                struct iwl4965_spectrum_resp spectrum;
                struct iwl4965_notif_statistics stats;
                struct iwl4965_compressed_ba_resp compressed_ba;
                struct iwl4965_missed_beacon_notif missed_beacon;
+               struct iwl5000_calibration calib;
                __le32 status;
                u8 raw[0];
        } u;
index 2dfd982d7d1f6977c6de528ea11fbc31ab365fd3..61716ba90427fdefb58f483ecaaa3c7aff2ac518 100644 (file)
 struct iwl_priv; /* FIXME: remove */
 #include "iwl-debug.h"
 #include "iwl-eeprom.h"
-#include "iwl-4965.h" /* FIXME: remove */
+#include "iwl-dev.h" /* FIXME: remove */
 #include "iwl-core.h"
+#include "iwl-io.h"
 #include "iwl-rfkill.h"
+#include "iwl-power.h"
 
 
 MODULE_DESCRIPTION("iwl core");
@@ -44,10 +46,49 @@ MODULE_VERSION(IWLWIFI_VERSION);
 MODULE_AUTHOR(DRV_COPYRIGHT);
 MODULE_LICENSE("GPL");
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-u32 iwl_debug_level;
-EXPORT_SYMBOL(iwl_debug_level);
-#endif
+#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np)    \
+       [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP,      \
+                                   IWL_RATE_SISO_##s##M_PLCP, \
+                                   IWL_RATE_MIMO2_##s##M_PLCP,\
+                                   IWL_RATE_MIMO3_##s##M_PLCP,\
+                                   IWL_RATE_##r##M_IEEE,      \
+                                   IWL_RATE_##ip##M_INDEX,    \
+                                   IWL_RATE_##in##M_INDEX,    \
+                                   IWL_RATE_##rp##M_INDEX,    \
+                                   IWL_RATE_##rn##M_INDEX,    \
+                                   IWL_RATE_##pp##M_INDEX,    \
+                                   IWL_RATE_##np##M_INDEX }
+
+/*
+ * Parameter order:
+ *   rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate
+ *
+ * If there isn't a valid next or previous rate then INV is used which
+ * maps to IWL_RATE_INVALID
+ *
+ */
+const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
+       IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2),    /*  1mbps */
+       IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5),          /*  2mbps */
+       IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11),        /*5.5mbps */
+       IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18),      /* 11mbps */
+       IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11),        /*  6mbps */
+       IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11),       /*  9mbps */
+       IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18),   /* 12mbps */
+       IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24),   /* 18mbps */
+       IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36),   /* 24mbps */
+       IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48),   /* 36mbps */
+       IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54),   /* 48mbps */
+       IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */
+       IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */
+       /* FIXME:RS:          ^^    should be INV (legacy) */
+};
+EXPORT_SYMBOL(iwl_rates);
+
+
+const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+EXPORT_SYMBOL(iwl_bcast_addr);
+
 
 /* This function both allocates and initializes hw and priv. */
 struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
@@ -72,6 +113,108 @@ out:
 }
 EXPORT_SYMBOL(iwl_alloc_all);
 
+void iwl_hw_detect(struct iwl_priv *priv)
+{
+       priv->hw_rev = _iwl_read32(priv, CSR_HW_REV);
+       priv->hw_wa_rev = _iwl_read32(priv, CSR_HW_REV_WA_REG);
+       pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &priv->rev_id);
+}
+EXPORT_SYMBOL(iwl_hw_detect);
+
+/* Tell nic where to find the "keep warm" buffer */
+int iwl_kw_init(struct iwl_priv *priv)
+{
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       ret = iwl_grab_nic_access(priv);
+       if (ret)
+               goto out;
+
+       iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG,
+                            priv->kw.dma_addr >> 4);
+       iwl_release_nic_access(priv);
+out:
+       spin_unlock_irqrestore(&priv->lock, flags);
+       return ret;
+}
+
+int iwl_kw_alloc(struct iwl_priv *priv)
+{
+       struct pci_dev *dev = priv->pci_dev;
+       struct iwl_kw *kw = &priv->kw;
+
+       kw->size = IWL_KW_SIZE;
+       kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr);
+       if (!kw->v_addr)
+               return -ENOMEM;
+
+       return 0;
+}
+
+/**
+ * iwl_kw_free - Free the "keep warm" buffer
+ */
+void iwl_kw_free(struct iwl_priv *priv)
+{
+       struct pci_dev *dev = priv->pci_dev;
+       struct iwl_kw *kw = &priv->kw;
+
+       if (kw->v_addr) {
+               pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr);
+               memset(kw, 0, sizeof(*kw));
+       }
+}
+
+int iwl_hw_nic_init(struct iwl_priv *priv)
+{
+       unsigned long flags;
+       struct iwl_rx_queue *rxq = &priv->rxq;
+       int ret;
+
+       /* nic_init */
+       spin_lock_irqsave(&priv->lock, flags);
+       priv->cfg->ops->lib->apm_ops.init(priv);
+       iwl_write32(priv, CSR_INT_COALESCING, 512 / 32);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN);
+
+       priv->cfg->ops->lib->apm_ops.config(priv);
+
+       /* Allocate the RX queue, or reset if it is already allocated */
+       if (!rxq->bd) {
+               ret = iwl_rx_queue_alloc(priv);
+               if (ret) {
+                       IWL_ERROR("Unable to initialize Rx queue\n");
+                       return -ENOMEM;
+               }
+       } else
+               iwl_rx_queue_reset(priv, rxq);
+
+       iwl_rx_replenish(priv);
+
+       iwl_rx_init(priv, rxq);
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       rxq->need_update = 1;
+       iwl_rx_queue_update_write_ptr(priv, rxq);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       /* Allocate and init all Tx and Command queues */
+       ret = iwl_txq_ctx_reset(priv);
+       if (ret)
+               return ret;
+
+       set_bit(STATUS_INIT, &priv->status);
+
+       return 0;
+}
+EXPORT_SYMBOL(iwl_hw_nic_init);
+
 /**
  * iwlcore_clear_stations_table - Clear the driver's station table
  *
@@ -90,7 +233,7 @@ void iwlcore_clear_stations_table(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwlcore_clear_stations_table);
 
-void iwlcore_reset_qos(struct iwl_priv *priv)
+void iwl_reset_qos(struct iwl_priv *priv)
 {
        u16 cw_min = 15;
        u16 cw_max = 1023;
@@ -176,7 +319,427 @@ void iwlcore_reset_qos(struct iwl_priv *priv)
 
        spin_unlock_irqrestore(&priv->lock, flags);
 }
-EXPORT_SYMBOL(iwlcore_reset_qos);
+EXPORT_SYMBOL(iwl_reset_qos);
+
+#ifdef CONFIG_IWL4965_HT
+#define MAX_BIT_RATE_40_MHZ 0x96; /* 150 Mbps */
+#define MAX_BIT_RATE_20_MHZ 0x48; /* 72 Mbps */
+static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
+                             struct ieee80211_ht_info *ht_info,
+                             enum ieee80211_band band)
+{
+       u16 max_bit_rate = 0;
+       u8 rx_chains_num = priv->hw_params.rx_chains_num;
+       u8 tx_chains_num = priv->hw_params.tx_chains_num;
+
+       ht_info->cap = 0;
+       memset(ht_info->supp_mcs_set, 0, 16);
+
+       ht_info->ht_supported = 1;
+
+       ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD;
+       ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20;
+       ht_info->cap |= (u16)(IEEE80211_HT_CAP_MIMO_PS &
+                            (IWL_MIMO_PS_NONE << 2));
+
+       max_bit_rate = MAX_BIT_RATE_20_MHZ;
+       if (priv->hw_params.fat_channel & BIT(band)) {
+               ht_info->cap |= (u16)IEEE80211_HT_CAP_SUP_WIDTH;
+               ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_40;
+               ht_info->supp_mcs_set[4] = 0x01;
+               max_bit_rate = MAX_BIT_RATE_40_MHZ;
+       }
+
+       if (priv->cfg->mod_params->amsdu_size_8K)
+               ht_info->cap |= (u16)IEEE80211_HT_CAP_MAX_AMSDU;
+
+       ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
+       ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF;
+
+       ht_info->supp_mcs_set[0] = 0xFF;
+       if (rx_chains_num >= 2)
+               ht_info->supp_mcs_set[1] = 0xFF;
+       if (rx_chains_num >= 3)
+               ht_info->supp_mcs_set[2] = 0xFF;
+
+       /* Highest supported Rx data rate */
+       max_bit_rate *= rx_chains_num;
+       ht_info->supp_mcs_set[10] = (u8)(max_bit_rate & 0x00FF);
+       ht_info->supp_mcs_set[11] = (u8)((max_bit_rate & 0xFF00) >> 8);
+
+       /* Tx MCS capabilities */
+       ht_info->supp_mcs_set[12] = IEEE80211_HT_CAP_MCS_TX_DEFINED;
+       if (tx_chains_num != rx_chains_num) {
+               ht_info->supp_mcs_set[12] |= IEEE80211_HT_CAP_MCS_TX_RX_DIFF;
+               ht_info->supp_mcs_set[12] |= ((tx_chains_num - 1) << 2);
+       }
+}
+#else
+static inline void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
+                             struct ieee80211_ht_info *ht_info,
+                             enum ieee80211_band band)
+{
+}
+#endif /* CONFIG_IWL4965_HT */
+
+static void iwlcore_init_hw_rates(struct iwl_priv *priv,
+                             struct ieee80211_rate *rates)
+{
+       int i;
+
+       for (i = 0; i < IWL_RATE_COUNT; i++) {
+               rates[i].bitrate = iwl_rates[i].ieee * 5;
+               rates[i].hw_value = i; /* Rate scaling will work on indexes */
+               rates[i].hw_value_short = i;
+               rates[i].flags = 0;
+               if ((i > IWL_LAST_OFDM_RATE) || (i < IWL_FIRST_OFDM_RATE)) {
+                       /*
+                        * If CCK != 1M then set short preamble rate flag.
+                        */
+                       rates[i].flags |=
+                               (iwl_rates[i].plcp == IWL_RATE_1M_PLCP) ?
+                                       0 : IEEE80211_RATE_SHORT_PREAMBLE;
+               }
+       }
+}
+
+/**
+ * iwlcore_init_geos - Initialize mac80211's geo/channel info based from eeprom
+ */
+static int iwlcore_init_geos(struct iwl_priv *priv)
+{
+       struct iwl_channel_info *ch;
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_channel *channels;
+       struct ieee80211_channel *geo_ch;
+       struct ieee80211_rate *rates;
+       int i = 0;
+
+       if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates ||
+           priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) {
+               IWL_DEBUG_INFO("Geography modes already initialized.\n");
+               set_bit(STATUS_GEO_CONFIGURED, &priv->status);
+               return 0;
+       }
+
+       channels = kzalloc(sizeof(struct ieee80211_channel) *
+                          priv->channel_count, GFP_KERNEL);
+       if (!channels)
+               return -ENOMEM;
+
+       rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_RATE_COUNT + 1)),
+                       GFP_KERNEL);
+       if (!rates) {
+               kfree(channels);
+               return -ENOMEM;
+       }
+
+       /* 5.2GHz channels start after the 2.4GHz channels */
+       sband = &priv->bands[IEEE80211_BAND_5GHZ];
+       sband->channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
+       /* just OFDM */
+       sband->bitrates = &rates[IWL_FIRST_OFDM_RATE];
+       sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE;
+
+       iwlcore_init_ht_hw_capab(priv, &sband->ht_info, IEEE80211_BAND_5GHZ);
+
+       sband = &priv->bands[IEEE80211_BAND_2GHZ];
+       sband->channels = channels;
+       /* OFDM & CCK */
+       sband->bitrates = rates;
+       sband->n_bitrates = IWL_RATE_COUNT;
+
+       iwlcore_init_ht_hw_capab(priv, &sband->ht_info, IEEE80211_BAND_2GHZ);
+
+       priv->ieee_channels = channels;
+       priv->ieee_rates = rates;
+
+       iwlcore_init_hw_rates(priv, rates);
+
+       for (i = 0;  i < priv->channel_count; i++) {
+               ch = &priv->channel_info[i];
+
+               /* FIXME: might be removed if scan is OK */
+               if (!is_channel_valid(ch))
+                       continue;
+
+               if (is_channel_a_band(ch))
+                       sband =  &priv->bands[IEEE80211_BAND_5GHZ];
+               else
+                       sband =  &priv->bands[IEEE80211_BAND_2GHZ];
+
+               geo_ch = &sband->channels[sband->n_channels++];
+
+               geo_ch->center_freq =
+                               ieee80211_channel_to_frequency(ch->channel);
+               geo_ch->max_power = ch->max_power_avg;
+               geo_ch->max_antenna_gain = 0xff;
+               geo_ch->hw_value = ch->channel;
+
+               if (is_channel_valid(ch)) {
+                       if (!(ch->flags & EEPROM_CHANNEL_IBSS))
+                               geo_ch->flags |= IEEE80211_CHAN_NO_IBSS;
+
+                       if (!(ch->flags & EEPROM_CHANNEL_ACTIVE))
+                               geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+
+                       if (ch->flags & EEPROM_CHANNEL_RADAR)
+                               geo_ch->flags |= IEEE80211_CHAN_RADAR;
+
+                       switch (ch->fat_extension_channel) {
+                       case HT_IE_EXT_CHANNEL_ABOVE:
+                               /* only above is allowed, disable below */
+                               geo_ch->flags |= IEEE80211_CHAN_NO_FAT_BELOW;
+                               break;
+                       case HT_IE_EXT_CHANNEL_BELOW:
+                               /* only below is allowed, disable above */
+                               geo_ch->flags |= IEEE80211_CHAN_NO_FAT_ABOVE;
+                               break;
+                       case HT_IE_EXT_CHANNEL_NONE:
+                               /* fat not allowed: disable both*/
+                               geo_ch->flags |= (IEEE80211_CHAN_NO_FAT_ABOVE |
+                                                 IEEE80211_CHAN_NO_FAT_BELOW);
+                               break;
+                       case HT_IE_EXT_CHANNEL_MAX:
+                               /* both above and below are permitted */
+                               break;
+                       }
+
+                       if (ch->max_power_avg > priv->max_channel_txpower_limit)
+                               priv->max_channel_txpower_limit =
+                                   ch->max_power_avg;
+               } else {
+                       geo_ch->flags |= IEEE80211_CHAN_DISABLED;
+               }
+
+               /* Save flags for reg domain usage */
+               geo_ch->orig_flags = geo_ch->flags;
+
+               IWL_DEBUG_INFO("Channel %d Freq=%d[%sGHz] %s flag=0%X\n",
+                               ch->channel, geo_ch->center_freq,
+                               is_channel_a_band(ch) ?  "5.2" : "2.4",
+                               geo_ch->flags & IEEE80211_CHAN_DISABLED ?
+                               "restricted" : "valid",
+                                geo_ch->flags);
+       }
+
+       if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) &&
+            priv->cfg->sku & IWL_SKU_A) {
+               printk(KERN_INFO DRV_NAME
+                      ": Incorrectly detected BG card as ABG.  Please send "
+                      "your PCI ID 0x%04X:0x%04X to maintainer.\n",
+                      priv->pci_dev->device, priv->pci_dev->subsystem_device);
+               priv->cfg->sku &= ~IWL_SKU_A;
+       }
+
+       printk(KERN_INFO DRV_NAME
+              ": Tunable channels: %d 802.11bg, %d 802.11a channels\n",
+              priv->bands[IEEE80211_BAND_2GHZ].n_channels,
+              priv->bands[IEEE80211_BAND_5GHZ].n_channels);
+
+
+       set_bit(STATUS_GEO_CONFIGURED, &priv->status);
+
+       return 0;
+}
+
+/*
+ * iwlcore_free_geos - undo allocations in iwlcore_init_geos
+ */
+static void iwlcore_free_geos(struct iwl_priv *priv)
+{
+       kfree(priv->ieee_channels);
+       kfree(priv->ieee_rates);
+       clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
+}
+
+#ifdef CONFIG_IWL4965_HT
+static u8 is_single_rx_stream(struct iwl_priv *priv)
+{
+       return !priv->current_ht_config.is_ht ||
+              ((priv->current_ht_config.supp_mcs_set[1] == 0) &&
+               (priv->current_ht_config.supp_mcs_set[2] == 0)) ||
+              priv->ps_mode == IWL_MIMO_PS_STATIC;
+}
+static u8 iwl_is_channel_extension(struct iwl_priv *priv,
+                                  enum ieee80211_band band,
+                                  u16 channel, u8 extension_chan_offset)
+{
+       const struct iwl_channel_info *ch_info;
+
+       ch_info = iwl_get_channel_info(priv, band, channel);
+       if (!is_channel_valid(ch_info))
+               return 0;
+
+       if (extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_NONE)
+               return 0;
+
+       if ((ch_info->fat_extension_channel == extension_chan_offset) ||
+           (ch_info->fat_extension_channel == HT_IE_EXT_CHANNEL_MAX))
+               return 1;
+
+       return 0;
+}
+
+u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
+                            struct ieee80211_ht_info *sta_ht_inf)
+{
+       struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config;
+
+       if ((!iwl_ht_conf->is_ht) ||
+          (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) ||
+          (iwl_ht_conf->extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_NONE))
+               return 0;
+
+       if (sta_ht_inf) {
+               if ((!sta_ht_inf->ht_supported) ||
+                  (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH)))
+                       return 0;
+       }
+
+       return iwl_is_channel_extension(priv, priv->band,
+                                        iwl_ht_conf->control_channel,
+                                        iwl_ht_conf->extension_chan_offset);
+}
+EXPORT_SYMBOL(iwl_is_fat_tx_allowed);
+
+void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
+{
+       struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+       u32 val;
+
+       if (!ht_info->is_ht)
+               return;
+
+       /* Set up channel bandwidth:  20 MHz only, or 20/40 mixed if fat ok */
+       if (iwl_is_fat_tx_allowed(priv, NULL))
+               rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK;
+       else
+               rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
+                                RXON_FLG_CHANNEL_MODE_PURE_40_MSK);
+
+       if (le16_to_cpu(rxon->channel) != ht_info->control_channel) {
+               IWL_DEBUG_ASSOC("control diff than current %d %d\n",
+                               le16_to_cpu(rxon->channel),
+                               ht_info->control_channel);
+               rxon->channel = cpu_to_le16(ht_info->control_channel);
+               return;
+       }
+
+       /* Note: control channel is opposite of extension channel */
+       switch (ht_info->extension_chan_offset) {
+       case IWL_EXT_CHANNEL_OFFSET_ABOVE:
+               rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
+               break;
+       case IWL_EXT_CHANNEL_OFFSET_BELOW:
+               rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
+               break;
+       case IWL_EXT_CHANNEL_OFFSET_NONE:
+       default:
+               rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK;
+               break;
+       }
+
+       val = ht_info->ht_protection;
+
+       rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS);
+
+       iwl_set_rxon_chain(priv);
+
+       IWL_DEBUG_ASSOC("supported HT rate 0x%X 0x%X 0x%X "
+                       "rxon flags 0x%X operation mode :0x%X "
+                       "extension channel offset 0x%x "
+                       "control chan %d\n",
+                       ht_info->supp_mcs_set[0],
+                       ht_info->supp_mcs_set[1],
+                       ht_info->supp_mcs_set[2],
+                       le32_to_cpu(rxon->flags), ht_info->ht_protection,
+                       ht_info->extension_chan_offset,
+                       ht_info->control_channel);
+       return;
+}
+EXPORT_SYMBOL(iwl_set_rxon_ht);
+
+#else
+static inline u8 is_single_rx_stream(struct iwl_priv *priv)
+{
+       return 1;
+}
+#endif /*CONFIG_IWL4965_HT */
+
+/*
+ * Determine how many receiver/antenna chains to use.
+ * More provides better reception via diversity.  Fewer saves power.
+ * MIMO (dual stream) requires at least 2, but works better with 3.
+ * This does not determine *which* chains to use, just how many.
+ */
+static int iwlcore_get_rx_chain_counter(struct iwl_priv *priv,
+                                       u8 *idle_state, u8 *rx_state)
+{
+       u8 is_single = is_single_rx_stream(priv);
+       u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1;
+
+       /* # of Rx chains to use when expecting MIMO. */
+       if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC)))
+               *rx_state = 2;
+       else
+               *rx_state = 3;
+
+       /* # Rx chains when idling and maybe trying to save power */
+       switch (priv->ps_mode) {
+       case IWL_MIMO_PS_STATIC:
+       case IWL_MIMO_PS_DYNAMIC:
+               *idle_state = (is_cam) ? 2 : 1;
+               break;
+       case IWL_MIMO_PS_NONE:
+               *idle_state = (is_cam) ? *rx_state : 1;
+               break;
+       default:
+               *idle_state = 1;
+               break;
+       }
+
+       return 0;
+}
+
+/**
+ * iwl_set_rxon_chain - Set up Rx chain usage in "staging" RXON image
+ *
+ * Selects how many and which Rx receivers/antennas/chains to use.
+ * This should not be used for scan command ... it puts data in wrong place.
+ */
+void iwl_set_rxon_chain(struct iwl_priv *priv)
+{
+       u8 is_single = is_single_rx_stream(priv);
+       u8 idle_state, rx_state;
+
+       priv->staging_rxon.rx_chain = 0;
+       rx_state = idle_state = 3;
+
+       /* Tell uCode which antennas are actually connected.
+        * Before first association, we assume all antennas are connected.
+        * Just after first association, iwl_chain_noise_calibration()
+        *    checks which antennas actually *are* connected. */
+       priv->staging_rxon.rx_chain |=
+                   cpu_to_le16(priv->hw_params.valid_rx_ant <<
+                                                RXON_RX_CHAIN_VALID_POS);
+
+       /* How many receivers should we use? */
+       iwlcore_get_rx_chain_counter(priv, &idle_state, &rx_state);
+       priv->staging_rxon.rx_chain |=
+               cpu_to_le16(rx_state << RXON_RX_CHAIN_MIMO_CNT_POS);
+       priv->staging_rxon.rx_chain |=
+               cpu_to_le16(idle_state << RXON_RX_CHAIN_CNT_POS);
+
+       if (!is_single && (rx_state >= 2) &&
+           !test_bit(STATUS_POWER_PMI, &priv->status))
+               priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
+       else
+               priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
+
+       IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain);
+}
+EXPORT_SYMBOL(iwl_set_rxon_chain);
 
 /**
  * iwlcore_set_rxon_channel - Set the phymode and channel values in staging RXON
@@ -188,7 +751,7 @@ EXPORT_SYMBOL(iwlcore_reset_qos);
  * NOTE:  Does not commit to the hardware; it sets appropriate bit fields
  * in the staging RXON flag structure based on the phymode
  */
-int iwlcore_set_rxon_channel(struct iwl_priv *priv,
+int iwl_set_rxon_channel(struct iwl_priv *priv,
                                enum ieee80211_band band,
                                u16 channel)
 {
@@ -214,41 +777,143 @@ int iwlcore_set_rxon_channel(struct iwl_priv *priv,
 
        return 0;
 }
-EXPORT_SYMBOL(iwlcore_set_rxon_channel);
+EXPORT_SYMBOL(iwl_set_rxon_channel);
 
-static void iwlcore_init_hw(struct iwl_priv *priv)
+int iwl_setup_mac(struct iwl_priv *priv)
 {
+       int ret;
        struct ieee80211_hw *hw = priv->hw;
        hw->rate_control_algorithm = "iwl-4965-rs";
 
-       /* Tell mac80211 and its clients (e.g. Wireless Extensions)
-        *       the range of signal quality values that we'll provide.
-        * Negative values for level/noise indicate that we'll provide dBm.
-        * For WE, at least, non-0 values here *enable* display of values
-        *       in app (iwconfig). */
-       hw->max_rssi = -20; /* signal level, negative indicates dBm */
-       hw->max_noise = -20;    /* noise level, negative indicates dBm */
-       hw->max_signal = 100;   /* link quality indication (%) */
-
-       /* Tell mac80211 our Tx characteristics */
-       hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
-
+       /* Tell mac80211 our characteristics */
+       hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
+                   IEEE80211_HW_SIGNAL_DBM |
+                   IEEE80211_HW_NOISE_DBM;
        /* Default value; 4 EDCA QOS priorities */
        hw->queues = 4;
 #ifdef CONFIG_IWL4965_HT
        /* Enhanced value; more queues, to support 11n aggregation */
-       hw->queues = 16;
+       hw->ampdu_queues = 12;
 #endif /* CONFIG_IWL4965_HT */
+
+       hw->conf.beacon_int = 100;
+
+       if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
+               priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
+                       &priv->bands[IEEE80211_BAND_2GHZ];
+       if (priv->bands[IEEE80211_BAND_5GHZ].n_channels)
+               priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+                       &priv->bands[IEEE80211_BAND_5GHZ];
+
+       ret = ieee80211_register_hw(priv->hw);
+       if (ret) {
+               IWL_ERROR("Failed to register hw (error %d)\n", ret);
+               return ret;
+       }
+       priv->mac80211_registered = 1;
+
+       return 0;
 }
+EXPORT_SYMBOL(iwl_setup_mac);
+
 
-int iwl_setup(struct iwl_priv *priv)
+int iwl_init_drv(struct iwl_priv *priv)
 {
-       int ret = 0;
-       iwlcore_init_hw(priv);
-       ret = priv->cfg->ops->lib->init_drv(priv);
+       int ret;
+       int i;
+
+       priv->retry_rate = 1;
+       priv->ibss_beacon = NULL;
+
+       spin_lock_init(&priv->lock);
+       spin_lock_init(&priv->power_data.lock);
+       spin_lock_init(&priv->sta_lock);
+       spin_lock_init(&priv->hcmd_lock);
+       spin_lock_init(&priv->lq_mngr.lock);
+
+       for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++)
+               INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
+
+       INIT_LIST_HEAD(&priv->free_frames);
+
+       mutex_init(&priv->mutex);
+
+       /* Clear the driver's (not device's) station table */
+       iwlcore_clear_stations_table(priv);
+
+       priv->data_retry_limit = -1;
+       priv->ieee_channels = NULL;
+       priv->ieee_rates = NULL;
+       priv->band = IEEE80211_BAND_2GHZ;
+
+       priv->iw_mode = IEEE80211_IF_TYPE_STA;
+
+       priv->use_ant_b_for_management_frame = 1; /* start with ant B */
+       priv->ps_mode = IWL_MIMO_PS_NONE;
+
+       /* Choose which receivers/antennas to use */
+       iwl_set_rxon_chain(priv);
+
+       if (priv->cfg->mod_params->enable_qos)
+               priv->qos_data.qos_enable = 1;
+
+       iwl_reset_qos(priv);
+
+       priv->qos_data.qos_active = 0;
+       priv->qos_data.qos_cap.val = 0;
+
+       iwl_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6);
+
+       priv->rates_mask = IWL_RATES_MASK;
+       /* If power management is turned on, default to AC mode */
+       priv->power_mode = IWL_POWER_AC;
+       priv->user_txpower_limit = IWL_DEFAULT_TX_POWER;
+
+       ret = iwl_init_channel_map(priv);
+       if (ret) {
+               IWL_ERROR("initializing regulatory failed: %d\n", ret);
+               goto err;
+       }
+
+       ret = iwlcore_init_geos(priv);
+       if (ret) {
+               IWL_ERROR("initializing geos failed: %d\n", ret);
+               goto err_free_channel_map;
+       }
+
+       return 0;
+
+err_free_channel_map:
+       iwl_free_channel_map(priv);
+err:
        return ret;
 }
-EXPORT_SYMBOL(iwl_setup);
+EXPORT_SYMBOL(iwl_init_drv);
+
+void iwl_free_calib_results(struct iwl_priv *priv)
+{
+       kfree(priv->calib_results.lo_res);
+       priv->calib_results.lo_res = NULL;
+       priv->calib_results.lo_res_len = 0;
+
+       kfree(priv->calib_results.tx_iq_res);
+       priv->calib_results.tx_iq_res = NULL;
+       priv->calib_results.tx_iq_res_len = 0;
+
+       kfree(priv->calib_results.tx_iq_perd_res);
+       priv->calib_results.tx_iq_perd_res = NULL;
+       priv->calib_results.tx_iq_perd_res_len = 0;
+}
+EXPORT_SYMBOL(iwl_free_calib_results);
+
+void iwl_uninit_drv(struct iwl_priv *priv)
+{
+       iwl_free_calib_results(priv);
+       iwlcore_free_geos(priv);
+       iwl_free_channel_map(priv);
+       kfree(priv->scan);
+}
+EXPORT_SYMBOL(iwl_uninit_drv);
 
 /* Low level driver call this function to update iwlcore with
  * driver status.
@@ -263,8 +928,10 @@ int iwlcore_low_level_notify(struct iwl_priv *priv,
                if (ret)
                        IWL_ERROR("Unable to initialize RFKILL system. "
                                  "Ignoring error: %d\n", ret);
+               iwl_power_initialize(priv);
                break;
        case IWLCORE_START_EVT:
+               iwl_power_update_mode(priv, 1);
                break;
        case IWLCORE_STOP_EVT:
                break;
@@ -290,3 +957,319 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags)
 }
 EXPORT_SYMBOL(iwl_send_statistics_request);
 
+/**
+ * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
+ *   using sample data 100 bytes apart.  If these sample points are good,
+ *   it's a pretty good bet that everything between them is good, too.
+ */
+static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
+{
+       u32 val;
+       int ret = 0;
+       u32 errcnt = 0;
+       u32 i;
+
+       IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
+
+       ret = iwl_grab_nic_access(priv);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
+               /* read data comes through single port, auto-incr addr */
+               /* NOTE: Use the debugless read so we don't flood kernel log
+                * if IWL_DL_IO is set */
+               iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
+                       i + RTC_INST_LOWER_BOUND);
+               val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+               if (val != le32_to_cpu(*image)) {
+                       ret = -EIO;
+                       errcnt++;
+                       if (errcnt >= 3)
+                               break;
+               }
+       }
+
+       iwl_release_nic_access(priv);
+
+       return ret;
+}
+
+/**
+ * iwlcore_verify_inst_full - verify runtime uCode image in card vs. host,
+ *     looking at all data.
+ */
+static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image,
+                                u32 len)
+{
+       u32 val;
+       u32 save_len = len;
+       int ret = 0;
+       u32 errcnt;
+
+       IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
+
+       ret = iwl_grab_nic_access(priv);
+       if (ret)
+               return ret;
+
+       iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND);
+
+       errcnt = 0;
+       for (; len > 0; len -= sizeof(u32), image++) {
+               /* read data comes through single port, auto-incr addr */
+               /* NOTE: Use the debugless read so we don't flood kernel log
+                * if IWL_DL_IO is set */
+               val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+               if (val != le32_to_cpu(*image)) {
+                       IWL_ERROR("uCode INST section is invalid at "
+                                 "offset 0x%x, is 0x%x, s/b 0x%x\n",
+                                 save_len - len, val, le32_to_cpu(*image));
+                       ret = -EIO;
+                       errcnt++;
+                       if (errcnt >= 20)
+                               break;
+               }
+       }
+
+       iwl_release_nic_access(priv);
+
+       if (!errcnt)
+               IWL_DEBUG_INFO
+                   ("ucode image in INSTRUCTION memory is good\n");
+
+       return ret;
+}
+
+/**
+ * iwl_verify_ucode - determine which instruction image is in SRAM,
+ *    and verify its contents
+ */
+int iwl_verify_ucode(struct iwl_priv *priv)
+{
+       __le32 *image;
+       u32 len;
+       int ret;
+
+       /* Try bootstrap */
+       image = (__le32 *)priv->ucode_boot.v_addr;
+       len = priv->ucode_boot.len;
+       ret = iwlcore_verify_inst_sparse(priv, image, len);
+       if (!ret) {
+               IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n");
+               return 0;
+       }
+
+       /* Try initialize */
+       image = (__le32 *)priv->ucode_init.v_addr;
+       len = priv->ucode_init.len;
+       ret = iwlcore_verify_inst_sparse(priv, image, len);
+       if (!ret) {
+               IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n");
+               return 0;
+       }
+
+       /* Try runtime/protocol */
+       image = (__le32 *)priv->ucode_code.v_addr;
+       len = priv->ucode_code.len;
+       ret = iwlcore_verify_inst_sparse(priv, image, len);
+       if (!ret) {
+               IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n");
+               return 0;
+       }
+
+       IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
+
+       /* Since nothing seems to match, show first several data entries in
+        * instruction SRAM, so maybe visual inspection will give a clue.
+        * Selection of bootstrap image (vs. other images) is arbitrary. */
+       image = (__le32 *)priv->ucode_boot.v_addr;
+       len = priv->ucode_boot.len;
+       ret = iwl_verify_inst_full(priv, image, len);
+
+       return ret;
+}
+EXPORT_SYMBOL(iwl_verify_ucode);
+
+
+static const char *desc_lookup(int i)
+{
+       switch (i) {
+       case 1:
+               return "FAIL";
+       case 2:
+               return "BAD_PARAM";
+       case 3:
+               return "BAD_CHECKSUM";
+       case 4:
+               return "NMI_INTERRUPT";
+       case 5:
+               return "SYSASSERT";
+       case 6:
+               return "FATAL_ERROR";
+       }
+
+       return "UNKNOWN";
+}
+
+#define ERROR_START_OFFSET  (1 * sizeof(u32))
+#define ERROR_ELEM_SIZE     (7 * sizeof(u32))
+
+void iwl_dump_nic_error_log(struct iwl_priv *priv)
+{
+       u32 data2, line;
+       u32 desc, time, count, base, data1;
+       u32 blink1, blink2, ilink1, ilink2;
+       int ret;
+
+       if (priv->ucode_type == UCODE_INIT)
+               base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
+       else
+               base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
+
+       if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
+               IWL_ERROR("Not valid error log pointer 0x%08X\n", base);
+               return;
+       }
+
+       ret = iwl_grab_nic_access(priv);
+       if (ret) {
+               IWL_WARNING("Can not read from adapter at this time.\n");
+               return;
+       }
+
+       count = iwl_read_targ_mem(priv, base);
+
+       if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
+               IWL_ERROR("Start IWL Error Log Dump:\n");
+               IWL_ERROR("Status: 0x%08lX, count: %d\n", priv->status, count);
+       }
+
+       desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
+       blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
+       blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
+       ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32));
+       ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32));
+       data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32));
+       data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32));
+       line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
+       time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
+
+       IWL_ERROR("Desc        Time       "
+               "data1      data2      line\n");
+       IWL_ERROR("%-13s (#%d) %010u 0x%08X 0x%08X %u\n",
+               desc_lookup(desc), desc, time, data1, data2, line);
+       IWL_ERROR("blink1  blink2  ilink1  ilink2\n");
+       IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
+               ilink1, ilink2);
+
+       iwl_release_nic_access(priv);
+}
+EXPORT_SYMBOL(iwl_dump_nic_error_log);
+
+#define EVENT_START_OFFSET  (4 * sizeof(u32))
+
+/**
+ * iwl_print_event_log - Dump error event log to syslog
+ *
+ * NOTE: Must be called with iwl4965_grab_nic_access() already obtained!
+ */
+void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+                               u32 num_events, u32 mode)
+{
+       u32 i;
+       u32 base;       /* SRAM byte address of event log header */
+       u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
+       u32 ptr;        /* SRAM byte address of log data */
+       u32 ev, time, data; /* event log data */
+
+       if (num_events == 0)
+               return;
+       if (priv->ucode_type == UCODE_INIT)
+               base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
+       else
+               base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+
+       if (mode == 0)
+               event_size = 2 * sizeof(u32);
+       else
+               event_size = 3 * sizeof(u32);
+
+       ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
+
+       /* "time" is actually "data" for mode 0 (no timestamp).
+       * place event id # at far right for easier visual parsing. */
+       for (i = 0; i < num_events; i++) {
+               ev = iwl_read_targ_mem(priv, ptr);
+               ptr += sizeof(u32);
+               time = iwl_read_targ_mem(priv, ptr);
+               ptr += sizeof(u32);
+               if (mode == 0)
+                       IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */
+               else {
+                       data = iwl_read_targ_mem(priv, ptr);
+                       ptr += sizeof(u32);
+                       IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev);
+               }
+       }
+}
+EXPORT_SYMBOL(iwl_print_event_log);
+
+
+void iwl_dump_nic_event_log(struct iwl_priv *priv)
+{
+       int ret;
+       u32 base;       /* SRAM byte address of event log header */
+       u32 capacity;   /* event log capacity in # entries */
+       u32 mode;       /* 0 - no timestamp, 1 - timestamp recorded */
+       u32 num_wraps;  /* # times uCode wrapped to top of log */
+       u32 next_entry; /* index of next entry to be written by uCode */
+       u32 size;       /* # entries that we'll print */
+
+       if (priv->ucode_type == UCODE_INIT)
+               base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
+       else
+               base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+
+       if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
+               IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
+               return;
+       }
+
+       ret = iwl_grab_nic_access(priv);
+       if (ret) {
+               IWL_WARNING("Can not read from adapter at this time.\n");
+               return;
+       }
+
+       /* event log header */
+       capacity = iwl_read_targ_mem(priv, base);
+       mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
+       num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
+       next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
+
+       size = num_wraps ? capacity : next_entry;
+
+       /* bail out if nothing in log */
+       if (size == 0) {
+               IWL_ERROR("Start IWL Event Log Dump: nothing in log\n");
+               iwl_release_nic_access(priv);
+               return;
+       }
+
+       IWL_ERROR("Start IWL Event Log Dump: display count %d, wraps %d\n",
+                       size, num_wraps);
+
+       /* if uCode has wrapped back to top of log, start at the oldest entry,
+        * i.e the next one that uCode would fill. */
+       if (num_wraps)
+               iwl_print_event_log(priv, next_entry,
+                                       capacity - next_entry, mode);
+       /* (then/else) start at top of log */
+       iwl_print_event_log(priv, 0, next_entry, mode);
+
+       iwl_release_nic_access(priv);
+}
+EXPORT_SYMBOL(iwl_dump_nic_event_log);
+
+
index 7193d97630dce3b3ad068667181e34c71bc48975..6b5af7afbb25e2caa6f3d71876d70831b27b71be 100644 (file)
@@ -86,20 +86,42 @@ struct iwl_hcmd_ops {
        int (*rxon_assoc)(struct iwl_priv *priv);
 };
 struct iwl_hcmd_utils_ops {
-       int (*enqueue_hcmd)(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
+       u16 (*get_hcmd_size)(u8 cmd_id, u16 len);
+       u16 (*build_addsta_hcmd)(const struct iwl_addsta_cmd *cmd, u8 *data);
+#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
+       void (*gain_computation)(struct iwl_priv *priv,
+                       u32 *average_noise,
+                       u16 min_average_noise_antennat_i,
+                       u32 min_average_noise);
+       void (*chain_noise_reset)(struct iwl_priv *priv);
+#endif
 };
 
 struct iwl_lib_ops {
-       /* iwlwifi driver (priv) init */
-       int (*init_drv)(struct iwl_priv *priv);
        /* set hw dependant perameters */
        int (*set_hw_params)(struct iwl_priv *priv);
-
+       /* ucode shared memory */
+       int (*alloc_shared_mem)(struct iwl_priv *priv);
+       void (*free_shared_mem)(struct iwl_priv *priv);
+       int (*shared_mem_rx_idx)(struct iwl_priv *priv);
+       /* Handling TX */
        void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv,
-                                       struct iwl4965_tx_queue *txq,
+                                       struct iwl_tx_queue *txq,
                                        u16 byte_cnt);
-       /* nic init */
-       int (*hw_nic_init)(struct iwl_priv *priv);
+       void (*txq_inval_byte_cnt_tbl)(struct iwl_priv *priv,
+                                      struct iwl_tx_queue *txq);
+       void (*txq_set_sched)(struct iwl_priv *priv, u32 mask);
+#ifdef CONFIG_IWL4965_HT
+       /* aggregations */
+       int (*txq_agg_enable)(struct iwl_priv *priv, int txq_id, int tx_fifo,
+                             int sta_id, int tid, u16 ssn_idx);
+       int (*txq_agg_disable)(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx,
+                              u8 tx_fifo);
+#endif /* CONFIG_IWL4965_HT */
+       /* setup Rx handler */
+       void (*rx_handler_setup)(struct iwl_priv *priv);
+       /* alive notification after init uCode load */
+       void (*init_alive_start)(struct iwl_priv *priv);
        /* alive notification */
        int (*alive_notify)(struct iwl_priv *priv);
        /* check validity of rtc data address */
@@ -108,6 +130,17 @@ struct iwl_lib_ops {
        int (*load_ucode)(struct iwl_priv *priv);
        /* rfkill */
        void (*radio_kill_sw)(struct iwl_priv *priv, int disable_radio);
+        /* power management */
+       struct {
+               int (*init)(struct iwl_priv *priv);
+               int (*reset)(struct iwl_priv *priv);
+               void (*stop)(struct iwl_priv *priv);
+               void (*config)(struct iwl_priv *priv);
+               int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src);
+       } apm_ops;
+       /* power */
+       int (*set_power)(struct iwl_priv *priv, void *cmd);
+       void (*update_chain_flags)(struct iwl_priv *priv);
        /* eeprom operations (as defined in iwl-eeprom.h) */
        struct iwl_eeprom_ops eeprom_ops;
 };
@@ -127,12 +160,14 @@ struct iwl_mod_params {
        int enable_qos;         /* def: 1 = use quality of service */
        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 */
 };
 
 struct iwl_cfg {
        const char *name;
        const char *fw_name;
        unsigned int sku;
+       int eeprom_size;
        const struct iwl_ops *ops;
        const struct iwl_mod_params *mod_params;
 };
@@ -143,14 +178,66 @@ struct iwl_cfg {
 
 struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
                struct ieee80211_ops *hw_ops);
+void iwl_hw_detect(struct iwl_priv *priv);
 
 void iwlcore_clear_stations_table(struct iwl_priv *priv);
-void iwlcore_reset_qos(struct iwl_priv *priv);
-int iwlcore_set_rxon_channel(struct iwl_priv *priv,
+void iwl_free_calib_results(struct iwl_priv *priv);
+void iwl_reset_qos(struct iwl_priv *priv);
+void iwl_set_rxon_chain(struct iwl_priv *priv);
+int iwl_set_rxon_channel(struct iwl_priv *priv,
                                enum ieee80211_band band,
                                u16 channel);
+void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info);
+u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
+                        struct ieee80211_ht_info *sta_ht_inf);
+int iwl_hw_nic_init(struct iwl_priv *priv);
+int iwl_setup_mac(struct iwl_priv *priv);
+int iwl_init_drv(struct iwl_priv *priv);
+void iwl_uninit_drv(struct iwl_priv *priv);
+/* "keep warm" functions */
+int iwl_kw_init(struct iwl_priv *priv);
+int iwl_kw_alloc(struct iwl_priv *priv);
+void iwl_kw_free(struct iwl_priv *priv);
+
+/*****************************************************
+* RX
+******************************************************/
+void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
+int iwl_rx_queue_alloc(struct iwl_priv *priv);
+void iwl_rx_handle(struct iwl_priv *priv);
+int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
+                                 struct iwl_rx_queue *q);
+void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
+void iwl_rx_replenish(struct iwl_priv *priv);
+int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
+/* FIXME: remove when TX is moved to iwl core */
+int iwl_rx_queue_restock(struct iwl_priv *priv);
+int iwl_rx_queue_space(const struct iwl_rx_queue *q);
+void iwl_rx_allocate(struct iwl_priv *priv);
+void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
+int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
+/* Handlers */
+void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
+                              struct iwl_rx_mem_buffer *rxb);
+
+/* TX helpers */
 
-int iwl_setup(struct iwl_priv *priv);
+/*****************************************************
+* TX
+******************************************************/
+int iwl_txq_ctx_reset(struct iwl_priv *priv);
+int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb);
+/* FIXME: remove when free Tx is fully merged into iwlcore */
+int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
+void iwl_hw_txq_ctx_free(struct iwl_priv *priv);
+int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd,
+                                       dma_addr_t addr, u16 len);
+int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
+#ifdef CONFIG_IWL4965_HT
+int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn);
+int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid);
+int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id);
+#endif
 
 /*****************************************************
  *   S e n d i n g     H o s t     C o m m a n d s   *
@@ -167,6 +254,17 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len,
                           int (*callback)(struct iwl_priv *priv,
                                           struct iwl_cmd *cmd,
                                           struct sk_buff *skb));
+
+int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
+
+/*****************************************************
+*  Error Handling Debugging
+******************************************************/
+void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+                        u32 num_events, u32 mode);
+void iwl_dump_nic_error_log(struct iwl_priv *priv);
+void iwl_dump_nic_event_log(struct iwl_priv *priv);
+
 /*************** DRIVER STATUS FUNCTIONS   *****/
 
 #define STATUS_HCMD_ACTIVE     0       /* host command in progress */
@@ -235,6 +333,7 @@ enum iwlcore_card_notify {
 int iwlcore_low_level_notify(struct iwl_priv *priv,
                             enum iwlcore_card_notify notify);
 extern int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags);
+extern int iwl_verify_ucode(struct iwl_priv *priv);
 int iwl_send_lq_cmd(struct iwl_priv *priv,
                    struct iwl_link_quality_cmd *lq, u8 flags);
 
@@ -243,4 +342,10 @@ static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
        return priv->cfg->ops->hcmd->rxon_assoc(priv);
 }
 
+static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
+                       struct iwl_priv *priv, enum ieee80211_band band)
+{
+       return priv->hw->wiphy->bands[band];
+}
+
 #endif /* __iwl_core_h__ */
index 12725796ea5f5bf63d83c23aca77006b1ba69c6e..545ed692d889b36125db3f1c841c1c4d0542188c 100644 (file)
 /* EEPROM reads */
 #define CSR_EEPROM_REG          (CSR_BASE+0x02c)
 #define CSR_EEPROM_GP           (CSR_BASE+0x030)
+#define CSR_GIO_REG            (CSR_BASE+0x03C)
 #define CSR_GP_UCODE           (CSR_BASE+0x044)
 #define CSR_UCODE_DRV_GP1       (CSR_BASE+0x054)
 #define CSR_UCODE_DRV_GP1_SET   (CSR_BASE+0x058)
 #define CSR_UCODE_DRV_GP1_CLR   (CSR_BASE+0x05c)
 #define CSR_UCODE_DRV_GP2       (CSR_BASE+0x060)
-#define CSR_GIO_CHICKEN_BITS    (CSR_BASE+0x100)
 #define CSR_LED_REG             (CSR_BASE+0x094)
+#define CSR_GIO_CHICKEN_BITS    (CSR_BASE+0x100)
 
-/* Analog phase-lock-loop configuration (3945 only)
- * Set bit 24. */
+/* Analog phase-lock-loop configuration  */
 #define CSR_ANA_PLL_CFG         (CSR_BASE+0x20c)
 /*
  * Indicates hardware rev, to determine CCK backoff for txpower calculation.
 
 /* Bits for CSR_HW_IF_CONFIG_REG */
 #define CSR49_HW_IF_CONFIG_REG_BIT_4965_R      (0x00000010)
-#define CSR49_HW_IF_CONFIG_REG_MSK_BOARD_VER   (0x00000C00)
-#define CSR49_HW_IF_CONFIG_REG_BIT_MAC_SI              (0x00000100)
-#define CSR49_HW_IF_CONFIG_REG_BIT_RADIO_SI    (0x00000200)
+#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER     (0x00000C00)
+#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI        (0x00000100)
+#define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI      (0x00000200)
 
 #define CSR39_HW_IF_CONFIG_REG_BIT_3945_MB         (0x00000100)
 #define CSR39_HW_IF_CONFIG_REG_BIT_3945_MM         (0x00000200)
 #define CSR49_FH_INT_TX_MASK   (CSR_FH_INT_BIT_TX_CHNL1 | \
                                 CSR_FH_INT_BIT_TX_CHNL0)
 
+/* GPIO */
+#define CSR_GPIO_IN_BIT_AUX_POWER                   (0x00000200)
+#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC                (0x00000000)
+#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC               (0x00000200)
 
 /* RESET */
 #define CSR_RESET_REG_FLAG_NEVO_RESET                (0x00000001)
 #define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW          (0x08000000)
 
 
+/* HW REV */
+#define CSR_HW_REV_TYPE_MSK            (0x00000F0)
+#define CSR_HW_REV_TYPE_3945           (0x00000D0)
+#define CSR_HW_REV_TYPE_4965           (0x0000000)
+#define CSR_HW_REV_TYPE_5300           (0x0000020)
+#define CSR_HW_REV_TYPE_5350           (0x0000030)
+#define CSR_HW_REV_TYPE_5100           (0x0000050)
+#define CSR_HW_REV_TYPE_5150           (0x0000040)
+#define CSR_HW_REV_TYPE_NONE           (0x00000F0)
+
 /* EEPROM REG */
 #define CSR_EEPROM_REG_READ_VALID_MSK  (0x00000001)
 #define CSR_EEPROM_REG_BIT_CMD         (0x00000002)
 #define CSR_EEPROM_GP_BAD_SIGNATURE    (0x00000000)
 #define CSR_EEPROM_GP_IF_OWNER_MSK     (0x00000180)
 
+/* CSR GIO */
+#define CSR_GIO_REG_VAL_L0S_ENABLED    (0x00000002)
+
 /* UCODE DRV GP */
 #define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP             (0x00000001)
 #define CSR_UCODE_SW_BIT_RFKILL                     (0x00000002)
 #define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED           (0x00000004)
 #define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT      (0x00000008)
 
-/* GPIO */
-#define CSR_GPIO_IN_BIT_AUX_POWER                   (0x00000200)
-#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC                (0x00000000)
-#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC          CSR_GPIO_IN_BIT_AUX_POWER
-
 /* GI Chicken Bits */
 #define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX  (0x00800000)
 #define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER  (0x20000000)
 #define CSR_LED_REG_TRUN_ON (0x78)
 #define CSR_LED_REG_TRUN_OFF (0x38)
 
+/* ANA_PLL */
+#define CSR39_ANA_PLL_CFG_VAL        (0x01000000)
+#define CSR50_ANA_PLL_CFG_VAL        (0x00880300)
+
 /*=== HBUS (Host-side Bus) ===*/
 #define HBUS_BASE      (0x400)
 /*
index c60724c21db8a9bdd41abcb7214261f08afdff38..11de561c7bf8de069993fc0a111b0feaea8bd779 100644 (file)
 #define __iwl_debug_h__
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-extern u32 iwl_debug_level;
 #define IWL_DEBUG(level, fmt, args...) \
-do { if (iwl_debug_level & (level)) \
-  printk(KERN_ERR DRV_NAME": %c %s " fmt, \
+do { if (priv->debug_level & (level)) \
+  dev_printk(KERN_ERR, &(priv->hw->wiphy->dev), "%c %s " fmt, \
         in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
 
 #define IWL_DEBUG_LIMIT(level, fmt, args...) \
-do { if ((iwl_debug_level & (level)) && net_ratelimit()) \
-  printk(KERN_ERR DRV_NAME": %c %s " fmt, \
+do { if ((priv->debug_level & (level)) && net_ratelimit()) \
+  dev_printk(KERN_ERR, &(priv->hw->wiphy->dev), "%c %s " fmt, \
         in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
 
-static inline void iwl_print_hex_dump(int level, void *p, u32 len)
-{
-       if (!(iwl_debug_level & level))
-               return;
-
-       print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1,
-                       p, len, 1);
-}
-
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 struct iwl_debugfs {
        const char *name;
        struct dentry *dir_drv;
        struct dentry *dir_data;
-       struct dir_data_files{
+       struct dentry *dir_rf;
+       struct dir_data_files {
                struct dentry *file_sram;
+               struct dentry *file_eeprom;
                struct dentry *file_stations;
                struct dentry *file_rx_statistics;
                struct dentry *file_tx_statistics;
+               struct dentry *file_log_event;
        } dbgfs_data_files;
+       struct dir_rf_files {
+#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
+               struct dentry *file_disable_sensitivity;
+               struct dentry *file_disable_chain_noise;
+#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */
+       } dbgfs_rf_files;
        u32 sram_offset;
        u32 sram_len;
 };
@@ -76,9 +75,6 @@ static inline void IWL_DEBUG(int level, const char *fmt, ...)
 static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...)
 {
 }
-static inline void iwl_print_hex_dump(int level, void *p, u32 len)
-{
-}
 #endif                         /* CONFIG_IWLWIFI_DEBUG */
 
 
index 9a30e1df311d9ba9611dc07598c3254dbc404e6f..29e16ba69cdb42f1796e240a5f2676dc15d2e190 100644 (file)
@@ -34,7 +34,7 @@
 #include <net/mac80211.h>
 
 
-#include "iwl-4965.h"
+#include "iwl-dev.h"
 #include "iwl-debug.h"
 #include "iwl-core.h"
 #include "iwl-io.h"
                goto err;                                               \
 } while (0)
 
+#define DEBUGFS_ADD_BOOL(name, parent, ptr) do {                        \
+       dbgfs->dbgfs_##parent##_files.file_##name =                     \
+       debugfs_create_bool(#name, 0644, dbgfs->dir_##parent, ptr);     \
+       if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name))          \
+               goto err;                                               \
+} while (0)
+
 #define DEBUGFS_REMOVE(name)  do {              \
        debugfs_remove(name);                   \
        name = NULL;                            \
@@ -85,6 +92,14 @@ static const struct file_operations iwl_dbgfs_##name##_ops = {          \
        .open = iwl_dbgfs_open_file_generic,                            \
 };
 
+#define DEBUGFS_WRITE_FILE_OPS(name)                                    \
+       DEBUGFS_WRITE_FUNC(name);                                       \
+static const struct file_operations iwl_dbgfs_##name##_ops = {          \
+       .write = iwl_dbgfs_##name##_write,                              \
+       .open = iwl_dbgfs_open_file_generic,                            \
+};
+
+
 #define DEBUGFS_READ_WRITE_FILE_OPS(name)                               \
        DEBUGFS_READ_FUNC(name);                                        \
        DEBUGFS_WRITE_FUNC(name);                                       \
@@ -206,7 +221,7 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
                                        size_t count, loff_t *ppos)
 {
        struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
-       struct iwl4965_station_entry *station;
+       struct iwl_station_entry *station;
        int max_sta = priv->hw_params.max_stations;
        char *buf;
        int i, j, pos = 0;
@@ -277,8 +292,70 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
        return ret;
 }
 
+static ssize_t iwl_dbgfs_eeprom_read(struct file *file,
+                                      char __user *user_buf,
+                                      size_t count,
+                                      loff_t *ppos)
+{
+       ssize_t ret;
+       struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+       int pos = 0, ofs = 0, buf_size = 0;
+       const u8 *ptr;
+       char *buf;
+       size_t eeprom_len = priv->cfg->eeprom_size;
+       buf_size = 4 * eeprom_len + 256;
+
+       if (eeprom_len % 16) {
+               IWL_ERROR("EEPROM size is not multiple of 16.\n");
+               return -ENODATA;
+       }
+
+       /* 4 characters for byte 0xYY */
+       buf = kzalloc(buf_size, GFP_KERNEL);
+       if (!buf) {
+               IWL_ERROR("Can not allocate Buffer\n");
+               return -ENOMEM;
+       }
+
+       ptr = priv->eeprom;
+       for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) {
+               pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs);
+               hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos,
+                                  buf_size - pos, 0);
+               pos += strlen(buf);
+               if (buf_size - pos > 0)
+                       buf[pos++] = '\n';
+       }
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_log_event_write(struct file *file,
+                                       const char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       u32 event_log_flag;
+       char buf[8];
+       int buf_size;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       if (sscanf(buf, "%d", &event_log_flag) != 1)
+               return -EFAULT;
+       if (event_log_flag == 1)
+               iwl_dump_nic_event_log(priv);
+
+       return count;
+}
 
 DEBUGFS_READ_WRITE_FILE_OPS(sram);
+DEBUGFS_WRITE_FILE_OPS(log_event);
+DEBUGFS_READ_FILE_OPS(eeprom);
 DEBUGFS_READ_FILE_OPS(stations);
 DEBUGFS_READ_FILE_OPS(rx_statistics);
 DEBUGFS_READ_FILE_OPS(tx_statistics);
@@ -290,6 +367,7 @@ DEBUGFS_READ_FILE_OPS(tx_statistics);
 int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
 {
        struct iwl_debugfs *dbgfs;
+       struct dentry *phyd = priv->hw->wiphy->debugfsdir;
 
        dbgfs = kzalloc(sizeof(struct iwl_debugfs), GFP_KERNEL);
        if (!dbgfs) {
@@ -298,17 +376,24 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
 
        priv->dbgfs = dbgfs;
        dbgfs->name = name;
-       dbgfs->dir_drv = debugfs_create_dir(name, NULL);
+       dbgfs->dir_drv = debugfs_create_dir(name, phyd);
        if (!dbgfs->dir_drv || IS_ERR(dbgfs->dir_drv)){
                goto err;
        }
 
        DEBUGFS_ADD_DIR(data, dbgfs->dir_drv);
+       DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv);
+       DEBUGFS_ADD_FILE(eeprom, data);
        DEBUGFS_ADD_FILE(sram, data);
+       DEBUGFS_ADD_FILE(log_event, data);
        DEBUGFS_ADD_FILE(stations, data);
        DEBUGFS_ADD_FILE(rx_statistics, data);
        DEBUGFS_ADD_FILE(tx_statistics, data);
-
+#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
+       DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
+       DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
+                        &priv->disable_chain_noise_cal);
+#endif  /* CONFIG_IWLWIFI_RUN_TIME_CALIB */
        return 0;
 
 err:
@@ -327,11 +412,18 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
        if (!(priv->dbgfs))
                return;
 
+       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_eeprom);
        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_rx_statistics);
        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_tx_statistics);
        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram);
+       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event);
        DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations);
        DEBUGFS_REMOVE(priv->dbgfs->dir_data);
+#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
+       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
+       DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise);
+#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */
+       DEBUGFS_REMOVE(priv->dbgfs->dir_rf);
        DEBUGFS_REMOVE(priv->dbgfs->dir_drv);
        kfree(priv->dbgfs);
        priv->dbgfs = NULL;
@@ -339,3 +431,4 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
 EXPORT_SYMBOL(iwl_dbgfs_unregister);
 
 
+
similarity index 80%
rename from drivers/net/wireless/iwlwifi/iwl-4965.h
rename to drivers/net/wireless/iwlwifi/iwl-dev.h
index 581b98556c86cff0d4f8d2f2c9c56b5b7843e03c..802f1a12b1aa9dcf986019265c876144d6626d04 100644 (file)
@@ -24,8 +24,8 @@
  *
  *****************************************************************************/
 /*
- * Please use this file (iwl-4965.h) for driver implementation definitions.
- * Please use iwl-4965-commands.h for uCode API definitions.
+ * Please use this file (iwl-dev.h) for driver implementation definitions.
+ * Please use iwl-commands.h for uCode API definitions.
  * Please use iwl-4965-hw.h for hardware-related definitions.
  */
 
 #include "iwl-prph.h"
 #include "iwl-debug.h"
 #include "iwl-led.h"
+#include "iwl-power.h"
 
 /* configuration for the iwl4965 */
 extern struct iwl_cfg iwl4965_agn_cfg;
+extern struct iwl_cfg iwl5300_agn_cfg;
+extern struct iwl_cfg iwl5100_agn_cfg;
+extern struct iwl_cfg iwl5350_agn_cfg;
 
 /* Change firmware file name, using "-" and incrementing number,
  *   *only* when uCode interface or architecture changes so that it
@@ -54,6 +58,8 @@ extern struct iwl_cfg iwl4965_agn_cfg;
  * This number will also appear in << 8 position of 1st dword of uCode file */
 #define IWL4965_UCODE_API "-1"
 
+/* CT-KILL constants */
+#define CT_KILL_THRESHOLD      110 /* in Celsius */
 
 /* Default noise level to report when noise measurement is not available.
  *   This may be because we're:
@@ -68,12 +74,6 @@ extern struct iwl_cfg iwl4965_agn_cfg;
  *   averages within an s8's (used in some apps) range of negative values. */
 #define IWL_NOISE_MEAS_NOT_AVAILABLE (-127)
 
-enum iwl4965_antenna {
-       IWL_ANTENNA_DIVERSITY,
-       IWL_ANTENNA_MAIN,
-       IWL_ANTENNA_AUX
-};
-
 /*
  * RTS threshold here is total size [2347] minus 4 FCS bytes
  * Per spec:
@@ -91,7 +91,7 @@ enum iwl4965_antenna {
 #define        DEFAULT_SHORT_RETRY_LIMIT 7U
 #define        DEFAULT_LONG_RETRY_LIMIT  4U
 
-struct iwl4965_rx_mem_buffer {
+struct iwl_rx_mem_buffer {
        dma_addr_t dma_addr;
        struct sk_buff *skb;
        struct list_head list;
@@ -102,7 +102,7 @@ struct iwl4965_rx_mem_buffer {
  *
  * Contains common data for Rx and Tx queues
  */
-struct iwl4965_queue {
+struct iwl_queue {
        int n_bd;              /* number of BDs in this queue */
        int write_ptr;       /* 1-st empty entry (index) host_w*/
        int read_ptr;         /* last used entry (index) host_r*/
@@ -118,13 +118,12 @@ struct iwl4965_queue {
 #define MAX_NUM_OF_TBS          (20)
 
 /* One for each TFD */
-struct iwl4965_tx_info {
-       struct ieee80211_tx_status status;
+struct iwl_tx_info {
        struct sk_buff *skb[MAX_NUM_OF_TBS];
 };
 
 /**
- * struct iwl4965_tx_queue - Tx Queue for DMA
+ * struct iwl_tx_queue - Tx Queue for DMA
  * @q: generic Rx/Tx queue descriptor
  * @bd: base of circular buffer of TFDs
  * @cmd: array of command/Tx buffers
@@ -136,12 +135,12 @@ struct iwl4965_tx_info {
  * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame
  * descriptors) and required locking structures.
  */
-struct iwl4965_tx_queue {
-       struct iwl4965_queue q;
-       struct iwl4965_tfd_frame *bd;
+struct iwl_tx_queue {
+       struct iwl_queue q;
+       struct iwl_tfd_frame *bd;
        struct iwl_cmd *cmd;
        dma_addr_t dma_addr_cmd;
-       struct iwl4965_tx_info *txb;
+       struct iwl_tx_info *txb;
        int need_update;
        int sched_retry;
        int active;
@@ -199,9 +198,9 @@ enum {
 struct iwl_channel_info {
        struct iwl4965_channel_tgd_info tgd;
        struct iwl4965_channel_tgh_info tgh;
-       struct iwl4965_eeprom_channel eeprom;     /* EEPROM regulatory limit */
-       struct iwl4965_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for
-                                                  * FAT channel */
+       struct iwl_eeprom_channel eeprom;       /* EEPROM regulatory limit */
+       struct iwl_eeprom_channel fat_eeprom;   /* EEPROM regulatory limit for
+                                                * FAT channel */
 
        u8 channel;       /* channel number */
        u8 flags;         /* flags copied from EEPROM */
@@ -252,29 +251,9 @@ struct iwl4965_clip_group {
 
 /* Power management (not Tx power) structures */
 
-struct iwl4965_power_vec_entry {
-       struct iwl4965_powertable_cmd cmd;
-       u8 no_dtim;
-};
-#define IWL_POWER_RANGE_0  (0)
-#define IWL_POWER_RANGE_1  (1)
-
-#define IWL_POWER_MODE_CAM     0x00    /* Continuously Aware Mode, always on */
-#define IWL_POWER_INDEX_3      0x03
-#define IWL_POWER_INDEX_5      0x05
-#define IWL_POWER_AC           0x06
-#define IWL_POWER_BATTERY      0x07
-#define IWL_POWER_LIMIT                0x07
-#define IWL_POWER_MASK         0x0F
-#define IWL_POWER_ENABLED      0x10
-#define IWL_POWER_LEVEL(x)     ((x) & IWL_POWER_MASK)
-
-struct iwl4965_power_mgr {
-       spinlock_t lock;
-       struct iwl4965_power_vec_entry pwr_range_0[IWL_POWER_AC];
-       struct iwl4965_power_vec_entry pwr_range_1[IWL_POWER_AC];
-       u8 active_index;
-       u32 dtim_val;
+enum iwl_pwr_src {
+       IWL_PWR_SRC_VMAIN,
+       IWL_PWR_SRC_VAUX,
 };
 
 #define IEEE80211_DATA_LEN              2304
@@ -282,7 +261,7 @@ struct iwl4965_power_mgr {
 #define IEEE80211_HLEN                  (IEEE80211_4ADDR_LEN)
 #define IEEE80211_FRAME_LEN             (IEEE80211_DATA_LEN + IEEE80211_HLEN)
 
-struct iwl4965_frame {
+struct iwl_frame {
        union {
                struct ieee80211_hdr frame;
                struct iwl4965_tx_beacon_cmd beacon;
@@ -328,6 +307,8 @@ struct iwl_cmd_meta {
 
 } __attribute__ ((packed));
 
+#define IWL_CMD_MAX_PAYLOAD 320
+
 /**
  * struct iwl_cmd
  *
@@ -339,7 +320,7 @@ struct iwl_cmd {
        struct iwl_cmd_meta meta;       /* driver data */
        struct iwl_cmd_header hdr;      /* uCode API */
        union {
-               struct iwl4965_addsta_cmd addsta;
+               struct iwl_addsta_cmd addsta;
                struct iwl4965_led_cmd led;
                u32 flags;
                u8 val8;
@@ -349,11 +330,12 @@ struct iwl_cmd {
                struct iwl4965_rxon_time_cmd rxon_time;
                struct iwl4965_powertable_cmd powertable;
                struct iwl4965_qosparam_cmd qosparam;
-               struct iwl4965_tx_cmd tx;
+               struct iwl_tx_cmd tx;
                struct iwl4965_tx_beacon_cmd tx_beacon;
                struct iwl4965_rxon_assoc_cmd rxon_assoc;
+               struct iwl_rem_sta_cmd rm_sta;
                u8 *indirect;
-               u8 payload[360];
+               u8 payload[IWL_CMD_MAX_PAYLOAD];
        } __attribute__ ((packed)) cmd;
 } __attribute__ ((packed));
 
@@ -378,7 +360,7 @@ struct iwl_host_cmd {
 #define SUP_RATE_11G_MAX_NUM_CHANNELS  12
 
 /**
- * struct iwl4965_rx_queue - Rx queue
+ * struct iwl_rx_queue - Rx queue
  * @processed: Internal index to last handled Rx packet
  * @read: Shared index to newest available Rx buffer
  * @write: Shared index to oldest written Rx packet
@@ -387,13 +369,13 @@ struct iwl_host_cmd {
  * @rx_used: List of Rx buffers with no SKB
  * @need_update: flag to indicate we need to update read/write index
  *
- * NOTE:  rx_free and rx_used are used as a FIFO for iwl4965_rx_mem_buffers
+ * NOTE:  rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers
  */
-struct iwl4965_rx_queue {
+struct iwl_rx_queue {
        __le32 *bd;
        dma_addr_t dma_addr;
-       struct iwl4965_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
-       struct iwl4965_rx_mem_buffer *queue[RX_QUEUE_SIZE];
+       struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
+       struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
        u32 processed;
        u32 read;
        u32 write;
@@ -421,7 +403,7 @@ struct iwl4965_rx_queue {
 
 #ifdef CONFIG_IWL4965_HT
 /**
- * struct iwl4965_ht_agg -- aggregation status while waiting for block-ack
+ * struct iwl_ht_agg -- aggregation status while waiting for block-ack
  * @txq_id: Tx queue used for Tx attempt
  * @frame_count: # frames attempted by Tx command
  * @wait_for_ba: Expect block-ack before next Tx reply
@@ -434,7 +416,7 @@ struct iwl4965_rx_queue {
  * for block ack (REPLY_COMPRESSED_BA).  This struct stores tx reply info
  * until block ack arrives.
  */
-struct iwl4965_ht_agg {
+struct iwl_ht_agg {
        u16 txq_id;
        u16 frame_count;
        u16 wait_for_ba;
@@ -450,19 +432,18 @@ struct iwl4965_ht_agg {
 
 #endif /* CONFIG_IWL4965_HT */
 
-struct iwl4965_tid_data {
+struct iwl_tid_data {
        u16 seq_number;
        u16 tfds_in_queue;
 #ifdef CONFIG_IWL4965_HT
-       struct iwl4965_ht_agg agg;
+       struct iwl_ht_agg agg;
 #endif /* CONFIG_IWL4965_HT */
 };
 
-struct iwl4965_hw_key {
+struct iwl_hw_key {
        enum ieee80211_key_alg alg;
        int keylen;
        u8 keyidx;
-       struct ieee80211_key_conf *conf;
        u8 key[32];
 };
 
@@ -474,7 +455,6 @@ union iwl4965_ht_rate_supp {
        };
 };
 
-#ifdef CONFIG_IWL4965_HT
 #define CFG_HT_RX_AMPDU_FACTOR_DEF  (0x3)
 #define CFG_HT_MPDU_DENSITY_2USEC   (0x5)
 #define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC
@@ -497,7 +477,6 @@ struct iwl_ht_info {
        u8 ht_protection;
        u8 non_GF_STA_present;
 };
-#endif                         /*CONFIG_IWL4965_HT */
 
 union iwl4965_qos_capabity {
        struct {
@@ -530,12 +509,12 @@ struct iwl4965_qos_info {
 #define STA_PS_STATUS_WAKE             0
 #define STA_PS_STATUS_SLEEP            1
 
-struct iwl4965_station_entry {
-       struct iwl4965_addsta_cmd sta;
-       struct iwl4965_tid_data tid[MAX_TID_COUNT];
+struct iwl_station_entry {
+       struct iwl_addsta_cmd sta;
+       struct iwl_tid_data tid[MAX_TID_COUNT];
        u8 used;
        u8 ps_status;
-       struct iwl4965_hw_key keyinfo;
+       struct iwl_hw_key keyinfo;
 };
 
 /* one for each uCode image (inst/data, boot/init/runtime) */
@@ -566,20 +545,51 @@ struct iwl4965_ibss_seq {
        struct list_head list;
 };
 
+struct iwl_sensitivity_ranges {
+       u16 min_nrg_cck;
+       u16 max_nrg_cck;
+
+       u16 nrg_th_cck;
+       u16 nrg_th_ofdm;
+
+       u16 auto_corr_min_ofdm;
+       u16 auto_corr_min_ofdm_mrc;
+       u16 auto_corr_min_ofdm_x1;
+       u16 auto_corr_min_ofdm_mrc_x1;
+
+       u16 auto_corr_max_ofdm;
+       u16 auto_corr_max_ofdm_mrc;
+       u16 auto_corr_max_ofdm_x1;
+       u16 auto_corr_max_ofdm_mrc_x1;
+
+       u16 auto_corr_max_cck;
+       u16 auto_corr_max_cck_mrc;
+       u16 auto_corr_min_cck;
+       u16 auto_corr_min_cck_mrc;
+};
+
+
+#define IWL_FAT_CHANNEL_52 BIT(IEEE80211_BAND_5GHZ)
+
 /**
  * struct iwl_hw_params
  * @max_txq_num: Max # Tx queues supported
- * @tx_cmd_len: Size of Tx command (but not including frame itself)
- * @tx_ant_num: Number of TX antennas
+ * @tx/rx_chains_num: Number of TX/RX chains
+ * @valid_tx/rx_ant: usable antennas
  * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2)
- * @rx_buffer_size:
  * @max_rxq_log: Log-base-2 of max_rxq_size
+ * @rx_buf_size: Rx buffer size
  * @max_stations:
  * @bcast_sta_id:
+ * @fat_channel: is 40MHz width possible in band 2.4
+ * BIT(IEEE80211_BAND_5GHZ) BIT(IEEE80211_BAND_5GHZ)
+ * @sw_crypto: 0 for hw, 1 for sw
+ * @max_xxx_size: for ucode uses
+ * @ct_kill_threshold: temperature threshold
+ * @struct iwl_sensitivity_ranges: range of sensitivity values
  */
 struct iwl_hw_params {
        u16 max_txq_num;
-       u16 tx_cmd_len;
        u8  tx_chains_num;
        u8  rx_chains_num;
        u8  valid_tx_ant;
@@ -590,10 +600,19 @@ struct iwl_hw_params {
        u32 max_pkt_size;
        u8  max_stations;
        u8  bcast_sta_id;
+       u8 fat_channel;
+       u8 sw_crypto;
+       u32 max_inst_size;
+       u32 max_data_size;
+       u32 max_bsm_size;
+       u32 ct_kill_threshold; /* value in hw-dependent units */
+#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
+       const struct iwl_sensitivity_ranges *sens;
+#endif
 };
 
-#define HT_SHORT_GI_20MHZ_ONLY          (1 << 0)
-#define HT_SHORT_GI_40MHZ_ONLY          (1 << 1)
+#define HT_SHORT_GI_20MHZ      (1 << 0)
+#define HT_SHORT_GI_40MHZ      (1 << 1)
 
 
 #define IWL_RX_HDR(x) ((struct iwl4965_rx_frame_hdr *)(\
@@ -612,43 +631,33 @@ struct iwl_hw_params {
  * for use by iwl-*.c
  *
  *****************************************************************************/
-struct iwl4965_addsta_cmd;
-extern int iwl4965_send_add_station(struct iwl_priv *priv,
-                               struct iwl4965_addsta_cmd *sta, u8 flags);
-extern u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr,
-                         int is_ap, u8 flags, void *ht_data);
+struct iwl_addsta_cmd;
+extern 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, struct ieee80211_ht_info *ht_info);
 extern int iwl4965_is_network_packet(struct iwl_priv *priv,
                                 struct ieee80211_hdr *header);
 extern int iwl4965_power_init_handle(struct iwl_priv *priv);
 extern void iwl4965_handle_data_packet_monitor(struct iwl_priv *priv,
-                                          struct iwl4965_rx_mem_buffer *rxb,
+                                          struct iwl_rx_mem_buffer *rxb,
                                           void *data, short len,
                                           struct ieee80211_rx_status *stats,
                                           u16 phy_flags);
 extern int iwl4965_is_duplicate_packet(struct iwl_priv *priv,
                                       struct ieee80211_hdr *header);
-extern int iwl4965_rx_queue_alloc(struct iwl_priv *priv);
-extern void iwl4965_rx_queue_reset(struct iwl_priv *priv,
-                              struct iwl4965_rx_queue *rxq);
 extern int iwl4965_calc_db_from_ratio(int sig_ratio);
 extern int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm);
-extern int iwl4965_tx_queue_init(struct iwl_priv *priv,
-                            struct iwl4965_tx_queue *txq, int count, u32 id);
-extern void iwl4965_rx_replenish(void *data);
-extern void iwl4965_tx_queue_free(struct iwl_priv *priv, struct iwl4965_tx_queue *txq);
 extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv,
                                        struct ieee80211_hdr *hdr,
                                        const u8 *dest, int left);
-extern int iwl4965_rx_queue_update_write_ptr(struct iwl_priv *priv,
-                                        struct iwl4965_rx_queue *q);
-extern void iwl4965_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
-                                  u32 decrypt_res,
-                                  struct ieee80211_rx_status *stats);
-extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr);
+extern void iwl4965_update_chain_flags(struct iwl_priv *priv);
+int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src);
+
 int iwl4965_init_geos(struct iwl_priv *priv);
 void iwl4965_free_geos(struct iwl_priv *priv);
 
-extern const u8 iwl4965_broadcast_addr[ETH_ALEN];
+extern const u8 iwl_bcast_addr[ETH_ALEN];
 int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
 
 /*
@@ -674,50 +683,59 @@ extern u8 iwl4965_sync_station(struct iwl_priv *priv, int sta_id,
  * iwl4965_mac_     <-- mac80211 callback
  *
  ****************************************************************************/
-extern void iwl4965_hw_rx_handler_setup(struct iwl_priv *priv);
 extern void iwl4965_hw_setup_deferred_work(struct iwl_priv *priv);
 extern void iwl4965_hw_cancel_deferred_work(struct iwl_priv *priv);
-extern int iwl4965_hw_rxq_stop(struct iwl_priv *priv);
 extern int iwl4965_hw_set_hw_params(struct iwl_priv *priv);
-extern int iwl4965_hw_nic_init(struct iwl_priv *priv);
-extern int iwl4965_hw_nic_stop_master(struct iwl_priv *priv);
-extern void iwl4965_hw_txq_ctx_free(struct iwl_priv *priv);
-extern void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv);
-extern int iwl4965_hw_nic_reset(struct iwl_priv *priv);
-extern int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd,
-                                       dma_addr_t addr, u16 len);
-extern int iwl4965_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl4965_tx_queue *txq);
+extern int iwl_rxq_stop(struct iwl_priv *priv);
+extern void iwl_txq_ctx_stop(struct iwl_priv *priv);
 extern int iwl4965_hw_get_temperature(struct iwl_priv *priv);
-extern int iwl4965_hw_tx_queue_init(struct iwl_priv *priv,
-                               struct iwl4965_tx_queue *txq);
 extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
-                                struct iwl4965_frame *frame, u8 rate);
-extern int iwl4965_hw_get_rx_read(struct iwl_priv *priv);
+                                struct iwl_frame *frame, u8 rate);
 extern void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv,
                                     struct iwl_cmd *cmd,
-                                    struct ieee80211_tx_control *ctrl,
+                                    struct ieee80211_tx_info *info,
                                     struct ieee80211_hdr *hdr,
                                     int sta_id, int tx_id);
 extern int iwl4965_hw_reg_send_txpower(struct iwl_priv *priv);
 extern int iwl4965_hw_reg_set_txpower(struct iwl_priv *priv, s8 power);
 extern void iwl4965_hw_rx_statistics(struct iwl_priv *priv,
-                                struct iwl4965_rx_mem_buffer *rxb);
+                                struct iwl_rx_mem_buffer *rxb);
 extern void iwl4965_disable_events(struct iwl_priv *priv);
 extern int iwl4965_get_temperature(const struct iwl_priv *priv);
+extern void iwl4965_rx_reply_rx(struct iwl_priv *priv,
+                               struct iwl_rx_mem_buffer *rxb);
 
 /**
- * iwl4965_hw_find_station - Find station id for a given BSSID
+ * iwl_find_station - Find station id for a given BSSID
  * @bssid: MAC address of station ID to find
  *
  * NOTE:  This should not be hardware specific but the code has
  * not yet been merged into a single common layer for managing the
  * station tables.
  */
-extern u8 iwl4965_hw_find_station(struct iwl_priv *priv, const u8 *bssid);
+extern u8 iwl_find_station(struct iwl_priv *priv, const u8 *bssid);
 
 extern int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel);
-extern int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
-extern int iwl4965_queue_space(const struct iwl4965_queue *q);
+extern int iwl_queue_space(const struct iwl_queue *q);
+static inline int iwl_queue_used(const struct iwl_queue *q, int i)
+{
+       return q->write_ptr > q->read_ptr ?
+               (i >= q->read_ptr && i < q->write_ptr) :
+               !(i < q->read_ptr && i >= q->write_ptr);
+}
+
+
+static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge)
+{
+       /* This is for scan command, the big buffer at end of command array */
+       if (is_huge)
+               return q->n_window;     /* must be power of 2 */
+
+       /* Otherwise, use normal size buffers */
+       return index & (q->n_window - 1);
+}
+
+
 struct iwl_priv;
 
 extern void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio);
@@ -725,45 +743,37 @@ extern void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio);
  * Forward declare iwl-4965.c functions for iwl-base.c
  */
 extern int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv,
-                                         struct iwl4965_tx_queue *txq,
+                                         struct iwl_tx_queue *txq,
                                          u16 byte_cnt);
-extern void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr,
-                               int is_ap);
-extern void iwl4965_set_rxon_chain(struct iwl_priv *priv);
 extern int iwl4965_alive_notify(struct iwl_priv *priv);
 extern void iwl4965_update_rate_scaling(struct iwl_priv *priv, u8 mode);
-extern void iwl4965_chain_noise_reset(struct iwl_priv *priv);
-extern void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags,
-                                    u8 force);
 extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv);
 extern void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv,
                                         u32 rate_n_flags,
-                                        struct ieee80211_tx_control *control);
+                                        struct ieee80211_tx_info *info);
 
 #ifdef CONFIG_IWL4965_HT
-void iwl4965_init_ht_hw_capab(struct iwl_priv *priv,
-                             struct ieee80211_ht_info *ht_info,
-                             enum ieee80211_band band);
+extern void iwl4965_init_ht_hw_capab(const struct iwl_priv *priv,
+                               struct ieee80211_ht_info *ht_info,
+                               enum ieee80211_band band);
 void iwl4965_set_rxon_ht(struct iwl_priv *priv,
                         struct iwl_ht_info *ht_info);
-void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index,
-                               struct ieee80211_ht_info *sta_ht_inf);
 int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
                                    enum ieee80211_ampdu_mlme_action action,
                                    const u8 *addr, u16 tid, u16 *ssn);
 int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id,
                                        u8 tid, int txq_id);
 #else
-static inline void iwl4965_init_ht_hw_capab(struct iwl_priv *priv,
+static inline void iwl4965_init_ht_hw_capab(const struct iwl_priv *priv,
                                            struct ieee80211_ht_info *ht_info,
                                            enum ieee80211_band band) {}
 
 #endif /*CONFIG_IWL4965_HT */
 /* Structures, enum, and defines specific to the 4965 */
 
-#define IWL4965_KW_SIZE 0x1000 /*4k */
+#define IWL_KW_SIZE 0x1000     /*4k */
 
-struct iwl4965_kw {
+struct iwl_kw {
        dma_addr_t dma_addr;
        void *v_addr;
        size_t size;
@@ -787,8 +797,8 @@ struct iwl4965_kw {
 #define IWL_EXT_CHANNEL_OFFSET_RESERVE1  2
 #define IWL_EXT_CHANNEL_OFFSET_BELOW     3
 
-#define NRG_NUM_PREV_STAT_L     20
-#define NUM_RX_CHAINS           (3)
+#define IWL_TX_CRC_SIZE 4
+#define IWL_TX_DELIMITER_SIZE 4
 
 #define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
 
@@ -818,23 +828,8 @@ struct iwl4965_lq_mngr {
 #define MAX_FA_CCK   50
 #define MIN_FA_CCK   5
 
-#define NRG_MIN_CCK  97
-#define NRG_MAX_CCK  0
-
-#define AUTO_CORR_MIN_OFDM        85
-#define AUTO_CORR_MIN_OFDM_MRC    170
-#define AUTO_CORR_MIN_OFDM_X1     105
-#define AUTO_CORR_MIN_OFDM_MRC_X1 220
-#define AUTO_CORR_MAX_OFDM        120
-#define AUTO_CORR_MAX_OFDM_MRC    210
-#define AUTO_CORR_MAX_OFDM_X1     140
-#define AUTO_CORR_MAX_OFDM_MRC_X1 270
 #define AUTO_CORR_STEP_OFDM       1
 
-#define AUTO_CORR_MIN_CCK      (125)
-#define AUTO_CORR_MAX_CCK      (200)
-#define AUTO_CORR_MIN_CCK_MRC  200
-#define AUTO_CORR_MAX_CCK_MRC  400
 #define AUTO_CORR_STEP_CCK     3
 #define AUTO_CORR_MAX_TH_CCK   160
 
@@ -853,6 +848,9 @@ struct iwl4965_lq_mngr {
 #define IN_BAND_FILTER                 0xFF
 #define MIN_AVERAGE_NOISE_MAX_VALUE    0xFFFFFFFF
 
+#define NRG_NUM_PREV_STAT_L     20
+#define NUM_RX_CHAINS           3
+
 enum iwl4965_false_alarm_state {
        IWL_FA_TOO_MANY = 0,
        IWL_FA_TOO_FEW = 1,
@@ -865,11 +863,6 @@ enum iwl4965_chain_noise_state {
        IWL_CHAIN_NOISE_CALIBRATED = 2,
 };
 
-enum iwl4965_sensitivity_state {
-       IWL_SENS_CALIB_ALLOWED = 0,
-       IWL_SENS_CALIB_NEED_REINIT = 1,
-};
-
 enum iwl4965_calib_enabled_state {
        IWL_CALIB_DISABLED = 0,  /* must be 0 */
        IWL_CALIB_ENABLED = 1,
@@ -884,8 +877,24 @@ struct statistics_general_data {
        u32 beacon_energy_c;
 };
 
+struct iwl_calib_results {
+       void *tx_iq_res;
+       void *tx_iq_perd_res;
+       void *lo_res;
+       u32 tx_iq_res_len;
+       u32 tx_iq_perd_res_len;
+       u32 lo_res_len;
+};
+
+enum ucode_type {
+       UCODE_NONE = 0,
+       UCODE_INIT,
+       UCODE_RT
+};
+
+#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
 /* Sensitivity calib data */
-struct iwl4965_sensitivity_data {
+struct iwl_sensitivity_data {
        u32 auto_corr_ofdm;
        u32 auto_corr_ofdm_mrc;
        u32 auto_corr_ofdm_x1;
@@ -909,12 +918,10 @@ struct iwl4965_sensitivity_data {
        s32 nrg_auto_corr_silence_diff;
        u32 num_in_cck_no_fa;
        u32 nrg_th_ofdm;
-
-       u8 state;
 };
 
 /* Chain noise (differential Rx gain) calib data */
-struct iwl4965_chain_noise_data {
+struct iwl_chain_noise_data {
        u8 state;
        u16 beacon_count;
        u32 chain_noise_a;
@@ -927,6 +934,7 @@ struct iwl4965_chain_noise_data {
        u8 delta_gain_code[NUM_RX_CHAINS];
        u8 radio_write;
 };
+#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */
 
 #define        EEPROM_SEM_TIMEOUT 10           /* milliseconds */
 #define EEPROM_SEM_RETRY_LIMIT 1000    /* number of attempts (not time) */
@@ -960,7 +968,7 @@ struct iwl_priv {
        bool add_radiotap;
 
        void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
-                                      struct iwl4965_rx_mem_buffer *rxb);
+                                      struct iwl_rx_mem_buffer *rxb);
 
        struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
 
@@ -985,6 +993,9 @@ struct iwl_priv {
        s32 temperature;        /* degrees Kelvin */
        s32 last_temperature;
 
+       /* init calibration results */
+       struct iwl_calib_results calib_results;
+
        /* Scan related variables */
        unsigned long last_scan_jiffies;
        unsigned long next_scan_jiffies;
@@ -1007,6 +1018,9 @@ struct iwl_priv {
 
        /* pci hardware address support */
        void __iomem *hw_base;
+       u32  hw_rev;
+       u32  hw_wa_rev;
+       u8   rev_id;
 
        /* uCode images, save to reload in case of failure */
        struct fw_desc ucode_code;      /* runtime inst */
@@ -1015,6 +1029,8 @@ struct iwl_priv {
        struct fw_desc ucode_init;      /* initialization inst */
        struct fw_desc ucode_init_data; /* initialization data */
        struct fw_desc ucode_boot;      /* bootstrap inst */
+       enum ucode_type ucode_type;
+       u8 ucode_write_complete;        /* the image write is complete */
 
 
        struct iwl4965_rxon_time_cmd rxon_timing;
@@ -1023,16 +1039,16 @@ struct iwl_priv {
         * changed via explicit cast within the
         * routines that actually update the physical
         * hardware */
-       const struct iwl4965_rxon_cmd active_rxon;
-       struct iwl4965_rxon_cmd staging_rxon;
+       const struct iwl_rxon_cmd active_rxon;
+       struct iwl_rxon_cmd staging_rxon;
 
        int error_recovering;
-       struct iwl4965_rxon_cmd recovery_rxon;
+       struct iwl_rxon_cmd recovery_rxon;
 
        /* 1st responses from initialize and runtime uCode images.
         * 4965's initialize alive response contains some calibration data. */
-       struct iwl4965_init_alive_resp card_alive_init;
-       struct iwl4965_alive_resp card_alive;
+       struct iwl_init_alive_resp card_alive_init;
+       struct iwl_alive_resp card_alive;
 #ifdef CONFIG_IWLWIFI_RFKILL
        struct iwl_rfkill_mngr rfkill_mngr;
 #endif
@@ -1050,13 +1066,12 @@ struct iwl_priv {
 
        u8 assoc_station_added;
        u8 use_ant_b_for_management_frame;      /* Tx antenna selection */
-       u8 valid_antenna;       /* Bit mask of antennas actually connected */
-#ifdef CONFIG_IWL4965_SENSITIVITY
-       struct iwl4965_sensitivity_data sensitivity_data;
-       struct iwl4965_chain_noise_data chain_noise_data;
        u8 start_calib;
+#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
+       struct iwl_sensitivity_data sensitivity_data;
+       struct iwl_chain_noise_data chain_noise_data;
        __le16 sensitivity_tbl[HD_TABLE_SIZE];
-#endif /*CONFIG_IWL4965_SENSITIVITY*/
+#endif /*CONFIG_IWLWIFI_RUN_TIME_CALIB*/
 
 #ifdef CONFIG_IWL4965_HT
        struct iwl_ht_info current_ht_config;
@@ -1075,10 +1090,10 @@ struct iwl_priv {
        int activity_timer_active;
 
        /* Rx and Tx DMA processing queues */
-       struct iwl4965_rx_queue rxq;
-       struct iwl4965_tx_queue txq[IWL_MAX_NUM_QUEUES];
+       struct iwl_rx_queue rxq;
+       struct iwl_tx_queue txq[IWL_MAX_NUM_QUEUES];
        unsigned long txq_ctx_active_msk;
-       struct iwl4965_kw kw;   /* keep warm address */
+       struct iwl_kw kw;       /* keep warm address */
        u32 scd_base_addr;      /* scheduler sram base address */
 
        unsigned long status;
@@ -1092,7 +1107,7 @@ struct iwl_priv {
                u64 bytes;
        } tx_stats[3], rx_stats[3];
 
-       struct iwl4965_power_mgr power_data;
+       struct iwl_power_mgr power_data;
 
        struct iwl4965_notif_statistics statistics;
        unsigned long last_statistics_time;
@@ -1111,7 +1126,7 @@ struct iwl_priv {
        /*station table variables */
        spinlock_t sta_lock;
        int num_stations;
-       struct iwl4965_station_entry stations[IWL_STATION_COUNT];
+       struct iwl_station_entry stations[IWL_STATION_COUNT];
        struct iwl_wep_key wep_keys[WEP_KEYS_MAX];
        u8 default_wep_key;
        u8 key_mapping_key;
@@ -1122,8 +1137,6 @@ struct iwl_priv {
 
        u8 mac80211_registered;
 
-       u32 notif_missed_beacons;
-
        /* Rx'd packet timing information */
        u32 last_beacon_time;
        u64 last_tsf;
@@ -1137,7 +1150,8 @@ struct iwl_priv {
        struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE];
 
        /* eeprom */
-       struct iwl4965_eeprom eeprom;
+       u8 *eeprom;
+       struct iwl_eeprom_calib_info *calib_info;
 
        enum ieee80211_if_types iw_mode;
 
@@ -1151,6 +1165,7 @@ struct iwl_priv {
        struct iwl_hw_params hw_params;
        /* driver/uCode shared Tx Byte Counts and Rx status */
        void *shared_virt;
+       int rb_closed_offset;
        /* Physical Pointer to Tx Byte Counts and Rx status */
        dma_addr_t shared_phys;
 
@@ -1176,6 +1191,7 @@ struct iwl_priv {
        struct work_struct report_work;
        struct work_struct request_scan;
        struct work_struct beacon_update;
+       struct work_struct set_monitor;
 
        struct tasklet_struct irq_tasklet;
 
@@ -1197,6 +1213,7 @@ struct iwl_priv {
 
 #ifdef CONFIG_IWLWIFI_DEBUG
        /* debugging info */
+       u32 debug_level;
        u32 framecnt_to_us;
        atomic_t restrict_refcnt;
 #ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -1206,12 +1223,56 @@ struct iwl_priv {
 #endif /* CONFIG_IWLWIFI_DEBUG */
 
        struct work_struct txpower_work;
-#ifdef CONFIG_IWL4965_SENSITIVITY
+#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
+       u32 disable_sens_cal;
+       u32 disable_chain_noise_cal;
+#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */
+#ifdef CONFIG_IWL4965_RUN_TIME_CALIB
        struct work_struct sensitivity_work;
-#endif
+#endif /* CONFIG_IWL4965_RUN_TIME_CALIB */
        struct timer_list statistics_periodic;
 }; /*iwl_priv */
 
+static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id)
+{
+       set_bit(txq_id, &priv->txq_ctx_active_msk);
+}
+
+static inline void iwl_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id)
+{
+       clear_bit(txq_id, &priv->txq_ctx_active_msk);
+}
+
+#ifdef CONFIG_IWLWIF_DEBUG
+const char *iwl_get_tx_fail_reason(u32 status);
+#else
+static inline const char *iwl_get_tx_fail_reason(u32 status) { return ""; }
+#endif
+
+
+#ifdef CONFIG_IWL4965_HT
+static inline int iwl_get_ra_sta_id(struct iwl_priv *priv,
+                                   struct ieee80211_hdr *hdr)
+{
+       if (priv->iw_mode == IEEE80211_IF_TYPE_STA) {
+               return IWL_AP_ID;
+       } else {
+               u8 *da = ieee80211_get_DA(hdr);
+               return iwl_find_station(priv, da);
+       }
+}
+
+static inline struct ieee80211_hdr *iwl_tx_queue_get_hdr(struct iwl_priv *priv,
+                                                        int txq_id, int idx)
+{
+       if (priv->txq[txq_id].txb[idx].skb[0])
+               return (struct ieee80211_hdr *)priv->txq[txq_id].
+                               txb[idx].skb[0]->data;
+       return NULL;
+}
+#endif
+
+
 static inline int iwl_is_associated(struct iwl_priv *priv)
 {
        return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
@@ -1224,11 +1285,6 @@ static inline int is_channel_valid(const struct iwl_channel_info *ch_info)
        return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0;
 }
 
-static inline int is_channel_narrow(const struct iwl_channel_info *ch_info)
-{
-       return (ch_info->flags & EEPROM_CHANNEL_NARROW) ? 1 : 0;
-}
-
 static inline int is_channel_radar(const struct iwl_channel_info *ch_info)
 {
        return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0;
@@ -1254,6 +1310,23 @@ static inline int is_channel_ibss(const struct iwl_channel_info *ch)
        return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0;
 }
 
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level,
+                                     void *p, u32 len)
+{
+       if (!(priv->debug_level & level))
+               return;
+
+       print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1,
+                       p, len, 1);
+}
+#else
+static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level,
+                                     void *p, u32 len)
+{
+}
+#endif
+
 extern const struct iwl_channel_info *iwl_get_channel_info(
        const struct iwl_priv *priv, enum ieee80211_band band, u16 channel);
 
index a07d5dcb7abc7f05e048d2bc8a514487cef3be27..11f9d9557a0e091203adc3402cdf41070df6f03e 100644 (file)
@@ -68,8 +68,8 @@
 
 #include <net/mac80211.h>
 
-#include "iwl-4965-commands.h"
-#include "iwl-4965.h"
+#include "iwl-commands.h"
+#include "iwl-dev.h"
 #include "iwl-core.h"
 #include "iwl-debug.h"
 #include "iwl-eeprom.h"
@@ -193,6 +193,12 @@ void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwlcore_eeprom_release_semaphore);
 
+const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset)
+{
+       BUG_ON(offset >= priv->cfg->eeprom_size);
+       return &priv->eeprom[offset];
+}
+EXPORT_SYMBOL(iwlcore_eeprom_query_addr);
 
 /**
  * iwl_eeprom_init - read EEPROM contents
@@ -203,30 +209,35 @@ EXPORT_SYMBOL(iwlcore_eeprom_release_semaphore);
  */
 int iwl_eeprom_init(struct iwl_priv *priv)
 {
-       u16 *e = (u16 *)&priv->eeprom;
+       u16 *e;
        u32 gp = iwl_read32(priv, CSR_EEPROM_GP);
        u32 r;
-       int sz = sizeof(priv->eeprom);
+       int sz = priv->cfg->eeprom_size;
        int ret;
        int i;
        u16 addr;
 
-       /* The EEPROM structure has several padding buffers within it
-        * and when adding new EEPROM maps is subject to programmer errors
-        * which may be very difficult to identify without explicitly
-        * checking the resulting size of the eeprom map. */
-       BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE);
+       /* allocate eeprom */
+       priv->eeprom = kzalloc(sz, GFP_KERNEL);
+       if (!priv->eeprom) {
+               ret = -ENOMEM;
+               goto alloc_err;
+       }
+       e = (u16 *)priv->eeprom;
 
-       if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) {
+       ret = priv->cfg->ops->lib->eeprom_ops.verify_signature(priv);
+       if (ret < 0) {
                IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp);
-               return -ENOENT;
+               ret = -ENOENT;
+               goto err;
        }
 
        /* Make sure driver (instead of uCode) is allowed to read EEPROM */
        ret = priv->cfg->ops->lib->eeprom_ops.acquire_semaphore(priv);
        if (ret < 0) {
                IWL_ERROR("Failed to acquire EEPROM semaphore.\n");
-               return -ENOENT;
+               ret = -ENOENT;
+               goto err;
        }
 
        /* eeprom is an array of 16bit values */
@@ -250,61 +261,98 @@ int iwl_eeprom_init(struct iwl_priv *priv)
                e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
        }
        ret = 0;
-
 done:
        priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv);
+err:
+       if (ret)
+               kfree(priv->eeprom);
+alloc_err:
        return ret;
 }
 EXPORT_SYMBOL(iwl_eeprom_init);
 
+void iwl_eeprom_free(struct iwl_priv *priv)
+{
+       if(priv->eeprom)
+               kfree(priv->eeprom);
+       priv->eeprom = NULL;
+}
+EXPORT_SYMBOL(iwl_eeprom_free);
+
+int iwl_eeprom_check_version(struct iwl_priv *priv)
+{
+       return priv->cfg->ops->lib->eeprom_ops.check_version(priv);
+}
+EXPORT_SYMBOL(iwl_eeprom_check_version);
+
+const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset)
+{
+       return priv->cfg->ops->lib->eeprom_ops.query_addr(priv, offset);
+}
+EXPORT_SYMBOL(iwl_eeprom_query_addr);
+
+u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset)
+{
+       return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8);
+}
+EXPORT_SYMBOL(iwl_eeprom_query16);
 
 void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac)
 {
-       memcpy(mac, priv->eeprom.mac_address, 6);
+       const u8 *addr = priv->cfg->ops->lib->eeprom_ops.query_addr(priv,
+                                       EEPROM_MAC_ADDRESS);
+       memcpy(mac, addr, ETH_ALEN);
 }
 EXPORT_SYMBOL(iwl_eeprom_get_mac);
 
 static void iwl_init_band_reference(const struct iwl_priv *priv,
-                                   int band,
-                                   int *eeprom_ch_count,
-                                   const struct iwl4965_eeprom_channel
-                                   **eeprom_ch_info,
-                                   const u8 **eeprom_ch_index)
+                       int eep_band, int *eeprom_ch_count,
+                       const struct iwl_eeprom_channel **eeprom_ch_info,
+                       const u8 **eeprom_ch_index)
 {
-       switch (band) {
+       u32 offset = priv->cfg->ops->lib->
+                       eeprom_ops.regulatory_bands[eep_band - 1];
+       switch (eep_band) {
        case 1:         /* 2.4GHz band */
                *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1);
-               *eeprom_ch_info = priv->eeprom.band_1_channels;
+               *eeprom_ch_info = (struct iwl_eeprom_channel *)
+                               iwl_eeprom_query_addr(priv, offset);
                *eeprom_ch_index = iwl_eeprom_band_1;
                break;
        case 2:         /* 4.9GHz band */
                *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2);
-               *eeprom_ch_info = priv->eeprom.band_2_channels;
+               *eeprom_ch_info = (struct iwl_eeprom_channel *)
+                               iwl_eeprom_query_addr(priv, offset);
                *eeprom_ch_index = iwl_eeprom_band_2;
                break;
        case 3:         /* 5.2GHz band */
                *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3);
-               *eeprom_ch_info = priv->eeprom.band_3_channels;
+               *eeprom_ch_info = (struct iwl_eeprom_channel *)
+                               iwl_eeprom_query_addr(priv, offset);
                *eeprom_ch_index = iwl_eeprom_band_3;
                break;
        case 4:         /* 5.5GHz band */
                *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4);
-               *eeprom_ch_info = priv->eeprom.band_4_channels;
+               *eeprom_ch_info = (struct iwl_eeprom_channel *)
+                               iwl_eeprom_query_addr(priv, offset);
                *eeprom_ch_index = iwl_eeprom_band_4;
                break;
        case 5:         /* 5.7GHz band */
                *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5);
-               *eeprom_ch_info = priv->eeprom.band_5_channels;
+               *eeprom_ch_info = (struct iwl_eeprom_channel *)
+                               iwl_eeprom_query_addr(priv, offset);
                *eeprom_ch_index = iwl_eeprom_band_5;
                break;
        case 6:         /* 2.4GHz FAT channels */
                *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6);
-               *eeprom_ch_info = priv->eeprom.band_24_channels;
+               *eeprom_ch_info = (struct iwl_eeprom_channel *)
+                               iwl_eeprom_query_addr(priv, offset);
                *eeprom_ch_index = iwl_eeprom_band_6;
                break;
        case 7:         /* 5 GHz FAT channels */
                *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7);
-               *eeprom_ch_info = priv->eeprom.band_52_channels;
+               *eeprom_ch_info = (struct iwl_eeprom_channel *)
+                               iwl_eeprom_query_addr(priv, offset);
                *eeprom_ch_index = iwl_eeprom_band_7;
                break;
        default:
@@ -317,13 +365,13 @@ static void iwl_init_band_reference(const struct iwl_priv *priv,
                            ? # x " " : "")
 
 /**
- * iwl4965_set_fat_chan_info - Copy fat channel info into driver's priv.
+ * iwl_set_fat_chan_info - Copy fat channel info into driver's priv.
  *
  * Does not set up a command, or touch hardware.
  */
-static int iwl4965_set_fat_chan_info(struct iwl_priv *priv,
+static int iwl_set_fat_chan_info(struct iwl_priv *priv,
                              enum ieee80211_band band, u16 channel,
-                             const struct iwl4965_eeprom_channel *eeprom_ch,
+                             const struct iwl_eeprom_channel *eeprom_ch,
                              u8 fat_extension_channel)
 {
        struct iwl_channel_info *ch_info;
@@ -334,7 +382,7 @@ static int iwl4965_set_fat_chan_info(struct iwl_priv *priv,
        if (!is_channel_valid(ch_info))
                return -1;
 
-       IWL_DEBUG_INFO("FAT Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x"
+       IWL_DEBUG_INFO("FAT Ch. %d [%sGHz] %s%s%s%s%s(0x%02x"
                        " %ddBm): Ad-Hoc %ssupported\n",
                        ch_info->channel,
                        is_channel_a_band(ch_info) ?
@@ -343,7 +391,6 @@ static int iwl4965_set_fat_chan_info(struct iwl_priv *priv,
                        CHECK_AND_PRINT(ACTIVE),
                        CHECK_AND_PRINT(RADAR),
                        CHECK_AND_PRINT(WIDE),
-                       CHECK_AND_PRINT(NARROW),
                        CHECK_AND_PRINT(DFS),
                        eeprom_ch->flags,
                        eeprom_ch->max_power_avg,
@@ -372,7 +419,7 @@ int iwl_init_channel_map(struct iwl_priv *priv)
 {
        int eeprom_ch_count = 0;
        const u8 *eeprom_ch_index = NULL;
-       const struct iwl4965_eeprom_channel *eeprom_ch_info = NULL;
+       const struct iwl_eeprom_channel *eeprom_ch_info = NULL;
        int band, ch;
        struct iwl_channel_info *ch_info;
 
@@ -381,12 +428,6 @@ int iwl_init_channel_map(struct iwl_priv *priv)
                return 0;
        }
 
-       if (priv->eeprom.version < 0x2f) {
-               IWL_WARNING("Unsupported EEPROM version: 0x%04X\n",
-                           priv->eeprom.version);
-               return -EINVAL;
-       }
-
        IWL_DEBUG_INFO("Initializing regulatory info from EEPROM\n");
 
        priv->channel_count =
@@ -447,7 +488,7 @@ int iwl_init_channel_map(struct iwl_priv *priv)
                        ch_info->scan_power = eeprom_ch_info[ch].max_power_avg;
                        ch_info->min_power = 0;
 
-                       IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x"
+                       IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x"
                                       " %ddBm): Ad-Hoc %ssupported\n",
                                       ch_info->channel,
                                       is_channel_a_band(ch_info) ?
@@ -457,7 +498,6 @@ int iwl_init_channel_map(struct iwl_priv *priv)
                                       CHECK_AND_PRINT_I(ACTIVE),
                                       CHECK_AND_PRINT_I(RADAR),
                                       CHECK_AND_PRINT_I(WIDE),
-                                      CHECK_AND_PRINT_I(NARROW),
                                       CHECK_AND_PRINT_I(DFS),
                                       eeprom_ch_info[ch].flags,
                                       eeprom_ch_info[ch].max_power_avg,
@@ -502,16 +542,16 @@ int iwl_init_channel_map(struct iwl_priv *priv)
                                fat_extension_chan = HT_IE_EXT_CHANNEL_ABOVE;
 
                        /* Set up driver's info for lower half */
-                       iwl4965_set_fat_chan_info(priv, ieeeband,
-                                                 eeprom_ch_index[ch],
-                                                 &(eeprom_ch_info[ch]),
-                                                 fat_extension_chan);
+                       iwl_set_fat_chan_info(priv, ieeeband,
+                                               eeprom_ch_index[ch],
+                                               &(eeprom_ch_info[ch]),
+                                               fat_extension_chan);
 
                        /* Set up driver's info for upper half */
-                       iwl4965_set_fat_chan_info(priv, ieeeband,
-                                                 (eeprom_ch_index[ch] + 4),
-                                                 &(eeprom_ch_info[ch]),
-                                                 HT_IE_EXT_CHANNEL_BELOW);
+                       iwl_set_fat_chan_info(priv, ieeeband,
+                                               (eeprom_ch_index[ch] + 4),
+                                               &(eeprom_ch_info[ch]),
+                                               HT_IE_EXT_CHANNEL_BELOW);
                }
        }
 
@@ -520,23 +560,21 @@ int iwl_init_channel_map(struct iwl_priv *priv)
 EXPORT_SYMBOL(iwl_init_channel_map);
 
 /*
- * iwl_free_channel_map - undo allocations in iwl4965_init_channel_map
+ * iwl_free_channel_map - undo allocations in iwl_init_channel_map
  */
 void iwl_free_channel_map(struct iwl_priv *priv)
 {
        kfree(priv->channel_info);
        priv->channel_count = 0;
 }
-EXPORT_SYMBOL(iwl_free_channel_map);
 
 /**
  * iwl_get_channel_info - Find driver's private channel info
  *
  * Based on band and channel number.
  */
-const struct iwl_channel_info *iwl_get_channel_info(
-               const struct iwl_priv *priv,
-               enum ieee80211_band band, u16 channel)
+const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv,
+                                       enum ieee80211_band band, u16 channel)
 {
        int i;
 
index bd0a042ca77f02d8afca5b8f6503967515f35c46..d3a2a5b4ac56214f4127c4a6456650e0f6fc82b6 100644 (file)
@@ -106,7 +106,7 @@ enum {
        EEPROM_CHANNEL_ACTIVE = (1 << 3),       /* active scanning allowed */
        EEPROM_CHANNEL_RADAR = (1 << 4),        /* radar detection required */
        EEPROM_CHANNEL_WIDE = (1 << 5),         /* 20 MHz channel okay */
-       EEPROM_CHANNEL_NARROW = (1 << 6),       /* 10 MHz channel (not used) */
+       /* Bit 6 Reserved (was Narrow Channel) */
        EEPROM_CHANNEL_DFS = (1 << 7),  /* dynamic freq selection candidate */
 };
 
@@ -116,7 +116,7 @@ enum {
 
 /* *regulatory* channel data format in eeprom, one for each channel.
  * There are separate entries for FAT (40 MHz) vs. normal (20 MHz) channels. */
-struct iwl4965_eeprom_channel {
+struct iwl_eeprom_channel {
        u8 flags;               /* EEPROM_CHANNEL_* flags copied from EEPROM */
        s8 max_power_avg;       /* max power (dBm) on this chnl, limit 31 */
 } __attribute__ ((packed));
@@ -131,17 +131,55 @@ struct iwl4965_eeprom_channel {
  * each of 3 target output levels */
 #define EEPROM_TX_POWER_MEASUREMENTS   (3)
 
-#define EEPROM_4965_TX_POWER_VERSION        (2)
+/* 4965 Specific */
+/* 4965 driver does not work with txpower calibration version < 5 */
+#define EEPROM_4965_TX_POWER_VERSION    (5)
+#define EEPROM_4965_EEPROM_VERSION     (0x2f)
+#define EEPROM_4965_CALIB_VERSION_OFFSET       (2*0xB6) /* 2 bytes */
+#define EEPROM_4965_CALIB_TXPOWER_OFFSET       (2*0xE8) /* 48  bytes */
+#define EEPROM_4965_BOARD_REVISION             (2*0x4F) /* 2 bytes */
+#define EEPROM_4965_BOARD_PBA                  (2*0x56+1) /* 9 bytes */
+
+/* 5000 Specific */
+#define EEPROM_5000_TX_POWER_VERSION    (4)
+#define EEPROM_5000_EEPROM_VERSION     (0x11A)
+
+/*5000 calibrations */
+#define EEPROM_5000_CALIB_ALL  (INDIRECT_ADDRESS | INDIRECT_CALIBRATION)
+#define EEPROM_5000_XTAL       ((2*0x128) | EEPROM_5000_CALIB_ALL)
+
+/* 5000 links */
+#define EEPROM_5000_LINK_HOST             (2*0x64)
+#define EEPROM_5000_LINK_GENERAL          (2*0x65)
+#define EEPROM_5000_LINK_REGULATORY       (2*0x66)
+#define EEPROM_5000_LINK_CALIBRATION      (2*0x67)
+#define EEPROM_5000_LINK_PROCESS_ADJST    (2*0x68)
+#define EEPROM_5000_LINK_OTHERS           (2*0x69)
+
+/* 5000 regulatory - indirect access */
+#define EEPROM_5000_REG_SKU_ID ((0x02)\
+               | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 4  bytes */
+#define EEPROM_5000_REG_BAND_1_CHANNELS       ((0x08)\
+               | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 28 bytes */
+#define EEPROM_5000_REG_BAND_2_CHANNELS       ((0x26)\
+               | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 26 bytes */
+#define EEPROM_5000_REG_BAND_3_CHANNELS       ((0x42)\
+               | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 24 bytes */
+#define EEPROM_5000_REG_BAND_4_CHANNELS       ((0x5C)\
+               | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 22 bytes */
+#define EEPROM_5000_REG_BAND_5_CHANNELS       ((0x74)\
+               | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 12 bytes */
+#define EEPROM_5000_REG_BAND_24_FAT_CHANNELS  ((0x82)\
+               | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 14  bytes */
+#define EEPROM_5000_REG_BAND_52_FAT_CHANNELS  ((0x92)\
+               | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 22  bytes */
 
-/* 4965 driver does not work with txpower calibration version < 5.
- * Look for this in calib_version member of struct iwl4965_eeprom. */
-#define EEPROM_TX_POWER_VERSION_NEW    (5)
 
 /* 2.4 GHz */
 extern const u8 iwl_eeprom_band_1[14];
 
 /*
- * 4965 factory calibration data for one txpower level, on one channel,
+ * factory calibration data for one txpower level, on one channel,
  * measured on one of the 2 tx chains (radio transmitter and associated
  * antenna).  EEPROM contains:
  *
@@ -154,7 +192,7 @@ extern const u8 iwl_eeprom_band_1[14];
  *
  * 4)  RF power amplifier detector level measurement (not used).
  */
-struct iwl4965_eeprom_calib_measure {
+struct iwl_eeprom_calib_measure {
        u8 temperature;         /* Device temperature (Celsius) */
        u8 gain_idx;            /* Index into gain table */
        u8 actual_pow;          /* Measured RF output power, half-dBm */
@@ -163,22 +201,22 @@ struct iwl4965_eeprom_calib_measure {
 
 
 /*
- * 4965 measurement set for one channel.  EEPROM contains:
+ * measurement set for one channel.  EEPROM contains:
  *
  * 1)  Channel number measured
  *
  * 2)  Measurements for each of 3 power levels for each of 2 radio transmitters
  *     (a.k.a. "tx chains") (6 measurements altogether)
  */
-struct iwl4965_eeprom_calib_ch_info {
+struct iwl_eeprom_calib_ch_info {
        u8 ch_num;
-       struct iwl4965_eeprom_calib_measure
+       struct iwl_eeprom_calib_measure
                measurements[EEPROM_TX_POWER_TX_CHAINS]
                        [EEPROM_TX_POWER_MEASUREMENTS];
 } __attribute__ ((packed));
 
 /*
- * 4965 txpower subband info.
+ * txpower subband info.
  *
  * For each frequency subband, EEPROM contains the following:
  *
@@ -187,16 +225,16 @@ struct iwl4965_eeprom_calib_ch_info {
  *
  * 2)  Sample measurement sets for 2 channels close to the range endpoints.
  */
-struct iwl4965_eeprom_calib_subband_info {
+struct iwl_eeprom_calib_subband_info {
        u8 ch_from;     /* channel number of lowest channel in subband */
        u8 ch_to;       /* channel number of highest channel in subband */
-       struct iwl4965_eeprom_calib_ch_info ch1;
-       struct iwl4965_eeprom_calib_ch_info ch2;
+       struct iwl_eeprom_calib_ch_info ch1;
+       struct iwl_eeprom_calib_ch_info ch2;
 } __attribute__ ((packed));
 
 
 /*
- * 4965 txpower calibration info.  EEPROM contains:
+ * txpower calibration info.  EEPROM contains:
  *
  * 1)  Factory-measured saturation power levels (maximum levels at which
  *     tx power amplifier can output a signal without too much distortion).
@@ -212,55 +250,58 @@ struct iwl4965_eeprom_calib_subband_info {
  *     characteristics of the analog radio circuitry vary with frequency.
  *
  *     Not all sets need to be filled with data;
- *     struct iwl4965_eeprom_calib_subband_info contains range of channels
+ *     struct iwl_eeprom_calib_subband_info contains range of channels
  *     (0 if unused) for each set of data.
  */
-struct iwl4965_eeprom_calib_info {
+struct iwl_eeprom_calib_info {
        u8 saturation_power24;  /* half-dBm (e.g. "34" = 17 dBm) */
        u8 saturation_power52;  /* half-dBm */
        s16 voltage;            /* signed */
-       struct iwl4965_eeprom_calib_subband_info
+       struct iwl_eeprom_calib_subband_info
                band_info[EEPROM_TX_POWER_BANDS];
 } __attribute__ ((packed));
 
 
-
-/*
- * 4965 EEPROM map
- */
-struct iwl4965_eeprom {
-       u8 reserved0[16];
-       u16 device_id;          /* abs.ofs: 16 */
-       u8 reserved1[2];
-       u16 pmc;                /* abs.ofs: 20 */
-       u8 reserved2[20];
-       u8 mac_address[6];      /* abs.ofs: 42 */
-       u8 reserved3[58];
-       u16 board_revision;     /* abs.ofs: 106 */
-       u8 reserved4[11];
-       u8 board_pba_number[9]; /* abs.ofs: 119 */
-       u8 reserved5[8];
-       u16 version;            /* abs.ofs: 136 */
-       u8 sku_cap;             /* abs.ofs: 138 */
-       u8 leds_mode;           /* abs.ofs: 139 */
-       u16 oem_mode;
-       u16 wowlan_mode;        /* abs.ofs: 142 */
-       u16 leds_time_interval; /* abs.ofs: 144 */
-       u8 leds_off_time;       /* abs.ofs: 146 */
-       u8 leds_on_time;        /* abs.ofs: 147 */
-       u8 almgor_m_version;    /* abs.ofs: 148 */
-       u8 antenna_switch_type; /* abs.ofs: 149 */
-       u8 reserved6[8];
-       u16 board_revision_4965;        /* abs.ofs: 158 */
-       u8 reserved7[13];
-       u8 board_pba_number_4965[9];    /* abs.ofs: 173 */
-       u8 reserved8[10];
-       u8 sku_id[4];           /* abs.ofs: 192 */
+#define ADDRESS_MSK                 0x0000FFFF
+#define INDIRECT_TYPE_MSK           0x000F0000
+#define INDIRECT_HOST               0x00010000
+#define INDIRECT_GENERAL            0x00020000
+#define INDIRECT_REGULATORY         0x00030000
+#define INDIRECT_CALIBRATION        0x00040000
+#define INDIRECT_PROCESS_ADJST      0x00050000
+#define INDIRECT_OTHERS             0x00060000
+#define INDIRECT_ADDRESS            0x00100000
+
+/* General */
+#define EEPROM_DEVICE_ID                    (2*0x08)   /* 2 bytes */
+#define EEPROM_MAC_ADDRESS                  (2*0x15)   /* 6  bytes */
+#define EEPROM_BOARD_REVISION               (2*0x35)   /* 2  bytes */
+#define EEPROM_BOARD_PBA_NUMBER             (2*0x3B+1) /* 9  bytes */
+#define EEPROM_VERSION                      (2*0x44)   /* 2  bytes */
+#define EEPROM_SKU_CAP                      (2*0x45)   /* 1  bytes */
+#define EEPROM_LEDS_MODE                    (2*0x45+1) /* 1  bytes */
+#define EEPROM_OEM_MODE                     (2*0x46)   /* 2  bytes */
+#define EEPROM_WOWLAN_MODE                  (2*0x47)   /* 2  bytes */
+#define EEPROM_RADIO_CONFIG                 (2*0x48)   /* 2  bytes */
+#define EEPROM_3945_M_VERSION               (2*0x4A)   /* 1  bytes */
+#define EEPROM_ANTENNA_SWITCH_TYPE          (2*0x4A+1) /* 1  bytes */
+
+/* The following masks are to be applied on EEPROM_RADIO_CONFIG */
+#define EEPROM_RF_CFG_TYPE_MSK(x)   (x & 0x3)         /* bits 0-1   */
+#define EEPROM_RF_CFG_STEP_MSK(x)   ((x >> 2)  & 0x3) /* bits 2-3   */
+#define EEPROM_RF_CFG_DASH_MSK(x)   ((x >> 4)  & 0x3) /* bits 4-5   */
+#define EEPROM_RF_CFG_PNUM_MSK(x)   ((x >> 6)  & 0x3) /* bits 6-7   */
+#define EEPROM_RF_CFG_TX_ANT_MSK(x) ((x >> 8)  & 0xF) /* bits 8-11  */
+#define EEPROM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
+
+#define EEPROM_3945_RF_CFG_TYPE_MAX  0x0
+#define EEPROM_4965_RF_CFG_TYPE_MAX  0x1
+#define EEPROM_5000_RF_CFG_TYPE_MAX  0x3
 
 /*
  * Per-channel regulatory data.
  *
- * Each channel that *might* be supported by 3945 or 4965 has a fixed location
+ * Each channel that *might* be supported by iwl has a fixed location
  * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory
  * txpower (MSB).
  *
@@ -269,40 +310,38 @@ struct iwl4965_eeprom {
  *
  * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
  */
-       u16 band_1_count;       /* abs.ofs: 196 */
-       struct iwl4965_eeprom_channel band_1_channels[14]; /* abs.ofs: 196 */
+#define EEPROM_REGULATORY_SKU_ID            (2*0x60)    /* 4  bytes */
+#define EEPROM_REGULATORY_BAND_1            (2*0x62)   /* 2  bytes */
+#define EEPROM_REGULATORY_BAND_1_CHANNELS   (2*0x63)   /* 28 bytes */
 
 /*
  * 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196,
  * 5.0 GHz channels 7, 8, 11, 12, 16
  * (4915-5080MHz) (none of these is ever supported)
  */
-       u16 band_2_count;       /* abs.ofs: 226 */
-       struct iwl4965_eeprom_channel band_2_channels[13]; /* abs.ofs: 228 */
+#define EEPROM_REGULATORY_BAND_2            (2*0x71)   /* 2  bytes */
+#define EEPROM_REGULATORY_BAND_2_CHANNELS   (2*0x72)   /* 26 bytes */
 
 /*
  * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
  * (5170-5320MHz)
  */
-       u16 band_3_count;       /* abs.ofs: 254 */
-       struct iwl4965_eeprom_channel band_3_channels[12]; /* abs.ofs: 256 */
+#define EEPROM_REGULATORY_BAND_3            (2*0x7F)   /* 2  bytes */
+#define EEPROM_REGULATORY_BAND_3_CHANNELS   (2*0x80)   /* 24 bytes */
 
 /*
  * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
  * (5500-5700MHz)
  */
-       u16 band_4_count;       /* abs.ofs: 280 */
-       struct iwl4965_eeprom_channel band_4_channels[11]; /* abs.ofs: 282 */
+#define EEPROM_REGULATORY_BAND_4            (2*0x8C)   /* 2  bytes */
+#define EEPROM_REGULATORY_BAND_4_CHANNELS   (2*0x8D)   /* 22 bytes */
 
 /*
  * 5.7 GHz channels 145, 149, 153, 157, 161, 165
  * (5725-5825MHz)
  */
-       u16 band_5_count;       /* abs.ofs: 304 */
-       struct iwl4965_eeprom_channel band_5_channels[6]; /* abs.ofs: 306 */
-
-       u8 reserved10[2];
-
+#define EEPROM_REGULATORY_BAND_5            (2*0x98)   /* 2  bytes */
+#define EEPROM_REGULATORY_BAND_5_CHANNELS   (2*0x99)   /* 12 bytes */
 
 /*
  * 2.4 GHz FAT channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11)
@@ -319,52 +358,35 @@ struct iwl4965_eeprom {
  *
  * NOTE:  4965 does not support FAT channels on 2.4 GHz.
  */
-       struct iwl4965_eeprom_channel band_24_channels[7]; /* abs.ofs: 320 */
-       u8 reserved11[2];
+#define EEPROM_4965_REGULATORY_BAND_24_FAT_CHANNELS (2*0xA0)   /* 14 bytes */
 
 /*
  * 5.2 GHz FAT channels 36 (40), 44 (48), 52 (56), 60 (64),
  * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161)
  */
-       struct iwl4965_eeprom_channel band_52_channels[11]; /* abs.ofs: 336 */
-       u8 reserved12[6];
-
-/*
- * 4965 driver requires txpower calibration format version 5 or greater.
- * Driver does not work with txpower calibration version < 5.
- * This value is simply a 16-bit number, no major/minor versions here.
- */
-       u16 calib_version;      /* abs.ofs: 364 */
-       u8 reserved13[2];
-       u8 reserved14[96];      /* abs.ofs: 368 */
-
-/*
- * 4965 Txpower calibration data.
- */
-       struct iwl4965_eeprom_calib_info calib_info;    /* abs.ofs: 464 */
-
-       u8 reserved16[140];     /* fill out to full 1024 byte block */
-
-
-} __attribute__ ((packed));
-
-#define IWL_EEPROM_IMAGE_SIZE 1024
-
-/* End of EEPROM */
+#define EEPROM_4965_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8)   /* 22 bytes */
 
 struct iwl_eeprom_ops {
+       const u32 regulatory_bands[7];
        int (*verify_signature) (struct iwl_priv *priv);
        int (*acquire_semaphore) (struct iwl_priv *priv);
        void (*release_semaphore) (struct iwl_priv *priv);
+       int (*check_version) (struct iwl_priv *priv);
+       const u8* (*query_addr) (const struct iwl_priv *priv, size_t offset);
 };
 
 
 void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac);
 int iwl_eeprom_init(struct iwl_priv *priv);
+void iwl_eeprom_free(struct iwl_priv *priv);
+int  iwl_eeprom_check_version(struct iwl_priv *priv);
+const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset);
+u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset);
 
 int iwlcore_eeprom_verify_signature(struct iwl_priv *priv);
 int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv);
 void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv);
+const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset);
 
 int iwl_init_channel_map(struct iwl_priv *priv);
 void iwl_free_channel_map(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h
new file mode 100644 (file)
index 0000000..9446424
--- /dev/null
@@ -0,0 +1,391 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+/****************************/
+/* Flow Handler Definitions */
+/****************************/
+
+/**
+ * This I/O area is directly read/writable by driver (e.g. Linux uses writel())
+ * Addresses are offsets from device's PCI hardware base address.
+ */
+#define FH_MEM_LOWER_BOUND                   (0x1000)
+#define FH_MEM_UPPER_BOUND                   (0x1EF0)
+
+/**
+ * Keep-Warm (KW) buffer base address.
+ *
+ * Driver must allocate a 4KByte buffer that is used by 4965 for keeping the
+ * host DRAM powered on (via dummy accesses to DRAM) to maintain low-latency
+ * DRAM access when 4965 is Txing or Rxing.  The dummy accesses prevent host
+ * from going into a power-savings mode that would cause higher DRAM latency,
+ * and possible data over/under-runs, before all Tx/Rx is complete.
+ *
+ * Driver loads FH_KW_MEM_ADDR_REG with the physical address (bits 35:4)
+ * of the buffer, which must be 4K aligned.  Once this is set up, the 4965
+ * automatically invokes keep-warm accesses when normal accesses might not
+ * be sufficient to maintain fast DRAM response.
+ *
+ * Bit fields:
+ *  31-0:  Keep-warm buffer physical base address [35:4], must be 4K aligned
+ */
+#define FH_KW_MEM_ADDR_REG                  (FH_MEM_LOWER_BOUND + 0x97C)
+
+
+/**
+ * TFD Circular Buffers Base (CBBC) addresses
+ *
+ * 4965 has 16 base pointer registers, one for each of 16 host-DRAM-resident
+ * circular buffers (CBs/queues) containing Transmit Frame Descriptors (TFDs)
+ * (see struct iwl_tfd_frame).  These 16 pointer registers are offset by 0x04
+ * bytes from one another.  Each TFD circular buffer in DRAM must be 256-byte
+ * aligned (address bits 0-7 must be 0).
+ *
+ * Bit fields in each pointer register:
+ *  27-0: TFD CB physical base address [35:8], must be 256-byte aligned
+ */
+#define FH_MEM_CBBC_LOWER_BOUND          (FH_MEM_LOWER_BOUND + 0x9D0)
+#define FH_MEM_CBBC_UPPER_BOUND          (FH_MEM_LOWER_BOUND + 0xA10)
+
+/* Find TFD CB base pointer for given queue (range 0-15). */
+#define FH_MEM_CBBC_QUEUE(x)  (FH_MEM_CBBC_LOWER_BOUND + (x) * 0x4)
+
+
+/**
+ * Rx SRAM Control and Status Registers (RSCSR)
+ *
+ * These registers provide handshake between driver and 4965 for the Rx queue
+ * (this queue handles *all* command responses, notifications, Rx data, etc.
+ * sent from 4965 uCode to host driver).  Unlike Tx, there is only one Rx
+ * queue, and only one Rx DMA/FIFO channel.  Also unlike Tx, which can
+ * concatenate up to 20 DRAM buffers to form a Tx frame, each Receive Buffer
+ * Descriptor (RBD) points to only one Rx Buffer (RB); there is a 1:1
+ * mapping between RBDs and RBs.
+ *
+ * Driver must allocate host DRAM memory for the following, and set the
+ * physical address of each into 4965 registers:
+ *
+ * 1)  Receive Buffer Descriptor (RBD) circular buffer (CB), typically with 256
+ *     entries (although any power of 2, up to 4096, is selectable by driver).
+ *     Each entry (1 dword) points to a receive buffer (RB) of consistent size
+ *     (typically 4K, although 8K or 16K are also selectable by driver).
+ *     Driver sets up RB size and number of RBDs in the CB via Rx config
+ *     register FH_MEM_RCSR_CHNL0_CONFIG_REG.
+ *
+ *     Bit fields within one RBD:
+ *     27-0:  Receive Buffer physical address bits [35:8], 256-byte aligned
+ *
+ *     Driver sets physical address [35:8] of base of RBD circular buffer
+ *     into FH_RSCSR_CHNL0_RBDCB_BASE_REG [27:0].
+ *
+ * 2)  Rx status buffer, 8 bytes, in which 4965 indicates which Rx Buffers
+ *     (RBs) have been filled, via a "write pointer", actually the index of
+ *     the RB's corresponding RBD within the circular buffer.  Driver sets
+ *     physical address [35:4] into FH_RSCSR_CHNL0_STTS_WPTR_REG [31:0].
+ *
+ *     Bit fields in lower dword of Rx status buffer (upper dword not used
+ *     by driver; see struct iwl4965_shared, val0):
+ *     31-12:  Not used by driver
+ *     11- 0:  Index of last filled Rx buffer descriptor
+ *             (4965 writes, driver reads this value)
+ *
+ * As the driver prepares Receive Buffers (RBs) for 4965 to fill, driver must
+ * enter pointers to these RBs into contiguous RBD circular buffer entries,
+ * and update the 4965's "write" index register,
+ * FH_RSCSR_CHNL0_RBDCB_WPTR_REG.
+ *
+ * This "write" index corresponds to the *next* RBD that the driver will make
+ * available, i.e. one RBD past the tail of the ready-to-fill RBDs within
+ * the circular buffer.  This value should initially be 0 (before preparing any
+ * RBs), should be 8 after preparing the first 8 RBs (for example), and must
+ * wrap back to 0 at the end of the circular buffer (but don't wrap before
+ * "read" index has advanced past 1!  See below).
+ * NOTE:  4965 EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8.
+ *
+ * As the 4965 fills RBs (referenced from contiguous RBDs within the circular
+ * buffer), it updates the Rx status buffer in host DRAM, 2) described above,
+ * to tell the driver the index of the latest filled RBD.  The driver must
+ * read this "read" index from DRAM after receiving an Rx interrupt from 4965.
+ *
+ * The driver must also internally keep track of a third index, which is the
+ * next RBD to process.  When receiving an Rx interrupt, driver should process
+ * all filled but unprocessed RBs up to, but not including, the RB
+ * corresponding to the "read" index.  For example, if "read" index becomes "1",
+ * driver may process the RB pointed to by RBD 0.  Depending on volume of
+ * traffic, there may be many RBs to process.
+ *
+ * If read index == write index, 4965 thinks there is no room to put new data.
+ * Due to this, the maximum number of filled RBs is 255, instead of 256.  To
+ * be safe, make sure that there is a gap of at least 2 RBDs between "write"
+ * and "read" indexes; that is, make sure that there are no more than 254
+ * buffers waiting to be filled.
+ */
+#define FH_MEM_RSCSR_LOWER_BOUND       (FH_MEM_LOWER_BOUND + 0xBC0)
+#define FH_MEM_RSCSR_UPPER_BOUND       (FH_MEM_LOWER_BOUND + 0xC00)
+#define FH_MEM_RSCSR_CHNL0             (FH_MEM_RSCSR_LOWER_BOUND)
+
+/**
+ * Physical base address of 8-byte Rx Status buffer.
+ * Bit fields:
+ *  31-0: Rx status buffer physical base address [35:4], must 16-byte aligned.
+ */
+#define FH_RSCSR_CHNL0_STTS_WPTR_REG   (FH_MEM_RSCSR_CHNL0)
+
+/**
+ * Physical base address of Rx Buffer Descriptor Circular Buffer.
+ * Bit fields:
+ *  27-0:  RBD CD physical base address [35:8], must be 256-byte aligned.
+ */
+#define FH_RSCSR_CHNL0_RBDCB_BASE_REG  (FH_MEM_RSCSR_CHNL0 + 0x004)
+
+/**
+ * Rx write pointer (index, really!).
+ * Bit fields:
+ *  11-0:  Index of driver's most recent prepared-to-be-filled RBD, + 1.
+ *         NOTE:  For 256-entry circular buffer, use only bits [7:0].
+ */
+#define FH_RSCSR_CHNL0_RBDCB_WPTR_REG  (FH_MEM_RSCSR_CHNL0 + 0x008)
+#define FH_RSCSR_CHNL0_WPTR        (FH_RSCSR_CHNL0_RBDCB_WPTR_REG)
+
+
+/**
+ * Rx Config/Status Registers (RCSR)
+ * Rx Config Reg for channel 0 (only channel used)
+ *
+ * Driver must initialize FH_MEM_RCSR_CHNL0_CONFIG_REG as follows for
+ * normal operation (see bit fields).
+ *
+ * Clearing FH_MEM_RCSR_CHNL0_CONFIG_REG to 0 turns off Rx DMA.
+ * Driver should poll FH_MEM_RSSR_RX_STATUS_REG        for
+ * FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (bit 24) before continuing.
+ *
+ * Bit fields:
+ * 31-30: Rx DMA channel enable: '00' off/pause, '01' pause at end of frame,
+ *        '10' operate normally
+ * 29-24: reserved
+ * 23-20: # RBDs in circular buffer = 2^value; use "8" for 256 RBDs (normal),
+ *        min "5" for 32 RBDs, max "12" for 4096 RBDs.
+ * 19-18: reserved
+ * 17-16: size of each receive buffer; '00' 4K (normal), '01' 8K,
+ *        '10' 12K, '11' 16K.
+ * 15-14: reserved
+ * 13-12: IRQ destination; '00' none, '01' host driver (normal operation)
+ * 11- 4: timeout for closing Rx buffer and interrupting host (units 32 usec)
+ *        typical value 0x10 (about 1/2 msec)
+ *  3- 0: reserved
+ */
+#define FH_MEM_RCSR_LOWER_BOUND      (FH_MEM_LOWER_BOUND + 0xC00)
+#define FH_MEM_RCSR_UPPER_BOUND      (FH_MEM_LOWER_BOUND + 0xCC0)
+#define FH_MEM_RCSR_CHNL0            (FH_MEM_RCSR_LOWER_BOUND)
+
+#define FH_MEM_RCSR_CHNL0_CONFIG_REG   (FH_MEM_RCSR_CHNL0)
+
+#define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MSK (0x00000FF0) /* bits 4-11 */
+#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MSK   (0x00001000) /* bits 12 */
+#define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK (0x00008000) /* bit 15 */
+#define FH_RCSR_CHNL0_RX_CONFIG_RB_SIZE_MSK   (0x00030000) /* bits 16-17 */
+#define FH_RCSR_CHNL0_RX_CONFIG_RBDBC_SIZE_MSK (0x00F00000) /* bits 20-23 */
+#define FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MSK (0xC0000000) /* bits 30-31*/
+
+#define FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT  (20)
+#define FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_BITSHIFT        (4)
+#define RX_RB_TIMEOUT  (0x10)
+
+#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL         (0x00000000)
+#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_EOF_VAL     (0x40000000)
+#define FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL        (0x80000000)
+
+#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K    (0x00000000)
+#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K    (0x00010000)
+#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_12K   (0x00020000)
+#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_16K   (0x00030000)
+
+#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL       (0x00000000)
+#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL     (0x00001000)
+
+
+/**
+ * Rx Shared Status Registers (RSSR)
+ *
+ * After stopping Rx DMA channel (writing 0 to
+ * FH_MEM_RCSR_CHNL0_CONFIG_REG), driver must poll
+ * FH_MEM_RSSR_RX_STATUS_REG until Rx channel is idle.
+ *
+ * Bit fields:
+ *  24:  1 = Channel 0 is idle
+ *
+ * FH_MEM_RSSR_SHARED_CTRL_REG and FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV
+ * contain default values that should not be altered by the driver.
+ */
+#define FH_MEM_RSSR_LOWER_BOUND           (FH_MEM_LOWER_BOUND + 0xC40)
+#define FH_MEM_RSSR_UPPER_BOUND           (FH_MEM_LOWER_BOUND + 0xD00)
+
+#define FH_MEM_RSSR_SHARED_CTRL_REG       (FH_MEM_RSSR_LOWER_BOUND)
+#define FH_MEM_RSSR_RX_STATUS_REG      (FH_MEM_RSSR_LOWER_BOUND + 0x004)
+#define FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV\
+                                       (FH_MEM_RSSR_LOWER_BOUND + 0x008)
+
+#define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE      (0x01000000)
+
+
+/**
+ * Transmit DMA Channel Control/Status Registers (TCSR)
+ *
+ * 4965 has one configuration register for each of 8 Tx DMA/FIFO channels
+ * supported in hardware (don't confuse these with the 16 Tx queues in DRAM,
+ * which feed the DMA/FIFO channels); config regs are separated by 0x20 bytes.
+ *
+ * To use a Tx DMA channel, driver must initialize its
+ * FH_TCSR_CHNL_TX_CONFIG_REG(chnl) with:
+ *
+ * FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+ * FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL
+ *
+ * All other bits should be 0.
+ *
+ * Bit fields:
+ * 31-30: Tx DMA channel enable: '00' off/pause, '01' pause at end of frame,
+ *        '10' operate normally
+ * 29- 4: Reserved, set to "0"
+ *     3: Enable internal DMA requests (1, normal operation), disable (0)
+ *  2- 0: Reserved, set to "0"
+ */
+#define FH_TCSR_LOWER_BOUND  (FH_MEM_LOWER_BOUND + 0xD00)
+#define FH_TCSR_UPPER_BOUND  (FH_MEM_LOWER_BOUND + 0xE60)
+
+/* Find Control/Status reg for given Tx DMA/FIFO channel */
+#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \
+       (FH_TCSR_LOWER_BOUND + 0x20 * _chnl)
+
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL    (0x00000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL     (0x00000008)
+
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE            (0x00000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF        (0x40000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE           (0x80000000)
+
+#define FH_TCSR_CHNL_NUM                            (7)
+
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY          (0x00000000)
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT           (0x00002000)
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID          (0x00000003)
+
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT           (0x00000000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD          (0x00100000)
+#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD           (0x00200000)
+
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM      (20)
+#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX      (12)
+#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \
+       (FH_TCSR_LOWER_BOUND + 0x20 * _chnl)
+#define FH_TCSR_CHNL_TX_CREDIT_REG(_chnl) \
+         (FH_TCSR_LOWER_BOUND + 0x20 * _chnl + 0x4)
+#define FH_TCSR_CHNL_TX_BUF_STS_REG(_chnl) \
+        (FH_TCSR_LOWER_BOUND + 0x20 * _chnl + 0x8)
+
+/**
+ * Tx Shared Status Registers (TSSR)
+ *
+ * After stopping Tx DMA channel (writing 0 to
+ * FH_TCSR_CHNL_TX_CONFIG_REG(chnl)), driver must poll
+ * FH_TSSR_TX_STATUS_REG until selected Tx channel is idle
+ * (channel's buffers empty | no pending requests).
+ *
+ * Bit fields:
+ * 31-24:  1 = Channel buffers empty (channel 7:0)
+ * 23-16:  1 = No pending requests (channel 7:0)
+ */
+#define FH_TSSR_LOWER_BOUND            (FH_MEM_LOWER_BOUND + 0xEA0)
+#define FH_TSSR_UPPER_BOUND            (FH_MEM_LOWER_BOUND + 0xEC0)
+
+#define FH_TSSR_TX_STATUS_REG  (FH_TSSR_LOWER_BOUND + 0x010)
+
+#define FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) ((1 << (_chnl)) << 24)
+#define FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl) ((1 << (_chnl)) << 16)
+
+#define FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) \
+       (FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \
+       FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl))
+
+
+
+#define FH_REGS_LOWER_BOUND                 (0x1000)
+#define FH_REGS_UPPER_BOUND                 (0x2000)
+
+/* Tx service channels */
+#define FH_SRVC_CHNL                                (9)
+#define FH_SRVC_LOWER_BOUND          (FH_REGS_LOWER_BOUND + 0x9C8)
+#define FH_SRVC_UPPER_BOUND          (FH_REGS_LOWER_BOUND + 0x9D0)
+#define FH_SRVC_CHNL_SRAM_ADDR_REG(_chnl) \
+               (FH_SRVC_LOWER_BOUND + ((_chnl) - 9) * 0x4)
+
+/* TFDB  Area - TFDs buffer table */
+#define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK      (0xFFFFFFFF)
+#define FH_TFDIB_LOWER_BOUND       (FH_REGS_LOWER_BOUND + 0x900)
+#define FH_TFDIB_UPPER_BOUND       (FH_REGS_LOWER_BOUND + 0x958)
+#define FH_TFDIB_CTRL0_REG(_chnl)  (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl))
+#define FH_TFDIB_CTRL1_REG(_chnl)  (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl) + 0x4)
+
+/* TCSR: tx_config register values */
+#define FH_RSCSR_FRAME_SIZE_MSK        (0x00003FFF)    /* bits 0-13 */
+
index fdb27f1cdc08d9ad73330aceb7043bc60784a71a..6c537360820b280df3502994978336c978265785 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/version.h>
 #include <net/mac80211.h>
 
-#include "iwl-4965.h" /* FIXME: remove */
+#include "iwl-dev.h" /* FIXME: remove */
 #include "iwl-debug.h"
 #include "iwl-eeprom.h"
 #include "iwl-core.h"
@@ -56,6 +56,7 @@ const char *get_cmd_string(u8 cmd)
                IWL_CMD(REPLY_RATE_SCALE);
                IWL_CMD(REPLY_LEDS_CMD);
                IWL_CMD(REPLY_TX_LINK_QUALITY_CMD);
+               IWL_CMD(COEX_PRIORITY_TABLE_CMD);
                IWL_CMD(RADAR_NOTIFICATION);
                IWL_CMD(REPLY_QUIET_CMD);
                IWL_CMD(REPLY_CHANNEL_SWITCH);
@@ -89,6 +90,9 @@ const char *get_cmd_string(u8 cmd)
                IWL_CMD(REPLY_RX_MPDU_CMD);
                IWL_CMD(REPLY_RX);
                IWL_CMD(REPLY_COMPRESSED_BA);
+               IWL_CMD(CALIBRATION_CFG_CMD);
+               IWL_CMD(CALIBRATION_RES_NOTIFICATION);
+               IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION);
        default:
                return "UNKNOWN";
 
@@ -101,7 +105,7 @@ EXPORT_SYMBOL(get_cmd_string);
 static int iwl_generic_cmd_callback(struct iwl_priv *priv,
                                    struct iwl_cmd *cmd, struct sk_buff *skb)
 {
-       struct iwl4965_rx_packet *pkt = NULL;
+       struct iwl_rx_packet *pkt = NULL;
 
        if (!skb) {
                IWL_ERROR("Error: Response NULL in %s.\n",
@@ -109,7 +113,7 @@ static int iwl_generic_cmd_callback(struct iwl_priv *priv,
                return 1;
        }
 
-       pkt = (struct iwl4965_rx_packet *)skb->data;
+       pkt = (struct iwl_rx_packet *)skb->data;
        if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
                IWL_ERROR("Bad return from %s (0x%08X)\n",
                        get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
@@ -139,7 +143,7 @@ static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return -EBUSY;
 
-       ret = priv->cfg->ops->utils->enqueue_hcmd(priv, cmd);
+       ret = iwl_enqueue_hcmd(priv, cmd);
        if (ret < 0) {
                IWL_ERROR("Error sending %s: enqueue_hcmd failed: %d\n",
                          get_cmd_string(cmd->id), ret);
@@ -170,7 +174,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
        if (cmd->meta.flags & CMD_WANT_SKB)
                cmd->meta.source = &cmd->meta;
 
-       cmd_idx = priv->cfg->ops->utils->enqueue_hcmd(priv, cmd);
+       cmd_idx = iwl_enqueue_hcmd(priv, cmd);
        if (cmd_idx < 0) {
                ret = cmd_idx;
                IWL_ERROR("Error sending %s: enqueue_hcmd failed: %d\n",
index a443472bea62c8312328ed45baa4289cfda836be..dedefa06ad8f125b2a1a2b3eb7a08776f197f854 100644 (file)
@@ -136,6 +136,8 @@ static inline void iwl_set_bits16(__le16 *dst, u8 pos, u8 len, int val)
 
 #define KELVIN_TO_CELSIUS(x) ((x)-273)
 #define CELSIUS_TO_KELVIN(x) ((x)+273)
+#define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
+
 
 #define IEEE80211_CHAN_W_RADAR_DETECT 0x00000010
 
@@ -235,6 +237,25 @@ static inline int ieee80211_is_reassoc_response(u16 fc)
               ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_RESP);
 }
 
+static inline int ieee80211_is_qos_data(u16 fc)
+{
+       return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
+              ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_QOS_DATA);
+}
+/**
+ * ieee80211_get_qos_ctrl - get pointer to the QoS control field
+ *
+ * This function returns the pointer to 802.11 header QoS field (2 bytes)
+ * This function doesn't check whether hdr is a QoS hdr, use with care
+ * @hdr: struct ieee80211_hdr *hdr
+ * @hdr_len: header length
+ */
+
+static inline u8 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr, int hdr_len)
+{
+       return  ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN);
+}
+
 static inline int iwl_check_bits(unsigned long field, unsigned long mask)
 {
        return ((field & mask) == mask) ? 1 : 0;
index 03fdf5b434a13de415e957a51237e3985ee99d82..aa6ad18494ce8243ce2c0f12107ca69d912063b2 100644 (file)
@@ -39,7 +39,7 @@
 #include <linux/etherdevice.h>
 #include <asm/unaligned.h>
 
-#include "iwl-4965.h"
+#include "iwl-dev.h"
 #include "iwl-core.h"
 #include "iwl-io.h"
 #include "iwl-helpers.h"
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
new file mode 100644 (file)
index 0000000..2e71803
--- /dev/null
@@ -0,0 +1,423 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2008 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:
+ * James P. Ketrenos <ipw2100-admin@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/version.h>
+#include <linux/init.h>
+
+#include <net/mac80211.h>
+
+#include "iwl-eeprom.h"
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-commands.h"
+#include "iwl-debug.h"
+#include "iwl-power.h"
+#include "iwl-helpers.h"
+
+/*
+ * Setting power level allow the card to go to sleep when not busy
+ * there are three factor that decide the power level to go to, they
+ * are list here with its priority
+ *  1- critical_power_setting this will be set according to card temperature.
+ *  2- system_power_setting this will be set by system PM manager.
+ *  3- user_power_setting this will be set by user either by writing to sys or
+ *     mac80211
+ *
+ * if system_power_setting and user_power_setting is set to auto
+ * the power level will be decided according to association status and battery
+ * status.
+ *
+ */
+
+#define MSEC_TO_USEC 1024
+#define IWL_POWER_RANGE_0_MAX  (2)
+#define IWL_POWER_RANGE_1_MAX  (10)
+
+
+#define NOSLP __constant_cpu_to_le16(0), 0, 0
+#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0
+#define SLP_TOUT(T) __constant_cpu_to_le32((T) * MSEC_TO_USEC)
+#define SLP_VEC(X0, X1, X2, X3, X4) {__constant_cpu_to_le32(X0), \
+                                    __constant_cpu_to_le32(X1), \
+                                    __constant_cpu_to_le32(X2), \
+                                    __constant_cpu_to_le32(X3), \
+                                    __constant_cpu_to_le32(X4)}
+
+#define IWL_POWER_ON_BATTERY           IWL_POWER_INDEX_5
+#define IWL_POWER_ON_AC_DISASSOC       IWL_POWER_MODE_CAM
+#define IWL_POWER_ON_AC_ASSOC          IWL_POWER_MODE_CAM
+
+
+#define IWL_CT_KILL_TEMPERATURE                110
+#define IWL_MIN_POWER_TEMPERATURE      100
+#define IWL_REDUCED_POWER_TEMPERATURE  95
+
+/* default power management (not Tx power) table values */
+/* for tim  0-10 */
+static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = {
+       {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
+       {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
+       {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
+       {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 2, 2, 2, 0xFF)}, 0},
+       {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 2, 4, 4, 0xFF)}, 1},
+       {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 2, 4, 6, 0xFF)}, 2}
+};
+
+
+/* for tim = 3-10 */
+static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = {
+       {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
+       {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
+       {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0},
+       {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 4, 6, 7, 9)}, 0},
+       {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 4, 6, 9, 10)}, 1},
+       {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2}
+};
+
+/* for tim > 11 */
+static struct iwl_power_vec_entry range_2[IWL_POWER_AC] = {
+       {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
+       {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
+       {{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0},
+       {{SLP, SLP_TOUT(50), SLP_TOUT(100), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
+       {{SLP, SLP_TOUT(50), SLP_TOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
+       {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
+};
+
+/* decide the right power level according to association status
+ * and battery status
+ */
+static u16 iwl_get_auto_power_mode(struct iwl_priv *priv)
+{
+       u16 mode = priv->power_data.user_power_setting;
+
+       switch (priv->power_data.user_power_setting) {
+       case IWL_POWER_AUTO:
+               /* if running on battery */
+               if (priv->power_data.is_battery_active)
+                       mode = IWL_POWER_ON_BATTERY;
+               else if (iwl_is_associated(priv))
+                       mode = IWL_POWER_ON_AC_ASSOC;
+               else
+                       mode = IWL_POWER_ON_AC_DISASSOC;
+               break;
+       case IWL_POWER_BATTERY:
+               mode = IWL_POWER_INDEX_3;
+               break;
+       case IWL_POWER_AC:
+               mode = IWL_POWER_MODE_CAM;
+               break;
+       }
+       return mode;
+}
+
+/* initialize to default */
+static int iwl_power_init_handle(struct iwl_priv *priv)
+{
+       int ret = 0, i;
+       struct iwl_power_mgr *pow_data;
+       int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_AC;
+       u16 pci_pm;
+
+       IWL_DEBUG_POWER("Initialize power \n");
+
+       pow_data = &(priv->power_data);
+
+       memset(pow_data, 0, sizeof(*pow_data));
+
+       memcpy(&pow_data->pwr_range_0[0], &range_0[0], size);
+       memcpy(&pow_data->pwr_range_1[0], &range_1[0], size);
+       memcpy(&pow_data->pwr_range_2[0], &range_2[0], size);
+
+       ret = pci_read_config_word(priv->pci_dev,
+                                 PCI_LINK_CTRL, &pci_pm);
+       if (ret != 0)
+               return 0;
+       else {
+               struct iwl4965_powertable_cmd *cmd;
+
+               IWL_DEBUG_POWER("adjust power command flags\n");
+
+               for (i = 0; i < IWL_POWER_AC; i++) {
+                       cmd = &pow_data->pwr_range_0[i].cmd;
+
+                       if (pci_pm & 0x1)
+                               cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
+                       else
+                               cmd->flags |= IWL_POWER_PCI_PM_MSK;
+               }
+       }
+       return ret;
+}
+
+/* adjust power command according to dtim period and power level*/
+static int iwl_update_power_command(struct iwl_priv *priv,
+                                   struct iwl4965_powertable_cmd *cmd,
+                                   u16 mode)
+{
+       int ret = 0, i;
+       u8 skip;
+       u32 max_sleep = 0;
+       struct iwl_power_vec_entry *range;
+       u8 period = 0;
+       struct iwl_power_mgr *pow_data;
+
+       if (mode > IWL_POWER_INDEX_5) {
+               IWL_DEBUG_POWER("Error invalid power mode \n");
+               return -1;
+       }
+       pow_data = &(priv->power_data);
+
+       if (pow_data->dtim_period <= IWL_POWER_RANGE_0_MAX)
+               range = &pow_data->pwr_range_0[0];
+       else if (pow_data->dtim_period <= IWL_POWER_RANGE_1_MAX)
+               range = &pow_data->pwr_range_1[0];
+       else
+               range = &pow_data->pwr_range_2[0];
+
+       period = pow_data->dtim_period;
+       memcpy(cmd, &range[mode].cmd, sizeof(struct iwl4965_powertable_cmd));
+
+       if (period == 0) {
+               period = 1;
+               skip = 0;
+       } else
+               skip = range[mode].no_dtim;
+
+       if (skip == 0) {
+               max_sleep = period;
+               cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
+       } else {
+               __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1];
+               max_sleep = le32_to_cpu(slp_itrvl);
+               if (max_sleep == 0xFF)
+                       max_sleep = period * (skip + 1);
+               else if (max_sleep >  period)
+                       max_sleep = (le32_to_cpu(slp_itrvl) / period) * period;
+               cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
+       }
+
+       for (i = 0; i < IWL_POWER_VEC_SIZE; i++) {
+               if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep)
+                       cmd->sleep_interval[i] = cpu_to_le32(max_sleep);
+       }
+
+       IWL_DEBUG_POWER("Flags value = 0x%08X\n", cmd->flags);
+       IWL_DEBUG_POWER("Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout));
+       IWL_DEBUG_POWER("Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout));
+       IWL_DEBUG_POWER("Sleep interval vector = { %d , %d , %d , %d , %d }\n",
+                       le32_to_cpu(cmd->sleep_interval[0]),
+                       le32_to_cpu(cmd->sleep_interval[1]),
+                       le32_to_cpu(cmd->sleep_interval[2]),
+                       le32_to_cpu(cmd->sleep_interval[3]),
+                       le32_to_cpu(cmd->sleep_interval[4]));
+
+       return ret;
+}
+
+
+/*
+ * calucaute the final power mode index
+ */
+int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh)
+{
+       struct iwl_power_mgr *setting = &(priv->power_data);
+       int ret = 0;
+       u16 uninitialized_var(final_mode);
+
+       /* If on battery, set to 3,
+       * if plugged into AC power, set to CAM ("continuously aware mode"),
+       * else user level */
+
+       switch (setting->system_power_setting) {
+       case IWL_POWER_AUTO:
+               final_mode = iwl_get_auto_power_mode(priv);
+               break;
+       case IWL_POWER_BATTERY:
+               final_mode = IWL_POWER_INDEX_3;
+               break;
+       case IWL_POWER_AC:
+               final_mode = IWL_POWER_MODE_CAM;
+               break;
+       default:
+               final_mode = setting->system_power_setting;
+       }
+
+       if (setting->critical_power_setting > final_mode)
+               final_mode = setting->critical_power_setting;
+
+       /* driver only support CAM for non STA network */
+       if (priv->iw_mode != IEEE80211_IF_TYPE_STA)
+               final_mode = IWL_POWER_MODE_CAM;
+
+       if (!iwl_is_rfkill(priv) && !setting->power_disabled &&
+           ((setting->power_mode != final_mode) || refresh)) {
+               struct iwl4965_powertable_cmd cmd;
+
+               if (final_mode != IWL_POWER_MODE_CAM)
+                       set_bit(STATUS_POWER_PMI, &priv->status);
+
+               iwl_update_power_command(priv, &cmd, final_mode);
+               cmd.keep_alive_beacons = 0;
+
+               if (final_mode == IWL_POWER_INDEX_5)
+                       cmd.flags |= IWL_POWER_FAST_PD;
+
+               if (priv->cfg->ops->lib->set_power)
+                       ret = priv->cfg->ops->lib->set_power(priv, &cmd);
+
+               if (final_mode == IWL_POWER_MODE_CAM)
+                       clear_bit(STATUS_POWER_PMI, &priv->status);
+               else
+                       set_bit(STATUS_POWER_PMI, &priv->status);
+
+               if (priv->cfg->ops->lib->update_chain_flags)
+                       priv->cfg->ops->lib->update_chain_flags(priv);
+
+               if (!ret)
+                       setting->power_mode = final_mode;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(iwl_power_update_mode);
+
+/* Allow other iwl code to disable/enable power management active
+ * this will be usefull for rate scale to disable PM during heavy
+ * Tx/Rx activities
+ */
+int iwl_power_disable_management(struct iwl_priv *priv)
+{
+       u16 prev_mode;
+       int ret = 0;
+
+       if (priv->power_data.power_disabled)
+               return -EBUSY;
+
+       prev_mode = priv->power_data.user_power_setting;
+       priv->power_data.user_power_setting = IWL_POWER_MODE_CAM;
+       ret = iwl_power_update_mode(priv, 0);
+       priv->power_data.power_disabled = 1;
+       priv->power_data.user_power_setting = prev_mode;
+
+       return ret;
+}
+EXPORT_SYMBOL(iwl_power_disable_management);
+
+/* Allow other iwl code to disable/enable power management active
+ * this will be usefull for rate scale to disable PM during hight
+ * valume activities
+ */
+int iwl_power_enable_management(struct iwl_priv *priv)
+{
+       int ret = 0;
+
+       priv->power_data.power_disabled = 0;
+       ret = iwl_power_update_mode(priv, 0);
+       return ret;
+}
+EXPORT_SYMBOL(iwl_power_enable_management);
+
+/* set user_power_setting */
+int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode)
+{
+       int ret = 0;
+
+       if (mode > IWL_POWER_LIMIT)
+               return -EINVAL;
+
+       priv->power_data.user_power_setting = mode;
+
+       ret = iwl_power_update_mode(priv, 0);
+
+       return ret;
+}
+EXPORT_SYMBOL(iwl_power_set_user_mode);
+
+
+/* set system_power_setting. This should be set by over all
+ * PM application.
+ */
+int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode)
+{
+       int ret = 0;
+
+       if (mode > IWL_POWER_LIMIT)
+               return -EINVAL;
+
+       priv->power_data.system_power_setting = mode;
+
+       ret = iwl_power_update_mode(priv, 0);
+
+       return ret;
+}
+EXPORT_SYMBOL(iwl_power_set_system_mode);
+
+/* initilize to default */
+void iwl_power_initialize(struct iwl_priv *priv)
+{
+
+       iwl_power_init_handle(priv);
+       priv->power_data.user_power_setting = IWL_POWER_AUTO;
+       priv->power_data.power_disabled = 0;
+       priv->power_data.system_power_setting = IWL_POWER_AUTO;
+       priv->power_data.is_battery_active = 0;
+       priv->power_data.power_disabled = 0;
+       priv->power_data.critical_power_setting = 0;
+}
+EXPORT_SYMBOL(iwl_power_initialize);
+
+/* set critical_power_setting according to temperature value */
+int iwl_power_temperature_change(struct iwl_priv *priv)
+{
+       int ret = 0;
+       u16 new_critical = priv->power_data.critical_power_setting;
+       s32 temperature = KELVIN_TO_CELSIUS(priv->last_temperature);
+
+       if (temperature > IWL_CT_KILL_TEMPERATURE)
+               return 0;
+       else if (temperature > IWL_MIN_POWER_TEMPERATURE)
+               new_critical = IWL_POWER_INDEX_5;
+       else if (temperature > IWL_REDUCED_POWER_TEMPERATURE)
+               new_critical = IWL_POWER_INDEX_3;
+       else
+               new_critical = IWL_POWER_MODE_CAM;
+
+       if (new_critical != priv->power_data.critical_power_setting)
+               priv->power_data.critical_power_setting = new_critical;
+
+       if (priv->power_data.critical_power_setting >
+                               priv->power_data.power_mode)
+               ret = iwl_power_update_mode(priv, 0);
+
+       return ret;
+}
+EXPORT_SYMBOL(iwl_power_temperature_change);
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
new file mode 100644 (file)
index 0000000..b066724
--- /dev/null
@@ -0,0 +1,76 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2008 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:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *****************************************************************************/
+#ifndef __iwl_power_setting_h__
+#define __iwl_power_setting_h__
+
+#include <net/mac80211.h>
+#include "iwl-commands.h"
+
+struct iwl_priv;
+
+#define IWL_POWER_MODE_CAM     0x00    /* Continuously Aware Mode, always on */
+#define IWL_POWER_INDEX_3      0x03
+#define IWL_POWER_INDEX_5      0x05
+#define IWL_POWER_AC           0x06
+#define IWL_POWER_BATTERY      0x07
+#define IWL_POWER_AUTO         0x08
+#define IWL_POWER_LIMIT                0x08
+#define IWL_POWER_MASK         0x0F
+#define IWL_POWER_ENABLED      0x10
+
+/* Power management (not Tx power) structures */
+
+struct iwl_power_vec_entry {
+       struct iwl4965_powertable_cmd cmd;
+       u8 no_dtim;
+};
+
+struct iwl_power_mgr {
+       spinlock_t lock;
+       struct iwl_power_vec_entry pwr_range_0[IWL_POWER_AC];
+       struct iwl_power_vec_entry pwr_range_1[IWL_POWER_AC];
+       struct iwl_power_vec_entry pwr_range_2[IWL_POWER_AC];
+       u32 dtim_period;
+       /* final power level that used to calculate final power command */
+       u8 power_mode;
+       u8 user_power_setting; /* set by user through mac80211 or sysfs */
+       u8 system_power_setting; /* set by kernel syatem tools */
+       u8 critical_power_setting; /* set if driver over heated */
+       u8 is_battery_active; /* DC/AC power */
+       u8 power_disabled; /* flag to disable using power saving level */
+};
+
+int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh);
+int iwl_power_disable_management(struct iwl_priv *priv);
+int iwl_power_enable_management(struct iwl_priv *priv);
+int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode);
+int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode);
+void iwl_power_initialize(struct iwl_priv *priv);
+int iwl_power_temperature_change(struct iwl_priv *priv);
+
+#endif  /* __iwl_power_setting_h__ */
index c9cf8eef1a90caff505015b201b5031e90d428da..70d9c7568b981cc38cb505bc9e4bb97c2b6355e3 100644 (file)
 #define ALM_SCD_SBYP_MODE_1_REG             (ALM_SCD_BASE + 0x02C)
 #define ALM_SCD_SBYP_MODE_2_REG             (ALM_SCD_BASE + 0x030)
 
+/**
+ * Tx Scheduler
+ *
+ * The Tx Scheduler selects the next frame to be transmitted, chosing TFDs
+ * (Transmit Frame Descriptors) from up to 16 circular Tx queues resident in
+ * host DRAM.  It steers each frame's Tx command (which contains the frame
+ * data) into one of up to 7 prioritized Tx DMA FIFO channels within the
+ * device.  A queue maps to only one (selectable by driver) Tx DMA channel,
+ * but one DMA channel may take input from several queues.
+ *
+ * Tx DMA channels have dedicated purposes.  For 4965, they are used as follows:
+ *
+ * 0 -- EDCA BK (background) frames, lowest priority
+ * 1 -- EDCA BE (best effort) frames, normal priority
+ * 2 -- EDCA VI (video) frames, higher priority
+ * 3 -- EDCA VO (voice) and management frames, highest priority
+ * 4 -- Commands (e.g. RXON, etc.)
+ * 5 -- HCCA short frames
+ * 6 -- HCCA long frames
+ * 7 -- not used by driver (device-internal only)
+ *
+ * Driver should normally map queues 0-6 to Tx DMA/FIFO channels 0-6.
+ * In addition, driver can map queues 7-15 to Tx DMA/FIFO channels 0-3 to
+ * support 11n aggregation via EDCA DMA channels.
+ *
+ * The driver sets up each queue to work in one of two modes:
+ *
+ * 1)  Scheduler-Ack, in which the scheduler automatically supports a
+ *     block-ack (BA) window of up to 64 TFDs.  In this mode, each queue
+ *     contains TFDs for a unique combination of Recipient Address (RA)
+ *     and Traffic Identifier (TID), that is, traffic of a given
+ *     Quality-Of-Service (QOS) priority, destined for a single station.
+ *
+ *     In scheduler-ack mode, the scheduler keeps track of the Tx status of
+ *     each frame within the BA window, including whether it's been transmitted,
+ *     and whether it's been acknowledged by the receiving station.  The device
+ *     automatically processes block-acks received from the receiving STA,
+ *     and reschedules un-acked frames to be retransmitted (successful
+ *     Tx completion may end up being out-of-order).
+ *
+ *     The driver must maintain the queue's Byte Count table in host DRAM
+ *     (struct iwl4965_sched_queue_byte_cnt_tbl) for this mode.
+ *     This mode does not support fragmentation.
+ *
+ * 2)  FIFO (a.k.a. non-Scheduler-ACK), in which each TFD is processed in order.
+ *     The device may automatically retry Tx, but will retry only one frame
+ *     at a time, until receiving ACK from receiving station, or reaching
+ *     retry limit and giving up.
+ *
+ *     The command queue (#4) must use this mode!
+ *     This mode does not require use of the Byte Count table in host DRAM.
+ *
+ * Driver controls scheduler operation via 3 means:
+ * 1)  Scheduler registers
+ * 2)  Shared scheduler data base in internal 4956 SRAM
+ * 3)  Shared data in host DRAM
+ *
+ * Initialization:
+ *
+ * When loading, driver should allocate memory for:
+ * 1)  16 TFD circular buffers, each with space for (typically) 256 TFDs.
+ * 2)  16 Byte Count circular buffers in 16 KBytes contiguous memory
+ *     (1024 bytes for each queue).
+ *
+ * After receiving "Alive" response from uCode, driver must initialize
+ * the scheduler (especially for queue #4, the command queue, otherwise
+ * the driver can't issue commands!):
+ */
+
+/**
+ * Max Tx window size is the max number of contiguous TFDs that the scheduler
+ * can keep track of at one time when creating block-ack chains of frames.
+ * Note that "64" matches the number of ack bits in a block-ack packet.
+ * Driver should use SCD_WIN_SIZE and SCD_FRAME_LIMIT values to initialize
+ * IWL49_SCD_CONTEXT_QUEUE_OFFSET(x) values.
+ */
+#define SCD_WIN_SIZE                           64
+#define SCD_FRAME_LIMIT                                64
+
+/* SCD registers are internal, must be accessed via HBUS_TARG_PRPH regs */
+#define IWL49_SCD_START_OFFSET         0xa02c00
+
+/*
+ * 4965 tells driver SRAM address for internal scheduler structs via this reg.
+ * Value is valid only after "Alive" response from uCode.
+ */
+#define IWL49_SCD_SRAM_BASE_ADDR           (IWL49_SCD_START_OFFSET + 0x0)
+
+/*
+ * Driver may need to update queue-empty bits after changing queue's
+ * write and read pointers (indexes) during (re-)initialization (i.e. when
+ * scheduler is not tracking what's happening).
+ * Bit fields:
+ * 31-16:  Write mask -- 1: update empty bit, 0: don't change empty bit
+ * 15-00:  Empty state, one for each queue -- 1: empty, 0: non-empty
+ * NOTE:  This register is not used by Linux driver.
+ */
+#define IWL49_SCD_EMPTY_BITS               (IWL49_SCD_START_OFFSET + 0x4)
+
+/*
+ * Physical base address of array of byte count (BC) circular buffers (CBs).
+ * Each Tx queue has a BC CB in host DRAM to support Scheduler-ACK mode.
+ * This register points to BC CB for queue 0, must be on 1024-byte boundary.
+ * Others are spaced by 1024 bytes.
+ * Each BC CB is 2 bytes * (256 + 64) = 740 bytes, followed by 384 bytes pad.
+ * (Index into a queue's BC CB) = (index into queue's TFD CB) = (SSN & 0xff).
+ * Bit fields:
+ * 25-00:  Byte Count CB physical address [35:10], must be 1024-byte aligned.
+ */
+#define IWL49_SCD_DRAM_BASE_ADDR           (IWL49_SCD_START_OFFSET + 0x10)
+
+/*
+ * Enables any/all Tx DMA/FIFO channels.
+ * Scheduler generates requests for only the active channels.
+ * Set this to 0xff to enable all 8 channels (normal usage).
+ * Bit fields:
+ *  7- 0:  Enable (1), disable (0), one bit for each channel 0-7
+ */
+#define IWL49_SCD_TXFACT                   (IWL49_SCD_START_OFFSET + 0x1c)
+/*
+ * Queue (x) Write Pointers (indexes, really!), one for each Tx queue.
+ * Initialized and updated by driver as new TFDs are added to queue.
+ * NOTE:  If using Block Ack, index must correspond to frame's
+ *        Start Sequence Number; index = (SSN & 0xff)
+ * NOTE:  Alternative to HBUS_TARG_WRPTR, which is what Linux driver uses?
+ */
+#define IWL49_SCD_QUEUE_WRPTR(x)  (IWL49_SCD_START_OFFSET + 0x24 + (x) * 4)
+
+/*
+ * Queue (x) Read Pointers (indexes, really!), one for each Tx queue.
+ * For FIFO mode, index indicates next frame to transmit.
+ * For Scheduler-ACK mode, index indicates first frame in Tx window.
+ * Initialized by driver, updated by scheduler.
+ */
+#define IWL49_SCD_QUEUE_RDPTR(x)  (IWL49_SCD_START_OFFSET + 0x64 + (x) * 4)
+
+/*
+ * Select which queues work in chain mode (1) vs. not (0).
+ * Use chain mode to build chains of aggregated frames.
+ * Bit fields:
+ * 31-16:  Reserved
+ * 15-00:  Mode, one bit for each queue -- 1: Chain mode, 0: one-at-a-time
+ * NOTE:  If driver sets up queue for chain mode, it should be also set up
+ *        Scheduler-ACK mode as well, via SCD_QUEUE_STATUS_BITS(x).
+ */
+#define IWL49_SCD_QUEUECHAIN_SEL  (IWL49_SCD_START_OFFSET + 0xd0)
+
+/*
+ * Select which queues interrupt driver when scheduler increments
+ * a queue's read pointer (index).
+ * Bit fields:
+ * 31-16:  Reserved
+ * 15-00:  Interrupt enable, one bit for each queue -- 1: enabled, 0: disabled
+ * NOTE:  This functionality is apparently a no-op; driver relies on interrupts
+ *        from Rx queue to read Tx command responses and update Tx queues.
+ */
+#define IWL49_SCD_INTERRUPT_MASK  (IWL49_SCD_START_OFFSET + 0xe4)
+
+/*
+ * Queue search status registers.  One for each queue.
+ * Sets up queue mode and assigns queue to Tx DMA channel.
+ * Bit fields:
+ * 19-10: Write mask/enable bits for bits 0-9
+ *     9: Driver should init to "0"
+ *     8: Scheduler-ACK mode (1), non-Scheduler-ACK (i.e. FIFO) mode (0).
+ *        Driver should init to "1" for aggregation mode, or "0" otherwise.
+ *   7-6: Driver should init to "0"
+ *     5: Window Size Left; indicates whether scheduler can request
+ *        another TFD, based on window size, etc.  Driver should init
+ *        this bit to "1" for aggregation mode, or "0" for non-agg.
+ *   4-1: Tx FIFO to use (range 0-7).
+ *     0: Queue is active (1), not active (0).
+ * Other bits should be written as "0"
+ *
+ * NOTE:  If enabling Scheduler-ACK mode, chain mode should also be enabled
+ *        via SCD_QUEUECHAIN_SEL.
+ */
+#define IWL49_SCD_QUEUE_STATUS_BITS(x)\
+       (IWL49_SCD_START_OFFSET + 0x104 + (x) * 4)
+
+/* Bit field positions */
+#define IWL49_SCD_QUEUE_STTS_REG_POS_ACTIVE    (0)
+#define IWL49_SCD_QUEUE_STTS_REG_POS_TXF       (1)
+#define IWL49_SCD_QUEUE_STTS_REG_POS_WSL       (5)
+#define IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACK   (8)
+
+/* Write masks */
+#define IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN        (10)
+#define IWL49_SCD_QUEUE_STTS_REG_MSK           (0x0007FC00)
+
+/**
+ * 4965 internal SRAM structures for scheduler, shared with driver ...
+ *
+ * Driver should clear and initialize the following areas after receiving
+ * "Alive" response from 4965 uCode, i.e. after initial
+ * uCode load, or after a uCode load done for error recovery:
+ *
+ * SCD_CONTEXT_DATA_OFFSET (size 128 bytes)
+ * SCD_TX_STTS_BITMAP_OFFSET (size 256 bytes)
+ * SCD_TRANSLATE_TBL_OFFSET (size 32 bytes)
+ *
+ * Driver accesses SRAM via HBUS_TARG_MEM_* registers.
+ * Driver reads base address of this scheduler area from SCD_SRAM_BASE_ADDR.
+ * All OFFSET values must be added to this base address.
+ */
+
+/*
+ * Queue context.  One 8-byte entry for each of 16 queues.
+ *
+ * Driver should clear this entire area (size 0x80) to 0 after receiving
+ * "Alive" notification from uCode.  Additionally, driver should init
+ * each queue's entry as follows:
+ *
+ * LS Dword bit fields:
+ *  0-06:  Max Tx window size for Scheduler-ACK.  Driver should init to 64.
+ *
+ * MS Dword bit fields:
+ * 16-22:  Frame limit.  Driver should init to 10 (0xa).
+ *
+ * Driver should init all other bits to 0.
+ *
+ * Init must be done after driver receives "Alive" response from 4965 uCode,
+ * and when setting up queue for aggregation.
+ */
+#define IWL49_SCD_CONTEXT_DATA_OFFSET                  0x380
+#define IWL49_SCD_CONTEXT_QUEUE_OFFSET(x) \
+                       (IWL49_SCD_CONTEXT_DATA_OFFSET + ((x) * 8))
+
+#define IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_POS          (0)
+#define IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK          (0x0000007F)
+#define IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS       (16)
+#define IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK       (0x007F0000)
+
+/*
+ * Tx Status Bitmap
+ *
+ * Driver should clear this entire area (size 0x100) to 0 after receiving
+ * "Alive" notification from uCode.  Area is used only by device itself;
+ * no other support (besides clearing) is required from driver.
+ */
+#define IWL49_SCD_TX_STTS_BITMAP_OFFSET                0x400
+
 /*
- * 4965 Tx Scheduler registers.
- * Details are documented in iwl-4965-hw.h
+ * RAxTID to queue translation mapping.
+ *
+ * When queue is in Scheduler-ACK mode, frames placed in a that queue must be
+ * for only one combination of receiver address (RA) and traffic ID (TID), i.e.
+ * one QOS priority level destined for one station (for this wireless link,
+ * not final destination).  The SCD_TRANSLATE_TABLE area provides 16 16-bit
+ * mappings, one for each of the 16 queues.  If queue is not in Scheduler-ACK
+ * mode, the device ignores the mapping value.
+ *
+ * Bit fields, for each 16-bit map:
+ * 15-9:  Reserved, set to 0
+ *  8-4:  Index into device's station table for recipient station
+ *  3-0:  Traffic ID (tid), range 0-15
+ *
+ * Driver should clear this entire area (size 32 bytes) to 0 after receiving
+ * "Alive" notification from uCode.  To update a 16-bit map value, driver
+ * must read a dword-aligned value from device SRAM, replace the 16-bit map
+ * value of interest, and write the dword value back into device SRAM.
  */
-#define IWL49_SCD_BASE         (PRPH_BASE + 0xa02c00)
-
-#define IWL49_SCD_SRAM_BASE_ADDR         (IWL49_SCD_BASE + 0x0)
-#define IWL49_SCD_EMPTY_BITS             (IWL49_SCD_BASE + 0x4)
-#define IWL49_SCD_DRAM_BASE_ADDR         (IWL49_SCD_BASE + 0x10)
-#define IWL49_SCD_AIT                    (IWL49_SCD_BASE + 0x18)
-#define IWL49_SCD_TXFACT                 (IWL49_SCD_BASE + 0x1c)
-#define IWL49_SCD_QUEUE_WRPTR(x)         (IWL49_SCD_BASE + 0x24 + (x) * 4)
-#define IWL49_SCD_QUEUE_RDPTR(x)         (IWL49_SCD_BASE + 0x64 + (x) * 4)
-#define IWL49_SCD_SETQUEUENUM            (IWL49_SCD_BASE + 0xa4)
-#define IWL49_SCD_SET_TXSTAT_TXED        (IWL49_SCD_BASE + 0xa8)
-#define IWL49_SCD_SET_TXSTAT_DONE        (IWL49_SCD_BASE + 0xac)
-#define IWL49_SCD_SET_TXSTAT_NOT_SCHD    (IWL49_SCD_BASE + 0xb0)
-#define IWL49_SCD_DECREASE_CREDIT        (IWL49_SCD_BASE + 0xb4)
-#define IWL49_SCD_DECREASE_SCREDIT       (IWL49_SCD_BASE + 0xb8)
-#define IWL49_SCD_LOAD_CREDIT            (IWL49_SCD_BASE + 0xbc)
-#define IWL49_SCD_LOAD_SCREDIT           (IWL49_SCD_BASE + 0xc0)
-#define IWL49_SCD_BAR                    (IWL49_SCD_BASE + 0xc4)
-#define IWL49_SCD_BAR_DW0                (IWL49_SCD_BASE + 0xc8)
-#define IWL49_SCD_BAR_DW1                (IWL49_SCD_BASE + 0xcc)
-#define IWL49_SCD_QUEUECHAIN_SEL         (IWL49_SCD_BASE + 0xd0)
-#define IWL49_SCD_QUERY_REQ              (IWL49_SCD_BASE + 0xd8)
-#define IWL49_SCD_QUERY_RES              (IWL49_SCD_BASE + 0xdc)
-#define IWL49_SCD_PENDING_FRAMES         (IWL49_SCD_BASE + 0xe0)
-#define IWL49_SCD_INTERRUPT_MASK         (IWL49_SCD_BASE + 0xe4)
-#define IWL49_SCD_INTERRUPT_THRESHOLD    (IWL49_SCD_BASE + 0xe8)
-#define IWL49_SCD_QUERY_MIN_FRAME_SIZE   (IWL49_SCD_BASE + 0x100)
-#define IWL49_SCD_QUEUE_STATUS_BITS(x)   (IWL49_SCD_BASE + 0x104 + (x) * 4)
-
-/* SP SCD */
+#define IWL49_SCD_TRANSLATE_TBL_OFFSET         0x500
+
+/* Find translation table dword to read/write for given queue */
+#define IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \
+       ((IWL49_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc)
+
+#define IWL_SCD_TXFIFO_POS_TID                 (0)
+#define IWL_SCD_TXFIFO_POS_RA                  (4)
+#define IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK     (0x01FF)
+
+/* 5000 SCD */
+#define IWL50_SCD_QUEUE_STTS_REG_POS_TXF       (0)
+#define IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE    (3)
+#define IWL50_SCD_QUEUE_STTS_REG_POS_WSL       (4)
+#define IWL50_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (19)
+#define IWL50_SCD_QUEUE_STTS_REG_MSK           (0x00FF0000)
+
+#define IWL50_SCD_QUEUE_CTX_REG1_CREDIT_POS            (8)
+#define IWL50_SCD_QUEUE_CTX_REG1_CREDIT_MSK            (0x00FFFF00)
+#define IWL50_SCD_QUEUE_CTX_REG1_SUPER_CREDIT_POS      (24)
+#define IWL50_SCD_QUEUE_CTX_REG1_SUPER_CREDIT_MSK      (0xFF000000)
+#define IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS          (0)
+#define IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK          (0x0000007F)
+#define IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS       (16)
+#define IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK       (0x007F0000)
+
+#define IWL50_SCD_CONTEXT_DATA_OFFSET          (0x600)
+#define IWL50_SCD_TX_STTS_BITMAP_OFFSET                (0x7B1)
+#define IWL50_SCD_TRANSLATE_TBL_OFFSET         (0x7E0)
+
+#define IWL50_SCD_CONTEXT_QUEUE_OFFSET(x)\
+       (IWL50_SCD_CONTEXT_DATA_OFFSET + ((x) * 8))
+
+#define IWL50_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \
+       ((IWL50_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffc)
+
+#define IWL50_SCD_QUEUECHAIN_SEL_ALL(x)                (((1<<(x)) - 1) &\
+       (~(1<<IWL_CMD_QUEUE_NUM)))
+
 #define IWL50_SCD_BASE                 (PRPH_BASE + 0xa02c00)
 
 #define IWL50_SCD_SRAM_BASE_ADDR         (IWL50_SCD_BASE + 0x0)
 #define IWL50_SCD_INTERRUPT_MASK         (IWL50_SCD_BASE + 0x108)
 #define IWL50_SCD_QUEUE_STATUS_BITS(x)   (IWL50_SCD_BASE + 0x10c + (x) * 4)
 
+/*********************** END TX SCHEDULER *************************************/
+
 #endif                         /* __iwl_prph_h__ */
index 5980a5621cb8de9d4afae1d47272f30c4effdb84..59c8a716bd96562c1f53851e289ce536968ede0b 100644 (file)
@@ -33,7 +33,7 @@
 #include <net/mac80211.h>
 
 #include "iwl-eeprom.h"
-#include "iwl-4965.h"
+#include "iwl-dev.h"
 #include "iwl-core.h"
 #include "iwl-helpers.h"
 
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
new file mode 100644 (file)
index 0000000..cc61c93
--- /dev/null
@@ -0,0 +1,470 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2008 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:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <net/mac80211.h>
+#include "iwl-eeprom.h"
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-sta.h"
+#include "iwl-io.h"
+#include "iwl-calib.h"
+#include "iwl-helpers.h"
+/************************** RX-FUNCTIONS ****************************/
+/*
+ * Rx theory of operation
+ *
+ * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs),
+ * each of which point to Receive Buffers to be filled by the NIC.  These get
+ * used not only for Rx frames, but for any command response or notification
+ * from the NIC.  The driver and NIC manage the Rx buffers by means
+ * of indexes into the circular buffer.
+ *
+ * Rx Queue Indexes
+ * The host/firmware share two index registers for managing the Rx buffers.
+ *
+ * The READ index maps to the first position that the firmware may be writing
+ * to -- the driver can read up to (but not including) this position and get
+ * good data.
+ * The READ index is managed by the firmware once the card is enabled.
+ *
+ * The WRITE index maps to the last position the driver has read from -- the
+ * position preceding WRITE is the last slot the firmware can place a packet.
+ *
+ * The queue is empty (no good data) if WRITE = READ - 1, and is full if
+ * WRITE = READ.
+ *
+ * During initialization, the host sets up the READ queue position to the first
+ * INDEX position, and WRITE to the last (READ - 1 wrapped)
+ *
+ * When the firmware places a packet in a buffer, it will advance the READ index
+ * and fire the RX interrupt.  The driver can then query the READ index and
+ * process as many packets as possible, moving the WRITE index forward as it
+ * resets the Rx queue buffers with new memory.
+ *
+ * The management in the driver is as follows:
+ * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free.  When
+ *   iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
+ *   to replenish the iwl->rxq->rx_free.
+ * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the
+ *   iwl->rxq is replenished and the READ INDEX is updated (updating the
+ *   'processed' and 'read' driver indexes as well)
+ * + A received packet is processed and handed to the kernel network stack,
+ *   detached from the iwl->rxq.  The driver 'processed' index is updated.
+ * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free
+ *   list. If there are no allocated buffers in iwl->rxq->rx_free, the READ
+ *   INDEX is not incremented and iwl->status(RX_STALLED) is set.  If there
+ *   were enough free buffers and RX_STALLED is set it is cleared.
+ *
+ *
+ * Driver sequence:
+ *
+ * iwl_rx_queue_alloc()   Allocates rx_free
+ * iwl_rx_replenish()     Replenishes rx_free list from rx_used, and calls
+ *                            iwl_rx_queue_restock
+ * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx
+ *                            queue, updates firmware pointers, and updates
+ *                            the WRITE index.  If insufficient rx_free buffers
+ *                            are available, schedules iwl_rx_replenish
+ *
+ * -- enable interrupts --
+ * ISR - iwl_rx()         Detach iwl_rx_mem_buffers from pool up to the
+ *                            READ INDEX, detaching the SKB from the pool.
+ *                            Moves the packet buffer from queue to rx_used.
+ *                            Calls iwl_rx_queue_restock to refill any empty
+ *                            slots.
+ * ...
+ *
+ */
+
+/**
+ * iwl_rx_queue_space - Return number of free slots available in queue.
+ */
+int iwl_rx_queue_space(const struct iwl_rx_queue *q)
+{
+       int s = q->read - q->write;
+       if (s <= 0)
+               s += RX_QUEUE_SIZE;
+       /* keep some buffer to not confuse full and empty queue */
+       s -= 2;
+       if (s < 0)
+               s = 0;
+       return s;
+}
+EXPORT_SYMBOL(iwl_rx_queue_space);
+
+/**
+ * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
+ */
+int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
+{
+       u32 reg = 0;
+       int ret = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&q->lock, flags);
+
+       if (q->need_update == 0)
+               goto exit_unlock;
+
+       /* If power-saving is in use, make sure device is awake */
+       if (test_bit(STATUS_POWER_PMI, &priv->status)) {
+               reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
+
+               if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+                       iwl_set_bit(priv, CSR_GP_CNTRL,
+                                   CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+                       goto exit_unlock;
+               }
+
+               ret = iwl_grab_nic_access(priv);
+               if (ret)
+                       goto exit_unlock;
+
+               /* Device expects a multiple of 8 */
+               iwl_write_direct32(priv, FH_RSCSR_CHNL0_WPTR,
+                                    q->write & ~0x7);
+               iwl_release_nic_access(priv);
+
+       /* Else device is assumed to be awake */
+       } else
+               /* Device expects a multiple of 8 */
+               iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7);
+
+
+       q->need_update = 0;
+
+ exit_unlock:
+       spin_unlock_irqrestore(&q->lock, flags);
+       return ret;
+}
+EXPORT_SYMBOL(iwl_rx_queue_update_write_ptr);
+/**
+ * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
+ */
+static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv,
+                                         dma_addr_t dma_addr)
+{
+       return cpu_to_le32((u32)(dma_addr >> 8));
+}
+
+/**
+ * iwl_rx_queue_restock - refill RX queue from pre-allocated pool
+ *
+ * If there are slots in the RX queue that need to be restocked,
+ * and we have free pre-allocated buffers, fill the ranks as much
+ * as we can, pulling from rx_free.
+ *
+ * This moves the 'write' index forward to catch up with 'processed', and
+ * also updates the memory address in the firmware to reference the new
+ * target buffer.
+ */
+int iwl_rx_queue_restock(struct iwl_priv *priv)
+{
+       struct iwl_rx_queue *rxq = &priv->rxq;
+       struct list_head *element;
+       struct iwl_rx_mem_buffer *rxb;
+       unsigned long flags;
+       int write;
+       int ret = 0;
+
+       spin_lock_irqsave(&rxq->lock, flags);
+       write = rxq->write & ~0x7;
+       while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
+               /* Get next free Rx buffer, remove from free list */
+               element = rxq->rx_free.next;
+               rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+               list_del(element);
+
+               /* Point to Rx buffer via next RBD in circular buffer */
+               rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->dma_addr);
+               rxq->queue[rxq->write] = rxb;
+               rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
+               rxq->free_count--;
+       }
+       spin_unlock_irqrestore(&rxq->lock, flags);
+       /* If the pre-allocated buffer pool is dropping low, schedule to
+        * refill it */
+       if (rxq->free_count <= RX_LOW_WATERMARK)
+               queue_work(priv->workqueue, &priv->rx_replenish);
+
+
+       /* If we've added more space for the firmware to place data, tell it.
+        * Increment device's write pointer in multiples of 8. */
+       if ((write != (rxq->write & ~0x7))
+           || (abs(rxq->write - rxq->read) > 7)) {
+               spin_lock_irqsave(&rxq->lock, flags);
+               rxq->need_update = 1;
+               spin_unlock_irqrestore(&rxq->lock, flags);
+               ret = iwl_rx_queue_update_write_ptr(priv, rxq);
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(iwl_rx_queue_restock);
+
+
+/**
+ * iwl_rx_replenish - Move all used packet from rx_used to rx_free
+ *
+ * When moving to rx_free an SKB is allocated for the slot.
+ *
+ * Also restock the Rx queue via iwl_rx_queue_restock.
+ * This is called as a scheduled work item (except for during initialization)
+ */
+void iwl_rx_allocate(struct iwl_priv *priv)
+{
+       struct iwl_rx_queue *rxq = &priv->rxq;
+       struct list_head *element;
+       struct iwl_rx_mem_buffer *rxb;
+       unsigned long flags;
+       spin_lock_irqsave(&rxq->lock, flags);
+       while (!list_empty(&rxq->rx_used)) {
+               element = rxq->rx_used.next;
+               rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+
+               /* Alloc a new receive buffer */
+               rxb->skb = alloc_skb(priv->hw_params.rx_buf_size,
+                               __GFP_NOWARN | GFP_ATOMIC);
+               if (!rxb->skb) {
+                       if (net_ratelimit())
+                               printk(KERN_CRIT DRV_NAME
+                                      ": Can not allocate SKB buffers\n");
+                       /* We don't reschedule replenish work here -- we will
+                        * call the restock method and if it still needs
+                        * more buffers it will schedule replenish */
+                       break;
+               }
+               priv->alloc_rxb_skb++;
+               list_del(element);
+
+               /* Get physical address of RB/SKB */
+               rxb->dma_addr =
+                   pci_map_single(priv->pci_dev, rxb->skb->data,
+                          priv->hw_params.rx_buf_size, PCI_DMA_FROMDEVICE);
+               list_add_tail(&rxb->list, &rxq->rx_free);
+               rxq->free_count++;
+       }
+       spin_unlock_irqrestore(&rxq->lock, flags);
+}
+EXPORT_SYMBOL(iwl_rx_allocate);
+
+void iwl_rx_replenish(struct iwl_priv *priv)
+{
+       unsigned long flags;
+
+       iwl_rx_allocate(priv);
+
+       spin_lock_irqsave(&priv->lock, flags);
+       iwl_rx_queue_restock(priv);
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL(iwl_rx_replenish);
+
+
+/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
+ * If an SKB has been detached, the POOL needs to have its SKB set to NULL
+ * This free routine walks the list of POOL entries and if SKB is set to
+ * non NULL it is unmapped and freed
+ */
+void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+       int i;
+       for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
+               if (rxq->pool[i].skb != NULL) {
+                       pci_unmap_single(priv->pci_dev,
+                                        rxq->pool[i].dma_addr,
+                                        priv->hw_params.rx_buf_size,
+                                        PCI_DMA_FROMDEVICE);
+                       dev_kfree_skb(rxq->pool[i].skb);
+               }
+       }
+
+       pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
+                           rxq->dma_addr);
+       rxq->bd = NULL;
+}
+EXPORT_SYMBOL(iwl_rx_queue_free);
+
+int iwl_rx_queue_alloc(struct iwl_priv *priv)
+{
+       struct iwl_rx_queue *rxq = &priv->rxq;
+       struct pci_dev *dev = priv->pci_dev;
+       int i;
+
+       spin_lock_init(&rxq->lock);
+       INIT_LIST_HEAD(&rxq->rx_free);
+       INIT_LIST_HEAD(&rxq->rx_used);
+
+       /* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */
+       rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr);
+       if (!rxq->bd)
+               return -ENOMEM;
+
+       /* Fill the rx_used queue with _all_ of the Rx buffers */
+       for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
+               list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+
+       /* Set us so that we have processed and used all buffers, but have
+        * not restocked the Rx queue with fresh buffers */
+       rxq->read = rxq->write = 0;
+       rxq->free_count = 0;
+       rxq->need_update = 0;
+       return 0;
+}
+EXPORT_SYMBOL(iwl_rx_queue_alloc);
+
+void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+       unsigned long flags;
+       int i;
+       spin_lock_irqsave(&rxq->lock, flags);
+       INIT_LIST_HEAD(&rxq->rx_free);
+       INIT_LIST_HEAD(&rxq->rx_used);
+       /* Fill the rx_used queue with _all_ of the Rx buffers */
+       for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
+               /* In the reset function, these buffers may have been allocated
+                * to an SKB, so we need to unmap and free potential storage */
+               if (rxq->pool[i].skb != NULL) {
+                       pci_unmap_single(priv->pci_dev,
+                                        rxq->pool[i].dma_addr,
+                                        priv->hw_params.rx_buf_size,
+                                        PCI_DMA_FROMDEVICE);
+                       priv->alloc_rxb_skb--;
+                       dev_kfree_skb(rxq->pool[i].skb);
+                       rxq->pool[i].skb = NULL;
+               }
+               list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+       }
+
+       /* Set us so that we have processed and used all buffers, but have
+        * not restocked the Rx queue with fresh buffers */
+       rxq->read = rxq->write = 0;
+       rxq->free_count = 0;
+       spin_unlock_irqrestore(&rxq->lock, flags);
+}
+EXPORT_SYMBOL(iwl_rx_queue_reset);
+
+int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+       int ret;
+       unsigned long flags;
+       unsigned int rb_size;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       ret = iwl_grab_nic_access(priv);
+       if (ret) {
+               spin_unlock_irqrestore(&priv->lock, flags);
+               return ret;
+       }
+
+       if (priv->cfg->mod_params->amsdu_size_8K)
+               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
+       else
+               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
+
+       /* Stop Rx DMA */
+       iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+
+       /* Reset driver's Rx queue write index */
+       iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
+
+       /* Tell device where to find RBD circular buffer in DRAM */
+       iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
+                          rxq->dma_addr >> 8);
+
+       /* Tell device where in DRAM to update its Rx status */
+       iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
+                          (priv->shared_phys + priv->rb_closed_offset) >> 4);
+
+       /* Enable Rx DMA, enable host interrupt, Rx buffer size 4k, 256 RBDs */
+       iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG,
+                          FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
+                          FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
+                          rb_size |
+                            /* 0x10 << 4 | */
+                          (RX_QUEUE_SIZE_LOG <<
+                             FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));
+
+       /*
+        * iwl_write32(priv,CSR_INT_COAL_REG,0);
+        */
+
+       iwl_release_nic_access(priv);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+int iwl_rxq_stop(struct iwl_priv *priv)
+{
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       ret = iwl_grab_nic_access(priv);
+       if (unlikely(ret)) {
+               spin_unlock_irqrestore(&priv->lock, flags);
+               return ret;
+       }
+
+       /* stop Rx DMA */
+       iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+       ret = iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
+                                    (1 << 24), 1000);
+       if (ret < 0)
+               IWL_ERROR("Can't stop Rx DMA.\n");
+
+       iwl_release_nic_access(priv);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(iwl_rxq_stop);
+
+void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
+                               struct iwl_rx_mem_buffer *rxb)
+
+{
+#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+       struct iwl4965_missed_beacon_notif *missed_beacon;
+
+       missed_beacon = &pkt->u.missed_beacon;
+       if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) {
+               IWL_DEBUG_CALIB("missed bcn cnsq %d totl %d rcd %d expctd %d\n",
+                   le32_to_cpu(missed_beacon->consequtive_missed_beacons),
+                   le32_to_cpu(missed_beacon->total_missed_becons),
+                   le32_to_cpu(missed_beacon->num_recvd_beacons),
+                   le32_to_cpu(missed_beacon->num_expected_beacons));
+               if (!test_bit(STATUS_SCANNING, &priv->status))
+                       iwl_init_sensitivity(priv);
+       }
+#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */
+}
+EXPORT_SYMBOL(iwl_rx_missed_beacon_notif);
index e4fdfaa2b9b2e89275a7b9adbf1ff6aa9af55a6d..983f10760fb06e686344e079371d089c7e062fb2 100644 (file)
  *****************************************************************************/
 
 #include <net/mac80211.h>
+#include <linux/etherdevice.h>
 
 #include "iwl-eeprom.h"
-#include "iwl-4965.h"
+#include "iwl-dev.h"
 #include "iwl-core.h"
 #include "iwl-sta.h"
 #include "iwl-io.h"
 #include "iwl-helpers.h"
-#include "iwl-4965.h"
-#include "iwl-sta.h"
 
+
+#define IWL_STA_DRIVER_ACTIVE          0x1     /* ucode entry is active */
+#define IWL_STA_UCODE_ACTIVE           0x2     /* ucode entry is active */
+
+u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr)
+{
+       int i;
+       int start = 0;
+       int ret = IWL_INVALID_STATION;
+       unsigned long flags;
+       DECLARE_MAC_BUF(mac);
+
+       if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) ||
+           (priv->iw_mode == IEEE80211_IF_TYPE_AP))
+               start = IWL_STA_ID;
+
+       if (is_broadcast_ether_addr(addr))
+               return priv->hw_params.bcast_sta_id;
+
+       spin_lock_irqsave(&priv->sta_lock, flags);
+       for (i = start; i < priv->hw_params.max_stations; i++)
+               if (priv->stations[i].used &&
+                   (!compare_ether_addr(priv->stations[i].sta.sta.addr,
+                                        addr))) {
+                       ret = i;
+                       goto out;
+               }
+
+       IWL_DEBUG_ASSOC_LIMIT("can not find STA %s total %d\n",
+                             print_mac(mac, addr), priv->num_stations);
+
+ out:
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
+       return ret;
+}
+EXPORT_SYMBOL(iwl_find_station);
+
+static int iwl_add_sta_callback(struct iwl_priv *priv,
+                                  struct iwl_cmd *cmd, struct sk_buff *skb)
+{
+       struct iwl_rx_packet *res = NULL;
+
+       if (!skb) {
+               IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n");
+               return 1;
+       }
+
+       res = (struct iwl_rx_packet *)skb->data;
+       if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+               IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
+                         res->hdr.flags);
+               return 1;
+       }
+
+       switch (res->u.add_sta.status) {
+       case ADD_STA_SUCCESS_MSK:
+               /* FIXME: implement iwl_sta_ucode_activate(priv, addr); */
+               /* fail through */
+       default:
+               IWL_DEBUG_HC("Received REPLY_ADD_STA:(0x%08X)\n",
+                            res->u.add_sta.status);
+               break;
+       }
+
+       /* We didn't cache the SKB; let the caller free it */
+       return 1;
+}
+
+
+
+int iwl_send_add_sta(struct iwl_priv *priv,
+                    struct iwl_addsta_cmd *sta, u8 flags)
+{
+       struct iwl_rx_packet *res = NULL;
+       int ret = 0;
+       u8 data[sizeof(*sta)];
+       struct iwl_host_cmd cmd = {
+               .id = REPLY_ADD_STA,
+               .meta.flags = flags,
+               .data = data,
+       };
+
+       if (flags & CMD_ASYNC)
+               cmd.meta.u.callback = iwl_add_sta_callback;
+       else
+               cmd.meta.flags |= CMD_WANT_SKB;
+
+       cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data);
+       ret = iwl_send_cmd(priv, &cmd);
+
+       if (ret || (flags & CMD_ASYNC))
+               return ret;
+
+       res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+       if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+               IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
+                         res->hdr.flags);
+               ret = -EIO;
+       }
+
+       if (ret == 0) {
+               switch (res->u.add_sta.status) {
+               case ADD_STA_SUCCESS_MSK:
+                       IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n");
+                       break;
+               default:
+                       ret = -EIO;
+                       IWL_WARNING("REPLY_ADD_STA failed\n");
+                       break;
+               }
+       }
+
+       priv->alloc_rxb_skb--;
+       dev_kfree_skb_any(cmd.meta.u.skb);
+
+       return ret;
+}
+EXPORT_SYMBOL(iwl_send_add_sta);
+
+#ifdef CONFIG_IWL4965_HT
+
+static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
+                                  struct ieee80211_ht_info *sta_ht_inf)
+{
+       __le32 sta_flags;
+       u8 mimo_ps_mode;
+
+       if (!sta_ht_inf || !sta_ht_inf->ht_supported)
+               goto done;
+
+       mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2;
+
+       sta_flags = priv->stations[index].sta.station_flags;
+
+       sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK);
+
+       switch (mimo_ps_mode) {
+       case WLAN_HT_CAP_MIMO_PS_STATIC:
+               sta_flags |= STA_FLG_MIMO_DIS_MSK;
+               break;
+       case WLAN_HT_CAP_MIMO_PS_DYNAMIC:
+               sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK;
+               break;
+       case WLAN_HT_CAP_MIMO_PS_DISABLED:
+               break;
+       default:
+               IWL_WARNING("Invalid MIMO PS mode %d", mimo_ps_mode);
+               break;
+       }
+
+       sta_flags |= cpu_to_le32(
+             (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS);
+
+       sta_flags |= cpu_to_le32(
+             (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
+
+       if (iwl_is_fat_tx_allowed(priv, sta_ht_inf))
+               sta_flags |= STA_FLG_FAT_EN_MSK;
+       else
+               sta_flags &= ~STA_FLG_FAT_EN_MSK;
+
+       priv->stations[index].sta.station_flags = sta_flags;
+ done:
+       return;
+}
+#else
+static inline void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
+                                       struct ieee80211_ht_info *sta_ht_info)
+{
+}
+#endif
+
+/**
+ * iwl_add_station_flags - 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_ht_info *ht_info)
+{
+       int i;
+       int index = IWL_INVALID_STATION;
+       struct iwl_station_entry *station;
+       unsigned long flags_spin;
+       DECLARE_MAC_BUF(mac);
+
+       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[i].sta.sta.addr,
+                                               addr)) {
+                               index = i;
+                               break;
+                       }
+
+                       if (!priv->stations[i].used &&
+                           index == IWL_INVALID_STATION)
+                               index = i;
+               }
+
+
+       /* These two conditions have the same outcome, but keep them separate
+         since they have different meanings */
+       if (unlikely(index == IWL_INVALID_STATION)) {
+               spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+               return index;
+       }
+
+       if (priv->stations[index].used &&
+           !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) {
+               spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+               return index;
+       }
+
+
+       IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr));
+       station = &priv->stations[index];
+       station->used = 1;
+       priv->num_stations++;
+
+       /* Set up the REPLY_ADD_STA command to send to device */
+       memset(&station->sta, 0, sizeof(struct iwl_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;
+
+       /* BCAST station and IBSS stations do not work in HT mode */
+       if (index != priv->hw_params.bcast_sta_id &&
+           priv->iw_mode != IEEE80211_IF_TYPE_IBSS)
+               iwl_set_ht_add_station(priv, index, ht_info);
+
+       spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+
+       /* Add station to device's station table */
+       iwl_send_add_sta(priv, &station->sta, flags);
+       return index;
+
+}
+EXPORT_SYMBOL(iwl_add_station_flags);
+
+
+static int iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
+{
+       unsigned long flags;
+       u8 sta_id;
+       DECLARE_MAC_BUF(mac);
+
+       sta_id = iwl_find_station(priv, addr);
+       if (sta_id != IWL_INVALID_STATION) {
+               IWL_DEBUG_ASSOC("Removed STA from Ucode: %s\n",
+                               print_mac(mac, addr));
+               spin_lock_irqsave(&priv->sta_lock, flags);
+               priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE;
+               memset(&priv->stations[sta_id], 0,
+                       sizeof(struct iwl_station_entry));
+               spin_unlock_irqrestore(&priv->sta_lock, flags);
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int iwl_remove_sta_callback(struct iwl_priv *priv,
+                                  struct iwl_cmd *cmd, struct sk_buff *skb)
+{
+       struct iwl_rx_packet *res = NULL;
+       const char *addr = cmd->cmd.rm_sta.addr;
+
+       if (!skb) {
+               IWL_ERROR("Error: Response NULL in REPLY_REMOVE_STA.\n");
+               return 1;
+       }
+
+       res = (struct iwl_rx_packet *)skb->data;
+       if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+               IWL_ERROR("Bad return from REPLY_REMOVE_STA (0x%08X)\n",
+               res->hdr.flags);
+               return 1;
+       }
+
+       switch (res->u.rem_sta.status) {
+       case REM_STA_SUCCESS_MSK:
+               iwl_sta_ucode_deactivate(priv, addr);
+               break;
+       default:
+               break;
+       }
+
+       /* We didn't cache the SKB; let the caller free it */
+       return 1;
+}
+
+static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
+                                  u8 flags)
+{
+       struct iwl_rx_packet *res = NULL;
+       int ret;
+
+       struct iwl_rem_sta_cmd rm_sta_cmd;
+
+       struct iwl_host_cmd cmd = {
+               .id = REPLY_REMOVE_STA,
+               .len = sizeof(struct iwl_rem_sta_cmd),
+               .meta.flags = flags,
+               .data = &rm_sta_cmd,
+       };
+
+       memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd));
+       rm_sta_cmd.num_sta = 1;
+       memcpy(&rm_sta_cmd.addr, addr , ETH_ALEN);
+
+       if (flags & CMD_ASYNC)
+               cmd.meta.u.callback = iwl_remove_sta_callback;
+       else
+               cmd.meta.flags |= CMD_WANT_SKB;
+       ret = iwl_send_cmd(priv, &cmd);
+
+       if (ret || (flags & CMD_ASYNC))
+               return ret;
+
+       res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+       if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+               IWL_ERROR("Bad return from REPLY_REMOVE_STA (0x%08X)\n",
+                         res->hdr.flags);
+               ret = -EIO;
+       }
+
+       if (!ret) {
+               switch (res->u.rem_sta.status) {
+               case REM_STA_SUCCESS_MSK:
+                       iwl_sta_ucode_deactivate(priv, addr);
+                       IWL_DEBUG_ASSOC("REPLY_REMOVE_STA PASSED\n");
+                       break;
+               default:
+                       ret = -EIO;
+                       IWL_ERROR("REPLY_REMOVE_STA failed\n");
+                       break;
+               }
+       }
+
+       priv->alloc_rxb_skb--;
+       dev_kfree_skb_any(cmd.meta.u.skb);
+
+       return ret;
+}
+/**
+ * iwl_remove_station - Remove driver's knowledge of station.
+ *
+ */
+u8 iwl_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[i].used &&
+                           !compare_ether_addr(priv->stations[i].sta.sta.addr,
+                                               addr)) {
+                               index = i;
+                               break;
+                       }
+
+       if (unlikely(index == IWL_INVALID_STATION))
+               goto out;
+
+       if (priv->stations[index].used) {
+               priv->stations[index].used = 0;
+               priv->num_stations--;
+       }
+
+       BUG_ON(priv->num_stations < 0);
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
+       iwl_send_remove_station(priv, addr, CMD_ASYNC);
+       return index;
+out:
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
+       return 0;
+}
+EXPORT_SYMBOL(iwl_remove_station);
 int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
 {
        int i;
@@ -91,6 +479,7 @@ int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
        else
                return 0;
 }
+EXPORT_SYMBOL(iwl_send_static_wepkey_cmd);
 
 int iwl_remove_default_wep_key(struct iwl_priv *priv,
                               struct ieee80211_key_conf *keyconf)
@@ -111,6 +500,7 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
 
        return ret;
 }
+EXPORT_SYMBOL(iwl_remove_default_wep_key);
 
 int iwl_set_default_wep_key(struct iwl_priv *priv,
                            struct ieee80211_key_conf *keyconf)
@@ -119,7 +509,7 @@ int iwl_set_default_wep_key(struct iwl_priv *priv,
        unsigned long flags;
 
        keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
-       keyconf->hw_key_idx = keyconf->keyidx;
+       keyconf->hw_key_idx = HW_KEY_DEFAULT;
        priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
@@ -138,6 +528,7 @@ int iwl_set_default_wep_key(struct iwl_priv *priv,
 
        return ret;
 }
+EXPORT_SYMBOL(iwl_set_default_wep_key);
 
 static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
                                struct ieee80211_key_conf *keyconf,
@@ -148,7 +539,6 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
        int ret;
 
        keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
-       keyconf->hw_key_idx = keyconf->keyidx;
 
        key_flags |= (STA_KEY_FLG_WEP | STA_KEY_FLG_MAP_KEY_MSK);
        key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
@@ -172,15 +562,18 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
        memcpy(&priv->stations[sta_id].sta.key.key[3],
                                keyconf->key, keyconf->keylen);
 
-       priv->stations[sta_id].sta.key.key_offset =
+       if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
+                       == STA_KEY_FLG_NO_ENC)
+               priv->stations[sta_id].sta.key.key_offset =
                                 iwl_get_free_ucode_key_index(priv);
-       priv->stations[sta_id].sta.key.key_flags = key_flags;
+       /* else, we are overriding an existing key => no need to allocated room
+        * in uCode. */
 
+       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;
 
-       ret = iwl4965_send_add_station(priv,
-               &priv->stations[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);
 
@@ -202,7 +595,6 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
                key_flags |= STA_KEY_MULTICAST_MSK;
 
        keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
-       keyconf->hw_key_idx = keyconf->keyidx;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
        priv->stations[sta_id].keyinfo.alg = keyconf->alg;
@@ -214,8 +606,13 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
        memcpy(priv->stations[sta_id].sta.key.key, keyconf->key,
               keyconf->keylen);
 
-       priv->stations[sta_id].sta.key.key_offset =
-                               iwl_get_free_ucode_key_index(priv);
+       if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
+                       == STA_KEY_FLG_NO_ENC)
+               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. */
+
        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;
@@ -223,8 +620,7 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 
        IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
-       return iwl4965_send_add_station(priv,
-                               &priv->stations[sta_id].sta, CMD_ASYNC);
+       return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
 }
 
 static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
@@ -236,15 +632,18 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
 
        keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
        keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
-       keyconf->hw_key_idx = keyconf->keyidx;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
 
        priv->stations[sta_id].keyinfo.alg = keyconf->alg;
-       priv->stations[sta_id].keyinfo.conf = keyconf;
        priv->stations[sta_id].keyinfo.keylen = 16;
-       priv->stations[sta_id].sta.key.key_offset =
+
+       if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
+                       == STA_KEY_FLG_NO_ENC)
+               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. */
 
        /* This copy is acutally not needed: we get the key with each TX */
        memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16);
@@ -256,54 +655,78 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
        return ret;
 }
 
-int iwl_remove_dynamic_key(struct iwl_priv *priv, u8 sta_id)
+int iwl_remove_dynamic_key(struct iwl_priv *priv,
+                               struct ieee80211_key_conf *keyconf,
+                               u8 sta_id)
 {
        unsigned long flags;
+       int ret = 0;
+       u16 key_flags;
+       u8 keyidx;
 
-       priv->key_mapping_key = 0;
+       priv->key_mapping_key--;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
+       key_flags = le16_to_cpu(priv->stations[sta_id].sta.key.key_flags);
+       keyidx = (key_flags >> STA_KEY_FLG_KEYID_POS) & 0x3;
+
+       if (keyconf->keyidx != keyidx) {
+               /* We need to remove a key with index different that the one
+                * in the uCode. This means that the key we need to remove has
+                * been replaced by another one with different index.
+                * Don't do anything and return ok
+                */
+               spin_unlock_irqrestore(&priv->sta_lock, flags);
+               return 0;
+       }
+
        if (!test_and_clear_bit(priv->stations[sta_id].sta.key.key_offset,
                &priv->ucode_key_table))
                IWL_ERROR("index %d not used in uCode key table.\n",
                        priv->stations[sta_id].sta.key.key_offset);
        memset(&priv->stations[sta_id].keyinfo, 0,
-                                       sizeof(struct iwl4965_hw_key));
+                                       sizeof(struct iwl_hw_key));
        memset(&priv->stations[sta_id].sta.key, 0,
                                        sizeof(struct iwl4965_keyinfo));
-       priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
+       priv->stations[sta_id].sta.key.key_flags =
+                       STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID;
+       priv->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET;
        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("hwcrypto: clear ucode station key info\n");
-       return iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0);
+       ret =  iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
+       return ret;
 }
+EXPORT_SYMBOL(iwl_remove_dynamic_key);
 
 int iwl_set_dynamic_key(struct iwl_priv *priv,
-                               struct ieee80211_key_conf *key, u8 sta_id)
+                               struct ieee80211_key_conf *keyconf, u8 sta_id)
 {
        int ret;
 
-       priv->key_mapping_key = 1;
+       priv->key_mapping_key++;
+       keyconf->hw_key_idx = HW_KEY_DYNAMIC;
 
-       switch (key->alg) {
+       switch (keyconf->alg) {
        case ALG_CCMP:
-               ret = iwl_set_ccmp_dynamic_key_info(priv, key, sta_id);
+               ret = iwl_set_ccmp_dynamic_key_info(priv, keyconf, sta_id);
                break;
        case ALG_TKIP:
-               ret = iwl_set_tkip_dynamic_key_info(priv, key, sta_id);
+               ret = iwl_set_tkip_dynamic_key_info(priv, keyconf, sta_id);
                break;
        case ALG_WEP:
-               ret = iwl_set_wep_dynamic_key_info(priv, key, sta_id);
+               ret = iwl_set_wep_dynamic_key_info(priv, keyconf, sta_id);
                break;
        default:
-               IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, key->alg);
+               IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, keyconf->alg);
                ret = -EINVAL;
        }
 
        return ret;
 }
+EXPORT_SYMBOL(iwl_set_dynamic_key);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
 static void iwl_dump_lq_cmd(struct iwl_priv *priv,
@@ -353,3 +776,168 @@ int iwl_send_lq_cmd(struct iwl_priv *priv,
 }
 EXPORT_SYMBOL(iwl_send_lq_cmd);
 
+/**
+ * iwl_sta_init_lq - Initialize a station's hardware rate table
+ *
+ * The uCode's station table contains a table of fallback rates
+ * for automatic fallback during transmission.
+ *
+ * NOTE: This sets up a default set of values.  These will be replaced later
+ *       if the driver's iwl-4965-rs rate scaling algorithm is used, instead of
+ *       rc80211_simple.
+ *
+ * NOTE: Run REPLY_ADD_STA command to set up station table entry, before
+ *       calling this function (which runs REPLY_TX_LINK_QUALITY_CMD,
+ *       which requires station table entry to exist).
+ */
+static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap)
+{
+       int i, r;
+       struct iwl_link_quality_cmd link_cmd = {
+               .reserved1 = 0,
+       };
+       u16 rate_flags;
+
+       /* Set up the rate scaling to start at selected rate, fall back
+        * all the way down to 1M in IEEE order, and then spin on 1M */
+       if (is_ap)
+               r = IWL_RATE_54M_INDEX;
+       else if (priv->band == IEEE80211_BAND_5GHZ)
+               r = IWL_RATE_6M_INDEX;
+       else
+               r = IWL_RATE_1M_INDEX;
+
+       for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
+               rate_flags = 0;
+               if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
+                       rate_flags |= RATE_MCS_CCK_MSK;
+
+               /* Use Tx antenna B only */
+               rate_flags |= RATE_MCS_ANT_B_MSK; /*FIXME:RS*/
+
+               link_cmd.rs_table[i].rate_n_flags =
+                       iwl4965_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
+               r = iwl4965_get_prev_ieee_rate(r);
+       }
+
+       link_cmd.general_params.single_stream_ant_msk = 2;
+       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);
+
+       /* Update the rate scaling for control frame Tx to AP */
+       link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id;
+
+       iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD,
+                              sizeof(link_cmd), &link_cmd, NULL);
+}
+/**
+ * iwl_rxon_add_station - add station into station table.
+ *
+ * there is only one AP station with id= IWL_AP_ID
+ * NOTE: mutex must be held before calling this fnction
+ */
+int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
+{
+       u8 sta_id;
+
+       /* Add station to device's station table */
+#ifdef CONFIG_IWL4965_HT
+       struct ieee80211_conf *conf = &priv->hw->conf;
+       struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf;
+
+       if ((is_ap) &&
+           (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) &&
+           (priv->iw_mode == IEEE80211_IF_TYPE_STA))
+               sta_id = iwl_add_station_flags(priv, addr, is_ap,
+                                                  0, cur_ht_config);
+       else
+#endif /* CONFIG_IWL4965_HT */
+               sta_id = iwl_add_station_flags(priv, addr, is_ap,
+                                                  0, NULL);
+
+       /* Set up default rate scaling table in device's station table */
+       iwl_sta_init_lq(priv, addr, is_ap);
+
+       return sta_id;
+}
+EXPORT_SYMBOL(iwl_rxon_add_station);
+
+
+/**
+ * iwl_get_sta_id - Find station's index within station table
+ *
+ * If new IBSS station, create new entry in station table
+ */
+int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
+{
+       int sta_id;
+       u16 fc = le16_to_cpu(hdr->frame_control);
+       DECLARE_MAC_BUF(mac);
+
+       /* If this frame is broadcast or management, use broadcast station id */
+       if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
+           is_multicast_ether_addr(hdr->addr1))
+               return priv->hw_params.bcast_sta_id;
+
+       switch (priv->iw_mode) {
+
+       /* If we are a client station in a BSS network, use the special
+        * AP station entry (that's the only station we communicate with) */
+       case IEEE80211_IF_TYPE_STA:
+               return IWL_AP_ID;
+
+       /* If we are an AP, then find the station, or use BCAST */
+       case IEEE80211_IF_TYPE_AP:
+               sta_id = iwl_find_station(priv, hdr->addr1);
+               if (sta_id != IWL_INVALID_STATION)
+                       return sta_id;
+               return priv->hw_params.bcast_sta_id;
+
+       /* If this frame is going out to an IBSS network, find the station,
+        * or create a new station table entry */
+       case IEEE80211_IF_TYPE_IBSS:
+               sta_id = iwl_find_station(priv, hdr->addr1);
+               if (sta_id != IWL_INVALID_STATION)
+                       return sta_id;
+
+               /* Create new station table entry */
+               sta_id = iwl_add_station_flags(priv, hdr->addr1,
+                                                  0, CMD_ASYNC, NULL);
+
+               if (sta_id != IWL_INVALID_STATION)
+                       return sta_id;
+
+               IWL_DEBUG_DROP("Station %s not in station map. "
+                              "Defaulting to broadcast...\n",
+                              print_mac(mac, hdr->addr1));
+               iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
+               return priv->hw_params.bcast_sta_id;
+
+       default:
+               IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode);
+               return priv->hw_params.bcast_sta_id;
+       }
+}
+EXPORT_SYMBOL(iwl_get_sta_id);
+
+
+/**
+ * iwl_sta_modify_enable_tid_tx - Enable Tx for this TID in station table
+ */
+void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid)
+{
+       unsigned long flags;
+
+       /* Remove "disable" flag, to enable Tx for this TID */
+       spin_lock_irqsave(&priv->sta_lock, flags);
+       priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX;
+       priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid));
+       priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+       iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+}
+EXPORT_SYMBOL(iwl_sta_modify_enable_tid_tx);
+
+
index 44f272ecc8272466dc71280f6ecf7c84035b65d4..3d55716f530109d50885370205f3ad0d4c60235d 100644 (file)
 #ifndef __iwl_sta_h__
 #define __iwl_sta_h__
 
-#include <net/mac80211.h>
-
-#include "iwl-eeprom.h"
-#include "iwl-core.h"
-#include "iwl-4965.h"
-#include "iwl-io.h"
-#include "iwl-helpers.h"
+#define HW_KEY_DYNAMIC 0
+#define HW_KEY_DEFAULT 1
 
 int iwl_get_free_ucode_key_index(struct iwl_priv *priv);
 int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty);
@@ -43,7 +38,12 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
                                struct ieee80211_key_conf *key);
 int iwl_set_default_wep_key(struct iwl_priv *priv,
                                struct ieee80211_key_conf *key);
-int iwl_remove_dynamic_key(struct iwl_priv *priv, u8 sta_id);
 int iwl_set_dynamic_key(struct iwl_priv *priv,
                                struct ieee80211_key_conf *key, u8 sta_id);
+int iwl_remove_dynamic_key(struct iwl_priv *priv,
+                               struct ieee80211_key_conf *key, u8 sta_id);
+int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap);
+u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap);
+int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
+void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid);
 #endif /* __iwl_sta_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
new file mode 100644 (file)
index 0000000..cfe6f4b
--- /dev/null
@@ -0,0 +1,1393 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2008 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:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/etherdevice.h>
+#include <net/mac80211.h>
+#include "iwl-eeprom.h"
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-sta.h"
+#include "iwl-io.h"
+#include "iwl-helpers.h"
+
+#ifdef CONFIG_IWL4965_HT
+
+static const u16 default_tid_to_tx_fifo[] = {
+       IWL_TX_FIFO_AC1,
+       IWL_TX_FIFO_AC0,
+       IWL_TX_FIFO_AC0,
+       IWL_TX_FIFO_AC1,
+       IWL_TX_FIFO_AC2,
+       IWL_TX_FIFO_AC2,
+       IWL_TX_FIFO_AC3,
+       IWL_TX_FIFO_AC3,
+       IWL_TX_FIFO_NONE,
+       IWL_TX_FIFO_NONE,
+       IWL_TX_FIFO_NONE,
+       IWL_TX_FIFO_NONE,
+       IWL_TX_FIFO_NONE,
+       IWL_TX_FIFO_NONE,
+       IWL_TX_FIFO_NONE,
+       IWL_TX_FIFO_NONE,
+       IWL_TX_FIFO_AC3
+};
+
+#endif /*CONFIG_IWL4965_HT */
+
+
+
+/**
+ * iwl_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
+ *
+ * Does NOT advance any TFD circular buffer read/write indexes
+ * Does NOT free the TFD itself (which is within circular buffer)
+ */
+int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+       struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0];
+       struct iwl_tfd_frame *bd = &bd_tmp[txq->q.read_ptr];
+       struct pci_dev *dev = priv->pci_dev;
+       int i;
+       int counter = 0;
+       int index, is_odd;
+
+       /* Host command buffers stay mapped in memory, nothing to clean */
+       if (txq->q.id == IWL_CMD_QUEUE_NUM)
+               return 0;
+
+       /* Sanity check on number of chunks */
+       counter = IWL_GET_BITS(*bd, num_tbs);
+       if (counter > MAX_NUM_OF_TBS) {
+               IWL_ERROR("Too many chunks: %i\n", counter);
+               /* @todo issue fatal error, it is quite serious situation */
+               return 0;
+       }
+
+       /* Unmap chunks, if any.
+        * TFD info for odd chunks is different format than for even chunks. */
+       for (i = 0; i < counter; i++) {
+               index = i / 2;
+               is_odd = i & 0x1;
+
+               if (is_odd)
+                       pci_unmap_single(
+                               dev,
+                               IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) |
+                               (IWL_GET_BITS(bd->pa[index],
+                                             tb2_addr_hi20) << 16),
+                               IWL_GET_BITS(bd->pa[index], tb2_len),
+                               PCI_DMA_TODEVICE);
+
+               else if (i > 0)
+                       pci_unmap_single(dev,
+                                        le32_to_cpu(bd->pa[index].tb1_addr),
+                                        IWL_GET_BITS(bd->pa[index], tb1_len),
+                                        PCI_DMA_TODEVICE);
+
+               /* Free SKB, if any, for this chunk */
+               if (txq->txb[txq->q.read_ptr].skb[i]) {
+                       struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[i];
+
+                       dev_kfree_skb(skb);
+                       txq->txb[txq->q.read_ptr].skb[i] = NULL;
+               }
+       }
+       return 0;
+}
+EXPORT_SYMBOL(iwl_hw_txq_free_tfd);
+
+
+int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,
+                                dma_addr_t addr, u16 len)
+{
+       int index, is_odd;
+       struct iwl_tfd_frame *tfd = ptr;
+       u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs);
+
+       /* Each TFD can point to a maximum 20 Tx buffers */
+       if ((num_tbs >= MAX_NUM_OF_TBS) || (num_tbs < 0)) {
+               IWL_ERROR("Error can not send more than %d chunks\n",
+                         MAX_NUM_OF_TBS);
+               return -EINVAL;
+       }
+
+       index = num_tbs / 2;
+       is_odd = num_tbs & 0x1;
+
+       if (!is_odd) {
+               tfd->pa[index].tb1_addr = cpu_to_le32(addr);
+               IWL_SET_BITS(tfd->pa[index], tb1_addr_hi,
+                            iwl_get_dma_hi_address(addr));
+               IWL_SET_BITS(tfd->pa[index], tb1_len, len);
+       } else {
+               IWL_SET_BITS(tfd->pa[index], tb2_addr_lo16,
+                            (u32) (addr & 0xffff));
+               IWL_SET_BITS(tfd->pa[index], tb2_addr_hi20, addr >> 16);
+               IWL_SET_BITS(tfd->pa[index], tb2_len, len);
+       }
+
+       IWL_SET_BITS(*tfd, num_tbs, num_tbs + 1);
+
+       return 0;
+}
+EXPORT_SYMBOL(iwl_hw_txq_attach_buf_to_tfd);
+
+/**
+ * iwl_txq_update_write_ptr - Send new write index to hardware
+ */
+int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+       u32 reg = 0;
+       int ret = 0;
+       int txq_id = txq->q.id;
+
+       if (txq->need_update == 0)
+               return ret;
+
+       /* if we're trying to save power */
+       if (test_bit(STATUS_POWER_PMI, &priv->status)) {
+               /* wake up nic if it's powered down ...
+                * uCode will wake up, and interrupt us again, so next
+                * time we'll skip this part. */
+               reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
+
+               if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+                       IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg);
+                       iwl_set_bit(priv, CSR_GP_CNTRL,
+                                   CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+                       return ret;
+               }
+
+               /* restore this queue's parameters in nic hardware. */
+               ret = iwl_grab_nic_access(priv);
+               if (ret)
+                       return ret;
+               iwl_write_direct32(priv, HBUS_TARG_WRPTR,
+                                    txq->q.write_ptr | (txq_id << 8));
+               iwl_release_nic_access(priv);
+
+       /* else not in power-save mode, uCode will never sleep when we're
+        * trying to tx (during RFKILL, we're not trying to tx). */
+       } else
+               iwl_write32(priv, HBUS_TARG_WRPTR,
+                           txq->q.write_ptr | (txq_id << 8));
+
+       txq->need_update = 0;
+
+       return ret;
+}
+EXPORT_SYMBOL(iwl_txq_update_write_ptr);
+
+
+/**
+ * iwl_tx_queue_free - Deallocate DMA queue.
+ * @txq: Transmit queue to deallocate.
+ *
+ * Empty queue by removing and destroying all BD's.
+ * Free all buffers.
+ * 0-fill, but do not free "txq" descriptor structure.
+ */
+static void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+       struct iwl_queue *q = &txq->q;
+       struct pci_dev *dev = priv->pci_dev;
+       int len;
+
+       if (q->n_bd == 0)
+               return;
+
+       /* first, empty all BD's */
+       for (; q->write_ptr != q->read_ptr;
+            q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd))
+               iwl_hw_txq_free_tfd(priv, txq);
+
+       len = sizeof(struct iwl_cmd) * q->n_window;
+       if (q->id == IWL_CMD_QUEUE_NUM)
+               len += IWL_MAX_SCAN_SIZE;
+
+       /* De-alloc array of command/tx buffers */
+       pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
+
+       /* De-alloc circular buffer of TFDs */
+       if (txq->q.n_bd)
+               pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) *
+                                   txq->q.n_bd, txq->bd, txq->q.dma_addr);
+
+       /* De-alloc array of per-TFD driver data */
+       kfree(txq->txb);
+       txq->txb = NULL;
+
+       /* 0-fill queue descriptor structure */
+       memset(txq, 0, sizeof(*txq));
+}
+
+/*************** DMA-QUEUE-GENERAL-FUNCTIONS  *****
+ * DMA services
+ *
+ * Theory of operation
+ *
+ * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer
+ * of buffer descriptors, each of which points to one or more data buffers for
+ * the device to read from or fill.  Driver and device exchange status of each
+ * queue via "read" and "write" pointers.  Driver keeps minimum of 2 empty
+ * entries in each circular buffer, to protect against confusing empty and full
+ * queue states.
+ *
+ * The device reads or writes the data in the queues via the device's several
+ * DMA/FIFO channels.  Each queue is mapped to a single DMA channel.
+ *
+ * For Tx queue, there are low mark and high mark limits. If, after queuing
+ * the packet for Tx, free space become < low mark, Tx queue stopped. When
+ * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
+ * Tx queue resumed.
+ *
+ * See more detailed info in iwl-4965-hw.h.
+ ***************************************************/
+
+int iwl_queue_space(const struct iwl_queue *q)
+{
+       int s = q->read_ptr - q->write_ptr;
+
+       if (q->read_ptr > q->write_ptr)
+               s -= q->n_bd;
+
+       if (s <= 0)
+               s += q->n_window;
+       /* keep some reserve to not confuse empty and full situations */
+       s -= 2;
+       if (s < 0)
+               s = 0;
+       return s;
+}
+EXPORT_SYMBOL(iwl_queue_space);
+
+
+/**
+ * iwl_queue_init - Initialize queue's high/low-water and read/write indexes
+ */
+static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
+                         int count, int slots_num, u32 id)
+{
+       q->n_bd = count;
+       q->n_window = slots_num;
+       q->id = id;
+
+       /* count must be power-of-two size, otherwise iwl_queue_inc_wrap
+        * and iwl_queue_dec_wrap are broken. */
+       BUG_ON(!is_power_of_2(count));
+
+       /* slots_num must be power-of-two size, otherwise
+        * get_cmd_index is broken. */
+       BUG_ON(!is_power_of_2(slots_num));
+
+       q->low_mark = q->n_window / 4;
+       if (q->low_mark < 4)
+               q->low_mark = 4;
+
+       q->high_mark = q->n_window / 8;
+       if (q->high_mark < 2)
+               q->high_mark = 2;
+
+       q->write_ptr = q->read_ptr = 0;
+
+       return 0;
+}
+
+/**
+ * iwl_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue
+ */
+static int iwl_tx_queue_alloc(struct iwl_priv *priv,
+                             struct iwl_tx_queue *txq, u32 id)
+{
+       struct pci_dev *dev = priv->pci_dev;
+
+       /* Driver private data, only for Tx (not command) queues,
+        * not shared with device. */
+       if (id != IWL_CMD_QUEUE_NUM) {
+               txq->txb = kmalloc(sizeof(txq->txb[0]) *
+                                  TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
+               if (!txq->txb) {
+                       IWL_ERROR("kmalloc for auxiliary BD "
+                                 "structures failed\n");
+                       goto error;
+               }
+       } else
+               txq->txb = NULL;
+
+       /* Circular buffer of transmit frame descriptors (TFDs),
+        * shared with device */
+       txq->bd = pci_alloc_consistent(dev,
+                       sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX,
+                       &txq->q.dma_addr);
+
+       if (!txq->bd) {
+               IWL_ERROR("pci_alloc_consistent(%zd) failed\n",
+                         sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX);
+               goto error;
+       }
+       txq->q.id = id;
+
+       return 0;
+
+ error:
+       kfree(txq->txb);
+       txq->txb = NULL;
+
+       return -ENOMEM;
+}
+
+/*
+ * Tell nic where to find circular buffer of Tx Frame Descriptors for
+ * given Tx queue, and enable the DMA channel used for that queue.
+ *
+ * 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA
+ * channels supported in hardware.
+ */
+static int iwl_hw_tx_queue_init(struct iwl_priv *priv,
+                               struct iwl_tx_queue *txq)
+{
+       int rc;
+       unsigned long flags;
+       int txq_id = txq->q.id;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       rc = iwl_grab_nic_access(priv);
+       if (rc) {
+               spin_unlock_irqrestore(&priv->lock, flags);
+               return rc;
+       }
+
+       /* Circular buffer (TFD queue in DRAM) physical base address */
+       iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
+                            txq->q.dma_addr >> 8);
+
+       /* Enable DMA channel, using same id as for TFD queue */
+       iwl_write_direct32(
+               priv, FH_TCSR_CHNL_TX_CONFIG_REG(txq_id),
+               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL);
+       iwl_release_nic_access(priv);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+/**
+ * iwl_tx_queue_init - Allocate and initialize one tx/cmd queue
+ */
+static int iwl_tx_queue_init(struct iwl_priv *priv,
+                            struct iwl_tx_queue *txq,
+                            int slots_num, u32 txq_id)
+{
+       struct pci_dev *dev = priv->pci_dev;
+       int len;
+       int rc = 0;
+
+       /*
+        * Alloc buffer array for commands (Tx or other types of commands).
+        * For the command queue (#4), allocate command space + one big
+        * command for scan, since scan command is very huge; the system will
+        * not have two scans at the same time, so only one is needed.
+        * For normal Tx queues (all other queues), no super-size command
+        * space is needed.
+        */
+       len = sizeof(struct iwl_cmd) * slots_num;
+       if (txq_id == IWL_CMD_QUEUE_NUM)
+               len +=  IWL_MAX_SCAN_SIZE;
+       txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd);
+       if (!txq->cmd)
+               return -ENOMEM;
+
+       /* Alloc driver data array and TFD circular buffer */
+       rc = iwl_tx_queue_alloc(priv, txq, txq_id);
+       if (rc) {
+               pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
+
+               return -ENOMEM;
+       }
+       txq->need_update = 0;
+
+       /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
+        * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
+       BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
+
+       /* Initialize queue's high/low-water marks, and head/tail indexes */
+       iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
+
+       /* Tell device where to find queue */
+       iwl_hw_tx_queue_init(priv, txq);
+
+       return 0;
+}
+/**
+ * iwl_hw_txq_ctx_free - Free TXQ Context
+ *
+ * Destroy all TX DMA queues and structures
+ */
+void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
+{
+       int txq_id;
+
+       /* Tx queues */
+       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
+               iwl_tx_queue_free(priv, &priv->txq[txq_id]);
+
+       /* Keep-warm buffer */
+       iwl_kw_free(priv);
+}
+EXPORT_SYMBOL(iwl_hw_txq_ctx_free);
+
+
+/**
+ * iwl_txq_ctx_reset - Reset TX queue context
+ * Destroys all DMA structures and initialise them again
+ *
+ * @param priv
+ * @return error code
+ */
+int iwl_txq_ctx_reset(struct iwl_priv *priv)
+{
+       int ret = 0;
+       int txq_id, slots_num;
+       unsigned long flags;
+
+       iwl_kw_free(priv);
+
+       /* Free all tx/cmd queues and keep-warm buffer */
+       iwl_hw_txq_ctx_free(priv);
+
+       /* Alloc keep-warm buffer */
+       ret = iwl_kw_alloc(priv);
+       if (ret) {
+               IWL_ERROR("Keep Warm allocation failed");
+               goto error_kw;
+       }
+       spin_lock_irqsave(&priv->lock, flags);
+       ret = iwl_grab_nic_access(priv);
+       if (unlikely(ret)) {
+               spin_unlock_irqrestore(&priv->lock, flags);
+               goto error_reset;
+       }
+
+       /* Turn off all Tx DMA fifos */
+       priv->cfg->ops->lib->txq_set_sched(priv, 0);
+
+       iwl_release_nic_access(priv);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+
+       /* Tell nic where to find the keep-warm buffer */
+       ret = iwl_kw_init(priv);
+       if (ret) {
+               IWL_ERROR("kw_init failed\n");
+               goto error_reset;
+       }
+
+       /* Alloc and init all Tx queues, including the command queue (#4) */
+       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
+               slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
+                                       TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+               ret = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
+                                      txq_id);
+               if (ret) {
+                       IWL_ERROR("Tx %d queue init failed\n", txq_id);
+                       goto error;
+               }
+       }
+
+       return ret;
+
+ error:
+       iwl_hw_txq_ctx_free(priv);
+ error_reset:
+       iwl_kw_free(priv);
+ error_kw:
+       return ret;
+}
+/**
+ * iwl_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory
+ */
+void iwl_txq_ctx_stop(struct iwl_priv *priv)
+{
+
+       int txq_id;
+       unsigned long flags;
+
+
+       /* Turn off all Tx DMA fifos */
+       spin_lock_irqsave(&priv->lock, flags);
+       if (iwl_grab_nic_access(priv)) {
+               spin_unlock_irqrestore(&priv->lock, flags);
+               return;
+       }
+
+       priv->cfg->ops->lib->txq_set_sched(priv, 0);
+
+       /* Stop each Tx DMA channel, and wait for it to be idle */
+       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
+               iwl_write_direct32(priv,
+                                  FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), 0x0);
+               iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG,
+                                   FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE
+                                   (txq_id), 200);
+       }
+       iwl_release_nic_access(priv);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       /* Deallocate memory for all Tx queues */
+       iwl_hw_txq_ctx_free(priv);
+}
+EXPORT_SYMBOL(iwl_txq_ctx_stop);
+
+/*
+ * handle build REPLY_TX command notification.
+ */
+static void iwl_tx_cmd_build_basic(struct iwl_priv *priv,
+                                 struct iwl_tx_cmd *tx_cmd,
+                                 struct ieee80211_tx_info *info,
+                                 struct ieee80211_hdr *hdr,
+                                 int is_unicast, u8 std_id)
+{
+       u16 fc = le16_to_cpu(hdr->frame_control);
+       __le32 tx_flags = tx_cmd->tx_flags;
+
+       tx_cmd->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+       if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
+               tx_flags |= TX_CMD_FLG_ACK_MSK;
+               if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)
+                       tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+               if (ieee80211_is_probe_response(fc) &&
+                   !(le16_to_cpu(hdr->seq_ctrl) & 0xf))
+                       tx_flags |= TX_CMD_FLG_TSF_MSK;
+       } else {
+               tx_flags &= (~TX_CMD_FLG_ACK_MSK);
+               tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+       }
+
+       if (ieee80211_is_back_request(fc))
+               tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK;
+
+
+       tx_cmd->sta_id = std_id;
+       if (ieee80211_get_morefrag(hdr))
+               tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
+
+       if (ieee80211_is_qos_data(fc)) {
+               u8 *qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc));
+               tx_cmd->tid_tspec = qc[0] & 0xf;
+               tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
+       } else {
+               tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+       }
+
+       if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
+               tx_flags |= TX_CMD_FLG_RTS_MSK;
+               tx_flags &= ~TX_CMD_FLG_CTS_MSK;
+       } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
+               tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+               tx_flags |= TX_CMD_FLG_CTS_MSK;
+       }
+
+       if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
+               tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
+
+       tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
+       if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
+               if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ ||
+                   (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ)
+                       tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(3);
+               else
+                       tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(2);
+       } else {
+               tx_cmd->timeout.pm_frame_timeout = 0;
+       }
+
+       tx_cmd->driver_txop = 0;
+       tx_cmd->tx_flags = tx_flags;
+       tx_cmd->next_frame_len = 0;
+}
+
+#define RTS_HCCA_RETRY_LIMIT           3
+#define RTS_DFAULT_RETRY_LIMIT         60
+
+static void iwl_tx_cmd_build_rate(struct iwl_priv *priv,
+                             struct iwl_tx_cmd *tx_cmd,
+                             struct ieee80211_tx_info *info,
+                             u16 fc, int sta_id,
+                             int is_hcca)
+{
+       u8 rts_retry_limit = 0;
+       u8 data_retry_limit = 0;
+       u8 rate_plcp;
+       u16 rate_flags = 0;
+       int rate_idx;
+
+       rate_idx = min(ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xffff,
+                       IWL_RATE_COUNT - 1);
+
+       rate_plcp = iwl_rates[rate_idx].plcp;
+
+       rts_retry_limit = (is_hcca) ?
+           RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT;
+
+       if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
+               rate_flags |= RATE_MCS_CCK_MSK;
+
+
+       if (ieee80211_is_probe_response(fc)) {
+               data_retry_limit = 3;
+               if (data_retry_limit < rts_retry_limit)
+                       rts_retry_limit = data_retry_limit;
+       } else
+               data_retry_limit = IWL_DEFAULT_TX_RETRY;
+
+       if (priv->data_retry_limit != -1)
+               data_retry_limit = priv->data_retry_limit;
+
+
+       if (ieee80211_is_data(fc)) {
+               tx_cmd->initial_rate_index = 0;
+               tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
+       } else {
+               switch (fc & IEEE80211_FCTL_STYPE) {
+               case IEEE80211_STYPE_AUTH:
+               case IEEE80211_STYPE_DEAUTH:
+               case IEEE80211_STYPE_ASSOC_REQ:
+               case IEEE80211_STYPE_REASSOC_REQ:
+                       if (tx_cmd->tx_flags & TX_CMD_FLG_RTS_MSK) {
+                               tx_cmd->tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+                               tx_cmd->tx_flags |= TX_CMD_FLG_CTS_MSK;
+                       }
+                       break;
+               default:
+                       break;
+               }
+
+               /* Alternate between antenna A and B for successive frames */
+               if (priv->use_ant_b_for_management_frame) {
+                       priv->use_ant_b_for_management_frame = 0;
+                       rate_flags |= RATE_MCS_ANT_B_MSK;
+               } else {
+                       priv->use_ant_b_for_management_frame = 1;
+                       rate_flags |= RATE_MCS_ANT_A_MSK;
+               }
+       }
+
+       tx_cmd->rts_retry_limit = rts_retry_limit;
+       tx_cmd->data_retry_limit = data_retry_limit;
+       tx_cmd->rate_n_flags = iwl4965_hw_set_rate_n_flags(rate_plcp, rate_flags);
+}
+
+static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
+                                     struct ieee80211_tx_info *info,
+                                     struct iwl_tx_cmd *tx_cmd,
+                                     struct sk_buff *skb_frag,
+                                     int sta_id)
+{
+       struct ieee80211_key_conf *keyconf = info->control.hw_key;
+
+       switch (keyconf->alg) {
+       case ALG_CCMP:
+               tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
+               memcpy(tx_cmd->key, keyconf->key, keyconf->keylen);
+               if (info->flags & IEEE80211_TX_CTL_AMPDU)
+                       tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK;
+               IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n");
+               break;
+
+       case ALG_TKIP:
+               tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
+               ieee80211_get_tkip_key(keyconf, skb_frag,
+                       IEEE80211_TKIP_P2_KEY, tx_cmd->key);
+               IWL_DEBUG_TX("tx_cmd with tkip hwcrypto\n");
+               break;
+
+       case ALG_WEP:
+               tx_cmd->sec_ctl |= (TX_CMD_SEC_WEP |
+                       (keyconf->keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT);
+
+               if (keyconf->keylen == WEP_KEY_LEN_128)
+                       tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
+
+               memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen);
+
+               IWL_DEBUG_TX("Configuring packet for WEP encryption "
+                            "with key %d\n", keyconf->keyidx);
+               break;
+
+       default:
+               printk(KERN_ERR "Unknown encode alg %d\n", keyconf->alg);
+               break;
+       }
+}
+
+static void iwl_update_tx_stats(struct iwl_priv *priv, u16 fc, u16 len)
+{
+       /* 0 - mgmt, 1 - cnt, 2 - data */
+       int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2;
+       priv->tx_stats[idx].cnt++;
+       priv->tx_stats[idx].bytes += len;
+}
+
+/*
+ * start REPLY_TX command process
+ */
+int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct iwl_tfd_frame *tfd;
+       u32 *control_flags;
+       int txq_id = skb_get_queue_mapping(skb);
+       struct iwl_tx_queue *txq = NULL;
+       struct iwl_queue *q = NULL;
+       dma_addr_t phys_addr;
+       dma_addr_t txcmd_phys;
+       dma_addr_t scratch_phys;
+       struct iwl_cmd *out_cmd = NULL;
+       struct iwl_tx_cmd *tx_cmd;
+       u16 len, idx, len_org;
+       u16 seq_number = 0;
+       u8 id, hdr_len, unicast;
+       u8 sta_id;
+       u16 fc;
+       u8 wait_write_ptr = 0;
+       u8 tid = 0;
+       u8 *qc = NULL;
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       if (iwl_is_rfkill(priv)) {
+               IWL_DEBUG_DROP("Dropping - RF KILL\n");
+               goto drop_unlock;
+       }
+
+       if (!priv->vif) {
+               IWL_DEBUG_DROP("Dropping - !priv->vif\n");
+               goto drop_unlock;
+       }
+
+       if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) ==
+            IWL_INVALID_RATE) {
+               IWL_ERROR("ERROR: No TX rate available.\n");
+               goto drop_unlock;
+       }
+
+       unicast = !is_multicast_ether_addr(hdr->addr1);
+       id = 0;
+
+       fc = le16_to_cpu(hdr->frame_control);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if (ieee80211_is_auth(fc))
+               IWL_DEBUG_TX("Sending AUTH frame\n");
+       else if (ieee80211_is_assoc_request(fc))
+               IWL_DEBUG_TX("Sending ASSOC frame\n");
+       else if (ieee80211_is_reassoc_request(fc))
+               IWL_DEBUG_TX("Sending REASSOC frame\n");
+#endif
+
+       /* drop all data frame if we are not associated */
+       if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
+          (!iwl_is_associated(priv) ||
+           ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id) ||
+           !priv->assoc_station_added)) {
+               IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n");
+               goto drop_unlock;
+       }
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       hdr_len = ieee80211_get_hdrlen(fc);
+
+       /* Find (or create) index into station table for destination station */
+       sta_id = iwl_get_sta_id(priv, hdr);
+       if (sta_id == IWL_INVALID_STATION) {
+               DECLARE_MAC_BUF(mac);
+
+               IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n",
+                              print_mac(mac, hdr->addr1));
+               goto drop;
+       }
+
+       IWL_DEBUG_TX("station Id %d\n", sta_id);
+
+       if (ieee80211_is_qos_data(fc)) {
+               qc = ieee80211_get_qos_ctrl(hdr, hdr_len);
+               tid = qc[0] & 0xf;
+               seq_number = priv->stations[sta_id].tid[tid].seq_number &
+                               IEEE80211_SCTL_SEQ;
+               hdr->seq_ctrl = cpu_to_le16(seq_number) |
+                       (hdr->seq_ctrl &
+                               __constant_cpu_to_le16(IEEE80211_SCTL_FRAG));
+               seq_number += 0x10;
+#ifdef CONFIG_IWL4965_HT
+               /* aggregation is on for this <sta,tid> */
+               if (info->flags & IEEE80211_TX_CTL_AMPDU)
+                       txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
+               priv->stations[sta_id].tid[tid].tfds_in_queue++;
+#endif /* CONFIG_IWL4965_HT */
+       }
+
+       /* Descriptor for chosen Tx queue */
+       txq = &priv->txq[txq_id];
+       q = &txq->q;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       /* Set up first empty TFD within this queue's circular TFD buffer */
+       tfd = &txq->bd[q->write_ptr];
+       memset(tfd, 0, sizeof(*tfd));
+       control_flags = (u32 *) tfd;
+       idx = get_cmd_index(q, q->write_ptr, 0);
+
+       /* Set up driver data for this TFD */
+       memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
+       txq->txb[q->write_ptr].skb[0] = skb;
+
+       /* Set up first empty entry in queue's array of Tx/cmd buffers */
+       out_cmd = &txq->cmd[idx];
+       tx_cmd = &out_cmd->cmd.tx;
+       memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
+       memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd));
+
+       /*
+        * Set up the Tx-command (not MAC!) header.
+        * Store the chosen Tx queue and TFD index within the sequence field;
+        * after Tx, uCode's Tx response will return this value so driver can
+        * locate the frame within the tx queue and do post-tx processing.
+        */
+       out_cmd->hdr.cmd = REPLY_TX;
+       out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
+                               INDEX_TO_SEQ(q->write_ptr)));
+
+       /* Copy MAC header from skb into command buffer */
+       memcpy(tx_cmd->hdr, hdr, hdr_len);
+
+       /*
+        * Use the first empty entry in this queue's command buffer array
+        * to contain the Tx command and MAC header concatenated together
+        * (payload data will be in another buffer).
+        * Size of this varies, due to varying MAC header length.
+        * If end is not dword aligned, we'll have 2 extra bytes at the end
+        * of the MAC header (device reads on dword boundaries).
+        * We'll tell device about this padding later.
+        */
+       len = sizeof(struct iwl_tx_cmd) +
+               sizeof(struct iwl_cmd_header) + hdr_len;
+
+       len_org = len;
+       len = (len + 3) & ~3;
+
+       if (len_org != len)
+               len_org = 1;
+       else
+               len_org = 0;
+
+       /* Physical address of this Tx command's header (not MAC header!),
+        * within command buffer array. */
+       txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx +
+                    offsetof(struct iwl_cmd, hdr);
+
+       /* Add buffer containing Tx command and MAC(!) header to TFD's
+        * first entry */
+       iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
+
+       if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT))
+               iwl_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id);
+
+       /* Set up TFD's 2nd entry to point directly to remainder of skb,
+        * if any (802.11 null frames have no payload). */
+       len = skb->len - hdr_len;
+       if (len) {
+               phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
+                                          len, PCI_DMA_TODEVICE);
+               iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len);
+       }
+
+       /* Tell NIC about any 2-byte padding after MAC header */
+       if (len_org)
+               tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
+
+       /* Total # bytes to be transmitted */
+       len = (u16)skb->len;
+       tx_cmd->len = cpu_to_le16(len);
+       /* TODO need this for burst mode later on */
+       iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, unicast, sta_id);
+
+       /* set is_hcca to 0; it probably will never be implemented */
+       iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0);
+
+       iwl_update_tx_stats(priv, fc, len);
+
+       scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
+               offsetof(struct iwl_tx_cmd, scratch);
+       tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
+       tx_cmd->dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys);
+
+       if (!ieee80211_get_morefrag(hdr)) {
+               txq->need_update = 1;
+               if (qc)
+                       priv->stations[sta_id].tid[tid].seq_number = seq_number;
+       } else {
+               wait_write_ptr = 1;
+               txq->need_update = 0;
+       }
+
+       iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
+
+       iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
+
+       /* Set up entry for this TFD in Tx byte-count array */
+       priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, len);
+
+       /* Tell device the write index *just past* this latest filled TFD */
+       q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
+       ret = iwl_txq_update_write_ptr(priv, txq);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       if (ret)
+               return ret;
+
+       if ((iwl_queue_space(q) < q->high_mark)
+           && priv->mac80211_registered) {
+               if (wait_write_ptr) {
+                       spin_lock_irqsave(&priv->lock, flags);
+                       txq->need_update = 1;
+                       iwl_txq_update_write_ptr(priv, txq);
+                       spin_unlock_irqrestore(&priv->lock, flags);
+               }
+
+               ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb));
+       }
+
+       return 0;
+
+drop_unlock:
+       spin_unlock_irqrestore(&priv->lock, flags);
+drop:
+       return -1;
+}
+EXPORT_SYMBOL(iwl_tx_skb);
+
+/*************** HOST COMMAND QUEUE FUNCTIONS   *****/
+
+/**
+ * iwl_enqueue_hcmd - enqueue a uCode command
+ * @priv: device private data point
+ * @cmd: a point to the ucode command structure
+ *
+ * The function returns < 0 values to indicate the operation is
+ * failed. On success, it turns the index (> 0) of command in the
+ * command queue.
+ */
+int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+       struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
+       struct iwl_queue *q = &txq->q;
+       struct iwl_tfd_frame *tfd;
+       u32 *control_flags;
+       struct iwl_cmd *out_cmd;
+       u32 idx;
+       u16 fix_size;
+       dma_addr_t phys_addr;
+       int ret;
+       unsigned long flags;
+
+       cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len);
+       fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
+
+       /* If any of the command structures end up being larger than
+        * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
+        * we will need to increase the size of the TFD entries */
+       BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
+              !(cmd->meta.flags & CMD_SIZE_HUGE));
+
+       if (iwl_is_rfkill(priv)) {
+               IWL_DEBUG_INFO("Not sending command - RF KILL");
+               return -EIO;
+       }
+
+       if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
+               IWL_ERROR("No space for Tx\n");
+               return -ENOSPC;
+       }
+
+       spin_lock_irqsave(&priv->hcmd_lock, flags);
+
+       tfd = &txq->bd[q->write_ptr];
+       memset(tfd, 0, sizeof(*tfd));
+
+       control_flags = (u32 *) tfd;
+
+       idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE);
+       out_cmd = &txq->cmd[idx];
+
+       out_cmd->hdr.cmd = cmd->id;
+       memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta));
+       memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len);
+
+       /* At this point, the out_cmd now has all of the incoming cmd
+        * information */
+
+       out_cmd->hdr.flags = 0;
+       out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
+                       INDEX_TO_SEQ(q->write_ptr));
+       if (out_cmd->meta.flags & CMD_SIZE_HUGE)
+               out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME);
+
+       phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx +
+                       offsetof(struct iwl_cmd, hdr);
+       iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size);
+
+       IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, "
+                    "%d bytes at %d[%d]:%d\n",
+                    get_cmd_string(out_cmd->hdr.cmd),
+                    out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),
+                    fix_size, q->write_ptr, idx, IWL_CMD_QUEUE_NUM);
+
+       txq->need_update = 1;
+
+       /* Set up entry in queue's byte count circular buffer */
+       priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, 0);
+
+       /* Increment and update queue's write index */
+       q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
+       ret = iwl_txq_update_write_ptr(priv, txq);
+
+       spin_unlock_irqrestore(&priv->hcmd_lock, flags);
+       return ret ? ret : idx;
+}
+
+int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
+{
+       struct iwl_tx_queue *txq = &priv->txq[txq_id];
+       struct iwl_queue *q = &txq->q;
+       struct iwl_tx_info *tx_info;
+       int nfreed = 0;
+
+       if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) {
+               IWL_ERROR("Read index for DMA queue txq id (%d), index %d, "
+                         "is out of range [0-%d] %d %d.\n", txq_id,
+                         index, q->n_bd, q->write_ptr, q->read_ptr);
+               return 0;
+       }
+
+       for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index;
+               q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
+
+               tx_info = &txq->txb[txq->q.read_ptr];
+               ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]);
+               tx_info->skb[0] = NULL;
+
+               if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl)
+                       priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq);
+
+               iwl_hw_txq_free_tfd(priv, txq);
+               nfreed++;
+       }
+       return nfreed;
+}
+EXPORT_SYMBOL(iwl_tx_queue_reclaim);
+
+
+/**
+ * iwl_hcmd_queue_reclaim - Reclaim TX command queue entries already Tx'd
+ *
+ * When FW advances 'R' index, all entries between old and new 'R' index
+ * need to be reclaimed. As result, some free space forms.  If there is
+ * enough free space (> low mark), wake the stack that feeds us.
+ */
+static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
+{
+       struct iwl_tx_queue *txq = &priv->txq[txq_id];
+       struct iwl_queue *q = &txq->q;
+       int nfreed = 0;
+
+       if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) {
+               IWL_ERROR("Read index for DMA queue txq id (%d), index %d, "
+                         "is out of range [0-%d] %d %d.\n", txq_id,
+                         index, q->n_bd, q->write_ptr, q->read_ptr);
+               return;
+       }
+
+       for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index;
+               q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
+
+               if (nfreed > 1) {
+                       IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index,
+                                       q->write_ptr, q->read_ptr);
+                       queue_work(priv->workqueue, &priv->restart);
+               }
+               nfreed++;
+       }
+}
+
+/**
+ * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
+ * @rxb: Rx buffer to reclaim
+ *
+ * If an Rx buffer has an async callback associated with it the callback
+ * will be executed.  The attached skb (if present) will only be freed
+ * if the callback returns 1
+ */
+void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+       u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+       int txq_id = SEQ_TO_QUEUE(sequence);
+       int index = SEQ_TO_INDEX(sequence);
+       int huge = sequence & SEQ_HUGE_FRAME;
+       int cmd_index;
+       struct iwl_cmd *cmd;
+
+       /* If a Tx command is being handled and it isn't in the actual
+        * command queue then there a command routing bug has been introduced
+        * in the queue management code. */
+       if (txq_id != IWL_CMD_QUEUE_NUM)
+               IWL_ERROR("Error wrong command queue %d command id 0x%X\n",
+                         txq_id, pkt->hdr.cmd);
+       BUG_ON(txq_id != IWL_CMD_QUEUE_NUM);
+
+       cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
+       cmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
+
+       /* Input error checking is done when commands are added to queue. */
+       if (cmd->meta.flags & CMD_WANT_SKB) {
+               cmd->meta.source->u.skb = rxb->skb;
+               rxb->skb = NULL;
+       } else if (cmd->meta.u.callback &&
+                  !cmd->meta.u.callback(priv, cmd, rxb->skb))
+               rxb->skb = NULL;
+
+       iwl_hcmd_queue_reclaim(priv, txq_id, index);
+
+       if (!(cmd->meta.flags & CMD_ASYNC)) {
+               clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+               wake_up_interruptible(&priv->wait_command_queue);
+       }
+}
+EXPORT_SYMBOL(iwl_tx_cmd_complete);
+
+
+#ifdef CONFIG_IWL4965_HT
+/*
+ * Find first available (lowest unused) Tx Queue, mark it "active".
+ * Called only when finding queue for aggregation.
+ * Should never return anything < 7, because they should already
+ * be in use as EDCA AC (0-3), Command (4), HCCA (5, 6).
+ */
+static int iwl_txq_ctx_activate_free(struct iwl_priv *priv)
+{
+       int txq_id;
+
+       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
+               if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk))
+                       return txq_id;
+       return -1;
+}
+
+int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
+{
+       int sta_id;
+       int tx_fifo;
+       int txq_id;
+       int ret;
+       unsigned long flags;
+       struct iwl_tid_data *tid_data;
+       DECLARE_MAC_BUF(mac);
+
+       if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
+               tx_fifo = default_tid_to_tx_fifo[tid];
+       else
+               return -EINVAL;
+
+       IWL_WARNING("%s on ra = %s tid = %d\n",
+                       __func__, print_mac(mac, ra), tid);
+
+       sta_id = iwl_find_station(priv, ra);
+       if (sta_id == IWL_INVALID_STATION)
+               return -ENXIO;
+
+       if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) {
+               IWL_ERROR("Start AGG when state is not IWL_AGG_OFF !\n");
+               return -ENXIO;
+       }
+
+       txq_id = iwl_txq_ctx_activate_free(priv);
+       if (txq_id == -1)
+               return -ENXIO;
+
+       spin_lock_irqsave(&priv->sta_lock, flags);
+       tid_data = &priv->stations[sta_id].tid[tid];
+       *ssn = SEQ_TO_SN(tid_data->seq_number);
+       tid_data->agg.txq_id = txq_id;
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+       ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo,
+                                                 sta_id, tid, *ssn);
+       if (ret)
+               return ret;
+
+       if (tid_data->tfds_in_queue == 0) {
+               printk(KERN_ERR "HW queue is empty\n");
+               tid_data->agg.state = IWL_AGG_ON;
+               ieee80211_start_tx_ba_cb_irqsafe(priv->hw, ra, tid);
+       } else {
+               IWL_DEBUG_HT("HW queue is NOT empty: %d packets in HW queue\n",
+                            tid_data->tfds_in_queue);
+               tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
+       }
+       return ret;
+}
+EXPORT_SYMBOL(iwl_tx_agg_start);
+
+int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid)
+{
+       int tx_fifo_id, txq_id, sta_id, ssn = -1;
+       struct iwl_tid_data *tid_data;
+       int ret, write_ptr, read_ptr;
+       unsigned long flags;
+       DECLARE_MAC_BUF(mac);
+
+       if (!ra) {
+               IWL_ERROR("ra = NULL\n");
+               return -EINVAL;
+       }
+
+       if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
+               tx_fifo_id = default_tid_to_tx_fifo[tid];
+       else
+               return -EINVAL;
+
+       sta_id = iwl_find_station(priv, ra);
+
+       if (sta_id == IWL_INVALID_STATION)
+               return -ENXIO;
+
+       if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON)
+               IWL_WARNING("Stopping AGG while state not IWL_AGG_ON\n");
+
+       tid_data = &priv->stations[sta_id].tid[tid];
+       ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4;
+       txq_id = tid_data->agg.txq_id;
+       write_ptr = priv->txq[txq_id].q.write_ptr;
+       read_ptr = priv->txq[txq_id].q.read_ptr;
+
+       /* The queue is not empty */
+       if (write_ptr != read_ptr) {
+               IWL_DEBUG_HT("Stopping a non empty AGG HW QUEUE\n");
+               priv->stations[sta_id].tid[tid].agg.state =
+                               IWL_EMPTYING_HW_QUEUE_DELBA;
+               return 0;
+       }
+
+       IWL_DEBUG_HT("HW queue is empty\n");
+       priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       ret = priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn,
+                                                  tx_fifo_id);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       if (ret)
+               return ret;
+
+       ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, ra, tid);
+
+       return 0;
+}
+EXPORT_SYMBOL(iwl_tx_agg_stop);
+
+int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id)
+{
+       struct iwl_queue *q = &priv->txq[txq_id].q;
+       u8 *addr = priv->stations[sta_id].sta.sta.addr;
+       struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid];
+
+       switch (priv->stations[sta_id].tid[tid].agg.state) {
+       case IWL_EMPTYING_HW_QUEUE_DELBA:
+               /* We are reclaiming the last packet of the */
+               /* aggregated HW queue */
+               if (txq_id  == tid_data->agg.txq_id &&
+                   q->read_ptr == q->write_ptr) {
+                       u16 ssn = SEQ_TO_SN(tid_data->seq_number);
+                       int tx_fifo = default_tid_to_tx_fifo[tid];
+                       IWL_DEBUG_HT("HW queue empty: continue DELBA flow\n");
+                       priv->cfg->ops->lib->txq_agg_disable(priv, txq_id,
+                                                            ssn, tx_fifo);
+                       tid_data->agg.state = IWL_AGG_OFF;
+                       ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, addr, tid);
+               }
+               break;
+       case IWL_EMPTYING_HW_QUEUE_ADDBA:
+               /* We are reclaiming the last packet of the queue */
+               if (tid_data->tfds_in_queue == 0) {
+                       IWL_DEBUG_HT("HW queue empty: continue ADDBA flow\n");
+                       tid_data->agg.state = IWL_AGG_ON;
+                       ieee80211_start_tx_ba_cb_irqsafe(priv->hw, addr, tid);
+               }
+               break;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(iwl_txq_check_empty);
+#endif /* CONFIG_IWL4965_HT */
+
+#ifdef CONFIG_IWLWIF_DEBUG
+#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+
+const char *iwl_get_tx_fail_reason(u32 status)
+{
+       switch (status & TX_STATUS_MSK) {
+       case TX_STATUS_SUCCESS:
+               return "SUCCESS";
+               TX_STATUS_ENTRY(SHORT_LIMIT);
+               TX_STATUS_ENTRY(LONG_LIMIT);
+               TX_STATUS_ENTRY(FIFO_UNDERRUN);
+               TX_STATUS_ENTRY(MGMNT_ABORT);
+               TX_STATUS_ENTRY(NEXT_FRAG);
+               TX_STATUS_ENTRY(LIFE_EXPIRE);
+               TX_STATUS_ENTRY(DEST_PS);
+               TX_STATUS_ENTRY(ABORTED);
+               TX_STATUS_ENTRY(BT_RETRY);
+               TX_STATUS_ENTRY(STA_INVALID);
+               TX_STATUS_ENTRY(FRAG_DROPPED);
+               TX_STATUS_ENTRY(TID_DISABLE);
+               TX_STATUS_ENTRY(FRAME_FLUSHED);
+               TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL);
+               TX_STATUS_ENTRY(TX_LOCKED);
+               TX_STATUS_ENTRY(NO_BEACON_ON_RADAR);
+       }
+
+       return "UNKNOWN";
+}
+EXPORT_SYMBOL(iwl_get_tx_fail_reason);
+#endif /* CONFIG_IWLWIFI_DEBUG */
index 13925b627e3b5569f5ebaf1399f121dea3d489d2..72279e07fe325d9b8d68e1b5c6482d646867366a 100644 (file)
@@ -102,16 +102,6 @@ MODULE_VERSION(DRV_VERSION);
 MODULE_AUTHOR(DRV_COPYRIGHT);
 MODULE_LICENSE("GPL");
 
-static __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr)
-{
-       u16 fc = le16_to_cpu(hdr->frame_control);
-       int hdr_len = ieee80211_get_hdrlen(fc);
-
-       if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA))
-               return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN);
-       return NULL;
-}
-
 static const struct ieee80211_supported_band *iwl3945_get_band(
                struct iwl3945_priv *priv, enum ieee80211_band band)
 {
@@ -2386,12 +2376,13 @@ static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode)
 }
 
 static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv,
-                                     struct ieee80211_tx_control *ctl,
+                                     struct ieee80211_tx_info *info,
                                      struct iwl3945_cmd *cmd,
                                      struct sk_buff *skb_frag,
                                      int last_frag)
 {
-       struct iwl3945_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo;
+       struct iwl3945_hw_key *keyinfo =
+           &priv->stations[info->control.hw_key->hw_key_idx].keyinfo;
 
        switch (keyinfo->alg) {
        case ALG_CCMP:
@@ -2414,7 +2405,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv,
 
        case ALG_WEP:
                cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP |
-                   (ctl->key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
+                   (info->control.hw_key->hw_key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
 
                if (keyinfo->keylen == 13)
                        cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128;
@@ -2422,7 +2413,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv,
                memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen);
 
                IWL_DEBUG_TX("Configuring packet for WEP encryption "
-                            "with key %d\n", ctl->key_idx);
+                            "with key %d\n", info->control.hw_key->hw_key_idx);
                break;
 
        default:
@@ -2436,16 +2427,15 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv,
  */
 static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv,
                                  struct iwl3945_cmd *cmd,
-                                 struct ieee80211_tx_control *ctrl,
+                                 struct ieee80211_tx_info *info,
                                  struct ieee80211_hdr *hdr,
                                  int is_unicast, u8 std_id)
 {
-       __le16 *qc;
        u16 fc = le16_to_cpu(hdr->frame_control);
        __le32 tx_flags = cmd->cmd.tx.tx_flags;
 
        cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
-       if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) {
+       if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
                tx_flags |= TX_CMD_FLG_ACK_MSK;
                if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)
                        tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
@@ -2461,17 +2451,18 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv,
        if (ieee80211_get_morefrag(hdr))
                tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
 
-       qc = ieee80211_get_qos_ctrl(hdr);
-       if (qc) {
-               cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf);
+       if (ieee80211_is_qos_data(fc)) {
+               u8 *qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc));
+               cmd->cmd.tx.tid_tspec = qc[0] & 0xf;
                tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
-       } else
+       } else {
                tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+       }
 
-       if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
+       if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
                tx_flags |= TX_CMD_FLG_RTS_MSK;
                tx_flags &= ~TX_CMD_FLG_CTS_MSK;
-       } else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
+       } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
                tx_flags &= ~TX_CMD_FLG_RTS_MSK;
                tx_flags |= TX_CMD_FLG_CTS_MSK;
        }
@@ -2555,25 +2546,27 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h
 /*
  * start REPLY_TX command process
  */
-static int iwl3945_tx_skb(struct iwl3945_priv *priv,
-                     struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct iwl3945_tfd_frame *tfd;
        u32 *control_flags;
-       int txq_id = ctl->queue;
+       int txq_id = skb_get_queue_mapping(skb);
        struct iwl3945_tx_queue *txq = NULL;
        struct iwl3945_queue *q = NULL;
        dma_addr_t phys_addr;
        dma_addr_t txcmd_phys;
        struct iwl3945_cmd *out_cmd = NULL;
-       u16 len, idx, len_org;
-       u8 id, hdr_len, unicast;
+       u16 len, idx, len_org, hdr_len;
+       u8 id;
+       u8 unicast;
        u8 sta_id;
+       u8 tid = 0;
        u16 seq_number = 0;
        u16 fc;
-       __le16 *qc;
        u8 wait_write_ptr = 0;
+       u8 *qc = NULL;
        unsigned long flags;
        int rc;
 
@@ -2588,7 +2581,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
                goto drop_unlock;
        }
 
-       if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) {
+       if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) == IWL_INVALID_RATE) {
                IWL_ERROR("ERROR: No TX rate available.\n");
                goto drop_unlock;
        }
@@ -2631,9 +2624,9 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
 
        IWL_DEBUG_RATE("station Id %d\n", sta_id);
 
-       qc = ieee80211_get_qos_ctrl(hdr);
-       if (qc) {
-               u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
+       if (ieee80211_is_qos_data(fc)) {
+               qc = ieee80211_get_qos_ctrl(hdr, hdr_len);
+               tid = qc[0] & 0xf;
                seq_number = priv->stations[sta_id].tid[tid].seq_number &
                                IEEE80211_SCTL_SEQ;
                hdr->seq_ctrl = cpu_to_le16(seq_number) |
@@ -2657,8 +2650,6 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
        /* Set up driver data for this TFD */
        memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl3945_tx_info));
        txq->txb[q->write_ptr].skb[0] = skb;
-       memcpy(&(txq->txb[q->write_ptr].status.control),
-              ctl, sizeof(struct ieee80211_tx_control));
 
        /* Init first empty entry in queue's array of Tx/cmd buffers */
        out_cmd = &txq->cmd[idx];
@@ -2707,8 +2698,8 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
         * first entry */
        iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
 
-       if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
-               iwl3945_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0);
+       if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT))
+               iwl3945_build_tx_cmd_hwcrypto(priv, info, out_cmd, skb, 0);
 
        /* Set up TFD's 2nd entry to point directly to remainder of skb,
         * if any (802.11 null frames have no payload). */
@@ -2733,10 +2724,10 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
        out_cmd->cmd.tx.len = cpu_to_le16(len);
 
        /* TODO need this for burst mode later on */
-       iwl3945_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id);
+       iwl3945_build_tx_cmd_basic(priv, out_cmd, info, hdr, unicast, sta_id);
 
        /* set is_hcca to 0; it probably will never be implemented */
-       iwl3945_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0);
+       iwl3945_hw_build_tx_cmd_rate(priv, out_cmd, info, hdr, sta_id, 0);
 
        out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
        out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
@@ -2744,7 +2735,6 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
        if (!ieee80211_get_morefrag(hdr)) {
                txq->need_update = 1;
                if (qc) {
-                       u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
                        priv->stations[sta_id].tid[tid].seq_number = seq_number;
                }
        } else {
@@ -2775,7 +2765,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv,
                        spin_unlock_irqrestore(&priv->lock, flags);
                }
 
-               ieee80211_stop_queue(priv->hw, ctl->queue);
+               ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb));
        }
 
        return 0;
@@ -3238,7 +3228,7 @@ static void iwl3945_bg_beacon_update(struct work_struct *work)
        struct sk_buff *beacon;
 
        /* Pull updated AP beacon from mac80211. will fail if not in AP mode */
-       beacon = ieee80211_beacon_get(priv->hw, priv->vif, NULL);
+       beacon = ieee80211_beacon_get(priv->hw, priv->vif);
 
        if (!beacon) {
                IWL_ERROR("update beacon failed\n");
@@ -4840,7 +4830,7 @@ static int iwl3945_init_channel_map(struct iwl3945_priv *priv)
                        ch_info->scan_power = eeprom_ch_info[ch].max_power_avg;
                        ch_info->min_power = 0;
 
-                       IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x"
+                       IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x"
                                       " %ddBm): Ad-Hoc %ssupported\n",
                                       ch_info->channel,
                                       is_channel_a_band(ch_info) ?
@@ -4850,7 +4840,6 @@ static int iwl3945_init_channel_map(struct iwl3945_priv *priv)
                                       CHECK_AND_PRINT(ACTIVE),
                                       CHECK_AND_PRINT(RADAR),
                                       CHECK_AND_PRINT(WIDE),
-                                      CHECK_AND_PRINT(NARROW),
                                       CHECK_AND_PRINT(DFS),
                                       eeprom_ch_info[ch].flags,
                                       eeprom_ch_info[ch].max_power_avg,
@@ -4986,9 +4975,6 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv,
                if (scan_ch->type & 1)
                        scan_ch->type |= (direct_mask << 1);
 
-               if (is_channel_narrow(ch_info))
-                       scan_ch->type |= (1 << 7);
-
                scan_ch->active_dwell = cpu_to_le16(active_dwell);
                scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
 
@@ -5835,7 +5821,7 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv)
        if (iwl3945_is_rfkill(priv))
                return;
 
-       ieee80211_start_queues(priv->hw);
+       ieee80211_wake_queues(priv->hw);
 
        priv->active_rate = priv->rates_mask;
        priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
@@ -5861,9 +5847,6 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv)
        /* Configure the adapter for unassociated operation */
        iwl3945_commit_rxon(priv);
 
-       /* At this point, the NIC is initialized and operational */
-       priv->notif_missed_beacons = 0;
-
        iwl3945_reg_txpower_periodic(priv);
 
        iwl3945_led_register(priv);
@@ -6147,6 +6130,24 @@ static void iwl3945_bg_rf_kill(struct work_struct *work)
        mutex_unlock(&priv->mutex);
 }
 
+static void iwl3945_bg_set_monitor(struct work_struct *work)
+{
+       struct iwl3945_priv *priv = container_of(work,
+                               struct iwl3945_priv, set_monitor);
+
+       IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n");
+
+       mutex_lock(&priv->mutex);
+
+       if (!iwl3945_is_ready(priv))
+               IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n");
+       else
+               if (iwl3945_set_mode(priv, IEEE80211_IF_TYPE_MNTR) != 0)
+                       IWL_ERROR("iwl3945_set_mode() failed\n");
+
+       mutex_unlock(&priv->mutex);
+}
+
 #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
 
 static void iwl3945_bg_scan_check(struct work_struct *data)
@@ -6675,8 +6676,7 @@ static void iwl3945_mac_stop(struct ieee80211_hw *hw)
        IWL_DEBUG_MAC80211("leave\n");
 }
 
-static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
-                     struct ieee80211_tx_control *ctl)
+static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct iwl3945_priv *priv = hw->priv;
 
@@ -6688,9 +6688,9 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
        }
 
        IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
-                    ctl->tx_rate->bitrate);
+                    ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
 
-       if (iwl3945_tx_skb(priv, skb, ctl))
+       if (iwl3945_tx_skb(priv, skb))
                dev_kfree_skb_any(skb);
 
        IWL_DEBUG_MAC80211("leave\n");
@@ -6999,7 +6999,22 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw,
         * XXX: dummy
         * see also iwl3945_connection_init_rx_config
         */
-       *total_flags = 0;
+       struct iwl3945_priv *priv = hw->priv;
+       int new_flags = 0;
+       if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) {
+               if (*total_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) {
+                       IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n",
+                                          IEEE80211_IF_TYPE_MNTR,
+                                          changed_flags, *total_flags);
+                       /* queue work 'cuz mac80211 is holding a lock which
+                        * prevents us from issuing (synchronous) f/w cmds */
+                       queue_work(priv->workqueue, &priv->set_monitor);
+                       new_flags &= FIF_PROMISC_IN_BSS |
+                                    FIF_OTHER_BSS |
+                                    FIF_ALLMULTI;
+               }
+       }
+       *total_flags = new_flags;
 }
 
 static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw,
@@ -7057,9 +7072,10 @@ static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
                rc = -EAGAIN;
                goto out_unlock;
        }
-       /* if we just finished scan ask for delay */
-       if (priv->last_scan_jiffies && time_after(priv->last_scan_jiffies +
-                               IWL_DELAY_NEXT_SCAN, jiffies)) {
+       /* if we just finished scan ask for delay for a broadcast scan */
+       if ((len == 0) && priv->last_scan_jiffies &&
+           time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN,
+                      jiffies)) {
                rc = -EAGAIN;
                goto out_unlock;
        }
@@ -7146,7 +7162,7 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        return rc;
 }
 
-static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, int queue,
+static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
                           const struct ieee80211_tx_queue_params *params)
 {
        struct iwl3945_priv *priv = hw->priv;
@@ -7220,9 +7236,9 @@ static int iwl3945_mac_get_tx_stats(struct ieee80211_hw *hw,
                q = &txq->q;
                avail = iwl3945_queue_space(q);
 
-               stats->data[i].len = q->n_window - avail;
-               stats->data[i].limit = q->n_window - q->high_mark;
-               stats->data[i].count = q->n_window;
+               stats[i].len = q->n_window - avail;
+               stats[i].limit = q->n_window - q->high_mark;
+               stats[i].count = q->n_window;
 
        }
        spin_unlock_irqrestore(&priv->lock, flags);
@@ -7311,8 +7327,7 @@ static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw)
 
 }
 
-static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
-                                struct ieee80211_tx_control *control)
+static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct iwl3945_priv *priv = hw->priv;
        unsigned long flags;
@@ -7875,6 +7890,7 @@ static void iwl3945_setup_deferred_work(struct iwl3945_priv *priv)
        INIT_WORK(&priv->abort_scan, iwl3945_bg_abort_scan);
        INIT_WORK(&priv->rf_kill, iwl3945_bg_rf_kill);
        INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update);
+       INIT_WORK(&priv->set_monitor, iwl3945_bg_set_monitor);
        INIT_DELAYED_WORK(&priv->post_associate, iwl3945_bg_post_associate);
        INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start);
        INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start);
@@ -7997,17 +8013,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 
        priv->ibss_beacon = NULL;
 
-       /* Tell mac80211 and its clients (e.g. Wireless Extensions)
-        *   the range of signal quality values that we'll provide.
-        * Negative values for level/noise indicate that we'll provide dBm.
-        * For WE, at least, non-0 values here *enable* display of values
-        *   in app (iwconfig). */
-       hw->max_rssi = -20;     /* signal level, negative indicates dBm */
-       hw->max_noise = -20;    /* noise level, negative indicates dBm */
-       hw->max_signal = 100;   /* link quality indication (%) */
-
-       /* Tell mac80211 our Tx characteristics */
-       hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
+       /* Tell mac80211 our characteristics */
+       hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
+                   IEEE80211_HW_SIGNAL_DBM |
+                   IEEE80211_HW_NOISE_DBM;
 
        /* 4 EDCA QOS priorities */
        hw->queues = 4;
@@ -8248,7 +8257,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
 
        iwl3945_free_channel_map(priv);
        iwl3945_free_geos(priv);
-
+       kfree(priv->scan);
        if (priv->ibss_beacon)
                dev_kfree_skb(priv->ibss_beacon);
 
index 883b42f7e9989dff95e085cf6afb6577eb9f7f1a..c71daec8c746606c7a31c9f7748691dc5031937f 100644 (file)
 #include <asm/div64.h>
 
 #include "iwl-eeprom.h"
-#include "iwl-4965.h"
+#include "iwl-dev.h"
 #include "iwl-core.h"
 #include "iwl-io.h"
 #include "iwl-helpers.h"
 #include "iwl-sta.h"
+#include "iwl-calib.h"
 
-static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv,
-                                 struct iwl4965_tx_queue *txq);
 
 /******************************************************************************
  *
@@ -88,22 +87,6 @@ MODULE_VERSION(DRV_VERSION);
 MODULE_AUTHOR(DRV_COPYRIGHT);
 MODULE_LICENSE("GPL");
 
-__le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr)
-{
-       u16 fc = le16_to_cpu(hdr->frame_control);
-       int hdr_len = ieee80211_get_hdrlen(fc);
-
-       if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA))
-               return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN);
-       return NULL;
-}
-
-static const struct ieee80211_supported_band *iwl4965_get_hw_mode(
-               struct iwl_priv *priv, enum ieee80211_band band)
-{
-       return priv->hw->wiphy->bands[band];
-}
-
 static int iwl4965_is_empty_essid(const char *essid, int essid_len)
 {
        /* Single white space is for Linksys APs */
@@ -144,236 +127,6 @@ static const char *iwl4965_escape_essid(const char *essid, u8 essid_len)
        return escaped;
 }
 
-/*************** DMA-QUEUE-GENERAL-FUNCTIONS  *****
- * DMA services
- *
- * Theory of operation
- *
- * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer
- * of buffer descriptors, each of which points to one or more data buffers for
- * the device to read from or fill.  Driver and device exchange status of each
- * queue via "read" and "write" pointers.  Driver keeps minimum of 2 empty
- * entries in each circular buffer, to protect against confusing empty and full
- * queue states.
- *
- * The device reads or writes the data in the queues via the device's several
- * DMA/FIFO channels.  Each queue is mapped to a single DMA channel.
- *
- * For Tx queue, there are low mark and high mark limits. If, after queuing
- * the packet for Tx, free space become < low mark, Tx queue stopped. When
- * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
- * Tx queue resumed.
- *
- * The 4965 operates with up to 17 queues:  One receive queue, one transmit
- * queue (#4) for sending commands to the device firmware, and 15 other
- * Tx queues that may be mapped to prioritized Tx DMA/FIFO channels.
- *
- * See more detailed info in iwl-4965-hw.h.
- ***************************************************/
-
-int iwl4965_queue_space(const struct iwl4965_queue *q)
-{
-       int s = q->read_ptr - q->write_ptr;
-
-       if (q->read_ptr > q->write_ptr)
-               s -= q->n_bd;
-
-       if (s <= 0)
-               s += q->n_window;
-       /* keep some reserve to not confuse empty and full situations */
-       s -= 2;
-       if (s < 0)
-               s = 0;
-       return s;
-}
-
-
-static inline int x2_queue_used(const struct iwl4965_queue *q, int i)
-{
-       return q->write_ptr > q->read_ptr ?
-               (i >= q->read_ptr && i < q->write_ptr) :
-               !(i < q->read_ptr && i >= q->write_ptr);
-}
-
-static inline u8 get_cmd_index(struct iwl4965_queue *q, u32 index, int is_huge)
-{
-       /* This is for scan command, the big buffer at end of command array */
-       if (is_huge)
-               return q->n_window;     /* must be power of 2 */
-
-       /* Otherwise, use normal size buffers */
-       return index & (q->n_window - 1);
-}
-
-/**
- * iwl4965_queue_init - Initialize queue's high/low-water and read/write indexes
- */
-static int iwl4965_queue_init(struct iwl_priv *priv, struct iwl4965_queue *q,
-                         int count, int slots_num, u32 id)
-{
-       q->n_bd = count;
-       q->n_window = slots_num;
-       q->id = id;
-
-       /* count must be power-of-two size, otherwise iwl_queue_inc_wrap
-        * and iwl_queue_dec_wrap are broken. */
-       BUG_ON(!is_power_of_2(count));
-
-       /* slots_num must be power-of-two size, otherwise
-        * get_cmd_index is broken. */
-       BUG_ON(!is_power_of_2(slots_num));
-
-       q->low_mark = q->n_window / 4;
-       if (q->low_mark < 4)
-               q->low_mark = 4;
-
-       q->high_mark = q->n_window / 8;
-       if (q->high_mark < 2)
-               q->high_mark = 2;
-
-       q->write_ptr = q->read_ptr = 0;
-
-       return 0;
-}
-
-/**
- * iwl4965_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue
- */
-static int iwl4965_tx_queue_alloc(struct iwl_priv *priv,
-                             struct iwl4965_tx_queue *txq, u32 id)
-{
-       struct pci_dev *dev = priv->pci_dev;
-
-       /* Driver private data, only for Tx (not command) queues,
-        * not shared with device. */
-       if (id != IWL_CMD_QUEUE_NUM) {
-               txq->txb = kmalloc(sizeof(txq->txb[0]) *
-                                  TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
-               if (!txq->txb) {
-                       IWL_ERROR("kmalloc for auxiliary BD "
-                                 "structures failed\n");
-                       goto error;
-               }
-       } else
-               txq->txb = NULL;
-
-       /* Circular buffer of transmit frame descriptors (TFDs),
-        * shared with device */
-       txq->bd = pci_alloc_consistent(dev,
-                       sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX,
-                       &txq->q.dma_addr);
-
-       if (!txq->bd) {
-               IWL_ERROR("pci_alloc_consistent(%zd) failed\n",
-                         sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX);
-               goto error;
-       }
-       txq->q.id = id;
-
-       return 0;
-
- error:
-       if (txq->txb) {
-               kfree(txq->txb);
-               txq->txb = NULL;
-       }
-
-       return -ENOMEM;
-}
-
-/**
- * iwl4965_tx_queue_init - Allocate and initialize one tx/cmd queue
- */
-int iwl4965_tx_queue_init(struct iwl_priv *priv,
-                     struct iwl4965_tx_queue *txq, int slots_num, u32 txq_id)
-{
-       struct pci_dev *dev = priv->pci_dev;
-       int len;
-       int rc = 0;
-
-       /*
-        * Alloc buffer array for commands (Tx or other types of commands).
-        * For the command queue (#4), allocate command space + one big
-        * command for scan, since scan command is very huge; the system will
-        * not have two scans at the same time, so only one is needed.
-        * For normal Tx queues (all other queues), no super-size command
-        * space is needed.
-        */
-       len = sizeof(struct iwl_cmd) * slots_num;
-       if (txq_id == IWL_CMD_QUEUE_NUM)
-               len +=  IWL_MAX_SCAN_SIZE;
-       txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd);
-       if (!txq->cmd)
-               return -ENOMEM;
-
-       /* Alloc driver data array and TFD circular buffer */
-       rc = iwl4965_tx_queue_alloc(priv, txq, txq_id);
-       if (rc) {
-               pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
-
-               return -ENOMEM;
-       }
-       txq->need_update = 0;
-
-       /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
-        * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
-       BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
-
-       /* Initialize queue's high/low-water marks, and head/tail indexes */
-       iwl4965_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
-
-       /* Tell device where to find queue */
-       iwl4965_hw_tx_queue_init(priv, txq);
-
-       return 0;
-}
-
-/**
- * iwl4965_tx_queue_free - Deallocate DMA queue.
- * @txq: Transmit queue to deallocate.
- *
- * Empty queue by removing and destroying all BD's.
- * Free all buffers.
- * 0-fill, but do not free "txq" descriptor structure.
- */
-void iwl4965_tx_queue_free(struct iwl_priv *priv, struct iwl4965_tx_queue *txq)
-{
-       struct iwl4965_queue *q = &txq->q;
-       struct pci_dev *dev = priv->pci_dev;
-       int len;
-
-       if (q->n_bd == 0)
-               return;
-
-       /* first, empty all BD's */
-       for (; q->write_ptr != q->read_ptr;
-            q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd))
-               iwl4965_hw_txq_free_tfd(priv, txq);
-
-       len = sizeof(struct iwl_cmd) * q->n_window;
-       if (q->id == IWL_CMD_QUEUE_NUM)
-               len += IWL_MAX_SCAN_SIZE;
-
-       /* De-alloc array of command/tx buffers */
-       pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
-
-       /* De-alloc circular buffer of TFDs */
-       if (txq->q.n_bd)
-               pci_free_consistent(dev, sizeof(struct iwl4965_tfd_frame) *
-                                   txq->q.n_bd, txq->bd, txq->q.dma_addr);
-
-       /* De-alloc array of per-TFD driver data */
-       if (txq->txb) {
-               kfree(txq->txb);
-               txq->txb = NULL;
-       }
-
-       /* 0-fill queue descriptor structure */
-       memset(txq, 0, sizeof(*txq));
-}
-
-const u8 iwl4965_broadcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
-
 /*************** STATION TABLE MANAGEMENT ****
  * mac80211 should be examined to determine if sta_info is duplicating
  * the functionality provided here
@@ -381,213 +134,11 @@ const u8 iwl4965_broadcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
 
 /**************************************************************/
 
-#if 0 /* temporary disable till we add real remove station */
-/**
- * iwl4965_remove_station - Remove driver's knowledge of station.
- *
- * NOTE:  This does not remove station from device's station table.
- */
-static u8 iwl4965_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[i].used &&
-                           !compare_ether_addr(priv->stations[i].sta.sta.addr,
-                                               addr)) {
-                               index = i;
-                               break;
-                       }
-
-       if (unlikely(index == IWL_INVALID_STATION))
-               goto out;
-
-       if (priv->stations[index].used) {
-               priv->stations[index].used = 0;
-               priv->num_stations--;
-       }
-
-       BUG_ON(priv->num_stations < 0);
-
-out:
-       spin_unlock_irqrestore(&priv->sta_lock, flags);
-       return 0;
-}
-#endif
-
-/**
- * iwl4965_add_station_flags - Add station to tables in driver and device
- */
-u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr,
-                               int is_ap, u8 flags, void *ht_data)
-{
-       int i;
-       int index = IWL_INVALID_STATION;
-       struct iwl4965_station_entry *station;
-       unsigned long flags_spin;
-       DECLARE_MAC_BUF(mac);
-
-       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[i].sta.sta.addr,
-                                               addr)) {
-                               index = i;
-                               break;
-                       }
-
-                       if (!priv->stations[i].used &&
-                           index == IWL_INVALID_STATION)
-                               index = i;
-               }
-
-
-       /* These two conditions have the same outcome, but keep them separate
-         since they have different meanings */
-       if (unlikely(index == IWL_INVALID_STATION)) {
-               spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
-               return index;
-       }
-
-       if (priv->stations[index].used &&
-           !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) {
-               spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
-               return index;
-       }
-
-
-       IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr));
-       station = &priv->stations[index];
-       station->used = 1;
-       priv->num_stations++;
-
-       /* Set up the REPLY_ADD_STA command to send to device */
-       memset(&station->sta, 0, sizeof(struct iwl4965_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;
-
-#ifdef CONFIG_IWL4965_HT
-       /* BCAST station and IBSS stations do not work in HT mode */
-       if (index != priv->hw_params.bcast_sta_id &&
-           priv->iw_mode != IEEE80211_IF_TYPE_IBSS)
-               iwl4965_set_ht_add_station(priv, index,
-                                (struct ieee80211_ht_info *) ht_data);
-#endif /*CONFIG_IWL4965_HT*/
-
-       spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
-
-       /* Add station to device's station table */
-       iwl4965_send_add_station(priv, &station->sta, flags);
-       return index;
-
-}
-
-
-
-/*************** HOST COMMAND QUEUE FUNCTIONS   *****/
-
-/**
- * iwl4965_enqueue_hcmd - enqueue a uCode command
- * @priv: device private data point
- * @cmd: a point to the ucode command structure
- *
- * The function returns < 0 values to indicate the operation is
- * failed. On success, it turns the index (> 0) of command in the
- * command queue.
- */
-int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
-{
-       struct iwl4965_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
-       struct iwl4965_queue *q = &txq->q;
-       struct iwl4965_tfd_frame *tfd;
-       u32 *control_flags;
-       struct iwl_cmd *out_cmd;
-       u32 idx;
-       u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
-       dma_addr_t phys_addr;
-       int ret;
-       unsigned long flags;
-
-       /* If any of the command structures end up being larger than
-        * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
-        * we will need to increase the size of the TFD entries */
-       BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
-              !(cmd->meta.flags & CMD_SIZE_HUGE));
-
-       if (iwl_is_rfkill(priv)) {
-               IWL_DEBUG_INFO("Not sending command - RF KILL");
-               return -EIO;
-       }
-
-       if (iwl4965_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
-               IWL_ERROR("No space for Tx\n");
-               return -ENOSPC;
-       }
-
-       spin_lock_irqsave(&priv->hcmd_lock, flags);
-
-       tfd = &txq->bd[q->write_ptr];
-       memset(tfd, 0, sizeof(*tfd));
-
-       control_flags = (u32 *) tfd;
-
-       idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE);
-       out_cmd = &txq->cmd[idx];
 
-       out_cmd->hdr.cmd = cmd->id;
-       memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta));
-       memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len);
-
-       /* At this point, the out_cmd now has all of the incoming cmd
-        * information */
-
-       out_cmd->hdr.flags = 0;
-       out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
-                       INDEX_TO_SEQ(q->write_ptr));
-       if (out_cmd->meta.flags & CMD_SIZE_HUGE)
-               out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME);
-
-       phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx +
-                       offsetof(struct iwl_cmd, hdr);
-       iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size);
-
-       IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, "
-                    "%d bytes at %d[%d]:%d\n",
-                    get_cmd_string(out_cmd->hdr.cmd),
-                    out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),
-                    fix_size, q->write_ptr, idx, IWL_CMD_QUEUE_NUM);
-
-       txq->need_update = 1;
-
-       /* Set up entry in queue's byte count circular buffer */
-       priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, 0);
-
-       /* Increment and update queue's write index */
-       q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
-       ret = iwl4965_tx_queue_update_write_ptr(priv, txq);
-
-       spin_unlock_irqrestore(&priv->hcmd_lock, flags);
-       return ret ? ret : idx;
-}
 
 static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
 {
-       struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon;
+       struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
 
        if (hw_decrypt)
                rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
@@ -596,38 +147,6 @@ static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
 
 }
 
-/**
- * iwl4965_rxon_add_station - add station into station table.
- *
- * there is only one AP station with id= IWL_AP_ID
- * NOTE: mutex must be held before calling this fnction
- */
-static int iwl4965_rxon_add_station(struct iwl_priv *priv,
-                               const u8 *addr, int is_ap)
-{
-       u8 sta_id;
-
-       /* Add station to device's station table */
-#ifdef CONFIG_IWL4965_HT
-       struct ieee80211_conf *conf = &priv->hw->conf;
-       struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf;
-
-       if ((is_ap) &&
-           (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) &&
-           (priv->iw_mode == IEEE80211_IF_TYPE_STA))
-               sta_id = iwl4965_add_station_flags(priv, addr, is_ap,
-                                                  0, cur_ht_config);
-       else
-#endif /* CONFIG_IWL4965_HT */
-               sta_id = iwl4965_add_station_flags(priv, addr, is_ap,
-                                                  0, NULL);
-
-       /* Set up default rate scaling table in device's station table */
-       iwl4965_add_station(priv, addr, is_ap);
-
-       return sta_id;
-}
-
 /**
  * iwl4965_check_rxon_cmd - validate RXON structure is valid
  *
@@ -635,7 +154,7 @@ static int iwl4965_rxon_add_station(struct iwl_priv *priv,
  * be #ifdef'd out once the driver is stable and folks aren't actively
  * making changes
  */
-static int iwl4965_check_rxon_cmd(struct iwl4965_rxon_cmd *rxon)
+static int iwl4965_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
 {
        int error = 0;
        int counter = 1;
@@ -760,7 +279,7 @@ static int iwl4965_full_rxon_required(struct iwl_priv *priv)
 static int iwl4965_commit_rxon(struct iwl_priv *priv)
 {
        /* cast away the const for active_rxon in this function */
-       struct iwl4965_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
+       struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
        DECLARE_MAC_BUF(mac);
        int rc = 0;
 
@@ -795,14 +314,6 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
        /* station table will be cleared */
        priv->assoc_station_added = 0;
 
-#ifdef CONFIG_IWL4965_SENSITIVITY
-       priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT;
-       if (!priv->error_recovering)
-               priv->start_calib = 0;
-
-       iwl4965_init_sensitivity(priv, CMD_ASYNC, 1);
-#endif /* CONFIG_IWL4965_SENSITIVITY */
-
        /* If we are currently associated and the new config requires
         * an RXON_ASSOC and the new config wants the associated mask enabled,
         * we must clear the associated from the active configuration
@@ -813,7 +324,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
                active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 
                rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
-                                     sizeof(struct iwl4965_rxon_cmd),
+                                     sizeof(struct iwl_rxon_cmd),
                                      &priv->active_rxon);
 
                /* If the mask clearing failed then we set
@@ -835,24 +346,22 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
                       le16_to_cpu(priv->staging_rxon.channel),
                       print_mac(mac, priv->staging_rxon.bssid_addr));
 
-       iwl4965_set_rxon_hwcrypto(priv, !priv->cfg->mod_params->sw_crypto);
+       iwl4965_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto);
        /* Apply the new configuration */
        rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
-                             sizeof(struct iwl4965_rxon_cmd), &priv->staging_rxon);
+                             sizeof(struct iwl_rxon_cmd), &priv->staging_rxon);
        if (rc) {
                IWL_ERROR("Error setting new configuration (%d).\n", rc);
                return rc;
        }
 
+       iwl_remove_station(priv, iwl_bcast_addr, 0);
        iwlcore_clear_stations_table(priv);
 
-#ifdef CONFIG_IWL4965_SENSITIVITY
        if (!priv->error_recovering)
                priv->start_calib = 0;
 
-       priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT;
-       iwl4965_init_sensitivity(priv, CMD_ASYNC, 1);
-#endif /* CONFIG_IWL4965_SENSITIVITY */
+       iwl_init_sensitivity(priv);
 
        memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
 
@@ -865,7 +374,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
        }
 
        /* Add the broadcast address so we can send broadcast frames */
-       if (iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0) ==
+       if (iwl_rxon_add_station(priv, iwl_bcast_addr, 0) ==
            IWL_INVALID_STATION) {
                IWL_ERROR("Error adding BROADCAST address for transmit.\n");
                return -EIO;
@@ -875,7 +384,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
         * add the IWL_AP_ID to the station rate table */
        if (iwl_is_associated(priv) &&
            (priv->iw_mode == IEEE80211_IF_TYPE_STA)) {
-               if (iwl4965_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1)
+               if (iwl_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1)
                    == IWL_INVALID_STATION) {
                        IWL_ERROR("Error adding AP address for transmit.\n");
                        return -EIO;
@@ -889,6 +398,13 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
        return 0;
 }
 
+void iwl4965_update_chain_flags(struct iwl_priv *priv)
+{
+
+       iwl_set_rxon_chain(priv);
+       iwl4965_commit_rxon(priv);
+}
+
 static int iwl4965_send_bt_config(struct iwl_priv *priv)
 {
        struct iwl4965_bt_cmd bt_cmd = {
@@ -905,8 +421,8 @@ static int iwl4965_send_bt_config(struct iwl_priv *priv)
 
 static int iwl4965_send_scan_abort(struct iwl_priv *priv)
 {
-       int rc = 0;
-       struct iwl4965_rx_packet *res;
+       int ret = 0;
+       struct iwl_rx_packet *res;
        struct iwl_host_cmd cmd = {
                .id = REPLY_SCAN_ABORT_CMD,
                .meta.flags = CMD_WANT_SKB,
@@ -920,13 +436,13 @@ static int iwl4965_send_scan_abort(struct iwl_priv *priv)
                return 0;
        }
 
-       rc = iwl_send_cmd_sync(priv, &cmd);
-       if (rc) {
+       ret = iwl_send_cmd_sync(priv, &cmd);
+       if (ret) {
                clear_bit(STATUS_SCAN_ABORTING, &priv->status);
-               return rc;
+               return ret;
        }
 
-       res = (struct iwl4965_rx_packet *)cmd.meta.u.skb->data;
+       res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
        if (res->u.status != CAN_ABORT_STATUS) {
                /* The scan abort will return 1 for success or
                 * 2 for "failure".  A failure condition can be
@@ -941,14 +457,7 @@ static int iwl4965_send_scan_abort(struct iwl_priv *priv)
 
        dev_kfree_skb_any(cmd.meta.u.skb);
 
-       return rc;
-}
-
-static int iwl4965_card_state_sync_callback(struct iwl_priv *priv,
-                                       struct iwl_cmd *cmd,
-                                       struct sk_buff *skb)
-{
-       return 1;
+       return ret;
 }
 
 /*
@@ -970,88 +479,10 @@ static int iwl4965_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_fla
                .meta.flags = meta_flag,
        };
 
-       if (meta_flag & CMD_ASYNC)
-               cmd.meta.u.callback = iwl4965_card_state_sync_callback;
-
        return iwl_send_cmd(priv, &cmd);
 }
 
-static int iwl4965_add_sta_sync_callback(struct iwl_priv *priv,
-                                    struct iwl_cmd *cmd, struct sk_buff *skb)
-{
-       struct iwl4965_rx_packet *res = NULL;
-
-       if (!skb) {
-               IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n");
-               return 1;
-       }
-
-       res = (struct iwl4965_rx_packet *)skb->data;
-       if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
-               IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
-                         res->hdr.flags);
-               return 1;
-       }
-
-       switch (res->u.add_sta.status) {
-       case ADD_STA_SUCCESS_MSK:
-               break;
-       default:
-               break;
-       }
-
-       /* We didn't cache the SKB; let the caller free it */
-       return 1;
-}
-
-int iwl4965_send_add_station(struct iwl_priv *priv,
-                        struct iwl4965_addsta_cmd *sta, u8 flags)
-{
-       struct iwl4965_rx_packet *res = NULL;
-       int rc = 0;
-       struct iwl_host_cmd cmd = {
-               .id = REPLY_ADD_STA,
-               .len = sizeof(struct iwl4965_addsta_cmd),
-               .meta.flags = flags,
-               .data = sta,
-       };
-
-       if (flags & CMD_ASYNC)
-               cmd.meta.u.callback = iwl4965_add_sta_sync_callback;
-       else
-               cmd.meta.flags |= CMD_WANT_SKB;
-
-       rc = iwl_send_cmd(priv, &cmd);
-
-       if (rc || (flags & CMD_ASYNC))
-               return rc;
-
-       res = (struct iwl4965_rx_packet *)cmd.meta.u.skb->data;
-       if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
-               IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
-                         res->hdr.flags);
-               rc = -EIO;
-       }
-
-       if (rc == 0) {
-               switch (res->u.add_sta.status) {
-               case ADD_STA_SUCCESS_MSK:
-                       IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n");
-                       break;
-               default:
-                       rc = -EIO;
-                       IWL_WARNING("REPLY_ADD_STA failed\n");
-                       break;
-               }
-       }
-
-       priv->alloc_rxb_skb--;
-       dev_kfree_skb_any(cmd.meta.u.skb);
-
-       return rc;
-}
-
-static void iwl4965_clear_free_frames(struct iwl_priv *priv)
+static void iwl_clear_free_frames(struct iwl_priv *priv)
 {
        struct list_head *element;
 
@@ -1061,7 +492,7 @@ static void iwl4965_clear_free_frames(struct iwl_priv *priv)
        while (!list_empty(&priv->free_frames)) {
                element = priv->free_frames.next;
                list_del(element);
-               kfree(list_entry(element, struct iwl4965_frame, list));
+               kfree(list_entry(element, struct iwl_frame, list));
                priv->frames_count--;
        }
 
@@ -1072,9 +503,9 @@ static void iwl4965_clear_free_frames(struct iwl_priv *priv)
        }
 }
 
-static struct iwl4965_frame *iwl4965_get_free_frame(struct iwl_priv *priv)
+static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv)
 {
-       struct iwl4965_frame *frame;
+       struct iwl_frame *frame;
        struct list_head *element;
        if (list_empty(&priv->free_frames)) {
                frame = kzalloc(sizeof(*frame), GFP_KERNEL);
@@ -1089,10 +520,10 @@ static struct iwl4965_frame *iwl4965_get_free_frame(struct iwl_priv *priv)
 
        element = priv->free_frames.next;
        list_del(element);
-       return list_entry(element, struct iwl4965_frame, list);
+       return list_entry(element, struct iwl_frame, list);
 }
 
-static void iwl4965_free_frame(struct iwl_priv *priv, struct iwl4965_frame *frame)
+static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame)
 {
        memset(frame, 0, sizeof(*frame));
        list_add(&frame->list, &priv->free_frames);
@@ -1116,27 +547,39 @@ unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv,
        return priv->ibss_beacon->len;
 }
 
-static u8 iwl4965_rate_get_lowest_plcp(int rate_mask)
+static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv)
 {
-       u8 i;
+       int i;
+       int rate_mask;
+
+       /* Set rate mask*/
+       if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)
+               rate_mask = priv->active_rate_basic & 0xF;
+       else
+               rate_mask = priv->active_rate_basic & 0xFF0;
 
+       /* Find lowest valid rate */
        for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
-            i = iwl4965_rates[i].next_ieee) {
+                                       i = iwl_rates[i].next_ieee) {
                if (rate_mask & (1 << i))
-                       return iwl4965_rates[i].plcp;
+                       return iwl_rates[i].plcp;
        }
 
-       return IWL_RATE_INVALID;
+       /* No valid rate was found. Assign the lowest one */
+       if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)
+               return IWL_RATE_1M_PLCP;
+       else
+               return IWL_RATE_6M_PLCP;
 }
 
 static int iwl4965_send_beacon_cmd(struct iwl_priv *priv)
 {
-       struct iwl4965_frame *frame;
+       struct iwl_frame *frame;
        unsigned int frame_size;
        int rc;
        u8 rate;
 
-       frame = iwl4965_get_free_frame(priv);
+       frame = iwl_get_free_frame(priv);
 
        if (!frame) {
                IWL_ERROR("Could not obtain free frame buffer for beacon "
@@ -1144,23 +587,14 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv)
                return -ENOMEM;
        }
 
-       if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) {
-               rate = iwl4965_rate_get_lowest_plcp(priv->active_rate_basic &
-                                               0xFF0);
-               if (rate == IWL_INVALID_RATE)
-                       rate = IWL_RATE_6M_PLCP;
-       } else {
-               rate = iwl4965_rate_get_lowest_plcp(priv->active_rate_basic & 0xF);
-               if (rate == IWL_INVALID_RATE)
-                       rate = IWL_RATE_1M_PLCP;
-       }
+       rate = iwl4965_rate_get_lowest_plcp(priv);
 
        frame_size = iwl4965_hw_get_beacon_cmd(priv, frame, rate);
 
        rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
                              &frame->u.cmd[0]);
 
-       iwl4965_free_frame(priv, frame);
+       iwl_free_frame(priv, frame);
 
        return rc;
 }
@@ -1171,15 +605,6 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv)
  *
  ******************************************************************************/
 
-static void iwl4965_unset_hw_params(struct iwl_priv *priv)
-{
-       if (priv->shared_virt)
-               pci_free_consistent(priv->pci_dev,
-                                   sizeof(struct iwl4965_shared),
-                                   priv->shared_virt,
-                                   priv->shared_phys);
-}
-
 /**
  * iwl4965_supported_rate_to_ie - fill in the supported rate in IE field
  *
@@ -1196,7 +621,7 @@ static u16 iwl4965_supported_rate_to_ie(u8 *ie, u16 supported_rate,
        for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) {
                if (bit & supported_rate) {
                        ret_rates |= bit;
-                       rates[*cnt] = iwl4965_rates[i].ieee |
+                       rates[*cnt] = iwl_rates[i].ieee |
                                ((bit & basic_rate) ? 0x80 : 0x00);
                        (*cnt)++;
                        (*left)--;
@@ -1209,9 +634,94 @@ static u16 iwl4965_supported_rate_to_ie(u8 *ie, u16 supported_rate,
        return ret_rates;
 }
 
-/**
- * iwl4965_fill_probe_req - fill in all required fields and IE for probe request
- */
+#ifdef CONFIG_IWL4965_HT
+static void iwl4965_ht_conf(struct iwl_priv *priv,
+                           struct ieee80211_bss_conf *bss_conf)
+{
+       struct ieee80211_ht_info *ht_conf = bss_conf->ht_conf;
+       struct ieee80211_ht_bss_info *ht_bss_conf = bss_conf->ht_bss_conf;
+       struct iwl_ht_info *iwl_conf = &priv->current_ht_config;
+
+       IWL_DEBUG_MAC80211("enter: \n");
+
+       iwl_conf->is_ht = bss_conf->assoc_ht;
+
+       if (!iwl_conf->is_ht)
+               return;
+
+       priv->ps_mode = (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2);
+
+       if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20)
+               iwl_conf->sgf |= HT_SHORT_GI_20MHZ;
+       if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40)
+               iwl_conf->sgf |= HT_SHORT_GI_40MHZ;
+
+       iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD);
+       iwl_conf->max_amsdu_size =
+               !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU);
+
+       iwl_conf->supported_chan_width =
+               !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH);
+       iwl_conf->extension_chan_offset =
+               ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET;
+       /* If no above or below channel supplied disable FAT channel */
+       if (iwl_conf->extension_chan_offset != IWL_EXT_CHANNEL_OFFSET_ABOVE &&
+           iwl_conf->extension_chan_offset != IWL_EXT_CHANNEL_OFFSET_BELOW)
+               iwl_conf->supported_chan_width = 0;
+
+       iwl_conf->tx_mimo_ps_mode =
+               (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2);
+       memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16);
+
+       iwl_conf->control_channel = ht_bss_conf->primary_channel;
+       iwl_conf->tx_chan_width =
+               !!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH);
+       iwl_conf->ht_protection =
+               ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION;
+       iwl_conf->non_GF_STA_present =
+               !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT);
+
+       IWL_DEBUG_MAC80211("control channel %d\n", iwl_conf->control_channel);
+       IWL_DEBUG_MAC80211("leave\n");
+}
+
+static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband,
+                       u8 *pos, int *left)
+{
+       struct ieee80211_ht_cap *ht_cap;
+
+       if (!sband || !sband->ht_info.ht_supported)
+               return;
+
+       if (*left < sizeof(struct ieee80211_ht_cap))
+               return;
+
+       *pos++ = sizeof(struct ieee80211_ht_cap);
+       ht_cap = (struct ieee80211_ht_cap *) pos;
+
+       ht_cap->cap_info = cpu_to_le16(sband->ht_info.cap);
+       memcpy(ht_cap->supp_mcs_set, sband->ht_info.supp_mcs_set, 16);
+       ht_cap->ampdu_params_info =
+               (sband->ht_info.ampdu_factor & IEEE80211_HT_CAP_AMPDU_FACTOR) |
+               ((sband->ht_info.ampdu_density << 2) &
+                       IEEE80211_HT_CAP_AMPDU_DENSITY);
+       *left -= sizeof(struct ieee80211_ht_cap);
+}
+#else
+static inline void iwl4965_ht_conf(struct iwl_priv *priv,
+                                  struct ieee80211_bss_conf *bss_conf)
+{
+}
+static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband,
+                       u8 *pos, int *left)
+{
+}
+#endif
+
+
+/**
+ * iwl4965_fill_probe_req - fill in all required fields and IE for probe request
+ */
 static u16 iwl4965_fill_probe_req(struct iwl_priv *priv,
                                  enum ieee80211_band band,
                                  struct ieee80211_mgmt *frame,
@@ -1220,10 +730,8 @@ static u16 iwl4965_fill_probe_req(struct iwl_priv *priv,
        int len = 0;
        u8 *pos = NULL;
        u16 active_rates, ret_rates, cck_rates, active_rate_basic;
-#ifdef CONFIG_IWL4965_HT
        const struct ieee80211_supported_band *sband =
-                                               iwl4965_get_hw_mode(priv, band);
-#endif /* CONFIG_IWL4965_HT */
+                                               iwl_get_hw_mode(priv, band);
 
        /* Make sure there is enough space for the probe request,
         * two mandatory IEs and the data */
@@ -1233,9 +741,9 @@ static u16 iwl4965_fill_probe_req(struct iwl_priv *priv,
        len += 24;
 
        frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
-       memcpy(frame->da, iwl4965_broadcast_addr, ETH_ALEN);
+       memcpy(frame->da, iwl_bcast_addr, ETH_ALEN);
        memcpy(frame->sa, priv->mac_addr, ETH_ALEN);
-       memcpy(frame->bssid, iwl4965_broadcast_addr, ETH_ALEN);
+       memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN);
        frame->seq_ctrl = 0;
 
        /* fill in our indirect SSID IE */
@@ -1306,24 +814,19 @@ static u16 iwl4965_fill_probe_req(struct iwl_priv *priv,
        if (*pos > 0)
                len += 2 + *pos;
 
-#ifdef CONFIG_IWL4965_HT
-       if (sband && sband->ht_info.ht_supported) {
-               struct ieee80211_ht_cap *ht_cap;
-               pos += (*pos) + 1;
-               *pos++ = WLAN_EID_HT_CAPABILITY;
-               *pos++ = sizeof(struct ieee80211_ht_cap);
-               ht_cap = (struct ieee80211_ht_cap *)pos;
-               ht_cap->cap_info = cpu_to_le16(sband->ht_info.cap);
-               memcpy(ht_cap->supp_mcs_set, sband->ht_info.supp_mcs_set, 16);
-               ht_cap->ampdu_params_info =(sband->ht_info.ampdu_factor &
-                                           IEEE80211_HT_CAP_AMPDU_FACTOR) |
-                                           ((sband->ht_info.ampdu_density << 2) &
-                                           IEEE80211_HT_CAP_AMPDU_DENSITY);
-               len += 2 + sizeof(struct ieee80211_ht_cap);
-       }
-#endif  /*CONFIG_IWL4965_HT */
-
  fill_end:
+       /* fill in HT IE */
+       left -= 2;
+       if (left < 0)
+               return 0;
+
+       *pos++ = WLAN_EID_HT_CAPABILITY;
+       *pos = 0;
+
+       iwl_ht_cap_to_ie(sband, pos, &left);
+
+       if (*pos > 0)
+               len += 2 + *pos;
        return (u16)len;
 }
 
@@ -1376,184 +879,6 @@ static void iwl4965_activate_qos(struct iwl_priv *priv, u8 force)
        }
 }
 
-/*
- * Power management (not Tx power!) functions
- */
-#define MSEC_TO_USEC 1024
-
-#define NOSLP __constant_cpu_to_le16(0), 0, 0
-#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0
-#define SLP_TIMEOUT(T) __constant_cpu_to_le32((T) * MSEC_TO_USEC)
-#define SLP_VEC(X0, X1, X2, X3, X4) {__constant_cpu_to_le32(X0), \
-                                    __constant_cpu_to_le32(X1), \
-                                    __constant_cpu_to_le32(X2), \
-                                    __constant_cpu_to_le32(X3), \
-                                    __constant_cpu_to_le32(X4)}
-
-
-/* default power management (not Tx power) table values */
-/* for tim  0-10 */
-static struct iwl4965_power_vec_entry range_0[IWL_POWER_AC] = {
-       {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
-       {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
-       {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0},
-       {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), SLP_VEC(2, 6, 9, 9, 10)}, 0},
-       {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 10)}, 1},
-       {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1}
-};
-
-/* for tim > 10 */
-static struct iwl4965_power_vec_entry range_1[IWL_POWER_AC] = {
-       {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
-       {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500),
-                SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
-       {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300),
-                SLP_VEC(2, 4, 6, 7, 0xFF)}, 0},
-       {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100),
-                SLP_VEC(2, 6, 9, 9, 0xFF)}, 0},
-       {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
-       {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25),
-                SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
-};
-
-int iwl4965_power_init_handle(struct iwl_priv *priv)
-{
-       int rc = 0, i;
-       struct iwl4965_power_mgr *pow_data;
-       int size = sizeof(struct iwl4965_power_vec_entry) * IWL_POWER_AC;
-       u16 pci_pm;
-
-       IWL_DEBUG_POWER("Initialize power \n");
-
-       pow_data = &(priv->power_data);
-
-       memset(pow_data, 0, sizeof(*pow_data));
-
-       pow_data->active_index = IWL_POWER_RANGE_0;
-       pow_data->dtim_val = 0xffff;
-
-       memcpy(&pow_data->pwr_range_0[0], &range_0[0], size);
-       memcpy(&pow_data->pwr_range_1[0], &range_1[0], size);
-
-       rc = pci_read_config_word(priv->pci_dev, PCI_LINK_CTRL, &pci_pm);
-       if (rc != 0)
-               return 0;
-       else {
-               struct iwl4965_powertable_cmd *cmd;
-
-               IWL_DEBUG_POWER("adjust power command flags\n");
-
-               for (i = 0; i < IWL_POWER_AC; i++) {
-                       cmd = &pow_data->pwr_range_0[i].cmd;
-
-                       if (pci_pm & 0x1)
-                               cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
-                       else
-                               cmd->flags |= IWL_POWER_PCI_PM_MSK;
-               }
-       }
-       return rc;
-}
-
-static int iwl4965_update_power_cmd(struct iwl_priv *priv,
-                               struct iwl4965_powertable_cmd *cmd, u32 mode)
-{
-       int rc = 0, i;
-       u8 skip;
-       u32 max_sleep = 0;
-       struct iwl4965_power_vec_entry *range;
-       u8 period = 0;
-       struct iwl4965_power_mgr *pow_data;
-
-       if (mode > IWL_POWER_INDEX_5) {
-               IWL_DEBUG_POWER("Error invalid power mode \n");
-               return -1;
-       }
-       pow_data = &(priv->power_data);
-
-       if (pow_data->active_index == IWL_POWER_RANGE_0)
-               range = &pow_data->pwr_range_0[0];
-       else
-               range = &pow_data->pwr_range_1[1];
-
-       memcpy(cmd, &range[mode].cmd, sizeof(struct iwl4965_powertable_cmd));
-
-#ifdef IWL_MAC80211_DISABLE
-       if (priv->assoc_network != NULL) {
-               unsigned long flags;
-
-               period = priv->assoc_network->tim.tim_period;
-       }
-#endif /*IWL_MAC80211_DISABLE */
-       skip = range[mode].no_dtim;
-
-       if (period == 0) {
-               period = 1;
-               skip = 0;
-       }
-
-       if (skip == 0) {
-               max_sleep = period;
-               cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
-       } else {
-               __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1];
-               max_sleep = (le32_to_cpu(slp_itrvl) / period) * period;
-               cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
-       }
-
-       for (i = 0; i < IWL_POWER_VEC_SIZE; i++) {
-               if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep)
-                       cmd->sleep_interval[i] = cpu_to_le32(max_sleep);
-       }
-
-       IWL_DEBUG_POWER("Flags value = 0x%08X\n", cmd->flags);
-       IWL_DEBUG_POWER("Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout));
-       IWL_DEBUG_POWER("Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout));
-       IWL_DEBUG_POWER("Sleep interval vector = { %d , %d , %d , %d , %d }\n",
-                       le32_to_cpu(cmd->sleep_interval[0]),
-                       le32_to_cpu(cmd->sleep_interval[1]),
-                       le32_to_cpu(cmd->sleep_interval[2]),
-                       le32_to_cpu(cmd->sleep_interval[3]),
-                       le32_to_cpu(cmd->sleep_interval[4]));
-
-       return rc;
-}
-
-static int iwl4965_send_power_mode(struct iwl_priv *priv, u32 mode)
-{
-       u32 uninitialized_var(final_mode);
-       int rc;
-       struct iwl4965_powertable_cmd cmd;
-
-       /* If on battery, set to 3,
-        * if plugged into AC power, set to CAM ("continuously aware mode"),
-        * else user level */
-       switch (mode) {
-       case IWL_POWER_BATTERY:
-               final_mode = IWL_POWER_INDEX_3;
-               break;
-       case IWL_POWER_AC:
-               final_mode = IWL_POWER_MODE_CAM;
-               break;
-       default:
-               final_mode = mode;
-               break;
-       }
-
-       cmd.keep_alive_beacons = 0;
-
-       iwl4965_update_power_cmd(priv, &cmd, final_mode);
-
-       rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd);
-
-       if (final_mode == IWL_POWER_MODE_CAM)
-               clear_bit(STATUS_POWER_PMI, &priv->status);
-       else
-               set_bit(STATUS_POWER_PMI, &priv->status);
-
-       return rc;
-}
-
 int iwl4965_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
 {
        /* Filter incoming packets to determine if they are targeted toward
@@ -1584,33 +909,7 @@ int iwl4965_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *heade
        return 1;
 }
 
-#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
-
-static const char *iwl4965_get_tx_fail_reason(u32 status)
-{
-       switch (status & TX_STATUS_MSK) {
-       case TX_STATUS_SUCCESS:
-               return "SUCCESS";
-               TX_STATUS_ENTRY(SHORT_LIMIT);
-               TX_STATUS_ENTRY(LONG_LIMIT);
-               TX_STATUS_ENTRY(FIFO_UNDERRUN);
-               TX_STATUS_ENTRY(MGMNT_ABORT);
-               TX_STATUS_ENTRY(NEXT_FRAG);
-               TX_STATUS_ENTRY(LIFE_EXPIRE);
-               TX_STATUS_ENTRY(DEST_PS);
-               TX_STATUS_ENTRY(ABORTED);
-               TX_STATUS_ENTRY(BT_RETRY);
-               TX_STATUS_ENTRY(STA_INVALID);
-               TX_STATUS_ENTRY(FRAG_DROPPED);
-               TX_STATUS_ENTRY(TID_DISABLE);
-               TX_STATUS_ENTRY(FRAME_FLUSHED);
-               TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL);
-               TX_STATUS_ENTRY(TX_LOCKED);
-               TX_STATUS_ENTRY(NO_BEACON_ON_RADAR);
-       }
 
-       return "UNKNOWN";
-}
 
 /**
  * iwl4965_scan_cancel - Cancel any currently executing HW scan
@@ -1785,8 +1084,8 @@ static int iwl4965_scan_initiate(struct iwl_priv *priv)
 }
 
 
-static void iwl4965_set_flags_for_phymode(struct iwl_priv *priv,
-                                         enum ieee80211_band band)
+static void iwl_set_flags_for_band(struct iwl_priv *priv,
+                                  enum ieee80211_band band)
 {
        if (band == IEEE80211_BAND_5GHZ) {
                priv->staging_rxon.flags &=
@@ -1871,7 +1170,7 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv)
        priv->staging_rxon.channel = cpu_to_le16(ch_info->channel);
        priv->band = ch_info->band;
 
-       iwl4965_set_flags_for_phymode(priv, priv->band);
+       iwl_set_flags_for_band(priv, priv->band);
 
        priv->staging_rxon.ofdm_basic_rates =
            (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
@@ -1884,7 +1183,7 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv)
        memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN);
        priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff;
        priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff;
-       iwl4965_set_rxon_chain(priv);
+       iwl_set_rxon_chain(priv);
 }
 
 static int iwl4965_set_mode(struct iwl_priv *priv, int mode)
@@ -1926,535 +1225,100 @@ static int iwl4965_set_mode(struct iwl_priv *priv, int mode)
        return 0;
 }
 
-static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
-                                     struct ieee80211_tx_control *ctl,
-                                     struct iwl_cmd *cmd,
-                                     struct sk_buff *skb_frag,
-                                     int sta_id)
+static void iwl4965_set_rate(struct iwl_priv *priv)
 {
-       struct iwl4965_hw_key *keyinfo = &priv->stations[sta_id].keyinfo;
-       struct iwl_wep_key *wepkey;
-       int keyidx = 0;
-
-       BUG_ON(ctl->key_idx > 3);
+       const struct ieee80211_supported_band *hw = NULL;
+       struct ieee80211_rate *rate;
+       int i;
 
-       switch (keyinfo->alg) {
-       case ALG_CCMP:
-               cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM;
-               memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen);
-               if (ctl->flags & IEEE80211_TXCTL_AMPDU)
-                       cmd->cmd.tx.tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK;
-               IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n");
-               break;
+       hw = iwl_get_hw_mode(priv, priv->band);
+       if (!hw) {
+               IWL_ERROR("Failed to set rate: unable to get hw mode\n");
+               return;
+       }
 
-       case ALG_TKIP:
-               cmd->cmd.tx.sec_ctl = TX_CMD_SEC_TKIP;
-               ieee80211_get_tkip_key(keyinfo->conf, skb_frag,
-                       IEEE80211_TKIP_P2_KEY, cmd->cmd.tx.key);
-               IWL_DEBUG_TX("tx_cmd with tkip hwcrypto\n");
-               break;
+       priv->active_rate = 0;
+       priv->active_rate_basic = 0;
 
-       case ALG_WEP:
-               wepkey = &priv->wep_keys[ctl->key_idx];
-               cmd->cmd.tx.sec_ctl = 0;
-               if (priv->default_wep_key) {
-                       /* the WEP key was sent as static */
-                       keyidx = ctl->key_idx;
-                       memcpy(&cmd->cmd.tx.key[3], wepkey->key,
-                                                       wepkey->key_size);
-                       if (wepkey->key_size == WEP_KEY_LEN_128)
-                               cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128;
-               } else {
-                       /* the WEP key was sent as dynamic */
-                       keyidx = keyinfo->keyidx;
-                       memcpy(&cmd->cmd.tx.key[3], keyinfo->key,
-                                                       keyinfo->keylen);
-                       if (keyinfo->keylen == WEP_KEY_LEN_128)
-                               cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128;
-               }
+       for (i = 0; i < hw->n_bitrates; i++) {
+               rate = &(hw->bitrates[i]);
+               if (rate->hw_value < IWL_RATE_COUNT)
+                       priv->active_rate |= (1 << rate->hw_value);
+       }
 
-               cmd->cmd.tx.sec_ctl |= (TX_CMD_SEC_WEP |
-                       (keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT);
+       IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n",
+                      priv->active_rate, priv->active_rate_basic);
 
-               IWL_DEBUG_TX("Configuring packet for WEP encryption "
-                            "with key %d\n", keyidx);
-               break;
+       /*
+        * If a basic rate is configured, then use it (adding IWL_RATE_1M_MASK)
+        * otherwise set it to the default of all CCK rates and 6, 12, 24 for
+        * OFDM
+        */
+       if (priv->active_rate_basic & IWL_CCK_BASIC_RATES_MASK)
+               priv->staging_rxon.cck_basic_rates =
+                   ((priv->active_rate_basic &
+                     IWL_CCK_RATES_MASK) >> IWL_FIRST_CCK_RATE) & 0xF;
+       else
+               priv->staging_rxon.cck_basic_rates =
+                   (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
 
-       default:
-               printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg);
-               break;
-       }
+       if (priv->active_rate_basic & IWL_OFDM_BASIC_RATES_MASK)
+               priv->staging_rxon.ofdm_basic_rates =
+                   ((priv->active_rate_basic &
+                     (IWL_OFDM_BASIC_RATES_MASK | IWL_RATE_6M_MASK)) >>
+                     IWL_FIRST_OFDM_RATE) & 0xFF;
+       else
+               priv->staging_rxon.ofdm_basic_rates =
+                  (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
 }
 
-/*
- * handle build REPLY_TX command notification.
- */
-static void iwl4965_build_tx_cmd_basic(struct iwl_priv *priv,
-                                 struct iwl_cmd *cmd,
-                                 struct ieee80211_tx_control *ctrl,
-                                 struct ieee80211_hdr *hdr,
-                                 int is_unicast, u8 std_id)
-{
-       __le16 *qc;
-       u16 fc = le16_to_cpu(hdr->frame_control);
-       __le32 tx_flags = cmd->cmd.tx.tx_flags;
-
-       cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
-       if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) {
-               tx_flags |= TX_CMD_FLG_ACK_MSK;
-               if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)
-                       tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
-               if (ieee80211_is_probe_response(fc) &&
-                   !(le16_to_cpu(hdr->seq_ctrl) & 0xf))
-                       tx_flags |= TX_CMD_FLG_TSF_MSK;
-       } else {
-               tx_flags &= (~TX_CMD_FLG_ACK_MSK);
-               tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
-       }
-
-       if (ieee80211_is_back_request(fc))
-               tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK;
+void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
+{
+       unsigned long flags;
 
+       if (!!disable_radio == test_bit(STATUS_RF_KILL_SW, &priv->status))
+               return;
 
-       cmd->cmd.tx.sta_id = std_id;
-       if (ieee80211_get_morefrag(hdr))
-               tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
+       IWL_DEBUG_RF_KILL("Manual SW RF KILL set to: RADIO %s\n",
+                         disable_radio ? "OFF" : "ON");
 
-       qc = ieee80211_get_qos_ctrl(hdr);
-       if (qc) {
-               cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf);
-               tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
-       } else
-               tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+       if (disable_radio) {
+               iwl4965_scan_cancel(priv);
+               /* FIXME: This is a workaround for AP */
+               if (priv->iw_mode != IEEE80211_IF_TYPE_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))
+                               iwl4965_send_card_state(priv,
+                                                       CARD_STATE_CMD_DISABLE,
+                                                       0);
+                       set_bit(STATUS_RF_KILL_SW, &priv->status);
 
-       if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
-               tx_flags |= TX_CMD_FLG_RTS_MSK;
-               tx_flags &= ~TX_CMD_FLG_CTS_MSK;
-       } else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
-               tx_flags &= ~TX_CMD_FLG_RTS_MSK;
-               tx_flags |= TX_CMD_FLG_CTS_MSK;
+                       /* make sure mac80211 stop sending Tx frame */
+                       if (priv->mac80211_registered)
+                               ieee80211_stop_queues(priv->hw);
+               }
+               return;
        }
 
-       if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
-               tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
+       spin_lock_irqsave(&priv->lock, flags);
+       iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
 
-       tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
-       if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
-               if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ ||
-                   (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ)
-                       cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(3);
-               else
-                       cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(2);
-       } else {
-               cmd->cmd.tx.timeout.pm_frame_timeout = 0;
-       }
+       clear_bit(STATUS_RF_KILL_SW, &priv->status);
+       spin_unlock_irqrestore(&priv->lock, flags);
 
-       cmd->cmd.tx.driver_txop = 0;
-       cmd->cmd.tx.tx_flags = tx_flags;
-       cmd->cmd.tx.next_frame_len = 0;
-}
-static void iwl_update_tx_stats(struct iwl_priv *priv, u16 fc, u16 len)
-{
-       /* 0 - mgmt, 1 - cnt, 2 - data */
-       int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2;
-       priv->tx_stats[idx].cnt++;
-       priv->tx_stats[idx].bytes += len;
-}
-/**
- * iwl4965_get_sta_id - Find station's index within station table
- *
- * If new IBSS station, create new entry in station table
- */
-static int iwl4965_get_sta_id(struct iwl_priv *priv,
-                               struct ieee80211_hdr *hdr)
-{
-       int sta_id;
-       u16 fc = le16_to_cpu(hdr->frame_control);
-       DECLARE_MAC_BUF(mac);
+       /* wake up ucode */
+       msleep(10);
 
-       /* If this frame is broadcast or management, use broadcast station id */
-       if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
-           is_multicast_ether_addr(hdr->addr1))
-               return priv->hw_params.bcast_sta_id;
-
-       switch (priv->iw_mode) {
-
-       /* If we are a client station in a BSS network, use the special
-        * AP station entry (that's the only station we communicate with) */
-       case IEEE80211_IF_TYPE_STA:
-               return IWL_AP_ID;
-
-       /* If we are an AP, then find the station, or use BCAST */
-       case IEEE80211_IF_TYPE_AP:
-               sta_id = iwl4965_hw_find_station(priv, hdr->addr1);
-               if (sta_id != IWL_INVALID_STATION)
-                       return sta_id;
-               return priv->hw_params.bcast_sta_id;
-
-       /* If this frame is going out to an IBSS network, find the station,
-        * or create a new station table entry */
-       case IEEE80211_IF_TYPE_IBSS:
-               sta_id = iwl4965_hw_find_station(priv, hdr->addr1);
-               if (sta_id != IWL_INVALID_STATION)
-                       return sta_id;
-
-               /* Create new station table entry */
-               sta_id = iwl4965_add_station_flags(priv, hdr->addr1,
-                                                  0, CMD_ASYNC, NULL);
-
-               if (sta_id != IWL_INVALID_STATION)
-                       return sta_id;
-
-               IWL_DEBUG_DROP("Station %s not in station map. "
-                              "Defaulting to broadcast...\n",
-                              print_mac(mac, hdr->addr1));
-               iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
-               return priv->hw_params.bcast_sta_id;
-
-       default:
-               IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode);
-               return priv->hw_params.bcast_sta_id;
-       }
-}
-
-/*
- * start REPLY_TX command process
- */
-static int iwl4965_tx_skb(struct iwl_priv *priv,
-                     struct sk_buff *skb, struct ieee80211_tx_control *ctl)
-{
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-       struct iwl4965_tfd_frame *tfd;
-       u32 *control_flags;
-       int txq_id = ctl->queue;
-       struct iwl4965_tx_queue *txq = NULL;
-       struct iwl4965_queue *q = NULL;
-       dma_addr_t phys_addr;
-       dma_addr_t txcmd_phys;
-       dma_addr_t scratch_phys;
-       struct iwl_cmd *out_cmd = NULL;
-       u16 len, idx, len_org;
-       u8 id, hdr_len, unicast;
-       u8 sta_id;
-       u16 seq_number = 0;
-       u16 fc;
-       __le16 *qc;
-       u8 wait_write_ptr = 0;
-       unsigned long flags;
-       int rc;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       if (iwl_is_rfkill(priv)) {
-               IWL_DEBUG_DROP("Dropping - RF KILL\n");
-               goto drop_unlock;
-       }
-
-       if (!priv->vif) {
-               IWL_DEBUG_DROP("Dropping - !priv->vif\n");
-               goto drop_unlock;
-       }
-
-       if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) {
-               IWL_ERROR("ERROR: No TX rate available.\n");
-               goto drop_unlock;
-       }
-
-       unicast = !is_multicast_ether_addr(hdr->addr1);
-       id = 0;
-
-       fc = le16_to_cpu(hdr->frame_control);
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-       if (ieee80211_is_auth(fc))
-               IWL_DEBUG_TX("Sending AUTH frame\n");
-       else if (ieee80211_is_assoc_request(fc))
-               IWL_DEBUG_TX("Sending ASSOC frame\n");
-       else if (ieee80211_is_reassoc_request(fc))
-               IWL_DEBUG_TX("Sending REASSOC frame\n");
-#endif
-
-       /* drop all data frame if we are not associated */
-       if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
-          (!iwl_is_associated(priv) ||
-           ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id) ||
-           !priv->assoc_station_added)) {
-               IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n");
-               goto drop_unlock;
-       }
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       hdr_len = ieee80211_get_hdrlen(fc);
-
-       /* Find (or create) index into station table for destination station */
-       sta_id = iwl4965_get_sta_id(priv, hdr);
-       if (sta_id == IWL_INVALID_STATION) {
-               DECLARE_MAC_BUF(mac);
-
-               IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n",
-                              print_mac(mac, hdr->addr1));
-               goto drop;
-       }
-
-       IWL_DEBUG_RATE("station Id %d\n", sta_id);
-
-       qc = ieee80211_get_qos_ctrl(hdr);
-       if (qc) {
-               u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
-               seq_number = priv->stations[sta_id].tid[tid].seq_number &
-                               IEEE80211_SCTL_SEQ;
-               hdr->seq_ctrl = cpu_to_le16(seq_number) |
-                       (hdr->seq_ctrl &
-                               __constant_cpu_to_le16(IEEE80211_SCTL_FRAG));
-               seq_number += 0x10;
-#ifdef CONFIG_IWL4965_HT
-               /* aggregation is on for this <sta,tid> */
-               if (ctl->flags & IEEE80211_TXCTL_AMPDU)
-                       txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
-               priv->stations[sta_id].tid[tid].tfds_in_queue++;
-#endif /* CONFIG_IWL4965_HT */
-       }
-
-       /* Descriptor for chosen Tx queue */
-       txq = &priv->txq[txq_id];
-       q = &txq->q;
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       /* Set up first empty TFD within this queue's circular TFD buffer */
-       tfd = &txq->bd[q->write_ptr];
-       memset(tfd, 0, sizeof(*tfd));
-       control_flags = (u32 *) tfd;
-       idx = get_cmd_index(q, q->write_ptr, 0);
-
-       /* Set up driver data for this TFD */
-       memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl4965_tx_info));
-       txq->txb[q->write_ptr].skb[0] = skb;
-       memcpy(&(txq->txb[q->write_ptr].status.control),
-              ctl, sizeof(struct ieee80211_tx_control));
-
-       /* Set up first empty entry in queue's array of Tx/cmd buffers */
-       out_cmd = &txq->cmd[idx];
-       memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
-       memset(&out_cmd->cmd.tx, 0, sizeof(out_cmd->cmd.tx));
-
-       /*
-        * Set up the Tx-command (not MAC!) header.
-        * Store the chosen Tx queue and TFD index within the sequence field;
-        * after Tx, uCode's Tx response will return this value so driver can
-        * locate the frame within the tx queue and do post-tx processing.
-        */
-       out_cmd->hdr.cmd = REPLY_TX;
-       out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
-                               INDEX_TO_SEQ(q->write_ptr)));
-
-       /* Copy MAC header from skb into command buffer */
-       memcpy(out_cmd->cmd.tx.hdr, hdr, hdr_len);
-
-       /*
-        * Use the first empty entry in this queue's command buffer array
-        * to contain the Tx command and MAC header concatenated together
-        * (payload data will be in another buffer).
-        * Size of this varies, due to varying MAC header length.
-        * If end is not dword aligned, we'll have 2 extra bytes at the end
-        * of the MAC header (device reads on dword boundaries).
-        * We'll tell device about this padding later.
-        */
-       len = priv->hw_params.tx_cmd_len +
-               sizeof(struct iwl_cmd_header) + hdr_len;
-
-       len_org = len;
-       len = (len + 3) & ~3;
-
-       if (len_org != len)
-               len_org = 1;
-       else
-               len_org = 0;
-
-       /* Physical address of this Tx command's header (not MAC header!),
-        * within command buffer array. */
-       txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx +
-                    offsetof(struct iwl_cmd, hdr);
-
-       /* Add buffer containing Tx command and MAC(!) header to TFD's
-        * first entry */
-       iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
-
-       if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
-               iwl4965_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, sta_id);
-
-       /* Set up TFD's 2nd entry to point directly to remainder of skb,
-        * if any (802.11 null frames have no payload). */
-       len = skb->len - hdr_len;
-       if (len) {
-               phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
-                                          len, PCI_DMA_TODEVICE);
-               iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len);
-       }
-
-       /* Tell 4965 about any 2-byte padding after MAC header */
-       if (len_org)
-               out_cmd->cmd.tx.tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
-
-       /* Total # bytes to be transmitted */
-       len = (u16)skb->len;
-       out_cmd->cmd.tx.len = cpu_to_le16(len);
-
-       /* TODO need this for burst mode later on */
-       iwl4965_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id);
-
-       /* set is_hcca to 0; it probably will never be implemented */
-       iwl4965_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0);
-
-       iwl_update_tx_stats(priv, fc, len);
-
-       scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
-               offsetof(struct iwl4965_tx_cmd, scratch);
-       out_cmd->cmd.tx.dram_lsb_ptr = cpu_to_le32(scratch_phys);
-       out_cmd->cmd.tx.dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys);
-
-       if (!ieee80211_get_morefrag(hdr)) {
-               txq->need_update = 1;
-               if (qc) {
-                       u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
-                       priv->stations[sta_id].tid[tid].seq_number = seq_number;
-               }
-       } else {
-               wait_write_ptr = 1;
-               txq->need_update = 0;
-       }
-
-       iwl_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload,
-                          sizeof(out_cmd->cmd.tx));
-
-       iwl_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr,
-                          ieee80211_get_hdrlen(fc));
-
-       /* Set up entry for this TFD in Tx byte-count array */
-       priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, len);
-
-       /* Tell device the write index *just past* this latest filled TFD */
-       q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
-       rc = iwl4965_tx_queue_update_write_ptr(priv, txq);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       if (rc)
-               return rc;
-
-       if ((iwl4965_queue_space(q) < q->high_mark)
-           && priv->mac80211_registered) {
-               if (wait_write_ptr) {
-                       spin_lock_irqsave(&priv->lock, flags);
-                       txq->need_update = 1;
-                       iwl4965_tx_queue_update_write_ptr(priv, txq);
-                       spin_unlock_irqrestore(&priv->lock, flags);
-               }
-
-               ieee80211_stop_queue(priv->hw, ctl->queue);
-       }
-
-       return 0;
-
-drop_unlock:
-       spin_unlock_irqrestore(&priv->lock, flags);
-drop:
-       return -1;
-}
-
-static void iwl4965_set_rate(struct iwl_priv *priv)
-{
-       const struct ieee80211_supported_band *hw = NULL;
-       struct ieee80211_rate *rate;
-       int i;
-
-       hw = iwl4965_get_hw_mode(priv, priv->band);
-       if (!hw) {
-               IWL_ERROR("Failed to set rate: unable to get hw mode\n");
-               return;
-       }
-
-       priv->active_rate = 0;
-       priv->active_rate_basic = 0;
-
-       for (i = 0; i < hw->n_bitrates; i++) {
-               rate = &(hw->bitrates[i]);
-               if (rate->hw_value < IWL_RATE_COUNT)
-                       priv->active_rate |= (1 << rate->hw_value);
-       }
-
-       IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n",
-                      priv->active_rate, priv->active_rate_basic);
-
-       /*
-        * If a basic rate is configured, then use it (adding IWL_RATE_1M_MASK)
-        * otherwise set it to the default of all CCK rates and 6, 12, 24 for
-        * OFDM
-        */
-       if (priv->active_rate_basic & IWL_CCK_BASIC_RATES_MASK)
-               priv->staging_rxon.cck_basic_rates =
-                   ((priv->active_rate_basic &
-                     IWL_CCK_RATES_MASK) >> IWL_FIRST_CCK_RATE) & 0xF;
-       else
-               priv->staging_rxon.cck_basic_rates =
-                   (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
-
-       if (priv->active_rate_basic & IWL_OFDM_BASIC_RATES_MASK)
-               priv->staging_rxon.ofdm_basic_rates =
-                   ((priv->active_rate_basic &
-                     (IWL_OFDM_BASIC_RATES_MASK | IWL_RATE_6M_MASK)) >>
-                     IWL_FIRST_OFDM_RATE) & 0xFF;
-       else
-               priv->staging_rxon.ofdm_basic_rates =
-                  (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
-}
-
-void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
-{
-       unsigned long flags;
-
-       if (!!disable_radio == test_bit(STATUS_RF_KILL_SW, &priv->status))
-               return;
-
-       IWL_DEBUG_RF_KILL("Manual SW RF KILL set to: RADIO %s\n",
-                         disable_radio ? "OFF" : "ON");
-
-       if (disable_radio) {
-               iwl4965_scan_cancel(priv);
-               /* FIXME: This is a workaround for AP */
-               if (priv->iw_mode != IEEE80211_IF_TYPE_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))
-                               iwl4965_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);
-               }
-               return;
-       }
-
-       spin_lock_irqsave(&priv->lock, flags);
-       iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-
-       clear_bit(STATUS_RF_KILL_SW, &priv->status);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       /* wake up ucode */
-       msleep(10);
-
-       spin_lock_irqsave(&priv->lock, flags);
-       iwl_read32(priv, CSR_UCODE_DRV_GP1);
-       if (!iwl_grab_nic_access(priv))
-               iwl_release_nic_access(priv);
-       spin_unlock_irqrestore(&priv->lock, flags);
+       spin_lock_irqsave(&priv->lock, flags);
+       iwl_read32(priv, CSR_UCODE_DRV_GP1);
+       if (!iwl_grab_nic_access(priv))
+               iwl_release_nic_access(priv);
+       spin_unlock_irqrestore(&priv->lock, flags);
 
        if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
                IWL_DEBUG_RF_KILL("Can not turn radio back on - "
@@ -2466,45 +1330,6 @@ void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
        return;
 }
 
-void iwl4965_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
-                           u32 decrypt_res, struct ieee80211_rx_status *stats)
-{
-       u16 fc =
-           le16_to_cpu(((struct ieee80211_hdr *)skb->data)->frame_control);
-
-       if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK)
-               return;
-
-       if (!(fc & IEEE80211_FCTL_PROTECTED))
-               return;
-
-       IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res);
-       switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) {
-       case RX_RES_STATUS_SEC_TYPE_TKIP:
-               /* The uCode has got a bad phase 1 Key, pushes the packet.
-                * Decryption will be done in SW. */
-               if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
-                   RX_RES_STATUS_BAD_KEY_TTAK)
-                       break;
-
-               if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
-                   RX_RES_STATUS_BAD_ICV_MIC)
-                       stats->flag |= RX_FLAG_MMIC_ERROR;
-       case RX_RES_STATUS_SEC_TYPE_WEP:
-       case RX_RES_STATUS_SEC_TYPE_CCMP:
-               if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
-                   RX_RES_STATUS_DECRYPT_OK) {
-                       IWL_DEBUG_RX("hw decrypt successfully!!!\n");
-                       stats->flag |= RX_FLAG_DECRYPTED;
-               }
-               break;
-
-       default:
-               break;
-       }
-}
-
-
 #define IWL_PACKET_RETRY_TIME HZ
 
 int iwl4965_is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
@@ -2629,7 +1454,7 @@ static int iwl4965_get_measurement(struct iwl_priv *priv,
                               u8 type)
 {
        struct iwl4965_spectrum_cmd spectrum;
-       struct iwl4965_rx_packet *res;
+       struct iwl_rx_packet *res;
        struct iwl_host_cmd cmd = {
                .id = REPLY_SPECTRUM_MEASUREMENT_CMD,
                .data = (void *)&spectrum,
@@ -2674,7 +1499,7 @@ static int iwl4965_get_measurement(struct iwl_priv *priv,
        if (rc)
                return rc;
 
-       res = (struct iwl4965_rx_packet *)cmd.meta.u.skb->data;
+       res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
        if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
                IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n");
                rc = -EIO;
@@ -2704,370 +1529,35 @@ static int iwl4965_get_measurement(struct iwl_priv *priv,
 }
 #endif
 
-static void iwl4965_txstatus_to_ieee(struct iwl_priv *priv,
-                                struct iwl4965_tx_info *tx_sta)
-{
-
-       tx_sta->status.ack_signal = 0;
-       tx_sta->status.excessive_retries = 0;
-       tx_sta->status.queue_length = 0;
-       tx_sta->status.queue_number = 0;
-
-       if (in_interrupt())
-               ieee80211_tx_status_irqsafe(priv->hw,
-                                           tx_sta->skb[0], &(tx_sta->status));
-       else
-               ieee80211_tx_status(priv->hw,
-                                   tx_sta->skb[0], &(tx_sta->status));
-
-       tx_sta->skb[0] = NULL;
-}
-
-/**
- * iwl4965_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd
- *
- * When FW advances 'R' index, all entries between old and new 'R' index
- * need to be reclaimed. As result, some free space forms.  If there is
- * enough free space (> low mark), wake the stack that feeds us.
- */
-int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
-{
-       struct iwl4965_tx_queue *txq = &priv->txq[txq_id];
-       struct iwl4965_queue *q = &txq->q;
-       int nfreed = 0;
-
-       if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) {
-               IWL_ERROR("Read index for DMA queue txq id (%d), index %d, "
-                         "is out of range [0-%d] %d %d.\n", txq_id,
-                         index, q->n_bd, q->write_ptr, q->read_ptr);
-               return 0;
-       }
-
-       for (index = iwl_queue_inc_wrap(index, q->n_bd);
-               q->read_ptr != index;
-               q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
-               if (txq_id != IWL_CMD_QUEUE_NUM) {
-                       iwl4965_txstatus_to_ieee(priv,
-                                       &(txq->txb[txq->q.read_ptr]));
-                       iwl4965_hw_txq_free_tfd(priv, txq);
-               } else if (nfreed > 1) {
-                       IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index,
-                                       q->write_ptr, q->read_ptr);
-                       queue_work(priv->workqueue, &priv->restart);
-               }
-               nfreed++;
-       }
-
-/*     if (iwl4965_queue_space(q) > q->low_mark && (txq_id >= 0) &&
-                       (txq_id != IWL_CMD_QUEUE_NUM) &&
-                       priv->mac80211_registered)
-               ieee80211_wake_queue(priv->hw, txq_id); */
-
-
-       return nfreed;
-}
-
-static int iwl4965_is_tx_success(u32 status)
-{
-       status &= TX_STATUS_MSK;
-       return (status == TX_STATUS_SUCCESS)
-           || (status == TX_STATUS_DIRECT_DONE);
-}
-
 /******************************************************************************
  *
  * Generic RX handler implementations
  *
  ******************************************************************************/
-#ifdef CONFIG_IWL4965_HT
-
-static inline int iwl4965_get_ra_sta_id(struct iwl_priv *priv,
-                                   struct ieee80211_hdr *hdr)
-{
-       if (priv->iw_mode == IEEE80211_IF_TYPE_STA)
-               return IWL_AP_ID;
-       else {
-               u8 *da = ieee80211_get_DA(hdr);
-               return iwl4965_hw_find_station(priv, da);
-       }
-}
-
-static struct ieee80211_hdr *iwl4965_tx_queue_get_hdr(
-       struct iwl_priv *priv, int txq_id, int idx)
+static void iwl_rx_reply_alive(struct iwl_priv *priv,
+                               struct iwl_rx_mem_buffer *rxb)
 {
-       if (priv->txq[txq_id].txb[idx].skb[0])
-               return (struct ieee80211_hdr *)priv->txq[txq_id].
-                               txb[idx].skb[0]->data;
-       return NULL;
-}
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+       struct iwl_alive_resp *palive;
+       struct delayed_work *pwork;
 
-static inline u32 iwl4965_get_scd_ssn(struct iwl4965_tx_resp *tx_resp)
-{
-       __le32 *scd_ssn = (__le32 *)((u32 *)&tx_resp->status +
-                               tx_resp->frame_count);
-       return le32_to_cpu(*scd_ssn) & MAX_SN;
+       palive = &pkt->u.alive_frame;
 
-}
+       IWL_DEBUG_INFO("Alive ucode status 0x%08X revision "
+                      "0x%01X 0x%01X\n",
+                      palive->is_valid, palive->ver_type,
+                      palive->ver_subtype);
 
-/**
- * iwl4965_tx_status_reply_tx - Handle Tx rspnse for frames in aggregation queue
- */
-static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
-                                     struct iwl4965_ht_agg *agg,
-                                     struct iwl4965_tx_resp_agg *tx_resp,
-                                     u16 start_idx)
-{
-       u16 status;
-       struct agg_tx_status *frame_status = &tx_resp->status;
-       struct ieee80211_tx_status *tx_status = NULL;
-       struct ieee80211_hdr *hdr = NULL;
-       int i, sh;
-       int txq_id, idx;
-       u16 seq;
-
-       if (agg->wait_for_ba)
-               IWL_DEBUG_TX_REPLY("got tx response w/o block-ack\n");
-
-       agg->frame_count = tx_resp->frame_count;
-       agg->start_idx = start_idx;
-       agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
-       agg->bitmap = 0;
-
-       /* # frames attempted by Tx command */
-       if (agg->frame_count == 1) {
-               /* Only one frame was attempted; no block-ack will arrive */
-               status = le16_to_cpu(frame_status[0].status);
-               seq  = le16_to_cpu(frame_status[0].sequence);
-               idx = SEQ_TO_INDEX(seq);
-               txq_id = SEQ_TO_QUEUE(seq);
-
-               /* FIXME: code repetition */
-               IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n",
-                                  agg->frame_count, agg->start_idx, idx);
-
-               tx_status = &(priv->txq[txq_id].txb[idx].status);
-               tx_status->retry_count = tx_resp->failure_frame;
-               tx_status->queue_number = status & 0xff;
-               tx_status->queue_length = tx_resp->failure_rts;
-               tx_status->control.flags &= ~IEEE80211_TXCTL_AMPDU;
-               tx_status->flags = iwl4965_is_tx_success(status)?
-                       IEEE80211_TX_STATUS_ACK : 0;
-               iwl4965_hwrate_to_tx_control(priv,
-                                            le32_to_cpu(tx_resp->rate_n_flags),
-                                            &tx_status->control);
-               /* FIXME: code repetition end */
-
-               IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n",
-                                   status & 0xff, tx_resp->failure_frame);
-               IWL_DEBUG_TX_REPLY("Rate Info rate_n_flags=%x\n",
-                               iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags));
-
-               agg->wait_for_ba = 0;
-       } else {
-               /* Two or more frames were attempted; expect block-ack */
-               u64 bitmap = 0;
-               int start = agg->start_idx;
-
-               /* Construct bit-map of pending frames within Tx window */
-               for (i = 0; i < agg->frame_count; i++) {
-                       u16 sc;
-                       status = le16_to_cpu(frame_status[i].status);
-                       seq  = le16_to_cpu(frame_status[i].sequence);
-                       idx = SEQ_TO_INDEX(seq);
-                       txq_id = SEQ_TO_QUEUE(seq);
-
-                       if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
-                                     AGG_TX_STATE_ABORT_MSK))
-                               continue;
-
-                       IWL_DEBUG_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n",
-                                          agg->frame_count, txq_id, idx);
-
-                       hdr = iwl4965_tx_queue_get_hdr(priv, txq_id, idx);
-
-                       sc = le16_to_cpu(hdr->seq_ctrl);
-                       if (idx != (SEQ_TO_SN(sc) & 0xff)) {
-                               IWL_ERROR("BUG_ON idx doesn't match seq control"
-                                         " idx=%d, seq_idx=%d, seq=%d\n",
-                                         idx, SEQ_TO_SN(sc),
-                                         hdr->seq_ctrl);
-                               return -1;
-                       }
-
-                       IWL_DEBUG_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n",
-                                          i, idx, SEQ_TO_SN(sc));
-
-                       sh = idx - start;
-                       if (sh > 64) {
-                               sh = (start - idx) + 0xff;
-                               bitmap = bitmap << sh;
-                               sh = 0;
-                               start = idx;
-                       } else if (sh < -64)
-                               sh  = 0xff - (start - idx);
-                       else if (sh < 0) {
-                               sh = start - idx;
-                               start = idx;
-                               bitmap = bitmap << sh;
-                               sh = 0;
-                       }
-                       bitmap |= (1 << sh);
-                       IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%x\n",
-                                          start, (u32)(bitmap & 0xFFFFFFFF));
-               }
-
-               agg->bitmap = bitmap;
-               agg->start_idx = start;
-               agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
-               IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n",
-                                  agg->frame_count, agg->start_idx,
-                                  (unsigned long long)agg->bitmap);
-
-               if (bitmap)
-                       agg->wait_for_ba = 1;
-       }
-       return 0;
-}
-#endif
-
-/**
- * iwl4965_rx_reply_tx - Handle standard (non-aggregation) Tx response
- */
-static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
-                           struct iwl4965_rx_mem_buffer *rxb)
-{
-       struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
-       u16 sequence = le16_to_cpu(pkt->hdr.sequence);
-       int txq_id = SEQ_TO_QUEUE(sequence);
-       int index = SEQ_TO_INDEX(sequence);
-       struct iwl4965_tx_queue *txq = &priv->txq[txq_id];
-       struct ieee80211_tx_status *tx_status;
-       struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
-       u32  status = le32_to_cpu(tx_resp->status);
-#ifdef CONFIG_IWL4965_HT
-       int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION;
-       struct ieee80211_hdr *hdr;
-       __le16 *qc;
-#endif
-
-       if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) {
-               IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
-                         "is out of range [0-%d] %d %d\n", txq_id,
-                         index, txq->q.n_bd, txq->q.write_ptr,
-                         txq->q.read_ptr);
-               return;
-       }
-
-#ifdef CONFIG_IWL4965_HT
-       hdr = iwl4965_tx_queue_get_hdr(priv, txq_id, index);
-       qc = ieee80211_get_qos_ctrl(hdr);
-
-       if (qc)
-               tid = le16_to_cpu(*qc) & 0xf;
-
-       sta_id = iwl4965_get_ra_sta_id(priv, hdr);
-       if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) {
-               IWL_ERROR("Station not known\n");
-               return;
-       }
-
-       if (txq->sched_retry) {
-               const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp);
-               struct iwl4965_ht_agg *agg = NULL;
-
-               if (!qc)
-                       return;
-
-               agg = &priv->stations[sta_id].tid[tid].agg;
-
-               iwl4965_tx_status_reply_tx(priv, agg,
-                               (struct iwl4965_tx_resp_agg *)tx_resp, index);
-
-               if ((tx_resp->frame_count == 1) &&
-                   !iwl4965_is_tx_success(status)) {
-                       /* TODO: send BAR */
-               }
-
-               if (txq->q.read_ptr != (scd_ssn & 0xff)) {
-                       int freed;
-                       index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
-                       IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn "
-                                          "%d index %d\n", scd_ssn , index);
-                       freed = iwl4965_tx_queue_reclaim(priv, txq_id, index);
-                       priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
-
-                       if (iwl4965_queue_space(&txq->q) > txq->q.low_mark &&
-                           txq_id >= 0 && priv->mac80211_registered &&
-                           agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)
-                               ieee80211_wake_queue(priv->hw, txq_id);
-
-                       iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id);
-               }
-       } else {
-#endif /* CONFIG_IWL4965_HT */
-       tx_status = &(txq->txb[txq->q.read_ptr].status);
-
-       tx_status->retry_count = tx_resp->failure_frame;
-       tx_status->queue_number = status;
-       tx_status->queue_length = tx_resp->bt_kill_count;
-       tx_status->queue_length |= tx_resp->failure_rts;
-       tx_status->flags =
-           iwl4965_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0;
-       iwl4965_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags),
-                                    &tx_status->control);
-
-       IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x "
-                    "retries %d\n", txq_id, iwl4965_get_tx_fail_reason(status),
-                    status, le32_to_cpu(tx_resp->rate_n_flags),
-                    tx_resp->failure_frame);
-
-       IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
-       if (index != -1) {
-               int freed = iwl4965_tx_queue_reclaim(priv, txq_id, index);
-#ifdef CONFIG_IWL4965_HT
-               if (tid != MAX_TID_COUNT)
-                       priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
-               if (iwl4965_queue_space(&txq->q) > txq->q.low_mark &&
-                       (txq_id >= 0) &&
-                       priv->mac80211_registered)
-                       ieee80211_wake_queue(priv->hw, txq_id);
-               if (tid != MAX_TID_COUNT)
-                       iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id);
-#endif
-       }
-#ifdef CONFIG_IWL4965_HT
-       }
-#endif /* CONFIG_IWL4965_HT */
-
-       if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
-               IWL_ERROR("TODO:  Implement Tx ABORT REQUIRED!!!\n");
-}
-
-
-static void iwl4965_rx_reply_alive(struct iwl_priv *priv,
-                              struct iwl4965_rx_mem_buffer *rxb)
-{
-       struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
-       struct iwl4965_alive_resp *palive;
-       struct delayed_work *pwork;
-
-       palive = &pkt->u.alive_frame;
-
-       IWL_DEBUG_INFO("Alive ucode status 0x%08X revision "
-                      "0x%01X 0x%01X\n",
-                      palive->is_valid, palive->ver_type,
-                      palive->ver_subtype);
-
-       if (palive->ver_subtype == INITIALIZE_SUBTYPE) {
-               IWL_DEBUG_INFO("Initialization Alive received.\n");
-               memcpy(&priv->card_alive_init,
-                      &pkt->u.alive_frame,
-                      sizeof(struct iwl4965_init_alive_resp));
-               pwork = &priv->init_alive_start;
+       if (palive->ver_subtype == INITIALIZE_SUBTYPE) {
+               IWL_DEBUG_INFO("Initialization Alive received.\n");
+               memcpy(&priv->card_alive_init,
+                      &pkt->u.alive_frame,
+                      sizeof(struct iwl_init_alive_resp));
+               pwork = &priv->init_alive_start;
        } else {
                IWL_DEBUG_INFO("Runtime Alive received.\n");
                memcpy(&priv->card_alive, &pkt->u.alive_frame,
-                      sizeof(struct iwl4965_alive_resp));
+                      sizeof(struct iwl_alive_resp));
                pwork = &priv->alive_start;
        }
 
@@ -3080,19 +1570,10 @@ static void iwl4965_rx_reply_alive(struct iwl_priv *priv,
                IWL_WARNING("uCode did not respond OK.\n");
 }
 
-static void iwl4965_rx_reply_add_sta(struct iwl_priv *priv,
-                                struct iwl4965_rx_mem_buffer *rxb)
-{
-       struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
-
-       IWL_DEBUG_RX("Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status);
-       return;
-}
-
 static void iwl4965_rx_reply_error(struct iwl_priv *priv,
-                              struct iwl4965_rx_mem_buffer *rxb)
+                                  struct iwl_rx_mem_buffer *rxb)
 {
-       struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
 
        IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) "
                "seq 0x%04X ser 0x%08X\n",
@@ -3105,10 +1586,10 @@ static void iwl4965_rx_reply_error(struct iwl_priv *priv,
 
 #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
 
-static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb)
+static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 {
-       struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
-       struct iwl4965_rxon_cmd *rxon = (void *)&priv->active_rxon;
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+       struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon;
        struct iwl4965_csa_notification *csa = &(pkt->u.csa_notif);
        IWL_DEBUG_11H("CSA notif: channel %d, status %d\n",
                      le16_to_cpu(csa->channel), le32_to_cpu(csa->status));
@@ -3117,15 +1598,15 @@ static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *
 }
 
 static void iwl4965_rx_spectrum_measure_notif(struct iwl_priv *priv,
-                                         struct iwl4965_rx_mem_buffer *rxb)
+                                         struct iwl_rx_mem_buffer *rxb)
 {
 #ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
-       struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
        struct iwl4965_spectrum_notification *report = &(pkt->u.spectrum_notif);
 
        if (!report->state) {
-               IWL_DEBUG(IWL_DL_11H | IWL_DL_INFO,
-                         "Spectrum Measure Notification: Start\n");
+               IWL_DEBUG(IWL_DL_11H,
+                       "Spectrum Measure Notification: Start\n");
                return;
        }
 
@@ -3135,10 +1616,10 @@ static void iwl4965_rx_spectrum_measure_notif(struct iwl_priv *priv,
 }
 
 static void iwl4965_rx_pm_sleep_notif(struct iwl_priv *priv,
-                                 struct iwl4965_rx_mem_buffer *rxb)
+                                     struct iwl_rx_mem_buffer *rxb)
 {
 #ifdef CONFIG_IWLWIFI_DEBUG
-       struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
        struct iwl4965_sleep_notification *sleep = &(pkt->u.sleep_notif);
        IWL_DEBUG_RX("sleep mode: %d, src: %d\n",
                     sleep->pm_sleep_mode, sleep->pm_wakeup_src);
@@ -3146,13 +1627,13 @@ static void iwl4965_rx_pm_sleep_notif(struct iwl_priv *priv,
 }
 
 static void iwl4965_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
-                                            struct iwl4965_rx_mem_buffer *rxb)
+                                            struct iwl_rx_mem_buffer *rxb)
 {
-       struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
        IWL_DEBUG_RADIO("Dumping %d bytes of unhandled "
                        "notification for %s:\n",
                        le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
-       iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
+       iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
 }
 
 static void iwl4965_bg_beacon_update(struct work_struct *work)
@@ -3162,7 +1643,7 @@ static void iwl4965_bg_beacon_update(struct work_struct *work)
        struct sk_buff *beacon;
 
        /* Pull updated AP beacon from mac80211. will fail if not in AP mode */
-       beacon = ieee80211_beacon_get(priv->hw, priv->vif, NULL);
+       beacon = ieee80211_beacon_get(priv->hw, priv->vif);
 
        if (!beacon) {
                IWL_ERROR("update beacon failed\n");
@@ -3181,10 +1662,10 @@ static void iwl4965_bg_beacon_update(struct work_struct *work)
 }
 
 static void iwl4965_rx_beacon_notif(struct iwl_priv *priv,
-                               struct iwl4965_rx_mem_buffer *rxb)
+                               struct iwl_rx_mem_buffer *rxb)
 {
 #ifdef CONFIG_IWLWIFI_DEBUG
-       struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
        struct iwl4965_beacon_notif *beacon = &(pkt->u.beacon_status);
        u8 rate = iwl4965_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
 
@@ -3204,10 +1685,10 @@ static void iwl4965_rx_beacon_notif(struct iwl_priv *priv,
 
 /* Service response to REPLY_SCAN_CMD (0x80) */
 static void iwl4965_rx_reply_scan(struct iwl_priv *priv,
-                             struct iwl4965_rx_mem_buffer *rxb)
+                             struct iwl_rx_mem_buffer *rxb)
 {
 #ifdef CONFIG_IWLWIFI_DEBUG
-       struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
        struct iwl4965_scanreq_notification *notif =
            (struct iwl4965_scanreq_notification *)pkt->u.raw;
 
@@ -3217,9 +1698,9 @@ static void iwl4965_rx_reply_scan(struct iwl_priv *priv,
 
 /* Service SCAN_START_NOTIFICATION (0x82) */
 static void iwl4965_rx_scan_start_notif(struct iwl_priv *priv,
-                                   struct iwl4965_rx_mem_buffer *rxb)
+                                   struct iwl_rx_mem_buffer *rxb)
 {
-       struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
        struct iwl4965_scanstart_notification *notif =
            (struct iwl4965_scanstart_notification *)pkt->u.raw;
        priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
@@ -3234,9 +1715,9 @@ static void iwl4965_rx_scan_start_notif(struct iwl_priv *priv,
 
 /* Service SCAN_RESULTS_NOTIFICATION (0x83) */
 static void iwl4965_rx_scan_results_notif(struct iwl_priv *priv,
-                                     struct iwl4965_rx_mem_buffer *rxb)
+                                     struct iwl_rx_mem_buffer *rxb)
 {
-       struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
        struct iwl4965_scanresults_notification *notif =
            (struct iwl4965_scanresults_notification *)pkt->u.raw;
 
@@ -3259,9 +1740,9 @@ static void iwl4965_rx_scan_results_notif(struct iwl_priv *priv,
 
 /* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
 static void iwl4965_rx_scan_complete_notif(struct iwl_priv *priv,
-                                      struct iwl4965_rx_mem_buffer *rxb)
+                                      struct iwl_rx_mem_buffer *rxb)
 {
-       struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
        struct iwl4965_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
 
        IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
@@ -3317,9 +1798,9 @@ reschedule:
 /* Handle notification from uCode that card's power state is changing
  * due to software, hardware, or critical temperature RFKILL */
 static void iwl4965_rx_card_state_notif(struct iwl_priv *priv,
-                                   struct iwl4965_rx_mem_buffer *rxb)
+                                   struct iwl_rx_mem_buffer *rxb)
 {
-       struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
        u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
        unsigned long status = priv->status;
 
@@ -3385,6 +1866,17 @@ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv,
                wake_up_interruptible(&priv->wait_command_queue);
 }
 
+/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD).
+ * This will be used later in iwl4965_rx_reply_rx() for REPLY_RX_MPDU_CMD. */
+static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv,
+                                   struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+       priv->last_phy_res[0] = 1;
+       memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]),
+              sizeof(struct iwl4965_rx_phy_res));
+}
+
 /**
  * iwl4965_setup_rx_handlers - Initialize Rx handler callbacks
  *
@@ -3396,8 +1888,7 @@ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv,
  */
 static void iwl4965_setup_rx_handlers(struct iwl_priv *priv)
 {
-       priv->rx_handlers[REPLY_ALIVE] = iwl4965_rx_reply_alive;
-       priv->rx_handlers[REPLY_ADD_STA] = iwl4965_rx_reply_add_sta;
+       priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive;
        priv->rx_handlers[REPLY_ERROR] = iwl4965_rx_reply_error;
        priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl4965_rx_csa;
        priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
@@ -3414,498 +1905,47 @@ static void iwl4965_setup_rx_handlers(struct iwl_priv *priv)
         */
        priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl4965_hw_rx_statistics;
        priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl4965_hw_rx_statistics;
-
+       /* scan handlers */
        priv->rx_handlers[REPLY_SCAN_CMD] = iwl4965_rx_reply_scan;
        priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl4965_rx_scan_start_notif;
        priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] =
            iwl4965_rx_scan_results_notif;
        priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] =
            iwl4965_rx_scan_complete_notif;
+       /* status change handler */
        priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl4965_rx_card_state_notif;
-       priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx;
 
+       priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] =
+           iwl_rx_missed_beacon_notif;
+       /* Rx handlers */
+       priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl4965_rx_reply_rx_phy;
+       priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl4965_rx_reply_rx;
        /* Set up hardware specific Rx handlers */
-       iwl4965_hw_rx_handler_setup(priv);
-}
-
-/**
- * iwl4965_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
- * @rxb: Rx buffer to reclaim
- *
- * If an Rx buffer has an async callback associated with it the callback
- * will be executed.  The attached skb (if present) will only be freed
- * if the callback returns 1
- */
-static void iwl4965_tx_cmd_complete(struct iwl_priv *priv,
-                               struct iwl4965_rx_mem_buffer *rxb)
-{
-       struct iwl4965_rx_packet *pkt = (struct iwl4965_rx_packet *)rxb->skb->data;
-       u16 sequence = le16_to_cpu(pkt->hdr.sequence);
-       int txq_id = SEQ_TO_QUEUE(sequence);
-       int index = SEQ_TO_INDEX(sequence);
-       int huge = sequence & SEQ_HUGE_FRAME;
-       int cmd_index;
-       struct iwl_cmd *cmd;
-
-       /* If a Tx command is being handled and it isn't in the actual
-        * command queue then there a command routing bug has been introduced
-        * in the queue management code. */
-       if (txq_id != IWL_CMD_QUEUE_NUM)
-               IWL_ERROR("Error wrong command queue %d command id 0x%X\n",
-                         txq_id, pkt->hdr.cmd);
-       BUG_ON(txq_id != IWL_CMD_QUEUE_NUM);
-
-       cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
-       cmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
-
-       /* Input error checking is done when commands are added to queue. */
-       if (cmd->meta.flags & CMD_WANT_SKB) {
-               cmd->meta.source->u.skb = rxb->skb;
-               rxb->skb = NULL;
-       } else if (cmd->meta.u.callback &&
-                  !cmd->meta.u.callback(priv, cmd, rxb->skb))
-               rxb->skb = NULL;
-
-       iwl4965_tx_queue_reclaim(priv, txq_id, index);
-
-       if (!(cmd->meta.flags & CMD_ASYNC)) {
-               clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
-               wake_up_interruptible(&priv->wait_command_queue);
-       }
-}
-
-/************************** RX-FUNCTIONS ****************************/
-/*
- * Rx theory of operation
- *
- * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs),
- * each of which point to Receive Buffers to be filled by 4965.  These get
- * used not only for Rx frames, but for any command response or notification
- * from the 4965.  The driver and 4965 manage the Rx buffers by means
- * of indexes into the circular buffer.
- *
- * Rx Queue Indexes
- * The host/firmware share two index registers for managing the Rx buffers.
- *
- * The READ index maps to the first position that the firmware may be writing
- * to -- the driver can read up to (but not including) this position and get
- * good data.
- * The READ index is managed by the firmware once the card is enabled.
- *
- * The WRITE index maps to the last position the driver has read from -- the
- * position preceding WRITE is the last slot the firmware can place a packet.
- *
- * The queue is empty (no good data) if WRITE = READ - 1, and is full if
- * WRITE = READ.
- *
- * During initialization, the host sets up the READ queue position to the first
- * INDEX position, and WRITE to the last (READ - 1 wrapped)
- *
- * When the firmware places a packet in a buffer, it will advance the READ index
- * and fire the RX interrupt.  The driver can then query the READ index and
- * process as many packets as possible, moving the WRITE index forward as it
- * resets the Rx queue buffers with new memory.
- *
- * The management in the driver is as follows:
- * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free.  When
- *   iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
- *   to replenish the iwl->rxq->rx_free.
- * + In iwl4965_rx_replenish (scheduled) if 'processed' != 'read' then the
- *   iwl->rxq is replenished and the READ INDEX is updated (updating the
- *   'processed' and 'read' driver indexes as well)
- * + A received packet is processed and handed to the kernel network stack,
- *   detached from the iwl->rxq.  The driver 'processed' index is updated.
- * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free
- *   list. If there are no allocated buffers in iwl->rxq->rx_free, the READ
- *   INDEX is not incremented and iwl->status(RX_STALLED) is set.  If there
- *   were enough free buffers and RX_STALLED is set it is cleared.
- *
- *
- * Driver sequence:
- *
- * iwl4965_rx_queue_alloc()   Allocates rx_free
- * iwl4965_rx_replenish()     Replenishes rx_free list from rx_used, and calls
- *                            iwl4965_rx_queue_restock
- * iwl4965_rx_queue_restock() Moves available buffers from rx_free into Rx
- *                            queue, updates firmware pointers, and updates
- *                            the WRITE index.  If insufficient rx_free buffers
- *                            are available, schedules iwl4965_rx_replenish
- *
- * -- enable interrupts --
- * ISR - iwl4965_rx()         Detach iwl4965_rx_mem_buffers from pool up to the
- *                            READ INDEX, detaching the SKB from the pool.
- *                            Moves the packet buffer from queue to rx_used.
- *                            Calls iwl4965_rx_queue_restock to refill any empty
- *                            slots.
- * ...
- *
- */
-
-/**
- * iwl4965_rx_queue_space - Return number of free slots available in queue.
- */
-static int iwl4965_rx_queue_space(const struct iwl4965_rx_queue *q)
-{
-       int s = q->read - q->write;
-       if (s <= 0)
-               s += RX_QUEUE_SIZE;
-       /* keep some buffer to not confuse full and empty queue */
-       s -= 2;
-       if (s < 0)
-               s = 0;
-       return s;
-}
-
-/**
- * iwl4965_rx_queue_update_write_ptr - Update the write pointer for the RX queue
- */
-int iwl4965_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl4965_rx_queue *q)
-{
-       u32 reg = 0;
-       int rc = 0;
-       unsigned long flags;
-
-       spin_lock_irqsave(&q->lock, flags);
-
-       if (q->need_update == 0)
-               goto exit_unlock;
-
-       /* If power-saving is in use, make sure device is awake */
-       if (test_bit(STATUS_POWER_PMI, &priv->status)) {
-               reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
-
-               if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
-                       iwl_set_bit(priv, CSR_GP_CNTRL,
-                                   CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-                       goto exit_unlock;
-               }
-
-               rc = iwl_grab_nic_access(priv);
-               if (rc)
-                       goto exit_unlock;
-
-               /* Device expects a multiple of 8 */
-               iwl_write_direct32(priv, FH_RSCSR_CHNL0_WPTR,
-                                    q->write & ~0x7);
-               iwl_release_nic_access(priv);
-
-       /* Else device is assumed to be awake */
-       } else
-               /* Device expects a multiple of 8 */
-               iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7);
-
-
-       q->need_update = 0;
-
- exit_unlock:
-       spin_unlock_irqrestore(&q->lock, flags);
-       return rc;
-}
-
-/**
- * iwl4965_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
- */
-static inline __le32 iwl4965_dma_addr2rbd_ptr(struct iwl_priv *priv,
-                                         dma_addr_t dma_addr)
-{
-       return cpu_to_le32((u32)(dma_addr >> 8));
-}
-
-
-/**
- * iwl4965_rx_queue_restock - refill RX queue from pre-allocated pool
- *
- * If there are slots in the RX queue that need to be restocked,
- * and we have free pre-allocated buffers, fill the ranks as much
- * as we can, pulling from rx_free.
- *
- * This moves the 'write' index forward to catch up with 'processed', and
- * also updates the memory address in the firmware to reference the new
- * target buffer.
- */
-static int iwl4965_rx_queue_restock(struct iwl_priv *priv)
-{
-       struct iwl4965_rx_queue *rxq = &priv->rxq;
-       struct list_head *element;
-       struct iwl4965_rx_mem_buffer *rxb;
-       unsigned long flags;
-       int write, rc;
-
-       spin_lock_irqsave(&rxq->lock, flags);
-       write = rxq->write & ~0x7;
-       while ((iwl4965_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
-               /* Get next free Rx buffer, remove from free list */
-               element = rxq->rx_free.next;
-               rxb = list_entry(element, struct iwl4965_rx_mem_buffer, list);
-               list_del(element);
-
-               /* Point to Rx buffer via next RBD in circular buffer */
-               rxq->bd[rxq->write] = iwl4965_dma_addr2rbd_ptr(priv, rxb->dma_addr);
-               rxq->queue[rxq->write] = rxb;
-               rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
-               rxq->free_count--;
-       }
-       spin_unlock_irqrestore(&rxq->lock, flags);
-       /* If the pre-allocated buffer pool is dropping low, schedule to
-        * refill it */
-       if (rxq->free_count <= RX_LOW_WATERMARK)
-               queue_work(priv->workqueue, &priv->rx_replenish);
-
-
-       /* If we've added more space for the firmware to place data, tell it.
-        * Increment device's write pointer in multiples of 8. */
-       if ((write != (rxq->write & ~0x7))
-           || (abs(rxq->write - rxq->read) > 7)) {
-               spin_lock_irqsave(&rxq->lock, flags);
-               rxq->need_update = 1;
-               spin_unlock_irqrestore(&rxq->lock, flags);
-               rc = iwl4965_rx_queue_update_write_ptr(priv, rxq);
-               if (rc)
-                       return rc;
-       }
-
-       return 0;
-}
-
-/**
- * iwl4965_rx_replenish - Move all used packet from rx_used to rx_free
- *
- * When moving to rx_free an SKB is allocated for the slot.
- *
- * Also restock the Rx queue via iwl4965_rx_queue_restock.
- * This is called as a scheduled work item (except for during initialization)
- */
-static void iwl4965_rx_allocate(struct iwl_priv *priv)
-{
-       struct iwl4965_rx_queue *rxq = &priv->rxq;
-       struct list_head *element;
-       struct iwl4965_rx_mem_buffer *rxb;
-       unsigned long flags;
-       spin_lock_irqsave(&rxq->lock, flags);
-       while (!list_empty(&rxq->rx_used)) {
-               element = rxq->rx_used.next;
-               rxb = list_entry(element, struct iwl4965_rx_mem_buffer, list);
-
-               /* Alloc a new receive buffer */
-               rxb->skb =
-                   alloc_skb(priv->hw_params.rx_buf_size,
-                               __GFP_NOWARN | GFP_ATOMIC);
-               if (!rxb->skb) {
-                       if (net_ratelimit())
-                               printk(KERN_CRIT DRV_NAME
-                                      ": Can not allocate SKB buffers\n");
-                       /* We don't reschedule replenish work here -- we will
-                        * call the restock method and if it still needs
-                        * more buffers it will schedule replenish */
-                       break;
-               }
-               priv->alloc_rxb_skb++;
-               list_del(element);
-
-               /* Get physical address of RB/SKB */
-               rxb->dma_addr =
-                   pci_map_single(priv->pci_dev, rxb->skb->data,
-                          priv->hw_params.rx_buf_size, PCI_DMA_FROMDEVICE);
-               list_add_tail(&rxb->list, &rxq->rx_free);
-               rxq->free_count++;
-       }
-       spin_unlock_irqrestore(&rxq->lock, flags);
+       priv->cfg->ops->lib->rx_handler_setup(priv);
 }
 
 /*
  * this should be called while priv->lock is locked
 */
-static void __iwl4965_rx_replenish(void *data)
+static void __iwl_rx_replenish(struct iwl_priv *priv)
 {
-       struct iwl_priv *priv = data;
-
-       iwl4965_rx_allocate(priv);
-       iwl4965_rx_queue_restock(priv);
+       iwl_rx_allocate(priv);
+       iwl_rx_queue_restock(priv);
 }
 
 
-void iwl4965_rx_replenish(void *data)
-{
-       struct iwl_priv *priv = data;
-       unsigned long flags;
-
-       iwl4965_rx_allocate(priv);
-
-       spin_lock_irqsave(&priv->lock, flags);
-       iwl4965_rx_queue_restock(priv);
-       spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
- * If an SKB has been detached, the POOL needs to have its SKB set to NULL
- * This free routine walks the list of POOL entries and if SKB is set to
- * non NULL it is unmapped and freed
- */
-static void iwl4965_rx_queue_free(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq)
-{
-       int i;
-       for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
-               if (rxq->pool[i].skb != NULL) {
-                       pci_unmap_single(priv->pci_dev,
-                                        rxq->pool[i].dma_addr,
-                                        priv->hw_params.rx_buf_size,
-                                        PCI_DMA_FROMDEVICE);
-                       dev_kfree_skb(rxq->pool[i].skb);
-               }
-       }
-
-       pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
-                           rxq->dma_addr);
-       rxq->bd = NULL;
-}
-
-int iwl4965_rx_queue_alloc(struct iwl_priv *priv)
-{
-       struct iwl4965_rx_queue *rxq = &priv->rxq;
-       struct pci_dev *dev = priv->pci_dev;
-       int i;
-
-       spin_lock_init(&rxq->lock);
-       INIT_LIST_HEAD(&rxq->rx_free);
-       INIT_LIST_HEAD(&rxq->rx_used);
-
-       /* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */
-       rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr);
-       if (!rxq->bd)
-               return -ENOMEM;
-
-       /* Fill the rx_used queue with _all_ of the Rx buffers */
-       for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
-               list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
-
-       /* Set us so that we have processed and used all buffers, but have
-        * not restocked the Rx queue with fresh buffers */
-       rxq->read = rxq->write = 0;
-       rxq->free_count = 0;
-       rxq->need_update = 0;
-       return 0;
-}
-
-void iwl4965_rx_queue_reset(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq)
-{
-       unsigned long flags;
-       int i;
-       spin_lock_irqsave(&rxq->lock, flags);
-       INIT_LIST_HEAD(&rxq->rx_free);
-       INIT_LIST_HEAD(&rxq->rx_used);
-       /* Fill the rx_used queue with _all_ of the Rx buffers */
-       for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
-               /* In the reset function, these buffers may have been allocated
-                * to an SKB, so we need to unmap and free potential storage */
-               if (rxq->pool[i].skb != NULL) {
-                       pci_unmap_single(priv->pci_dev,
-                                        rxq->pool[i].dma_addr,
-                                        priv->hw_params.rx_buf_size,
-                                        PCI_DMA_FROMDEVICE);
-                       priv->alloc_rxb_skb--;
-                       dev_kfree_skb(rxq->pool[i].skb);
-                       rxq->pool[i].skb = NULL;
-               }
-               list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
-       }
-
-       /* Set us so that we have processed and used all buffers, but have
-        * not restocked the Rx queue with fresh buffers */
-       rxq->read = rxq->write = 0;
-       rxq->free_count = 0;
-       spin_unlock_irqrestore(&rxq->lock, flags);
-}
-
-/* Convert linear signal-to-noise ratio into dB */
-static u8 ratio2dB[100] = {
-/*      0   1   2   3   4   5   6   7   8   9 */
-        0,  0,  6, 10, 12, 14, 16, 17, 18, 19, /* 00 - 09 */
-       20, 21, 22, 22, 23, 23, 24, 25, 26, 26, /* 10 - 19 */
-       26, 26, 26, 27, 27, 28, 28, 28, 29, 29, /* 20 - 29 */
-       29, 30, 30, 30, 31, 31, 31, 31, 32, 32, /* 30 - 39 */
-       32, 32, 32, 33, 33, 33, 33, 33, 34, 34, /* 40 - 49 */
-       34, 34, 34, 34, 35, 35, 35, 35, 35, 35, /* 50 - 59 */
-       36, 36, 36, 36, 36, 36, 36, 37, 37, 37, /* 60 - 69 */
-       37, 37, 37, 37, 37, 38, 38, 38, 38, 38, /* 70 - 79 */
-       38, 38, 38, 38, 38, 39, 39, 39, 39, 39, /* 80 - 89 */
-       39, 39, 39, 39, 39, 40, 40, 40, 40, 40  /* 90 - 99 */
-};
-
-/* Calculates a relative dB value from a ratio of linear
- *   (i.e. not dB) signal levels.
- * Conversion assumes that levels are voltages (20*log), not powers (10*log). */
-int iwl4965_calc_db_from_ratio(int sig_ratio)
-{
-       /* 1000:1 or higher just report as 60 dB */
-       if (sig_ratio >= 1000)
-               return 60;
-
-       /* 100:1 or higher, divide by 10 and use table,
-        *   add 20 dB to make up for divide by 10 */
-       if (sig_ratio >= 100)
-               return (20 + (int)ratio2dB[sig_ratio/10]);
-
-       /* We shouldn't see this */
-       if (sig_ratio < 1)
-               return 0;
-
-       /* Use table for ratios 1:1 - 99:1 */
-       return (int)ratio2dB[sig_ratio];
-}
-
-#define PERFECT_RSSI (-20) /* dBm */
-#define WORST_RSSI (-95)   /* dBm */
-#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI)
-
-/* Calculate an indication of rx signal quality (a percentage, not dBm!).
- * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info
- *   about formulas used below. */
-int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm)
-{
-       int sig_qual;
-       int degradation = PERFECT_RSSI - rssi_dbm;
-
-       /* If we get a noise measurement, use signal-to-noise ratio (SNR)
-        * as indicator; formula is (signal dbm - noise dbm).
-        * SNR at or above 40 is a great signal (100%).
-        * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator.
-        * Weakest usable signal is usually 10 - 15 dB SNR. */
-       if (noise_dbm) {
-               if (rssi_dbm - noise_dbm >= 40)
-                       return 100;
-               else if (rssi_dbm < noise_dbm)
-                       return 0;
-               sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2;
-
-       /* Else use just the signal level.
-        * This formula is a least squares fit of data points collected and
-        *   compared with a reference system that had a percentage (%) display
-        *   for signal quality. */
-       } else
-               sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation *
-                           (15 * RSSI_RANGE + 62 * degradation)) /
-                          (RSSI_RANGE * RSSI_RANGE);
-
-       if (sig_qual > 100)
-               sig_qual = 100;
-       else if (sig_qual < 1)
-               sig_qual = 0;
-
-       return sig_qual;
-}
-
 /**
- * iwl4965_rx_handle - Main entry function for receiving responses from uCode
+ * iwl_rx_handle - Main entry function for receiving responses from uCode
  *
  * Uses the priv->rx_handlers callback function array to invoke
  * the appropriate handlers, including command responses,
  * frame-received notifications, and other notifications.
  */
-static void iwl4965_rx_handle(struct iwl_priv *priv)
+void iwl_rx_handle(struct iwl_priv *priv)
 {
-       struct iwl4965_rx_mem_buffer *rxb;
-       struct iwl4965_rx_packet *pkt;
-       struct iwl4965_rx_queue *rxq = &priv->rxq;
+       struct iwl_rx_mem_buffer *rxb;
+       struct iwl_rx_packet *pkt;
+       struct iwl_rx_queue *rxq = &priv->rxq;
        u32 r, i;
        int reclaim;
        unsigned long flags;
@@ -3914,14 +1954,14 @@ static void iwl4965_rx_handle(struct iwl_priv *priv)
 
        /* uCode's read index (stored in shared DRAM) indicates the last Rx
         * buffer that the driver may process (last buffer filled by ucode). */
-       r = iwl4965_hw_get_rx_read(priv);
+       r = priv->cfg->ops->lib->shared_mem_rx_idx(priv);
        i = rxq->read;
 
        /* Rx interrupt, but nothing sent from uCode */
        if (i == r)
-               IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i);
+               IWL_DEBUG(IWL_DL_RX, "r = %d, i = %d\n", r, i);
 
-       if (iwl4965_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2))
+       if (iwl_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2))
                fill_rx = 1;
 
        while (i != r) {
@@ -3937,7 +1977,7 @@ static void iwl4965_rx_handle(struct iwl_priv *priv)
                pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
                                            priv->hw_params.rx_buf_size,
                                            PCI_DMA_FROMDEVICE);
-               pkt = (struct iwl4965_rx_packet *)rxb->skb->data;
+               pkt = (struct iwl_rx_packet *)rxb->skb->data;
 
                /* Reclaim a command buffer only if this packet is a response
                 *   to a (driver-originated) command.
@@ -3956,13 +1996,12 @@ static void iwl4965_rx_handle(struct iwl_priv *priv)
                 *   handle those that need handling via function in
                 *   rx_handlers table.  See iwl4965_setup_rx_handlers() */
                if (priv->rx_handlers[pkt->hdr.cmd]) {
-                       IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
-                               "r = %d, i = %d, %s, 0x%02x\n", r, i,
-                               get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
+                       IWL_DEBUG(IWL_DL_RX, "r = %d, i = %d, %s, 0x%02x\n", r,
+                               i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
                        priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
                } else {
                        /* No handling needed */
-                       IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
+                       IWL_DEBUG(IWL_DL_RX,
                                "r %d i %d No handler needed for %s, 0x%02x\n",
                                r, i, get_cmd_string(pkt->hdr.cmd),
                                pkt->hdr.cmd);
@@ -3973,7 +2012,7 @@ static void iwl4965_rx_handle(struct iwl_priv *priv)
                         * fire off the (possibly) blocking iwl_send_cmd()
                         * as we reclaim the driver command queue */
                        if (rxb && rxb->skb)
-                               iwl4965_tx_cmd_complete(priv, rxb);
+                               iwl_tx_cmd_complete(priv, rxb);
                        else
                                IWL_WARNING("Claim null rxb?\n");
                }
@@ -4000,7 +2039,7 @@ static void iwl4965_rx_handle(struct iwl_priv *priv)
                        count++;
                        if (count >= 8) {
                                priv->rxq.read = i;
-                               __iwl4965_rx_replenish(priv);
+                               __iwl_rx_replenish(priv);
                                count = 0;
                        }
                }
@@ -4008,275 +2047,140 @@ static void iwl4965_rx_handle(struct iwl_priv *priv)
 
        /* Backtrack one entry */
        priv->rxq.read = i;
-       iwl4965_rx_queue_restock(priv);
-}
-
-/**
- * iwl4965_tx_queue_update_write_ptr - Send new write index to hardware
- */
-static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv,
-                                 struct iwl4965_tx_queue *txq)
-{
-       u32 reg = 0;
-       int rc = 0;
-       int txq_id = txq->q.id;
-
-       if (txq->need_update == 0)
-               return rc;
-
-       /* if we're trying to save power */
-       if (test_bit(STATUS_POWER_PMI, &priv->status)) {
-               /* wake up nic if it's powered down ...
-                * uCode will wake up, and interrupt us again, so next
-                * time we'll skip this part. */
-               reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
-
-               if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
-                       IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg);
-                       iwl_set_bit(priv, CSR_GP_CNTRL,
-                                   CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-                       return rc;
-               }
-
-               /* restore this queue's parameters in nic hardware. */
-               rc = iwl_grab_nic_access(priv);
-               if (rc)
-                       return rc;
-               iwl_write_direct32(priv, HBUS_TARG_WRPTR,
-                                    txq->q.write_ptr | (txq_id << 8));
-               iwl_release_nic_access(priv);
-
-       /* else not in power-save mode, uCode will never sleep when we're
-        * trying to tx (during RFKILL, we're not trying to tx). */
-       } else
-               iwl_write32(priv, HBUS_TARG_WRPTR,
-                           txq->q.write_ptr | (txq_id << 8));
-
-       txq->need_update = 0;
-
-       return rc;
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-static void iwl4965_print_rx_config_cmd(struct iwl4965_rxon_cmd *rxon)
-{
-       DECLARE_MAC_BUF(mac);
-
-       IWL_DEBUG_RADIO("RX CONFIG:\n");
-       iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
-       IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
-       IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
-       IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n",
-                       le32_to_cpu(rxon->filter_flags));
-       IWL_DEBUG_RADIO("u8 dev_type: 0x%x\n", rxon->dev_type);
-       IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n",
-                       rxon->ofdm_basic_rates);
-       IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates);
-       IWL_DEBUG_RADIO("u8[6] node_addr: %s\n",
-                       print_mac(mac, rxon->node_addr));
-       IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n",
-                       print_mac(mac, rxon->bssid_addr));
-       IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
-}
-#endif
-
-static void iwl4965_enable_interrupts(struct iwl_priv *priv)
-{
-       IWL_DEBUG_ISR("Enabling interrupts\n");
-       set_bit(STATUS_INT_ENABLED, &priv->status);
-       iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
-}
-
-/* call this function to flush any scheduled tasklet */
-static inline void iwl_synchronize_irq(struct iwl_priv *priv)
-{
-       /* wait to make sure we flush pedding tasklet*/
-       synchronize_irq(priv->pci_dev->irq);
-       tasklet_kill(&priv->irq_tasklet);
+       iwl_rx_queue_restock(priv);
 }
+/* Convert linear signal-to-noise ratio into dB */
+static u8 ratio2dB[100] = {
+/*      0   1   2   3   4   5   6   7   8   9 */
+        0,  0,  6, 10, 12, 14, 16, 17, 18, 19, /* 00 - 09 */
+       20, 21, 22, 22, 23, 23, 24, 25, 26, 26, /* 10 - 19 */
+       26, 26, 26, 27, 27, 28, 28, 28, 29, 29, /* 20 - 29 */
+       29, 30, 30, 30, 31, 31, 31, 31, 32, 32, /* 30 - 39 */
+       32, 32, 32, 33, 33, 33, 33, 33, 34, 34, /* 40 - 49 */
+       34, 34, 34, 34, 35, 35, 35, 35, 35, 35, /* 50 - 59 */
+       36, 36, 36, 36, 36, 36, 36, 37, 37, 37, /* 60 - 69 */
+       37, 37, 37, 37, 37, 38, 38, 38, 38, 38, /* 70 - 79 */
+       38, 38, 38, 38, 38, 39, 39, 39, 39, 39, /* 80 - 89 */
+       39, 39, 39, 39, 39, 40, 40, 40, 40, 40  /* 90 - 99 */
+};
 
-static inline void iwl4965_disable_interrupts(struct iwl_priv *priv)
+/* Calculates a relative dB value from a ratio of linear
+ *   (i.e. not dB) signal levels.
+ * Conversion assumes that levels are voltages (20*log), not powers (10*log). */
+int iwl4965_calc_db_from_ratio(int sig_ratio)
 {
-       clear_bit(STATUS_INT_ENABLED, &priv->status);
-
-       /* disable interrupts from uCode/NIC to host */
-       iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+       /* 1000:1 or higher just report as 60 dB */
+       if (sig_ratio >= 1000)
+               return 60;
 
-       /* acknowledge/clear/reset any interrupts still pending
-        * from uCode or flow handler (Rx/Tx DMA) */
-       iwl_write32(priv, CSR_INT, 0xffffffff);
-       iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
-       IWL_DEBUG_ISR("Disabled interrupts\n");
-}
+       /* 100:1 or higher, divide by 10 and use table,
+        *   add 20 dB to make up for divide by 10 */
+       if (sig_ratio >= 100)
+               return (20 + (int)ratio2dB[sig_ratio/10]);
 
-static const char *desc_lookup(int i)
-{
-       switch (i) {
-       case 1:
-               return "FAIL";
-       case 2:
-               return "BAD_PARAM";
-       case 3:
-               return "BAD_CHECKSUM";
-       case 4:
-               return "NMI_INTERRUPT";
-       case 5:
-               return "SYSASSERT";
-       case 6:
-               return "FATAL_ERROR";
-       }
+       /* We shouldn't see this */
+       if (sig_ratio < 1)
+               return 0;
 
-       return "UNKNOWN";
+       /* Use table for ratios 1:1 - 99:1 */
+       return (int)ratio2dB[sig_ratio];
 }
 
-#define ERROR_START_OFFSET  (1 * sizeof(u32))
-#define ERROR_ELEM_SIZE     (7 * sizeof(u32))
+#define PERFECT_RSSI (-20) /* dBm */
+#define WORST_RSSI (-95)   /* dBm */
+#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI)
 
-static void iwl4965_dump_nic_error_log(struct iwl_priv *priv)
+/* Calculate an indication of rx signal quality (a percentage, not dBm!).
+ * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info
+ *   about formulas used below. */
+int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm)
 {
-       u32 data2, line;
-       u32 desc, time, count, base, data1;
-       u32 blink1, blink2, ilink1, ilink2;
-       int rc;
-
-       base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
-
-       if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
-               IWL_ERROR("Not valid error log pointer 0x%08X\n", base);
-               return;
-       }
-
-       rc = iwl_grab_nic_access(priv);
-       if (rc) {
-               IWL_WARNING("Can not read from adapter at this time.\n");
-               return;
-       }
-
-       count = iwl_read_targ_mem(priv, base);
-
-       if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
-               IWL_ERROR("Start IWL Error Log Dump:\n");
-               IWL_ERROR("Status: 0x%08lX, count: %d\n", priv->status, count);
-       }
-
-       desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
-       blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
-       blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
-       ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32));
-       ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32));
-       data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32));
-       data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32));
-       line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
-       time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
-
-       IWL_ERROR("Desc               Time       "
-                 "data1      data2      line\n");
-       IWL_ERROR("%-13s (#%d) %010u 0x%08X 0x%08X %u\n",
-                 desc_lookup(desc), desc, time, data1, data2, line);
-       IWL_ERROR("blink1  blink2  ilink1  ilink2\n");
-       IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
-                 ilink1, ilink2);
-
-       iwl_release_nic_access(priv);
-}
-
-#define EVENT_START_OFFSET  (4 * sizeof(u32))
+       int sig_qual;
+       int degradation = PERFECT_RSSI - rssi_dbm;
 
-/**
- * iwl4965_print_event_log - Dump error event log to syslog
- *
- * NOTE: Must be called with iwl_grab_nic_access() already obtained!
- */
-static void iwl4965_print_event_log(struct iwl_priv *priv, u32 start_idx,
-                               u32 num_events, u32 mode)
-{
-       u32 i;
-       u32 base;       /* SRAM byte address of event log header */
-       u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
-       u32 ptr;        /* SRAM byte address of log data */
-       u32 ev, time, data; /* event log data */
+       /* If we get a noise measurement, use signal-to-noise ratio (SNR)
+        * as indicator; formula is (signal dbm - noise dbm).
+        * SNR at or above 40 is a great signal (100%).
+        * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator.
+        * Weakest usable signal is usually 10 - 15 dB SNR. */
+       if (noise_dbm) {
+               if (rssi_dbm - noise_dbm >= 40)
+                       return 100;
+               else if (rssi_dbm < noise_dbm)
+                       return 0;
+               sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2;
 
-       if (num_events == 0)
-               return;
+       /* Else use just the signal level.
+        * This formula is a least squares fit of data points collected and
+        *   compared with a reference system that had a percentage (%) display
+        *   for signal quality. */
+       } else
+               sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation *
+                           (15 * RSSI_RANGE + 62 * degradation)) /
+                          (RSSI_RANGE * RSSI_RANGE);
 
-       base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+       if (sig_qual > 100)
+               sig_qual = 100;
+       else if (sig_qual < 1)
+               sig_qual = 0;
 
-       if (mode == 0)
-               event_size = 2 * sizeof(u32);
-       else
-               event_size = 3 * sizeof(u32);
-
-       ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
-
-       /* "time" is actually "data" for mode 0 (no timestamp).
-        * place event id # at far right for easier visual parsing. */
-       for (i = 0; i < num_events; i++) {
-               ev = iwl_read_targ_mem(priv, ptr);
-               ptr += sizeof(u32);
-               time = iwl_read_targ_mem(priv, ptr);
-               ptr += sizeof(u32);
-               if (mode == 0)
-                       IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */
-               else {
-                       data = iwl_read_targ_mem(priv, ptr);
-                       ptr += sizeof(u32);
-                       IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev);
-               }
-       }
+       return sig_qual;
 }
 
-static void iwl4965_dump_nic_event_log(struct iwl_priv *priv)
+#ifdef CONFIG_IWLWIFI_DEBUG
+static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv)
 {
-       int rc;
-       u32 base;       /* SRAM byte address of event log header */
-       u32 capacity;   /* event log capacity in # entries */
-       u32 mode;       /* 0 - no timestamp, 1 - timestamp recorded */
-       u32 num_wraps;  /* # times uCode wrapped to top of log */
-       u32 next_entry; /* index of next entry to be written by uCode */
-       u32 size;       /* # entries that we'll print */
-
-       base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
-       if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
-               IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
-               return;
-       }
-
-       rc = iwl_grab_nic_access(priv);
-       if (rc) {
-               IWL_WARNING("Can not read from adapter at this time.\n");
-               return;
-       }
-
-       /* event log header */
-       capacity = iwl_read_targ_mem(priv, base);
-       mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
-       num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
-       next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
+       struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+       DECLARE_MAC_BUF(mac);
 
-       size = num_wraps ? capacity : next_entry;
+       IWL_DEBUG_RADIO("RX CONFIG:\n");
+       iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
+       IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
+       IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
+       IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n",
+                       le32_to_cpu(rxon->filter_flags));
+       IWL_DEBUG_RADIO("u8 dev_type: 0x%x\n", rxon->dev_type);
+       IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n",
+                       rxon->ofdm_basic_rates);
+       IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates);
+       IWL_DEBUG_RADIO("u8[6] node_addr: %s\n",
+                       print_mac(mac, rxon->node_addr));
+       IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n",
+                       print_mac(mac, rxon->bssid_addr));
+       IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
+}
+#endif
 
-       /* bail out if nothing in log */
-       if (size == 0) {
-               IWL_ERROR("Start IWL Event Log Dump: nothing in log\n");
-               iwl_release_nic_access(priv);
-               return;
-       }
+static void iwl4965_enable_interrupts(struct iwl_priv *priv)
+{
+       IWL_DEBUG_ISR("Enabling interrupts\n");
+       set_bit(STATUS_INT_ENABLED, &priv->status);
+       iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
+}
 
-       IWL_ERROR("Start IWL Event Log Dump: display count %d, wraps %d\n",
-                 size, num_wraps);
+/* call this function to flush any scheduled tasklet */
+static inline void iwl_synchronize_irq(struct iwl_priv *priv)
+{
+       /* wait to make sure we flush pedding tasklet*/
+       synchronize_irq(priv->pci_dev->irq);
+       tasklet_kill(&priv->irq_tasklet);
+}
 
-       /* if uCode has wrapped back to top of log, start at the oldest entry,
-        * i.e the next one that uCode would fill. */
-       if (num_wraps)
-               iwl4965_print_event_log(priv, next_entry,
-                                   capacity - next_entry, mode);
+static inline void iwl4965_disable_interrupts(struct iwl_priv *priv)
+{
+       clear_bit(STATUS_INT_ENABLED, &priv->status);
 
-       /* (then/else) start at top of log */
-       iwl4965_print_event_log(priv, 0, next_entry, mode);
+       /* disable interrupts from uCode/NIC to host */
+       iwl_write32(priv, CSR_INT_MASK, 0x00000000);
 
-       iwl_release_nic_access(priv);
+       /* acknowledge/clear/reset any interrupts still pending
+        * from uCode or flow handler (Rx/Tx DMA) */
+       iwl_write32(priv, CSR_INT, 0xffffffff);
+       iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
+       IWL_DEBUG_ISR("Disabled interrupts\n");
 }
 
+
 /**
  * iwl4965_irq_handle_error - called for HW or SW error interrupt from card
  */
@@ -4289,10 +2193,10 @@ static void iwl4965_irq_handle_error(struct iwl_priv *priv)
        clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-       if (iwl_debug_level & IWL_DL_FW_ERRORS) {
-               iwl4965_dump_nic_error_log(priv);
-               iwl4965_dump_nic_event_log(priv);
-               iwl4965_print_rx_config_cmd(&priv->staging_rxon);
+       if (priv->debug_level & IWL_DL_FW_ERRORS) {
+               iwl_dump_nic_error_log(priv);
+               iwl_dump_nic_event_log(priv);
+               iwl4965_print_rx_config_cmd(priv);
        }
 #endif
 
@@ -4303,7 +2207,7 @@ static void iwl4965_irq_handle_error(struct iwl_priv *priv)
        clear_bit(STATUS_READY, &priv->status);
 
        if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
-               IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS,
+               IWL_DEBUG(IWL_DL_FW_ERRORS,
                          "Restarting adapter due to uCode error.\n");
 
                if (iwl_is_associated(priv)) {
@@ -4311,7 +2215,8 @@ static void iwl4965_irq_handle_error(struct iwl_priv *priv)
                               sizeof(priv->recovery_rxon));
                        priv->error_recovering = 1;
                }
-               queue_work(priv->workqueue, &priv->restart);
+               if (priv->cfg->mod_params->restart_fw)
+                       queue_work(priv->workqueue, &priv->restart);
        }
 }
 
@@ -4324,7 +2229,7 @@ static void iwl4965_error_recovery(struct iwl_priv *priv)
        priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
        iwl4965_commit_rxon(priv);
 
-       iwl4965_rxon_add_station(priv, priv->bssid, 1);
+       iwl_rxon_add_station(priv, priv->bssid, 1);
 
        spin_lock_irqsave(&priv->lock, flags);
        priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id);
@@ -4356,7 +2261,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
        iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-       if (iwl_debug_level & IWL_DL_ISR) {
+       if (priv->debug_level & IWL_DL_ISR) {
                /* just for debug */
                inta_mask = iwl_read32(priv, CSR_INT_MASK);
                IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
@@ -4390,7 +2295,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
        }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-       if (iwl_debug_level & (IWL_DL_ISR)) {
+       if (priv->debug_level & (IWL_DL_ISR)) {
                /* NIC fires this, but we don't use it, redundant with WAKEUP */
                if (inta & CSR_INT_BIT_SCD)
                        IWL_DEBUG_ISR("Scheduler finished to transmit "
@@ -4411,8 +2316,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
                                CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
                        hw_rf_kill = 1;
 
-               IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR,
-                               "RF_KILL bit toggled to %s.\n",
+               IWL_DEBUG(IWL_DL_RF_KILL, "RF_KILL bit toggled to %s.\n",
                                hw_rf_kill ? "disable radio":"enable radio");
 
                /* Queue restart only if RF_KILL switch was set to "kill"
@@ -4444,13 +2348,13 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
        /* uCode wakes up after power-down sleep */
        if (inta & CSR_INT_BIT_WAKEUP) {
                IWL_DEBUG_ISR("Wakeup interrupt\n");
-               iwl4965_rx_queue_update_write_ptr(priv, &priv->rxq);
-               iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[0]);
-               iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[1]);
-               iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[2]);
-               iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[3]);
-               iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[4]);
-               iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[5]);
+               iwl_rx_queue_update_write_ptr(priv, &priv->rxq);
+               iwl_txq_update_write_ptr(priv, &priv->txq[0]);
+               iwl_txq_update_write_ptr(priv, &priv->txq[1]);
+               iwl_txq_update_write_ptr(priv, &priv->txq[2]);
+               iwl_txq_update_write_ptr(priv, &priv->txq[3]);
+               iwl_txq_update_write_ptr(priv, &priv->txq[4]);
+               iwl_txq_update_write_ptr(priv, &priv->txq[5]);
 
                handled |= CSR_INT_BIT_WAKEUP;
        }
@@ -4459,13 +2363,16 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
         * Rx "responses" (frame-received notification), and other
         * notifications from uCode come through here*/
        if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
-               iwl4965_rx_handle(priv);
+               iwl_rx_handle(priv);
                handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
        }
 
        if (inta & CSR_INT_BIT_FH_TX) {
                IWL_DEBUG_ISR("Tx interrupt\n");
                handled |= CSR_INT_BIT_FH_TX;
+               /* FH finished to write, send event */
+               priv->ucode_write_complete = 1;
+               wake_up_interruptible(&priv->wait_command_queue);
        }
 
        if (inta & ~handled)
@@ -4483,7 +2390,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
                iwl4965_enable_interrupts(priv);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-       if (iwl_debug_level & (IWL_DL_ISR)) {
+       if (priv->debug_level & (IWL_DL_ISR)) {
                inta = iwl_read32(priv, CSR_INT);
                inta_mask = iwl_read32(priv, CSR_INT_MASK);
                inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
@@ -4620,7 +2527,7 @@ static int iwl4965_get_channels_for_scan(struct iwl_priv *priv,
        u16 active_dwell = 0;
        int added, i;
 
-       sband = iwl4965_get_hw_mode(priv, band);
+       sband = iwl_get_hw_mode(priv, band);
        if (!sband)
                return 0;
 
@@ -4652,9 +2559,6 @@ static int iwl4965_get_channels_for_scan(struct iwl_priv *priv,
                if (scan_ch->type & 1)
                        scan_ch->type |= (direct_mask << 1);
 
-               if (is_channel_narrow(ch_info))
-                       scan_ch->type |= (1 << 7);
-
                scan_ch->active_dwell = cpu_to_le16(active_dwell);
                scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
 
@@ -4687,163 +2591,6 @@ static int iwl4965_get_channels_for_scan(struct iwl_priv *priv,
        return added;
 }
 
-static void iwl4965_init_hw_rates(struct iwl_priv *priv,
-                             struct ieee80211_rate *rates)
-{
-       int i;
-
-       for (i = 0; i < IWL_RATE_COUNT; i++) {
-               rates[i].bitrate = iwl4965_rates[i].ieee * 5;
-               rates[i].hw_value = i; /* Rate scaling will work on indexes */
-               rates[i].hw_value_short = i;
-               rates[i].flags = 0;
-               if ((i > IWL_LAST_OFDM_RATE) || (i < IWL_FIRST_OFDM_RATE)) {
-                       /*
-                        * If CCK != 1M then set short preamble rate flag.
-                        */
-                       rates[i].flags |=
-                               (iwl4965_rates[i].plcp == IWL_RATE_1M_PLCP) ?
-                                       0 : IEEE80211_RATE_SHORT_PREAMBLE;
-               }
-       }
-}
-
-/**
- * iwl4965_init_geos - Initialize mac80211's geo/channel info based from eeprom
- */
-int iwl4965_init_geos(struct iwl_priv *priv)
-{
-       struct iwl_channel_info *ch;
-       struct ieee80211_supported_band *sband;
-       struct ieee80211_channel *channels;
-       struct ieee80211_channel *geo_ch;
-       struct ieee80211_rate *rates;
-       int i = 0;
-
-       if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates ||
-           priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) {
-               IWL_DEBUG_INFO("Geography modes already initialized.\n");
-               set_bit(STATUS_GEO_CONFIGURED, &priv->status);
-               return 0;
-       }
-
-       channels = kzalloc(sizeof(struct ieee80211_channel) *
-                          priv->channel_count, GFP_KERNEL);
-       if (!channels)
-               return -ENOMEM;
-
-       rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_RATE_COUNT + 1)),
-                       GFP_KERNEL);
-       if (!rates) {
-               kfree(channels);
-               return -ENOMEM;
-       }
-
-       /* 5.2GHz channels start after the 2.4GHz channels */
-       sband = &priv->bands[IEEE80211_BAND_5GHZ];
-       sband->channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
-       /* just OFDM */
-       sband->bitrates = &rates[IWL_FIRST_OFDM_RATE];
-       sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE;
-
-       iwl4965_init_ht_hw_capab(priv, &sband->ht_info, IEEE80211_BAND_5GHZ);
-
-       sband = &priv->bands[IEEE80211_BAND_2GHZ];
-       sband->channels = channels;
-       /* OFDM & CCK */
-       sband->bitrates = rates;
-       sband->n_bitrates = IWL_RATE_COUNT;
-
-       iwl4965_init_ht_hw_capab(priv, &sband->ht_info, IEEE80211_BAND_2GHZ);
-
-       priv->ieee_channels = channels;
-       priv->ieee_rates = rates;
-
-       iwl4965_init_hw_rates(priv, rates);
-
-       for (i = 0;  i < priv->channel_count; i++) {
-               ch = &priv->channel_info[i];
-
-               /* FIXME: might be removed if scan is OK */
-               if (!is_channel_valid(ch))
-                       continue;
-
-               if (is_channel_a_band(ch))
-                       sband =  &priv->bands[IEEE80211_BAND_5GHZ];
-               else
-                       sband =  &priv->bands[IEEE80211_BAND_2GHZ];
-
-               geo_ch = &sband->channels[sband->n_channels++];
-
-               geo_ch->center_freq = ieee80211_channel_to_frequency(ch->channel);
-               geo_ch->max_power = ch->max_power_avg;
-               geo_ch->max_antenna_gain = 0xff;
-               geo_ch->hw_value = ch->channel;
-
-               if (is_channel_valid(ch)) {
-                       if (!(ch->flags & EEPROM_CHANNEL_IBSS))
-                               geo_ch->flags |= IEEE80211_CHAN_NO_IBSS;
-
-                       if (!(ch->flags & EEPROM_CHANNEL_ACTIVE))
-                               geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
-
-                       if (ch->flags & EEPROM_CHANNEL_RADAR)
-                               geo_ch->flags |= IEEE80211_CHAN_RADAR;
-
-                       if (ch->max_power_avg > priv->max_channel_txpower_limit)
-                               priv->max_channel_txpower_limit =
-                                   ch->max_power_avg;
-               } else {
-                       geo_ch->flags |= IEEE80211_CHAN_DISABLED;
-               }
-
-               /* Save flags for reg domain usage */
-               geo_ch->orig_flags = geo_ch->flags;
-
-               IWL_DEBUG_INFO("Channel %d Freq=%d[%sGHz] %s flag=0%X\n",
-                               ch->channel, geo_ch->center_freq,
-                               is_channel_a_band(ch) ?  "5.2" : "2.4",
-                               geo_ch->flags & IEEE80211_CHAN_DISABLED ?
-                               "restricted" : "valid",
-                                geo_ch->flags);
-       }
-
-       if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) &&
-            priv->cfg->sku & IWL_SKU_A) {
-               printk(KERN_INFO DRV_NAME
-                      ": Incorrectly detected BG card as ABG.  Please send "
-                      "your PCI ID 0x%04X:0x%04X to maintainer.\n",
-                      priv->pci_dev->device, priv->pci_dev->subsystem_device);
-               priv->cfg->sku &= ~IWL_SKU_A;
-       }
-
-       printk(KERN_INFO DRV_NAME
-              ": Tunable channels: %d 802.11bg, %d 802.11a channels\n",
-              priv->bands[IEEE80211_BAND_2GHZ].n_channels,
-              priv->bands[IEEE80211_BAND_5GHZ].n_channels);
-
-       if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
-               priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
-                       &priv->bands[IEEE80211_BAND_2GHZ];
-       if (priv->bands[IEEE80211_BAND_5GHZ].n_channels)
-               priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
-                       &priv->bands[IEEE80211_BAND_5GHZ];
-
-       set_bit(STATUS_GEO_CONFIGURED, &priv->status);
-
-       return 0;
-}
-
-/*
- * iwl4965_free_geos - undo allocations in iwl4965_init_geos
- */
-void iwl4965_free_geos(struct iwl_priv *priv)
-{
-       kfree(priv->ieee_channels);
-       kfree(priv->ieee_rates);
-       clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
-}
-
 /******************************************************************************
  *
  * uCode download functions
@@ -4860,146 +2607,6 @@ static void iwl4965_dealloc_ucode_pci(struct iwl_priv *priv)
        iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot);
 }
 
-/**
- * iwl4965_verify_inst_full - verify runtime uCode image in card vs. host,
- *     looking at all data.
- */
-static int iwl4965_verify_inst_full(struct iwl_priv *priv, __le32 *image,
-                                u32 len)
-{
-       u32 val;
-       u32 save_len = len;
-       int rc = 0;
-       u32 errcnt;
-
-       IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
-
-       rc = iwl_grab_nic_access(priv);
-       if (rc)
-               return rc;
-
-       iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND);
-
-       errcnt = 0;
-       for (; len > 0; len -= sizeof(u32), image++) {
-               /* read data comes through single port, auto-incr addr */
-               /* NOTE: Use the debugless read so we don't flood kernel log
-                * if IWL_DL_IO is set */
-               val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
-               if (val != le32_to_cpu(*image)) {
-                       IWL_ERROR("uCode INST section is invalid at "
-                                 "offset 0x%x, is 0x%x, s/b 0x%x\n",
-                                 save_len - len, val, le32_to_cpu(*image));
-                       rc = -EIO;
-                       errcnt++;
-                       if (errcnt >= 20)
-                               break;
-               }
-       }
-
-       iwl_release_nic_access(priv);
-
-       if (!errcnt)
-               IWL_DEBUG_INFO
-                   ("ucode image in INSTRUCTION memory is good\n");
-
-       return rc;
-}
-
-
-/**
- * iwl4965_verify_inst_sparse - verify runtime uCode image in card vs. host,
- *   using sample data 100 bytes apart.  If these sample points are good,
- *   it's a pretty good bet that everything between them is good, too.
- */
-static int iwl4965_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
-{
-       u32 val;
-       int rc = 0;
-       u32 errcnt = 0;
-       u32 i;
-
-       IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
-
-       rc = iwl_grab_nic_access(priv);
-       if (rc)
-               return rc;
-
-       for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
-               /* read data comes through single port, auto-incr addr */
-               /* NOTE: Use the debugless read so we don't flood kernel log
-                * if IWL_DL_IO is set */
-               iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
-                       i + RTC_INST_LOWER_BOUND);
-               val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
-               if (val != le32_to_cpu(*image)) {
-#if 0 /* Enable this if you want to see details */
-                       IWL_ERROR("uCode INST section is invalid at "
-                                 "offset 0x%x, is 0x%x, s/b 0x%x\n",
-                                 i, val, *image);
-#endif
-                       rc = -EIO;
-                       errcnt++;
-                       if (errcnt >= 3)
-                               break;
-               }
-       }
-
-       iwl_release_nic_access(priv);
-
-       return rc;
-}
-
-
-/**
- * iwl4965_verify_ucode - determine which instruction image is in SRAM,
- *    and verify its contents
- */
-static int iwl4965_verify_ucode(struct iwl_priv *priv)
-{
-       __le32 *image;
-       u32 len;
-       int rc = 0;
-
-       /* Try bootstrap */
-       image = (__le32 *)priv->ucode_boot.v_addr;
-       len = priv->ucode_boot.len;
-       rc = iwl4965_verify_inst_sparse(priv, image, len);
-       if (rc == 0) {
-               IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n");
-               return 0;
-       }
-
-       /* Try initialize */
-       image = (__le32 *)priv->ucode_init.v_addr;
-       len = priv->ucode_init.len;
-       rc = iwl4965_verify_inst_sparse(priv, image, len);
-       if (rc == 0) {
-               IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n");
-               return 0;
-       }
-
-       /* Try runtime/protocol */
-       image = (__le32 *)priv->ucode_code.v_addr;
-       len = priv->ucode_code.len;
-       rc = iwl4965_verify_inst_sparse(priv, image, len);
-       if (rc == 0) {
-               IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n");
-               return 0;
-       }
-
-       IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
-
-       /* Since nothing seems to match, show first several data entries in
-        * instruction SRAM, so maybe visual inspection will give a clue.
-        * Selection of bootstrap image (vs. other images) is arbitrary. */
-       image = (__le32 *)priv->ucode_boot.v_addr;
-       len = priv->ucode_boot.len;
-       rc = iwl4965_verify_inst_full(priv, image, len);
-
-       return rc;
-}
-
 static void iwl4965_nic_start(struct iwl_priv *priv)
 {
        /* Remove all resets to allow NIC to operate */
@@ -5075,34 +2682,34 @@ static int iwl4965_read_ucode(struct iwl_priv *priv)
        }
 
        /* Verify that uCode images will fit in card's SRAM */
-       if (inst_size > IWL_MAX_INST_SIZE) {
+       if (inst_size > priv->hw_params.max_inst_size) {
                IWL_DEBUG_INFO("uCode instr len %d too large to fit in\n",
                               inst_size);
                ret = -EINVAL;
                goto err_release;
        }
 
-       if (data_size > IWL_MAX_DATA_SIZE) {
+       if (data_size > priv->hw_params.max_data_size) {
                IWL_DEBUG_INFO("uCode data len %d too large to fit in\n",
                                data_size);
                ret = -EINVAL;
                goto err_release;
        }
-       if (init_size > IWL_MAX_INST_SIZE) {
+       if (init_size > priv->hw_params.max_inst_size) {
                IWL_DEBUG_INFO
                    ("uCode init instr len %d too large to fit in\n",
                      init_size);
                ret = -EINVAL;
                goto err_release;
        }
-       if (init_data_size > IWL_MAX_DATA_SIZE) {
+       if (init_data_size > priv->hw_params.max_data_size) {
                IWL_DEBUG_INFO
                    ("uCode init data len %d too large to fit in\n",
                      init_data_size);
                ret = -EINVAL;
                goto err_release;
        }
-       if (boot_size > IWL_MAX_BSM_SIZE) {
+       if (boot_size > priv->hw_params.max_bsm_size) {
                IWL_DEBUG_INFO
                    ("uCode boot instr len %d too large to fit in\n",
                      boot_size);
@@ -5161,153 +2768,54 @@ static int iwl4965_read_ucode(struct iwl_priv *priv)
        len = priv->ucode_data.len;
        IWL_DEBUG_INFO("Copying (but not loading) uCode data len %Zd\n", len);
        memcpy(priv->ucode_data.v_addr, src, len);
-       memcpy(priv->ucode_data_backup.v_addr, src, len);
-
-       /* Initialization instructions (3rd block) */
-       if (init_size) {
-               src = &ucode->data[inst_size + data_size];
-               len = priv->ucode_init.len;
-               IWL_DEBUG_INFO("Copying (but not loading) init instr len %Zd\n",
-                               len);
-               memcpy(priv->ucode_init.v_addr, src, len);
-       }
-
-       /* Initialization data (4th block) */
-       if (init_data_size) {
-               src = &ucode->data[inst_size + data_size + init_size];
-               len = priv->ucode_init_data.len;
-               IWL_DEBUG_INFO("Copying (but not loading) init data len %Zd\n",
-                              len);
-               memcpy(priv->ucode_init_data.v_addr, src, len);
-       }
-
-       /* Bootstrap instructions (5th block) */
-       src = &ucode->data[inst_size + data_size + init_size + init_data_size];
-       len = priv->ucode_boot.len;
-       IWL_DEBUG_INFO("Copying (but not loading) boot instr len %Zd\n", len);
-       memcpy(priv->ucode_boot.v_addr, src, len);
-
-       /* We have our copies now, allow OS release its copies */
-       release_firmware(ucode_raw);
-       return 0;
-
- err_pci_alloc:
-       IWL_ERROR("failed to allocate pci memory\n");
-       ret = -ENOMEM;
-       iwl4965_dealloc_ucode_pci(priv);
-
- err_release:
-       release_firmware(ucode_raw);
-
- error:
-       return ret;
-}
-
-
-/**
- * iwl4965_set_ucode_ptrs - Set uCode address location
- *
- * Tell initialization uCode where to find runtime uCode.
- *
- * BSM registers initially contain pointers to initialization uCode.
- * We need to replace them to load runtime uCode inst and data,
- * and to save runtime data when powering down.
- */
-static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv)
-{
-       dma_addr_t pinst;
-       dma_addr_t pdata;
-       int rc = 0;
-       unsigned long flags;
-
-       /* bits 35:4 for 4965 */
-       pinst = priv->ucode_code.p_addr >> 4;
-       pdata = priv->ucode_data_backup.p_addr >> 4;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       rc = iwl_grab_nic_access(priv);
-       if (rc) {
-               spin_unlock_irqrestore(&priv->lock, flags);
-               return rc;
-       }
-
-       /* Tell bootstrap uCode where to find image to load */
-       iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
-       iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
-       iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG,
-                                priv->ucode_data.len);
-
-       /* Inst bytecount must be last to set up, bit 31 signals uCode
-        *   that all new ptr/size info is in place */
-       iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG,
-                                priv->ucode_code.len | BSM_DRAM_INST_LOAD);
-
-       iwl_release_nic_access(priv);
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       IWL_DEBUG_INFO("Runtime uCode pointers are set.\n");
-
-       return rc;
-}
-
-/**
- * iwl4965_init_alive_start - Called after REPLY_ALIVE notification received
- *
- * Called after REPLY_ALIVE notification received from "initialize" uCode.
- *
- * The 4965 "initialize" ALIVE reply contains calibration data for:
- *   Voltage, temperature, and MIMO tx gain correction, now stored in priv
- *   (3945 does not contain this data).
- *
- * Tell "initialize" uCode to go ahead and load the runtime uCode.
-*/
-static void iwl4965_init_alive_start(struct iwl_priv *priv)
-{
-       /* Check alive response for "valid" sign from uCode */
-       if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
-               /* We had an error bringing up the hardware, so take it
-                * all the way back down so we can try again */
-               IWL_DEBUG_INFO("Initialize Alive failed.\n");
-               goto restart;
+       memcpy(priv->ucode_data_backup.v_addr, src, len);
+
+       /* Initialization instructions (3rd block) */
+       if (init_size) {
+               src = &ucode->data[inst_size + data_size];
+               len = priv->ucode_init.len;
+               IWL_DEBUG_INFO("Copying (but not loading) init instr len %Zd\n",
+                               len);
+               memcpy(priv->ucode_init.v_addr, src, len);
        }
 
-       /* Bootstrap uCode has loaded initialize uCode ... verify inst image.
-        * This is a paranoid check, because we would not have gotten the
-        * "initialize" alive if code weren't properly loaded.  */
-       if (iwl4965_verify_ucode(priv)) {
-               /* Runtime instruction load was bad;
-                * take it all the way back down so we can try again */
-               IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n");
-               goto restart;
+       /* Initialization data (4th block) */
+       if (init_data_size) {
+               src = &ucode->data[inst_size + data_size + init_size];
+               len = priv->ucode_init_data.len;
+               IWL_DEBUG_INFO("Copying (but not loading) init data len %Zd\n",
+                              len);
+               memcpy(priv->ucode_init_data.v_addr, src, len);
        }
 
-       /* Calculate temperature */
-       priv->temperature = iwl4965_get_temperature(priv);
+       /* Bootstrap instructions (5th block) */
+       src = &ucode->data[inst_size + data_size + init_size + init_data_size];
+       len = priv->ucode_boot.len;
+       IWL_DEBUG_INFO("Copying (but not loading) boot instr len %Zd\n", len);
+       memcpy(priv->ucode_boot.v_addr, src, len);
 
-       /* Send pointers to protocol/runtime uCode image ... init code will
-        * load and launch runtime uCode, which will send us another "Alive"
-        * notification. */
-       IWL_DEBUG_INFO("Initialization Alive received.\n");
-       if (iwl4965_set_ucode_ptrs(priv)) {
-               /* Runtime instruction load won't happen;
-                * take it all the way back down so we can try again */
-               IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n");
-               goto restart;
-       }
-       return;
+       /* We have our copies now, allow OS release its copies */
+       release_firmware(ucode_raw);
+       return 0;
 
- restart:
-       queue_work(priv->workqueue, &priv->restart);
-}
+ err_pci_alloc:
+       IWL_ERROR("failed to allocate pci memory\n");
+       ret = -ENOMEM;
+       iwl4965_dealloc_ucode_pci(priv);
+
+ err_release:
+       release_firmware(ucode_raw);
 
+ error:
+       return ret;
+}
 
 /**
- * iwl4965_alive_start - called after REPLY_ALIVE notification received
+ * iwl_alive_start - called after REPLY_ALIVE notification received
  *                   from protocol/runtime uCode (initialization uCode's
- *                   Alive gets handled by iwl4965_init_alive_start()).
+ *                   Alive gets handled by iwl_init_alive_start()).
  */
-static void iwl4965_alive_start(struct iwl_priv *priv)
+static void iwl_alive_start(struct iwl_priv *priv)
 {
        int ret = 0;
 
@@ -5323,7 +2831,7 @@ static void iwl4965_alive_start(struct iwl_priv *priv)
        /* Initialize uCode has loaded Runtime uCode ... verify inst image.
         * This is a paranoid check, because we would not have gotten the
         * "runtime" alive if code weren't properly loaded.  */
-       if (iwl4965_verify_ucode(priv)) {
+       if (iwl_verify_ucode(priv)) {
                /* Runtime instruction load was bad;
                 * take it all the way back down so we can try again */
                IWL_DEBUG_INFO("Bad runtime uCode load.\n");
@@ -5331,7 +2839,6 @@ static void iwl4965_alive_start(struct iwl_priv *priv)
        }
 
        iwlcore_clear_stations_table(priv);
-
        ret = priv->cfg->ops->lib->alive_notify(priv);
        if (ret) {
                IWL_WARNING("Could not complete ALIVE transition [ntf]: %d\n",
@@ -5348,16 +2855,14 @@ static void iwl4965_alive_start(struct iwl_priv *priv)
        if (iwl_is_rfkill(priv))
                return;
 
-       ieee80211_start_queues(priv->hw);
+       ieee80211_wake_queues(priv->hw);
 
        priv->active_rate = priv->rates_mask;
        priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
 
-       iwl4965_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode));
-
        if (iwl_is_associated(priv)) {
-               struct iwl4965_rxon_cmd *active_rxon =
-                               (struct iwl4965_rxon_cmd *)(&priv->active_rxon);
+               struct iwl_rxon_cmd *active_rxon =
+                               (struct iwl_rxon_cmd *)&priv->active_rxon;
 
                memcpy(&priv->staging_rxon, &priv->active_rxon,
                       sizeof(priv->staging_rxon));
@@ -5371,12 +2876,12 @@ static void iwl4965_alive_start(struct iwl_priv *priv)
        /* Configure Bluetooth device coexistence support */
        iwl4965_send_bt_config(priv);
 
+       iwl_reset_run_time_calib(priv);
+
        /* Configure the adapter for unassociated operation */
        iwl4965_commit_rxon(priv);
 
        /* At this point, the NIC is initialized and operational */
-       priv->notif_missed_beacons = 0;
-
        iwl4965_rf_kill_ct_config(priv);
 
        iwl_leds_register(priv);
@@ -5402,12 +2907,9 @@ static void __iwl4965_down(struct iwl_priv *priv)
 {
        unsigned long flags;
        int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status);
-       struct ieee80211_conf *conf = NULL;
 
        IWL_DEBUG_INFO(DRV_NAME " is going down\n");
 
-       conf = ieee80211_get_hw_conf(priv->hw);
-
        if (!exit_pending)
                set_bit(STATUS_EXIT_PENDING, &priv->status);
 
@@ -5469,8 +2971,8 @@ static void __iwl4965_down(struct iwl_priv *priv)
                         CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       iwl4965_hw_txq_ctx_stop(priv);
-       iwl4965_hw_rxq_stop(priv);
+       iwl_txq_ctx_stop(priv);
+       iwl_rxq_stop(priv);
 
        spin_lock_irqsave(&priv->lock, flags);
        if (!iwl_grab_nic_access(priv)) {
@@ -5482,19 +2984,19 @@ static void __iwl4965_down(struct iwl_priv *priv)
 
        udelay(5);
 
-       iwl4965_hw_nic_stop_master(priv);
-       iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
-       iwl4965_hw_nic_reset(priv);
+       /* FIXME: apm_ops.suspend(priv) */
+       priv->cfg->ops->lib->apm_ops.reset(priv);
+       priv->cfg->ops->lib->free_shared_mem(priv);
 
  exit:
-       memset(&priv->card_alive, 0, sizeof(struct iwl4965_alive_resp));
+       memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
 
        if (priv->ibss_beacon)
                dev_kfree_skb(priv->ibss_beacon);
        priv->ibss_beacon = NULL;
 
        /* clear out any free frames */
-       iwl4965_clear_free_frames(priv);
+       iwl_clear_free_frames(priv);
 }
 
 static void iwl4965_down(struct iwl_priv *priv)
@@ -5546,7 +3048,13 @@ static int __iwl4965_up(struct iwl_priv *priv)
        iwl_rfkill_set_hw_state(priv);
        iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
 
-       ret = priv->cfg->ops->lib->hw_nic_init(priv);
+       ret = priv->cfg->ops->lib->alloc_shared_mem(priv);
+       if (ret) {
+               IWL_ERROR("Unable to allocate shared memory\n");
+               return ret;
+       }
+
+       ret = iwl_hw_nic_init(priv);
        if (ret) {
                IWL_ERROR("Unable to init nic\n");
                return ret;
@@ -5613,7 +3121,7 @@ static int __iwl4965_up(struct iwl_priv *priv)
  *
  *****************************************************************************/
 
-static void iwl4965_bg_init_alive_start(struct work_struct *data)
+static void iwl_bg_init_alive_start(struct work_struct *data)
 {
        struct iwl_priv *priv =
            container_of(data, struct iwl_priv, init_alive_start.work);
@@ -5622,11 +3130,11 @@ static void iwl4965_bg_init_alive_start(struct work_struct *data)
                return;
 
        mutex_lock(&priv->mutex);
-       iwl4965_init_alive_start(priv);
+       priv->cfg->ops->lib->init_alive_start(priv);
        mutex_unlock(&priv->mutex);
 }
 
-static void iwl4965_bg_alive_start(struct work_struct *data)
+static void iwl_bg_alive_start(struct work_struct *data)
 {
        struct iwl_priv *priv =
            container_of(data, struct iwl_priv, alive_start.work);
@@ -5635,7 +3143,7 @@ static void iwl4965_bg_alive_start(struct work_struct *data)
                return;
 
        mutex_lock(&priv->mutex);
-       iwl4965_alive_start(priv);
+       iwl_alive_start(priv);
        mutex_unlock(&priv->mutex);
 }
 
@@ -5651,7 +3159,7 @@ static void iwl4965_bg_rf_kill(struct work_struct *work)
        mutex_lock(&priv->mutex);
 
        if (!iwl_is_rfkill(priv)) {
-               IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL,
+               IWL_DEBUG(IWL_DL_RF_KILL,
                          "HW and/or SW RF Kill no longer active, restarting "
                          "device\n");
                if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
@@ -5674,6 +3182,24 @@ static void iwl4965_bg_rf_kill(struct work_struct *work)
        mutex_unlock(&priv->mutex);
 }
 
+static void iwl4965_bg_set_monitor(struct work_struct *work)
+{
+       struct iwl_priv *priv = container_of(work,
+                               struct iwl_priv, set_monitor);
+
+       IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n");
+
+       mutex_lock(&priv->mutex);
+
+       if (!iwl_is_ready(priv))
+               IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n");
+       else
+               if (iwl4965_set_mode(priv, IEEE80211_IF_TYPE_MNTR) != 0)
+                       IWL_ERROR("iwl4965_set_mode() failed\n");
+
+       mutex_unlock(&priv->mutex);
+}
+
 #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
 
 static void iwl4965_bg_scan_check(struct work_struct *data)
@@ -5687,9 +3213,9 @@ static void iwl4965_bg_scan_check(struct work_struct *data)
        mutex_lock(&priv->mutex);
        if (test_bit(STATUS_SCANNING, &priv->status) ||
            test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
-               IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN,
-                         "Scan completion watchdog resetting adapter (%dms)\n",
-                         jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
+               IWL_DEBUG(IWL_DL_SCAN, "Scan completion watchdog resetting "
+                       "adapter (%dms)\n",
+                       jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
 
                if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
                        iwl4965_send_scan_abort(priv);
@@ -5887,6 +3413,8 @@ static void iwl4965_bg_request_scan(struct work_struct *data)
                                direct_mask,
                                (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
 
+       scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
+                              RXON_FILTER_BCON_AWARE_MSK);
        cmd.len += le16_to_cpu(scan->tx_cmd.len) +
            scan->channel_count * sizeof(struct iwl4965_scan_channel);
        cmd.data = scan;
@@ -5941,7 +3469,7 @@ static void iwl4965_bg_rx_replenish(struct work_struct *data)
                return;
 
        mutex_lock(&priv->mutex);
-       iwl4965_rx_replenish(priv);
+       iwl_rx_replenish(priv);
        mutex_unlock(&priv->mutex);
 }
 
@@ -5989,9 +3517,9 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
 
 #ifdef CONFIG_IWL4965_HT
        if (priv->current_ht_config.is_ht)
-               iwl4965_set_rxon_ht(priv, &priv->current_ht_config);
+               iwl_set_rxon_ht(priv, &priv->current_ht_config);
 #endif /* CONFIG_IWL4965_HT*/
-       iwl4965_set_rxon_chain(priv);
+       iwl_set_rxon_chain(priv);
        priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
 
        IWL_DEBUG_ASSOC("assoc id %d beacon interval %d\n",
@@ -6025,8 +3553,8 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
                /* clear out the station table */
                iwlcore_clear_stations_table(priv);
 
-               iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0);
-               iwl4965_rxon_add_station(priv, priv->bssid, 0);
+               iwl_rxon_add_station(priv, iwl_bcast_addr, 0);
+               iwl_rxon_add_station(priv, priv->bssid, 0);
                iwl4965_rate_scale_init(priv->hw, IWL_STA_ID);
                iwl4965_send_beacon_cmd(priv);
 
@@ -6040,17 +3568,16 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
 
        iwl4965_sequence_reset(priv);
 
-#ifdef CONFIG_IWL4965_SENSITIVITY
        /* Enable Rx differential gain and sensitivity calibrations */
-       iwl4965_chain_noise_reset(priv);
+       iwl_chain_noise_reset(priv);
        priv->start_calib = 1;
-#endif /* CONFIG_IWL4965_SENSITIVITY */
 
        if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
                priv->assoc_station_added = 1;
 
        iwl4965_activate_qos(priv, 0);
 
+       iwl_power_update_mode(priv, 0);
        /* we have just associated, don't start scan too early */
        priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
 }
@@ -6089,7 +3616,7 @@ static void iwl4965_bg_scan_completed(struct work_struct *work)
        struct iwl_priv *priv =
            container_of(work, struct iwl_priv, scan_completed);
 
-       IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, "SCAN complete scan\n");
+       IWL_DEBUG(IWL_DL_SCAN, "SCAN complete scan\n");
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
@@ -6138,7 +3665,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw)
        /* we should be verifying the device is ready to be opened */
        mutex_lock(&priv->mutex);
 
-       memset(&priv->staging_rxon, 0, sizeof(struct iwl4965_rxon_cmd));
+       memset(&priv->staging_rxon, 0, sizeof(struct iwl_rxon_cmd));
        /* fetch ucode file from disk, alloc and copy to bus-master buffers ...
         * ucode filename and max sizes are card-specific. */
 
@@ -6163,21 +3690,23 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw)
        if (test_bit(STATUS_IN_SUSPEND, &priv->status))
                return 0;
 
-       /* Wait for START_ALIVE from ucode. Otherwise callbacks from
+       /* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from
         * mac80211 will not be run successfully. */
-       ret = wait_event_interruptible_timeout(priv->wait_command_queue,
-                       test_bit(STATUS_READY, &priv->status),
-                       UCODE_READY_TIMEOUT);
-       if (!ret) {
-               if (!test_bit(STATUS_READY, &priv->status)) {
-                       IWL_ERROR("Wait for START_ALIVE timeout after %dms.\n",
-                                 jiffies_to_msecs(UCODE_READY_TIMEOUT));
-                       ret = -ETIMEDOUT;
-                       goto out_release_irq;
+       if (priv->ucode_type == UCODE_RT) {
+               ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+                               test_bit(STATUS_READY, &priv->status),
+                               UCODE_READY_TIMEOUT);
+               if (!ret) {
+                       if (!test_bit(STATUS_READY, &priv->status)) {
+                               IWL_ERROR("START_ALIVE timeout after %dms.\n",
+                                       jiffies_to_msecs(UCODE_READY_TIMEOUT));
+                               ret = -ETIMEDOUT;
+                               goto out_release_irq;
+                       }
                }
-       }
 
-       priv->is_open = 1;
+               priv->is_open = 1;
+       }
        IWL_DEBUG_MAC80211("leave\n");
        return 0;
 
@@ -6225,8 +3754,7 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw)
        IWL_DEBUG_MAC80211("leave\n");
 }
 
-static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
-                     struct ieee80211_tx_control *ctl)
+static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct iwl_priv *priv = hw->priv;
 
@@ -6238,9 +3766,9 @@ static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
        }
 
        IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
-                    ctl->tx_rate->bitrate);
+                    ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
 
-       if (iwl4965_tx_skb(priv, skb, ctl))
+       if (iwl_tx_skb(priv, skb))
                dev_kfree_skb_any(skb);
 
        IWL_DEBUG_MAC80211("leave\n");
@@ -6295,6 +3823,7 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co
        const struct iwl_channel_info *ch_info;
        unsigned long flags;
        int ret = 0;
+       u16 channel;
 
        mutex_lock(&priv->mutex);
        IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value);
@@ -6315,22 +3844,21 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co
                return 0;
        }
 
-       spin_lock_irqsave(&priv->lock, flags);
-
-       ch_info = iwl_get_channel_info(priv, conf->channel->band,
-                       ieee80211_frequency_to_channel(conf->channel->center_freq));
+       channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
+       ch_info = iwl_get_channel_info(priv, conf->channel->band, channel);
        if (!is_channel_valid(ch_info)) {
                IWL_DEBUG_MAC80211("leave - invalid channel\n");
-               spin_unlock_irqrestore(&priv->lock, flags);
                ret = -EINVAL;
                goto out;
        }
 
+       spin_lock_irqsave(&priv->lock, flags);
+
 #ifdef CONFIG_IWL4965_HT
        /* if we are switching from ht to 2.4 clear flags
         * from any ht related info since 2.4 does not
         * support ht */
-       if ((le16_to_cpu(priv->staging_rxon.channel) != conf->channel->hw_value)
+       if ((le16_to_cpu(priv->staging_rxon.channel) != channel)
 #ifdef IEEE80211_CONF_CHANNEL_SWITCH
            && !(conf->flags & IEEE80211_CONF_CHANNEL_SWITCH)
 #endif
@@ -6338,10 +3866,9 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co
                priv->staging_rxon.flags = 0;
 #endif /* CONFIG_IWL4965_HT */
 
-       iwlcore_set_rxon_channel(priv, conf->channel->band,
-               ieee80211_frequency_to_channel(conf->channel->center_freq));
+       iwl_set_rxon_channel(priv, conf->channel->band, channel);
 
-       iwl4965_set_flags_for_phymode(priv, conf->channel->band);
+       iwl_set_flags_for_band(priv, conf->channel->band);
 
        /* The list of supported rates and rate mask can be different
         * for each band; since the band may have changed, reset
@@ -6410,7 +3937,7 @@ static void iwl4965_config_ap(struct iwl_priv *priv)
                        IWL_WARNING("REPLY_RXON_TIMING failed - "
                                        "Attempting to continue.\n");
 
-               iwl4965_set_rxon_chain(priv);
+               iwl_set_rxon_chain(priv);
 
                /* FIXME: what should be the assoc_id for AP? */
                priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
@@ -6438,7 +3965,7 @@ static void iwl4965_config_ap(struct iwl_priv *priv)
                priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
                iwl4965_commit_rxon(priv);
                iwl4965_activate_qos(priv, 1);
-               iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0);
+               iwl_rxon_add_station(priv, iwl_bcast_addr, 0);
        }
        iwl4965_send_beacon_cmd(priv);
 
@@ -6527,7 +4054,7 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
                else {
                        rc = iwl4965_commit_rxon(priv);
                        if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc)
-                               iwl4965_rxon_add_station(
+                               iwl_rxon_add_station(
                                        priv, priv->active_rxon.bssid_addr, 1);
                }
 
@@ -6562,7 +4089,22 @@ static void iwl4965_configure_filter(struct ieee80211_hw *hw,
         * XXX: dummy
         * see also iwl4965_connection_init_rx_config
         */
-       *total_flags = 0;
+       struct iwl_priv *priv = hw->priv;
+       int new_flags = 0;
+       if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) {
+               if (*total_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) {
+                       IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n",
+                                          IEEE80211_IF_TYPE_MNTR,
+                                          changed_flags, *total_flags);
+                       /* queue work 'cuz mac80211 is holding a lock which
+                        * prevents us from issuing (synchronous) f/w cmds */
+                       queue_work(priv->workqueue, &priv->set_monitor);
+                       new_flags &= FIF_PROMISC_IN_BSS |
+                                    FIF_OTHER_BSS |
+                                    FIF_ALLMULTI;
+               }
+       }
+       *total_flags = new_flags;
 }
 
 static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw,
@@ -6592,64 +4134,6 @@ static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw,
 
 }
 
-
-#ifdef CONFIG_IWL4965_HT
-static void iwl4965_ht_conf(struct iwl_priv *priv,
-                           struct ieee80211_bss_conf *bss_conf)
-{
-       struct ieee80211_ht_info *ht_conf = bss_conf->ht_conf;
-       struct ieee80211_ht_bss_info *ht_bss_conf = bss_conf->ht_bss_conf;
-       struct iwl_ht_info *iwl_conf = &priv->current_ht_config;
-
-       IWL_DEBUG_MAC80211("enter: \n");
-
-       iwl_conf->is_ht = bss_conf->assoc_ht;
-
-       if (!iwl_conf->is_ht)
-               return;
-
-       priv->ps_mode = (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2);
-
-       if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20)
-               iwl_conf->sgf |= 0x1;
-       if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40)
-               iwl_conf->sgf |= 0x2;
-
-       iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD);
-       iwl_conf->max_amsdu_size =
-               !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU);
-
-       iwl_conf->supported_chan_width =
-               !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH);
-       iwl_conf->extension_chan_offset =
-               ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET;
-       /* If no above or below channel supplied disable FAT channel */
-       if (iwl_conf->extension_chan_offset != IWL_EXT_CHANNEL_OFFSET_ABOVE &&
-           iwl_conf->extension_chan_offset != IWL_EXT_CHANNEL_OFFSET_BELOW)
-               iwl_conf->supported_chan_width = 0;
-
-       iwl_conf->tx_mimo_ps_mode =
-               (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2);
-       memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16);
-
-       iwl_conf->control_channel = ht_bss_conf->primary_channel;
-       iwl_conf->tx_chan_width =
-               !!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH);
-       iwl_conf->ht_protection =
-               ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION;
-       iwl_conf->non_GF_STA_present =
-               !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT);
-
-       IWL_DEBUG_MAC80211("control channel %d\n", iwl_conf->control_channel);
-       IWL_DEBUG_MAC80211("leave\n");
-}
-#else
-static inline void iwl4965_ht_conf(struct iwl_priv *priv,
-                                  struct ieee80211_bss_conf *bss_conf)
-{
-}
-#endif
-
 #define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
 static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif,
@@ -6680,7 +4164,7 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
        if (changes & BSS_CHANGED_HT) {
                IWL_DEBUG_MAC80211("HT %d\n", bss_conf->assoc_ht);
                iwl4965_ht_conf(priv, bss_conf);
-               iwl4965_set_rxon_chain(priv);
+               iwl_set_rxon_chain(priv);
        }
 
        if (changes & BSS_CHANGED_ASSOC) {
@@ -6780,7 +4264,7 @@ static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw,
 
        IWL_DEBUG_MAC80211("enter\n");
 
-       sta_id = iwl4965_hw_find_station(priv, addr);
+       sta_id = iwl_find_station(priv, addr);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
                                   print_mac(mac, addr));
@@ -6808,7 +4292,7 @@ static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw,
        priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
        priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
 
-       iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+       iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
 
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 
@@ -6827,7 +4311,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
        IWL_DEBUG_MAC80211("enter\n");
 
-       if (priv->cfg->mod_params->sw_crypto) {
+       if (priv->hw_params.sw_crypto) {
                IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n");
                return -EOPNOTSUPP;
        }
@@ -6836,7 +4320,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                /* only support pairwise keys */
                return -EOPNOTSUPP;
 
-       sta_id = iwl4965_hw_find_station(priv, addr);
+       sta_id = iwl_find_station(priv, addr);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
                                   print_mac(mac, addr));
@@ -6857,7 +4341,8 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                if (cmd == SET_KEY)
                        is_default_wep_key = !priv->key_mapping_key;
                else
-                       is_default_wep_key = priv->default_wep_key;
+                       is_default_wep_key =
+                                       (key->hw_key_idx == HW_KEY_DEFAULT);
        }
 
        switch (cmd) {
@@ -6873,7 +4358,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                if (is_default_wep_key)
                        ret = iwl_remove_default_wep_key(priv, key);
                else
-                       ret = iwl_remove_dynamic_key(priv, sta_id);
+                       ret = iwl_remove_dynamic_key(priv, key, sta_id);
 
                IWL_DEBUG_MAC80211("disable hwcrypto key\n");
                break;
@@ -6886,7 +4371,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        return ret;
 }
 
-static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, int queue,
+static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
                           const struct ieee80211_tx_queue_params *params)
 {
        struct iwl_priv *priv = hw->priv;
@@ -6942,8 +4427,8 @@ static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw,
 {
        struct iwl_priv *priv = hw->priv;
        int i, avail;
-       struct iwl4965_tx_queue *txq;
-       struct iwl4965_queue *q;
+       struct iwl_tx_queue *txq;
+       struct iwl_queue *q;
        unsigned long flags;
 
        IWL_DEBUG_MAC80211("enter\n");
@@ -6958,11 +4443,11 @@ static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw,
        for (i = 0; i < AC_NUM; i++) {
                txq = &priv->txq[i];
                q = &txq->q;
-               avail = iwl4965_queue_space(q);
+               avail = iwl_queue_space(q);
 
-               stats->data[i].len = q->n_window - avail;
-               stats->data[i].limit = q->n_window - q->high_mark;
-               stats->data[i].count = q->n_window;
+               stats[i].len = q->n_window - avail;
+               stats[i].limit = q->n_window - q->high_mark;
+               stats[i].count = q->n_window;
 
        }
        spin_unlock_irqrestore(&priv->lock, flags);
@@ -6975,6 +4460,9 @@ static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw,
 static int iwl4965_mac_get_stats(struct ieee80211_hw *hw,
                             struct ieee80211_low_level_stats *stats)
 {
+       struct iwl_priv *priv = hw->priv;
+
+       priv = hw->priv;
        IWL_DEBUG_MAC80211("enter\n");
        IWL_DEBUG_MAC80211("leave\n");
 
@@ -6983,6 +4471,9 @@ static int iwl4965_mac_get_stats(struct ieee80211_hw *hw,
 
 static u64 iwl4965_mac_get_tsf(struct ieee80211_hw *hw)
 {
+       struct iwl_priv *priv;
+
+       priv = hw->priv;
        IWL_DEBUG_MAC80211("enter\n");
        IWL_DEBUG_MAC80211("leave\n");
 
@@ -7004,7 +4495,7 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
        spin_unlock_irqrestore(&priv->lock, flags);
 #endif /* CONFIG_IWL4965_HT */
 
-       iwlcore_reset_qos(priv);
+       iwl_reset_qos(priv);
 
        cancel_delayed_work(&priv->post_associate);
 
@@ -7041,6 +4532,8 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
                iwl4965_commit_rxon(priv);
        }
 
+       iwl_power_update_mode(priv, 0);
+
        /* Per mac80211.h: This is only used in IBSS mode... */
        if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
 
@@ -7056,8 +4549,7 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
        IWL_DEBUG_MAC80211("leave\n");
 }
 
-static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
-                                struct ieee80211_tx_control *control)
+static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct iwl_priv *priv = hw->priv;
        unsigned long flags;
@@ -7089,7 +4581,7 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk
        IWL_DEBUG_MAC80211("leave\n");
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       iwlcore_reset_qos(priv);
+       iwl_reset_qos(priv);
 
        queue_work(priv->workqueue, &priv->post_associate.work);
 
@@ -7114,13 +4606,18 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk
  * See the level definitions in iwl for details.
  */
 
-static ssize_t show_debug_level(struct device_driver *d, char *buf)
+static ssize_t show_debug_level(struct device *d,
+                               struct device_attribute *attr, char *buf)
 {
-       return sprintf(buf, "0x%08X\n", iwl_debug_level);
+       struct iwl_priv *priv = d->driver_data;
+
+       return sprintf(buf, "0x%08X\n", priv->debug_level);
 }
-static ssize_t store_debug_level(struct device_driver *d,
+static ssize_t store_debug_level(struct device *d,
+                               struct device_attribute *attr,
                                 const char *buf, size_t count)
 {
+       struct iwl_priv *priv = d->driver_data;
        char *p = (char *)buf;
        u32 val;
 
@@ -7129,17 +4626,37 @@ static ssize_t store_debug_level(struct device_driver *d,
                printk(KERN_INFO DRV_NAME
                       ": %s is not in hex or decimal form.\n", buf);
        else
-               iwl_debug_level = val;
+               priv->debug_level = val;
 
        return strnlen(buf, count);
 }
 
-static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
-                  show_debug_level, store_debug_level);
+static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO,
+                       show_debug_level, store_debug_level);
+
 
 #endif /* CONFIG_IWLWIFI_DEBUG */
 
 
+static ssize_t show_version(struct device *d,
+                               struct device_attribute *attr, char *buf)
+{
+       struct iwl_priv *priv = d->driver_data;
+       struct iwl_alive_resp *palive = &priv->card_alive;
+
+       if (palive->is_valid)
+               return sprintf(buf, "fw version: 0x%01X.0x%01X.0x%01X.0x%01X\n"
+                                   "fw type: 0x%01X 0x%01X\n",
+                               palive->ucode_major, palive->ucode_minor,
+                               palive->sw_rev[0], palive->sw_rev[1],
+                               palive->ver_type, palive->ver_subtype);
+
+       else
+               return sprintf(buf, "fw not loaded\n");
+}
+
+static DEVICE_ATTR(version, S_IWUSR | S_IRUGO, show_version, NULL);
+
 static ssize_t show_temperature(struct device *d,
                                struct device_attribute *attr, char *buf)
 {
@@ -7372,20 +4889,11 @@ static ssize_t store_power_level(struct device *d,
                goto out;
        }
 
-       if ((mode < 1) || (mode > IWL_POWER_LIMIT) || (mode == IWL_POWER_AC))
-               mode = IWL_POWER_AC;
-       else
-               mode |= IWL_POWER_ENABLED;
-
-       if (mode != priv->power_mode) {
-               rc = iwl4965_send_power_mode(priv, IWL_POWER_LEVEL(mode));
-               if (rc) {
-                       IWL_DEBUG_MAC80211("failed setting power mode.\n");
-                       goto out;
-               }
-               priv->power_mode = mode;
+       rc = iwl_power_set_user_mode(priv, mode);
+       if (rc) {
+               IWL_DEBUG_MAC80211("failed setting power mode.\n");
+               goto out;
        }
-
        rc = count;
 
  out:
@@ -7415,7 +4923,7 @@ static ssize_t show_power_level(struct device *d,
                                struct device_attribute *attr, char *buf)
 {
        struct iwl_priv *priv = dev_get_drvdata(d);
-       int level = IWL_POWER_LEVEL(priv->power_mode);
+       int level = priv->power_data.power_mode;
        char *p = buf;
 
        p += sprintf(p, "%d ", level);
@@ -7433,14 +4941,14 @@ static ssize_t show_power_level(struct device *d,
                             timeout_duration[level - 1] / 1000,
                             period_duration[level - 1] / 1000);
        }
-
+/*
        if (!(priv->power_mode & IWL_POWER_ENABLED))
                p += sprintf(p, " OFF\n");
        else
                p += sprintf(p, " \n");
-
+*/
+       p += sprintf(p, " \n");
        return (p - buf + 1);
-
 }
 
 static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
@@ -7493,44 +5001,6 @@ static ssize_t show_statistics(struct device *d,
 
 static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL);
 
-static ssize_t show_antenna(struct device *d,
-                           struct device_attribute *attr, char *buf)
-{
-       struct iwl_priv *priv = dev_get_drvdata(d);
-
-       if (!iwl_is_alive(priv))
-               return -EAGAIN;
-
-       return sprintf(buf, "%d\n", priv->antenna);
-}
-
-static ssize_t store_antenna(struct device *d,
-                            struct device_attribute *attr,
-                            const char *buf, size_t count)
-{
-       int ant;
-       struct iwl_priv *priv = dev_get_drvdata(d);
-
-       if (count == 0)
-               return 0;
-
-       if (sscanf(buf, "%1i", &ant) != 1) {
-               IWL_DEBUG_INFO("not in hex or decimal form.\n");
-               return count;
-       }
-
-       if ((ant >= 0) && (ant <= 2)) {
-               IWL_DEBUG_INFO("Setting antenna select to %d.\n", ant);
-               priv->antenna = (enum iwl4965_antenna)ant;
-       } else
-               IWL_DEBUG_INFO("Bad antenna select value %d.\n", ant);
-
-
-       return count;
-}
-
-static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna);
-
 static ssize_t show_status(struct device *d,
                           struct device_attribute *attr, char *buf)
 {
@@ -7542,34 +5012,6 @@ static ssize_t show_status(struct device *d,
 
 static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
 
-static ssize_t dump_error_log(struct device *d,
-                             struct device_attribute *attr,
-                             const char *buf, size_t count)
-{
-       char *p = (char *)buf;
-
-       if (p[0] == '1')
-               iwl4965_dump_nic_error_log((struct iwl_priv *)d->driver_data);
-
-       return strnlen(buf, count);
-}
-
-static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log);
-
-static ssize_t dump_event_log(struct device *d,
-                             struct device_attribute *attr,
-                             const char *buf, size_t count)
-{
-       char *p = (char *)buf;
-
-       if (p[0] == '1')
-               iwl4965_dump_nic_event_log((struct iwl_priv *)d->driver_data);
-
-       return strnlen(buf, count);
-}
-
-static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);
-
 /*****************************************************************************
  *
  * driver setup and teardown
@@ -7590,9 +5032,10 @@ static void iwl4965_setup_deferred_work(struct iwl_priv *priv)
        INIT_WORK(&priv->abort_scan, iwl4965_bg_abort_scan);
        INIT_WORK(&priv->rf_kill, iwl4965_bg_rf_kill);
        INIT_WORK(&priv->beacon_update, iwl4965_bg_beacon_update);
+       INIT_WORK(&priv->set_monitor, iwl4965_bg_set_monitor);
        INIT_DELAYED_WORK(&priv->post_associate, iwl4965_bg_post_associate);
-       INIT_DELAYED_WORK(&priv->init_alive_start, iwl4965_bg_init_alive_start);
-       INIT_DELAYED_WORK(&priv->alive_start, iwl4965_bg_alive_start);
+       INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
+       INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
        INIT_DELAYED_WORK(&priv->scan_check, iwl4965_bg_scan_check);
 
        iwl4965_hw_setup_deferred_work(priv);
@@ -7613,10 +5056,7 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv)
 }
 
 static struct attribute *iwl4965_sysfs_entries[] = {
-       &dev_attr_antenna.attr,
        &dev_attr_channels.attr,
-       &dev_attr_dump_errors.attr,
-       &dev_attr_dump_events.attr,
        &dev_attr_flags.attr,
        &dev_attr_filter_flags.attr,
 #ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
@@ -7629,6 +5069,10 @@ static struct attribute *iwl4965_sysfs_entries[] = {
        &dev_attr_status.attr,
        &dev_attr_temperature.attr,
        &dev_attr_tx_power.attr,
+#ifdef CONFIG_IWLWIFI_DEBUG
+       &dev_attr_debug_level.attr,
+#endif
+       &dev_attr_version.attr,
 
        NULL
 };
@@ -7678,7 +5122,9 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        /* Disabling hardware scan means that mac80211 will perform scans
         * "the hard way", rather than using device's scan. */
        if (cfg->mod_params->disable_hw_scan) {
-               IWL_DEBUG_INFO("Disabling hw_scan\n");
+               if (cfg->mod_params->debug & IWL_DL_INFO)
+                       dev_printk(KERN_DEBUG, &(pdev->dev),
+                                  "Disabling hw_scan\n");
                iwl4965_hw_ops.hw_scan = NULL;
        }
 
@@ -7697,7 +5143,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        priv->pci_dev = pdev;
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-       iwl_debug_level = priv->cfg->mod_params->debug;
+       priv->debug_level = priv->cfg->mod_params->debug;
        atomic_set(&priv->restrict_refcnt, 0);
 #endif
 
@@ -7711,13 +5157,19 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 
        pci_set_master(pdev);
 
-       err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+       err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
        if (!err)
-               err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+               err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+       if (err) {
+               err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+               if (!err)
+                       err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+               /* both attempts failed: */
                if (err) {
-                       printk(KERN_WARNING DRV_NAME
-                               ": No suitable DMA available.\n");
+                       printk(KERN_WARNING "%s: No suitable DMA available.\n",
+                               DRV_NAME);
                        goto out_pci_disable_device;
+               }
        }
 
        err = pci_request_regions(pdev, DRV_NAME);
@@ -7743,31 +5195,31 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
                (unsigned long long) pci_resource_len(pdev, 0));
        IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base);
 
+       iwl_hw_detect(priv);
        printk(KERN_INFO DRV_NAME
-               ": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name);
+               ": Detected Intel Wireless WiFi Link %s REV=0x%X\n",
+               priv->cfg->name, priv->hw_rev);
 
-       /*****************
-        * 4. Read EEPROM
-        *****************/
-       /* nic init */
-       iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
-               CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
-
-       iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-       err = iwl_poll_bit(priv, CSR_GP_CNTRL,
-               CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
-               CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+       /* amp init */
+       err = priv->cfg->ops->lib->apm_ops.init(priv);
        if (err < 0) {
-               IWL_DEBUG_INFO("Failed to init the card\n");
+               IWL_DEBUG_INFO("Failed to init APMG\n");
                goto out_iounmap;
        }
+       /*****************
+        * 4. Read EEPROM
+        *****************/
        /* Read the EEPROM */
        err = iwl_eeprom_init(priv);
        if (err) {
                IWL_ERROR("Unable to init EEPROM\n");
                goto out_iounmap;
        }
-       /* MAC Address location in EEPROM same for 3945/4965 */
+       err = iwl_eeprom_check_version(priv);
+       if (err)
+               goto out_iounmap;
+
+       /* extract MAC Address */
        iwl_eeprom_get_mac(priv, priv->mac_addr);
        IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr));
        SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
@@ -7778,16 +5230,16 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        /* Device-specific setup */
        if (priv->cfg->ops->lib->set_hw_params(priv)) {
                IWL_ERROR("failed to set hw parameters\n");
-               goto out_iounmap;
+               goto out_free_eeprom;
        }
 
        /*******************
-        * 6. Setup hw/priv
+        * 6. Setup priv
         *******************/
 
-       err = iwl_setup(priv);
+       err = iwl_init_drv(priv);
        if (err)
-               goto out_unset_hw_params;
+               goto out_free_eeprom;
        /* At this point both hw and priv are initialized. */
 
        /**********************************
@@ -7800,9 +5252,6 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
                IWL_DEBUG_INFO("Radio disabled.\n");
        }
 
-       if (priv->cfg->mod_params->enable_qos)
-               priv->qos_data.qos_enable = 1;
-
        /********************
         * 8. Setup services
         ********************/
@@ -7813,14 +5262,9 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group);
        if (err) {
                IWL_ERROR("failed to create sysfs device attributes\n");
-               goto out_unset_hw_params;
+               goto out_uninit_drv;
        }
 
-       err = iwl_dbgfs_register(priv, DRV_NAME);
-       if (err) {
-               IWL_ERROR("failed to create debugfs files\n");
-               goto out_remove_sysfs;
-       }
 
        iwl4965_setup_deferred_work(priv);
        iwl4965_setup_rx_handlers(priv);
@@ -7831,14 +5275,28 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        pci_save_state(pdev);
        pci_disable_device(pdev);
 
+       /**********************************
+        * 10. Setup and register mac80211
+        **********************************/
+
+       err = iwl_setup_mac(priv);
+       if (err)
+               goto out_remove_sysfs;
+
+       err = iwl_dbgfs_register(priv, DRV_NAME);
+       if (err)
+               IWL_ERROR("failed to create debugfs files\n");
+
        /* notify iwlcore to init */
        iwlcore_low_level_notify(priv, IWLCORE_INIT_EVT);
        return 0;
 
  out_remove_sysfs:
        sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
- out_unset_hw_params:
-       iwl4965_unset_hw_params(priv);
+ out_uninit_drv:
+       iwl_uninit_drv(priv);
+ out_free_eeprom:
+       iwl_eeprom_free(priv);
  out_iounmap:
        pci_iounmap(pdev, priv->hw_base);
  out_pci_release_regions:
@@ -7864,6 +5322,9 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
 
        IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n");
 
+       iwl_dbgfs_unregister(priv);
+       sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
+
        if (priv->mac80211_registered) {
                ieee80211_unregister_hw(priv->hw);
                priv->mac80211_registered = 0;
@@ -7891,17 +5352,15 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
        }
 
        iwlcore_low_level_notify(priv, IWLCORE_REMOVE_EVT);
-       iwl_dbgfs_unregister(priv);
-       sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
 
        iwl4965_dealloc_ucode_pci(priv);
 
        if (priv->rxq.bd)
-               iwl4965_rx_queue_free(priv, &priv->rxq);
-       iwl4965_hw_txq_ctx_free(priv);
+               iwl_rx_queue_free(priv, &priv->rxq);
+       iwl_hw_txq_ctx_free(priv);
 
-       iwl4965_unset_hw_params(priv);
        iwlcore_clear_stations_table(priv);
+       iwl_eeprom_free(priv);
 
 
        /*netif_stop_queue(dev); */
@@ -7918,8 +5377,7 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
        pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
 
-       iwl_free_channel_map(priv);
-       iwl4965_free_geos(priv);
+       iwl_uninit_drv(priv);
 
        if (priv->ibss_beacon)
                dev_kfree_skb(priv->ibss_beacon);
@@ -7969,6 +5427,11 @@ static int iwl4965_pci_resume(struct pci_dev *pdev)
 static struct pci_device_id iwl_hw_card_ids[] = {
        {IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)},
        {IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)},
+#ifdef CONFIG_IWL5000
+       {IWL_PCI_DEVICE(0x4235, PCI_ANY_ID, iwl5300_agn_cfg)},
+       {IWL_PCI_DEVICE(0x4232, PCI_ANY_ID, iwl5100_agn_cfg)},
+       {IWL_PCI_DEVICE(0x423A, PCI_ANY_ID, iwl5350_agn_cfg)},
+#endif /* CONFIG_IWL5000 */
        {0}
 };
 MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
@@ -8002,20 +5465,9 @@ static int __init iwl4965_init(void)
                IWL_ERROR("Unable to initialize PCI module\n");
                goto error_register;
        }
-#ifdef CONFIG_IWLWIFI_DEBUG
-       ret = driver_create_file(&iwl_driver.driver, &driver_attr_debug_level);
-       if (ret) {
-               IWL_ERROR("Unable to create driver sysfs file\n");
-               goto error_debug;
-       }
-#endif
 
        return ret;
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-error_debug:
-       pci_unregister_driver(&iwl_driver);
-#endif
 error_register:
        iwl4965_rate_control_unregister();
        return ret;
@@ -8023,9 +5475,6 @@ error_register:
 
 static void __exit iwl4965_exit(void)
 {
-#ifdef CONFIG_IWLWIFI_DEBUG
-       driver_remove_file(&iwl_driver.driver, &driver_attr_debug_level);
-#endif
        pci_unregister_driver(&iwl_driver);
        iwl4965_rate_control_unregister();
 }
index f0724e31adfda477218a907af49dbcc573312da4..02080a3682a91787a6e5dffb2986d826f97272b9 100644 (file)
@@ -1,9 +1,5 @@
-libertas-objs := main.o wext.o \
-               rx.o tx.o cmd.o           \
-               cmdresp.o scan.o          \
-               11d.o             \
-               debugfs.o         \
-               ethtool.o assoc.o
+libertas-objs := main.o wext.o rx.o tx.o cmd.o cmdresp.o scan.o 11d.o  \
+                debugfs.o persistcfg.o ethtool.o assoc.o
 
 usb8xxx-objs += if_usb.o
 libertas_cs-objs += if_cs.o
index c9c3640ce9fbb4978d4fd06cf06355f0b7da4faa..a267d6e65f03e82df3ef7f22403117a5fb3b003a 100644 (file)
@@ -603,7 +603,8 @@ static int assoc_helper_channel(struct lbs_private *priv,
                /* Change mesh channel first; 21.p21 firmware won't let
                   you change channel otherwise (even though it'll return
                   an error to this */
-               lbs_mesh_config(priv, 0, assoc_req->channel);
+               lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
+                               assoc_req->channel);
        }
 
        lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
@@ -642,7 +643,8 @@ static int assoc_helper_channel(struct lbs_private *priv,
 
  restore_mesh:
        if (priv->mesh_dev)
-               lbs_mesh_config(priv, 1, priv->curbssparams.channel);
+               lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
+                               priv->curbssparams.channel);
 
  done:
        lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
@@ -1248,7 +1250,7 @@ static int get_common_rates(struct lbs_private *priv,
        lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
        lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
 
-       if (!priv->auto_rate) {
+       if (!priv->enablehwauto) {
                for (i = 0; i < tmp_size; i++) {
                        if (tmp[i] == priv->cur_rate)
                                goto done;
index 8124fd9b1353523c603e679914d2fd839ac6f97b..75427e61898dfbecb84d7db4024e34ae254e723b 100644 (file)
@@ -4,6 +4,7 @@
   */
 
 #include <net/iw_handler.h>
+#include <net/ieee80211.h>
 #include <linux/kfifo.h>
 #include "host.h"
 #include "hostcmd.h"
@@ -109,7 +110,7 @@ int lbs_update_hw_spec(struct lbs_private *priv)
         * CF card    firmware 5.0.16p0:   cap 0x00000303
         * USB dongle firmware 5.110.17p2: cap 0x00000303
         */
-       printk("libertas: %s, fw %u.%u.%up%u, cap 0x%08x\n",
+       lbs_pr_info("%s, fw %u.%u.%up%u, cap 0x%08x\n",
                print_mac(mac, cmd.permanentaddr),
                priv->fwrelease >> 24 & 0xff,
                priv->fwrelease >> 16 & 0xff,
@@ -675,58 +676,60 @@ static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd,
        return 0;
 }
 
-static int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
-                                             struct cmd_ds_command *cmd,
-                                             u16 cmd_action)
+static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok)
 {
-       struct cmd_ds_802_11_rate_adapt_rateset
-       *rateadapt = &cmd->params.rateset;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-       cmd->size =
-           cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset)
-                            + S_DS_GEN);
-       cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET);
-
-       rateadapt->action = cpu_to_le16(cmd_action);
-       rateadapt->enablehwauto = cpu_to_le16(priv->enablehwauto);
-       rateadapt->bitmap = cpu_to_le16(priv->ratebitmap);
-
-       lbs_deb_leave(LBS_DEB_CMD);
-       return 0;
+/*             Bit     Rate
+*              15:13 Reserved
+*              12    54 Mbps
+*              11    48 Mbps
+*              10    36 Mbps
+*              9     24 Mbps
+*              8     18 Mbps
+*              7     12 Mbps
+*              6     9 Mbps
+*              5     6 Mbps
+*              4     Reserved
+*              3     11 Mbps
+*              2     5.5 Mbps
+*              1     2 Mbps
+*              0     1 Mbps
+**/
+
+       uint16_t ratemask;
+       int i = lbs_data_rate_to_fw_index(rate);
+       if (lower_rates_ok)
+               ratemask = (0x1fef >> (12 - i));
+       else
+               ratemask = (1 << i);
+       return cpu_to_le16(ratemask);
 }
 
-/**
- *  @brief Get the current data rate
- *
- *  @param priv        A pointer to struct lbs_private structure
- *
- *  @return            The data rate on success, error on failure
- */
-int lbs_get_data_rate(struct lbs_private *priv)
+int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
+                                     uint16_t cmd_action)
 {
-       struct cmd_ds_802_11_data_rate cmd;
-       int ret = -1;
+       struct cmd_ds_802_11_rate_adapt_rateset cmd;
+       int ret;
 
        lbs_deb_enter(LBS_DEB_CMD);
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-       cmd.action = cpu_to_le16(CMD_ACT_GET_TX_RATE);
-
-       ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
-       if (ret)
-               goto out;
+       if (!priv->cur_rate && !priv->enablehwauto)
+               return -EINVAL;
 
-       lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof (cmd));
+       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
 
-       ret = (int) lbs_fw_index_to_data_rate(cmd.rates[0]);
-       lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", ret);
+       cmd.action = cpu_to_le16(cmd_action);
+       cmd.enablehwauto = cpu_to_le16(priv->enablehwauto);
+       cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto);
+       ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd);
+       if (!ret && cmd_action == CMD_ACT_GET) {
+               priv->ratebitmap = le16_to_cpu(cmd.bitmap);
+               priv->enablehwauto = le16_to_cpu(cmd.enablehwauto);
+       }
 
-out:
        lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
        return ret;
 }
+EXPORT_SYMBOL_GPL(lbs_cmd_802_11_rate_adapt_rateset);
 
 /**
  *  @brief Set the data rate
@@ -778,28 +781,6 @@ out:
        return ret;
 }
 
-static int lbs_cmd_mac_multicast_adr(struct lbs_private *priv,
-                                     struct cmd_ds_command *cmd,
-                                     u16 cmd_action)
-{
-       struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-       cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
-                            S_DS_GEN);
-       cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR);
-
-       lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs);
-       pMCastAdr->action = cpu_to_le16(cmd_action);
-       pMCastAdr->nr_of_adrs =
-           cpu_to_le16((u16) priv->nr_of_multicastmacaddr);
-       memcpy(pMCastAdr->maclist, priv->multicastlist,
-              priv->nr_of_multicastmacaddr * ETH_ALEN);
-
-       lbs_deb_leave(LBS_DEB_CMD);
-       return 0;
-}
-
 /**
  *  @brief Get the radio channel
  *
@@ -1052,24 +1033,69 @@ int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
        return ret;
 }
 
-int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan)
+int lbs_mesh_config_send(struct lbs_private *priv,
+                        struct cmd_ds_mesh_config *cmd,
+                        uint16_t action, uint16_t type)
+{
+       int ret;
+
+       lbs_deb_enter(LBS_DEB_CMD);
+
+       cmd->hdr.command = cpu_to_le16(CMD_MESH_CONFIG);
+       cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
+       cmd->hdr.result = 0;
+
+       cmd->type = cpu_to_le16(type);
+       cmd->action = cpu_to_le16(action);
+
+       ret = lbs_cmd_with_response(priv, CMD_MESH_CONFIG, cmd);
+
+       lbs_deb_leave(LBS_DEB_CMD);
+       return ret;
+}
+
+/* This function is the CMD_MESH_CONFIG legacy function.  It only handles the
+ * START and STOP actions.  The extended actions supported by CMD_MESH_CONFIG
+ * are all handled by preparing a struct cmd_ds_mesh_config and passing it to
+ * lbs_mesh_config_send.
+ */
+int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
 {
        struct cmd_ds_mesh_config cmd;
+       struct mrvl_meshie *ie;
 
        memset(&cmd, 0, sizeof(cmd));
-       cmd.action = cpu_to_le16(enable);
        cmd.channel = cpu_to_le16(chan);
-       cmd.type = cpu_to_le16(priv->mesh_tlv);
-       cmd.hdr.size = cpu_to_le16(sizeof(cmd));
-
-       if (enable) {
-               cmd.length = cpu_to_le16(priv->mesh_ssid_len);
-               memcpy(cmd.data, priv->mesh_ssid, priv->mesh_ssid_len);
+       ie = (struct mrvl_meshie *)cmd.data;
+
+       switch (action) {
+       case CMD_ACT_MESH_CONFIG_START:
+               ie->hdr.id = MFIE_TYPE_GENERIC;
+               ie->val.oui[0] = 0x00;
+               ie->val.oui[1] = 0x50;
+               ie->val.oui[2] = 0x43;
+               ie->val.type = MARVELL_MESH_IE_TYPE;
+               ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
+               ie->val.version = MARVELL_MESH_IE_VERSION;
+               ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
+               ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
+               ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
+               ie->val.mesh_id_len = priv->mesh_ssid_len;
+               memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
+               ie->hdr.len = sizeof(struct mrvl_meshie_val) -
+                       IW_ESSID_MAX_SIZE + priv->mesh_ssid_len;
+               cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
+               break;
+       case CMD_ACT_MESH_CONFIG_STOP:
+               break;
+       default:
+               return -1;
        }
-       lbs_deb_cmd("mesh config enable %d TLV %x channel %d SSID %s\n",
-                   enable, priv->mesh_tlv, chan,
+       lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
+                   action, priv->mesh_tlv, chan,
                    escape_essid(priv->mesh_ssid, priv->mesh_ssid_len));
-       return lbs_cmd_with_response(priv, CMD_MESH_CONFIG, &cmd);
+
+       return lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
 }
 
 static int lbs_cmd_bcn_ctrl(struct lbs_private * priv,
@@ -1144,7 +1170,7 @@ static void lbs_submit_command(struct lbs_private *priv,
        struct cmd_header *cmd;
        uint16_t cmdsize;
        uint16_t command;
-       int timeo = 5 * HZ;
+       int timeo = 3 * HZ;
        int ret;
 
        lbs_deb_enter(LBS_DEB_HOST);
@@ -1162,7 +1188,7 @@ static void lbs_submit_command(struct lbs_private *priv,
        /* These commands take longer */
        if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE ||
            command == CMD_802_11_AUTHENTICATE)
-               timeo = 10 * HZ;
+               timeo = 5 * HZ;
 
        lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n",
                     command, le16_to_cpu(cmd->seqnum), cmdsize);
@@ -1174,7 +1200,7 @@ static void lbs_submit_command(struct lbs_private *priv,
                lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret);
                /* Let the timer kick in and retry, and potentially reset
                   the whole thing if the condition persists */
-               timeo = HZ;
+               timeo = HZ/4;
        }
 
        /* Setup the timer after transmit command */
@@ -1279,8 +1305,7 @@ void lbs_set_mac_control(struct lbs_private *priv)
        cmd.action = cpu_to_le16(priv->mac_control);
        cmd.reserved = 0;
 
-       lbs_cmd_async(priv, CMD_MAC_CONTROL,
-               &cmd.hdr, sizeof(cmd));
+       lbs_cmd_async(priv, CMD_MAC_CONTROL, &cmd.hdr, sizeof(cmd));
 
        lbs_deb_leave(LBS_DEB_CMD);
 }
@@ -1387,15 +1412,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
                                                 cmd_action, pdata_buf);
                break;
 
-       case CMD_802_11_RATE_ADAPT_RATESET:
-               ret = lbs_cmd_802_11_rate_adapt_rateset(priv,
-                                                        cmdptr, cmd_action);
-               break;
-
-       case CMD_MAC_MULTICAST_ADR:
-               ret = lbs_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
-               break;
-
        case CMD_802_11_MONITOR_MODE:
                ret = lbs_cmd_802_11_monitor_mode(cmdptr,
                                          cmd_action, pdata_buf);
@@ -1484,7 +1500,7 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
                ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
                break;
        default:
-               lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no);
+               lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no);
                ret = -1;
                break;
        }
index 3dfc2d43c22469805aa81ad5ad1076f8e5e26528..a53b51f8bdb4d9c6020699d0b2749337d39e0cbb 100644 (file)
@@ -34,18 +34,22 @@ int lbs_update_hw_spec(struct lbs_private *priv);
 int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
                    struct cmd_ds_mesh_access *cmd);
 
-int lbs_get_data_rate(struct lbs_private *priv);
 int lbs_set_data_rate(struct lbs_private *priv, u8 rate);
 
 int lbs_get_channel(struct lbs_private *priv);
 int lbs_set_channel(struct lbs_private *priv, u8 channel);
 
+int lbs_mesh_config_send(struct lbs_private *priv,
+                        struct cmd_ds_mesh_config *cmd,
+                        uint16_t action, uint16_t type);
 int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
 
 int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria);
 int lbs_suspend(struct lbs_private *priv);
-int lbs_resume(struct lbs_private *priv);
+void lbs_resume(struct lbs_private *priv);
 
+int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
+                                     uint16_t cmd_action);
 int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
                                      uint16_t cmd_action, uint16_t *timeout);
 int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
index 5abecb7673e6300e74f906862b7a9fe7a77457a1..24de3c3cf877e1da4bb13dfc48573847316fa559 100644 (file)
@@ -203,22 +203,6 @@ static int lbs_ret_802_11_rf_tx_power(struct lbs_private *priv,
        return 0;
 }
 
-static int lbs_ret_802_11_rate_adapt_rateset(struct lbs_private *priv,
-                                             struct cmd_ds_command *resp)
-{
-       struct cmd_ds_802_11_rate_adapt_rateset *rates = &resp->params.rateset;
-
-       lbs_deb_enter(LBS_DEB_CMD);
-
-       if (rates->action == CMD_ACT_GET) {
-               priv->enablehwauto = le16_to_cpu(rates->enablehwauto);
-               priv->ratebitmap = le16_to_cpu(rates->bitmap);
-       }
-
-       lbs_deb_leave(LBS_DEB_CMD);
-       return 0;
-}
-
 static int lbs_ret_802_11_rssi(struct lbs_private *priv,
                                struct cmd_ds_command *resp)
 {
@@ -316,16 +300,11 @@ static inline int handle_cmd_response(struct lbs_private *priv,
 
                break;
 
-       case CMD_RET(CMD_MAC_MULTICAST_ADR):
        case CMD_RET(CMD_802_11_RESET):
        case CMD_RET(CMD_802_11_AUTHENTICATE):
        case CMD_RET(CMD_802_11_BEACON_STOP):
                break;
 
-       case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET):
-               ret = lbs_ret_802_11_rate_adapt_rateset(priv, resp);
-               break;
-
        case CMD_RET(CMD_802_11_RSSI):
                ret = lbs_ret_802_11_rssi(priv, resp);
                break;
@@ -376,8 +355,8 @@ static inline int handle_cmd_response(struct lbs_private *priv,
                break;
 
        default:
-               lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n",
-                            le16_to_cpu(resp->command));
+               lbs_pr_err("CMD_RESP: unknown cmd response 0x%04x\n",
+                          le16_to_cpu(resp->command));
                break;
        }
        lbs_deb_leave(LBS_DEB_HOST);
index b652fa301e19ae45a8a5c1be3ce4c669e7c61451..a8ac974dacaccf8650185699dfcba31751b2cac8 100644 (file)
@@ -60,13 +60,17 @@ void lbs_mac_event_disconnected(struct lbs_private *priv);
 
 void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str);
 
+/* persistcfg.c */
+void lbs_persist_config_init(struct net_device *net);
+void lbs_persist_config_remove(struct net_device *net);
+
 /* main.c */
 struct chan_freq_power *lbs_get_region_cfp_table(u8 region,
        int *cfp_no);
 struct lbs_private *lbs_add_card(void *card, struct device *dmdev);
-int lbs_remove_card(struct lbs_private *priv);
+void lbs_remove_card(struct lbs_private *priv);
 int lbs_start_card(struct lbs_private *priv);
-int lbs_stop_card(struct lbs_private *priv);
+void lbs_stop_card(struct lbs_private *priv);
 void lbs_host_to_card_done(struct lbs_private *priv);
 
 int lbs_update_channel(struct lbs_private *priv);
index d395201110628a9d16dda6bf6c0a4b0e310dded5..12e687550bcefd6b7be7f5d30a7bcc6ac75551fb 100644 (file)
@@ -40,6 +40,7 @@
 #define LBS_DEB_THREAD 0x00100000
 #define LBS_DEB_HEX    0x00200000
 #define LBS_DEB_SDIO   0x00400000
+#define LBS_DEB_SYSFS  0x00800000
 
 extern unsigned int lbs_debug;
 
@@ -81,7 +82,8 @@ do { if ((lbs_debug & (grp)) == (grp)) \
 #define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args)
 #define lbs_deb_cs(fmt, args...)        LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args)
 #define lbs_deb_thread(fmt, args...)    LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args)
-#define lbs_deb_sdio(fmt, args...)      LBS_DEB_LL(LBS_DEB_SDIO, " thread", fmt, ##args)
+#define lbs_deb_sdio(fmt, args...)      LBS_DEB_LL(LBS_DEB_SDIO, " sdio", fmt, ##args)
+#define lbs_deb_sysfs(fmt, args...)     LBS_DEB_LL(LBS_DEB_SYSFS, " sysfs", fmt, ##args)
 
 #define lbs_pr_info(format, args...) \
        printk(KERN_INFO DRV_NAME": " format, ## args)
@@ -170,6 +172,16 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
 
 #define MARVELL_MESH_IE_LENGTH         9
 
+/* Values used to populate the struct mrvl_mesh_ie.  The only time you need this
+ * is when enabling the mesh using CMD_MESH_CONFIG.
+ */
+#define MARVELL_MESH_IE_TYPE           4
+#define MARVELL_MESH_IE_SUBTYPE                0
+#define MARVELL_MESH_IE_VERSION                0
+#define MARVELL_MESH_PROTO_ID_HWMP     0
+#define MARVELL_MESH_METRIC_ID         0
+#define MARVELL_MESH_CAPABILITY                0
+
 /** INT status Bit Definition*/
 #define MRVDRV_TX_DNLD_RDY             0x0001
 #define MRVDRV_RX_UPLD_RDY             0x0002
index 0d9edb9b11f5e0b300bdf44ad23fc1e32702c0b4..f5bb40c54d85128d4e3eae2f042e7291d763600b 100644 (file)
@@ -140,6 +140,8 @@ struct lbs_private {
        wait_queue_head_t waitq;
        struct workqueue_struct *work_thread;
 
+       struct work_struct mcast_work;
+
        /** Scanning */
        struct delayed_work scan_work;
        struct delayed_work assoc_work;
@@ -151,6 +153,7 @@ struct lbs_private {
 
        /** Hardware access */
        int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
+       void (*reset_card) (struct lbs_private *priv);
 
        /* Wake On LAN */
        uint32_t wol_criteria;
@@ -234,8 +237,8 @@ struct lbs_private {
        /** 802.11 statistics */
 //     struct cmd_DS_802_11_GET_STAT wlan802_11Stat;
 
-       u16 enablehwauto;
-       u16 ratebitmap;
+       uint16_t enablehwauto;
+       uint16_t ratebitmap;
 
        u32 fragthsd;
        u32 rtsthsd;
@@ -293,7 +296,6 @@ struct lbs_private {
 
        /** data rate stuff */
        u8 cur_rate;
-       u8 auto_rate;
 
        /** RF calibration data */
 
index 3915c3144fad0e7d282b56d2cd6af0a6e8e4bbe6..c92e41b4faf4f3047d8b36cc1e275ae9c95956f6 100644 (file)
@@ -256,6 +256,23 @@ enum cmd_mesh_access_opts {
        CMD_ACT_MESH_GET_AUTOSTART_ENABLED,
 };
 
+/* Define actions and types for CMD_MESH_CONFIG */
+enum cmd_mesh_config_actions {
+       CMD_ACT_MESH_CONFIG_STOP = 0,
+       CMD_ACT_MESH_CONFIG_START,
+       CMD_ACT_MESH_CONFIG_SET,
+       CMD_ACT_MESH_CONFIG_GET,
+};
+
+enum cmd_mesh_config_types {
+       CMD_TYPE_MESH_SET_BOOTFLAG = 1,
+       CMD_TYPE_MESH_SET_BOOTTIME,
+       CMD_TYPE_MESH_SET_DEF_CHANNEL,
+       CMD_TYPE_MESH_SET_MESH_IE,
+       CMD_TYPE_MESH_GET_DEFAULTS,
+       CMD_TYPE_MESH_GET_MESH_IE, /* GET_DEFAULTS is superset of GET_MESHIE */
+};
+
 /** Card Event definition */
 #define MACREG_INT_CODE_TX_PPA_FREE            0
 #define MACREG_INT_CODE_TX_DMA_DONE            1
index f29bc5bbda3ef1f39ebe98bea8526630cf97fee4..913b480211a9a19d30946d0eff0f1055307fddb3 100644 (file)
@@ -219,6 +219,7 @@ struct cmd_ds_mac_control {
 };
 
 struct cmd_ds_mac_multicast_adr {
+       struct cmd_header hdr;
        __le16 action;
        __le16 nr_of_adrs;
        u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
@@ -499,6 +500,7 @@ struct cmd_ds_802_11_data_rate {
 };
 
 struct cmd_ds_802_11_rate_adapt_rateset {
+       struct cmd_header hdr;
        __le16 action;
        __le16 enablehwauto;
        __le16 bitmap;
@@ -702,8 +704,6 @@ struct cmd_ds_command {
                struct cmd_ds_802_11_rf_tx_power txp;
                struct cmd_ds_802_11_rf_antenna rant;
                struct cmd_ds_802_11_monitor_mode monitor;
-               struct cmd_ds_802_11_rate_adapt_rateset rateset;
-               struct cmd_ds_mac_multicast_adr madr;
                struct cmd_ds_802_11_ad_hoc_join adj;
                struct cmd_ds_802_11_rssi rssi;
                struct cmd_ds_802_11_rssi_rsp rssirsp;
index 54280e292ea59ffea89aa9d7465442cf37c85463..873ab10a07868472b617c48bba10174d41b8f07b 100644 (file)
@@ -148,76 +148,72 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r
 {
        int i;
 
-       for (i = 0; i < 1000; i++) {
+       for (i = 0; i < 100000; i++) {
                u8 val = if_cs_read8(card, addr);
                if (val == reg)
                        return i;
-               udelay(500);
+               udelay(5);
        }
        return -ETIME;
 }
 
 
 
-/* Host control registers and their bit definitions */
+/* First the bitmasks for the host/card interrupt/status registers: */
+#define IF_CS_BIT_TX                   0x0001
+#define IF_CS_BIT_RX                   0x0002
+#define IF_CS_BIT_COMMAND              0x0004
+#define IF_CS_BIT_RESP                 0x0008
+#define IF_CS_BIT_EVENT                        0x0010
+#define        IF_CS_BIT_MASK                  0x001f
 
-#define IF_CS_H_STATUS                 0x00000000
-#define IF_CS_H_STATUS_TX_OVER         0x0001
-#define IF_CS_H_STATUS_RX_OVER         0x0002
-#define IF_CS_H_STATUS_DNLD_OVER       0x0004
+/* And now the individual registers and assorted masks */
+#define IF_CS_HOST_STATUS              0x00000000
 
-#define IF_CS_H_INT_CAUSE              0x00000002
-#define IF_CS_H_IC_TX_OVER             0x0001
-#define IF_CS_H_IC_RX_OVER             0x0002
-#define IF_CS_H_IC_DNLD_OVER           0x0004
-#define IF_CS_H_IC_POWER_DOWN          0x0008
-#define IF_CS_H_IC_HOST_EVENT          0x0010
-#define IF_CS_H_IC_MASK                        0x001f
+#define IF_CS_HOST_INT_CAUSE           0x00000002
 
-#define IF_CS_H_INT_MASK               0x00000004
-#define        IF_CS_H_IM_MASK                 0x001f
+#define IF_CS_HOST_INT_MASK            0x00000004
 
-#define IF_CS_H_WRITE_LEN              0x00000014
+#define IF_CS_HOST_WRITE               0x00000016
+#define IF_CS_HOST_WRITE_LEN           0x00000014
 
-#define IF_CS_H_WRITE                  0x00000016
+#define IF_CS_HOST_CMD                 0x0000001A
+#define IF_CS_HOST_CMD_LEN             0x00000018
 
-#define IF_CS_H_CMD_LEN                        0x00000018
+#define IF_CS_READ                     0x00000010
+#define IF_CS_READ_LEN                 0x00000024
 
-#define IF_CS_H_CMD                    0x0000001A
+#define IF_CS_CARD_CMD                 0x00000012
+#define IF_CS_CARD_CMD_LEN             0x00000030
 
-#define IF_CS_C_READ_LEN               0x00000024
+#define IF_CS_CARD_STATUS              0x00000020
+#define IF_CS_CARD_STATUS_MASK         0x7f00
 
-#define IF_CS_H_READ                   0x00000010
+#define IF_CS_CARD_INT_CAUSE           0x00000022
 
-/* Card control registers and their bit definitions */
-
-#define IF_CS_C_STATUS                 0x00000020
-#define IF_CS_C_S_TX_DNLD_RDY          0x0001
-#define IF_CS_C_S_RX_UPLD_RDY          0x0002
-#define IF_CS_C_S_CMD_DNLD_RDY         0x0004
-#define IF_CS_C_S_CMD_UPLD_RDY         0x0008
-#define IF_CS_C_S_CARDEVENT            0x0010
-#define IF_CS_C_S_MASK                 0x001f
-#define IF_CS_C_S_STATUS_MASK          0x7f00
-
-#define IF_CS_C_INT_CAUSE              0x00000022
-#define        IF_CS_C_IC_MASK                 0x001f
-
-#define IF_CS_C_SQ_READ_LOW            0x00000028
-#define IF_CS_C_SQ_HELPER_OK           0x10
-
-#define IF_CS_C_CMD_LEN                        0x00000030
-
-#define IF_CS_C_CMD                    0x00000012
+#define IF_CS_CARD_SQ_READ_LOW         0x00000028
+#define IF_CS_CARD_SQ_HELPER_OK                0x10
 
 #define IF_CS_SCRATCH                  0x0000003F
 
 
 
 /********************************************************************/
-/* I/O                                                              */
+/* I/O and interrupt handling                                       */
 /********************************************************************/
 
+static inline void if_cs_enable_ints(struct if_cs_card *card)
+{
+       lbs_deb_enter(LBS_DEB_CS);
+       if_cs_write16(card, IF_CS_HOST_INT_MASK, 0);
+}
+
+static inline void if_cs_disable_ints(struct if_cs_card *card)
+{
+       lbs_deb_enter(LBS_DEB_CS);
+       if_cs_write16(card, IF_CS_HOST_INT_MASK, IF_CS_BIT_MASK);
+}
+
 /*
  * Called from if_cs_host_to_card to send a command to the hardware
  */
@@ -228,11 +224,12 @@ static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb)
        int loops = 0;
 
        lbs_deb_enter(LBS_DEB_CS);
+       if_cs_disable_ints(card);
 
        /* Is hardware ready? */
        while (1) {
-               u16 val = if_cs_read16(card, IF_CS_C_STATUS);
-               if (val & IF_CS_C_S_CMD_DNLD_RDY)
+               u16 val = if_cs_read16(card, IF_CS_CARD_STATUS);
+               if (val & IF_CS_BIT_COMMAND)
                        break;
                if (++loops > 100) {
                        lbs_pr_err("card not ready for commands\n");
@@ -241,51 +238,56 @@ static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb)
                mdelay(1);
        }
 
-       if_cs_write16(card, IF_CS_H_CMD_LEN, nb);
+       if_cs_write16(card, IF_CS_HOST_CMD_LEN, nb);
 
-       if_cs_write16_rep(card, IF_CS_H_CMD, buf, nb / 2);
+       if_cs_write16_rep(card, IF_CS_HOST_CMD, buf, nb / 2);
        /* Are we supposed to transfer an odd amount of bytes? */
        if (nb & 1)
-               if_cs_write8(card, IF_CS_H_CMD, buf[nb-1]);
+               if_cs_write8(card, IF_CS_HOST_CMD, buf[nb-1]);
 
        /* "Assert the download over interrupt command in the Host
         * status register" */
-       if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);
+       if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND);
 
        /* "Assert the download over interrupt command in the Card
         * interrupt case register" */
-       if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);
+       if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND);
        ret = 0;
 
 done:
+       if_cs_enable_ints(card);
        lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
        return ret;
 }
 
-
 /*
  * Called from if_cs_host_to_card to send a data to the hardware
  */
 static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb)
 {
        struct if_cs_card *card = (struct if_cs_card *)priv->card;
+       u16 status;
 
        lbs_deb_enter(LBS_DEB_CS);
+       if_cs_disable_ints(card);
+
+       status = if_cs_read16(card, IF_CS_CARD_STATUS);
+       BUG_ON((status & IF_CS_BIT_TX) == 0);
 
-       if_cs_write16(card, IF_CS_H_WRITE_LEN, nb);
+       if_cs_write16(card, IF_CS_HOST_WRITE_LEN, nb);
 
        /* write even number of bytes, then odd byte if necessary */
-       if_cs_write16_rep(card, IF_CS_H_WRITE, buf, nb / 2);
+       if_cs_write16_rep(card, IF_CS_HOST_WRITE, buf, nb / 2);
        if (nb & 1)
-               if_cs_write8(card, IF_CS_H_WRITE, buf[nb-1]);
+               if_cs_write8(card, IF_CS_HOST_WRITE, buf[nb-1]);
 
-       if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_TX_OVER);
-       if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_STATUS_TX_OVER);
+       if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_TX);
+       if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_TX);
+       if_cs_enable_ints(card);
 
        lbs_deb_leave(LBS_DEB_CS);
 }
 
-
 /*
  * Get the command result out of the card.
  */
@@ -293,27 +295,28 @@ static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len)
 {
        unsigned long flags;
        int ret = -1;
-       u16 val;
+       u16 status;
 
        lbs_deb_enter(LBS_DEB_CS);
 
        /* is hardware ready? */
-       val = if_cs_read16(priv->card, IF_CS_C_STATUS);
-       if ((val & IF_CS_C_S_CMD_UPLD_RDY) == 0) {
-               lbs_pr_err("card not ready for CMD\n");
+       status = if_cs_read16(priv->card, IF_CS_CARD_STATUS);
+       if ((status & IF_CS_BIT_RESP) == 0) {
+               lbs_pr_err("no cmd response in card\n");
+               *len = 0;
                goto out;
        }
 
-       *len = if_cs_read16(priv->card, IF_CS_C_CMD_LEN);
+       *len = if_cs_read16(priv->card, IF_CS_CARD_CMD_LEN);
        if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) {
                lbs_pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len);
                goto out;
        }
 
        /* read even number of bytes, then odd byte if necessary */
-       if_cs_read16_rep(priv->card, IF_CS_C_CMD, data, *len/sizeof(u16));
+       if_cs_read16_rep(priv->card, IF_CS_CARD_CMD, data, *len/sizeof(u16));
        if (*len & 1)
-               data[*len-1] = if_cs_read8(priv->card, IF_CS_C_CMD);
+               data[*len-1] = if_cs_read8(priv->card, IF_CS_CARD_CMD);
 
        /* This is a workaround for a firmware that reports too much
         * bytes */
@@ -330,7 +333,6 @@ out:
        return ret;
 }
 
-
 static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
 {
        struct sk_buff *skb = NULL;
@@ -339,7 +341,7 @@ static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
 
        lbs_deb_enter(LBS_DEB_CS);
 
-       len = if_cs_read16(priv->card, IF_CS_C_READ_LEN);
+       len = if_cs_read16(priv->card, IF_CS_READ_LEN);
        if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
                lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len);
                priv->stats.rx_dropped++;
@@ -354,38 +356,19 @@ static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
        data = skb->data;
 
        /* read even number of bytes, then odd byte if necessary */
-       if_cs_read16_rep(priv->card, IF_CS_H_READ, data, len/sizeof(u16));
+       if_cs_read16_rep(priv->card, IF_CS_READ, data, len/sizeof(u16));
        if (len & 1)
-               data[len-1] = if_cs_read8(priv->card, IF_CS_H_READ);
+               data[len-1] = if_cs_read8(priv->card, IF_CS_READ);
 
 dat_err:
-       if_cs_write16(priv->card, IF_CS_H_STATUS, IF_CS_H_STATUS_RX_OVER);
-       if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_RX_OVER);
+       if_cs_write16(priv->card, IF_CS_HOST_STATUS, IF_CS_BIT_RX);
+       if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_RX);
 
 out:
        lbs_deb_leave_args(LBS_DEB_CS, "ret %p", skb);
        return skb;
 }
 
-
-
-/********************************************************************/
-/* Interrupts                                                       */
-/********************************************************************/
-
-static inline void if_cs_enable_ints(struct if_cs_card *card)
-{
-       lbs_deb_enter(LBS_DEB_CS);
-       if_cs_write16(card, IF_CS_H_INT_MASK, 0);
-}
-
-static inline void if_cs_disable_ints(struct if_cs_card *card)
-{
-       lbs_deb_enter(LBS_DEB_CS);
-       if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK);
-}
-
-
 static irqreturn_t if_cs_interrupt(int irq, void *data)
 {
        struct if_cs_card *card = data;
@@ -394,10 +377,8 @@ static irqreturn_t if_cs_interrupt(int irq, void *data)
 
        lbs_deb_enter(LBS_DEB_CS);
 
-       cause = if_cs_read16(card, IF_CS_C_INT_CAUSE);
-       if_cs_write16(card, IF_CS_C_INT_CAUSE, cause & IF_CS_C_IC_MASK);
-
-       lbs_deb_cs("cause 0x%04x\n", cause);
+       /* Ask card interrupt cause register if there is something for us */
+       cause = if_cs_read16(card, IF_CS_CARD_INT_CAUSE);
        if (cause == 0) {
                /* Not for us */
                return IRQ_NONE;
@@ -409,11 +390,11 @@ static irqreturn_t if_cs_interrupt(int irq, void *data)
                return IRQ_HANDLED;
        }
 
-       /* TODO: I'm not sure what the best ordering is */
-
-       cause = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK;
+       /* Clear interrupt cause */
+       if_cs_write16(card, IF_CS_CARD_INT_CAUSE, cause & IF_CS_BIT_MASK);
+       lbs_deb_cs("cause 0x%04x\n", cause);
 
-       if (cause & IF_CS_C_S_RX_UPLD_RDY) {
+       if (cause & IF_CS_BIT_RX) {
                struct sk_buff *skb;
                lbs_deb_cs("rx packet\n");
                skb = if_cs_receive_data(priv);
@@ -421,16 +402,16 @@ static irqreturn_t if_cs_interrupt(int irq, void *data)
                        lbs_process_rxed_packet(priv, skb);
        }
 
-       if (cause & IF_CS_H_IC_TX_OVER) {
-               lbs_deb_cs("tx over\n");
+       if (cause & IF_CS_BIT_TX) {
+               lbs_deb_cs("tx done\n");
                lbs_host_to_card_done(priv);
        }
 
-       if (cause & IF_CS_C_S_CMD_UPLD_RDY) {
+       if (cause & IF_CS_BIT_RESP) {
                unsigned long flags;
                u8 i;
 
-               lbs_deb_cs("cmd upload ready\n");
+               lbs_deb_cs("cmd resp\n");
                spin_lock_irqsave(&priv->driver_lock, flags);
                i = (priv->resp_idx == 0) ? 1 : 0;
                spin_unlock_irqrestore(&priv->driver_lock, flags);
@@ -444,15 +425,16 @@ static irqreturn_t if_cs_interrupt(int irq, void *data)
                spin_unlock_irqrestore(&priv->driver_lock, flags);
        }
 
-       if (cause & IF_CS_H_IC_HOST_EVENT) {
-               u16 event = if_cs_read16(priv->card, IF_CS_C_STATUS)
-                       & IF_CS_C_S_STATUS_MASK;
-               if_cs_write16(priv->card, IF_CS_H_INT_CAUSE,
-                       IF_CS_H_IC_HOST_EVENT);
-               lbs_deb_cs("eventcause 0x%04x\n", event);
+       if (cause & IF_CS_BIT_EVENT) {
+               u16 event = if_cs_read16(priv->card, IF_CS_CARD_STATUS)
+                       & IF_CS_CARD_STATUS_MASK;
+               if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE,
+                       IF_CS_BIT_EVENT);
+               lbs_deb_cs("host event 0x%04x\n", event);
                lbs_queue_event(priv, event >> 8 & 0xff);
        }
 
+       lbs_deb_leave(LBS_DEB_CS);
        return IRQ_HANDLED;
 }
 
@@ -514,26 +496,26 @@ static int if_cs_prog_helper(struct if_cs_card *card)
 
                /* "write the number of bytes to be sent to the I/O Command
                 * write length register" */
-               if_cs_write16(card, IF_CS_H_CMD_LEN, count);
+               if_cs_write16(card, IF_CS_HOST_CMD_LEN, count);
 
                /* "write this to I/O Command port register as 16 bit writes */
                if (count)
-                       if_cs_write16_rep(card, IF_CS_H_CMD,
+                       if_cs_write16_rep(card, IF_CS_HOST_CMD,
                                &fw->data[sent],
                                count >> 1);
 
                /* "Assert the download over interrupt command in the Host
                 * status register" */
-               if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);
+               if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND);
 
                /* "Assert the download over interrupt command in the Card
                 * interrupt case register" */
-               if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);
+               if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND);
 
                /* "The host polls the Card Status register ... for 50 ms before
                   declaring a failure */
-               ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS,
-                       IF_CS_C_S_CMD_DNLD_RDY);
+               ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS,
+                       IF_CS_BIT_COMMAND);
                if (ret < 0) {
                        lbs_pr_err("can't download helper at 0x%x, ret %d\n",
                                sent, ret);
@@ -575,14 +557,15 @@ static int if_cs_prog_real(struct if_cs_card *card)
        }
        lbs_deb_cs("fw size %td\n", fw->size);
 
-       ret = if_cs_poll_while_fw_download(card, IF_CS_C_SQ_READ_LOW, IF_CS_C_SQ_HELPER_OK);
+       ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_SQ_READ_LOW,
+               IF_CS_CARD_SQ_HELPER_OK);
        if (ret < 0) {
                lbs_pr_err("helper firmware doesn't answer\n");
                goto err_release;
        }
 
        for (sent = 0; sent < fw->size; sent += len) {
-               len = if_cs_read16(card, IF_CS_C_SQ_READ_LOW);
+               len = if_cs_read16(card, IF_CS_CARD_SQ_READ_LOW);
                if (len & 1) {
                        retry++;
                        lbs_pr_info("odd, need to retry this firmware block\n");
@@ -600,16 +583,16 @@ static int if_cs_prog_real(struct if_cs_card *card)
                }
 
 
-               if_cs_write16(card, IF_CS_H_CMD_LEN, len);
+               if_cs_write16(card, IF_CS_HOST_CMD_LEN, len);
 
-               if_cs_write16_rep(card, IF_CS_H_CMD,
+               if_cs_write16_rep(card, IF_CS_HOST_CMD,
                        &fw->data[sent],
                        (len+1) >> 1);
-               if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);
-               if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);
+               if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND);
+               if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND);
 
-               ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS,
-                       IF_CS_C_S_CMD_DNLD_RDY);
+               ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS,
+                       IF_CS_BIT_COMMAND);
                if (ret < 0) {
                        lbs_pr_err("can't download firmware at 0x%x\n", sent);
                        goto err_release;
@@ -837,7 +820,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
 
        /* Clear any interrupt cause that happend while sending
         * firmware/initializing card */
-       if_cs_write16(card, IF_CS_C_INT_CAUSE, IF_CS_C_IC_MASK);
+       if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK);
        if_cs_enable_ints(card);
 
        /* And finally bring the card up */
index 8032df72aaab59fa368783d82325befd23ee7dda..24783103a7ddb5bba1f34b48396040b38447774a 100644 (file)
@@ -7,6 +7,10 @@
 #include <linux/netdevice.h>
 #include <linux/usb.h>
 
+#ifdef CONFIG_OLPC
+#include <asm/olpc.h>
+#endif
+
 #define DRV_NAME "usb8xxx"
 
 #include "host.h"
@@ -146,6 +150,14 @@ static void if_usb_fw_timeo(unsigned long priv)
        wake_up(&cardp->fw_wq);
 }
 
+#ifdef CONFIG_OLPC
+static void if_usb_reset_olpc_card(struct lbs_private *priv)
+{
+       printk(KERN_CRIT "Resetting OLPC wireless via EC...\n");
+       olpc_ec_cmd(0x25, NULL, 0, NULL, 0);
+}
+#endif
+
 /**
  *  @brief sets the configuration values
  *  @param ifnum       interface number
@@ -231,6 +243,11 @@ static int if_usb_probe(struct usb_interface *intf,
        cardp->priv->fw_ready = 1;
 
        priv->hw_host_to_card = if_usb_host_to_card;
+#ifdef CONFIG_OLPC
+       if (machine_is_olpc())
+               priv->reset_card = if_usb_reset_olpc_card;
+#endif
+
        cardp->boot2_version = udev->descriptor.bcdDevice;
 
        if_usb_submit_rx_urb(cardp);
@@ -364,6 +381,11 @@ static int if_usb_reset_device(struct if_usb_card *cardp)
        ret = usb_reset_device(cardp->udev);
        msleep(100);
 
+#ifdef CONFIG_OLPC
+       if (ret && machine_is_olpc())
+               if_usb_reset_olpc_card(NULL);
+#endif
+
        lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
 
        return ret;
index acfc4bfcc26272e7e1184a24308e4bab70377a10..abd6d9ed8f4bff9bcc83f9dbdd30563cd572c399 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/if_arp.h>
 #include <linux/kthread.h>
 #include <linux/kfifo.h>
+#include <linux/stddef.h>
 
 #include <net/iw_handler.h>
 #include <net/ieee80211.h>
@@ -343,14 +344,15 @@ static ssize_t lbs_mesh_set(struct device *dev,
 {
        struct lbs_private *priv = to_net_dev(dev)->priv;
        int enable;
-       int ret;
+       int ret, action = CMD_ACT_MESH_CONFIG_STOP;
 
        sscanf(buf, "%x", &enable);
        enable = !!enable;
        if (enable == !!priv->mesh_dev)
                return count;
-
-       ret = lbs_mesh_config(priv, enable, priv->curbssparams.channel);
+       if (enable)
+               action = CMD_ACT_MESH_CONFIG_START;
+       ret = lbs_mesh_config(priv, action, priv->curbssparams.channel);
        if (ret)
                return ret;
 
@@ -446,6 +448,8 @@ static int lbs_mesh_stop(struct net_device *dev)
 
        spin_unlock_irq(&priv->driver_lock);
 
+       schedule_work(&priv->mcast_work);
+
        lbs_deb_leave(LBS_DEB_MESH);
        return 0;
 }
@@ -467,6 +471,8 @@ static int lbs_eth_stop(struct net_device *dev)
        netif_stop_queue(dev);
        spin_unlock_irq(&priv->driver_lock);
 
+       schedule_work(&priv->mcast_work);
+
        lbs_deb_leave(LBS_DEB_NET);
        return 0;
 }
@@ -563,89 +569,116 @@ done:
        return ret;
 }
 
-static int lbs_copy_multicast_address(struct lbs_private *priv,
-                                    struct net_device *dev)
+
+static inline int mac_in_list(unsigned char *list, int list_len,
+                             unsigned char *mac)
 {
-       int i = 0;
-       struct dev_mc_list *mcptr = dev->mc_list;
+       while (list_len) {
+               if (!memcmp(list, mac, ETH_ALEN))
+                       return 1;
+               list += ETH_ALEN;
+               list_len--;
+       }
+       return 0;
+}
+
+
+static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd,
+                              struct net_device *dev, int nr_addrs)
+{
+       int i = nr_addrs;
+       struct dev_mc_list *mc_list;
+       DECLARE_MAC_BUF(mac);
+
+       if ((dev->flags & (IFF_UP|IFF_MULTICAST)) != (IFF_UP|IFF_MULTICAST))
+               return nr_addrs;
+
+       netif_tx_lock_bh(dev);
+       for (mc_list = dev->mc_list; mc_list; mc_list = mc_list->next) {
+               if (mac_in_list(cmd->maclist, nr_addrs, mc_list->dmi_addr)) {
+                       lbs_deb_net("mcast address %s:%s skipped\n", dev->name,
+                                   print_mac(mac, mc_list->dmi_addr));
+                       continue;
+               }
 
-       for (i = 0; i < dev->mc_count; i++) {
-               memcpy(&priv->multicastlist[i], mcptr->dmi_addr, ETH_ALEN);
-               mcptr = mcptr->next;
+               if (i == MRVDRV_MAX_MULTICAST_LIST_SIZE)
+                       break;
+               memcpy(&cmd->maclist[6*i], mc_list->dmi_addr, ETH_ALEN);
+               lbs_deb_net("mcast address %s:%s added to filter\n", dev->name,
+                           print_mac(mac, mc_list->dmi_addr));
+               i++;
        }
+       netif_tx_unlock_bh(dev);
+       if (mc_list)
+               return -EOVERFLOW;
+
        return i;
 }
 
-static void lbs_set_multicast_list(struct net_device *dev)
+static void lbs_set_mcast_worker(struct work_struct *work)
 {
-       struct lbs_private *priv = dev->priv;
-       int old_mac_control;
-       DECLARE_MAC_BUF(mac);
+       struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work);
+       struct cmd_ds_mac_multicast_adr mcast_cmd;
+       int dev_flags;
+       int nr_addrs;
+       int old_mac_control = priv->mac_control;
 
        lbs_deb_enter(LBS_DEB_NET);
 
-       old_mac_control = priv->mac_control;
-
-       if (dev->flags & IFF_PROMISC) {
-               lbs_deb_net("enable promiscuous mode\n");
-               priv->mac_control |=
-                   CMD_ACT_MAC_PROMISCUOUS_ENABLE;
-               priv->mac_control &=
-                   ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE |
-                     CMD_ACT_MAC_MULTICAST_ENABLE);
-       } else {
-               /* Multicast */
-               priv->mac_control &=
-                   ~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
-
-               if (dev->flags & IFF_ALLMULTI || dev->mc_count >
-                   MRVDRV_MAX_MULTICAST_LIST_SIZE) {
-                       lbs_deb_net( "enabling all multicast\n");
-                       priv->mac_control |=
-                           CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
-                       priv->mac_control &=
-                           ~CMD_ACT_MAC_MULTICAST_ENABLE;
-               } else {
-                       priv->mac_control &=
-                           ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
-
-                       if (!dev->mc_count) {
-                               lbs_deb_net("no multicast addresses, "
-                                      "disabling multicast\n");
-                               priv->mac_control &=
-                                   ~CMD_ACT_MAC_MULTICAST_ENABLE;
-                       } else {
-                               int i;
-
-                               priv->mac_control |=
-                                   CMD_ACT_MAC_MULTICAST_ENABLE;
-
-                               priv->nr_of_multicastmacaddr =
-                                   lbs_copy_multicast_address(priv, dev);
-
-                               lbs_deb_net("multicast addresses: %d\n",
-                                      dev->mc_count);
-
-                               for (i = 0; i < dev->mc_count; i++) {
-                                       lbs_deb_net("Multicast address %d: %s\n",
-                                              i, print_mac(mac,
-                                              priv->multicastlist[i]));
-                               }
-                               /* send multicast addresses to firmware */
-                               lbs_prepare_and_send_command(priv,
-                                                     CMD_MAC_MULTICAST_ADR,
-                                                     CMD_ACT_SET, 0, 0,
-                                                     NULL);
-                       }
-               }
+       dev_flags = priv->dev->flags;
+       if (priv->mesh_dev)
+               dev_flags |= priv->mesh_dev->flags;
+
+       if (dev_flags & IFF_PROMISC) {
+               priv->mac_control |= CMD_ACT_MAC_PROMISCUOUS_ENABLE;
+               priv->mac_control &= ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE |
+                                      CMD_ACT_MAC_MULTICAST_ENABLE);
+               goto out_set_mac_control;
+       } else if (dev_flags & IFF_ALLMULTI) {
+       do_allmulti:
+               priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
+               priv->mac_control &= ~(CMD_ACT_MAC_PROMISCUOUS_ENABLE |
+                                      CMD_ACT_MAC_MULTICAST_ENABLE);
+               goto out_set_mac_control;
        }
 
+       /* Once for priv->dev, again for priv->mesh_dev if it exists */
+       nr_addrs = lbs_add_mcast_addrs(&mcast_cmd, priv->dev, 0);
+       if (nr_addrs >= 0 && priv->mesh_dev)
+               nr_addrs = lbs_add_mcast_addrs(&mcast_cmd, priv->mesh_dev, nr_addrs);
+       if (nr_addrs < 0)
+               goto do_allmulti;
+
+       if (nr_addrs) {
+               int size = offsetof(struct cmd_ds_mac_multicast_adr,
+                                   maclist[6*nr_addrs]);
+
+               mcast_cmd.action = cpu_to_le16(CMD_ACT_SET);
+               mcast_cmd.hdr.size = cpu_to_le16(size);
+               mcast_cmd.nr_of_adrs = cpu_to_le16(nr_addrs);
+
+               lbs_cmd_async(priv, CMD_MAC_MULTICAST_ADR, &mcast_cmd.hdr, size);
+
+               priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE;
+       } else
+               priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE;
+
+       priv->mac_control &= ~(CMD_ACT_MAC_PROMISCUOUS_ENABLE |
+                              CMD_ACT_MAC_ALL_MULTICAST_ENABLE);
+ out_set_mac_control:
        if (priv->mac_control != old_mac_control)
                lbs_set_mac_control(priv);
 
        lbs_deb_leave(LBS_DEB_NET);
 }
 
+static void lbs_set_multicast_list(struct net_device *dev)
+{
+       struct lbs_private *priv = dev->priv;
+
+       schedule_work(&priv->mcast_work);
+}
+
 /**
  *  @brief This function handles the major jobs in the LBS driver.
  *  It handles all events generated by firmware, RX data received
@@ -689,20 +722,20 @@ static int lbs_thread(void *data)
                        shouldsleep = 1;        /* Something is en route to the device already */
                else if (priv->tx_pending_len > 0)
                        shouldsleep = 0;        /* We've a packet to send */
+               else if (priv->resp_len[priv->resp_idx])
+                       shouldsleep = 0;        /* We have a command response */
                else if (priv->cur_cmd)
                        shouldsleep = 1;        /* Can't send a command; one already running */
                else if (!list_empty(&priv->cmdpendingq))
                        shouldsleep = 0;        /* We have a command to send */
                else if (__kfifo_len(priv->event_fifo))
                        shouldsleep = 0;        /* We have an event to process */
-               else if (priv->resp_len[priv->resp_idx])
-                       shouldsleep = 0;        /* We have a command response */
                else
                        shouldsleep = 1;        /* No command */
 
                if (shouldsleep) {
                        lbs_deb_thread("sleeping, connect_status %d, "
-                               "ps_mode %d, ps_state %d\n",
+                               "psmode %d, psstate %d\n",
                                priv->connect_status,
                                priv->psmode, priv->psstate);
                        spin_unlock_irq(&priv->driver_lock);
@@ -749,16 +782,21 @@ static int lbs_thread(void *data)
                if (priv->cmd_timed_out && priv->cur_cmd) {
                        struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
 
-                       if (++priv->nr_retries > 10) {
-                               lbs_pr_info("Excessive timeouts submitting command %x\n",
-                                           le16_to_cpu(cmdnode->cmdbuf->command));
+                       if (++priv->nr_retries > 3) {
+                               lbs_pr_info("Excessive timeouts submitting "
+                                       "command 0x%04x\n",
+                                       le16_to_cpu(cmdnode->cmdbuf->command));
                                lbs_complete_command(priv, cmdnode, -ETIMEDOUT);
                                priv->nr_retries = 0;
+                               if (priv->reset_card)
+                                       priv->reset_card(priv);
                        } else {
                                priv->cur_cmd = NULL;
                                priv->dnld_sent = DNLD_RES_RECEIVED;
-                               lbs_pr_info("requeueing command %x due to timeout (#%d)\n",
-                                           le16_to_cpu(cmdnode->cmdbuf->command), priv->nr_retries);
+                               lbs_pr_info("requeueing command 0x%04x due "
+                                       "to timeout (#%d)\n",
+                                       le16_to_cpu(cmdnode->cmdbuf->command),
+                                       priv->nr_retries);
 
                                /* Stick it back at the _top_ of the pending queue
                                   for immediate resubmission */
@@ -890,7 +928,7 @@ int lbs_suspend(struct lbs_private *priv)
 }
 EXPORT_SYMBOL_GPL(lbs_suspend);
 
-int lbs_resume(struct lbs_private *priv)
+void lbs_resume(struct lbs_private *priv)
 {
        lbs_deb_enter(LBS_DEB_FW);
 
@@ -906,7 +944,6 @@ int lbs_resume(struct lbs_private *priv)
                netif_device_attach(priv->mesh_dev);
 
        lbs_deb_leave(LBS_DEB_FW);
-       return 0;
 }
 EXPORT_SYMBOL_GPL(lbs_resume);
 
@@ -929,20 +966,10 @@ static int lbs_setup_firmware(struct lbs_private *priv)
         */
        memset(priv->current_addr, 0xff, ETH_ALEN);
        ret = lbs_update_hw_spec(priv);
-       if (ret) {
-               ret = -1;
+       if (ret)
                goto done;
-       }
 
        lbs_set_mac_control(priv);
-
-       ret = lbs_get_data_rate(priv);
-       if (ret < 0) {
-               ret = -1;
-               goto done;
-       }
-
-       ret = 0;
 done:
        lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
        return ret;
@@ -960,12 +987,11 @@ static void command_timer_fn(unsigned long data)
        lbs_deb_enter(LBS_DEB_CMD);
        spin_lock_irqsave(&priv->driver_lock, flags);
 
-       if (!priv->cur_cmd) {
-               lbs_pr_info("Command timer expired; no pending command\n");
+       if (!priv->cur_cmd)
                goto out;
-       }
 
-       lbs_pr_info("Command %x timed out\n", le16_to_cpu(priv->cur_cmd->cmdbuf->command));
+       lbs_pr_info("command 0x%04x timed out\n",
+               le16_to_cpu(priv->cur_cmd->cmdbuf->command));
 
        priv->cmd_timed_out = 1;
        wake_up_interruptible(&priv->waitq);
@@ -1019,7 +1045,7 @@ static int lbs_init_adapter(struct lbs_private *priv)
        priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL;
        priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
        priv->radioon = RADIO_ON;
-       priv->auto_rate = 1;
+       priv->enablehwauto = 1;
        priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
        priv->psmode = LBS802_11POWERMODECAM;
        priv->psstate = PS_STATE_FULL_POWER;
@@ -1134,6 +1160,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
        priv->work_thread = create_singlethread_workqueue("lbs_worker");
        INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker);
        INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
+       INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker);
        INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker);
 
        sprintf(priv->mesh_ssid, "mesh");
@@ -1156,7 +1183,7 @@ done:
 EXPORT_SYMBOL_GPL(lbs_add_card);
 
 
-int lbs_remove_card(struct lbs_private *priv)
+void lbs_remove_card(struct lbs_private *priv)
 {
        struct net_device *dev = priv->dev;
        union iwreq_data wrqu;
@@ -1168,8 +1195,9 @@ int lbs_remove_card(struct lbs_private *priv)
 
        dev = priv->dev;
 
-       cancel_delayed_work(&priv->scan_work);
-       cancel_delayed_work(&priv->assoc_work);
+       cancel_delayed_work_sync(&priv->scan_work);
+       cancel_delayed_work_sync(&priv->assoc_work);
+       cancel_work_sync(&priv->mcast_work);
        destroy_workqueue(priv->work_thread);
 
        if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
@@ -1191,7 +1219,6 @@ int lbs_remove_card(struct lbs_private *priv)
        free_netdev(dev);
 
        lbs_deb_leave(LBS_DEB_MAIN);
-       return 0;
 }
 EXPORT_SYMBOL_GPL(lbs_remove_card);
 
@@ -1236,9 +1263,11 @@ int lbs_start_card(struct lbs_private *priv)
                   useful */
 
                priv->mesh_tlv = 0x100 + 291;
-               if (lbs_mesh_config(priv, 1, priv->curbssparams.channel)) {
+               if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
+                                   priv->curbssparams.channel)) {
                        priv->mesh_tlv = 0x100 + 37;
-                       if (lbs_mesh_config(priv, 1, priv->curbssparams.channel))
+                       if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
+                                           priv->curbssparams.channel))
                                priv->mesh_tlv = 0;
                }
                if (priv->mesh_tlv) {
@@ -1262,24 +1291,28 @@ done:
 EXPORT_SYMBOL_GPL(lbs_start_card);
 
 
-int lbs_stop_card(struct lbs_private *priv)
+void lbs_stop_card(struct lbs_private *priv)
 {
        struct net_device *dev = priv->dev;
-       int ret = -1;
        struct cmd_ctrl_node *cmdnode;
        unsigned long flags;
 
        lbs_deb_enter(LBS_DEB_MAIN);
 
+       if (!priv)
+               goto out;
+
        netif_stop_queue(priv->dev);
        netif_carrier_off(priv->dev);
 
        lbs_debugfs_remove_one(priv);
        device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
-       if (priv->mesh_tlv)
+       if (priv->mesh_tlv) {
                device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
+       }
 
        /* Flush pending command nodes */
+       del_timer_sync(&priv->command_timer);
        spin_lock_irqsave(&priv->driver_lock, flags);
        list_for_each_entry(cmdnode, &priv->cmdpendingq, list) {
                cmdnode->result = -ENOENT;
@@ -1290,8 +1323,8 @@ int lbs_stop_card(struct lbs_private *priv)
 
        unregister_netdev(dev);
 
-       lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
-       return ret;
+out:
+       lbs_deb_leave(LBS_DEB_MAIN);
 }
 EXPORT_SYMBOL_GPL(lbs_stop_card);
 
@@ -1332,6 +1365,8 @@ static int lbs_add_mesh(struct lbs_private *priv)
 #ifdef WIRELESS_EXT
        mesh_dev->wireless_handlers = (struct iw_handler_def *)&mesh_handler_def;
 #endif
+       mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+       mesh_dev->set_multicast_list = lbs_set_multicast_list;
        /* Register virtual mesh interface */
        ret = register_netdev(mesh_dev);
        if (ret) {
@@ -1343,6 +1378,8 @@ static int lbs_add_mesh(struct lbs_private *priv)
        if (ret)
                goto err_unregister;
 
+       lbs_persist_config_init(mesh_dev);
+
        /* Everything successful */
        ret = 0;
        goto done;
@@ -1369,8 +1406,9 @@ static void lbs_remove_mesh(struct lbs_private *priv)
 
        lbs_deb_enter(LBS_DEB_MESH);
        netif_stop_queue(mesh_dev);
-       netif_carrier_off(priv->mesh_dev);
+       netif_carrier_off(mesh_dev);
        sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
+       lbs_persist_config_remove(mesh_dev);
        unregister_netdev(mesh_dev);
        priv->mesh_dev = NULL;
        free_netdev(mesh_dev);
@@ -1533,10 +1571,11 @@ static void lbs_remove_rtap(struct lbs_private *priv)
 {
        lbs_deb_enter(LBS_DEB_MAIN);
        if (priv->rtap_net_dev == NULL)
-               return;
+               goto out;
        unregister_netdev(priv->rtap_net_dev);
        free_netdev(priv->rtap_net_dev);
        priv->rtap_net_dev = NULL;
+out:
        lbs_deb_leave(LBS_DEB_MAIN);
 }
 
@@ -1563,7 +1602,6 @@ static int lbs_add_rtap(struct lbs_private *priv)
        rtap_dev->stop = lbs_rtap_stop;
        rtap_dev->get_stats = lbs_rtap_get_stats;
        rtap_dev->hard_start_xmit = lbs_rtap_hard_start_xmit;
-       rtap_dev->set_multicast_list = lbs_set_multicast_list;
        rtap_dev->priv = priv;
        SET_NETDEV_DEV(rtap_dev, priv->dev->dev.parent);
 
diff --git a/drivers/net/wireless/libertas/persistcfg.c b/drivers/net/wireless/libertas/persistcfg.c
new file mode 100644 (file)
index 0000000..6d0ff8d
--- /dev/null
@@ -0,0 +1,453 @@
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/kthread.h>
+#include <linux/kfifo.h>
+
+#include "host.h"
+#include "decl.h"
+#include "dev.h"
+#include "wext.h"
+#include "debugfs.h"
+#include "scan.h"
+#include "assoc.h"
+#include "cmd.h"
+
+static int mesh_get_default_parameters(struct device *dev,
+                                      struct mrvl_mesh_defaults *defs)
+{
+       struct lbs_private *priv = to_net_dev(dev)->priv;
+       struct cmd_ds_mesh_config cmd;
+       int ret;
+
+       memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
+       ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
+                                  CMD_TYPE_MESH_GET_DEFAULTS);
+
+       if (ret)
+               return -EOPNOTSUPP;
+
+       memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
+
+       return 0;
+}
+
+/**
+ * @brief Get function for sysfs attribute bootflag
+ */
+static ssize_t bootflag_get(struct device *dev,
+                           struct device_attribute *attr, char *buf)
+{
+       struct mrvl_mesh_defaults defs;
+       int ret;
+
+       ret = mesh_get_default_parameters(dev, &defs);
+
+       if (ret)
+               return ret;
+
+       return snprintf(buf, 12, "0x%x\n", le32_to_cpu(defs.bootflag));
+}
+
+/**
+ * @brief Set function for sysfs attribute bootflag
+ */
+static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       struct lbs_private *priv = to_net_dev(dev)->priv;
+       struct cmd_ds_mesh_config cmd;
+       uint32_t datum;
+       int ret;
+
+       memset(&cmd, 0, sizeof(cmd));
+       ret = sscanf(buf, "%x", &datum);
+       if (ret != 1)
+               return -EINVAL;
+
+       *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
+       cmd.length = cpu_to_le16(sizeof(uint32_t));
+       ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+                                  CMD_TYPE_MESH_SET_BOOTFLAG);
+       if (ret)
+               return ret;
+
+       return strlen(buf);
+}
+
+/**
+ * @brief Get function for sysfs attribute boottime
+ */
+static ssize_t boottime_get(struct device *dev,
+                           struct device_attribute *attr, char *buf)
+{
+       struct mrvl_mesh_defaults defs;
+       int ret;
+
+       ret = mesh_get_default_parameters(dev, &defs);
+
+       if (ret)
+               return ret;
+
+       return snprintf(buf, 12, "0x%x\n", defs.boottime);
+}
+
+/**
+ * @brief Set function for sysfs attribute boottime
+ */
+static ssize_t boottime_set(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct lbs_private *priv = to_net_dev(dev)->priv;
+       struct cmd_ds_mesh_config cmd;
+       uint32_t datum;
+       int ret;
+
+       memset(&cmd, 0, sizeof(cmd));
+       ret = sscanf(buf, "%x", &datum);
+       if (ret != 1)
+               return -EINVAL;
+
+       /* A too small boot time will result in the device booting into
+        * standalone (no-host) mode before the host can take control of it,
+        * so the change will be hard to revert.  This may be a desired
+        * feature (e.g to configure a very fast boot time for devices that
+        * will not be attached to a host), but dangerous.  So I'm enforcing a
+        * lower limit of 20 seconds:  remove and recompile the driver if this
+        * does not work for you.
+        */
+       datum = (datum < 20) ? 20 : datum;
+       cmd.data[0] = datum;
+       cmd.length = cpu_to_le16(sizeof(uint8_t));
+       ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+                                  CMD_TYPE_MESH_SET_BOOTTIME);
+       if (ret)
+               return ret;
+
+       return strlen(buf);
+}
+
+/**
+ * @brief Get function for sysfs attribute channel
+ */
+static ssize_t channel_get(struct device *dev,
+                          struct device_attribute *attr, char *buf)
+{
+       struct mrvl_mesh_defaults defs;
+       int ret;
+
+       ret = mesh_get_default_parameters(dev, &defs);
+
+       if (ret)
+               return ret;
+
+       return snprintf(buf, 12, "0x%x\n", le16_to_cpu(defs.channel));
+}
+
+/**
+ * @brief Set function for sysfs attribute channel
+ */
+static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
+                          const char *buf, size_t count)
+{
+       struct lbs_private *priv = to_net_dev(dev)->priv;
+       struct cmd_ds_mesh_config cmd;
+       uint16_t datum;
+       int ret;
+
+       memset(&cmd, 0, sizeof(cmd));
+       ret = sscanf(buf, "%hx", &datum);
+       if (ret != 1 || datum < 1 || datum > 11)
+               return -EINVAL;
+
+       *((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
+       cmd.length = cpu_to_le16(sizeof(uint16_t));
+       ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+                                  CMD_TYPE_MESH_SET_DEF_CHANNEL);
+       if (ret)
+               return ret;
+
+       return strlen(buf);
+}
+
+/**
+ * @brief Get function for sysfs attribute mesh_id
+ */
+static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
+                          char *buf)
+{
+       struct mrvl_mesh_defaults defs;
+       int maxlen;
+       int ret;
+
+       ret = mesh_get_default_parameters(dev, &defs);
+
+       if (ret)
+               return ret;
+
+       if (defs.meshie.val.mesh_id_len > IW_ESSID_MAX_SIZE) {
+               lbs_pr_err("inconsistent mesh ID length");
+               defs.meshie.val.mesh_id_len = IW_ESSID_MAX_SIZE;
+       }
+
+       /* SSID not null terminated: reserve room for \0 + \n */
+       maxlen = defs.meshie.val.mesh_id_len + 2;
+       maxlen = (PAGE_SIZE > maxlen) ? maxlen : PAGE_SIZE;
+
+       defs.meshie.val.mesh_id[defs.meshie.val.mesh_id_len] = '\0';
+
+       return snprintf(buf, maxlen, "%s\n", defs.meshie.val.mesh_id);
+}
+
+/**
+ * @brief Set function for sysfs attribute mesh_id
+ */
+static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
+                          const char *buf, size_t count)
+{
+       struct cmd_ds_mesh_config cmd;
+       struct mrvl_mesh_defaults defs;
+       struct mrvl_meshie *ie;
+       struct lbs_private *priv = to_net_dev(dev)->priv;
+       int len;
+       int ret;
+
+       if (count < 2 || count > IW_ESSID_MAX_SIZE + 1)
+               return -EINVAL;
+
+       memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
+       ie = (struct mrvl_meshie *) &cmd.data[0];
+
+       /* fetch all other Information Element parameters */
+       ret = mesh_get_default_parameters(dev, &defs);
+
+       cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
+
+       /* transfer IE elements */
+       memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
+
+       len = count - 1;
+       memcpy(ie->val.mesh_id, buf, len);
+       /* SSID len */
+       ie->val.mesh_id_len = len;
+       /* IE len */
+       ie->hdr.len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len;
+
+       ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+                                  CMD_TYPE_MESH_SET_MESH_IE);
+       if (ret)
+               return ret;
+
+       return strlen(buf);
+}
+
+/**
+ * @brief Get function for sysfs attribute protocol_id
+ */
+static ssize_t protocol_id_get(struct device *dev,
+                              struct device_attribute *attr, char *buf)
+{
+       struct mrvl_mesh_defaults defs;
+       int ret;
+
+       ret = mesh_get_default_parameters(dev, &defs);
+
+       if (ret)
+               return ret;
+
+       return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id);
+}
+
+/**
+ * @brief Set function for sysfs attribute protocol_id
+ */
+static ssize_t protocol_id_set(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct cmd_ds_mesh_config cmd;
+       struct mrvl_mesh_defaults defs;
+       struct mrvl_meshie *ie;
+       struct lbs_private *priv = to_net_dev(dev)->priv;
+       uint32_t datum;
+       int ret;
+
+       memset(&cmd, 0, sizeof(cmd));
+       ret = sscanf(buf, "%x", &datum);
+       if (ret != 1)
+               return -EINVAL;
+
+       /* fetch all other Information Element parameters */
+       ret = mesh_get_default_parameters(dev, &defs);
+
+       cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
+
+       /* transfer IE elements */
+       ie = (struct mrvl_meshie *) &cmd.data[0];
+       memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
+       /* update protocol id */
+       ie->val.active_protocol_id = datum;
+
+       ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+                                  CMD_TYPE_MESH_SET_MESH_IE);
+       if (ret)
+               return ret;
+
+       return strlen(buf);
+}
+
+/**
+ * @brief Get function for sysfs attribute metric_id
+ */
+static ssize_t metric_id_get(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct mrvl_mesh_defaults defs;
+       int ret;
+
+       ret = mesh_get_default_parameters(dev, &defs);
+
+       if (ret)
+               return ret;
+
+       return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id);
+}
+
+/**
+ * @brief Set function for sysfs attribute metric_id
+ */
+static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
+                            const char *buf, size_t count)
+{
+       struct cmd_ds_mesh_config cmd;
+       struct mrvl_mesh_defaults defs;
+       struct mrvl_meshie *ie;
+       struct lbs_private *priv = to_net_dev(dev)->priv;
+       uint32_t datum;
+       int ret;
+
+       memset(&cmd, 0, sizeof(cmd));
+       ret = sscanf(buf, "%x", &datum);
+       if (ret != 1)
+               return -EINVAL;
+
+       /* fetch all other Information Element parameters */
+       ret = mesh_get_default_parameters(dev, &defs);
+
+       cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
+
+       /* transfer IE elements */
+       ie = (struct mrvl_meshie *) &cmd.data[0];
+       memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
+       /* update metric id */
+       ie->val.active_metric_id = datum;
+
+       ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+                                  CMD_TYPE_MESH_SET_MESH_IE);
+       if (ret)
+               return ret;
+
+       return strlen(buf);
+}
+
+/**
+ * @brief Get function for sysfs attribute capability
+ */
+static ssize_t capability_get(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct mrvl_mesh_defaults defs;
+       int ret;
+
+       ret = mesh_get_default_parameters(dev, &defs);
+
+       if (ret)
+               return ret;
+
+       return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability);
+}
+
+/**
+ * @brief Set function for sysfs attribute capability
+ */
+static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
+                             const char *buf, size_t count)
+{
+       struct cmd_ds_mesh_config cmd;
+       struct mrvl_mesh_defaults defs;
+       struct mrvl_meshie *ie;
+       struct lbs_private *priv = to_net_dev(dev)->priv;
+       uint32_t datum;
+       int ret;
+
+       memset(&cmd, 0, sizeof(cmd));
+       ret = sscanf(buf, "%x", &datum);
+       if (ret != 1)
+               return -EINVAL;
+
+       /* fetch all other Information Element parameters */
+       ret = mesh_get_default_parameters(dev, &defs);
+
+       cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
+
+       /* transfer IE elements */
+       ie = (struct mrvl_meshie *) &cmd.data[0];
+       memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
+       /* update value */
+       ie->val.mesh_capability = datum;
+
+       ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+                                  CMD_TYPE_MESH_SET_MESH_IE);
+       if (ret)
+               return ret;
+
+       return strlen(buf);
+}
+
+
+static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
+static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
+static DEVICE_ATTR(channel, 0644, channel_get, channel_set);
+static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
+static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
+static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
+static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
+
+static struct attribute *boot_opts_attrs[] = {
+       &dev_attr_bootflag.attr,
+       &dev_attr_boottime.attr,
+       &dev_attr_channel.attr,
+       NULL
+};
+
+static struct attribute_group boot_opts_group = {
+       .name = "boot_options",
+       .attrs = boot_opts_attrs,
+};
+
+static struct attribute *mesh_ie_attrs[] = {
+       &dev_attr_mesh_id.attr,
+       &dev_attr_protocol_id.attr,
+       &dev_attr_metric_id.attr,
+       &dev_attr_capability.attr,
+       NULL
+};
+
+static struct attribute_group mesh_ie_group = {
+       .name = "mesh_ie",
+       .attrs = mesh_ie_attrs,
+};
+
+void lbs_persist_config_init(struct net_device *dev)
+{
+       int ret;
+       ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group);
+       ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
+}
+
+void lbs_persist_config_remove(struct net_device *dev)
+{
+       sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
+       sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
+}
index 05af7316f6988ab1521a8f3911ebe8f5b27a4923..5749f22b296f90969b6580df2ae505629892762d 100644 (file)
@@ -237,7 +237,7 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
        /* Take the data rate from the rxpd structure
         * only if the rate is auto
         */
-       if (priv->auto_rate)
+       if (priv->enablehwauto)
                priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate);
 
        lbs_compute_rssi(priv, p_rx_pd);
@@ -383,7 +383,7 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
        /* Take the data rate from the rxpd structure
         * only if the rate is auto
         */
-       if (priv->auto_rate)
+       if (priv->enablehwauto)
                priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate);
 
        lbs_compute_rssi(priv, prxpd);
index 4031be4208624cce879ffa734d1db5d71bf932fb..e0c2599da92f182c2e3a31b616d04fd9c2ac4323 100644 (file)
@@ -6,6 +6,8 @@
 
 #include <linux/if_ether.h>
 #include <asm/byteorder.h>
+#include <linux/wireless.h>
+#include <net/ieee80211.h>
 
 struct ieeetypes_cfparamset {
        u8 elementid;
@@ -252,4 +254,32 @@ struct mrvlietypes_ledbhv {
        struct led_bhv ledbhv[1];
 } __attribute__ ((packed));
 
+/* Meant to be packed as the value member of a struct ieee80211_info_element.
+ * Note that the len member of the ieee80211_info_element varies depending on
+ * the mesh_id_len */
+struct mrvl_meshie_val {
+       uint8_t oui[P80211_OUI_LEN];
+       uint8_t type;
+       uint8_t subtype;
+       uint8_t version;
+       uint8_t active_protocol_id;
+       uint8_t active_metric_id;
+       uint8_t mesh_capability;
+       uint8_t mesh_id_len;
+       uint8_t mesh_id[IW_ESSID_MAX_SIZE];
+} __attribute__ ((packed));
+
+struct mrvl_meshie {
+       struct ieee80211_info_element hdr;
+       struct mrvl_meshie_val val;
+} __attribute__ ((packed));
+
+struct mrvl_mesh_defaults {
+       __le32 bootflag;
+       uint8_t boottime;
+       uint8_t reserved;
+       __le16 channel;
+       struct mrvl_meshie meshie;
+} __attribute__ ((packed));
+
 #endif
index 0973d015a5201e7dc604f1c86229c25b5a6bc265..8b3ed77860b3e2cc6e8b526b53ccd43aaac95815 100644 (file)
@@ -1002,7 +1002,7 @@ static int lbs_mesh_set_freq(struct net_device *dev,
                else if (priv->mode == IW_MODE_ADHOC)
                        lbs_stop_adhoc_network(priv);
        }
-       lbs_mesh_config(priv, 1, fwrq->m);
+       lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m);
        lbs_update_channel(priv);
        ret = 0;
 
@@ -1021,29 +1021,38 @@ static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,
 
        lbs_deb_enter(LBS_DEB_WEXT);
        lbs_deb_wext("vwrq->value %d\n", vwrq->value);
+       lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed);
+
+       if (vwrq->fixed && vwrq->value == -1)
+               goto out;
 
        /* Auto rate? */
-       if (vwrq->value == -1) {
-               priv->auto_rate = 1;
+       priv->enablehwauto = !vwrq->fixed;
+
+       if (vwrq->value == -1)
                priv->cur_rate = 0;
-       else {
+       else {
                if (vwrq->value % 100000)
                        goto out;
 
+               new_rate = vwrq->value / 500000;
+               priv->cur_rate = new_rate;
+               /* the rest is only needed for lbs_set_data_rate() */
                memset(rates, 0, sizeof(rates));
                copy_active_data_rates(priv, rates);
-               new_rate = vwrq->value / 500000;
                if (!memchr(rates, new_rate, sizeof(rates))) {
                        lbs_pr_alert("fixed data rate 0x%X out of range\n",
                                new_rate);
                        goto out;
                }
-
-               priv->cur_rate = new_rate;
-               priv->auto_rate = 0;
        }
 
-       ret = lbs_set_data_rate(priv, new_rate);
+       /* Try the newer command first (Firmware Spec 5.1 and above) */
+       ret = lbs_cmd_802_11_rate_adapt_rateset(priv, CMD_ACT_SET);
+
+       /* Fallback to older version */
+       if (ret)
+               ret = lbs_set_data_rate(priv, new_rate);
 
 out:
        lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
@@ -1060,7 +1069,7 @@ static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info,
        if (priv->connect_status == LBS_CONNECTED) {
                vwrq->value = priv->cur_rate * 500000;
 
-               if (priv->auto_rate)
+               if (priv->enablehwauto)
                        vwrq->fixed = 0;
                else
                        vwrq->fixed = 1;
@@ -2011,7 +2020,8 @@ static int lbs_mesh_set_essid(struct net_device *dev,
                priv->mesh_ssid_len = dwrq->length;
        }
 
-       lbs_mesh_config(priv, 1, priv->curbssparams.channel);
+       lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
+                       priv->curbssparams.channel);
  out:
        lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
        return ret;
index 06d2c67f4c81d00603790d38dbfe08adeb67df2d..c6f27b9022f921d246a3ea70bdfc7684208df4ea 100644 (file)
@@ -64,7 +64,7 @@ struct p54_common {
        unsigned int tx_hdr_len;
        void *cached_vdcf;
        unsigned int fw_var;
-       struct ieee80211_tx_queue_stats tx_stats;
+       struct ieee80211_tx_queue_stats tx_stats[4];
 };
 
 int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
index 63f9badf3f523a77eb513f1293da991f35008903..9f7224de6fd1a874b4f6c037b21f3bf6ea574549 100644 (file)
@@ -146,10 +146,10 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
 
        if (priv->fw_var >= 0x300) {
                /* Firmware supports QoS, use it! */
-               priv->tx_stats.data[0].limit = 3;
-               priv->tx_stats.data[1].limit = 4;
-               priv->tx_stats.data[2].limit = 3;
-               priv->tx_stats.data[3].limit = 1;
+               priv->tx_stats[0].limit = 3;
+               priv->tx_stats[1].limit = 4;
+               priv->tx_stats[2].limit = 3;
+               priv->tx_stats[3].limit = 1;
                dev->queues = 4;
        }
 }
@@ -355,7 +355,7 @@ static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
        struct ieee80211_rx_status rx_status = {0};
        u16 freq = le16_to_cpu(hdr->freq);
 
-       rx_status.ssi = hdr->rssi;
+       rx_status.signal = hdr->rssi;
        /* XX correct? */
        rx_status.rate_idx = hdr->rate & 0xf;
        rx_status.freq = freq;
@@ -375,11 +375,8 @@ static void inline p54_wake_free_queues(struct ieee80211_hw *dev)
        struct p54_common *priv = dev->priv;
        int i;
 
-       /* ieee80211_start_queues is great if all queues are really empty.
-        * But, what if some are full? */
-
        for (i = 0; i < dev->queues; i++)
-               if (priv->tx_stats.data[i].len < priv->tx_stats.data[i].limit)
+               if (priv->tx_stats[i].len < priv->tx_stats[i].limit)
                        ieee80211_wake_queue(dev, i);
 }
 
@@ -395,45 +392,42 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
        u32 last_addr = priv->rx_start;
 
        while (entry != (struct sk_buff *)&priv->tx_queue) {
-               range = (struct memrecord *)&entry->cb;
+               struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
+               range = (void *)info->driver_data;
                if (range->start_addr == addr) {
-                       struct ieee80211_tx_status status;
                        struct p54_control_hdr *entry_hdr;
                        struct p54_tx_control_allocdata *entry_data;
                        int pad = 0;
 
-                       if (entry->next != (struct sk_buff *)&priv->tx_queue)
-                               freed = ((struct memrecord *)&entry->next->cb)->start_addr - last_addr;
-                       else
+                       if (entry->next != (struct sk_buff *)&priv->tx_queue) {
+                               struct ieee80211_tx_info *ni;
+                               struct memrecord *mr;
+
+                               ni = IEEE80211_SKB_CB(entry->next);
+                               mr = (struct memrecord *)ni->driver_data;
+                               freed = mr->start_addr - last_addr;
+                       } else
                                freed = priv->rx_end - last_addr;
 
                        last_addr = range->end_addr;
                        __skb_unlink(entry, &priv->tx_queue);
-                       if (!range->control) {
-                               kfree_skb(entry);
-                               break;
-                       }
-                       memset(&status, 0, sizeof(status));
-                       memcpy(&status.control, range->control,
-                              sizeof(status.control));
-                       kfree(range->control);
-                       priv->tx_stats.data[status.control.queue].len--;
-
+                       memset(&info->status, 0, sizeof(info->status));
+                       priv->tx_stats[skb_get_queue_mapping(skb)].len--;
                        entry_hdr = (struct p54_control_hdr *) entry->data;
                        entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data;
                        if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0)
                                pad = entry_data->align[0];
 
-                       if (!(status.control.flags & IEEE80211_TXCTL_NO_ACK)) {
+                       if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
                                if (!(payload->status & 0x01))
-                                       status.flags |= IEEE80211_TX_STATUS_ACK;
+                                       info->flags |= IEEE80211_TX_STAT_ACK;
                                else
-                                       status.excessive_retries = 1;
+                                       info->status.excessive_retries = 1;
                        }
-                       status.retry_count = payload->retries - 1;
-                       status.ack_signal = le16_to_cpu(payload->ack_rssi);
+                       info->status.retry_count = payload->retries - 1;
+                       info->status.ack_signal = le16_to_cpu(payload->ack_rssi);
                        skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
-                       ieee80211_tx_status_irqsafe(dev, entry, &status);
+                       ieee80211_tx_status_irqsafe(dev, entry);
                        break;
                } else
                        last_addr = range->end_addr;
@@ -498,13 +492,11 @@ EXPORT_SYMBOL_GPL(p54_rx);
  * allocated areas.
  */
 static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
-                              struct p54_control_hdr *data, u32 len,
-                              struct ieee80211_tx_control *control)
+                              struct p54_control_hdr *data, u32 len)
 {
        struct p54_common *priv = dev->priv;
        struct sk_buff *entry = priv->tx_queue.next;
        struct sk_buff *target_skb = NULL;
-       struct memrecord *range;
        u32 last_addr = priv->rx_start;
        u32 largest_hole = 0;
        u32 target_addr = priv->rx_start;
@@ -516,7 +508,8 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
        left = skb_queue_len(&priv->tx_queue);
        while (left--) {
                u32 hole_size;
-               range = (struct memrecord *)&entry->cb;
+               struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
+               struct memrecord *range = (void *)info->driver_data;
                hole_size = range->start_addr - last_addr;
                if (!target_skb && hole_size >= len) {
                        target_skb = entry->prev;
@@ -531,17 +524,18 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
                target_skb = priv->tx_queue.prev;
                largest_hole = max(largest_hole, priv->rx_end - last_addr - len);
                if (!skb_queue_empty(&priv->tx_queue)) {
-                       range = (struct memrecord *)&target_skb->cb;
+                       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(target_skb);
+                       struct memrecord *range = (void *)info->driver_data;
                        target_addr = range->end_addr;
                }
        } else
                largest_hole = max(largest_hole, priv->rx_end - last_addr);
 
        if (skb) {
-               range = (struct memrecord *)&skb->cb;
+               struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+               struct memrecord *range = (void *)info->driver_data;
                range->start_addr = target_addr;
                range->end_addr = target_addr + len;
-               range->control = control;
                __skb_queue_after(&priv->tx_queue, target_skb, skb);
                if (largest_hole < IEEE80211_MAX_RTS_THRESHOLD + 0x170 +
                                   sizeof(struct p54_control_hdr))
@@ -552,32 +546,27 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
        data->req_id = cpu_to_le32(target_addr + 0x70);
 }
 
-static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
-                 struct ieee80211_tx_control *control)
+static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
-       struct ieee80211_tx_queue_stats_data *current_queue;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_tx_queue_stats *current_queue;
        struct p54_common *priv = dev->priv;
        struct p54_control_hdr *hdr;
        struct p54_tx_control_allocdata *txhdr;
-       struct ieee80211_tx_control *control_copy;
        size_t padding, len;
        u8 rate;
 
-       current_queue = &priv->tx_stats.data[control->queue];
+       current_queue = &priv->tx_stats[skb_get_queue_mapping(skb)];
        if (unlikely(current_queue->len > current_queue->limit))
                return NETDEV_TX_BUSY;
        current_queue->len++;
        current_queue->count++;
        if (current_queue->len == current_queue->limit)
-               ieee80211_stop_queue(dev, control->queue);
+               ieee80211_stop_queue(dev, skb_get_queue_mapping(skb));
 
        padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
        len = skb->len;
 
-       control_copy = kmalloc(sizeof(*control), GFP_ATOMIC);
-       if (control_copy)
-               memcpy(control_copy, control, sizeof(*control));
-
        txhdr = (struct p54_tx_control_allocdata *)
                        skb_push(skb, sizeof(*txhdr) + padding);
        hdr = (struct p54_control_hdr *) skb_push(skb, sizeof(*hdr));
@@ -587,35 +576,37 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
        else
                hdr->magic1 = cpu_to_le16(0x0010);
        hdr->len = cpu_to_le16(len);
-       hdr->type = (control->flags & IEEE80211_TXCTL_NO_ACK) ? 0 : cpu_to_le16(1);
-       hdr->retry1 = hdr->retry2 = control->retry_limit;
-       p54_assign_address(dev, skb, hdr, skb->len, control_copy);
+       hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1);
+       hdr->retry1 = hdr->retry2 = info->control.retry_limit;
 
        memset(txhdr->wep_key, 0x0, 16);
        txhdr->padding = 0;
        txhdr->padding2 = 0;
 
        /* TODO: add support for alternate retry TX rates */
-       rate = control->tx_rate->hw_value;
-       if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE)
+       rate = ieee80211_get_tx_rate(dev, info)->hw_value;
+       if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE)
                rate |= 0x10;
-       if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
+       if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
                rate |= 0x40;
-       else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+       else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
                rate |= 0x20;
        memset(txhdr->rateset, rate, 8);
        txhdr->wep_key_present = 0;
        txhdr->wep_key_len = 0;
-       txhdr->frame_type = cpu_to_le32(control->queue + 4);
+       txhdr->frame_type = cpu_to_le32(skb_get_queue_mapping(skb) + 4);
        txhdr->magic4 = 0;
-       txhdr->antenna = (control->antenna_sel_tx == 0) ?
-               2 : control->antenna_sel_tx - 1;
+       txhdr->antenna = (info->antenna_sel_tx == 0) ?
+               2 : info->antenna_sel_tx - 1;
        txhdr->output_power = 0x7f; // HW Maximum
-       txhdr->magic5 = (control->flags & IEEE80211_TXCTL_NO_ACK) ?
+       txhdr->magic5 = (info->flags & IEEE80211_TX_CTL_NO_ACK) ?
                0 : ((rate > 0x3) ? cpu_to_le32(0x33) : cpu_to_le32(0x23));
        if (padding)
                txhdr->align[0] = padding;
 
+       /* modifies skb->cb and with it info, so must be last! */
+       p54_assign_address(dev, skb, hdr, skb->len);
+
        priv->tx(dev, hdr, skb->len, 0);
        return 0;
 }
@@ -638,7 +629,7 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type,
        filter = (struct p54_tx_control_filter *) hdr->data;
        hdr->magic1 = cpu_to_le16(0x8001);
        hdr->len = cpu_to_le16(sizeof(*filter));
-       p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*filter), NULL);
+       p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*filter));
        hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET);
 
        filter->filter_type = cpu_to_le16(filter_type);
@@ -682,7 +673,7 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
        hdr->magic1 = cpu_to_le16(0x8001);
        hdr->len = cpu_to_le16(sizeof(*chan));
        hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE);
-       p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + payload_len, NULL);
+       p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + payload_len);
 
        chan->magic1 = cpu_to_le16(0x1);
        chan->magic2 = cpu_to_le16(0x0);
@@ -755,7 +746,7 @@ static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act)
        hdr->magic1 = cpu_to_le16(0x8001);
        hdr->len = cpu_to_le16(sizeof(*led));
        hdr->type = cpu_to_le16(P54_CONTROL_TYPE_LED);
-       p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*led), NULL);
+       p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*led));
 
        led = (struct p54_tx_control_led *) hdr->data;
        led->mode = cpu_to_le16(mode);
@@ -805,7 +796,7 @@ static void p54_set_vdcf(struct ieee80211_hw *dev)
 
        hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len;
 
-       p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*vdcf), NULL);
+       p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*vdcf));
 
        vdcf = (struct p54_tx_control_vdcf *) hdr->data;
 
@@ -841,12 +832,8 @@ static void p54_stop(struct ieee80211_hw *dev)
 {
        struct p54_common *priv = dev->priv;
        struct sk_buff *skb;
-       while ((skb = skb_dequeue(&priv->tx_queue))) {
-               struct memrecord *range = (struct memrecord *)&skb->cb;
-               if (range->control)
-                       kfree(range->control);
+       while ((skb = skb_dequeue(&priv->tx_queue)))
                kfree_skb(skb);
-       }
        priv->stop(dev);
        priv->mode = IEEE80211_IF_TYPE_INVALID;
 }
@@ -936,7 +923,7 @@ static void p54_configure_filter(struct ieee80211_hw *dev,
        }
 }
 
-static int p54_conf_tx(struct ieee80211_hw *dev, int queue,
+static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue,
                       const struct ieee80211_tx_queue_params *params)
 {
        struct p54_common *priv = dev->priv;
@@ -945,7 +932,7 @@ static int p54_conf_tx(struct ieee80211_hw *dev, int queue,
        vdcf = (struct p54_tx_control_vdcf *)(((struct p54_control_hdr *)
                ((void *)priv->cached_vdcf + priv->tx_hdr_len))->data);
 
-       if ((params) && !((queue < 0) || (queue > 4))) {
+       if ((params) && !(queue > 4)) {
                P54_SET_QUEUE(vdcf->queue[queue], params->aifs,
                        params->cw_min, params->cw_max, params->txop);
        } else
@@ -967,11 +954,8 @@ static int p54_get_tx_stats(struct ieee80211_hw *dev,
                            struct ieee80211_tx_queue_stats *stats)
 {
        struct p54_common *priv = dev->priv;
-       unsigned int i;
 
-       for (i = 0; i < dev->queues; i++)
-               memcpy(&stats->data[i], &priv->tx_stats.data[i],
-                       sizeof(stats->data[i]));
+       memcpy(stats, &priv->tx_stats, sizeof(stats[0]) * dev->queues);
 
        return 0;
 }
@@ -1004,11 +988,12 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
        skb_queue_head_init(&priv->tx_queue);
        dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz;
        dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */
-                   IEEE80211_HW_RX_INCLUDES_FCS;
+                    IEEE80211_HW_RX_INCLUDES_FCS |
+                    IEEE80211_HW_SIGNAL_UNSPEC;
        dev->channel_change_time = 1000;        /* TODO: find actual value */
-       dev->max_rssi = 127;
+       dev->max_signal = 127;
 
-       priv->tx_stats.data[0].limit = 5;
+       priv->tx_stats[0].limit = 5;
        dev->queues = 1;
 
        dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 +
index c15b56e1d75ec94b127baf3eac3b39adc9cfaf9d..2245fcce92dc917e4707bf37cef9f086c1ca2b7c 100644 (file)
@@ -152,7 +152,6 @@ struct pda_pa_curve_data {
 struct memrecord {
        u32 start_addr;
        u32 end_addr;
-       struct ieee80211_tx_control *control;
 };
 
 struct p54_eeprom_lm86 {
index fa527723fbe0e210f7e774d0e22a13f5fcb4bfea..7dd4add4bf4e55c13efeaef04ca9e9ac4def0e07 100644 (file)
@@ -665,7 +665,7 @@ static int p54p_resume(struct pci_dev *pdev)
 
        if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) {
                p54p_open(dev);
-               ieee80211_start_queues(dev);
+               ieee80211_wake_queues(dev);
        }
 
        return 0;
index 18c9931e3267182c2872b2fda928d1383e8db5ab..3954897d06784849f251354a70a14f28c8a7fa09 100644 (file)
@@ -1135,7 +1135,7 @@ static int rndis_iw_get_range(struct net_device *dev,
        /* fill in 802.11g rates */
        if (has_80211g_rates) {
                num = range->num_bitrates;
-               for (i = 0; i < sizeof(rates_80211g); i++) {
+               for (i = 0; i < ARRAY_SIZE(rates_80211g); i++) {
                        for (j = 0; j < num; j++) {
                                if (range->bitrate[j] ==
                                        rates_80211g[i] * 1000000)
index ab1029e7988457539fc7f08e5548a19a0c322890..0ace761494225a493f47bccd21a36900be0d0f96 100644 (file)
@@ -5,12 +5,16 @@ config RT2X00
          This will enable the experimental support for the Ralink drivers,
          developed in the rt2x00 project <http://rt2x00.serialmonkey.com>.
 
-         These drivers will make use of the mac80211 stack.
+         These drivers make use of the mac80211 stack.
 
          When building one of the individual drivers, the rt2x00 library
          will also be created. That library (when the driver is built as
          a module) will be called "rt2x00lib.ko".
 
+         Additionally PCI and USB libraries will also be build depending
+         on the types of drivers being selected, these libraries will be
+         called "rt2x00pci.ko" and "rt2x00usb.ko".
+
 if RT2X00
 
 config RT2X00_LIB
@@ -40,26 +44,27 @@ config RT2X00_LIB_LEDS
        depends on RT2X00_LIB
 
 config RT2400PCI
-       tristate "Ralink rt2400 pci/pcmcia support"
+       tristate "Ralink rt2400 (PCI/PCMCIA) support"
        depends on PCI
        select RT2X00_LIB_PCI
        select EEPROM_93CX6
        ---help---
-         This is an experimental driver for the Ralink rt2400 wireless chip.
+         This adds support for rt2400 wireless chipset family.
+         Supported chips: RT2460.
 
          When compiled as a module, this driver will be called "rt2400pci.ko".
 
 config RT2400PCI_RFKILL
-       bool "RT2400 rfkill support"
+       bool "Ralink rt2400 rfkill support"
        depends on RT2400PCI
        select RT2X00_LIB_RFKILL
        ---help---
-         This adds support for integrated rt2400 devices that feature a
+         This adds support for integrated rt2400 hardware that features a
          hardware button to control the radio state.
          This feature depends on the RF switch subsystem rfkill.
 
 config RT2400PCI_LEDS
-       bool "RT2400 leds support"
+       bool "Ralink rt2400 leds support"
        depends on RT2400PCI
        select LEDS_CLASS
        select RT2X00_LIB_LEDS
@@ -67,26 +72,27 @@ config RT2400PCI_LEDS
          This adds support for led triggers provided my mac80211.
 
 config RT2500PCI
-       tristate "Ralink rt2500 pci/pcmcia support"
+       tristate "Ralink rt2500 (PCI/PCMCIA) support"
        depends on PCI
        select RT2X00_LIB_PCI
        select EEPROM_93CX6
        ---help---
-         This is an experimental driver for the Ralink rt2500 wireless chip.
+         This adds support for rt2500 wireless chipset family.
+         Supported chips: RT2560.
 
          When compiled as a module, this driver will be called "rt2500pci.ko".
 
 config RT2500PCI_RFKILL
-       bool "RT2500 rfkill support"
+       bool "Ralink rt2500 rfkill support"
        depends on RT2500PCI
        select RT2X00_LIB_RFKILL
        ---help---
-         This adds support for integrated rt2500 devices that feature a
+         This adds support for integrated rt2500 hardware that features a
          hardware button to control the radio state.
          This feature depends on the RF switch subsystem rfkill.
 
 config RT2500PCI_LEDS
-       bool "RT2500 leds support"
+       bool "Ralink rt2500 leds support"
        depends on RT2500PCI
        select LEDS_CLASS
        select RT2X00_LIB_LEDS
@@ -94,28 +100,29 @@ config RT2500PCI_LEDS
          This adds support for led triggers provided my mac80211.
 
 config RT61PCI
-       tristate "Ralink rt61 pci/pcmcia support"
+       tristate "Ralink rt2501/rt61 (PCI/PCMCIA) support"
        depends on PCI
        select RT2X00_LIB_PCI
        select RT2X00_LIB_FIRMWARE
        select CRC_ITU_T
        select EEPROM_93CX6
        ---help---
-         This is an experimental driver for the Ralink rt61 wireless chip.
+         This adds support for rt2501 wireless chipset family.
+         Supported chips: RT2561, RT2561S & RT2661.
 
          When compiled as a module, this driver will be called "rt61pci.ko".
 
 config RT61PCI_RFKILL
-       bool "RT61 rfkill support"
+       bool "Ralink rt2501/rt61 rfkill support"
        depends on RT61PCI
        select RT2X00_LIB_RFKILL
        ---help---
-         This adds support for integrated rt61 devices that feature a
+         This adds support for integrated rt61 hardware that features a
          hardware button to control the radio state.
          This feature depends on the RF switch subsystem rfkill.
 
 config RT61PCI_LEDS
-       bool "RT61 leds support"
+       bool "Ralink rt2501/rt61 leds support"
        depends on RT61PCI
        select LEDS_CLASS
        select RT2X00_LIB_LEDS
@@ -123,16 +130,17 @@ config RT61PCI_LEDS
          This adds support for led triggers provided my mac80211.
 
 config RT2500USB
-       tristate "Ralink rt2500 usb support"
+       tristate "Ralink rt2500 (USB) support"
        depends on USB
        select RT2X00_LIB_USB
        ---help---
-         This is an experimental driver for the Ralink rt2500 wireless chip.
+         This adds support for rt2500 wireless chipset family.
+         Supported chips: RT2571 & RT2572.
 
          When compiled as a module, this driver will be called "rt2500usb.ko".
 
 config RT2500USB_LEDS
-       bool "RT2500 leds support"
+       bool "Ralink rt2500 leds support"
        depends on RT2500USB
        select LEDS_CLASS
        select RT2X00_LIB_LEDS
@@ -140,18 +148,19 @@ config RT2500USB_LEDS
          This adds support for led triggers provided my mac80211.
 
 config RT73USB
-       tristate "Ralink rt73 usb support"
+       tristate "Ralink rt2501/rt73 (USB) support"
        depends on USB
        select RT2X00_LIB_USB
        select RT2X00_LIB_FIRMWARE
        select CRC_ITU_T
        ---help---
-         This is an experimental driver for the Ralink rt73 wireless chip.
+         This adds support for rt2501 wireless chipset family.
+         Supported chips: RT2571W, RT2573 & RT2671.
 
          When compiled as a module, this driver will be called "rt73usb.ko".
 
 config RT73USB_LEDS
-       bool "RT73 leds support"
+       bool "Ralink rt2501/rt73 leds support"
        depends on RT73USB
        select LEDS_CLASS
        select RT2X00_LIB_LEDS
@@ -164,7 +173,7 @@ config RT2X00_LIB_DEBUGFS
        ---help---
          Enable creation of debugfs files for the rt2x00 drivers.
          These debugfs files support both reading and writing of the
-         most important register types of the rt2x00 devices.
+         most important register types of the rt2x00 hardware.
 
 config RT2X00_DEBUG
        bool "Ralink debug output"
index 560b9c73c0b9bcd41e1c0698818be95b59445084..900140d3b304539d8a50127246cb1744a3c18184 100644 (file)
@@ -620,48 +620,38 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev)
 static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
                                   struct queue_entry *entry)
 {
-       struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data;
+       struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        u32 word;
 
-       rt2x00_desc_read(priv_rx->desc, 2, &word);
+       rt2x00_desc_read(entry_priv->desc, 2, &word);
        rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH,
                           entry->queue->data_size);
-       rt2x00_desc_write(priv_rx->desc, 2, word);
+       rt2x00_desc_write(entry_priv->desc, 2, word);
 
-       rt2x00_desc_read(priv_rx->desc, 1, &word);
-       rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, priv_rx->data_dma);
-       rt2x00_desc_write(priv_rx->desc, 1, word);
+       rt2x00_desc_read(entry_priv->desc, 1, &word);
+       rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
+       rt2x00_desc_write(entry_priv->desc, 1, word);
 
-       rt2x00_desc_read(priv_rx->desc, 0, &word);
+       rt2x00_desc_read(entry_priv->desc, 0, &word);
        rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
-       rt2x00_desc_write(priv_rx->desc, 0, word);
+       rt2x00_desc_write(entry_priv->desc, 0, word);
 }
 
 static void rt2400pci_init_txentry(struct rt2x00_dev *rt2x00dev,
                                   struct queue_entry *entry)
 {
-       struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data;
+       struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        u32 word;
 
-       rt2x00_desc_read(priv_tx->desc, 1, &word);
-       rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, priv_tx->data_dma);
-       rt2x00_desc_write(priv_tx->desc, 1, word);
-
-       rt2x00_desc_read(priv_tx->desc, 2, &word);
-       rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH,
-                          entry->queue->data_size);
-       rt2x00_desc_write(priv_tx->desc, 2, word);
-
-       rt2x00_desc_read(priv_tx->desc, 0, &word);
+       rt2x00_desc_read(entry_priv->desc, 0, &word);
        rt2x00_set_field32(&word, TXD_W0_VALID, 0);
        rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
-       rt2x00_desc_write(priv_tx->desc, 0, word);
+       rt2x00_desc_write(entry_priv->desc, 0, word);
 }
 
 static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev)
 {
-       struct queue_entry_priv_pci_rx *priv_rx;
-       struct queue_entry_priv_pci_tx *priv_tx;
+       struct queue_entry_priv_pci *entry_priv;
        u32 reg;
 
        /*
@@ -674,28 +664,28 @@ static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field32(&reg, TXCSR2_NUM_PRIO, rt2x00dev->tx[0].limit);
        rt2x00pci_register_write(rt2x00dev, TXCSR2, reg);
 
-       priv_tx = rt2x00dev->tx[1].entries[0].priv_data;
+       entry_priv = rt2x00dev->tx[1].entries[0].priv_data;
        rt2x00pci_register_read(rt2x00dev, TXCSR3, &reg);
        rt2x00_set_field32(&reg, TXCSR3_TX_RING_REGISTER,
-                          priv_tx->desc_dma);
+                          entry_priv->desc_dma);
        rt2x00pci_register_write(rt2x00dev, TXCSR3, reg);
 
-       priv_tx = rt2x00dev->tx[0].entries[0].priv_data;
+       entry_priv = rt2x00dev->tx[0].entries[0].priv_data;
        rt2x00pci_register_read(rt2x00dev, TXCSR5, &reg);
        rt2x00_set_field32(&reg, TXCSR5_PRIO_RING_REGISTER,
-                          priv_tx->desc_dma);
+                          entry_priv->desc_dma);
        rt2x00pci_register_write(rt2x00dev, TXCSR5, reg);
 
-       priv_tx = rt2x00dev->bcn[1].entries[0].priv_data;
+       entry_priv = rt2x00dev->bcn[1].entries[0].priv_data;
        rt2x00pci_register_read(rt2x00dev, TXCSR4, &reg);
        rt2x00_set_field32(&reg, TXCSR4_ATIM_RING_REGISTER,
-                          priv_tx->desc_dma);
+                          entry_priv->desc_dma);
        rt2x00pci_register_write(rt2x00dev, TXCSR4, reg);
 
-       priv_tx = rt2x00dev->bcn[0].entries[0].priv_data;
+       entry_priv = rt2x00dev->bcn[0].entries[0].priv_data;
        rt2x00pci_register_read(rt2x00dev, TXCSR6, &reg);
        rt2x00_set_field32(&reg, TXCSR6_BEACON_RING_REGISTER,
-                          priv_tx->desc_dma);
+                          entry_priv->desc_dma);
        rt2x00pci_register_write(rt2x00dev, TXCSR6, reg);
 
        rt2x00pci_register_read(rt2x00dev, RXCSR1, &reg);
@@ -703,9 +693,10 @@ static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field32(&reg, RXCSR1_NUM_RXD, rt2x00dev->rx->limit);
        rt2x00pci_register_write(rt2x00dev, RXCSR1, reg);
 
-       priv_rx = rt2x00dev->rx->entries[0].priv_data;
+       entry_priv = rt2x00dev->rx->entries[0].priv_data;
        rt2x00pci_register_read(rt2x00dev, RXCSR2, &reg);
-       rt2x00_set_field32(&reg, RXCSR2_RX_RING_REGISTER, priv_rx->desc_dma);
+       rt2x00_set_field32(&reg, RXCSR2_RX_RING_REGISTER,
+                          entry_priv->desc_dma);
        rt2x00pci_register_write(rt2x00dev, RXCSR2, reg);
 
        return 0;
@@ -1001,17 +992,22 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev,
  */
 static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                    struct sk_buff *skb,
-                                   struct txentry_desc *txdesc,
-                                   struct ieee80211_tx_control *control)
+                                   struct txentry_desc *txdesc)
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+       struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
        __le32 *txd = skbdesc->desc;
        u32 word;
 
        /*
         * Start writing the descriptor words.
         */
+       rt2x00_desc_read(entry_priv->desc, 1, &word);
+       rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
+       rt2x00_desc_write(entry_priv->desc, 1, word);
+
        rt2x00_desc_read(txd, 2, &word);
+       rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, skbdesc->data_len);
        rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, skbdesc->data_len);
        rt2x00_desc_write(txd, 2, word);
 
@@ -1046,8 +1042,7 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                           test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
        rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
-                          !!(control->flags &
-                             IEEE80211_TXCTL_LONG_RETRY_LIMIT));
+                          test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
        rt2x00_desc_write(txd, 0, word);
 }
 
@@ -1055,11 +1050,11 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
  * TX data initialization
  */
 static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                   const unsigned int queue)
+                                   const enum data_queue_qid queue)
 {
        u32 reg;
 
-       if (queue == RT2X00_BCN_QUEUE_BEACON) {
+       if (queue == QID_BEACON) {
                rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
                if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) {
                        rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
@@ -1071,12 +1066,9 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
        }
 
        rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
-       rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO,
-                          (queue == IEEE80211_TX_QUEUE_DATA0));
-       rt2x00_set_field32(&reg, TXCSR0_KICK_TX,
-                          (queue == IEEE80211_TX_QUEUE_DATA1));
-       rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM,
-                          (queue == RT2X00_BCN_QUEUE_ATIM));
+       rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue == QID_AC_BE));
+       rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue == QID_AC_BK));
+       rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, (queue == QID_ATIM));
        rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
 }
 
@@ -1086,16 +1078,15 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 static void rt2400pci_fill_rxdone(struct queue_entry *entry,
                                  struct rxdone_entry_desc *rxdesc)
 {
-       struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data;
+       struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        u32 word0;
        u32 word2;
        u32 word3;
 
-       rt2x00_desc_read(priv_rx->desc, 0, &word0);
-       rt2x00_desc_read(priv_rx->desc, 2, &word2);
-       rt2x00_desc_read(priv_rx->desc, 3, &word3);
+       rt2x00_desc_read(entry_priv->desc, 0, &word0);
+       rt2x00_desc_read(entry_priv->desc, 2, &word2);
+       rt2x00_desc_read(entry_priv->desc, 3, &word3);
 
-       rxdesc->flags = 0;
        if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
                rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
        if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
@@ -1111,7 +1102,7 @@ static void rt2400pci_fill_rxdone(struct queue_entry *entry,
            entry->queue->rt2x00dev->rssi_offset;
        rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
 
-       rxdesc->dev_flags = RXDONE_SIGNAL_PLCP;
+       rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP;
        if (rt2x00_get_field32(word0, RXD_W0_MY_BSS))
                rxdesc->dev_flags |= RXDONE_MY_BSS;
 }
@@ -1120,18 +1111,18 @@ static void rt2400pci_fill_rxdone(struct queue_entry *entry,
  * Interrupt functions.
  */
 static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev,
-                            const enum ieee80211_tx_queue queue_idx)
+                            const enum data_queue_qid queue_idx)
 {
        struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, queue_idx);
-       struct queue_entry_priv_pci_tx *priv_tx;
+       struct queue_entry_priv_pci *entry_priv;
        struct queue_entry *entry;
        struct txdone_entry_desc txdesc;
        u32 word;
 
        while (!rt2x00queue_empty(queue)) {
                entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
-               priv_tx = entry->priv_data;
-               rt2x00_desc_read(priv_tx->desc, 0, &word);
+               entry_priv = entry->priv_data;
+               rt2x00_desc_read(entry_priv->desc, 0, &word);
 
                if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
                    !rt2x00_get_field32(word, TXD_W0_VALID))
@@ -1140,7 +1131,18 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev,
                /*
                 * Obtain the status about this packet.
                 */
-               txdesc.status = rt2x00_get_field32(word, TXD_W0_RESULT);
+               txdesc.flags = 0;
+               switch (rt2x00_get_field32(word, TXD_W0_RESULT)) {
+               case 0: /* Success */
+               case 1: /* Success with retry */
+                       __set_bit(TXDONE_SUCCESS, &txdesc.flags);
+                       break;
+               case 2: /* Failure, excessive retries */
+                       __set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags);
+                       /* Don't break, this is a failed frame! */
+               default: /* Failure */
+                       __set_bit(TXDONE_FAILURE, &txdesc.flags);
+               }
                txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
 
                rt2x00pci_txdone(rt2x00dev, entry, &txdesc);
@@ -1187,19 +1189,19 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
         * 3 - Atim ring transmit done interrupt.
         */
        if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING))
-               rt2400pci_txdone(rt2x00dev, RT2X00_BCN_QUEUE_ATIM);
+               rt2400pci_txdone(rt2x00dev, QID_ATIM);
 
        /*
         * 4 - Priority ring transmit done interrupt.
         */
        if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING))
-               rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
+               rt2400pci_txdone(rt2x00dev, QID_AC_BE);
 
        /*
         * 5 - Tx ring transmit done interrupt.
         */
        if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
-               rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
+               rt2400pci_txdone(rt2x00dev, QID_AC_BK);
 
        return IRQ_HANDLED;
 }
@@ -1364,11 +1366,9 @@ static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        /*
         * Initialize all hw fields.
         */
-       rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+       rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+                              IEEE80211_HW_SIGNAL_DBM;
        rt2x00dev->hw->extra_tx_headroom = 0;
-       rt2x00dev->hw->max_signal = MAX_SIGNAL;
-       rt2x00dev->hw->max_rssi = MAX_RX_SSI;
-       rt2x00dev->hw->queues = 2;
 
        SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
        SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
@@ -1445,8 +1445,7 @@ static int rt2400pci_set_retry_limit(struct ieee80211_hw *hw,
        return 0;
 }
 
-static int rt2400pci_conf_tx(struct ieee80211_hw *hw,
-                            int queue,
+static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue,
                             const struct ieee80211_tx_queue_params *params)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -1456,7 +1455,7 @@ static int rt2400pci_conf_tx(struct ieee80211_hw *hw,
         * per queue. So by default we only configure the TX queue,
         * and ignore all other configurations.
         */
-       if (queue != IEEE80211_TX_QUEUE_DATA0)
+       if (queue != 0)
                return -EINVAL;
 
        if (rt2x00mac_conf_tx(hw, queue, params))
@@ -1485,18 +1484,27 @@ static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw)
        return tsf;
 }
 
-static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
-                                  struct ieee80211_tx_control *control)
+static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
-       struct rt2x00_intf *intf = vif_to_intf(control->vif);
-       struct queue_entry_priv_pci_tx *priv_tx;
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
+       struct queue_entry_priv_pci *entry_priv;
        struct skb_frame_desc *skbdesc;
+       struct txentry_desc txdesc;
        u32 reg;
 
        if (unlikely(!intf->beacon))
                return -ENOBUFS;
-       priv_tx = intf->beacon->priv_data;
+       entry_priv = intf->beacon->priv_data;
+
+       /*
+        * Copy all TX descriptor information into txdesc,
+        * after that we are free to use the skb->cb array
+        * for our information.
+        */
+       intf->beacon->skb = skb;
+       rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
 
        /*
         * Fill in skb descriptor
@@ -1506,7 +1514,7 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
        skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED;
        skbdesc->data = skb->data;
        skbdesc->data_len = skb->len;
-       skbdesc->desc = priv_tx->desc;
+       skbdesc->desc = entry_priv->desc;
        skbdesc->desc_len = intf->beacon->queue->desc_size;
        skbdesc->entry = intf->beacon;
 
@@ -1520,21 +1528,14 @@ static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
        rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
        rt2x00pci_register_write(rt2x00dev, CSR14, reg);
 
-       /*
-        * mac80211 doesn't provide the control->queue variable
-        * for beacons. Set our own queue identification so
-        * it can be used during descriptor initialization.
-        */
-       control->queue = RT2X00_BCN_QUEUE_BEACON;
-       rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
-
        /*
         * Enable beacon generation.
         * Write entire beacon with descriptor to register,
         * and kick the beacon generator.
         */
-       memcpy(priv_tx->data, skb->data, skb->len);
-       rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue);
+       memcpy(entry_priv->data, skb->data, skb->len);
+       rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
+       rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
 
        return 0;
 }
@@ -1593,28 +1594,28 @@ static const struct data_queue_desc rt2400pci_queue_rx = {
        .entry_num              = RX_ENTRIES,
        .data_size              = DATA_FRAME_SIZE,
        .desc_size              = RXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_pci_rx),
+       .priv_size              = sizeof(struct queue_entry_priv_pci),
 };
 
 static const struct data_queue_desc rt2400pci_queue_tx = {
        .entry_num              = TX_ENTRIES,
        .data_size              = DATA_FRAME_SIZE,
        .desc_size              = TXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_pci_tx),
+       .priv_size              = sizeof(struct queue_entry_priv_pci),
 };
 
 static const struct data_queue_desc rt2400pci_queue_bcn = {
        .entry_num              = BEACON_ENTRIES,
        .data_size              = MGMT_FRAME_SIZE,
        .desc_size              = TXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_pci_tx),
+       .priv_size              = sizeof(struct queue_entry_priv_pci),
 };
 
 static const struct data_queue_desc rt2400pci_queue_atim = {
        .entry_num              = ATIM_ENTRIES,
        .data_size              = DATA_FRAME_SIZE,
        .desc_size              = TXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_pci_tx),
+       .priv_size              = sizeof(struct queue_entry_priv_pci),
 };
 
 static const struct rt2x00_ops rt2400pci_ops = {
@@ -1623,6 +1624,7 @@ static const struct rt2x00_ops rt2400pci_ops = {
        .max_ap_intf    = 1,
        .eeprom_size    = EEPROM_SIZE,
        .rf_size        = RF_SIZE,
+       .tx_queues      = NUM_TX_QUEUES,
        .rx             = &rt2400pci_queue_rx,
        .tx             = &rt2400pci_queue_tx,
        .bcn            = &rt2400pci_queue_bcn,
index a5210f9a3360ba521f7ca6dc786351156f32dc18..e9aa326be9f69243c9937974c572566b027e3d9e 100644 (file)
 #define BBP_SIZE                       0x0020
 #define RF_SIZE                                0x0010
 
+/*
+ * Number of TX queues.
+ */
+#define NUM_TX_QUEUES                  2
+
 /*
  * Control/Status Registers(CSR).
  * Some values are set in TU, whereas 1 TU == 1024 us.
index a5ed54b69262f8f6b167ebf87d6613b9c4319ec0..673350953b8990afa5e1992ba7aac61c156ca896 100644 (file)
@@ -317,8 +317,7 @@ static void rt2500pci_config_intf(struct rt2x00_dev *rt2x00dev,
                                  struct rt2x00intf_conf *conf,
                                  const unsigned int flags)
 {
-       struct data_queue *queue =
-           rt2x00queue_get_queue(rt2x00dev, RT2X00_BCN_QUEUE_BEACON);
+       struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, QID_BEACON);
        unsigned int bcn_preload;
        u32 reg;
 
@@ -716,38 +715,33 @@ dynamic_cca_tune:
 static void rt2500pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
                                   struct queue_entry *entry)
 {
-       struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data;
+       struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        u32 word;
 
-       rt2x00_desc_read(priv_rx->desc, 1, &word);
-       rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, priv_rx->data_dma);
-       rt2x00_desc_write(priv_rx->desc, 1, word);
+       rt2x00_desc_read(entry_priv->desc, 1, &word);
+       rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
+       rt2x00_desc_write(entry_priv->desc, 1, word);
 
-       rt2x00_desc_read(priv_rx->desc, 0, &word);
+       rt2x00_desc_read(entry_priv->desc, 0, &word);
        rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
-       rt2x00_desc_write(priv_rx->desc, 0, word);
+       rt2x00_desc_write(entry_priv->desc, 0, word);
 }
 
 static void rt2500pci_init_txentry(struct rt2x00_dev *rt2x00dev,
                                   struct queue_entry *entry)
 {
-       struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data;
+       struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        u32 word;
 
-       rt2x00_desc_read(priv_tx->desc, 1, &word);
-       rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, priv_tx->data_dma);
-       rt2x00_desc_write(priv_tx->desc, 1, word);
-
-       rt2x00_desc_read(priv_tx->desc, 0, &word);
+       rt2x00_desc_read(entry_priv->desc, 0, &word);
        rt2x00_set_field32(&word, TXD_W0_VALID, 0);
        rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
-       rt2x00_desc_write(priv_tx->desc, 0, word);
+       rt2x00_desc_write(entry_priv->desc, 0, word);
 }
 
 static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev)
 {
-       struct queue_entry_priv_pci_rx *priv_rx;
-       struct queue_entry_priv_pci_tx *priv_tx;
+       struct queue_entry_priv_pci *entry_priv;
        u32 reg;
 
        /*
@@ -760,28 +754,28 @@ static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field32(&reg, TXCSR2_NUM_PRIO, rt2x00dev->tx[0].limit);
        rt2x00pci_register_write(rt2x00dev, TXCSR2, reg);
 
-       priv_tx = rt2x00dev->tx[1].entries[0].priv_data;
+       entry_priv = rt2x00dev->tx[1].entries[0].priv_data;
        rt2x00pci_register_read(rt2x00dev, TXCSR3, &reg);
        rt2x00_set_field32(&reg, TXCSR3_TX_RING_REGISTER,
-                          priv_tx->desc_dma);
+                          entry_priv->desc_dma);
        rt2x00pci_register_write(rt2x00dev, TXCSR3, reg);
 
-       priv_tx = rt2x00dev->tx[0].entries[0].priv_data;
+       entry_priv = rt2x00dev->tx[0].entries[0].priv_data;
        rt2x00pci_register_read(rt2x00dev, TXCSR5, &reg);
        rt2x00_set_field32(&reg, TXCSR5_PRIO_RING_REGISTER,
-                          priv_tx->desc_dma);
+                          entry_priv->desc_dma);
        rt2x00pci_register_write(rt2x00dev, TXCSR5, reg);
 
-       priv_tx = rt2x00dev->bcn[1].entries[0].priv_data;
+       entry_priv = rt2x00dev->bcn[1].entries[0].priv_data;
        rt2x00pci_register_read(rt2x00dev, TXCSR4, &reg);
        rt2x00_set_field32(&reg, TXCSR4_ATIM_RING_REGISTER,
-                          priv_tx->desc_dma);
+                          entry_priv->desc_dma);
        rt2x00pci_register_write(rt2x00dev, TXCSR4, reg);
 
-       priv_tx = rt2x00dev->bcn[0].entries[0].priv_data;
+       entry_priv = rt2x00dev->bcn[0].entries[0].priv_data;
        rt2x00pci_register_read(rt2x00dev, TXCSR6, &reg);
        rt2x00_set_field32(&reg, TXCSR6_BEACON_RING_REGISTER,
-                          priv_tx->desc_dma);
+                          entry_priv->desc_dma);
        rt2x00pci_register_write(rt2x00dev, TXCSR6, reg);
 
        rt2x00pci_register_read(rt2x00dev, RXCSR1, &reg);
@@ -789,9 +783,10 @@ static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field32(&reg, RXCSR1_NUM_RXD, rt2x00dev->rx->limit);
        rt2x00pci_register_write(rt2x00dev, RXCSR1, reg);
 
-       priv_rx = rt2x00dev->rx->entries[0].priv_data;
+       entry_priv = rt2x00dev->rx->entries[0].priv_data;
        rt2x00pci_register_read(rt2x00dev, RXCSR2, &reg);
-       rt2x00_set_field32(&reg, RXCSR2_RX_RING_REGISTER, priv_rx->desc_dma);
+       rt2x00_set_field32(&reg, RXCSR2_RX_RING_REGISTER,
+                          entry_priv->desc_dma);
        rt2x00pci_register_write(rt2x00dev, RXCSR2, reg);
 
        return 0;
@@ -1156,16 +1151,20 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev,
  */
 static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                    struct sk_buff *skb,
-                                   struct txentry_desc *txdesc,
-                                   struct ieee80211_tx_control *control)
+                                   struct txentry_desc *txdesc)
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+       struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
        __le32 *txd = skbdesc->desc;
        u32 word;
 
        /*
         * Start writing the descriptor words.
         */
+       rt2x00_desc_read(entry_priv->desc, 1, &word);
+       rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
+       rt2x00_desc_write(entry_priv->desc, 1, word);
+
        rt2x00_desc_read(txd, 2, &word);
        rt2x00_set_field32(&word, TXD_W2_IV_OFFSET, IEEE80211_HEADER);
        rt2x00_set_field32(&word, TXD_W2_AIFS, txdesc->aifs);
@@ -1199,9 +1198,7 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXD_W0_CIPHER_OWNER, 1);
        rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
        rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
-                          !!(control->flags &
-                             IEEE80211_TXCTL_LONG_RETRY_LIMIT));
-       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len);
+                          test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
        rt2x00_desc_write(txd, 0, word);
 }
@@ -1210,11 +1207,11 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
  * TX data initialization
  */
 static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                   const unsigned int queue)
+                                   const enum data_queue_qid queue)
 {
        u32 reg;
 
-       if (queue == RT2X00_BCN_QUEUE_BEACON) {
+       if (queue == QID_BEACON) {
                rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
                if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) {
                        rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
@@ -1226,12 +1223,9 @@ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
        }
 
        rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
-       rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO,
-                          (queue == IEEE80211_TX_QUEUE_DATA0));
-       rt2x00_set_field32(&reg, TXCSR0_KICK_TX,
-                          (queue == IEEE80211_TX_QUEUE_DATA1));
-       rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM,
-                          (queue == RT2X00_BCN_QUEUE_ATIM));
+       rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue == QID_AC_BE));
+       rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue == QID_AC_BK));
+       rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, (queue == QID_ATIM));
        rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
 }
 
@@ -1241,14 +1235,13 @@ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 static void rt2500pci_fill_rxdone(struct queue_entry *entry,
                                  struct rxdone_entry_desc *rxdesc)
 {
-       struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data;
+       struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        u32 word0;
        u32 word2;
 
-       rt2x00_desc_read(priv_rx->desc, 0, &word0);
-       rt2x00_desc_read(priv_rx->desc, 2, &word2);
+       rt2x00_desc_read(entry_priv->desc, 0, &word0);
+       rt2x00_desc_read(entry_priv->desc, 2, &word2);
 
-       rxdesc->flags = 0;
        if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
                rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
        if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
@@ -1265,7 +1258,6 @@ static void rt2500pci_fill_rxdone(struct queue_entry *entry,
            entry->queue->rt2x00dev->rssi_offset;
        rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
 
-       rxdesc->dev_flags = 0;
        if (rt2x00_get_field32(word0, RXD_W0_OFDM))
                rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP;
        if (rt2x00_get_field32(word0, RXD_W0_MY_BSS))
@@ -1276,18 +1268,18 @@ static void rt2500pci_fill_rxdone(struct queue_entry *entry,
  * Interrupt functions.
  */
 static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev,
-                            const enum ieee80211_tx_queue queue_idx)
+                            const enum data_queue_qid queue_idx)
 {
        struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, queue_idx);
-       struct queue_entry_priv_pci_tx *priv_tx;
+       struct queue_entry_priv_pci *entry_priv;
        struct queue_entry *entry;
        struct txdone_entry_desc txdesc;
        u32 word;
 
        while (!rt2x00queue_empty(queue)) {
                entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
-               priv_tx = entry->priv_data;
-               rt2x00_desc_read(priv_tx->desc, 0, &word);
+               entry_priv = entry->priv_data;
+               rt2x00_desc_read(entry_priv->desc, 0, &word);
 
                if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
                    !rt2x00_get_field32(word, TXD_W0_VALID))
@@ -1296,7 +1288,18 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev,
                /*
                 * Obtain the status about this packet.
                 */
-               txdesc.status = rt2x00_get_field32(word, TXD_W0_RESULT);
+               txdesc.flags = 0;
+               switch (rt2x00_get_field32(word, TXD_W0_RESULT)) {
+               case 0: /* Success */
+               case 1: /* Success with retry */
+                       __set_bit(TXDONE_SUCCESS, &txdesc.flags);
+                       break;
+               case 2: /* Failure, excessive retries */
+                       __set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags);
+                       /* Don't break, this is a failed frame! */
+               default: /* Failure */
+                       __set_bit(TXDONE_FAILURE, &txdesc.flags);
+               }
                txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
 
                rt2x00pci_txdone(rt2x00dev, entry, &txdesc);
@@ -1343,19 +1346,19 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
         * 3 - Atim ring transmit done interrupt.
         */
        if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING))
-               rt2500pci_txdone(rt2x00dev, RT2X00_BCN_QUEUE_ATIM);
+               rt2500pci_txdone(rt2x00dev, QID_ATIM);
 
        /*
         * 4 - Priority ring transmit done interrupt.
         */
        if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING))
-               rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
+               rt2500pci_txdone(rt2x00dev, QID_AC_BE);
 
        /*
         * 5 - Tx ring transmit done interrupt.
         */
        if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
-               rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
+               rt2500pci_txdone(rt2x00dev, QID_AC_BK);
 
        return IRQ_HANDLED;
 }
@@ -1684,11 +1687,10 @@ static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        /*
         * Initialize all hw fields.
         */
-       rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+       rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+                              IEEE80211_HW_SIGNAL_DBM;
+
        rt2x00dev->hw->extra_tx_headroom = 0;
-       rt2x00dev->hw->max_signal = MAX_SIGNAL;
-       rt2x00dev->hw->max_rssi = MAX_RX_SSI;
-       rt2x00dev->hw->queues = 2;
 
        SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
        SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
@@ -1797,19 +1799,28 @@ static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw)
        return tsf;
 }
 
-static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
-                                  struct ieee80211_tx_control *control)
+static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
-       struct rt2x00_intf *intf = vif_to_intf(control->vif);
-       struct queue_entry_priv_pci_tx *priv_tx;
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
+       struct queue_entry_priv_pci *entry_priv;
        struct skb_frame_desc *skbdesc;
+       struct txentry_desc txdesc;
        u32 reg;
 
        if (unlikely(!intf->beacon))
                return -ENOBUFS;
 
-       priv_tx = intf->beacon->priv_data;
+       entry_priv = intf->beacon->priv_data;
+
+       /*
+        * Copy all TX descriptor information into txdesc,
+        * after that we are free to use the skb->cb array
+        * for our information.
+        */
+       intf->beacon->skb = skb;
+       rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
 
        /*
         * Fill in skb descriptor
@@ -1819,7 +1830,7 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
        skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED;
        skbdesc->data = skb->data;
        skbdesc->data_len = skb->len;
-       skbdesc->desc = priv_tx->desc;
+       skbdesc->desc = entry_priv->desc;
        skbdesc->desc_len = intf->beacon->queue->desc_size;
        skbdesc->entry = intf->beacon;
 
@@ -1833,21 +1844,14 @@ static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
        rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
        rt2x00pci_register_write(rt2x00dev, CSR14, reg);
 
-       /*
-        * mac80211 doesn't provide the control->queue variable
-        * for beacons. Set our own queue identification so
-        * it can be used during descriptor initialization.
-        */
-       control->queue = RT2X00_BCN_QUEUE_BEACON;
-       rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
-
        /*
         * Enable beacon generation.
         * Write entire beacon with descriptor to register,
         * and kick the beacon generator.
         */
-       memcpy(priv_tx->data, skb->data, skb->len);
-       rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue);
+       memcpy(entry_priv->data, skb->data, skb->len);
+       rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
+       rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
 
        return 0;
 }
@@ -1906,28 +1910,28 @@ static const struct data_queue_desc rt2500pci_queue_rx = {
        .entry_num              = RX_ENTRIES,
        .data_size              = DATA_FRAME_SIZE,
        .desc_size              = RXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_pci_rx),
+       .priv_size              = sizeof(struct queue_entry_priv_pci),
 };
 
 static const struct data_queue_desc rt2500pci_queue_tx = {
        .entry_num              = TX_ENTRIES,
        .data_size              = DATA_FRAME_SIZE,
        .desc_size              = TXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_pci_tx),
+       .priv_size              = sizeof(struct queue_entry_priv_pci),
 };
 
 static const struct data_queue_desc rt2500pci_queue_bcn = {
        .entry_num              = BEACON_ENTRIES,
        .data_size              = MGMT_FRAME_SIZE,
        .desc_size              = TXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_pci_tx),
+       .priv_size              = sizeof(struct queue_entry_priv_pci),
 };
 
 static const struct data_queue_desc rt2500pci_queue_atim = {
        .entry_num              = ATIM_ENTRIES,
        .data_size              = DATA_FRAME_SIZE,
        .desc_size              = TXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_pci_tx),
+       .priv_size              = sizeof(struct queue_entry_priv_pci),
 };
 
 static const struct rt2x00_ops rt2500pci_ops = {
@@ -1936,6 +1940,7 @@ static const struct rt2x00_ops rt2500pci_ops = {
        .max_ap_intf    = 1,
        .eeprom_size    = EEPROM_SIZE,
        .rf_size        = RF_SIZE,
+       .tx_queues      = NUM_TX_QUEUES,
        .rx             = &rt2500pci_queue_rx,
        .tx             = &rt2500pci_queue_tx,
        .bcn            = &rt2500pci_queue_bcn,
index 13899550465acf5f402bd9c3c96d230235f7ac90..ea93b8f423a98a5ff2106340aae7fff5e0ba2c4f 100644 (file)
 #define BBP_SIZE                       0x0040
 #define RF_SIZE                                0x0014
 
+/*
+ * Number of TX queues.
+ */
+#define NUM_TX_QUEUES                  2
+
 /*
  * Control/Status Registers(CSR).
  * Some values are set in TU, whereas 1 TU == 1024 us.
index fdbd0ef2be4bceef492431262796e6466a11e0b8..cca1504550dc6aa86347f42cd17e887b73ce05e3 100644 (file)
@@ -76,10 +76,10 @@ static inline void rt2500usb_register_multiread(struct rt2x00_dev *rt2x00dev,
                                                const unsigned int offset,
                                                void *value, const u16 length)
 {
-       int timeout = REGISTER_TIMEOUT * (length / sizeof(u16));
        rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
                                      USB_VENDOR_REQUEST_IN, offset,
-                                     value, length, timeout);
+                                     value, length,
+                                     REGISTER_TIMEOUT16(length));
 }
 
 static inline void rt2500usb_register_write(struct rt2x00_dev *rt2x00dev,
@@ -106,10 +106,10 @@ static inline void rt2500usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
                                                 const unsigned int offset,
                                                 void *value, const u16 length)
 {
-       int timeout = REGISTER_TIMEOUT * (length / sizeof(u16));
        rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
                                      USB_VENDOR_REQUEST_OUT, offset,
-                                     value, length, timeout);
+                                     value, length,
+                                     REGISTER_TIMEOUT16(length));
 }
 
 static u16 rt2500usb_bbp_check(struct rt2x00_dev *rt2x00dev)
@@ -1033,8 +1033,7 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev,
  */
 static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                    struct sk_buff *skb,
-                                   struct txentry_desc *txdesc,
-                                   struct ieee80211_tx_control *control)
+                                   struct txentry_desc *txdesc)
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
        __le32 *txd = skbdesc->desc;
@@ -1058,7 +1057,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_desc_write(txd, 2, word);
 
        rt2x00_desc_read(txd, 0, &word);
-       rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, control->retry_limit);
+       rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, txdesc->retry_limit);
        rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
                           test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W0_ACK,
@@ -1068,7 +1067,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXD_W0_OFDM,
                           test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W0_NEW_SEQ,
-                          !!(control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT));
+                          test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
        rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len);
        rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE);
@@ -1094,11 +1093,11 @@ static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
  * TX data initialization
  */
 static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                   const unsigned int queue)
+                                   const enum data_queue_qid queue)
 {
        u16 reg;
 
-       if (queue != RT2X00_BCN_QUEUE_BEACON)
+       if (queue != QID_BEACON)
                return;
 
        rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
@@ -1125,30 +1124,32 @@ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 static void rt2500usb_fill_rxdone(struct queue_entry *entry,
                                  struct rxdone_entry_desc *rxdesc)
 {
-       struct queue_entry_priv_usb_rx *priv_rx = entry->priv_data;
+       struct queue_entry_priv_usb *entry_priv = entry->priv_data;
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
        __le32 *rxd =
            (__le32 *)(entry->skb->data +
-                      (priv_rx->urb->actual_length - entry->queue->desc_size));
-       unsigned int offset = entry->queue->desc_size + 2;
+                      (entry_priv->urb->actual_length -
+                       entry->queue->desc_size));
        u32 word0;
        u32 word1;
 
        /*
-        * Copy descriptor to the available headroom inside the skbuffer.
+        * Copy descriptor to the skb->cb array, this has 2 benefits:
+        * 1) Each descriptor word is 4 byte aligned.
+        * 2) Descriptor is safe  from moving of frame data in rt2x00usb.
         */
-       skb_push(entry->skb, offset);
-       memcpy(entry->skb->data, rxd, entry->queue->desc_size);
-       rxd = (__le32 *)entry->skb->data;
+       skbdesc->desc_len =
+           min_t(u16, entry->queue->desc_size, sizeof(entry->skb->cb));
+       memcpy(entry->skb->cb, rxd, skbdesc->desc_len);
+       skbdesc->desc = entry->skb->cb;
+       rxd = (__le32 *)skbdesc->desc;
 
        /*
-        * The descriptor is now aligned to 4 bytes and thus it is
-        * now safe to read it on all architectures.
+        * It is now safe to read the descriptor on all architectures.
         */
        rt2x00_desc_read(rxd, 0, &word0);
        rt2x00_desc_read(rxd, 1, &word1);
 
-       rxdesc->flags = 0;
        if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
                rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
        if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
@@ -1165,7 +1166,6 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry,
            entry->queue->rt2x00dev->rssi_offset;
        rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
 
-       rxdesc->dev_flags = 0;
        if (rt2x00_get_field32(word0, RXD_W0_OFDM))
                rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP;
        if (rt2x00_get_field32(word0, RXD_W0_MY_BSS))
@@ -1174,16 +1174,9 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry,
        /*
         * Adjust the skb memory window to the frame boundaries.
         */
-       skb_pull(entry->skb, offset);
        skb_trim(entry->skb, rxdesc->size);
-
-       /*
-        * Set descriptor and data pointer.
-        */
        skbdesc->data = entry->skb->data;
        skbdesc->data_len = rxdesc->size;
-       skbdesc->desc = rxd;
-       skbdesc->desc_len = entry->queue->desc_size;
 }
 
 /*
@@ -1192,7 +1185,7 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry,
 static void rt2500usb_beacondone(struct urb *urb)
 {
        struct queue_entry *entry = (struct queue_entry *)urb->context;
-       struct queue_entry_priv_usb_bcn *priv_bcn = entry->priv_data;
+       struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
 
        if (!test_bit(DEVICE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags))
                return;
@@ -1203,9 +1196,9 @@ static void rt2500usb_beacondone(struct urb *urb)
         * Otherwise we should free the sk_buffer, the device
         * should be doing the rest of the work now.
         */
-       if (priv_bcn->guardian_urb == urb) {
-               usb_submit_urb(priv_bcn->urb, GFP_ATOMIC);
-       } else if (priv_bcn->urb == urb) {
+       if (bcn_priv->guardian_urb == urb) {
+               usb_submit_urb(bcn_priv->urb, GFP_ATOMIC);
+       } else if (bcn_priv->urb == urb) {
                dev_kfree_skb(entry->skb);
                entry->skb = NULL;
        }
@@ -1587,11 +1580,10 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        rt2x00dev->hw->flags =
            IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
            IEEE80211_HW_RX_INCLUDES_FCS |
-           IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+           IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+           IEEE80211_HW_SIGNAL_DBM;
+
        rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
-       rt2x00dev->hw->max_signal = MAX_SIGNAL;
-       rt2x00dev->hw->max_rssi = MAX_RX_SSI;
-       rt2x00dev->hw->queues = 2;
 
        SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);
        SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
@@ -1674,15 +1666,15 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
 /*
  * IEEE80211 stack callback functions.
  */
-static int rt2500usb_beacon_update(struct ieee80211_hw *hw,
-                                  struct sk_buff *skb,
-                                  struct ieee80211_tx_control *control)
+static int rt2500usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev);
-       struct rt2x00_intf *intf = vif_to_intf(control->vif);
-       struct queue_entry_priv_usb_bcn *priv_bcn;
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
+       struct queue_entry_priv_usb_bcn *bcn_priv;
        struct skb_frame_desc *skbdesc;
+       struct txentry_desc txdesc;
        int pipe = usb_sndbulkpipe(usb_dev, 1);
        int length;
        u16 reg;
@@ -1690,7 +1682,15 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw,
        if (unlikely(!intf->beacon))
                return -ENOBUFS;
 
-       priv_bcn = intf->beacon->priv_data;
+       bcn_priv = intf->beacon->priv_data;
+
+       /*
+        * Copy all TX descriptor information into txdesc,
+        * after that we are free to use the skb->cb array
+        * for our information.
+        */
+       intf->beacon->skb = skb;
+       rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
 
        /*
         * Add the descriptor in front of the skb.
@@ -1720,13 +1720,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw,
        rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 0);
        rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
 
-       /*
-        * mac80211 doesn't provide the control->queue variable
-        * for beacons. Set our own queue identification so
-        * it can be used during descriptor initialization.
-        */
-       control->queue = RT2X00_BCN_QUEUE_BEACON;
-       rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
+       rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
 
        /*
         * USB devices cannot blindly pass the skb->len as the
@@ -1735,7 +1729,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw,
         */
        length = rt2500usb_get_tx_data_len(rt2x00dev, skb);
 
-       usb_fill_bulk_urb(priv_bcn->urb, usb_dev, pipe,
+       usb_fill_bulk_urb(bcn_priv->urb, usb_dev, pipe,
                          skb->data, length, rt2500usb_beacondone,
                          intf->beacon);
 
@@ -1744,20 +1738,20 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw,
         * We only need a single byte, so lets recycle
         * the 'flags' field we are not using for beacons.
         */
-       priv_bcn->guardian_data = 0;
-       usb_fill_bulk_urb(priv_bcn->guardian_urb, usb_dev, pipe,
-                         &priv_bcn->guardian_data, 1, rt2500usb_beacondone,
+       bcn_priv->guardian_data = 0;
+       usb_fill_bulk_urb(bcn_priv->guardian_urb, usb_dev, pipe,
+                         &bcn_priv->guardian_data, 1, rt2500usb_beacondone,
                          intf->beacon);
 
        /*
         * Send out the guardian byte.
         */
-       usb_submit_urb(priv_bcn->guardian_urb, GFP_ATOMIC);
+       usb_submit_urb(bcn_priv->guardian_urb, GFP_ATOMIC);
 
        /*
         * Enable beacon generation.
         */
-       rt2500usb_kick_tx_queue(rt2x00dev, control->queue);
+       rt2500usb_kick_tx_queue(rt2x00dev, QID_BEACON);
 
        return 0;
 }
@@ -1803,14 +1797,14 @@ static const struct data_queue_desc rt2500usb_queue_rx = {
        .entry_num              = RX_ENTRIES,
        .data_size              = DATA_FRAME_SIZE,
        .desc_size              = RXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_usb_rx),
+       .priv_size              = sizeof(struct queue_entry_priv_usb),
 };
 
 static const struct data_queue_desc rt2500usb_queue_tx = {
        .entry_num              = TX_ENTRIES,
        .data_size              = DATA_FRAME_SIZE,
        .desc_size              = TXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_usb_tx),
+       .priv_size              = sizeof(struct queue_entry_priv_usb),
 };
 
 static const struct data_queue_desc rt2500usb_queue_bcn = {
@@ -1824,7 +1818,7 @@ static const struct data_queue_desc rt2500usb_queue_atim = {
        .entry_num              = ATIM_ENTRIES,
        .data_size              = DATA_FRAME_SIZE,
        .desc_size              = TXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_usb_tx),
+       .priv_size              = sizeof(struct queue_entry_priv_usb),
 };
 
 static const struct rt2x00_ops rt2500usb_ops = {
@@ -1833,6 +1827,7 @@ static const struct rt2x00_ops rt2500usb_ops = {
        .max_ap_intf    = 1,
        .eeprom_size    = EEPROM_SIZE,
        .rf_size        = RF_SIZE,
+       .tx_queues      = NUM_TX_QUEUES,
        .rx             = &rt2500usb_queue_rx,
        .tx             = &rt2500usb_queue_tx,
        .bcn            = &rt2500usb_queue_bcn,
index a37a068d0c71d00bbf63a959e390aa1b1926744d..7d50098f0cc5d7affe871c840e63a1b6f3024875 100644 (file)
 #define BBP_SIZE                       0x0060
 #define RF_SIZE                                0x0014
 
+/*
+ * Number of TX queues.
+ */
+#define NUM_TX_QUEUES                  2
+
 /*
  * Control/Status Registers(CSR).
  * Some values are set in TU, whereas 1 TU == 1024 us.
index 611d98320593869dc9c26faf2c64218c8c32e3ec..15ec797c5ec191acc930e37abb7caef6cecb006d 100644 (file)
@@ -44,7 +44,7 @@
 /*
  * Module information.
  */
-#define DRV_VERSION    "2.1.4"
+#define DRV_VERSION    "2.1.6"
 #define DRV_PROJECT    "http://rt2x00.serialmonkey.com"
 
 /*
@@ -409,7 +409,7 @@ static inline struct rt2x00_intf* vif_to_intf(struct ieee80211_vif *vif)
  * @supported_rates: Rate types which are supported (CCK, OFDM).
  * @num_channels: Number of supported channels. This is used as array size
  *     for @tx_power_a, @tx_power_bg and @channels.
- * channels: Device/chipset specific channel values (See &struct rf_channel).
+ * @channels: Device/chipset specific channel values (See &struct rf_channel).
  * @tx_power_a: TX power values for all 5.2GHz channels (may be NULL).
  * @tx_power_bg: TX power values for all 2.4GHz channels (may be NULL).
  * @tx_power_default: Default TX power value to use when either
@@ -545,15 +545,13 @@ struct rt2x00lib_ops {
         */
        void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev,
                               struct sk_buff *skb,
-                              struct txentry_desc *txdesc,
-                              struct ieee80211_tx_control *control);
+                              struct txentry_desc *txdesc);
        int (*write_tx_data) (struct rt2x00_dev *rt2x00dev,
-                             struct data_queue *queue, struct sk_buff *skb,
-                             struct ieee80211_tx_control *control);
+                             struct data_queue *queue, struct sk_buff *skb);
        int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev,
                                struct sk_buff *skb);
        void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev,
-                              const unsigned int queue);
+                              const enum data_queue_qid queue);
 
        /*
         * RX control handlers
@@ -597,6 +595,7 @@ struct rt2x00_ops {
        const unsigned int max_ap_intf;
        const unsigned int eeprom_size;
        const unsigned int rf_size;
+       const unsigned int tx_queues;
        const struct data_queue_desc *rx;
        const struct data_queue_desc *tx;
        const struct data_queue_desc *bcn;
@@ -626,7 +625,6 @@ enum rt2x00_flags {
        /*
         * Driver features
         */
-       DRIVER_SUPPORT_MIXED_INTERFACES,
        DRIVER_REQUIRE_FIRMWARE,
        DRIVER_REQUIRE_BEACON_GUARD,
        DRIVER_REQUIRE_ATIM_QUEUE,
@@ -933,17 +931,49 @@ static inline u16 get_duration_res(const unsigned int size, const u8 rate)
 }
 
 /**
- * rt2x00queue_get_queue - Convert mac80211 queue index to rt2x00 queue
+ * rt2x00queue_create_tx_descriptor - Create TX descriptor from mac80211 input
+ * @entry: The entry which will be used to transfer the TX frame.
+ * @txdesc: rt2x00 TX descriptor which will be initialized by this function.
+ *
+ * This function will initialize the &struct txentry_desc based on information
+ * from mac80211. This descriptor can then be used by rt2x00lib and the drivers
+ * to correctly initialize the hardware descriptor.
+ * Note that before calling this function the skb->cb array must be untouched
+ * by rt2x00lib. Only after this function completes will it be save to
+ * overwrite the skb->cb information.
+ * The reason for this is that mac80211 writes its own tx information into
+ * the skb->cb array, and this function will use that information to initialize
+ * the &struct txentry_desc structure.
+ */
+void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
+                                     struct txentry_desc *txdesc);
+
+/**
+ * rt2x00queue_write_tx_descriptor - Write TX descriptor to hardware
+ * @entry: The entry which will be used to transfer the TX frame.
+ * @txdesc: TX descriptor which will be used to write hardware descriptor
+ *
+ * This function will write a TX descriptor initialized by
+ * &rt2x00queue_create_tx_descriptor to the hardware. After this call
+ * has completed the frame is now owned by the hardware, the hardware
+ * queue will have automatically be kicked unless this frame was generated
+ * by rt2x00lib, in which case the frame is "special" and must be kicked
+ * by the caller.
+ */
+void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
+                                    struct txentry_desc *txdesc);
+
+/**
+ * rt2x00queue_get_queue - Convert queue index to queue pointer
  * @rt2x00dev: Pointer to &struct rt2x00_dev.
- * @queue: mac80211/rt2x00 queue index
- *     (see &enum ieee80211_tx_queue and &enum rt2x00_bcn_queue).
+ * @queue: rt2x00 queue index (see &enum data_queue_qid).
  */
 struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
-                                        const unsigned int queue);
+                                        const enum data_queue_qid queue);
 
 /**
  * rt2x00queue_get_entry - Get queue entry where the given index points to.
- * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @queue: Pointer to &struct data_queue from where we obtain the entry.
  * @index: Index identifier for obtaining the correct index.
  */
 struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
@@ -952,7 +982,7 @@ struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
 /**
  * rt2x00queue_index_inc - Index incrementation function
  * @queue: Queue (&struct data_queue) to perform the action on.
- * @action: Index type (&enum queue_index) to perform the action on.
+ * @index: Index type (&enum queue_index) to perform the action on.
  *
  * This function will increase the requested index on the queue,
  * it will grab the appropriate locks and handle queue overflow events by
@@ -970,18 +1000,10 @@ void rt2x00lib_txdone(struct queue_entry *entry,
 void rt2x00lib_rxdone(struct queue_entry *entry,
                      struct rxdone_entry_desc *rxdesc);
 
-/*
- * TX descriptor initializer
- */
-void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-                            struct sk_buff *skb,
-                            struct ieee80211_tx_control *control);
-
 /*
  * mac80211 handlers.
  */
-int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
-                struct ieee80211_tx_control *control);
+int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
 int rt2x00mac_start(struct ieee80211_hw *hw);
 void rt2x00mac_stop(struct ieee80211_hw *hw);
 int rt2x00mac_add_interface(struct ieee80211_hw *hw,
@@ -1004,7 +1026,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
                                struct ieee80211_vif *vif,
                                struct ieee80211_bss_conf *bss_conf,
                                u32 changes);
-int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue,
+int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
                      const struct ieee80211_tx_queue_params *params);
 
 /*
index bfab3b8780d63ee2a953e65c4e194adb1cb10a72..bd92cb8e68e059131ef70674b46188d84fea917f 100644 (file)
@@ -115,7 +115,7 @@ struct rt2x00debug_intf {
 };
 
 void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
-                           struct sk_buff *skb)
+                           enum rt2x00_dump_type type, struct sk_buff *skb)
 {
        struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
        struct skb_frame_desc *desc = get_skb_frame_desc(skb);
@@ -148,7 +148,7 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
        dump_hdr->chip_rt = cpu_to_le16(rt2x00dev->chip.rt);
        dump_hdr->chip_rf = cpu_to_le16(rt2x00dev->chip.rf);
        dump_hdr->chip_rev = cpu_to_le32(rt2x00dev->chip.rev);
-       dump_hdr->type = cpu_to_le16(desc->frame_type);
+       dump_hdr->type = cpu_to_le16(type);
        dump_hdr->queue_index = desc->entry->queue->qid;
        dump_hdr->entry_index = desc->entry->entry_idx;
        dump_hdr->timestamp_sec = cpu_to_le32(timestamp.tv_sec);
index 2673d568bcac286dc9f3cbdb8da9d3c5051ff7cc..f7a44170c0257c6d31da587b0ebd154854958b1b 100644 (file)
@@ -28,7 +28,6 @@
 
 #include "rt2x00.h"
 #include "rt2x00lib.h"
-#include "rt2x00dump.h"
 
 /*
  * Link tuning handlers
@@ -126,7 +125,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
        /*
         * Start the TX queues.
         */
-       ieee80211_start_queues(rt2x00dev->hw);
+       ieee80211_wake_queues(rt2x00dev->hw);
 
        return 0;
 }
@@ -416,7 +415,6 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
        struct rt2x00_dev *rt2x00dev = data;
        struct rt2x00_intf *intf = vif_to_intf(vif);
        struct sk_buff *skb;
-       struct ieee80211_tx_control control;
        struct ieee80211_bss_conf conf;
        int delayed_flags;
 
@@ -434,9 +432,9 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
        spin_unlock(&intf->lock);
 
        if (delayed_flags & DELAYED_UPDATE_BEACON) {
-               skb = ieee80211_beacon_get(rt2x00dev->hw, vif, &control);
-               if (skb && rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw,
-                                                            skb, &control))
+               skb = ieee80211_beacon_get(rt2x00dev->hw, vif);
+               if (skb &&
+                   rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, skb))
                        dev_kfree_skb(skb);
        }
 
@@ -495,64 +493,55 @@ void rt2x00lib_txdone(struct queue_entry *entry,
                      struct txdone_entry_desc *txdesc)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-       struct skb_frame_desc *skbdesc;
-       struct ieee80211_tx_status tx_status;
-       int success = !!(txdesc->status == TX_SUCCESS ||
-                        txdesc->status == TX_SUCCESS_RETRY);
-       int fail = !!(txdesc->status == TX_FAIL_RETRY ||
-                     txdesc->status == TX_FAIL_INVALID ||
-                     txdesc->status == TX_FAIL_OTHER);
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
+
+       /*
+        * Send frame to debugfs immediately, after this call is completed
+        * we are going to overwrite the skb->cb array.
+        */
+       rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TXDONE, entry->skb);
 
        /*
         * Update TX statistics.
         */
-       rt2x00dev->link.qual.tx_success += success;
-       rt2x00dev->link.qual.tx_failed += fail;
+       rt2x00dev->link.qual.tx_success +=
+           test_bit(TXDONE_SUCCESS, &txdesc->flags);
+       rt2x00dev->link.qual.tx_failed +=
+           txdesc->retry + !!test_bit(TXDONE_FAILURE, &txdesc->flags);
 
        /*
         * Initialize TX status
         */
-       tx_status.flags = 0;
-       tx_status.ack_signal = 0;
-       tx_status.excessive_retries = (txdesc->status == TX_FAIL_RETRY);
-       tx_status.retry_count = txdesc->retry;
-       memcpy(&tx_status.control, txdesc->control, sizeof(*txdesc->control));
+       memset(&tx_info->status, 0, sizeof(tx_info->status));
+       tx_info->status.ack_signal = 0;
+       tx_info->status.excessive_retries =
+           test_bit(TXDONE_EXCESSIVE_RETRY, &txdesc->flags);
+       tx_info->status.retry_count = txdesc->retry;
 
-       if (!(tx_status.control.flags & IEEE80211_TXCTL_NO_ACK)) {
-               if (success)
-                       tx_status.flags |= IEEE80211_TX_STATUS_ACK;
-               else
+       if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
+               if (test_bit(TXDONE_SUCCESS, &txdesc->flags))
+                       tx_info->flags |= IEEE80211_TX_STAT_ACK;
+               else if (test_bit(TXDONE_FAILURE, &txdesc->flags))
                        rt2x00dev->low_level_stats.dot11ACKFailureCount++;
        }
 
-       tx_status.queue_length = entry->queue->limit;
-       tx_status.queue_number = tx_status.control.queue;
-
-       if (tx_status.control.flags & IEEE80211_TXCTL_USE_RTS_CTS) {
-               if (success)
+       if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
+               if (test_bit(TXDONE_SUCCESS, &txdesc->flags))
                        rt2x00dev->low_level_stats.dot11RTSSuccessCount++;
-               else
+               else if (test_bit(TXDONE_FAILURE, &txdesc->flags))
                        rt2x00dev->low_level_stats.dot11RTSFailureCount++;
        }
 
        /*
-        * Send the tx_status to debugfs. Only send the status report
-        * to mac80211 when the frame originated from there. If this was
-        * a extra frame coming through a mac80211 library call (RTS/CTS)
-        * then we should not send the status report back.
-        * If send to mac80211, mac80211 will clean up the skb structure,
-        * otherwise we have to do it ourself.
+        * Only send the status report to mac80211 when TX status was
+        * requested by it. If this was a extra frame coming through
+        * a mac80211 library call (RTS/CTS) then we should not send the
+        * status report back.
         */
-       skbdesc = get_skb_frame_desc(entry->skb);
-       skbdesc->frame_type = DUMP_FRAME_TXDONE;
-
-       rt2x00debug_dump_frame(rt2x00dev, entry->skb);
-
-       if (!(skbdesc->flags & FRAME_DESC_DRIVER_GENERATED))
-               ieee80211_tx_status_irqsafe(rt2x00dev->hw,
-                                           entry->skb, &tx_status);
+       if (tx_info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)
+               ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb);
        else
-               dev_kfree_skb(entry->skb);
+               dev_kfree_skb_irq(entry->skb);
        entry->skb = NULL;
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_txdone);
@@ -603,9 +592,9 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
        rt2x00dev->link.qual.rx_success++;
 
        rx_status->rate_idx = idx;
-       rx_status->signal =
+       rx_status->qual =
            rt2x00lib_calculate_link_signal(rt2x00dev, rxdesc->rssi);
-       rx_status->ssi = rxdesc->rssi;
+       rx_status->signal = rxdesc->rssi;
        rx_status->flag = rxdesc->flags;
        rx_status->antenna = rt2x00dev->link.ant.active.rx;
 
@@ -613,154 +602,12 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
         * Send frame to mac80211 & debugfs.
         * mac80211 will clean up the skb structure.
         */
-       get_skb_frame_desc(entry->skb)->frame_type = DUMP_FRAME_RXDONE;
-       rt2x00debug_dump_frame(rt2x00dev, entry->skb);
+       rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
        ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb, rx_status);
        entry->skb = NULL;
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
 
-/*
- * TX descriptor initializer
- */
-void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-                            struct sk_buff *skb,
-                            struct ieee80211_tx_control *control)
-{
-       struct txentry_desc txdesc;
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skbdesc->data;
-       const struct rt2x00_rate *rate;
-       int tx_rate;
-       int length;
-       int duration;
-       int residual;
-       u16 frame_control;
-       u16 seq_ctrl;
-
-       memset(&txdesc, 0, sizeof(txdesc));
-
-       txdesc.queue = skbdesc->entry->queue->qid;
-       txdesc.cw_min = skbdesc->entry->queue->cw_min;
-       txdesc.cw_max = skbdesc->entry->queue->cw_max;
-       txdesc.aifs = skbdesc->entry->queue->aifs;
-
-       /*
-        * Read required fields from ieee80211 header.
-        */
-       frame_control = le16_to_cpu(hdr->frame_control);
-       seq_ctrl = le16_to_cpu(hdr->seq_ctrl);
-
-       tx_rate = control->tx_rate->hw_value;
-
-       /*
-        * Check whether this frame is to be acked
-        */
-       if (!(control->flags & IEEE80211_TXCTL_NO_ACK))
-               __set_bit(ENTRY_TXD_ACK, &txdesc.flags);
-
-       /*
-        * Check if this is a RTS/CTS frame
-        */
-       if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) {
-               __set_bit(ENTRY_TXD_BURST, &txdesc.flags);
-               if (is_rts_frame(frame_control)) {
-                       __set_bit(ENTRY_TXD_RTS_FRAME, &txdesc.flags);
-                       __set_bit(ENTRY_TXD_ACK, &txdesc.flags);
-               } else
-                       __clear_bit(ENTRY_TXD_ACK, &txdesc.flags);
-               if (control->rts_cts_rate)
-                       tx_rate = control->rts_cts_rate->hw_value;
-       }
-
-       rate = rt2x00_get_rate(tx_rate);
-
-       /*
-        * Check if more fragments are pending
-        */
-       if (ieee80211_get_morefrag(hdr)) {
-               __set_bit(ENTRY_TXD_BURST, &txdesc.flags);
-               __set_bit(ENTRY_TXD_MORE_FRAG, &txdesc.flags);
-       }
-
-       /*
-        * Beacons and probe responses require the tsf timestamp
-        * to be inserted into the frame.
-        */
-       if (control->queue == RT2X00_BCN_QUEUE_BEACON ||
-           is_probe_resp(frame_control))
-               __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc.flags);
-
-       /*
-        * Determine with what IFS priority this frame should be send.
-        * Set ifs to IFS_SIFS when the this is not the first fragment,
-        * or this fragment came after RTS/CTS.
-        */
-       if ((seq_ctrl & IEEE80211_SCTL_FRAG) > 0 ||
-           test_bit(ENTRY_TXD_RTS_FRAME, &txdesc.flags))
-               txdesc.ifs = IFS_SIFS;
-       else
-               txdesc.ifs = IFS_BACKOFF;
-
-       /*
-        * PLCP setup
-        * Length calculation depends on OFDM/CCK rate.
-        */
-       txdesc.signal = rate->plcp;
-       txdesc.service = 0x04;
-
-       length = skbdesc->data_len + FCS_LEN;
-       if (rate->flags & DEV_RATE_OFDM) {
-               __set_bit(ENTRY_TXD_OFDM_RATE, &txdesc.flags);
-
-               txdesc.length_high = (length >> 6) & 0x3f;
-               txdesc.length_low = length & 0x3f;
-       } else {
-               /*
-                * Convert length to microseconds.
-                */
-               residual = get_duration_res(length, rate->bitrate);
-               duration = get_duration(length, rate->bitrate);
-
-               if (residual != 0) {
-                       duration++;
-
-                       /*
-                        * Check if we need to set the Length Extension
-                        */
-                       if (rate->bitrate == 110 && residual <= 30)
-                               txdesc.service |= 0x80;
-               }
-
-               txdesc.length_high = (duration >> 8) & 0xff;
-               txdesc.length_low = duration & 0xff;
-
-               /*
-                * When preamble is enabled we should set the
-                * preamble bit for the signal.
-                */
-               if (rt2x00_get_rate_preamble(tx_rate))
-                       txdesc.signal |= 0x08;
-       }
-
-       rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, skb, &txdesc, control);
-
-       /*
-        * Update queue entry.
-        */
-       skbdesc->entry->skb = skb;
-
-       /*
-        * The frame has been completely initialized and ready
-        * for sending to the device. The caller will push the
-        * frame to the device, but we are going to push the
-        * frame to debugfs here.
-        */
-       skbdesc->frame_type = DUMP_FRAME_TX;
-       rt2x00debug_dump_frame(rt2x00dev, skb);
-}
-EXPORT_SYMBOL_GPL(rt2x00lib_write_tx_desc);
-
 /*
  * Driver initialization handlers.
  */
@@ -976,6 +823,11 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
        if (status)
                return status;
 
+       /*
+        * Initialize HW fields.
+        */
+       rt2x00dev->hw->queues = rt2x00dev->ops->tx_queues;
+
        /*
         * Register HW.
         */
@@ -1331,7 +1183,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
         * In that case we have disabled the TX queue and should
         * now enable it again
         */
-       ieee80211_start_queues(rt2x00dev->hw);
+       ieee80211_wake_queues(rt2x00dev->hw);
 
        /*
         * During interface iteration we might have changed the
index 41ee02cd28252fe98bfe825fd37e0ee5db4ba0af..c4ce534e3cdbbac56c52177aa4bc02179da897aa 100644 (file)
@@ -26,6 +26,8 @@
 #ifndef RT2X00LIB_H
 #define RT2X00LIB_H
 
+#include "rt2x00dump.h"
+
 /*
  * Interval defines
  * Both the link tuner as the rfkill will be called once per second.
@@ -128,7 +130,8 @@ static inline void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev)
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
 void rt2x00debug_register(struct rt2x00_dev *rt2x00dev);
 void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev);
-void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
+void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
+                           enum rt2x00_dump_type type, struct sk_buff *skb);
 #else
 static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
 {
@@ -139,6 +142,7 @@ static inline void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
 }
 
 static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
+                                         enum rt2x00_dump_type type,
                                          struct sk_buff *skb)
 {
 }
index 87e280a21971faf5dbb8e5f15186ec8d41c21ec2..b02dbc8a666e46a7acde175f5c377c27e6a4985e 100644 (file)
 
 static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
                                struct data_queue *queue,
-                               struct sk_buff *frag_skb,
-                               struct ieee80211_tx_control *control)
+                               struct sk_buff *frag_skb)
 {
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(frag_skb);
        struct skb_frame_desc *skbdesc;
+       struct ieee80211_tx_info *rts_info;
        struct sk_buff *skb;
        int size;
 
-       if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+       if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
                size = sizeof(struct ieee80211_cts);
        else
                size = sizeof(struct ieee80211_rts);
@@ -52,13 +53,33 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
        skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom);
        skb_put(skb, size);
 
-       if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
-               ieee80211_ctstoself_get(rt2x00dev->hw, control->vif,
-                                       frag_skb->data, frag_skb->len, control,
+       /*
+        * Copy TX information over from original frame to
+        * RTS/CTS frame. Note that we set the no encryption flag
+        * since we don't want this frame to be encrypted.
+        * RTS frames should be acked, while CTS-to-self frames
+        * should not. The ready for TX flag is cleared to prevent
+        * it being automatically send when the descriptor is
+        * written to the hardware.
+        */
+       memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb));
+       rts_info = IEEE80211_SKB_CB(skb);
+       rts_info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
+       rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT;
+       rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS;
+
+       if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
+               rts_info->flags |= IEEE80211_TX_CTL_NO_ACK;
+       else
+               rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
+
+       if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
+               ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif,
+                                       frag_skb->data, size, tx_info,
                                        (struct ieee80211_cts *)(skb->data));
        else
-               ieee80211_rts_get(rt2x00dev->hw, control->vif,
-                                 frag_skb->data, frag_skb->len, control,
+               ieee80211_rts_get(rt2x00dev->hw, tx_info->control.vif,
+                                 frag_skb->data, size, tx_info,
                                  (struct ieee80211_rts *)(skb->data));
 
        /*
@@ -68,7 +89,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
        memset(skbdesc, 0, sizeof(*skbdesc));
        skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED;
 
-       if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb, control)) {
+       if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb)) {
                WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n");
                return NETDEV_TX_BUSY;
        }
@@ -76,13 +97,13 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
        return NETDEV_TX_OK;
 }
 
-int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
-                struct ieee80211_tx_control *control)
+int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
+       enum data_queue_qid qid = skb_get_queue_mapping(skb);
        struct data_queue *queue;
-       struct skb_frame_desc *skbdesc;
        u16 frame_control;
 
        /*
@@ -100,16 +121,15 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
        /*
         * Determine which queue to put packet on.
         */
-       if (control->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM &&
+       if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM &&
            test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags))
-               queue = rt2x00queue_get_queue(rt2x00dev, RT2X00_BCN_QUEUE_ATIM);
+               queue = rt2x00queue_get_queue(rt2x00dev, QID_ATIM);
        else
-               queue = rt2x00queue_get_queue(rt2x00dev, control->queue);
+               queue = rt2x00queue_get_queue(rt2x00dev, qid);
        if (unlikely(!queue)) {
                ERROR(rt2x00dev,
                      "Attempt to send packet over invalid queue %d.\n"
-                     "Please file bug report to %s.\n",
-                     control->queue, DRV_PROJECT);
+                     "Please file bug report to %s.\n", qid, DRV_PROJECT);
                dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
@@ -119,38 +139,37 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
         * create and queue that frame first. But make sure we have
         * at least enough entries available to send this CTS/RTS
         * frame as well as the data frame.
+        * Note that when the driver has set the set_rts_threshold()
+        * callback function it doesn't need software generation of
+        * neither RTS or CTS-to-self frames and handles everything
+        * inside the hardware.
         */
        frame_control = le16_to_cpu(ieee80211hdr->frame_control);
        if (!is_rts_frame(frame_control) && !is_cts_frame(frame_control) &&
-           (control->flags & (IEEE80211_TXCTL_USE_RTS_CTS |
-                              IEEE80211_TXCTL_USE_CTS_PROTECT))) {
+           (tx_info->flags & (IEEE80211_TX_CTL_USE_RTS_CTS |
+                              IEEE80211_TX_CTL_USE_CTS_PROTECT)) &&
+           !rt2x00dev->ops->hw->set_rts_threshold) {
                if (rt2x00queue_available(queue) <= 1) {
-                       ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+                       ieee80211_stop_queue(rt2x00dev->hw, qid);
                        return NETDEV_TX_BUSY;
                }
 
-               if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb, control)) {
-                       ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+               if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb)) {
+                       ieee80211_stop_queue(rt2x00dev->hw, qid);
                        return NETDEV_TX_BUSY;
                }
        }
 
-       /*
-        * Initialize skb descriptor
-        */
-       skbdesc = get_skb_frame_desc(skb);
-       memset(skbdesc, 0, sizeof(*skbdesc));
-
-       if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb, control)) {
-               ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+       if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb)) {
+               ieee80211_stop_queue(rt2x00dev->hw, qid);
                return NETDEV_TX_BUSY;
        }
 
        if (rt2x00queue_full(queue))
-               ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+               ieee80211_stop_queue(rt2x00dev->hw, qid);
 
        if (rt2x00dev->ops->lib->kick_tx_queue)
-               rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue);
+               rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, qid);
 
        return NETDEV_TX_OK;
 }
@@ -183,8 +202,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        struct rt2x00_intf *intf = vif_to_intf(conf->vif);
-       struct data_queue *queue =
-           rt2x00queue_get_queue(rt2x00dev, RT2X00_BCN_QUEUE_BEACON);
+       struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, QID_BEACON);
        struct queue_entry *entry = NULL;
        unsigned int i;
 
@@ -197,13 +215,12 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
                return -ENODEV;
 
        /*
-        * When we don't support mixed interfaces (a combination
-        * of sta and ap virtual interfaces) then we can only
-        * add this interface when the rival interface count is 0.
+        * We don't support mixed combinations of sta and ap virtual
+        * interfaces. We can only add this interface when the rival
+        * interface count is 0.
         */
-       if (!test_bit(DRIVER_SUPPORT_MIXED_INTERFACES, &rt2x00dev->flags) &&
-           ((conf->type == IEEE80211_IF_TYPE_AP && rt2x00dev->intf_sta_count) ||
-            (conf->type != IEEE80211_IF_TYPE_AP && rt2x00dev->intf_ap_count)))
+       if ((conf->type == IEEE80211_IF_TYPE_AP && rt2x00dev->intf_sta_count) ||
+           (conf->type != IEEE80211_IF_TYPE_AP && rt2x00dev->intf_ap_count))
                return -ENOBUFS;
 
        /*
@@ -378,9 +395,7 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw,
        if (conf->type != IEEE80211_IF_TYPE_AP || !conf->beacon)
                return 0;
 
-       status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw,
-                                                  conf->beacon,
-                                                  conf->beacon_control);
+       status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, conf->beacon);
        if (status)
                dev_kfree_skb(conf->beacon);
 
@@ -454,10 +469,10 @@ int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw,
        struct rt2x00_dev *rt2x00dev = hw->priv;
        unsigned int i;
 
-       for (i = 0; i < hw->queues; i++) {
-               stats->data[i].len = rt2x00dev->tx[i].length;
-               stats->data[i].limit = rt2x00dev->tx[i].limit;
-               stats->data[i].count = rt2x00dev->tx[i].count;
+       for (i = 0; i < rt2x00dev->ops->tx_queues; i++) {
+               stats[i].len = rt2x00dev->tx[i].length;
+               stats[i].limit = rt2x00dev->tx[i].limit;
+               stats[i].count = rt2x00dev->tx[i].count;
        }
 
        return 0;
@@ -515,7 +530,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed);
 
-int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue_idx,
+int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
                      const struct ieee80211_tx_queue_params *params)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
index 971af2546b59a85e3e820f6d9b7e14e9276a515f..70a3d135f64ec22fee19567322dc549771f34327 100644 (file)
  * TX data handlers.
  */
 int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
-                           struct data_queue *queue, struct sk_buff *skb,
-                           struct ieee80211_tx_control *control)
+                           struct data_queue *queue, struct sk_buff *skb)
 {
        struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
-       struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data;
+       struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        struct skb_frame_desc *skbdesc;
+       struct txentry_desc txdesc;
        u32 word;
 
        if (rt2x00queue_full(queue))
                return -EINVAL;
 
-       rt2x00_desc_read(priv_tx->desc, 0, &word);
+       rt2x00_desc_read(entry_priv->desc, 0, &word);
 
        if (rt2x00_get_field32(word, TXD_ENTRY_OWNER_NIC) ||
            rt2x00_get_field32(word, TXD_ENTRY_VALID)) {
                ERROR(rt2x00dev,
                      "Arrived at non-free entry in the non-full queue %d.\n"
                      "Please file bug report to %s.\n",
-                     control->queue, DRV_PROJECT);
+                     entry->queue->qid, DRV_PROJECT);
                return -EINVAL;
        }
 
+       /*
+        * Copy all TX descriptor information into txdesc,
+        * after that we are free to use the skb->cb array
+        * for our information.
+        */
+       entry->skb = skb;
+       rt2x00queue_create_tx_descriptor(entry, &txdesc);
+
        /*
         * Fill in skb descriptor
         */
        skbdesc = get_skb_frame_desc(skb);
+       memset(skbdesc, 0, sizeof(*skbdesc));
        skbdesc->data = skb->data;
        skbdesc->data_len = skb->len;
-       skbdesc->desc = priv_tx->desc;
+       skbdesc->desc = entry_priv->desc;
        skbdesc->desc_len = queue->desc_size;
        skbdesc->entry = entry;
 
-       memcpy(&priv_tx->control, control, sizeof(priv_tx->control));
-       memcpy(priv_tx->data, skb->data, skb->len);
-       rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
+       memcpy(entry_priv->data, skb->data, skb->len);
 
+       rt2x00queue_write_tx_descriptor(entry, &txdesc);
        rt2x00queue_index_inc(queue, Q_INDEX);
 
        return 0;
@@ -84,7 +92,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
 {
        struct data_queue *queue = rt2x00dev->rx;
        struct queue_entry *entry;
-       struct queue_entry_priv_pci_rx *priv_rx;
+       struct queue_entry_priv_pci *entry_priv;
        struct ieee80211_hdr *hdr;
        struct skb_frame_desc *skbdesc;
        struct rxdone_entry_desc rxdesc;
@@ -94,8 +102,8 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
 
        while (1) {
                entry = rt2x00queue_get_entry(queue, Q_INDEX);
-               priv_rx = entry->priv_data;
-               rt2x00_desc_read(priv_rx->desc, 0, &word);
+               entry_priv = entry->priv_data;
+               rt2x00_desc_read(entry_priv->desc, 0, &word);
 
                if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC))
                        break;
@@ -103,7 +111,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
                memset(&rxdesc, 0, sizeof(rxdesc));
                rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
 
-               hdr = (struct ieee80211_hdr *)priv_rx->data;
+               hdr = (struct ieee80211_hdr *)entry_priv->data;
                header_size =
                    ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
 
@@ -123,7 +131,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
 
                skb_reserve(entry->skb, align);
                memcpy(skb_put(entry->skb, rxdesc.size),
-                      priv_rx->data, rxdesc.size);
+                      entry_priv->data, rxdesc.size);
 
                /*
                 * Fill in skb descriptor
@@ -132,7 +140,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
                memset(skbdesc, 0, sizeof(*skbdesc));
                skbdesc->data = entry->skb->data;
                skbdesc->data_len = entry->skb->len;
-               skbdesc->desc = priv_rx->desc;
+               skbdesc->desc = entry_priv->desc;
                skbdesc->desc_len = queue->desc_size;
                skbdesc->entry = entry;
 
@@ -143,7 +151,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
 
                if (test_bit(DEVICE_ENABLED_RADIO, &queue->rt2x00dev->flags)) {
                        rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1);
-                       rt2x00_desc_write(priv_rx->desc, 0, word);
+                       rt2x00_desc_write(entry_priv->desc, 0, word);
                }
 
                rt2x00queue_index_inc(queue, Q_INDEX);
@@ -154,10 +162,10 @@ EXPORT_SYMBOL_GPL(rt2x00pci_rxdone);
 void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry,
                      struct txdone_entry_desc *txdesc)
 {
-       struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data;
+       struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+       enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
        u32 word;
 
-       txdesc->control = &priv_tx->control;
        rt2x00lib_txdone(entry, txdesc);
 
        /*
@@ -165,10 +173,10 @@ void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry,
         */
        entry->flags = 0;
 
-       rt2x00_desc_read(priv_tx->desc, 0, &word);
+       rt2x00_desc_read(entry_priv->desc, 0, &word);
        rt2x00_set_field32(&word, TXD_ENTRY_OWNER_NIC, 0);
        rt2x00_set_field32(&word, TXD_ENTRY_VALID, 0);
-       rt2x00_desc_write(priv_tx->desc, 0, word);
+       rt2x00_desc_write(entry_priv->desc, 0, word);
 
        rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
 
@@ -178,7 +186,7 @@ void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry,
         * is reenabled when the txdone handler has finished.
         */
        if (!rt2x00queue_full(entry->queue))
-               ieee80211_wake_queue(rt2x00dev->hw, priv_tx->control.queue);
+               ieee80211_wake_queue(rt2x00dev->hw, qid);
 
 }
 EXPORT_SYMBOL_GPL(rt2x00pci_txdone);
@@ -217,14 +225,9 @@ static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
                                     struct data_queue *queue)
 {
        struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
-       struct queue_entry_priv_pci_rx *priv_rx;
-       struct queue_entry_priv_pci_tx *priv_tx;
+       struct queue_entry_priv_pci *entry_priv;
        void *addr;
        dma_addr_t dma;
-       void *desc_addr;
-       dma_addr_t desc_dma;
-       void *data_addr;
-       dma_addr_t data_dma;
        unsigned int i;
 
        /*
@@ -240,24 +243,11 @@ static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
         * Initialize all queue entries to contain valid addresses.
         */
        for (i = 0; i < queue->limit; i++) {
-               desc_addr = desc_offset(queue, addr, i);
-               desc_dma = desc_offset(queue, dma, i);
-               data_addr = data_offset(queue, addr, i);
-               data_dma = data_offset(queue, dma, i);
-
-               if (queue->qid == QID_RX) {
-                       priv_rx = queue->entries[i].priv_data;
-                       priv_rx->desc = desc_addr;
-                       priv_rx->desc_dma = desc_dma;
-                       priv_rx->data = data_addr;
-                       priv_rx->data_dma = data_dma;
-               } else {
-                       priv_tx = queue->entries[i].priv_data;
-                       priv_tx->desc = desc_addr;
-                       priv_tx->desc_dma = desc_dma;
-                       priv_tx->data = data_addr;
-                       priv_tx->data_dma = data_dma;
-               }
+               entry_priv = queue->entries[i].priv_data;
+               entry_priv->desc = desc_offset(queue, addr, i);
+               entry_priv->desc_dma = desc_offset(queue, dma, i);
+               entry_priv->data = data_offset(queue, addr, i);
+               entry_priv->data_dma = data_offset(queue, dma, i);
        }
 
        return 0;
@@ -267,28 +257,13 @@ static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev,
                                     struct data_queue *queue)
 {
        struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
-       struct queue_entry_priv_pci_rx *priv_rx;
-       struct queue_entry_priv_pci_tx *priv_tx;
-       void *data_addr;
-       dma_addr_t data_dma;
-
-       if (queue->qid == QID_RX) {
-               priv_rx = queue->entries[0].priv_data;
-               data_addr = priv_rx->data;
-               data_dma = priv_rx->data_dma;
-
-               priv_rx->data = NULL;
-       } else {
-               priv_tx = queue->entries[0].priv_data;
-               data_addr = priv_tx->data;
-               data_dma = priv_tx->data_dma;
-
-               priv_tx->data = NULL;
-       }
+       struct queue_entry_priv_pci *entry_priv =
+           queue->entries[0].priv_data;
 
-       if (data_addr)
+       if (entry_priv->data)
                pci_free_consistent(pci_dev, dma_size(queue),
-                                   data_addr, data_dma);
+                                   entry_priv->data, entry_priv->data_dma);
+       entry_priv->data = NULL;
 }
 
 int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
index 9d1cdb99431c3af4a2bd4ac5745bde32a2c8ed8d..37c851e442c166687a355abc1c72c3342494863c 100644 (file)
@@ -91,40 +91,22 @@ rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev,
  * TX data handlers.
  */
 int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
-                           struct data_queue *queue, struct sk_buff *skb,
-                           struct ieee80211_tx_control *control);
+                           struct data_queue *queue, struct sk_buff *skb);
 
 /**
- * struct queue_entry_priv_pci_rx: Per RX entry PCI specific information
- *
- * @desc: Pointer to device descriptor.
- * @data: Pointer to device's entry memory.
- * @dma: DMA pointer to &data.
- */
-struct queue_entry_priv_pci_rx {
-       __le32 *desc;
-       dma_addr_t desc_dma;
-
-       void *data;
-       dma_addr_t data_dma;
-};
-
-/**
- * struct queue_entry_priv_pci_tx: Per TX entry PCI specific information
+ * struct queue_entry_priv_pci: Per entry PCI specific information
  *
  * @desc: Pointer to device descriptor
+ * @desc_dma: DMA pointer to &desc.
  * @data: Pointer to device's entry memory.
- * @dma: DMA pointer to &data.
- * @control: mac80211 control structure used to transmit data.
+ * @data_dma: DMA pointer to &data.
  */
-struct queue_entry_priv_pci_tx {
+struct queue_entry_priv_pci {
        __le32 *desc;
        dma_addr_t desc_dma;
 
        void *data;
        dma_addr_t data_dma;
-
-       struct ieee80211_tx_control control;
 };
 
 /**
index 659e9f44c40c76e1bac4a4c05fab2c342ff6d161..e69ef4b192397bb50b541db1d2e9ad4eefb5cb7a 100644 (file)
 #include "rt2x00.h"
 #include "rt2x00lib.h"
 
+void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
+                                     struct txentry_desc *txdesc)
+{
+       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data;
+       struct ieee80211_rate *rate =
+           ieee80211_get_tx_rate(rt2x00dev->hw, tx_info);
+       const struct rt2x00_rate *hwrate;
+       unsigned int data_length;
+       unsigned int duration;
+       unsigned int residual;
+       u16 frame_control;
+
+       memset(txdesc, 0, sizeof(*txdesc));
+
+       /*
+        * Initialize information from queue
+        */
+       txdesc->queue = entry->queue->qid;
+       txdesc->cw_min = entry->queue->cw_min;
+       txdesc->cw_max = entry->queue->cw_max;
+       txdesc->aifs = entry->queue->aifs;
+
+       /* Data length should be extended with 4 bytes for CRC */
+       data_length = entry->skb->len + 4;
+
+       /*
+        * Read required fields from ieee80211 header.
+        */
+       frame_control = le16_to_cpu(hdr->frame_control);
+
+       /*
+        * Check whether this frame is to be acked.
+        */
+       if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK))
+               __set_bit(ENTRY_TXD_ACK, &txdesc->flags);
+
+       /*
+        * Check if this is a RTS/CTS frame
+        */
+       if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) {
+               __set_bit(ENTRY_TXD_BURST, &txdesc->flags);
+               if (is_rts_frame(frame_control))
+                       __set_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags);
+               else
+                       __set_bit(ENTRY_TXD_CTS_FRAME, &txdesc->flags);
+               if (tx_info->control.rts_cts_rate_idx >= 0)
+                       rate =
+                           ieee80211_get_rts_cts_rate(rt2x00dev->hw, tx_info);
+       }
+
+       /*
+        * Determine retry information.
+        */
+       txdesc->retry_limit = tx_info->control.retry_limit;
+       if (tx_info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
+               __set_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags);
+
+       /*
+        * Check if more fragments are pending
+        */
+       if (ieee80211_get_morefrag(hdr)) {
+               __set_bit(ENTRY_TXD_BURST, &txdesc->flags);
+               __set_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags);
+       }
+
+       /*
+        * Beacons and probe responses require the tsf timestamp
+        * to be inserted into the frame.
+        */
+       if (txdesc->queue == QID_BEACON || is_probe_resp(frame_control))
+               __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags);
+
+       /*
+        * Determine with what IFS priority this frame should be send.
+        * Set ifs to IFS_SIFS when the this is not the first fragment,
+        * or this fragment came after RTS/CTS.
+        */
+       if (test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)) {
+               txdesc->ifs = IFS_SIFS;
+       } else if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) {
+               __set_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags);
+               txdesc->ifs = IFS_BACKOFF;
+       } else {
+               txdesc->ifs = IFS_SIFS;
+       }
+
+       /*
+        * PLCP setup
+        * Length calculation depends on OFDM/CCK rate.
+        */
+       hwrate = rt2x00_get_rate(rate->hw_value);
+       txdesc->signal = hwrate->plcp;
+       txdesc->service = 0x04;
+
+       if (hwrate->flags & DEV_RATE_OFDM) {
+               __set_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags);
+
+               txdesc->length_high = (data_length >> 6) & 0x3f;
+               txdesc->length_low = data_length & 0x3f;
+       } else {
+               /*
+                * Convert length to microseconds.
+                */
+               residual = get_duration_res(data_length, hwrate->bitrate);
+               duration = get_duration(data_length, hwrate->bitrate);
+
+               if (residual != 0) {
+                       duration++;
+
+                       /*
+                        * Check if we need to set the Length Extension
+                        */
+                       if (hwrate->bitrate == 110 && residual <= 30)
+                               txdesc->service |= 0x80;
+               }
+
+               txdesc->length_high = (duration >> 8) & 0xff;
+               txdesc->length_low = duration & 0xff;
+
+               /*
+                * When preamble is enabled we should set the
+                * preamble bit for the signal.
+                */
+               if (rt2x00_get_rate_preamble(rate->hw_value))
+                       txdesc->signal |= 0x08;
+       }
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_create_tx_descriptor);
+
+void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
+                                    struct txentry_desc *txdesc)
+{
+       struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+
+       rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, entry->skb, txdesc);
+
+       /*
+        * All processing on the frame has been completed, this means
+        * it is now ready to be dumped to userspace through debugfs.
+        */
+       rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, entry->skb);
+
+       /*
+        * We are done writing the frame to the queue entry,
+        * also kick the queue in case the correct flags are set,
+        * note that this will automatically filter beacons and
+        * RTS/CTS frames since those frames don't have this flag
+        * set.
+        */
+       if (rt2x00dev->ops->lib->kick_tx_queue &&
+           !(skbdesc->flags & FRAME_DESC_DRIVER_GENERATED))
+               rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev,
+                                                  entry->queue->qid);
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_write_tx_descriptor);
+
 struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
-                                        const unsigned int queue)
+                                        const enum data_queue_qid queue)
 {
        int atim = test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
 
-       if (queue < rt2x00dev->hw->queues && rt2x00dev->tx)
+       if (queue < rt2x00dev->ops->tx_queues && rt2x00dev->tx)
                return &rt2x00dev->tx[queue];
 
        if (!rt2x00dev->bcn)
                return NULL;
 
-       if (queue == RT2X00_BCN_QUEUE_BEACON)
+       if (queue == QID_BEACON)
                return &rt2x00dev->bcn[0];
-       else if (queue == RT2X00_BCN_QUEUE_ATIM && atim)
+       else if (queue == QID_ATIM && atim)
                return &rt2x00dev->bcn[1];
 
        return NULL;
@@ -255,11 +414,11 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
        /*
         * We need the following queues:
         * RX: 1
-        * TX: hw->queues
+        * TX: ops->tx_queues
         * Beacon: 1
         * Atim: 1 (if required)
         */
-       rt2x00dev->data_queues = 2 + rt2x00dev->hw->queues + req_atim;
+       rt2x00dev->data_queues = 2 + rt2x00dev->ops->tx_queues + req_atim;
 
        queue = kzalloc(rt2x00dev->data_queues * sizeof(*queue), GFP_KERNEL);
        if (!queue) {
@@ -272,7 +431,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
         */
        rt2x00dev->rx = queue;
        rt2x00dev->tx = &queue[1];
-       rt2x00dev->bcn = &queue[1 + rt2x00dev->hw->queues];
+       rt2x00dev->bcn = &queue[1 + rt2x00dev->ops->tx_queues];
 
        /*
         * Initialize queue parameters.
index 7027c9f47d3f0f1d509c67a857ecd648b3317cf4..4d00ced14cc7c8a4e4f64743a4fae4f8f28f3211 100644 (file)
 
 /**
  * enum data_queue_qid: Queue identification
+ *
+ * @QID_AC_BE: AC BE queue
+ * @QID_AC_BK: AC BK queue
+ * @QID_AC_VI: AC VI queue
+ * @QID_AC_VO: AC VO queue
+ * @QID_HCCA: HCCA queue
+ * @QID_MGMT: MGMT queue (prio queue)
+ * @QID_RX: RX queue
+ * @QID_OTHER: None of the above (don't use, only present for completeness)
+ * @QID_BEACON: Beacon queue (value unspecified, don't send it to device)
+ * @QID_ATIM: Atim queue (value unspeficied, don't send it to device)
  */
 enum data_queue_qid {
        QID_AC_BE = 0,
@@ -64,21 +75,8 @@ enum data_queue_qid {
        QID_MGMT = 13,
        QID_RX = 14,
        QID_OTHER = 15,
-};
-
-/**
- * enum rt2x00_bcn_queue: Beacon queue index
- *
- * Start counting with a high offset, this because this enumeration
- * supplements &enum ieee80211_tx_queue and we should prevent value
- * conflicts.
- *
- * @RT2X00_BCN_QUEUE_BEACON: Beacon queue
- * @RT2X00_BCN_QUEUE_ATIM: Atim queue (sends frame after beacon)
- */
-enum rt2x00_bcn_queue {
-       RT2X00_BCN_QUEUE_BEACON = 100,
-       RT2X00_BCN_QUEUE_ATIM = 101,
+       QID_BEACON,
+       QID_ATIM,
 };
 
 /**
@@ -94,38 +92,39 @@ enum skb_frame_desc_flags {
 /**
  * struct skb_frame_desc: Descriptor information for the skb buffer
  *
- * This structure is placed over the skb->cb array, this means that
- * this structure should not exceed the size of that array (48 bytes).
+ * This structure is placed over the driver_data array, this means that
+ * this structure should not exceed the size of that array (40 bytes).
  *
  * @flags: Frame flags, see &enum skb_frame_desc_flags.
- * @frame_type: Frame type, see &enum rt2x00_dump_type.
  * @data: Pointer to data part of frame (Start of ieee80211 header).
  * @desc: Pointer to descriptor part of the frame.
  *     Note that this pointer could point to something outside
  *     of the scope of the skb->data pointer.
  * @data_len: Length of the frame data.
  * @desc_len: Length of the frame descriptor.
-
  * @entry: The entry to which this sk buffer belongs.
  */
 struct skb_frame_desc {
        unsigned int flags;
 
-       unsigned int frame_type;
+       unsigned short data_len;
+       unsigned short desc_len;
 
        void *data;
        void *desc;
 
-       unsigned int data_len;
-       unsigned int desc_len;
-
        struct queue_entry *entry;
 };
 
+/**
+ * get_skb_frame_desc - Obtain the rt2x00 frame descriptor from a sk_buff.
+ * @skb: &struct sk_buff from where we obtain the &struct skb_frame_desc
+ */
 static inline struct skb_frame_desc* get_skb_frame_desc(struct sk_buff *skb)
 {
-       BUILD_BUG_ON(sizeof(struct skb_frame_desc) > sizeof(skb->cb));
-       return (struct skb_frame_desc *)&skb->cb[0];
+       BUILD_BUG_ON(sizeof(struct skb_frame_desc) >
+                    IEEE80211_TX_INFO_DRIVER_DATA_SIZE);
+       return (struct skb_frame_desc *)&IEEE80211_SKB_CB(skb)->driver_data;
 }
 
 /**
@@ -160,19 +159,33 @@ struct rxdone_entry_desc {
        int dev_flags;
 };
 
+/**
+ * enum txdone_entry_desc_flags: Flags for &struct txdone_entry_desc
+ *
+ * @TXDONE_UNKNOWN: Hardware could not determine success of transmission.
+ * @TXDONE_SUCCESS: Frame was successfully send
+ * @TXDONE_FAILURE: Frame was not successfully send
+ * @TXDONE_EXCESSIVE_RETRY: In addition to &TXDONE_FAILURE, the
+ *     frame transmission failed due to excessive retries.
+ */
+enum txdone_entry_desc_flags {
+       TXDONE_UNKNOWN = 1 << 0,
+       TXDONE_SUCCESS = 1 << 1,
+       TXDONE_FAILURE = 1 << 2,
+       TXDONE_EXCESSIVE_RETRY = 1 << 3,
+};
+
 /**
  * struct txdone_entry_desc: TX done entry descriptor
  *
  * Summary of information that has been read from the TX frame descriptor
  * after the device is done with transmission.
  *
- * @control: Control structure which was used to transmit the frame.
- * @status: TX status (See &enum tx_status).
+ * @flags: TX done flags (See &enum txdone_entry_desc_flags).
  * @retry: Retry count.
  */
 struct txdone_entry_desc {
-       struct ieee80211_tx_control *control;
-       int status;
+       unsigned long flags;
        int retry;
 };
 
@@ -180,19 +193,25 @@ struct txdone_entry_desc {
  * enum txentry_desc_flags: Status flags for TX entry descriptor
  *
  * @ENTRY_TXD_RTS_FRAME: This frame is a RTS frame.
+ * @ENTRY_TXD_CTS_FRAME: This frame is a CTS-to-self frame.
  * @ENTRY_TXD_OFDM_RATE: This frame is send out with an OFDM rate.
+ * @ENTRY_TXD_FIRST_FRAGMENT: This is the first frame.
  * @ENTRY_TXD_MORE_FRAG: This frame is followed by another fragment.
  * @ENTRY_TXD_REQ_TIMESTAMP: Require timestamp to be inserted.
  * @ENTRY_TXD_BURST: This frame belongs to the same burst event.
  * @ENTRY_TXD_ACK: An ACK is required for this frame.
+ * @ENTRY_TXD_RETRY_MODE: When set, the long retry count is used.
  */
 enum txentry_desc_flags {
        ENTRY_TXD_RTS_FRAME,
+       ENTRY_TXD_CTS_FRAME,
        ENTRY_TXD_OFDM_RATE,
+       ENTRY_TXD_FIRST_FRAGMENT,
        ENTRY_TXD_MORE_FRAG,
        ENTRY_TXD_REQ_TIMESTAMP,
        ENTRY_TXD_BURST,
        ENTRY_TXD_ACK,
+       ENTRY_TXD_RETRY_MODE,
 };
 
 /**
@@ -206,6 +225,7 @@ enum txentry_desc_flags {
  * @length_low: PLCP length low word.
  * @signal: PLCP signal.
  * @service: PLCP service.
+ * @retry_limit: Max number of retries.
  * @aifs: AIFS value.
  * @ifs: IFS value.
  * @cw_min: cwmin value.
@@ -221,10 +241,11 @@ struct txentry_desc {
        u16 signal;
        u16 service;
 
-       int aifs;
-       int ifs;
-       int cw_min;
-       int cw_max;
+       short retry_limit;
+       short aifs;
+       short ifs;
+       short cw_min;
+       short cw_max;
 };
 
 /**
@@ -240,7 +261,6 @@ struct txentry_desc {
  *     encryption or decryption. The entry should only be touched after
  *     the device has signaled it is done with it.
  */
-
 enum queue_entry_flags {
        ENTRY_BCN_ASSIGNED,
        ENTRY_OWNER_DEVICE_DATA,
@@ -369,7 +389,7 @@ struct data_queue_desc {
  * the end of the TX queue array.
  */
 #define tx_queue_end(__dev) \
-       &(__dev)->tx[(__dev)->hw->queues]
+       &(__dev)->tx[(__dev)->ops->tx_queues]
 
 /**
  * queue_loop - Loop through the queues within a specific range (HELPER MACRO).
index 0325bed2fbf599c7207efdd5ee44cf808aabecf4..3f255df58b781a2d5daed14ea18bc6db89916515 100644 (file)
 #ifndef RT2X00REG_H
 #define RT2X00REG_H
 
-/*
- * TX result flags.
- */
-enum tx_status {
-       TX_SUCCESS = 0,
-       TX_SUCCESS_RETRY = 1,
-       TX_FAIL_RETRY = 2,
-       TX_FAIL_INVALID = 3,
-       TX_FAIL_OTHER = 4,
-};
-
 /*
  * Antenna values
  */
index 5a331674dcb2384c036f77b08aa79f93b819946a..52d12fdc0ccf2f7a5dac92e17511a13e19896e2a 100644 (file)
@@ -129,9 +129,9 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
 {
        struct queue_entry *entry = (struct queue_entry *)urb->context;
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-       struct queue_entry_priv_usb_tx *priv_tx = entry->priv_data;
        struct txdone_entry_desc txdesc;
        __le32 *txd = (__le32 *)entry->skb->data;
+       enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
        u32 word;
 
        if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
@@ -147,10 +147,18 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
 
        /*
         * Obtain the status about this packet.
+        * Note that when the status is 0 it does not mean the
+        * frame was send out correctly. It only means the frame
+        * was succesfully pushed to the hardware, we have no
+        * way to determine the transmission status right now.
+        * (Only indirectly by looking at the failed TX counters
+        * in the register).
         */
-       txdesc.status = !urb->status ? TX_SUCCESS : TX_FAIL_RETRY;
+       if (!urb->status)
+               __set_bit(TXDONE_UNKNOWN, &txdesc.flags);
+       else
+               __set_bit(TXDONE_FAILURE, &txdesc.flags);
        txdesc.retry = 0;
-       txdesc.control = &priv_tx->control;
 
        rt2x00lib_txdone(entry, &txdesc);
 
@@ -166,17 +174,17 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
         * is reenabled when the txdone handler has finished.
         */
        if (!rt2x00queue_full(entry->queue))
-               ieee80211_wake_queue(rt2x00dev->hw, priv_tx->control.queue);
+               ieee80211_wake_queue(rt2x00dev->hw, qid);
 }
 
 int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
-                           struct data_queue *queue, struct sk_buff *skb,
-                           struct ieee80211_tx_control *control)
+                           struct data_queue *queue, struct sk_buff *skb)
 {
        struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev);
        struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
-       struct queue_entry_priv_usb_tx *priv_tx = entry->priv_data;
+       struct queue_entry_priv_usb *entry_priv = entry->priv_data;
        struct skb_frame_desc *skbdesc;
+       struct txentry_desc txdesc;
        u32 length;
 
        if (rt2x00queue_full(queue))
@@ -186,10 +194,18 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
                ERROR(rt2x00dev,
                      "Arrived at non-free entry in the non-full queue %d.\n"
                      "Please file bug report to %s.\n",
-                     control->queue, DRV_PROJECT);
+                     entry->queue->qid, DRV_PROJECT);
                return -EINVAL;
        }
 
+       /*
+        * Copy all TX descriptor information into txdesc,
+        * after that we are free to use the skb->cb array
+        * for our information.
+        */
+       entry->skb = skb;
+       rt2x00queue_create_tx_descriptor(entry, &txdesc);
+
        /*
         * Add the descriptor in front of the skb.
         */
@@ -200,14 +216,14 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
         * Fill in skb descriptor
         */
        skbdesc = get_skb_frame_desc(skb);
+       memset(skbdesc, 0, sizeof(*skbdesc));
        skbdesc->data = skb->data + queue->desc_size;
        skbdesc->data_len = skb->len - queue->desc_size;
        skbdesc->desc = skb->data;
        skbdesc->desc_len = queue->desc_size;
        skbdesc->entry = entry;
 
-       memcpy(&priv_tx->control, control, sizeof(priv_tx->control));
-       rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
+       rt2x00queue_write_tx_descriptor(entry, &txdesc);
 
        /*
         * USB devices cannot blindly pass the skb->len as the
@@ -220,9 +236,9 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
         * Initialize URB and send the frame to the device.
         */
        __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
-       usb_fill_bulk_urb(priv_tx->urb, usb_dev, usb_sndbulkpipe(usb_dev, 1),
+       usb_fill_bulk_urb(entry_priv->urb, usb_dev, usb_sndbulkpipe(usb_dev, 1),
                          skb->data, length, rt2x00usb_interrupt_txdone, entry);
-       usb_submit_urb(priv_tx->urb, GFP_ATOMIC);
+       usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
 
        rt2x00queue_index_inc(queue, Q_INDEX);
 
@@ -237,22 +253,35 @@ static struct sk_buff* rt2x00usb_alloc_rxskb(struct data_queue *queue)
 {
        struct sk_buff *skb;
        unsigned int frame_size;
+       unsigned int reserved_size;
 
        /*
-        * As alignment we use 2 and not NET_IP_ALIGN because we need
-        * to be sure we have 2 bytes room in the head. (NET_IP_ALIGN
-        * can be 0 on some hardware). We use these 2 bytes for frame
-        * alignment later, we assume that the chance that
-        * header_size % 4 == 2 is bigger then header_size % 2 == 0
-        * and thus optimize alignment by reserving the 2 bytes in
-        * advance.
+        * The frame size includes descriptor size, because the
+        * hardware directly receive the frame into the skbuffer.
         */
        frame_size = queue->data_size + queue->desc_size;
-       skb = dev_alloc_skb(queue->desc_size + frame_size + 2);
+
+       /*
+        * For the allocation we should keep a few things in mind:
+        * 1) 4byte alignment of 802.11 payload
+        *
+        * For (1) we need at most 4 bytes to guarentee the correct
+        * alignment. We are going to optimize the fact that the chance
+        * that the 802.11 header_size % 4 == 2 is much bigger then
+        * anything else. However since we need to move the frame up
+        * to 3 bytes to the front, which means we need to preallocate
+        * 6 bytes.
+        */
+       reserved_size = 6;
+
+       /*
+        * Allocate skbuffer.
+        */
+       skb = dev_alloc_skb(frame_size + reserved_size);
        if (!skb)
                return NULL;
 
-       skb_reserve(skb, queue->desc_size + 2);
+       skb_reserve(skb, reserved_size);
        skb_put(skb, frame_size);
 
        return skb;
@@ -265,7 +294,8 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
        struct sk_buff *skb;
        struct skb_frame_desc *skbdesc;
        struct rxdone_entry_desc rxdesc;
-       int header_size;
+       unsigned int header_size;
+       unsigned int align;
 
        if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
            !test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
@@ -289,19 +319,29 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
        memset(&rxdesc, 0, sizeof(rxdesc));
        rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
 
+       header_size = ieee80211_get_hdrlen_from_skb(entry->skb);
+
        /*
         * The data behind the ieee80211 header must be
-        * aligned on a 4 byte boundary.
+        * aligned on a 4 byte boundary. We already reserved
+        * 2 bytes for header_size % 4 == 2 optimization.
+        * To determine the number of bytes which the data
+        * should be moved to the left, we must add these
+        * 2 bytes to the header_size.
         */
-       header_size = ieee80211_get_hdrlen_from_skb(entry->skb);
-       if (header_size % 4 == 0) {
-               skb_push(entry->skb, 2);
-               memmove(entry->skb->data, entry->skb->data + 2,
-                       entry->skb->len - 2);
-               skbdesc->data = entry->skb->data;
-               skb_trim(entry->skb,entry->skb->len - 2);
+       align = (header_size + 2) % 4;
+
+       if (align) {
+               skb_push(entry->skb, align);
+               /* Move entire frame in 1 command */
+               memmove(entry->skb->data, entry->skb->data + align,
+                       rxdesc.size);
        }
 
+       /* Update data pointers, trim buffer to correct size */
+       skbdesc->data = entry->skb->data;
+       skb_trim(entry->skb, rxdesc.size);
+
        /*
         * Allocate a new sk buffer to replace the current one.
         * If allocation fails, we should drop the current frame
@@ -338,44 +378,28 @@ skip_entry:
  */
 void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
 {
-       struct queue_entry_priv_usb_rx *priv_rx;
-       struct queue_entry_priv_usb_tx *priv_tx;
-       struct queue_entry_priv_usb_bcn *priv_bcn;
-       struct data_queue *queue;
+       struct queue_entry_priv_usb *entry_priv;
+       struct queue_entry_priv_usb_bcn *bcn_priv;
        unsigned int i;
 
-       rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0x0000, 0x0000,
+       rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 00,
                                    REGISTER_TIMEOUT);
 
        /*
         * Cancel all queues.
         */
        for (i = 0; i < rt2x00dev->rx->limit; i++) {
-               priv_rx = rt2x00dev->rx->entries[i].priv_data;
-               usb_kill_urb(priv_rx->urb);
-       }
-
-       tx_queue_for_each(rt2x00dev, queue) {
-               for (i = 0; i < queue->limit; i++) {
-                       priv_tx = queue->entries[i].priv_data;
-                       usb_kill_urb(priv_tx->urb);
-               }
+               entry_priv = rt2x00dev->rx->entries[i].priv_data;
+               usb_kill_urb(entry_priv->urb);
        }
 
+       /*
+        * Kill guardian urb.
+        */
        for (i = 0; i < rt2x00dev->bcn->limit; i++) {
-               priv_bcn = rt2x00dev->bcn->entries[i].priv_data;
-               usb_kill_urb(priv_bcn->urb);
-
-               if (priv_bcn->guardian_urb)
-                       usb_kill_urb(priv_bcn->guardian_urb);
-       }
-
-       if (!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags))
-               return;
-
-       for (i = 0; i < rt2x00dev->bcn[1].limit; i++) {
-               priv_tx = rt2x00dev->bcn[1].entries[i].priv_data;
-               usb_kill_urb(priv_tx->urb);
+               bcn_priv = rt2x00dev->bcn->entries[i].priv_data;
+               if (bcn_priv->guardian_urb)
+                       usb_kill_urb(bcn_priv->guardian_urb);
        }
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
@@ -387,15 +411,15 @@ void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev,
                            struct queue_entry *entry)
 {
        struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev);
-       struct queue_entry_priv_usb_rx *priv_rx = entry->priv_data;
+       struct queue_entry_priv_usb *entry_priv = entry->priv_data;
 
-       usb_fill_bulk_urb(priv_rx->urb, usb_dev,
+       usb_fill_bulk_urb(entry_priv->urb, usb_dev,
                          usb_rcvbulkpipe(usb_dev, 1),
                          entry->skb->data, entry->skb->len,
                          rt2x00usb_interrupt_rxdone, entry);
 
        __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
-       usb_submit_urb(priv_rx->urb, GFP_ATOMIC);
+       usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_init_rxentry);
 
@@ -409,38 +433,31 @@ EXPORT_SYMBOL_GPL(rt2x00usb_init_txentry);
 static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev,
                               struct data_queue *queue)
 {
-       struct queue_entry_priv_usb_rx *priv_rx;
-       struct queue_entry_priv_usb_tx *priv_tx;
-       struct queue_entry_priv_usb_bcn *priv_bcn;
-       struct urb *urb;
-       unsigned int guardian =
-           test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags);
+       struct queue_entry_priv_usb *entry_priv;
+       struct queue_entry_priv_usb_bcn *bcn_priv;
        unsigned int i;
 
+       for (i = 0; i < queue->limit; i++) {
+               entry_priv = queue->entries[i].priv_data;
+               entry_priv->urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (!entry_priv->urb)
+                       return -ENOMEM;
+       }
+
        /*
-        * Allocate the URB's
+        * If this is not the beacon queue or
+        * no guardian byte was required for the beacon,
+        * then we are done.
         */
+       if (rt2x00dev->bcn != queue ||
+           !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))
+               return 0;
+
        for (i = 0; i < queue->limit; i++) {
-               urb = usb_alloc_urb(0, GFP_KERNEL);
-               if (!urb)
+               bcn_priv = queue->entries[i].priv_data;
+               bcn_priv->guardian_urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (!bcn_priv->guardian_urb)
                        return -ENOMEM;
-
-               if (queue->qid == QID_RX) {
-                       priv_rx = queue->entries[i].priv_data;
-                       priv_rx->urb = urb;
-               } else if (queue->qid == QID_MGMT && guardian) {
-                       priv_bcn = queue->entries[i].priv_data;
-                       priv_bcn->urb = urb;
-
-                       urb = usb_alloc_urb(0, GFP_KERNEL);
-                       if (!urb)
-                               return -ENOMEM;
-
-                       priv_bcn->guardian_urb = urb;
-               } else {
-                       priv_tx = queue->entries[i].priv_data;
-                       priv_tx->urb = urb;
-               }
        }
 
        return 0;
@@ -449,38 +466,35 @@ static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev,
 static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev,
                               struct data_queue *queue)
 {
-       struct queue_entry_priv_usb_rx *priv_rx;
-       struct queue_entry_priv_usb_tx *priv_tx;
-       struct queue_entry_priv_usb_bcn *priv_bcn;
-       struct urb *urb;
-       unsigned int guardian =
-           test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags);
+       struct queue_entry_priv_usb *entry_priv;
+       struct queue_entry_priv_usb_bcn *bcn_priv;
        unsigned int i;
 
        if (!queue->entries)
                return;
 
        for (i = 0; i < queue->limit; i++) {
-               if (queue->qid == QID_RX) {
-                       priv_rx = queue->entries[i].priv_data;
-                       urb = priv_rx->urb;
-               } else if (queue->qid == QID_MGMT && guardian) {
-                       priv_bcn = queue->entries[i].priv_data;
-
-                       usb_kill_urb(priv_bcn->guardian_urb);
-                       usb_free_urb(priv_bcn->guardian_urb);
-
-                       urb = priv_bcn->urb;
-               } else {
-                       priv_tx = queue->entries[i].priv_data;
-                       urb = priv_tx->urb;
-               }
-
-               usb_kill_urb(urb);
-               usb_free_urb(urb);
+               entry_priv = queue->entries[i].priv_data;
+               usb_kill_urb(entry_priv->urb);
+               usb_free_urb(entry_priv->urb);
                if (queue->entries[i].skb)
                        kfree_skb(queue->entries[i].skb);
        }
+
+       /*
+        * If this is not the beacon queue or
+        * no guardian byte was required for the beacon,
+        * then we are done.
+        */
+       if (rt2x00dev->bcn != queue ||
+           !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))
+               return;
+
+       for (i = 0; i < queue->limit; i++) {
+               bcn_priv = queue->entries[i].priv_data;
+               usb_kill_urb(bcn_priv->guardian_urb);
+               usb_free_urb(bcn_priv->guardian_urb);
+       }
 }
 
 int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)
index 11e55180cbaf61c95eaa6138bba8fae42fa695e6..26f53f868af67e01440a1239741403c441b590cd 100644 (file)
 #define REGISTER_TIMEOUT               500
 #define REGISTER_TIMEOUT_FIRMWARE      1000
 
+/**
+ * REGISTER_TIMEOUT16 - Determine the timeout for 16bit register access
+ * @__datalen: Data length
+ */
+#define REGISTER_TIMEOUT16(__datalen)  \
+       ( REGISTER_TIMEOUT * ((__datalen) / sizeof(u16)) )
+
+/**
+ * REGISTER_TIMEOUT32 - Determine the timeout for 32bit register access
+ * @__datalen: Data length
+ */
+#define REGISTER_TIMEOUT32(__datalen)  \
+       ( REGISTER_TIMEOUT * ((__datalen) / sizeof(u32)) )
+
 /*
  * Cache size
  */
@@ -185,13 +199,12 @@ static inline int rt2x00usb_vendor_request_sw(struct rt2x00_dev *rt2x00dev,
  * kmalloc for correct handling inside the kernel USB layer.
  */
 static inline int rt2x00usb_eeprom_read(struct rt2x00_dev *rt2x00dev,
-                                       __le16 *eeprom, const u16 lenght)
+                                       __le16 *eeprom, const u16 length)
 {
-       int timeout = REGISTER_TIMEOUT * (lenght / sizeof(u16));
-
        return rt2x00usb_vendor_request(rt2x00dev, USB_EEPROM_READ,
                                        USB_VENDOR_REQUEST_IN, 0, 0,
-                                       eeprom, lenght, timeout);
+                                       eeprom, length,
+                                       REGISTER_TIMEOUT16(length));
 }
 
 /*
@@ -203,47 +216,31 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev);
  * TX data handlers.
  */
 int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
-                           struct data_queue *queue, struct sk_buff *skb,
-                           struct ieee80211_tx_control *control);
-
-/**
- * struct queue_entry_priv_usb_rx: Per RX entry USB specific information
- *
- * @urb: Urb structure used for device communication.
- */
-struct queue_entry_priv_usb_rx {
-       struct urb *urb;
-};
+                           struct data_queue *queue, struct sk_buff *skb);
 
 /**
- * struct queue_entry_priv_usb_tx: Per TX entry USB specific information
+ * struct queue_entry_priv_usb: Per entry USB specific information
  *
  * @urb: Urb structure used for device communication.
- * @control: mac80211 control structure used to transmit data.
  */
-struct queue_entry_priv_usb_tx {
+struct queue_entry_priv_usb {
        struct urb *urb;
-
-       struct ieee80211_tx_control control;
 };
 
 /**
- * struct queue_entry_priv_usb_tx: Per TX entry USB specific information
+ * struct queue_entry_priv_usb_bcn: Per TX entry USB specific information
  *
- * The first section should match &struct queue_entry_priv_usb_tx exactly.
+ * The first section should match &struct queue_entry_priv_usb exactly.
  * rt2500usb can use this structure to send a guardian byte when working
  * with beacons.
  *
  * @urb: Urb structure used for device communication.
- * @control: mac80211 control structure used to transmit data.
  * @guardian_data: Set to 0, used for sending the guardian data.
  * @guardian_urb: Urb structure used to send the guardian data.
  */
 struct queue_entry_priv_usb_bcn {
        struct urb *urb;
 
-       struct ieee80211_tx_control control;
-
        unsigned int guardian_data;
        struct urb *guardian_urb;
 };
index 14bc7b281659c621bdd380c190c6e8bb181cc326..e13ed5ced26e9d2014e1851e5007d9d9c83628f3 100644 (file)
@@ -1018,49 +1018,34 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, void *data,
 static void rt61pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
                                 struct queue_entry *entry)
 {
-       struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data;
+       struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        u32 word;
 
-       rt2x00_desc_read(priv_rx->desc, 5, &word);
+       rt2x00_desc_read(entry_priv->desc, 5, &word);
        rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS,
-                          priv_rx->data_dma);
-       rt2x00_desc_write(priv_rx->desc, 5, word);
+                          entry_priv->data_dma);
+       rt2x00_desc_write(entry_priv->desc, 5, word);
 
-       rt2x00_desc_read(priv_rx->desc, 0, &word);
+       rt2x00_desc_read(entry_priv->desc, 0, &word);
        rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
-       rt2x00_desc_write(priv_rx->desc, 0, word);
+       rt2x00_desc_write(entry_priv->desc, 0, word);
 }
 
 static void rt61pci_init_txentry(struct rt2x00_dev *rt2x00dev,
                                 struct queue_entry *entry)
 {
-       struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data;
+       struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        u32 word;
 
-       rt2x00_desc_read(priv_tx->desc, 1, &word);
-       rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1);
-       rt2x00_desc_write(priv_tx->desc, 1, word);
-
-       rt2x00_desc_read(priv_tx->desc, 5, &word);
-       rt2x00_set_field32(&word, TXD_W5_PID_TYPE, entry->queue->qid);
-       rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, entry->entry_idx);
-       rt2x00_desc_write(priv_tx->desc, 5, word);
-
-       rt2x00_desc_read(priv_tx->desc, 6, &word);
-       rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
-                          priv_tx->data_dma);
-       rt2x00_desc_write(priv_tx->desc, 6, word);
-
-       rt2x00_desc_read(priv_tx->desc, 0, &word);
+       rt2x00_desc_read(entry_priv->desc, 0, &word);
        rt2x00_set_field32(&word, TXD_W0_VALID, 0);
        rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
-       rt2x00_desc_write(priv_tx->desc, 0, word);
+       rt2x00_desc_write(entry_priv->desc, 0, word);
 }
 
 static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev)
 {
-       struct queue_entry_priv_pci_rx *priv_rx;
-       struct queue_entry_priv_pci_tx *priv_tx;
+       struct queue_entry_priv_pci *entry_priv;
        u32 reg;
 
        /*
@@ -1082,28 +1067,28 @@ static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev)
                           rt2x00dev->tx[0].desc_size / 4);
        rt2x00pci_register_write(rt2x00dev, TX_RING_CSR1, reg);
 
-       priv_tx = rt2x00dev->tx[0].entries[0].priv_data;
+       entry_priv = rt2x00dev->tx[0].entries[0].priv_data;
        rt2x00pci_register_read(rt2x00dev, AC0_BASE_CSR, &reg);
        rt2x00_set_field32(&reg, AC0_BASE_CSR_RING_REGISTER,
-                          priv_tx->desc_dma);
+                          entry_priv->desc_dma);
        rt2x00pci_register_write(rt2x00dev, AC0_BASE_CSR, reg);
 
-       priv_tx = rt2x00dev->tx[1].entries[0].priv_data;
+       entry_priv = rt2x00dev->tx[1].entries[0].priv_data;
        rt2x00pci_register_read(rt2x00dev, AC1_BASE_CSR, &reg);
        rt2x00_set_field32(&reg, AC1_BASE_CSR_RING_REGISTER,
-                          priv_tx->desc_dma);
+                          entry_priv->desc_dma);
        rt2x00pci_register_write(rt2x00dev, AC1_BASE_CSR, reg);
 
-       priv_tx = rt2x00dev->tx[2].entries[0].priv_data;
+       entry_priv = rt2x00dev->tx[2].entries[0].priv_data;
        rt2x00pci_register_read(rt2x00dev, AC2_BASE_CSR, &reg);
        rt2x00_set_field32(&reg, AC2_BASE_CSR_RING_REGISTER,
-                          priv_tx->desc_dma);
+                          entry_priv->desc_dma);
        rt2x00pci_register_write(rt2x00dev, AC2_BASE_CSR, reg);
 
-       priv_tx = rt2x00dev->tx[3].entries[0].priv_data;
+       entry_priv = rt2x00dev->tx[3].entries[0].priv_data;
        rt2x00pci_register_read(rt2x00dev, AC3_BASE_CSR, &reg);
        rt2x00_set_field32(&reg, AC3_BASE_CSR_RING_REGISTER,
-                          priv_tx->desc_dma);
+                          entry_priv->desc_dma);
        rt2x00pci_register_write(rt2x00dev, AC3_BASE_CSR, reg);
 
        rt2x00pci_register_read(rt2x00dev, RX_RING_CSR, &reg);
@@ -1113,10 +1098,10 @@ static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field32(&reg, RX_RING_CSR_RXD_WRITEBACK_SIZE, 4);
        rt2x00pci_register_write(rt2x00dev, RX_RING_CSR, reg);
 
-       priv_rx = rt2x00dev->rx->entries[0].priv_data;
+       entry_priv = rt2x00dev->rx->entries[0].priv_data;
        rt2x00pci_register_read(rt2x00dev, RX_BASE_CSR, &reg);
        rt2x00_set_field32(&reg, RX_BASE_CSR_RING_REGISTER,
-                          priv_rx->desc_dma);
+                          entry_priv->desc_dma);
        rt2x00pci_register_write(rt2x00dev, RX_BASE_CSR, reg);
 
        rt2x00pci_register_read(rt2x00dev, TX_DMA_DST_CSR, &reg);
@@ -1526,10 +1511,10 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev,
  */
 static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                    struct sk_buff *skb,
-                                   struct txentry_desc *txdesc,
-                                   struct ieee80211_tx_control *control)
+                                   struct txentry_desc *txdesc)
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+       struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
        __le32 *txd = skbdesc->desc;
        u32 word;
 
@@ -1543,6 +1528,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
        rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
        rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1);
+       rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1);
        rt2x00_desc_write(txd, 1, word);
 
        rt2x00_desc_read(txd, 2, &word);
@@ -1553,11 +1539,19 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_desc_write(txd, 2, word);
 
        rt2x00_desc_read(txd, 5, &word);
+       rt2x00_set_field32(&word, TXD_W5_PID_TYPE, skbdesc->entry->queue->qid);
+       rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE,
+                          skbdesc->entry->entry_idx);
        rt2x00_set_field32(&word, TXD_W5_TX_POWER,
                           TXPOWER_TO_DEV(rt2x00dev->tx_power));
        rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
        rt2x00_desc_write(txd, 5, word);
 
+       rt2x00_desc_read(txd, 6, &word);
+       rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
+                          entry_priv->data_dma);
+       rt2x00_desc_write(txd, 6, word);
+
        if (skbdesc->desc_len > TXINFO_SIZE) {
                rt2x00_desc_read(txd, 11, &word);
                rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, skbdesc->data_len);
@@ -1577,8 +1571,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                           test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
        rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
-                          !!(control->flags &
-                             IEEE80211_TXCTL_LONG_RETRY_LIMIT));
+                          test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0);
        rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len);
        rt2x00_set_field32(&word, TXD_W0_BURST,
@@ -1591,11 +1584,11 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
  * TX data initialization
  */
 static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                 const unsigned int queue)
+                                 const enum data_queue_qid queue)
 {
        u32 reg;
 
-       if (queue == RT2X00_BCN_QUEUE_BEACON) {
+       if (queue == QID_BEACON) {
                /*
                 * For Wi-Fi faily generated beacons between participating
                 * stations. Set TBTT phase adaptive adjustment step to 8us.
@@ -1613,14 +1606,10 @@ static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
        }
 
        rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
-       rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0,
-                          (queue == IEEE80211_TX_QUEUE_DATA0));
-       rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1,
-                          (queue == IEEE80211_TX_QUEUE_DATA1));
-       rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC2,
-                          (queue == IEEE80211_TX_QUEUE_DATA2));
-       rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC3,
-                          (queue == IEEE80211_TX_QUEUE_DATA3));
+       rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, (queue == QID_AC_BE));
+       rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1, (queue == QID_AC_BK));
+       rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC2, (queue == QID_AC_VI));
+       rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC3, (queue == QID_AC_VO));
        rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
 }
 
@@ -1671,14 +1660,13 @@ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
 static void rt61pci_fill_rxdone(struct queue_entry *entry,
                                struct rxdone_entry_desc *rxdesc)
 {
-       struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data;
+       struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        u32 word0;
        u32 word1;
 
-       rt2x00_desc_read(priv_rx->desc, 0, &word0);
-       rt2x00_desc_read(priv_rx->desc, 1, &word1);
+       rt2x00_desc_read(entry_priv->desc, 0, &word0);
+       rt2x00_desc_read(entry_priv->desc, 1, &word1);
 
-       rxdesc->flags = 0;
        if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
                rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
 
@@ -1692,7 +1680,6 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry,
        rxdesc->rssi = rt61pci_agc_to_rssi(entry->queue->rt2x00dev, word1);
        rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
 
-       rxdesc->dev_flags = 0;
        if (rt2x00_get_field32(word0, RXD_W0_OFDM))
                rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP;
        if (rt2x00_get_field32(word0, RXD_W0_MY_BSS))
@@ -1707,7 +1694,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
        struct data_queue *queue;
        struct queue_entry *entry;
        struct queue_entry *entry_done;
-       struct queue_entry_priv_pci_tx *priv_tx;
+       struct queue_entry_priv_pci *entry_priv;
        struct txdone_entry_desc txdesc;
        u32 word;
        u32 reg;
@@ -1752,8 +1739,8 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
                        continue;
 
                entry = &queue->entries[index];
-               priv_tx = entry->priv_data;
-               rt2x00_desc_read(priv_tx->desc, 0, &word);
+               entry_priv = entry->priv_data;
+               rt2x00_desc_read(entry_priv->desc, 0, &word);
 
                if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
                    !rt2x00_get_field32(word, TXD_W0_VALID))
@@ -1768,7 +1755,8 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
                                "TX status report missed for entry %d\n",
                                entry_done->entry_idx);
 
-                       txdesc.status = TX_FAIL_OTHER;
+                       txdesc.flags = 0;
+                       __set_bit(TXDONE_UNKNOWN, &txdesc.flags);
                        txdesc.retry = 0;
 
                        rt2x00pci_txdone(rt2x00dev, entry_done, &txdesc);
@@ -1778,7 +1766,17 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
                /*
                 * Obtain the status about this packet.
                 */
-               txdesc.status = rt2x00_get_field32(reg, STA_CSR4_TX_RESULT);
+               txdesc.flags = 0;
+               switch (rt2x00_get_field32(reg, STA_CSR4_TX_RESULT)) {
+               case 0: /* Success, maybe with retry */
+                       __set_bit(TXDONE_SUCCESS, &txdesc.flags);
+                       break;
+               case 6: /* Failure, excessive retries */
+                       __set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags);
+                       /* Don't break, this is a failed frame! */
+               default: /* Failure */
+                       __set_bit(TXDONE_FAILURE, &txdesc.flags);
+               }
                txdesc.retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT);
 
                rt2x00pci_txdone(rt2x00dev, entry, &txdesc);
@@ -2249,11 +2247,9 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
         */
        rt2x00dev->hw->flags =
            IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
-           IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+           IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+           IEEE80211_HW_SIGNAL_DBM;
        rt2x00dev->hw->extra_tx_headroom = 0;
-       rt2x00dev->hw->max_signal = MAX_SIGNAL;
-       rt2x00dev->hw->max_rssi = MAX_RX_SSI;
-       rt2x00dev->hw->queues = 4;
 
        SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
        SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
@@ -2361,21 +2357,30 @@ static u64 rt61pci_get_tsf(struct ieee80211_hw *hw)
        return tsf;
 }
 
-static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
-                         struct ieee80211_tx_control *control)
+static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
-       struct rt2x00_intf *intf = vif_to_intf(control->vif);
-       struct queue_entry_priv_pci_tx *priv_tx;
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
+       struct queue_entry_priv_pci *entry_priv;
        struct skb_frame_desc *skbdesc;
+       struct txentry_desc txdesc;
        unsigned int beacon_base;
        u32 reg;
 
        if (unlikely(!intf->beacon))
                return -ENOBUFS;
 
-       priv_tx = intf->beacon->priv_data;
-       memset(priv_tx->desc, 0, intf->beacon->queue->desc_size);
+       /*
+        * Copy all TX descriptor information into txdesc,
+        * after that we are free to use the skb->cb array
+        * for our information.
+        */
+       intf->beacon->skb = skb;
+       rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
+
+       entry_priv = intf->beacon->priv_data;
+       memset(entry_priv->desc, 0, intf->beacon->queue->desc_size);
 
        /*
         * Fill in skb descriptor
@@ -2385,7 +2390,7 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
        skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED;
        skbdesc->data = skb->data;
        skbdesc->data_len = skb->len;
-       skbdesc->desc = priv_tx->desc;
+       skbdesc->desc = entry_priv->desc;
        skbdesc->desc_len = intf->beacon->queue->desc_size;
        skbdesc->entry = intf->beacon;
 
@@ -2399,25 +2404,18 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
        rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
        rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
 
-       /*
-        * mac80211 doesn't provide the control->queue variable
-        * for beacons. Set our own queue identification so
-        * it can be used during descriptor initialization.
-        */
-       control->queue = RT2X00_BCN_QUEUE_BEACON;
-       rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
-
        /*
         * Write entire beacon with descriptor to register,
         * and kick the beacon generator.
         */
+       rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
        beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
        rt2x00pci_register_multiwrite(rt2x00dev, beacon_base,
                                      skbdesc->desc, skbdesc->desc_len);
        rt2x00pci_register_multiwrite(rt2x00dev,
                                      beacon_base + skbdesc->desc_len,
                                      skbdesc->data, skbdesc->data_len);
-       rt61pci_kick_tx_queue(rt2x00dev, control->queue);
+       rt61pci_kick_tx_queue(rt2x00dev, QID_BEACON);
 
        return 0;
 }
@@ -2469,21 +2467,21 @@ static const struct data_queue_desc rt61pci_queue_rx = {
        .entry_num              = RX_ENTRIES,
        .data_size              = DATA_FRAME_SIZE,
        .desc_size              = RXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_pci_rx),
+       .priv_size              = sizeof(struct queue_entry_priv_pci),
 };
 
 static const struct data_queue_desc rt61pci_queue_tx = {
        .entry_num              = TX_ENTRIES,
        .data_size              = DATA_FRAME_SIZE,
        .desc_size              = TXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_pci_tx),
+       .priv_size              = sizeof(struct queue_entry_priv_pci),
 };
 
 static const struct data_queue_desc rt61pci_queue_bcn = {
        .entry_num              = 4 * BEACON_ENTRIES,
        .data_size              = 0, /* No DMA required for beacons */
        .desc_size              = TXINFO_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_pci_tx),
+       .priv_size              = sizeof(struct queue_entry_priv_pci),
 };
 
 static const struct rt2x00_ops rt61pci_ops = {
@@ -2492,6 +2490,7 @@ static const struct rt2x00_ops rt61pci_ops = {
        .max_ap_intf    = 4,
        .eeprom_size    = EEPROM_SIZE,
        .rf_size        = RF_SIZE,
+       .tx_queues      = NUM_TX_QUEUES,
        .rx             = &rt61pci_queue_rx,
        .tx             = &rt61pci_queue_tx,
        .bcn            = &rt61pci_queue_bcn,
index 3511bba7ff65479cdee3d2b3c158876929b89a36..c5a04b9329d2953f4957683bd633ff5a0afd56ba 100644 (file)
 #define BBP_SIZE                       0x0080
 #define RF_SIZE                                0x0014
 
+/*
+ * Number of TX queues.
+ */
+#define NUM_TX_QUEUES                  4
+
 /*
  * PCI registers.
  */
index da19a3a91f4d3909fd21d732a5f833862b6bdb10..26c2e0a1a308d3a68991a64ecc023d97db797960 100644 (file)
@@ -74,10 +74,10 @@ static inline void rt73usb_register_multiread(struct rt2x00_dev *rt2x00dev,
                                              const unsigned int offset,
                                              void *value, const u32 length)
 {
-       int timeout = REGISTER_TIMEOUT * (length / sizeof(u32));
        rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
                                      USB_VENDOR_REQUEST_IN, offset,
-                                     value, length, timeout);
+                                     value, length,
+                                     REGISTER_TIMEOUT32(length));
 }
 
 static inline void rt73usb_register_write(struct rt2x00_dev *rt2x00dev,
@@ -102,10 +102,10 @@ static inline void rt73usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
                                               const unsigned int offset,
                                               void *value, const u32 length)
 {
-       int timeout = REGISTER_TIMEOUT * (length / sizeof(u32));
        rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
                                      USB_VENDOR_REQUEST_OUT, offset,
-                                     value, length, timeout);
+                                     value, length,
+                                     REGISTER_TIMEOUT32(length));
 }
 
 static u32 rt73usb_bbp_check(struct rt2x00_dev *rt2x00dev)
@@ -876,7 +876,6 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, void *data,
        char *ptr = data;
        char *cache;
        int buflen;
-       int timeout;
 
        /*
         * Wait for stable hardware.
@@ -907,14 +906,14 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, void *data,
 
        for (i = 0; i < len; i += CSR_CACHE_SIZE_FIRMWARE) {
                buflen = min_t(int, len - i, CSR_CACHE_SIZE_FIRMWARE);
-               timeout = REGISTER_TIMEOUT * (buflen / sizeof(u32));
 
                memcpy(cache, ptr, buflen);
 
                rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE,
                                         USB_VENDOR_REQUEST_OUT,
                                         FIRMWARE_IMAGE_BASE + i, 0,
-                                        cache, buflen, timeout);
+                                        cache, buflen,
+                                        REGISTER_TIMEOUT32(buflen));
 
                ptr += buflen;
        }
@@ -1256,8 +1255,7 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev,
  */
 static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                    struct sk_buff *skb,
-                                   struct txentry_desc *txdesc,
-                                   struct ieee80211_tx_control *control)
+                                   struct txentry_desc *txdesc)
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
        __le32 *txd = skbdesc->desc;
@@ -1302,8 +1300,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                           test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
        rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
-                          !!(control->flags &
-                             IEEE80211_TXCTL_LONG_RETRY_LIMIT));
+                          test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0);
        rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len);
        rt2x00_set_field32(&word, TXD_W0_BURST2,
@@ -1331,11 +1328,11 @@ static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
  * TX data initialization
  */
 static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                 const unsigned int queue)
+                                 const enum data_queue_qid queue)
 {
        u32 reg;
 
-       if (queue != RT2X00_BCN_QUEUE_BEACON)
+       if (queue != QID_BEACON)
                return;
 
        /*
@@ -1406,25 +1403,26 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry,
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
        __le32 *rxd = (__le32 *)entry->skb->data;
-       unsigned int offset = entry->queue->desc_size + 2;
        u32 word0;
        u32 word1;
 
        /*
-        * Copy descriptor to the available headroom inside the skbuffer.
+        * Copy descriptor to the skb->cb array, this has 2 benefits:
+        * 1) Each descriptor word is 4 byte aligned.
+        * 2) Descriptor is safe  from moving of frame data in rt2x00usb.
         */
-       skb_push(entry->skb, offset);
-       memcpy(entry->skb->data, rxd, entry->queue->desc_size);
-       rxd = (__le32 *)entry->skb->data;
+       skbdesc->desc_len =
+           min_t(u16, entry->queue->desc_size, sizeof(entry->skb->cb));
+       memcpy(entry->skb->cb, rxd, skbdesc->desc_len);
+       skbdesc->desc = entry->skb->cb;
+       rxd = (__le32 *)skbdesc->desc;
 
        /*
-        * The descriptor is now aligned to 4 bytes and thus it is
-        * now safe to read it on all architectures.
+        * It is now safe to read the descriptor on all architectures.
         */
        rt2x00_desc_read(rxd, 0, &word0);
        rt2x00_desc_read(rxd, 1, &word1);
 
-       rxdesc->flags = 0;
        if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
                rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
 
@@ -1438,25 +1436,18 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry,
        rxdesc->rssi = rt73usb_agc_to_rssi(entry->queue->rt2x00dev, word1);
        rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
 
-       rxdesc->dev_flags = 0;
        if (rt2x00_get_field32(word0, RXD_W0_OFDM))
                rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP;
        if (rt2x00_get_field32(word0, RXD_W0_MY_BSS))
                rxdesc->dev_flags |= RXDONE_MY_BSS;
 
        /*
-        * Adjust the skb memory window to the frame boundaries.
+        * Set skb pointers, and update frame information.
         */
-       skb_pull(entry->skb, offset + entry->queue->desc_size);
+       skb_pull(entry->skb, entry->queue->desc_size);
        skb_trim(entry->skb, rxdesc->size);
-
-       /*
-        * Set descriptor and data pointer.
-        */
        skbdesc->data = entry->skb->data;
        skbdesc->data_len = rxdesc->size;
-       skbdesc->desc = rxd;
-       skbdesc->desc_len = entry->queue->desc_size;
 }
 
 /*
@@ -1831,11 +1822,9 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
         */
        rt2x00dev->hw->flags =
            IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
-           IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+           IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+           IEEE80211_HW_SIGNAL_DBM;
        rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
-       rt2x00dev->hw->max_signal = MAX_SIGNAL;
-       rt2x00dev->hw->max_rssi = MAX_RX_SSI;
-       rt2x00dev->hw->queues = 4;
 
        SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);
        SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
@@ -1959,19 +1948,27 @@ static u64 rt73usb_get_tsf(struct ieee80211_hw *hw)
 #define rt73usb_get_tsf        NULL
 #endif
 
-static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
-                                struct ieee80211_tx_control *control)
+static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
-       struct rt2x00_intf *intf = vif_to_intf(control->vif);
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
        struct skb_frame_desc *skbdesc;
+       struct txentry_desc txdesc;
        unsigned int beacon_base;
-       unsigned int timeout;
        u32 reg;
 
        if (unlikely(!intf->beacon))
                return -ENOBUFS;
 
+       /*
+        * Copy all TX descriptor information into txdesc,
+        * after that we are free to use the skb->cb array
+        * for our information.
+        */
+       intf->beacon->skb = skb;
+       rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
+
        /*
         * Add the descriptor in front of the skb.
         */
@@ -2000,24 +1997,17 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
        rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
        rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
 
-       /*
-        * mac80211 doesn't provide the control->queue variable
-        * for beacons. Set our own queue identification so
-        * it can be used during descriptor initialization.
-        */
-       control->queue = RT2X00_BCN_QUEUE_BEACON;
-       rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
-
        /*
         * Write entire beacon with descriptor to register,
         * and kick the beacon generator.
         */
+       rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
        beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
-       timeout = REGISTER_TIMEOUT * (skb->len / sizeof(u32));
        rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE,
                                 USB_VENDOR_REQUEST_OUT, beacon_base, 0,
-                                skb->data, skb->len, timeout);
-       rt73usb_kick_tx_queue(rt2x00dev, control->queue);
+                                skb->data, skb->len,
+                                REGISTER_TIMEOUT32(skb->len));
+       rt73usb_kick_tx_queue(rt2x00dev, QID_BEACON);
 
        return 0;
 }
@@ -2068,21 +2058,21 @@ static const struct data_queue_desc rt73usb_queue_rx = {
        .entry_num              = RX_ENTRIES,
        .data_size              = DATA_FRAME_SIZE,
        .desc_size              = RXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_usb_rx),
+       .priv_size              = sizeof(struct queue_entry_priv_usb),
 };
 
 static const struct data_queue_desc rt73usb_queue_tx = {
        .entry_num              = TX_ENTRIES,
        .data_size              = DATA_FRAME_SIZE,
        .desc_size              = TXD_DESC_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_usb_tx),
+       .priv_size              = sizeof(struct queue_entry_priv_usb),
 };
 
 static const struct data_queue_desc rt73usb_queue_bcn = {
        .entry_num              = 4 * BEACON_ENTRIES,
        .data_size              = MGMT_FRAME_SIZE,
        .desc_size              = TXINFO_SIZE,
-       .priv_size              = sizeof(struct queue_entry_priv_usb_tx),
+       .priv_size              = sizeof(struct queue_entry_priv_usb),
 };
 
 static const struct rt2x00_ops rt73usb_ops = {
@@ -2091,6 +2081,7 @@ static const struct rt2x00_ops rt73usb_ops = {
        .max_ap_intf    = 4,
        .eeprom_size    = EEPROM_SIZE,
        .rf_size        = RF_SIZE,
+       .tx_queues      = NUM_TX_QUEUES,
        .rx             = &rt73usb_queue_rx,
        .tx             = &rt73usb_queue_tx,
        .bcn            = &rt73usb_queue_bcn,
index 06d687425fefa069ea28f0bae2df6d118d437478..25cdcc9bf7c471b6170397f6afecb9065817cbf3 100644 (file)
 #define BBP_SIZE                       0x0080
 #define RF_SIZE                                0x0014
 
+/*
+ * Number of TX queues.
+ */
+#define NUM_TX_QUEUES                  4
+
 /*
  * USB registers.
  */
index c181f23e930dc96048f3b1d700434bbf92a6a26b..b7172a12c0572e3d9b1c27b3cf6747d7021a2eed 100644 (file)
@@ -132,8 +132,8 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
 
                        rx_status.antenna = (flags2 >> 15) & 1;
                        /* TODO: improve signal/rssi reporting */
-                       rx_status.signal = flags2 & 0xFF;
-                       rx_status.ssi = (flags2 >> 8) & 0x7F;
+                       rx_status.qual = flags2 & 0xFF;
+                       rx_status.signal = (flags2 >> 8) & 0x7F;
                        /* XXX: is this correct? */
                        rx_status.rate_idx = (flags >> 20) & 0xF;
                        rx_status.freq = dev->conf.channel->center_freq;
@@ -170,34 +170,29 @@ static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio)
        while (skb_queue_len(&ring->queue)) {
                struct rtl8180_tx_desc *entry = &ring->desc[ring->idx];
                struct sk_buff *skb;
-               struct ieee80211_tx_status status;
-               struct ieee80211_tx_control *control;
+               struct ieee80211_tx_info *info;
                u32 flags = le32_to_cpu(entry->flags);
 
                if (flags & RTL8180_TX_DESC_FLAG_OWN)
                        return;
 
-               memset(&status, 0, sizeof(status));
-
                ring->idx = (ring->idx + 1) % ring->entries;
                skb = __skb_dequeue(&ring->queue);
                pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf),
                                 skb->len, PCI_DMA_TODEVICE);
 
-               control = *((struct ieee80211_tx_control **)skb->cb);
-               if (control)
-                       memcpy(&status.control, control, sizeof(*control));
-               kfree(control);
+               info = IEEE80211_SKB_CB(skb);
+               memset(&info->status, 0, sizeof(info->status));
 
-               if (!(status.control.flags & IEEE80211_TXCTL_NO_ACK)) {
+               if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
                        if (flags & RTL8180_TX_DESC_FLAG_TX_OK)
-                               status.flags = IEEE80211_TX_STATUS_ACK;
+                               info->flags |= IEEE80211_TX_STAT_ACK;
                        else
-                               status.excessive_retries = 1;
+                               info->status.excessive_retries = 1;
                }
-               status.retry_count = flags & 0xFF;
+               info->status.retry_count = flags & 0xFF;
 
-               ieee80211_tx_status_irqsafe(dev, skb, &status);
+               ieee80211_tx_status_irqsafe(dev, skb);
                if (ring->entries - skb_queue_len(&ring->queue) == 2)
                        ieee80211_wake_queue(dev, prio);
        }
@@ -238,9 +233,9 @@ static irqreturn_t rtl8180_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
-                     struct ieee80211_tx_control *control)
+static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct rtl8180_priv *priv = dev->priv;
        struct rtl8180_tx_ring *ring;
        struct rtl8180_tx_desc *entry;
@@ -251,46 +246,40 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
        u16 plcp_len = 0;
        __le16 rts_duration = 0;
 
-       prio = control->queue;
+       prio = skb_get_queue_mapping(skb);
        ring = &priv->tx_ring[prio];
 
        mapping = pci_map_single(priv->pdev, skb->data,
                                 skb->len, PCI_DMA_TODEVICE);
 
-       BUG_ON(!control->tx_rate);
-
        tx_flags = RTL8180_TX_DESC_FLAG_OWN | RTL8180_TX_DESC_FLAG_FS |
                   RTL8180_TX_DESC_FLAG_LS |
-                  (control->tx_rate->hw_value << 24) | skb->len;
+                  (ieee80211_get_tx_rate(dev, info)->hw_value << 24) |
+                  skb->len;
 
        if (priv->r8185)
                tx_flags |= RTL8180_TX_DESC_FLAG_DMA |
                            RTL8180_TX_DESC_FLAG_NO_ENC;
 
-       if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
-               BUG_ON(!control->rts_cts_rate);
+       if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
                tx_flags |= RTL8180_TX_DESC_FLAG_RTS;
-               tx_flags |= control->rts_cts_rate->hw_value << 19;
-       } else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
-               BUG_ON(!control->rts_cts_rate);
+               tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
+       } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
                tx_flags |= RTL8180_TX_DESC_FLAG_CTS;
-               tx_flags |= control->rts_cts_rate->hw_value << 19;
+               tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
        }
 
-       *((struct ieee80211_tx_control **) skb->cb) =
-               kmemdup(control, sizeof(*control), GFP_ATOMIC);
-
-       if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
+       if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
                rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len,
-                                                     control);
+                                                     info);
 
        if (!priv->r8185) {
                unsigned int remainder;
 
                plcp_len = DIV_ROUND_UP(16 * (skb->len + 4),
-                                       (control->tx_rate->bitrate * 2) / 10);
+                               (ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10);
                remainder = (16 * (skb->len + 4)) %
-                           ((control->tx_rate->bitrate * 2) / 10);
+                           ((ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10);
                if (remainder > 0 && remainder <= 6)
                        plcp_len |= 1 << 15;
        }
@@ -303,13 +292,13 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
        entry->plcp_len = cpu_to_le16(plcp_len);
        entry->tx_buf = cpu_to_le32(mapping);
        entry->frame_len = cpu_to_le32(skb->len);
-       entry->flags2 = control->alt_retry_rate != NULL ?
-                       control->alt_retry_rate->bitrate << 4 : 0;
-       entry->retry_limit = control->retry_limit;
+       entry->flags2 = info->control.alt_retry_rate_idx >= 0 ?
+               ieee80211_get_alt_retry_rate(dev, info)->bitrate << 4 : 0;
+       entry->retry_limit = info->control.retry_limit;
        entry->flags = cpu_to_le32(tx_flags);
        __skb_queue_tail(&ring->queue, skb);
        if (ring->entries - skb_queue_len(&ring->queue) < 2)
-               ieee80211_stop_queue(dev, control->queue);
+               ieee80211_stop_queue(dev, skb_get_queue_mapping(skb));
        spin_unlock_irqrestore(&priv->lock, flags);
 
        rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4)));
@@ -525,7 +514,6 @@ static void rtl8180_free_tx_ring(struct ieee80211_hw *dev, unsigned int prio)
 
                pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf),
                                 skb->len, PCI_DMA_TODEVICE);
-               kfree(*((struct ieee80211_tx_control **) skb->cb));
                kfree_skb(skb);
                ring->idx = (ring->idx + 1) % ring->entries;
        }
@@ -894,9 +882,10 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev,
        dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
 
        dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
-                    IEEE80211_HW_RX_INCLUDES_FCS;
+                    IEEE80211_HW_RX_INCLUDES_FCS |
+                    IEEE80211_HW_SIGNAL_UNSPEC;
        dev->queues = 1;
-       dev->max_rssi = 65;
+       dev->max_signal = 65;
 
        reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
        reg &= RTL818X_TX_CONF_HWVER_MASK;
index 076d88b6db0e9f69c23d3e952af95b03097a549f..a0cfb666de0ee718f641b8fc9b4fd93d44c7f6fa 100644 (file)
@@ -44,12 +44,6 @@ struct rtl8187_rx_hdr {
        __le64 mac_time;
 } __attribute__((packed));
 
-struct rtl8187_tx_info {
-       struct ieee80211_tx_control *control;
-       struct urb *urb;
-       struct ieee80211_hw *dev;
-};
-
 struct rtl8187_tx_hdr {
        __le32 flags;
 #define RTL8187_TX_FLAG_NO_ENCRYPT     (1 << 15)
index 9223ada5f00ed2d73ca633793c2b9e646033019a..0078c7e9918c4cc772bb2ac57ed3207a9b48c7e0 100644 (file)
@@ -150,27 +150,22 @@ void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
 
 static void rtl8187_tx_cb(struct urb *urb)
 {
-       struct ieee80211_tx_status status;
        struct sk_buff *skb = (struct sk_buff *)urb->context;
-       struct rtl8187_tx_info *info = (struct rtl8187_tx_info *)skb->cb;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_hw *hw = info->driver_data[0];
 
-       memset(&status, 0, sizeof(status));
-
-       usb_free_urb(info->urb);
-       if (info->control)
-               memcpy(&status.control, info->control, sizeof(status.control));
-       kfree(info->control);
+       usb_free_urb(info->driver_data[1]);
        skb_pull(skb, sizeof(struct rtl8187_tx_hdr));
-       status.flags |= IEEE80211_TX_STATUS_ACK;
-       ieee80211_tx_status_irqsafe(info->dev, skb, &status);
+       memset(&info->status, 0, sizeof(info->status));
+       info->flags |= IEEE80211_TX_STAT_ACK;
+       ieee80211_tx_status_irqsafe(hw, skb);
 }
 
-static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
-                     struct ieee80211_tx_control *control)
+static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
        struct rtl8187_priv *priv = dev->priv;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct rtl8187_tx_hdr *hdr;
-       struct rtl8187_tx_info *info;
        struct urb *urb;
        __le16 rts_dur = 0;
        u32 flags;
@@ -185,33 +180,27 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
        flags = skb->len;
        flags |= RTL8187_TX_FLAG_NO_ENCRYPT;
 
-       BUG_ON(!control->tx_rate);
-
-       flags |= control->tx_rate->hw_value << 24;
+       flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24;
        if (ieee80211_get_morefrag((struct ieee80211_hdr *)skb->data))
                flags |= RTL8187_TX_FLAG_MORE_FRAG;
-       if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
-               BUG_ON(!control->rts_cts_rate);
+       if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
                flags |= RTL8187_TX_FLAG_RTS;
-               flags |= control->rts_cts_rate->hw_value << 19;
+               flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
                rts_dur = ieee80211_rts_duration(dev, priv->vif,
-                                                skb->len, control);
-       } else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
-               BUG_ON(!control->rts_cts_rate);
+                                                skb->len, info);
+       } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
                flags |= RTL8187_TX_FLAG_CTS;
-               flags |= control->rts_cts_rate->hw_value << 19;
+               flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
        }
 
        hdr = (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr));
        hdr->flags = cpu_to_le32(flags);
        hdr->len = 0;
        hdr->rts_duration = rts_dur;
-       hdr->retry = cpu_to_le32(control->retry_limit << 8);
+       hdr->retry = cpu_to_le32(info->control.retry_limit << 8);
 
-       info = (struct rtl8187_tx_info *)skb->cb;
-       info->control = kmemdup(control, sizeof(*control), GFP_ATOMIC);
-       info->urb = urb;
-       info->dev = dev;
+       info->driver_data[0] = dev;
+       info->driver_data[1] = urb;
        usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, 2),
                          hdr, skb->len, rtl8187_tx_cb, skb);
        rc = usb_submit_urb(urb, GFP_ATOMIC);
@@ -271,8 +260,8 @@ static void rtl8187_rx_cb(struct urb *urb)
        }
 
        rx_status.antenna = (hdr->signal >> 7) & 1;
-       rx_status.signal = 64 - min(hdr->noise, (u8)64);
-       rx_status.ssi = signal;
+       rx_status.qual = 64 - min(hdr->noise, (u8)64);
+       rx_status.signal = signal;
        rx_status.rate_idx = rate;
        rx_status.freq = dev->conf.channel->center_freq;
        rx_status.band = dev->conf.channel->band;
@@ -750,11 +739,11 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
 
        priv->mode = IEEE80211_IF_TYPE_MNTR;
        dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
-                    IEEE80211_HW_RX_INCLUDES_FCS;
+                    IEEE80211_HW_RX_INCLUDES_FCS |
+                    IEEE80211_HW_SIGNAL_UNSPEC;
        dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr);
        dev->queues = 1;
-       dev->max_rssi = 65;
-       dev->max_signal = 64;
+       dev->max_signal = 65;
 
        eeprom.data = dev;
        eeprom.register_read = rtl8187_eeprom_register_read;
index 418606ac1c3be8263b8f62bd9f15b00763254705..6d86b365f15078b2f8ae0eb338777ccfed76259a 100644 (file)
@@ -224,36 +224,6 @@ out:
        return r;
 }
 
-/**
- * clear_tx_skb_control_block - clears the control block of tx skbuffs
- * @skb: a &struct sk_buff pointer
- *
- * This clears the control block of skbuff buffers, which were transmitted to
- * the device. Notify that the function is not thread-safe, so prevent
- * multiple calls.
- */
-static void clear_tx_skb_control_block(struct sk_buff *skb)
-{
-       struct zd_tx_skb_control_block *cb =
-               (struct zd_tx_skb_control_block *)skb->cb;
-
-       kfree(cb->control);
-       cb->control = NULL;
-}
-
-/**
- * kfree_tx_skb - frees a tx skbuff
- * @skb: a &struct sk_buff pointer
- *
- * Frees the tx skbuff. Frees also the allocated control structure in the
- * control block if necessary.
- */
-static void kfree_tx_skb(struct sk_buff *skb)
-{
-       clear_tx_skb_control_block(skb);
-       dev_kfree_skb_any(skb);
-}
-
 static void zd_op_stop(struct ieee80211_hw *hw)
 {
        struct zd_mac *mac = zd_hw_mac(hw);
@@ -276,40 +246,15 @@ static void zd_op_stop(struct ieee80211_hw *hw)
 
 
        while ((skb = skb_dequeue(ack_wait_queue)))
-               kfree_tx_skb(skb);
-}
-
-/**
- * init_tx_skb_control_block - initializes skb control block
- * @skb: a &sk_buff pointer
- * @dev: pointer to the mac80221 device
- * @control: mac80211 tx control applying for the frame in @skb
- *
- * Initializes the control block of the skbuff to be transmitted.
- */
-static int init_tx_skb_control_block(struct sk_buff *skb,
-                                    struct ieee80211_hw *hw,
-                                    struct ieee80211_tx_control *control)
-{
-       struct zd_tx_skb_control_block *cb =
-               (struct zd_tx_skb_control_block *)skb->cb;
-
-       ZD_ASSERT(sizeof(*cb) <= sizeof(skb->cb));
-       memset(cb, 0, sizeof(*cb));
-       cb->hw= hw;
-       cb->control = kmalloc(sizeof(*control), GFP_ATOMIC);
-       if (cb->control == NULL)
-               return -ENOMEM;
-       memcpy(cb->control, control, sizeof(*control));
-
-       return 0;
+               dev_kfree_skb_any(skb);
 }
 
 /**
  * tx_status - reports tx status of a packet if required
  * @hw - a &struct ieee80211_hw pointer
  * @skb - a sk-buffer
- * @status - the tx status of the packet without control information
+ * @flags: extra flags to set in the TX status info
+ * @ackssi: ACK signal strength
  * @success - True for successfull transmission of the frame
  *
  * This information calls ieee80211_tx_status_irqsafe() if required by the
@@ -319,18 +264,17 @@ static int init_tx_skb_control_block(struct sk_buff *skb,
  * If no status information has been requested, the skb is freed.
  */
 static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
-                     struct ieee80211_tx_status *status,
-                     bool success)
+                     u32 flags, int ackssi, bool success)
 {
-       struct zd_tx_skb_control_block *cb = (struct zd_tx_skb_control_block *)
-               skb->cb;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+       memset(&info->status, 0, sizeof(info->status));
 
-       ZD_ASSERT(cb->control != NULL);
-       memcpy(&status->control, cb->control, sizeof(status->control));
        if (!success)
-               status->excessive_retries = 1;
-       clear_tx_skb_control_block(skb);
-       ieee80211_tx_status_irqsafe(hw, skb, status);
+               info->status.excessive_retries = 1;
+       info->flags |= flags;
+       info->status.ack_signal = ackssi;
+       ieee80211_tx_status_irqsafe(hw, skb);
 }
 
 /**
@@ -345,15 +289,12 @@ void zd_mac_tx_failed(struct ieee80211_hw *hw)
 {
        struct sk_buff_head *q = &zd_hw_mac(hw)->ack_wait_queue;
        struct sk_buff *skb;
-       struct ieee80211_tx_status status;
 
        skb = skb_dequeue(q);
        if (skb == NULL)
                return;
 
-       memset(&status, 0, sizeof(status));
-
-       tx_status(hw, skb, &status, 0);
+       tx_status(hw, skb, 0, 0, 0);
 }
 
 /**
@@ -368,28 +309,20 @@ void zd_mac_tx_failed(struct ieee80211_hw *hw)
  */
 void zd_mac_tx_to_dev(struct sk_buff *skb, int error)
 {
-       struct zd_tx_skb_control_block *cb =
-               (struct zd_tx_skb_control_block *)skb->cb;
-       struct ieee80211_hw *hw = cb->hw;
-
-       if (likely(cb->control)) {
-               skb_pull(skb, sizeof(struct zd_ctrlset));
-               if (unlikely(error ||
-                   (cb->control->flags & IEEE80211_TXCTL_NO_ACK)))
-               {
-                       struct ieee80211_tx_status status;
-                       memset(&status, 0, sizeof(status));
-                       tx_status(hw, skb, &status, !error);
-               } else {
-                       struct sk_buff_head *q =
-                               &zd_hw_mac(hw)->ack_wait_queue;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_hw *hw = info->driver_data[0];
 
-                       skb_queue_tail(q, skb);
-                       while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS)
-                               zd_mac_tx_failed(hw);
-               }
+       skb_pull(skb, sizeof(struct zd_ctrlset));
+       if (unlikely(error ||
+           (info->flags & IEEE80211_TX_CTL_NO_ACK))) {
+               tx_status(hw, skb, 0, 0, !error);
        } else {
-               kfree_tx_skb(skb);
+               struct sk_buff_head *q =
+                       &zd_hw_mac(hw)->ack_wait_queue;
+
+               skb_queue_tail(q, skb);
+               while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS)
+                       zd_mac_tx_failed(hw);
        }
 }
 
@@ -454,7 +387,7 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
        cs->control = 0;
 
        /* First fragment */
-       if (flags & IEEE80211_TXCTL_FIRST_FRAGMENT)
+       if (flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
                cs->control |= ZD_CS_NEED_RANDOM_BACKOFF;
 
        /* Multicast */
@@ -466,10 +399,10 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
            (IEEE80211_FTYPE_CTL|IEEE80211_STYPE_PSPOLL))
                cs->control |= ZD_CS_PS_POLL_FRAME;
 
-       if (flags & IEEE80211_TXCTL_USE_RTS_CTS)
+       if (flags & IEEE80211_TX_CTL_USE_RTS_CTS)
                cs->control |= ZD_CS_RTS;
 
-       if (flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+       if (flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
                cs->control |= ZD_CS_SELF_CTS;
 
        /* FIXME: Management frame? */
@@ -516,25 +449,28 @@ void zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon)
 }
 
 static int fill_ctrlset(struct zd_mac *mac,
-                       struct sk_buff *skb,
-                       struct ieee80211_tx_control *control)
+                       struct sk_buff *skb)
 {
        int r;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        unsigned int frag_len = skb->len + FCS_LEN;
        unsigned int packet_length;
+       struct ieee80211_rate *txrate;
        struct zd_ctrlset *cs = (struct zd_ctrlset *)
                skb_push(skb, sizeof(struct zd_ctrlset));
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
        ZD_ASSERT(frag_len <= 0xffff);
 
-       cs->modulation = control->tx_rate->hw_value;
-       if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE)
-               cs->modulation = control->tx_rate->hw_value_short;
+       txrate = ieee80211_get_tx_rate(mac->hw, info);
+
+       cs->modulation = txrate->hw_value;
+       if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE)
+               cs->modulation = txrate->hw_value_short;
 
        cs->tx_length = cpu_to_le16(frag_len);
 
-       cs_set_control(mac, cs, hdr, control->flags);
+       cs_set_control(mac, cs, hdr, info->flags);
 
        packet_length = frag_len + sizeof(struct zd_ctrlset) + 10;
        ZD_ASSERT(packet_length <= 0xffff);
@@ -579,24 +515,21 @@ static int fill_ctrlset(struct zd_mac *mac,
  * control block of the skbuff will be initialized. If necessary the incoming
  * mac80211 queues will be stopped.
  */
-static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
-                    struct ieee80211_tx_control *control)
+static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct zd_mac *mac = zd_hw_mac(hw);
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        int r;
 
-       r = fill_ctrlset(mac, skb, control);
+       r = fill_ctrlset(mac, skb);
        if (r)
                return r;
 
-       r = init_tx_skb_control_block(skb, hw, control);
-       if (r)
-               return r;
+       info->driver_data[0] = hw;
+
        r = zd_usb_tx(&mac->chip.usb, skb);
-       if (r) {
-               clear_tx_skb_control_block(skb);
+       if (r)
                return r;
-       }
        return 0;
 }
 
@@ -634,13 +567,8 @@ static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr,
                tx_hdr = (struct ieee80211_hdr *)skb->data;
                if (likely(!compare_ether_addr(tx_hdr->addr2, rx_hdr->addr1)))
                {
-                       struct ieee80211_tx_status status;
-
-                       memset(&status, 0, sizeof(status));
-                       status.flags = IEEE80211_TX_STATUS_ACK;
-                       status.ack_signal = stats->ssi;
                        __skb_unlink(skb, q);
-                       tx_status(hw, skb, &status, 1);
+                       tx_status(hw, skb, IEEE80211_TX_STAT_ACK, stats->signal, 1);
                        goto out;
                }
        }
@@ -691,8 +619,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
 
        stats.freq = zd_channels[_zd_chip_get_channel(&mac->chip) - 1].center_freq;
        stats.band = IEEE80211_BAND_2GHZ;
-       stats.ssi = status->signal_strength;
-       stats.signal = zd_rx_qual_percent(buffer,
+       stats.signal = status->signal_strength;
+       stats.qual = zd_rx_qual_percent(buffer,
                                          length - sizeof(struct rx_status),
                                          status);
 
@@ -751,6 +679,7 @@ static int zd_op_add_interface(struct ieee80211_hw *hw,
        case IEEE80211_IF_TYPE_MNTR:
        case IEEE80211_IF_TYPE_MESH_POINT:
        case IEEE80211_IF_TYPE_STA:
+       case IEEE80211_IF_TYPE_IBSS:
                mac->type = conf->type;
                break;
        default:
@@ -781,7 +710,8 @@ static int zd_op_config_interface(struct ieee80211_hw *hw,
        struct zd_mac *mac = zd_hw_mac(hw);
        int associated;
 
-       if (mac->type == IEEE80211_IF_TYPE_MESH_POINT) {
+       if (mac->type == IEEE80211_IF_TYPE_MESH_POINT ||
+           mac->type == IEEE80211_IF_TYPE_IBSS) {
                associated = true;
                if (conf->beacon) {
                        zd_mac_config_beacon(hw, conf->beacon);
@@ -941,6 +871,17 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw,
        }
 }
 
+static int zd_op_beacon_update(struct ieee80211_hw *hw,
+                              struct sk_buff *skb)
+{
+       struct zd_mac *mac = zd_hw_mac(hw);
+       zd_mac_config_beacon(hw, skb);
+       kfree_skb(skb);
+       zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS |
+                                       hw->conf.beacon_int);
+       return 0;
+}
+
 static const struct ieee80211_ops zd_ops = {
        .tx                     = zd_op_tx,
        .start                  = zd_op_start,
@@ -951,6 +892,7 @@ static const struct ieee80211_ops zd_ops = {
        .config_interface       = zd_op_config_interface,
        .configure_filter       = zd_op_configure_filter,
        .bss_info_changed       = zd_op_bss_info_changed,
+       .beacon_update          = zd_op_beacon_update,
 };
 
 struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
@@ -982,10 +924,10 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
        hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band;
 
        hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
-                   IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
-       hw->max_rssi = 100;
-       hw->max_signal = 100;
+                   IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
+                   IEEE80211_HW_SIGNAL_DB;
 
+       hw->max_signal = 100;
        hw->queues = 1;
        hw->extra_tx_headroom = sizeof(struct zd_ctrlset);
 
index 71170244d2c96ce925e64c3c9c73be1534fd608a..18c1d56d3dd7faf7d9c8285ce0a1e1ee7da5e4af 100644 (file)
@@ -149,22 +149,6 @@ struct housekeeping {
        struct delayed_work link_led_work;
 };
 
-/**
- * struct zd_tx_skb_control_block - control block for tx skbuffs
- * @control: &struct ieee80211_tx_control pointer
- * @context: context pointer
- *
- * This structure is used to fill the cb field in an &sk_buff to transmit.
- * The control field is NULL, if there is no requirement from the mac80211
- * stack to report about the packet ACK. This is the case if the flag
- * IEEE80211_TXCTL_NO_ACK is not set in &struct ieee80211_tx_control.
- */
-struct zd_tx_skb_control_block {
-       struct ieee80211_tx_control *control;
-       struct ieee80211_hw *hw;
-       void *context;
-};
-
 #define ZD_MAC_STATS_BUFFER_SIZE 16
 
 #define ZD_MAC_MAX_ACK_WAITERS 10
index 8941f5eb96c2774cb6a6e2004d237c66eaab7bc7..1ccff240bf973c917c5c3e8a2cbb6aae8a8bd8f5 100644 (file)
@@ -169,10 +169,11 @@ static int upload_code(struct usb_device *udev,
        if (flags & REBOOT) {
                u8 ret;
 
+               /* Use "DMA-aware" buffer. */
                r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
                        USB_REQ_FIRMWARE_CONFIRM,
                        USB_DIR_IN | USB_TYPE_VENDOR,
-                       0, 0, &ret, sizeof(ret), 5000 /* ms */);
+                       0, 0, p, sizeof(ret), 5000 /* ms */);
                if (r != sizeof(ret)) {
                        dev_err(&udev->dev,
                                "control request firmeware confirmation failed."
@@ -181,6 +182,7 @@ static int upload_code(struct usb_device *udev,
                                r = -ENODEV;
                        goto error;
                }
+               ret = p[0];
                if (ret & 0x80) {
                        dev_err(&udev->dev,
                                "Internal error while downloading."
@@ -312,22 +314,31 @@ int zd_usb_read_fw(struct zd_usb *usb, zd_addr_t addr, u8 *data, u16 len)
 {
        int r;
        struct usb_device *udev = zd_usb_to_usbdev(usb);
+       u8 *buf;
 
+       /* Use "DMA-aware" buffer. */
+       buf = kmalloc(len, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
        r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
                USB_REQ_FIRMWARE_READ_DATA, USB_DIR_IN | 0x40, addr, 0,
-               data, len, 5000);
+               buf, len, 5000);
        if (r < 0) {
                dev_err(&udev->dev,
                        "read over firmware interface failed: %d\n", r);
-               return r;
+               goto exit;
        } else if (r != len) {
                dev_err(&udev->dev,
                        "incomplete read over firmware interface: %d/%d\n",
                        r, len);
-               return -EIO;
+               r = -EIO;
+               goto exit;
        }
-
-       return 0;
+       r = 0;
+       memcpy(data, buf, len);
+exit:
+       kfree(buf);
+       return r;
 }
 
 #define urb_dev(urb) (&(urb)->dev->dev)
@@ -869,7 +880,7 @@ static void tx_urb_complete(struct urb *urb)
 {
        int r;
        struct sk_buff *skb;
-       struct zd_tx_skb_control_block *cb;
+       struct ieee80211_tx_info *info;
        struct zd_usb *usb;
 
        switch (urb->status) {
@@ -893,8 +904,8 @@ free_urb:
         * grab 'usb' pointer before handing off the skb (since
         * it might be freed by zd_mac_tx_to_dev or mac80211)
         */
-       cb = (struct zd_tx_skb_control_block *)skb->cb;
-       usb = &zd_hw_mac(cb->hw)->chip.usb;
+       info = IEEE80211_SKB_CB(skb);
+       usb = &zd_hw_mac(info->driver_data[0])->chip.usb;
        zd_mac_tx_to_dev(skb, urb->status);
        free_tx_urb(usb, urb);
        tx_dec_submitted_urbs(usb);
index 57c4ccfab1ee79f28790c3fe7b8a48c1d0baa78e..f883dcfffe0613d966f3e8de5d8f1b2159ae4389 100644 (file)
@@ -510,17 +510,15 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
        sprom_do_read(bus, buf);
        err = sprom_check_crc(buf, bus->sprom_size);
        if (err) {
-               /* check for rev 4 sprom - has special signature */
-               if (buf[32] == 0x5372) {
-                       kfree(buf);
-                       buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
-                                     GFP_KERNEL);
-                       if (!buf)
-                               goto out;
-                       bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
-                       sprom_do_read(bus, buf);
-                       err = sprom_check_crc(buf, bus->sprom_size);
-               }
+               /* try for a 440 byte SPROM - revision 4 and higher */
+               kfree(buf);
+               buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
+                             GFP_KERNEL);
+               if (!buf)
+                       goto out;
+               bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
+               sprom_do_read(bus, buf);
+               err = sprom_check_crc(buf, bus->sprom_size);
                if (err)
                        ssb_printk(KERN_WARNING PFX "WARNING: Invalid"
                                   " SPROM CRC (corrupt SPROM)\n");
diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h
new file mode 100644 (file)
index 0000000..9b64b6d
--- /dev/null
@@ -0,0 +1,6 @@
+#define PHY_BRCM_WIRESPEED_ENABLE      0x00000001
+#define PHY_BRCM_AUTO_PWRDWN_ENABLE    0x00000002
+#define PHY_BRCM_APD_CLK125_ENABLE     0x00000004
+#define PHY_BRCM_STD_IBND_DISABLE      0x00000008
+#define PHY_BRCM_EXT_IBND_RX_ENABLE    0x00000010
+#define PHY_BRCM_EXT_IBND_TX_ENABLE    0x00000020
index 0b5e03eae6d25556b8ebb7209bb1af3033d7ffe1..9300f37cd7e8429104b27024dc00df6b657e526c 100644 (file)
@@ -306,20 +306,32 @@ struct ieee80211_ht_addt_info {
 #define IEEE80211_HT_CAP_SGI_40                        0x0040
 #define IEEE80211_HT_CAP_DELAY_BA              0x0400
 #define IEEE80211_HT_CAP_MAX_AMSDU             0x0800
+/* 802.11n HT capability AMPDU settings */
 #define IEEE80211_HT_CAP_AMPDU_FACTOR          0x03
 #define IEEE80211_HT_CAP_AMPDU_DENSITY         0x1C
+/* 802.11n HT capability MSC set */
+#define IEEE80211_SUPP_MCS_SET_UEQM            4
+#define IEEE80211_HT_CAP_MAX_STREAMS           4
+#define IEEE80211_SUPP_MCS_SET_LEN             10
+/* maximum streams the spec allows */
+#define IEEE80211_HT_CAP_MCS_TX_DEFINED                0x01
+#define IEEE80211_HT_CAP_MCS_TX_RX_DIFF                0x02
+#define IEEE80211_HT_CAP_MCS_TX_STREAMS                0x0C
+#define IEEE80211_HT_CAP_MCS_TX_UEQM           0x10
 /* 802.11n HT IE masks */
 #define IEEE80211_HT_IE_CHA_SEC_OFFSET         0x03
+#define IEEE80211_HT_IE_CHA_SEC_ABOVE          0x01
+#define IEEE80211_HT_IE_CHA_SEC_BELOW          0x03
 #define IEEE80211_HT_IE_CHA_WIDTH              0x04
 #define IEEE80211_HT_IE_HT_PROTECTION          0x0003
 #define IEEE80211_HT_IE_NON_GF_STA_PRSNT       0x0004
 #define IEEE80211_HT_IE_NON_HT_STA_PRSNT       0x0010
 
 /* MIMO Power Save Modes */
-#define WLAN_HT_CAP_MIMO_PS_STATIC         0
-#define WLAN_HT_CAP_MIMO_PS_DYNAMIC        1
-#define WLAN_HT_CAP_MIMO_PS_INVALID        2
-#define WLAN_HT_CAP_MIMO_PS_DISABLED       3
+#define WLAN_HT_CAP_MIMO_PS_STATIC     0
+#define WLAN_HT_CAP_MIMO_PS_DYNAMIC    1
+#define WLAN_HT_CAP_MIMO_PS_INVALID    2
+#define WLAN_HT_CAP_MIMO_PS_DISABLED   3
 
 /* Authentication algorithms */
 #define WLAN_AUTH_OPEN 0
@@ -552,16 +564,17 @@ enum ieee80211_back_parties {
  */
 static inline u8 *ieee80211_get_SA(struct ieee80211_hdr *hdr)
 {
-       u8 *raw = (u8 *) hdr;
-       u8 tofrom = (*(raw+1)) & 3; /* get the TODS and FROMDS bits */
-
-       switch (tofrom) {
-               case 2:
-                       return hdr->addr3;
-               case 3:
-                       return hdr->addr4;
+       __le16 fc = hdr->frame_control;
+       fc &= cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS);
+
+       switch (fc) {
+       case __constant_cpu_to_le16(IEEE80211_FCTL_FROMDS):
+               return hdr->addr3;
+       case __constant_cpu_to_le16(IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS):
+               return hdr->addr4;
+       default:
+               return hdr->addr2;
        }
-       return hdr->addr2;
 }
 
 /**
@@ -577,12 +590,13 @@ static inline u8 *ieee80211_get_SA(struct ieee80211_hdr *hdr)
  */
 static inline u8 *ieee80211_get_DA(struct ieee80211_hdr *hdr)
 {
-       u8 *raw = (u8 *) hdr;
-       u8 to_ds = (*(raw+1)) & 1; /* get the TODS bit */
+       __le16 fc = hdr->frame_control;
+       fc &= cpu_to_le16(IEEE80211_FCTL_TODS);
 
-       if (to_ds)
+       if (fc)
                return hdr->addr3;
-       return hdr->addr1;
+       else
+               return hdr->addr1;
 }
 
 /**
@@ -595,8 +609,8 @@ static inline u8 *ieee80211_get_DA(struct ieee80211_hdr *hdr)
  */
 static inline int ieee80211_get_morefrag(struct ieee80211_hdr *hdr)
 {
-       return (le16_to_cpu(hdr->frame_control) &
-               IEEE80211_FCTL_MOREFRAGS) != 0;
+       __le16 fc = hdr->frame_control;
+       return !!(fc & cpu_to_le16(IEEE80211_FCTL_MOREFRAGS));
 }
 
 #endif /* IEEE80211_H */
index 0a383ac083cb57c29db2ca0e55024d509d6b7c39..759bc043dc65a9fbf5d3646671efd21b08607551 100644 (file)
@@ -81,6 +81,7 @@ enum ctattr_protoinfo {
        CTA_PROTOINFO_UNSPEC,
        CTA_PROTOINFO_TCP,
        CTA_PROTOINFO_DCCP,
+       CTA_PROTOINFO_SCTP,
        __CTA_PROTOINFO_MAX
 };
 #define CTA_PROTOINFO_MAX (__CTA_PROTOINFO_MAX - 1)
@@ -103,6 +104,15 @@ enum ctattr_protoinfo_dccp {
 };
 #define CTA_PROTOINFO_DCCP_MAX (__CTA_PROTOINFO_DCCP_MAX - 1)
 
+enum ctattr_protoinfo_sctp {
+       CTA_PROTOINFO_SCTP_UNSPEC,
+       CTA_PROTOINFO_SCTP_STATE,
+       CTA_PROTOINFO_SCTP_VTAG_ORIGINAL,
+       CTA_PROTOINFO_SCTP_VTAG_REPLY,
+       __CTA_PROTOINFO_SCTP_MAX
+};
+#define CTA_PROTOINFO_SCTP_MAX (__CTA_PROTOINFO_SCTP_MAX - 1)
+
 enum ctattr_counters {
        CTA_COUNTERS_UNSPEC,
        CTA_COUNTERS_PACKETS,           /* old 64bit counters */
diff --git a/include/linux/netfilter_bridge/ebt_ip6.h b/include/linux/netfilter_bridge/ebt_ip6.h
new file mode 100644 (file)
index 0000000..2273c3a
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *  ebt_ip6
+ *
+ *     Authors:
+ * Kuo-Lang Tseng <kuo-lang.tseng@intel.com>
+ * Manohar Castelino <manohar.r.castelino@intel.com>
+ *
+ *  Jan 11, 2008
+ *
+ */
+
+#ifndef __LINUX_BRIDGE_EBT_IP6_H
+#define __LINUX_BRIDGE_EBT_IP6_H
+
+#define EBT_IP6_SOURCE 0x01
+#define EBT_IP6_DEST 0x02
+#define EBT_IP6_TCLASS 0x04
+#define EBT_IP6_PROTO 0x08
+#define EBT_IP6_SPORT 0x10
+#define EBT_IP6_DPORT 0x20
+#define EBT_IP6_MASK (EBT_IP6_SOURCE | EBT_IP6_DEST | EBT_IP6_TCLASS |\
+                     EBT_IP6_PROTO | EBT_IP6_SPORT | EBT_IP6_DPORT)
+#define EBT_IP6_MATCH "ip6"
+
+/* the same values are used for the invflags */
+struct ebt_ip6_info
+{
+       struct in6_addr saddr;
+       struct in6_addr daddr;
+       struct in6_addr smsk;
+       struct in6_addr dmsk;
+       uint8_t  tclass;
+       uint8_t  protocol;
+       uint8_t  bitmask;
+       uint8_t  invflags;
+       uint16_t sport[2];
+       uint16_t dport[2];
+};
+
+#endif
index 96e231ae75548a3188b77b5708567cb99c75e0e4..b76e653157e56db9d3d2329b2294465736d9de68 100644 (file)
@@ -4,7 +4,8 @@
 #define EBT_LOG_IP 0x01 /* if the frame is made by ip, log the ip information */
 #define EBT_LOG_ARP 0x02
 #define EBT_LOG_NFLOG 0x04
-#define EBT_LOG_MASK (EBT_LOG_IP | EBT_LOG_ARP)
+#define EBT_LOG_IP6 0x08
+#define EBT_LOG_MASK (EBT_LOG_IP | EBT_LOG_ARP | EBT_LOG_IP6)
 #define EBT_LOG_PREFIX_SIZE 30
 #define EBT_LOG_WATCHER "log"
 
index 650318b0c405b2669fcfe413eb7a73f9b4628240..29c7727ff0e82faa06a636d10ff64eab8c5af2ca 100644 (file)
@@ -60,6 +60,7 @@ enum nf_ip_hook_priorities {
        NF_IP_PRI_MANGLE = -150,
        NF_IP_PRI_NAT_DST = -100,
        NF_IP_PRI_FILTER = 0,
+       NF_IP_PRI_SECURITY = 50,
        NF_IP_PRI_NAT_SRC = 100,
        NF_IP_PRI_SELINUX_LAST = 225,
        NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,
index 3475a65dae9b52d33683b140d43dd6aa902eb0cf..fd50988b83ec09979f2497d2109ed7a9ba20969b 100644 (file)
@@ -64,6 +64,7 @@ enum nf_ip6_hook_priorities {
        NF_IP6_PRI_MANGLE = -150,
        NF_IP6_PRI_NAT_DST = -100,
        NF_IP6_PRI_FILTER = 0,
+       NF_IP6_PRI_SECURITY = 50,
        NF_IP6_PRI_NAT_SRC = 100,
        NF_IP6_PRI_SELINUX_LAST = 225,
        NF_IP6_PRI_LAST = INT_MAX,
index bec1062a25a1e83146e8478f2bb8443a05fcf288..9ff1b54908f3a2260a01bea28b81ab811713fdd5 100644 (file)
@@ -193,7 +193,7 @@ extern int netlink_unregister_notifier(struct notifier_block *nb);
 
 /* finegrained unicast helpers: */
 struct sock *netlink_getsockbyfilp(struct file *filp);
-int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock,
+int netlink_attachskb(struct sock *sk, struct sk_buff *skb,
                      long *timeo, struct sock *ssk);
 void netlink_detachskb(struct sock *sk, struct sk_buff *skb);
 int netlink_sendskb(struct sock *sk, struct sk_buff *skb);
index 9b940e64417956006015b0d321b8690802686fac..1bbb346066ddb99272c92a587a881629be0c6e41 100644 (file)
 #define PCI_DEVICE_ID_TIGON3_5787M     0x1693
 #define PCI_DEVICE_ID_TIGON3_5782      0x1696
 #define PCI_DEVICE_ID_TIGON3_5784      0x1698
+#define PCI_DEVICE_ID_TIGON3_5785      0x1699
 #define PCI_DEVICE_ID_TIGON3_5786      0x169a
 #define PCI_DEVICE_ID_TIGON3_5787      0x169b
 #define PCI_DEVICE_ID_TIGON3_5788      0x169c
index 18e62e3d406fe86a83e03a8a34257b54fd069ba7..9881295f38570b8c4b6a98d56f517b564a97dc7d 100644 (file)
@@ -296,10 +296,9 @@ struct tcp_sock {
        u32     rcv_ssthresh;   /* Current window clamp                 */
 
        u32     frto_highmark;  /* snd_nxt when RTO occurred */
-       u8      reordering;     /* Packet reordering metric.            */
+       u16     advmss;         /* Advertised MSS                       */
        u8      frto_counter;   /* Number of new acks after RTO */
        u8      nonagle;        /* Disable Nagle algorithm?             */
-       u8      keepalive_probes; /* num of allowed keep alive probes   */
 
 /* RTT measurement */
        u32     srtt;           /* smoothed round trip time << 3        */
@@ -310,6 +309,10 @@ struct tcp_sock {
 
        u32     packets_out;    /* Packets which are "in flight"        */
        u32     retrans_out;    /* Retransmitted packets out            */
+
+       u16     urg_data;       /* Saved octet of OOB data and control flags */
+       u8      urg_mode;       /* In urgent mode               */
+       u8      ecn_flags;      /* ECN status bits.                     */
 /*
  *      Options received (usually on last packet, some only on SYN packets).
  */
@@ -325,13 +328,24 @@ struct tcp_sock {
        u32     snd_cwnd_used;
        u32     snd_cwnd_stamp;
 
-       struct sk_buff_head     out_of_order_queue; /* Out of order segments go here */
-
        u32     rcv_wnd;        /* Current receiver window              */
        u32     write_seq;      /* Tail(+1) of data held in tcp send buffer */
        u32     pushed_seq;     /* Last pushed seq, required to talk to windows */
+       u32     lost_out;       /* Lost packets                 */
+       u32     sacked_out;     /* SACK'd packets                       */
+       u32     fackets_out;    /* FACK'd packets                       */
+       u32     tso_deferred;
+       u32     bytes_acked;    /* Appropriate Byte Counting - RFC3465 */
 
-/*     SACKs data      */
+       /* from STCP, retrans queue hinting */
+       struct sk_buff* lost_skb_hint;
+       struct sk_buff *scoreboard_skb_hint;
+       struct sk_buff *retransmit_skb_hint;
+       struct sk_buff *forward_skb_hint;
+
+       struct sk_buff_head     out_of_order_queue; /* Out of order segments go here */
+
+       /* SACKs data, these 2 need to be together (see tcp_build_and_update_options) */
        struct tcp_sack_block duplicate_sack[1]; /* D-SACK block */
        struct tcp_sack_block selective_acks[4]; /* The SACKS themselves*/
 
@@ -342,23 +356,14 @@ struct tcp_sock {
                                         * sacked_out > 0)
                                         */
 
-       /* from STCP, retrans queue hinting */
-       struct sk_buff* lost_skb_hint;
-
-       struct sk_buff *scoreboard_skb_hint;
-       struct sk_buff *retransmit_skb_hint;
-       struct sk_buff *forward_skb_hint;
-
        int     lost_cnt_hint;
        int     retransmit_cnt_hint;
 
        u32     lost_retrans_low;       /* Sent seq after any rxmit (lowest) */
 
-       u16     advmss;         /* Advertised MSS                       */
+       u8      reordering;     /* Packet reordering metric.            */
+       u8      keepalive_probes; /* num of allowed keep alive probes   */
        u32     prior_ssthresh; /* ssthresh saved at recovery start     */
-       u32     lost_out;       /* Lost packets                 */
-       u32     sacked_out;     /* SACK'd packets                       */
-       u32     fackets_out;    /* FACK'd packets                       */
        u32     high_seq;       /* snd_nxt at onset of congestion       */
 
        u32     retrans_stamp;  /* Timestamp of the last retransmit,
@@ -366,25 +371,18 @@ struct tcp_sock {
                                 * the first SYN. */
        u32     undo_marker;    /* tracking retrans started here. */
        int     undo_retrans;   /* number of undoable retransmissions. */
+       u32     total_retrans;  /* Total retransmits for entire connection */
+
        u32     urg_seq;        /* Seq of received urgent pointer */
-       u16     urg_data;       /* Saved octet of OOB data and control flags */
-       u8      urg_mode;       /* In urgent mode               */
-       u8      ecn_flags;      /* ECN status bits.                     */
        u32     snd_up;         /* Urgent pointer               */
 
-       u32     total_retrans;  /* Total retransmits for entire connection */
-       u32     bytes_acked;    /* Appropriate Byte Counting - RFC3465 */
-
        unsigned int            keepalive_time;   /* time before keep alive takes place */
        unsigned int            keepalive_intvl;  /* time interval between keep alive probes */
-       int                     linger2;
 
        struct tcp_deferred_accept_info defer_tcp_accept;
 
        unsigned long last_synq_overflow; 
 
-       u32     tso_deferred;
-
 /* Receiver side RTT estimation */
        struct {
                u32     rtt;
@@ -412,6 +410,8 @@ struct tcp_sock {
 /* TCP MD5 Signagure Option information */
        struct tcp_md5sig_info  *md5sig_info;
 #endif
+
+       int                     linger2;
 };
 
 static inline struct tcp_sock *tcp_sk(const struct sock *sk)
index b0c916d1f37508f817ef52dba253d3f939391fb0..2bc6fa4adeb5e2d2076b456ad4cfd6943952cef9 100644 (file)
@@ -2,7 +2,7 @@
  * include/linux/tipc_config.h: Include file for TIPC configuration interface
  * 
  * Copyright (c) 2003-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2007, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #define  TIPC_CMD_SET_MAX_SLAVES    0x800A    /* tx unsigned, rx none */
 #define  TIPC_CMD_SET_NETID         0x800B    /* tx unsigned, rx none */
 
+/*
+ * Reserved commands:
+ * May not be issued by any process.
+ * Used internally by TIPC.
+ */
+
+#define  TIPC_CMD_NOT_NET_ADMIN     0xC001    /* tx none, rx none */
+
 /*
  * TLV types defined for TIPC
  */
index 3add87465b1fc671a8ebf2280fd1868d3c7315cc..e0aa39612eba2ff30d5f6f3d5347485d8275efee 100644 (file)
@@ -522,7 +522,7 @@ extern int wanrouter_proc_init(void);
 extern void wanrouter_proc_cleanup(void);
 extern int wanrouter_proc_add(struct wan_device *wandev);
 extern int wanrouter_proc_delete(struct wan_device *wandev);
-extern int wanrouter_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+extern long wanrouter_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 
 /* Public Data */
 /* list of registered devices */
index 0a9b5b41ed6766cd5cb95402ebb4cfbd68990f66..4a95a0e5eeca20753246406664254b67d949d7ad 100644 (file)
 #define IW_ENCODE_ALG_WEP      1
 #define IW_ENCODE_ALG_TKIP     2
 #define IW_ENCODE_ALG_CCMP     3
+#define IW_ENCODE_ALG_PMK      4
 /* struct iw_encode_ext ->ext_flags */
 #define IW_ENCODE_EXT_TX_SEQ_VALID     0x00000001
 #define IW_ENCODE_EXT_RX_SEQ_VALID     0x00000002
 #define IW_ENC_CAPA_WPA2       0x00000002
 #define IW_ENC_CAPA_CIPHER_TKIP        0x00000004
 #define IW_ENC_CAPA_CIPHER_CCMP        0x00000008
+#define IW_ENC_CAPA_4WAY_HANDSHAKE     0x00000010
 
 /* Event capability macros - in (struct iw_range *)->event_capa
  * Because we have more than 32 possible events, we use an array of
index 529816bfbc52a3d5c54f1ef72cb7fa29a8b46f19..b31399e1fd83a3c3230d1b2c516c359675ef0f36 100644 (file)
@@ -1262,9 +1262,6 @@ extern int ieee80211_set_encryption(struct ieee80211_device *ieee);
 /* ieee80211_tx.c */
 extern int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev);
 extern void ieee80211_txb_free(struct ieee80211_txb *);
-extern int ieee80211_tx_frame(struct ieee80211_device *ieee,
-                             struct ieee80211_hdr *frame, int hdr_len,
-                             int total_len, int encrypt_mpdu);
 
 /* ieee80211_rx.c */
 extern void ieee80211_rx_any(struct ieee80211_device *ieee,
@@ -1312,14 +1309,6 @@ extern int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
 extern int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
                                      struct iw_request_info *info,
                                      union iwreq_data *wrqu, char *extra);
-extern int ieee80211_wx_set_auth(struct net_device *dev,
-                                struct iw_request_info *info,
-                                union iwreq_data *wrqu,
-                                char *extra);
-extern int ieee80211_wx_get_auth(struct net_device *dev,
-                                struct iw_request_info *info,
-                                union iwreq_data *wrqu,
-                                char *extra);
 
 static inline void ieee80211_increment_scans(struct ieee80211_device *ieee)
 {
index 6512d85f11b39775609cc83cf9d43e09002d8d8d..3780592ebe8e7b0dc767c0becbd6e36beea855a8 100644 (file)
@@ -19,7 +19,6 @@
 struct ip6_tnl {
        struct ip6_tnl *next;   /* next tunnel in list */
        struct net_device *dev; /* virtual device associated with tunnel */
-       struct net_device_stats stat;   /* statistics for tunnel device */
        int recursion;          /* depth of hard_start_xmit recursion */
        struct ip6_tnl_parm parms;      /* tunnel configuration parameters */
        struct flowi fl;        /* flowi template for xmit */
index 633ed4def8e3ab2fb27d3c0b964df23b0438d9e2..a85bda64b8528ce2f7b8c4416ba10e83f654b9af 100644 (file)
@@ -11,7 +11,6 @@ struct ip_tunnel
 {
        struct ip_tunnel        *next;
        struct net_device       *dev;
-       struct net_device_stats stat;
 
        int                     recursion;      /* Depth of hard_start_xmit recursion */
        int                     err_count;      /* Number of arrived ICMP errors */
index dae3f9ec11549b240ae07be19dc4f58a2389ce62..1196de85f8db701a919149bcebb817c4670606f5 100644 (file)
@@ -97,6 +97,18 @@ struct ieee80211_ht_bss_info {
        u8 bss_op_mode; /* use IEEE80211_HT_IE_ */
 };
 
+/**
+ * enum ieee80211_max_queues - maximum number of queues
+ *
+ * @IEEE80211_MAX_QUEUES: Maximum number of regular device queues.
+ * @IEEE80211_MAX_AMPDU_QUEUES: Maximum number of queues usable
+ *     for A-MPDU operation.
+ */
+enum ieee80211_max_queues {
+       IEEE80211_MAX_QUEUES =          16,
+       IEEE80211_MAX_AMPDU_QUEUES =    16,
+};
+
 /**
  * struct ieee80211_tx_queue_params - transmit queue configuration
  *
@@ -117,58 +129,18 @@ struct ieee80211_tx_queue_params {
 };
 
 /**
- * struct ieee80211_tx_queue_stats_data - transmit queue statistics
+ * struct ieee80211_tx_queue_stats - transmit queue statistics
  *
  * @len: number of packets in queue
  * @limit: queue length limit
  * @count: number of frames sent
  */
-struct ieee80211_tx_queue_stats_data {
+struct ieee80211_tx_queue_stats {
        unsigned int len;
        unsigned int limit;
        unsigned int count;
 };
 
-/**
- * enum ieee80211_tx_queue - transmit queue number
- *
- * These constants are used with some callbacks that take a
- * queue number to set parameters for a queue.
- *
- * @IEEE80211_TX_QUEUE_DATA0: data queue 0
- * @IEEE80211_TX_QUEUE_DATA1: data queue 1
- * @IEEE80211_TX_QUEUE_DATA2: data queue 2
- * @IEEE80211_TX_QUEUE_DATA3: data queue 3
- * @IEEE80211_TX_QUEUE_DATA4: data queue 4
- * @IEEE80211_TX_QUEUE_SVP: ??
- * @NUM_TX_DATA_QUEUES: number of data queues
- * @IEEE80211_TX_QUEUE_AFTER_BEACON: transmit queue for frames to be
- *     sent after a beacon
- * @IEEE80211_TX_QUEUE_BEACON: transmit queue for beacon frames
- * @NUM_TX_DATA_QUEUES_AMPDU: adding more queues for A-MPDU
- */
-enum ieee80211_tx_queue {
-       IEEE80211_TX_QUEUE_DATA0,
-       IEEE80211_TX_QUEUE_DATA1,
-       IEEE80211_TX_QUEUE_DATA2,
-       IEEE80211_TX_QUEUE_DATA3,
-       IEEE80211_TX_QUEUE_DATA4,
-       IEEE80211_TX_QUEUE_SVP,
-
-       NUM_TX_DATA_QUEUES,
-
-/* due to stupidity in the sub-ioctl userspace interface, the items in
- * this struct need to have fixed values. As soon as it is removed, we can
- * fix these entries. */
-       IEEE80211_TX_QUEUE_AFTER_BEACON = 6,
-       IEEE80211_TX_QUEUE_BEACON = 7,
-       NUM_TX_DATA_QUEUES_AMPDU = 16
-};
-
-struct ieee80211_tx_queue_stats {
-       struct ieee80211_tx_queue_stats_data data[NUM_TX_DATA_QUEUES_AMPDU];
-};
-
 struct ieee80211_low_level_stats {
        unsigned int dot11ACKFailureCount;
        unsigned int dot11RTSFailureCount;
@@ -229,91 +201,128 @@ struct ieee80211_bss_conf {
 };
 
 /**
- * enum mac80211_tx_control_flags - flags to describe Tx configuration for
- *                                 the Tx frame
- *
- * These flags are used with the @flags member of &ieee80211_tx_control
- *
- * @IEEE80211_TXCTL_REQ_TX_STATUS: request TX status callback for this frame.
- * @IEEE80211_TXCTL_DO_NOT_ENCRYPT: send this frame without encryption;
- *                                 e.g., for EAPOL frame
- * @IEEE80211_TXCTL_USE_RTS_CTS: use RTS-CTS before sending frame
- * @IEEE80211_TXCTL_USE_CTS_PROTECT: use CTS protection for the frame (e.g.,
- *                                  for combined 802.11g / 802.11b networks)
- * @IEEE80211_TXCTL_NO_ACK: tell the low level not to wait for an ack
- * @IEEE80211_TXCTL_RATE_CTRL_PROBE
- * @EEE80211_TXCTL_CLEAR_PS_FILT: clear powersave filter
- *                                 for destination station
- * @IEEE80211_TXCTL_REQUEUE:
- * @IEEE80211_TXCTL_FIRST_FRAGMENT: this is a first fragment of the frame
- * @IEEE80211_TXCTL_LONG_RETRY_LIMIT: this frame should be send using the
- *                                   through set_retry_limit configured long
- *                                   retry value
- * @IEEE80211_TXCTL_EAPOL_FRAME: internal to mac80211
- * @IEEE80211_TXCTL_SEND_AFTER_DTIM: send this frame after DTIM beacon
- * @IEEE80211_TXCTL_AMPDU: this frame should be sent as part of an A-MPDU
- * @IEEE80211_TXCTL_OFDM_HT: this frame can be sent in HT OFDM rates. number
- *                          of streams when this flag is on can be extracted
- *                          from antenna_sel_tx, so if 1 antenna is marked
- *                          use SISO, 2 antennas marked use MIMO, n antennas
- *                          marked use MIMO_n.
- * @IEEE80211_TXCTL_GREEN_FIELD: use green field protection for this frame
- * @IEEE80211_TXCTL_40_MHZ_WIDTH: send this frame using 40 Mhz channel width
- * @IEEE80211_TXCTL_DUP_DATA: duplicate data frame on both 20 Mhz channels
- * @IEEE80211_TXCTL_SHORT_GI: send this frame using short guard interval
+ * enum mac80211_tx_flags - flags to transmission information/status
+ *
+ * These flags are used with the @flags member of &ieee80211_tx_info
+ *
+ * @IEEE80211_TX_CTL_REQ_TX_STATUS: request TX status callback for this frame.
+ * @IEEE80211_TX_CTL_DO_NOT_ENCRYPT: send this frame without encryption;
+ *     e.g., for EAPOL frame
+ * @IEEE80211_TX_CTL_USE_RTS_CTS: use RTS-CTS before sending frame
+ * @IEEE80211_TX_CTL_USE_CTS_PROTECT: use CTS protection for the frame (e.g.,
+ *     for combined 802.11g / 802.11b networks)
+ * @IEEE80211_TX_CTL_NO_ACK: tell the low level not to wait for an ack
+ * @IEEE80211_TX_CTL_RATE_CTRL_PROBE
+ * @IEEE80211_TX_CTL_CLEAR_PS_FILT: clear powersave filter for destination
+ *     station
+ * @IEEE80211_TX_CTL_REQUEUE:
+ * @IEEE80211_TX_CTL_FIRST_FRAGMENT: this is a first fragment of the frame
+ * @IEEE80211_TX_CTL_LONG_RETRY_LIMIT: this frame should be send using the
+ *     through set_retry_limit configured long retry value
+ * @IEEE80211_TX_CTL_EAPOL_FRAME: internal to mac80211
+ * @IEEE80211_TX_CTL_SEND_AFTER_DTIM: send this frame after DTIM beacon
+ * @IEEE80211_TX_CTL_AMPDU: this frame should be sent as part of an A-MPDU
+ * @IEEE80211_TX_CTL_OFDM_HT: this frame can be sent in HT OFDM rates. number
+ *     of streams when this flag is on can be extracted from antenna_sel_tx,
+ *     so if 1 antenna is marked use SISO, 2 antennas marked use MIMO, n
+ *     antennas marked use MIMO_n.
+ * @IEEE80211_TX_CTL_GREEN_FIELD: use green field protection for this frame
+ * @IEEE80211_TX_CTL_40_MHZ_WIDTH: send this frame using 40 Mhz channel width
+ * @IEEE80211_TX_CTL_DUP_DATA: duplicate data frame on both 20 Mhz channels
+ * @IEEE80211_TX_CTL_SHORT_GI: send this frame using short guard interval
+ * @IEEE80211_TX_STAT_TX_FILTERED: The frame was not transmitted
+ *     because the destination STA was in powersave mode.
+ * @IEEE80211_TX_STAT_ACK: Frame was acknowledged
+ * @IEEE80211_TX_STAT_AMPDU: The frame was aggregated, so status
+ *     is for the whole aggregation.
  */
 enum mac80211_tx_control_flags {
-       IEEE80211_TXCTL_REQ_TX_STATUS           = (1<<0),
-       IEEE80211_TXCTL_DO_NOT_ENCRYPT          = (1<<1),
-       IEEE80211_TXCTL_USE_RTS_CTS             = (1<<2),
-       IEEE80211_TXCTL_USE_CTS_PROTECT         = (1<<3),
-       IEEE80211_TXCTL_NO_ACK                  = (1<<4),
-       IEEE80211_TXCTL_RATE_CTRL_PROBE         = (1<<5),
-       IEEE80211_TXCTL_CLEAR_PS_FILT           = (1<<6),
-       IEEE80211_TXCTL_REQUEUE                 = (1<<7),
-       IEEE80211_TXCTL_FIRST_FRAGMENT          = (1<<8),
-       IEEE80211_TXCTL_SHORT_PREAMBLE          = (1<<9),
-       IEEE80211_TXCTL_LONG_RETRY_LIMIT        = (1<<10),
-       IEEE80211_TXCTL_EAPOL_FRAME             = (1<<11),
-       IEEE80211_TXCTL_SEND_AFTER_DTIM         = (1<<12),
-       IEEE80211_TXCTL_AMPDU                   = (1<<13),
-       IEEE80211_TXCTL_OFDM_HT                 = (1<<14),
-       IEEE80211_TXCTL_GREEN_FIELD             = (1<<15),
-       IEEE80211_TXCTL_40_MHZ_WIDTH            = (1<<16),
-       IEEE80211_TXCTL_DUP_DATA                = (1<<17),
-       IEEE80211_TXCTL_SHORT_GI                = (1<<18),
+       IEEE80211_TX_CTL_REQ_TX_STATUS          = BIT(0),
+       IEEE80211_TX_CTL_DO_NOT_ENCRYPT         = BIT(1),
+       IEEE80211_TX_CTL_USE_RTS_CTS            = BIT(2),
+       IEEE80211_TX_CTL_USE_CTS_PROTECT        = BIT(3),
+       IEEE80211_TX_CTL_NO_ACK                 = BIT(4),
+       IEEE80211_TX_CTL_RATE_CTRL_PROBE        = BIT(5),
+       IEEE80211_TX_CTL_CLEAR_PS_FILT          = BIT(6),
+       IEEE80211_TX_CTL_REQUEUE                = BIT(7),
+       IEEE80211_TX_CTL_FIRST_FRAGMENT         = BIT(8),
+       IEEE80211_TX_CTL_SHORT_PREAMBLE         = BIT(9),
+       IEEE80211_TX_CTL_LONG_RETRY_LIMIT       = BIT(10),
+       IEEE80211_TX_CTL_EAPOL_FRAME            = BIT(11),
+       IEEE80211_TX_CTL_SEND_AFTER_DTIM        = BIT(12),
+       IEEE80211_TX_CTL_AMPDU                  = BIT(13),
+       IEEE80211_TX_CTL_OFDM_HT                = BIT(14),
+       IEEE80211_TX_CTL_GREEN_FIELD            = BIT(15),
+       IEEE80211_TX_CTL_40_MHZ_WIDTH           = BIT(16),
+       IEEE80211_TX_CTL_DUP_DATA               = BIT(17),
+       IEEE80211_TX_CTL_SHORT_GI               = BIT(18),
+       IEEE80211_TX_CTL_INJECTED               = BIT(19),
+       IEEE80211_TX_STAT_TX_FILTERED           = BIT(20),
+       IEEE80211_TX_STAT_ACK                   = BIT(21),
+       IEEE80211_TX_STAT_AMPDU                 = BIT(22),
 };
 
-/* Transmit control fields. This data structure is passed to low-level driver
- * with each TX frame. The low-level driver is responsible for configuring
- * the hardware to use given values (depending on what is supported). */
 
-struct ieee80211_tx_control {
-       struct ieee80211_vif *vif;
-       struct ieee80211_rate *tx_rate;
-
-       /* Transmit rate for RTS/CTS frame */
-       struct ieee80211_rate *rts_cts_rate;
-
-       /* retry rate for the last retries */
-       struct ieee80211_rate *alt_retry_rate;
-
-       u32 flags;              /* tx control flags defined above */
-       u8 key_idx;             /* keyidx from hw->set_key(), undefined if
-                                * IEEE80211_TXCTL_DO_NOT_ENCRYPT is set */
-       u8 retry_limit;         /* 1 = only first attempt, 2 = one retry, ..
-                                * This could be used when set_retry_limit
-                                * is not implemented by the driver */
-       u8 antenna_sel_tx;      /* 0 = default/diversity, otherwise bit
-                                * position represents antenna number used */
-       u8 icv_len;             /* length of the ICV/MIC field in octets */
-       u8 iv_len;              /* length of the IV field in octets */
-       u8 queue;               /* hardware queue to use for this frame;
-                                * 0 = highest, hw->queues-1 = lowest */
-       u16 aid;                /* Station AID */
-       int type;       /* internal */
+#define IEEE80211_TX_INFO_DRIVER_DATA_SIZE \
+       (sizeof(((struct sk_buff *)0)->cb) - 8)
+#define IEEE80211_TX_INFO_DRIVER_DATA_PTRS \
+       (IEEE80211_TX_INFO_DRIVER_DATA_SIZE / sizeof(void *))
+
+/**
+ * struct ieee80211_tx_info - skb transmit information
+ *
+ * This structure is placed in skb->cb for three uses:
+ *  (1) mac80211 TX control - mac80211 tells the driver what to do
+ *  (2) driver internal use (if applicable)
+ *  (3) TX status information - driver tells mac80211 what happened
+ *
+ * @flags: transmit info flags, defined above
+ * @retry_count: number of retries
+ * @excessive_retries: set to 1 if the frame was retried many times
+ *     but not acknowledged
+ * @ampdu_ack_len: number of aggregated frames.
+ *     relevant only if IEEE80211_TX_STATUS_AMPDU was set.
+ * @ampdu_ack_map: block ack bit map for the aggregation.
+ *     relevant only if IEEE80211_TX_STATUS_AMPDU was set.
+ * @ack_signal: signal strength of the ACK frame
+ */
+struct ieee80211_tx_info {
+       /* common information */
+       u32 flags;
+       u8 band;
+       s8 tx_rate_idx;
+       u8 antenna_sel_tx;
+
+       /* 1 byte hole */
+
+       union {
+               struct {
+                       struct ieee80211_vif *vif;
+                       struct ieee80211_key_conf *hw_key;
+                       unsigned long jiffies;
+                       int ifindex;
+                       u16 aid;
+                       s8 rts_cts_rate_idx, alt_retry_rate_idx;
+                       u8 retry_limit;
+                       u8 icv_len;
+                       u8 iv_len;
+               } control;
+               struct {
+                       u64 ampdu_ack_map;
+                       int ack_signal;
+                       u8 retry_count;
+                       bool excessive_retries;
+                       u8 ampdu_ack_len;
+               } status;
+               void *driver_data[IEEE80211_TX_INFO_DRIVER_DATA_PTRS];
+       };
 };
 
+static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb)
+{
+       return (struct ieee80211_tx_info *)skb->cb;
+}
+
 
 /**
  * enum mac80211_rx_flags - receive flags
@@ -353,13 +362,16 @@ enum mac80211_rx_flags {
  * The low-level driver should provide this information (the subset
  * supported by hardware) to the 802.11 code with each received
  * frame.
+ *
  * @mactime: value in microseconds of the 64-bit Time Synchronization Function
  *     (TSF) timer when the first data symbol (MPDU) arrived at the hardware.
  * @band: the active band when this frame was received
  * @freq: frequency the radio was tuned to when receiving this frame, in MHz
- * @ssi: signal strength when receiving this frame
- * @signal: used as 'qual' in statistics reporting
- * @noise: PHY noise when receiving this frame
+ * @signal: signal strength when receiving this frame, either in dBm, in dB or
+ *     unspecified depending on the hardware capabilities flags
+ *     @IEEE80211_HW_SIGNAL_*
+ * @noise: noise when receiving this frame, in dBm.
+ * @qual: overall signal quality indication, in percent (0-100).
  * @antenna: antenna used
  * @rate_idx: index of data rate into band's supported rates
  * @flag: %RX_FLAG_*
@@ -368,63 +380,14 @@ struct ieee80211_rx_status {
        u64 mactime;
        enum ieee80211_band band;
        int freq;
-       int ssi;
        int signal;
        int noise;
+       int qual;
        int antenna;
        int rate_idx;
        int flag;
 };
 
-/**
- * enum ieee80211_tx_status_flags - transmit status flags
- *
- * Status flags to indicate various transmit conditions.
- *
- * @IEEE80211_TX_STATUS_TX_FILTERED: The frame was not transmitted
- *     because the destination STA was in powersave mode.
- * @IEEE80211_TX_STATUS_ACK: Frame was acknowledged
- * @IEEE80211_TX_STATUS_AMPDU: The frame was aggregated, so status
- *     is for the whole aggregation.
- */
-enum ieee80211_tx_status_flags {
-       IEEE80211_TX_STATUS_TX_FILTERED = 1<<0,
-       IEEE80211_TX_STATUS_ACK         = 1<<1,
-       IEEE80211_TX_STATUS_AMPDU       = 1<<2,
-};
-
-/**
- * struct ieee80211_tx_status - transmit status
- *
- * As much information as possible should be provided for each transmitted
- * frame with ieee80211_tx_status().
- *
- * @control: a copy of the &struct ieee80211_tx_control passed to the driver
- *     in the tx() callback.
- * @flags: transmit status flags, defined above
- * @retry_count: number of retries
- * @excessive_retries: set to 1 if the frame was retried many times
- *     but not acknowledged
- * @ampdu_ack_len: number of aggregated frames.
- *     relevant only if IEEE80211_TX_STATUS_AMPDU was set.
- * @ampdu_ack_map: block ack bit map for the aggregation.
- *     relevant only if IEEE80211_TX_STATUS_AMPDU was set.
- * @ack_signal: signal strength of the ACK frame
- * @queue_length: ?? REMOVE
- * @queue_number: ?? REMOVE
- */
-struct ieee80211_tx_status {
-       struct ieee80211_tx_control control;
-       u8 flags;
-       u8 retry_count;
-       bool excessive_retries;
-       u8 ampdu_ack_len;
-       u64 ampdu_ack_map;
-       int ack_signal;
-       int queue_length;
-       int queue_number;
-};
-
 /**
  * enum ieee80211_conf_flags - configuration flags
  *
@@ -580,7 +543,6 @@ struct ieee80211_if_conf {
        u8 *ssid;
        size_t ssid_len;
        struct sk_buff *beacon;
-       struct ieee80211_tx_control *beacon_control;
 };
 
 /**
@@ -610,11 +572,14 @@ enum ieee80211_key_alg {
  * @IEEE80211_KEY_FLAG_GENERATE_MMIC: This flag should be set by
  *     the driver for a TKIP key if it requires Michael MIC
  *     generation in software.
+ * @IEEE80211_KEY_FLAG_PAIRWISE: Set by mac80211, this flag indicates
+ *     that the key is pairwise rather then a shared key.
  */
 enum ieee80211_key_flags {
        IEEE80211_KEY_FLAG_WMM_STA      = 1<<0,
        IEEE80211_KEY_FLAG_GENERATE_IV  = 1<<1,
        IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2,
+       IEEE80211_KEY_FLAG_PAIRWISE     = 1<<3,
 };
 
 /**
@@ -721,6 +686,25 @@ enum ieee80211_tkip_key_type {
  * @IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE:
  *     Hardware is not capable of receiving frames with short preamble on
  *     the 2.4 GHz band.
+ *
+ * @IEEE80211_HW_SIGNAL_UNSPEC:
+ *     Hardware can provide signal values but we don't know its units. We
+ *     expect values between 0 and @max_signal.
+ *     If possible please provide dB or dBm instead.
+ *
+ * @IEEE80211_HW_SIGNAL_DB:
+ *     Hardware gives signal values in dB, decibel difference from an
+ *     arbitrary, fixed reference. We expect values between 0 and @max_signal.
+ *     If possible please provide dBm instead.
+ *
+ * @IEEE80211_HW_SIGNAL_DBM:
+ *     Hardware gives signal values in dBm, decibel difference from
+ *     one milliwatt. This is the preferred method since it is standardized
+ *     between different devices. @max_signal does not need to be set.
+ *
+ * @IEEE80211_HW_NOISE_DBM:
+ *     Hardware can provide noise (radio interference) values in units dBm,
+ *      decibel difference from one milliwatt.
  */
 enum ieee80211_hw_flags {
        IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE           = 1<<0,
@@ -728,6 +712,10 @@ enum ieee80211_hw_flags {
        IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING        = 1<<2,
        IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE          = 1<<3,
        IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE      = 1<<4,
+       IEEE80211_HW_SIGNAL_UNSPEC                      = 1<<5,
+       IEEE80211_HW_SIGNAL_DB                          = 1<<6,
+       IEEE80211_HW_SIGNAL_DBM                         = 1<<7,
+       IEEE80211_HW_NOISE_DBM                          = 1<<8,
 };
 
 /**
@@ -758,15 +746,18 @@ enum ieee80211_hw_flags {
  *
  * @channel_change_time: time (in microseconds) it takes to change channels.
  *
- * @max_rssi: Maximum value for ssi in RX information, use
- *     negative numbers for dBm and 0 to indicate no support.
- *
- * @max_signal: like @max_rssi, but for the signal value.
- *
- * @max_noise: like @max_rssi, but for the noise value.
+ * @max_signal: Maximum value for signal (rssi) in RX information, used
+ *     only when @IEEE80211_HW_SIGNAL_UNSPEC or @IEEE80211_HW_SIGNAL_DB
  *
  * @queues: number of available hardware transmit queues for
- *     data packets. WMM/QoS requires at least four.
+ *     data packets. WMM/QoS requires at least four, these
+ *     queues need to have configurable access parameters.
+ *
+ * @ampdu_queues: number of available hardware transmit queues
+ *     for A-MPDU packets, these have no access parameters
+ *     because they're used only for A-MPDU frames. Note that
+ *     mac80211 will not currently use any of the regular queues
+ *     for aggregation.
  *
  * @rate_control_algorithm: rate control algorithm for this hardware.
  *     If unset (NULL), the default algorithm will be used. Must be
@@ -785,10 +776,8 @@ struct ieee80211_hw {
        unsigned int extra_tx_headroom;
        int channel_change_time;
        int vif_data_size;
-       u8 queues;
-       s8 max_rssi;
+       u16 queues, ampdu_queues;
        s8 max_signal;
-       s8 max_noise;
 };
 
 /**
@@ -813,6 +802,51 @@ static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr)
        memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN);
 }
 
+static inline int ieee80211_num_regular_queues(struct ieee80211_hw *hw)
+{
+#ifdef CONFIG_MAC80211_QOS
+       return hw->queues;
+#else
+       return 1;
+#endif
+}
+
+static inline int ieee80211_num_queues(struct ieee80211_hw *hw)
+{
+#ifdef CONFIG_MAC80211_QOS
+       return hw->queues + hw->ampdu_queues;
+#else
+       return 1;
+#endif
+}
+
+static inline struct ieee80211_rate *
+ieee80211_get_tx_rate(const struct ieee80211_hw *hw,
+                     const struct ieee80211_tx_info *c)
+{
+       if (WARN_ON(c->tx_rate_idx < 0))
+               return NULL;
+       return &hw->wiphy->bands[c->band]->bitrates[c->tx_rate_idx];
+}
+
+static inline struct ieee80211_rate *
+ieee80211_get_rts_cts_rate(const struct ieee80211_hw *hw,
+                          const struct ieee80211_tx_info *c)
+{
+       if (c->control.rts_cts_rate_idx < 0)
+               return NULL;
+       return &hw->wiphy->bands[c->band]->bitrates[c->control.rts_cts_rate_idx];
+}
+
+static inline struct ieee80211_rate *
+ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
+                            const struct ieee80211_tx_info *c)
+{
+       if (c->control.alt_retry_rate_idx < 0)
+               return NULL;
+       return &hw->wiphy->bands[c->band]->bitrates[c->control.alt_retry_rate_idx];
+}
+
 /**
  * DOC: Hardware crypto acceleration
  *
@@ -970,8 +1004,10 @@ enum ieee80211_ampdu_mlme_action {
  * @tx: Handler that 802.11 module calls for each transmitted frame.
  *     skb contains the buffer starting from the IEEE 802.11 header.
  *     The low-level driver should send the frame out based on
- *     configuration in the TX control data. Must be implemented and
- *     atomic.
+ *     configuration in the TX control data. This handler should,
+ *     preferably, never fail and stop queues appropriately, more
+ *     importantly, however, it must never fail for A-MPDU-queues.
+ *     Must be implemented and atomic.
  *
  * @start: Called before the first netdevice attached to the hardware
  *     is enabled. This should turn on the hardware and must turn on
@@ -1063,15 +1099,13 @@ enum ieee80211_ampdu_mlme_action {
  *     of assocaited station or AP.
  *
  * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
- *     bursting) for a hardware TX queue. The @queue parameter uses the
- *     %IEEE80211_TX_QUEUE_* constants. Must be atomic.
+ *     bursting) for a hardware TX queue. Must be atomic.
  *
  * @get_tx_stats: Get statistics of the current TX queue status. This is used
  *     to get number of currently queued packets (queue length), maximum queue
  *     size (limit), and total number of packets sent using each TX queue
- *     (count). This information is used for WMM to find out which TX
- *     queues have room for more packets and by hostapd to provide
- *     statistics about the current queueing state to external programs.
+ *     (count). The 'stats' pointer points to an array that has hw->queues +
+ *     hw->ampdu_queues items.
  *
  * @get_tsf: Get the current TSF timer value from firmware/hardware. Currently,
  *     this is only used for IBSS mode debugging and, as such, is not a
@@ -1107,8 +1141,7 @@ enum ieee80211_ampdu_mlme_action {
  *     that TX/RX_STOP can pass NULL for this parameter.
  */
 struct ieee80211_ops {
-       int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb,
-                 struct ieee80211_tx_control *control);
+       int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
        int (*start)(struct ieee80211_hw *hw);
        void (*stop)(struct ieee80211_hw *hw);
        int (*add_interface)(struct ieee80211_hw *hw,
@@ -1145,15 +1178,14 @@ struct ieee80211_ops {
                               u32 short_retry, u32 long_retr);
        void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                        enum sta_notify_cmd, const u8 *addr);
-       int (*conf_tx)(struct ieee80211_hw *hw, int queue,
+       int (*conf_tx)(struct ieee80211_hw *hw, u16 queue,
                       const struct ieee80211_tx_queue_params *params);
        int (*get_tx_stats)(struct ieee80211_hw *hw,
                            struct ieee80211_tx_queue_stats *stats);
        u64 (*get_tsf)(struct ieee80211_hw *hw);
        void (*reset_tsf)(struct ieee80211_hw *hw);
        int (*beacon_update)(struct ieee80211_hw *hw,
-                            struct sk_buff *skb,
-                            struct ieee80211_tx_control *control);
+                            struct sk_buff *skb);
        int (*tx_last_beacon)(struct ieee80211_hw *hw);
        int (*ampdu_action)(struct ieee80211_hw *hw,
                            enum ieee80211_ampdu_mlme_action action,
@@ -1349,13 +1381,9 @@ void ieee80211_rx_irqsafe(struct ieee80211_hw *hw,
  *
  * @hw: the hardware the frame was transmitted by
  * @skb: the frame that was transmitted, owned by mac80211 after this call
- * @status: status information for this frame; the status pointer need not
- *     be valid after this function returns and is not freed by mac80211,
- *     it is recommended that it points to a stack area
  */
 void ieee80211_tx_status(struct ieee80211_hw *hw,
-                        struct sk_buff *skb,
-                        struct ieee80211_tx_status *status);
+                        struct sk_buff *skb);
 
 /**
  * ieee80211_tx_status_irqsafe - irq-safe transmit status callback
@@ -1368,13 +1396,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw,
  *
  * @hw: the hardware the frame was transmitted by
  * @skb: the frame that was transmitted, owned by mac80211 after this call
- * @status: status information for this frame; the status pointer need not
- *     be valid after this function returns and is not freed by mac80211,
- *     it is recommended that it points to a stack area
  */
 void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
-                                struct sk_buff *skb,
-                                struct ieee80211_tx_status *status);
+                                struct sk_buff *skb);
 
 /**
  * ieee80211_beacon_get - beacon generation function
@@ -1390,8 +1414,7 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
  * is responsible of freeing it.
  */
 struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
-                                    struct ieee80211_vif *vif,
-                                    struct ieee80211_tx_control *control);
+                                    struct ieee80211_vif *vif);
 
 /**
  * ieee80211_rts_get - RTS frame generation function
@@ -1399,7 +1422,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
  * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
  * @frame: pointer to the frame that is going to be protected by the RTS.
  * @frame_len: the frame length (in octets).
- * @frame_txctl: &struct ieee80211_tx_control of the frame.
+ * @frame_txctl: &struct ieee80211_tx_info of the frame.
  * @rts: The buffer where to store the RTS frame.
  *
  * If the RTS frames are generated by the host system (i.e., not in
@@ -1409,7 +1432,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
  */
 void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                       const void *frame, size_t frame_len,
-                      const struct ieee80211_tx_control *frame_txctl,
+                      const struct ieee80211_tx_info *frame_txctl,
                       struct ieee80211_rts *rts);
 
 /**
@@ -1417,7 +1440,7 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
  * @hw: pointer obtained from ieee80211_alloc_hw().
  * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
  * @frame_len: the length of the frame that is going to be protected by the RTS.
- * @frame_txctl: &struct ieee80211_tx_control of the frame.
+ * @frame_txctl: &struct ieee80211_tx_info of the frame.
  *
  * If the RTS is generated in firmware, but the host system must provide
  * the duration field, the low-level driver uses this function to receive
@@ -1425,7 +1448,7 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
  */
 __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
                              struct ieee80211_vif *vif, size_t frame_len,
-                             const struct ieee80211_tx_control *frame_txctl);
+                             const struct ieee80211_tx_info *frame_txctl);
 
 /**
  * ieee80211_ctstoself_get - CTS-to-self frame generation function
@@ -1433,7 +1456,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
  * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
  * @frame: pointer to the frame that is going to be protected by the CTS-to-self.
  * @frame_len: the frame length (in octets).
- * @frame_txctl: &struct ieee80211_tx_control of the frame.
+ * @frame_txctl: &struct ieee80211_tx_info of the frame.
  * @cts: The buffer where to store the CTS-to-self frame.
  *
  * If the CTS-to-self frames are generated by the host system (i.e., not in
@@ -1444,7 +1467,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
 void ieee80211_ctstoself_get(struct ieee80211_hw *hw,
                             struct ieee80211_vif *vif,
                             const void *frame, size_t frame_len,
-                            const struct ieee80211_tx_control *frame_txctl,
+                            const struct ieee80211_tx_info *frame_txctl,
                             struct ieee80211_cts *cts);
 
 /**
@@ -1452,7 +1475,7 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw,
  * @hw: pointer obtained from ieee80211_alloc_hw().
  * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
  * @frame_len: the length of the frame that is going to be protected by the CTS-to-self.
- * @frame_txctl: &struct ieee80211_tx_control of the frame.
+ * @frame_txctl: &struct ieee80211_tx_info of the frame.
  *
  * If the CTS-to-self is generated in firmware, but the host system must provide
  * the duration field, the low-level driver uses this function to receive
@@ -1461,7 +1484,7 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw,
 __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
                                    struct ieee80211_vif *vif,
                                    size_t frame_len,
-                                   const struct ieee80211_tx_control *frame_txctl);
+                                   const struct ieee80211_tx_info *frame_txctl);
 
 /**
  * ieee80211_generic_frame_duration - Calculate the duration field for a frame
@@ -1500,8 +1523,7 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
  * use common code for all beacons.
  */
 struct sk_buff *
-ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-                         struct ieee80211_tx_control *control);
+ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
 
 /**
  * ieee80211_get_hdrlen_from_skb - get header length from data
@@ -1558,14 +1580,6 @@ void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue);
  */
 void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue);
 
-/**
- * ieee80211_start_queues - start all queues
- * @hw: pointer to as obtained from ieee80211_alloc_hw().
- *
- * Drivers should use this function instead of netif_start_queue.
- */
-void ieee80211_start_queues(struct ieee80211_hw *hw);
-
 /**
  * ieee80211_stop_queues - stop all queues
  * @hw: pointer as obtained from ieee80211_alloc_hw().
index aa540e6be502b49c5b7322e6ee57f630e6fa584a..8df751b3be55bc2c5b15719f55be5188e1045738 100644 (file)
@@ -201,8 +201,11 @@ extern void unregister_pernet_gen_device(int id, struct pernet_operations *);
 struct ctl_path;
 struct ctl_table;
 struct ctl_table_header;
+
 extern struct ctl_table_header *register_net_sysctl_table(struct net *net,
        const struct ctl_path *path, struct ctl_table *table);
+extern struct ctl_table_header *register_net_sysctl_rotable(
+       const struct ctl_path *path, struct ctl_table *table);
 extern void unregister_net_sysctl_table(struct ctl_table_header *header);
 
 #endif /* __NET_NET_NAMESPACE_H */
index 9bf059817aec6721d1378998ff9f94f624064c0a..7573d52a43469a9dbc3feeb6555810ceb9e1a740 100644 (file)
@@ -9,8 +9,6 @@
 #ifndef _NF_CONNTRACK_IPV4_H
 #define _NF_CONNTRACK_IPV4_H
 
-/* Returns new sk_buff, or NULL */
-struct sk_buff *nf_ct_ipv4_ct_gather_frags(struct sk_buff *skb);
 
 extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4;
 
index 2dbd6c015b947da0f1b21cc4d14201241e6bc8d9..d77dec768dc24ecb2616be531e6ca030dceabeaa 100644 (file)
@@ -223,6 +223,25 @@ static inline void nf_ct_refresh(struct nf_conn *ct,
        __nf_ct_refresh_acct(ct, 0, skb, extra_jiffies, 0);
 }
 
+extern void __nf_ct_kill_acct(struct nf_conn *ct,
+                               enum ip_conntrack_info ctinfo,
+                               const struct sk_buff *skb,
+                               int do_acct);
+
+/* kill conntrack and do accounting */
+static inline void nf_ct_kill_acct(struct nf_conn *ct,
+                               enum ip_conntrack_info ctinfo,
+                               const struct sk_buff *skb)
+{
+       __nf_ct_kill_acct(ct, ctinfo, skb, 1);
+}
+
+/* kill conntrack without accounting */
+static inline void nf_ct_kill(struct nf_conn *ct)
+{
+       __nf_ct_kill_acct(ct, 0, NULL, 0);
+}
+
 /* These are for NAT.  Icky. */
 /* Update TCP window tracking data when NAT mangles the packet */
 extern void nf_conntrack_tcp_update(const struct sk_buff *skb,
index 34ee348a2cf207e9b1522706fa2e7a3b216d1b55..6ef90b5fafb351e279a007bf6913dc375ed816f2 100644 (file)
@@ -36,6 +36,7 @@ struct netns_ipv4 {
        struct xt_table         *iptable_mangle;
        struct xt_table         *iptable_raw;
        struct xt_table         *arptable_filter;
+       struct xt_table         *iptable_security;
 #endif
 
        int sysctl_icmp_echo_ignore_all;
index ac053be6c25625671d3f037929444d15a68dfdb3..5bacd838e88bfd7a3d5b84dcc89e74bbcad60226 100644 (file)
@@ -35,6 +35,7 @@ struct netns_ipv6 {
        struct xt_table         *ip6table_filter;
        struct xt_table         *ip6table_mangle;
        struct xt_table         *ip6table_raw;
+       struct xt_table         *ip6table_security;
 #endif
        struct rt6_info         *ip6_null_entry;
        struct rt6_statistics   *rt6_stats;
index 90b1e8d23b1638e59d45e9623d5a2f6ff81c8356..5672d489e9240c0adb4afe1750021709b74ed773 100644 (file)
@@ -179,6 +179,8 @@ int sctp_eps_proc_init(void);
 void sctp_eps_proc_exit(void);
 int sctp_assocs_proc_init(void);
 void sctp_assocs_proc_exit(void);
+int sctp_remaddr_proc_init(void);
+void sctp_remaddr_proc_exit(void);
 
 
 /*
index 7f25195f98557aff042ba461f4638f7ae5fdfe2b..fbc27ac8a09e64f55edcf40e67cd52267b4df39e 100644 (file)
@@ -300,6 +300,7 @@ struct sctp_sock {
 
        /* The default SACK delay timeout for new associations. */
        __u32 sackdelay;
+       __u32 sackfreq;
 
        /* Flags controlling Heartbeat, SACK delay, and Path MTU Discovery. */
        __u32 param_flags;
@@ -946,6 +947,7 @@ struct sctp_transport {
 
        /* SACK delay timeout */
        unsigned long sackdelay;
+       __u32 sackfreq;
 
        /* When was the last time (in jiffies) that we heard from this
         * transport?  We use this to pick new active and retran paths.
@@ -1553,6 +1555,7 @@ struct sctp_association {
                 *             : SACK's are not delayed (see Section 6).
                 */
                __u8    sack_needed;     /* Do we need to sack the peer? */
+               __u32   sack_cnt;
 
                /* These are capabilities which our peer advertised.  */
                __u8    ecn_capable;     /* Can peer do ECN? */
@@ -1662,6 +1665,7 @@ struct sctp_association {
 
        /* SACK delay timeout */
        unsigned long sackdelay;
+       __u32 sackfreq;
 
 
        unsigned long timeouts[SCTP_NUM_TIMEOUT_TYPES];
index 9619b9d35c9e7d581db9b35448af14c1b9598b8c..f205b10f0ab95f05ec3cef5aea549991c4f0f0d7 100644 (file)
@@ -93,8 +93,9 @@ enum sctp_optname {
 #define SCTP_STATUS SCTP_STATUS
        SCTP_GET_PEER_ADDR_INFO,
 #define SCTP_GET_PEER_ADDR_INFO SCTP_GET_PEER_ADDR_INFO
-       SCTP_DELAYED_ACK_TIME,
-#define SCTP_DELAYED_ACK_TIME SCTP_DELAYED_ACK_TIME
+       SCTP_DELAYED_ACK,
+#define SCTP_DELAYED_ACK_TIME SCTP_DELAYED_ACK
+#define SCTP_DELAYED_ACK SCTP_DELAYED_ACK
        SCTP_CONTEXT,   /* Receive Context */
 #define SCTP_CONTEXT SCTP_CONTEXT
        SCTP_FRAGMENT_INTERLEAVE,
@@ -136,12 +137,14 @@ enum sctp_optname {
 #define SCTP_GET_LOCAL_ADDRS_NUM_OLD   SCTP_GET_LOCAL_ADDRS_NUM_OLD
        SCTP_GET_LOCAL_ADDRS_OLD,       /* Get all local addresss. */
 #define SCTP_GET_LOCAL_ADDRS_OLD       SCTP_GET_LOCAL_ADDRS_OLD
-       SCTP_SOCKOPT_CONNECTX, /* CONNECTX requests. */
-#define SCTP_SOCKOPT_CONNECTX  SCTP_SOCKOPT_CONNECTX
+       SCTP_SOCKOPT_CONNECTX_OLD, /* CONNECTX old requests. */
+#define SCTP_SOCKOPT_CONNECTX_OLD      SCTP_SOCKOPT_CONNECTX_OLD
        SCTP_GET_PEER_ADDRS,    /* Get all peer addresss. */
 #define SCTP_GET_PEER_ADDRS    SCTP_GET_PEER_ADDRS
        SCTP_GET_LOCAL_ADDRS,   /* Get all local addresss. */
 #define SCTP_GET_LOCAL_ADDRS   SCTP_GET_LOCAL_ADDRS
+       SCTP_SOCKOPT_CONNECTX, /* CONNECTX requests. */
+#define SCTP_SOCKOPT_CONNECTX  SCTP_SOCKOPT_CONNECTX
 };
 
 /*
@@ -618,13 +621,26 @@ struct sctp_authkeyid {
 };
 
 
-/* 7.1.23. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME)
+/*
+ * 7.1.23.  Get or set delayed ack timer (SCTP_DELAYED_SACK)
  *
- *   This options will get or set the delayed ack timer.  The time is set
- *   in milliseconds.  If the assoc_id is 0, then this sets or gets the
- *   endpoints default delayed ack timer value.  If the assoc_id field is
- *   non-zero, then the set or get effects the specified association.
+ * This option will effect the way delayed acks are performed.  This
+ * option allows you to get or set the delayed ack time, in
+ * milliseconds.  It also allows changing the delayed ack frequency.
+ * Changing the frequency to 1 disables the delayed sack algorithm.  If
+ * the assoc_id is 0, then this sets or gets the endpoints default
+ * values.  If the assoc_id field is non-zero, then the set or get
+ * effects the specified association for the one to many model (the
+ * assoc_id field is ignored by the one to one model).  Note that if
+ * sack_delay or sack_freq are 0 when setting this option, then the
+ * current values will remain unchanged.
  */
+struct sctp_sack_info {
+       sctp_assoc_t    sack_assoc_id;
+       uint32_t        sack_delay;
+       uint32_t        sack_freq;
+};
+
 struct sctp_assoc_value {
     sctp_assoc_t            assoc_id;
     uint32_t                assoc_value;
index 11105bcc4457336308a64982b4a8dc0eb6069409..9923e41a821549e2a450c90320beecc03db77052 100644 (file)
@@ -84,7 +84,8 @@ struct tipc_port {
 u32 tipc_createport_raw(void *usr_handle,
                        u32 (*dispatcher)(struct tipc_port *, struct sk_buff *),
                        void (*wakeup)(struct tipc_port *),
-                       const u32 importance);
+                       const u32 importance,
+                       struct tipc_port **tp_ptr);
 
 int tipc_reject_msg(struct sk_buff *buf, u32 err);
 
index 667b4080d30fe27eee5949a4c9e846ea6b3384ef..9324f8dd183eac07d299269fdf0f836bd6c8f193 100644 (file)
@@ -39,12 +39,18 @@ enum ieee80211_band {
  *     on this channel.
  * @IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel.
  * @IEEE80211_CHAN_RADAR: Radar detection is required on this channel.
+ * @IEEE80211_CHAN_NO_FAT_ABOVE: extension channel above this channel
+ *     is not permitted.
+ * @IEEE80211_CHAN_NO_FAT_BELOW: extension channel below this channel
+ *     is not permitted.
  */
 enum ieee80211_channel_flags {
        IEEE80211_CHAN_DISABLED         = 1<<0,
        IEEE80211_CHAN_PASSIVE_SCAN     = 1<<1,
        IEEE80211_CHAN_NO_IBSS          = 1<<2,
        IEEE80211_CHAN_RADAR            = 1<<3,
+       IEEE80211_CHAN_NO_FAT_ABOVE     = 1<<4,
+       IEEE80211_CHAN_NO_FAT_BELOW     = 1<<5,
 };
 
 /**
index b3b69fd5133024f9c7aaa116cab75c65772379d4..3e84b958186b5d043ef34c706ff4036433f93c8b 100644 (file)
@@ -1054,7 +1054,7 @@ retry:
                        }
 
                        timeo = MAX_SCHEDULE_TIMEOUT;
-                       ret = netlink_attachskb(sock, nc, 0, &timeo, NULL);
+                       ret = netlink_attachskb(sock, nc, &timeo, NULL);
                        if (ret == 1)
                                goto retry;
                        if (ret) {
index bf7787395fe09c17e25cbcea93f089386aad5af8..626c7795ae30edcdab4e5d6997995eff1e029942 100644 (file)
 #include <asm/uaccess.h>
 #include "br_private.h"
 
-static struct net_device_stats *br_dev_get_stats(struct net_device *dev)
-{
-       struct net_bridge *br = netdev_priv(dev);
-       return &br->statistics;
-}
-
 /* net device transmit always called with no BH (preempt_disabled) */
 int br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
 {
@@ -34,8 +28,8 @@ int br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
        const unsigned char *dest = skb->data;
        struct net_bridge_fdb_entry *dst;
 
-       br->statistics.tx_packets++;
-       br->statistics.tx_bytes += skb->len;
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += skb->len;
 
        skb_reset_mac_header(skb);
        skb_pull(skb, ETH_HLEN);
@@ -161,7 +155,6 @@ void br_dev_setup(struct net_device *dev)
        ether_setup(dev);
 
        dev->do_ioctl = br_dev_ioctl;
-       dev->get_stats = br_dev_get_stats;
        dev->hard_start_xmit = br_dev_xmit;
        dev->open = br_dev_open;
        dev->set_multicast_list = br_dev_set_multicast_list;
index bdd7c35c3c7ba870a618f359733a19197e61e758..a4711674b3df0470b53855b6ff5e2523a1958603 100644 (file)
@@ -115,7 +115,7 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb,
                                struct sk_buff *skb2;
 
                                if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) {
-                                       br->statistics.tx_dropped++;
+                                       br->dev->stats.tx_dropped++;
                                        kfree_skb(skb);
                                        return;
                                }
index 255c00f60ce7a3a14a5b0089e440d2edf46403e1..fa0f5711a9961c9f0d24b286933fa42ea6485ed9 100644 (file)
@@ -24,13 +24,13 @@ const u8 br_group_address[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
 
 static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb)
 {
-       struct net_device *indev;
+       struct net_device *indev, *brdev = br->dev;
 
-       br->statistics.rx_packets++;
-       br->statistics.rx_bytes += skb->len;
+       brdev->stats.rx_packets++;
+       brdev->stats.rx_bytes += skb->len;
 
        indev = skb->dev;
-       skb->dev = br->dev;
+       skb->dev = brdev;
 
        NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,
                netif_receive_skb);
@@ -64,7 +64,7 @@ int br_handle_frame_finish(struct sk_buff *skb)
        dst = NULL;
 
        if (is_multicast_ether_addr(dest)) {
-               br->statistics.multicast++;
+               br->dev->stats.multicast++;
                skb2 = skb;
        } else if ((dst = __br_fdb_get(br, dest)) && dst->is_local) {
                skb2 = skb;
index c11b554fd109d4f1b587c8b254a5352889a29b86..0243cb489eddf9e9f4d5042c7e5361ca6d3edcd2 100644 (file)
@@ -90,7 +90,6 @@ struct net_bridge
        spinlock_t                      lock;
        struct list_head                port_list;
        struct net_device               *dev;
-       struct net_device_stats         statistics;
        spinlock_t                      hash_lock;
        struct hlist_head               hash[BR_HASH_SIZE];
        struct list_head                age_list;
index 7beeefa0f9c05ffabef8dcbd3257330ed7ad649c..fb684c2ff8b60ab24f3d7c34c9777fdceb98d2f2 100644 (file)
@@ -83,6 +83,15 @@ config BRIDGE_EBT_IP
 
          To compile it as a module, choose M here.  If unsure, say N.
 
+config BRIDGE_EBT_IP6
+       tristate "ebt: IP6 filter support"
+       depends on BRIDGE_NF_EBTABLES
+       help
+         This option adds the IP6 match, which allows basic IPV6 header field
+         filtering.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
 config BRIDGE_EBT_LIMIT
        tristate "ebt: limit match support"
        depends on BRIDGE_NF_EBTABLES
index 83715d73a50352c33eb922e81974e769b84bbd1a..dd960645b4139ca1c8e0545ae75bf1a81fad7d8c 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_BRIDGE_EBT_802_3) += ebt_802_3.o
 obj-$(CONFIG_BRIDGE_EBT_AMONG) += ebt_among.o
 obj-$(CONFIG_BRIDGE_EBT_ARP) += ebt_arp.o
 obj-$(CONFIG_BRIDGE_EBT_IP) += ebt_ip.o
+obj-$(CONFIG_BRIDGE_EBT_IP) += ebt_ip6.o
 obj-$(CONFIG_BRIDGE_EBT_LIMIT) += ebt_limit.o
 obj-$(CONFIG_BRIDGE_EBT_MARK) += ebt_mark_m.o
 obj-$(CONFIG_BRIDGE_EBT_PKTTYPE) += ebt_pkttype.o
diff --git a/net/bridge/netfilter/ebt_ip6.c b/net/bridge/netfilter/ebt_ip6.c
new file mode 100644 (file)
index 0000000..36efb3a
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ *  ebt_ip6
+ *
+ *     Authors:
+ *     Manohar Castelino <manohar.r.castelino@intel.com>
+ *     Kuo-Lang Tseng <kuo-lang.tseng@intel.com>
+ *     Jan Engelhardt <jengelh@computergmbh.de>
+ *
+ * Summary:
+ * This is just a modification of the IPv4 code written by
+ * Bart De Schuymer <bdschuym@pandora.be>
+ * with the changes required to support IPv6
+ *
+ *  Jan, 2008
+ */
+
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_ip6.h>
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
+#include <linux/in.h>
+#include <linux/module.h>
+#include <net/dsfield.h>
+
+struct tcpudphdr {
+       __be16 src;
+       __be16 dst;
+};
+
+static int ebt_filter_ip6(const struct sk_buff *skb,
+   const struct net_device *in,
+   const struct net_device *out, const void *data,
+   unsigned int datalen)
+{
+       const struct ebt_ip6_info *info = (struct ebt_ip6_info *)data;
+       const struct ipv6hdr *ih6;
+       struct ipv6hdr _ip6h;
+       const struct tcpudphdr *pptr;
+       struct tcpudphdr _ports;
+       struct in6_addr tmp_addr;
+       int i;
+
+       ih6 = skb_header_pointer(skb, 0, sizeof(_ip6h), &_ip6h);
+       if (ih6 == NULL)
+               return EBT_NOMATCH;
+       if (info->bitmask & EBT_IP6_TCLASS &&
+          FWINV(info->tclass != ipv6_get_dsfield(ih6), EBT_IP6_TCLASS))
+               return EBT_NOMATCH;
+       for (i = 0; i < 4; i++)
+               tmp_addr.in6_u.u6_addr32[i] = ih6->saddr.in6_u.u6_addr32[i] &
+                       info->smsk.in6_u.u6_addr32[i];
+       if (info->bitmask & EBT_IP6_SOURCE &&
+               FWINV((ipv6_addr_cmp(&tmp_addr, &info->saddr) != 0),
+                       EBT_IP6_SOURCE))
+               return EBT_NOMATCH;
+       for (i = 0; i < 4; i++)
+               tmp_addr.in6_u.u6_addr32[i] = ih6->daddr.in6_u.u6_addr32[i] &
+                       info->dmsk.in6_u.u6_addr32[i];
+       if (info->bitmask & EBT_IP6_DEST &&
+          FWINV((ipv6_addr_cmp(&tmp_addr, &info->daddr) != 0), EBT_IP6_DEST))
+               return EBT_NOMATCH;
+       if (info->bitmask & EBT_IP6_PROTO) {
+               uint8_t nexthdr = ih6->nexthdr;
+               int offset_ph;
+
+               offset_ph = ipv6_skip_exthdr(skb, sizeof(_ip6h), &nexthdr);
+               if (offset_ph == -1)
+                       return EBT_NOMATCH;
+               if (FWINV(info->protocol != nexthdr, EBT_IP6_PROTO))
+                       return EBT_NOMATCH;
+               if (!(info->bitmask & EBT_IP6_DPORT) &&
+                   !(info->bitmask & EBT_IP6_SPORT))
+                       return EBT_MATCH;
+               pptr = skb_header_pointer(skb, offset_ph, sizeof(_ports),
+                                         &_ports);
+               if (pptr == NULL)
+                       return EBT_NOMATCH;
+               if (info->bitmask & EBT_IP6_DPORT) {
+                       u32 dst = ntohs(pptr->dst);
+                       if (FWINV(dst < info->dport[0] ||
+                                 dst > info->dport[1], EBT_IP6_DPORT))
+                               return EBT_NOMATCH;
+               }
+               if (info->bitmask & EBT_IP6_SPORT) {
+                       u32 src = ntohs(pptr->src);
+                       if (FWINV(src < info->sport[0] ||
+                                 src > info->sport[1], EBT_IP6_SPORT))
+                       return EBT_NOMATCH;
+               }
+               return EBT_MATCH;
+       }
+       return EBT_MATCH;
+}
+
+static int ebt_ip6_check(const char *tablename, unsigned int hookmask,
+   const struct ebt_entry *e, void *data, unsigned int datalen)
+{
+       struct ebt_ip6_info *info = (struct ebt_ip6_info *)data;
+
+       if (datalen != EBT_ALIGN(sizeof(struct ebt_ip6_info)))
+               return -EINVAL;
+       if (e->ethproto != htons(ETH_P_IPV6) || e->invflags & EBT_IPROTO)
+               return -EINVAL;
+       if (info->bitmask & ~EBT_IP6_MASK || info->invflags & ~EBT_IP6_MASK)
+               return -EINVAL;
+       if (info->bitmask & (EBT_IP6_DPORT | EBT_IP6_SPORT)) {
+               if (info->invflags & EBT_IP6_PROTO)
+                       return -EINVAL;
+               if (info->protocol != IPPROTO_TCP &&
+                   info->protocol != IPPROTO_UDP &&
+                   info->protocol != IPPROTO_UDPLITE &&
+                   info->protocol != IPPROTO_SCTP &&
+                   info->protocol != IPPROTO_DCCP)
+                        return -EINVAL;
+       }
+       if (info->bitmask & EBT_IP6_DPORT && info->dport[0] > info->dport[1])
+               return -EINVAL;
+       if (info->bitmask & EBT_IP6_SPORT && info->sport[0] > info->sport[1])
+               return -EINVAL;
+       return 0;
+}
+
+static struct ebt_match filter_ip6 =
+{
+       .name           = EBT_IP6_MATCH,
+       .match          = ebt_filter_ip6,
+       .check          = ebt_ip6_check,
+       .me             = THIS_MODULE,
+};
+
+static int __init ebt_ip6_init(void)
+{
+       return ebt_register_match(&filter_ip6);
+}
+
+static void __exit ebt_ip6_fini(void)
+{
+       ebt_unregister_match(&filter_ip6);
+}
+
+module_init(ebt_ip6_init);
+module_exit(ebt_ip6_fini);
+MODULE_DESCRIPTION("Ebtables: IPv6 protocol packet match");
+MODULE_LICENSE("GPL");
index 0b209e4aad0a0a76e53c9cbc7c89d950eda92af7..c883ec8a28b46c77673b1ada6316fd10ae983353 100644 (file)
@@ -18,6 +18,9 @@
 #include <linux/if_arp.h>
 #include <linux/spinlock.h>
 #include <net/netfilter/nf_log.h>
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
+#include <linux/in6.h>
 
 static DEFINE_SPINLOCK(ebt_log_lock);
 
@@ -58,6 +61,27 @@ static void print_MAC(const unsigned char *p)
                printk("%02x%c", *p, i == ETH_ALEN - 1 ? ' ':':');
 }
 
+static void
+print_ports(const struct sk_buff *skb, uint8_t protocol, int offset)
+{
+       if (protocol == IPPROTO_TCP ||
+           protocol == IPPROTO_UDP ||
+           protocol == IPPROTO_UDPLITE ||
+           protocol == IPPROTO_SCTP ||
+           protocol == IPPROTO_DCCP) {
+               const struct tcpudphdr *pptr;
+               struct tcpudphdr _ports;
+
+               pptr = skb_header_pointer(skb, offset,
+                                         sizeof(_ports), &_ports);
+               if (pptr == NULL) {
+                       printk(" INCOMPLETE TCP/UDP header");
+                       return;
+               }
+               printk(" SPT=%u DPT=%u", ntohs(pptr->src), ntohs(pptr->dst));
+       }
+}
+
 #define myNIPQUAD(a) a[0], a[1], a[2], a[3]
 static void
 ebt_log_packet(unsigned int pf, unsigned int hooknum,
@@ -95,23 +119,31 @@ ebt_log_packet(unsigned int pf, unsigned int hooknum,
                printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u, IP "
                       "tos=0x%02X, IP proto=%d", NIPQUAD(ih->saddr),
                       NIPQUAD(ih->daddr), ih->tos, ih->protocol);
-               if (ih->protocol == IPPROTO_TCP ||
-                   ih->protocol == IPPROTO_UDP ||
-                   ih->protocol == IPPROTO_UDPLITE ||
-                   ih->protocol == IPPROTO_SCTP ||
-                   ih->protocol == IPPROTO_DCCP) {
-                       const struct tcpudphdr *pptr;
-                       struct tcpudphdr _ports;
-
-                       pptr = skb_header_pointer(skb, ih->ihl*4,
-                                                 sizeof(_ports), &_ports);
-                       if (pptr == NULL) {
-                               printk(" INCOMPLETE TCP/UDP header");
-                               goto out;
-                       }
-                       printk(" SPT=%u DPT=%u", ntohs(pptr->src),
-                          ntohs(pptr->dst));
+               print_ports(skb, ih->protocol, ih->ihl*4);
+               goto out;
+       }
+
+       if ((bitmask & EBT_LOG_IP6) && eth_hdr(skb)->h_proto ==
+          htons(ETH_P_IPV6)) {
+               const struct ipv6hdr *ih;
+               struct ipv6hdr _iph;
+               uint8_t nexthdr;
+               int offset_ph;
+
+               ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
+               if (ih == NULL) {
+                       printk(" INCOMPLETE IPv6 header");
+                       goto out;
                }
+               printk(" IPv6 SRC=%x:%x:%x:%x:%x:%x:%x:%x "
+                      "IPv6 DST=%x:%x:%x:%x:%x:%x:%x:%x, IPv6 "
+                      "priority=0x%01X, Next Header=%d", NIP6(ih->saddr),
+                      NIP6(ih->daddr), ih->priority, ih->nexthdr);
+               nexthdr = ih->nexthdr;
+               offset_ph = ipv6_skip_exthdr(skb, sizeof(_iph), &nexthdr);
+               if (offset_ph == -1)
+                       goto out;
+               print_ports(skb, nexthdr, offset_ph);
                goto out;
        }
 
index 90e2177af081ec724cad7bef0b72b4ba7e818d17..dccd737ea2e3396aa24824660b38095e78105f4e 100644 (file)
@@ -242,11 +242,11 @@ static ssize_t netstat_show(const struct device *d,
                        offset % sizeof(unsigned long) != 0);
 
        read_lock(&dev_base_lock);
-       if (dev_isalive(dev) && dev->get_stats &&
-           (stats = (*dev->get_stats)(dev)))
+       if (dev_isalive(dev)) {
+               stats = dev->get_stats(dev);
                ret = sprintf(buf, fmt_ulong,
                              *(unsigned long *)(((u8 *) stats) + offset));
-
+       }
        read_unlock(&dev_base_lock);
        return ret;
 }
@@ -457,8 +457,7 @@ int netdev_register_kobject(struct net_device *net)
        strlcpy(dev->bus_id, net->name, BUS_ID_SIZE);
 
 #ifdef CONFIG_SYSFS
-       if (net->get_stats)
-               *groups++ = &netstat_group;
+       *groups++ = &netstat_group;
 
 #ifdef CONFIG_WIRELESS_EXT
        if (net->wireless_handlers && net->wireless_handlers->get_wireless_stats)
index a9a77216310e028c2dfe1d125d2706c21c51630d..6c8d7f0ea01ab90678572ede2c06024c601d8008 100644 (file)
@@ -607,6 +607,8 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
 {
        struct ifinfomsg *ifm;
        struct nlmsghdr *nlh;
+       struct net_device_stats *stats;
+       struct nlattr *attr;
 
        nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags);
        if (nlh == NULL)
@@ -653,19 +655,13 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
                NLA_PUT(skb, IFLA_BROADCAST, dev->addr_len, dev->broadcast);
        }
 
-       if (dev->get_stats) {
-               struct net_device_stats *stats = dev->get_stats(dev);
-               if (stats) {
-                       struct nlattr *attr;
+       attr = nla_reserve(skb, IFLA_STATS,
+                       sizeof(struct rtnl_link_stats));
+       if (attr == NULL)
+               goto nla_put_failure;
 
-                       attr = nla_reserve(skb, IFLA_STATS,
-                                          sizeof(struct rtnl_link_stats));
-                       if (attr == NULL)
-                               goto nla_put_failure;
-
-                       copy_rtnl_link_stats(nla_data(attr), stats);
-               }
-       }
+       stats = dev->get_stats(dev);
+       copy_rtnl_link_stats(nla_data(attr), stats);
 
        if (dev->rtnl_link_ops) {
                if (rtnl_link_fill(skb, dev) < 0)
index 5fc801057244b797aafce24665147987cdd877ef..a570e2af22cb78d0994d41d19e83a29a5e7c5527 100644 (file)
@@ -124,14 +124,6 @@ static struct ctl_table net_core_table[] = {
        },
 #endif /* CONFIG_XFRM */
 #endif /* CONFIG_NET */
-       {
-               .ctl_name       = NET_CORE_SOMAXCONN,
-               .procname       = "somaxconn",
-               .data           = &init_net.core.sysctl_somaxconn,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = &proc_dointvec
-       },
        {
                .ctl_name       = NET_CORE_BUDGET,
                .procname       = "netdev_budget",
@@ -151,6 +143,18 @@ static struct ctl_table net_core_table[] = {
        { .ctl_name = 0 }
 };
 
+static struct ctl_table netns_core_table[] = {
+       {
+               .ctl_name       = NET_CORE_SOMAXCONN,
+               .procname       = "somaxconn",
+               .data           = &init_net.core.sysctl_somaxconn,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec
+       },
+       { .ctl_name = 0 }
+};
+
 static __net_initdata struct ctl_path net_core_path[] = {
        { .procname = "net", .ctl_name = CTL_NET, },
        { .procname = "core", .ctl_name = NET_CORE, },
@@ -159,23 +163,17 @@ static __net_initdata struct ctl_path net_core_path[] = {
 
 static __net_init int sysctl_core_net_init(struct net *net)
 {
-       struct ctl_table *tbl, *tmp;
+       struct ctl_table *tbl;
 
        net->core.sysctl_somaxconn = SOMAXCONN;
 
-       tbl = net_core_table;
+       tbl = netns_core_table;
        if (net != &init_net) {
-               tbl = kmemdup(tbl, sizeof(net_core_table), GFP_KERNEL);
+               tbl = kmemdup(tbl, sizeof(netns_core_table), GFP_KERNEL);
                if (tbl == NULL)
                        goto err_dup;
 
-               for (tmp = tbl; tmp->procname; tmp++) {
-                       if (tmp->data >= (void *)&init_net &&
-                                       tmp->data < (void *)(&init_net + 1))
-                               tmp->data += (char *)net - (char *)&init_net;
-                       else
-                               tmp->mode &= ~0222;
-               }
+               tbl[0].data = &net->core.sysctl_somaxconn;
        }
 
        net->core.sysctl_hdr = register_net_sysctl_table(net,
@@ -186,7 +184,7 @@ static __net_init int sysctl_core_net_init(struct net *net)
        return 0;
 
 err_reg:
-       if (tbl != net_core_table)
+       if (tbl != netns_core_table)
                kfree(tbl);
 err_dup:
        return -ENOMEM;
@@ -198,7 +196,7 @@ static __net_exit void sysctl_core_net_exit(struct net *net)
 
        tbl = net->core.sysctl_hdr->ctl_table_arg;
        unregister_net_sysctl_table(net->core.sysctl_hdr);
-       BUG_ON(tbl == net_core_table);
+       BUG_ON(tbl == netns_core_table);
        kfree(tbl);
 }
 
@@ -209,6 +207,7 @@ static __net_initdata struct pernet_operations sysctl_core_ops = {
 
 static __init int sysctl_core_init(void)
 {
+       register_net_sysctl_rotable(net_core_path, net_core_table);
        return register_pernet_subsys(&sysctl_core_ops);
 }
 
index 200ee1e6372878787c46b63227dff24642806ffe..69dbc342a4649271341946341b6231495e293c91 100644 (file)
@@ -391,7 +391,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
 
                wstats.updated = 0;
                if (rx_stats->mask & IEEE80211_STATMASK_RSSI) {
-                       wstats.level = rx_stats->rssi;
+                       wstats.level = rx_stats->signal;
                        wstats.updated |= IW_QUAL_LEVEL_UPDATED;
                } else
                        wstats.updated |= IW_QUAL_LEVEL_INVALID;
index d8b02603cbe5d9a86811b88c5510620cfec42a94..d996547f7a629564aeb4fb99164054a41165c746 100644 (file)
@@ -542,90 +542,4 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
        return 1;
 }
 
-/* Incoming 802.11 strucure is converted to a TXB
- * a block of 802.11 fragment packets (stored as skbs) */
-int ieee80211_tx_frame(struct ieee80211_device *ieee,
-                      struct ieee80211_hdr *frame, int hdr_len, int total_len,
-                      int encrypt_mpdu)
-{
-       struct ieee80211_txb *txb = NULL;
-       unsigned long flags;
-       struct net_device_stats *stats = &ieee->stats;
-       struct sk_buff *skb_frag;
-       int priority = -1;
-       int fraglen = total_len;
-       int headroom = ieee->tx_headroom;
-       struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx];
-
-       spin_lock_irqsave(&ieee->lock, flags);
-
-       if (encrypt_mpdu && (!ieee->sec.encrypt || !crypt))
-               encrypt_mpdu = 0;
-
-       /* If there is no driver handler to take the TXB, dont' bother
-        * creating it... */
-       if (!ieee->hard_start_xmit) {
-               printk(KERN_WARNING "%s: No xmit handler.\n", ieee->dev->name);
-               goto success;
-       }
-
-       if (unlikely(total_len < 24)) {
-               printk(KERN_WARNING "%s: skb too small (%d).\n",
-                      ieee->dev->name, total_len);
-               goto success;
-       }
-
-       if (encrypt_mpdu) {
-               frame->frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
-               fraglen += crypt->ops->extra_mpdu_prefix_len +
-                          crypt->ops->extra_mpdu_postfix_len;
-               headroom += crypt->ops->extra_mpdu_prefix_len;
-       }
-
-       /* When we allocate the TXB we allocate enough space for the reserve
-        * and full fragment bytes (bytes_per_frag doesn't include prefix,
-        * postfix, header, FCS, etc.) */
-       txb = ieee80211_alloc_txb(1, fraglen, headroom, GFP_ATOMIC);
-       if (unlikely(!txb)) {
-               printk(KERN_WARNING "%s: Could not allocate TXB\n",
-                      ieee->dev->name);
-               goto failed;
-       }
-       txb->encrypted = 0;
-       txb->payload_size = fraglen;
-
-       skb_frag = txb->fragments[0];
-
-       memcpy(skb_put(skb_frag, total_len), frame, total_len);
-
-       if (ieee->config &
-           (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
-               skb_put(skb_frag, 4);
-
-       /* To avoid overcomplicating things, we do the corner-case frame
-        * encryption in software. The only real situation where encryption is
-        * needed here is during software-based shared key authentication. */
-       if (encrypt_mpdu)
-               ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len);
-
-      success:
-       spin_unlock_irqrestore(&ieee->lock, flags);
-
-       if (txb) {
-               if ((*ieee->hard_start_xmit) (txb, ieee->dev, priority) == 0) {
-                       stats->tx_packets++;
-                       stats->tx_bytes += txb->payload_size;
-                       return 0;
-               }
-               ieee80211_txb_free(txb);
-       }
-       return 0;
-
-      failed:
-       spin_unlock_irqrestore(&ieee->lock, flags);
-       stats->tx_errors++;
-       return 1;
-}
-
-EXPORT_SYMBOL(ieee80211_tx_frame);
 EXPORT_SYMBOL(ieee80211_txb_free);
index 623489afa62c223e3f4b9d3ee1963c5aea2c1479..822606b615cae8851955f03011646478f9658fbb 100644 (file)
@@ -744,98 +744,9 @@ int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
        return 0;
 }
 
-int ieee80211_wx_set_auth(struct net_device *dev,
-                         struct iw_request_info *info,
-                         union iwreq_data *wrqu,
-                         char *extra)
-{
-       struct ieee80211_device *ieee = netdev_priv(dev);
-       unsigned long flags;
-       int err = 0;
-
-       spin_lock_irqsave(&ieee->lock, flags);
-
-       switch (wrqu->param.flags & IW_AUTH_INDEX) {
-       case IW_AUTH_WPA_VERSION:
-       case IW_AUTH_CIPHER_PAIRWISE:
-       case IW_AUTH_CIPHER_GROUP:
-       case IW_AUTH_KEY_MGMT:
-               /*
-                * Host AP driver does not use these parameters and allows
-                * wpa_supplicant to control them internally.
-                */
-               break;
-       case IW_AUTH_TKIP_COUNTERMEASURES:
-               break;          /* FIXME */
-       case IW_AUTH_DROP_UNENCRYPTED:
-               ieee->drop_unencrypted = !!wrqu->param.value;
-               break;
-       case IW_AUTH_80211_AUTH_ALG:
-               break;          /* FIXME */
-       case IW_AUTH_WPA_ENABLED:
-               ieee->privacy_invoked = ieee->wpa_enabled = !!wrqu->param.value;
-               break;
-       case IW_AUTH_RX_UNENCRYPTED_EAPOL:
-               ieee->ieee802_1x = !!wrqu->param.value;
-               break;
-       case IW_AUTH_PRIVACY_INVOKED:
-               ieee->privacy_invoked = !!wrqu->param.value;
-               break;
-       default:
-               err = -EOPNOTSUPP;
-               break;
-       }
-       spin_unlock_irqrestore(&ieee->lock, flags);
-       return err;
-}
-
-int ieee80211_wx_get_auth(struct net_device *dev,
-                         struct iw_request_info *info,
-                         union iwreq_data *wrqu,
-                         char *extra)
-{
-       struct ieee80211_device *ieee = netdev_priv(dev);
-       unsigned long flags;
-       int err = 0;
-
-       spin_lock_irqsave(&ieee->lock, flags);
-
-       switch (wrqu->param.flags & IW_AUTH_INDEX) {
-       case IW_AUTH_WPA_VERSION:
-       case IW_AUTH_CIPHER_PAIRWISE:
-       case IW_AUTH_CIPHER_GROUP:
-       case IW_AUTH_KEY_MGMT:
-       case IW_AUTH_TKIP_COUNTERMEASURES:              /* FIXME */
-       case IW_AUTH_80211_AUTH_ALG:                    /* FIXME */
-               /*
-                * Host AP driver does not use these parameters and allows
-                * wpa_supplicant to control them internally.
-                */
-               err = -EOPNOTSUPP;
-               break;
-       case IW_AUTH_DROP_UNENCRYPTED:
-               wrqu->param.value = ieee->drop_unencrypted;
-               break;
-       case IW_AUTH_WPA_ENABLED:
-               wrqu->param.value = ieee->wpa_enabled;
-               break;
-       case IW_AUTH_RX_UNENCRYPTED_EAPOL:
-               wrqu->param.value = ieee->ieee802_1x;
-               break;
-       default:
-               err = -EOPNOTSUPP;
-               break;
-       }
-       spin_unlock_irqrestore(&ieee->lock, flags);
-       return err;
-}
-
 EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
 EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
 
 EXPORT_SYMBOL(ieee80211_wx_get_scan);
 EXPORT_SYMBOL(ieee80211_wx_set_encode);
 EXPORT_SYMBOL(ieee80211_wx_get_encode);
-
-EXPORT_SYMBOL_GPL(ieee80211_wx_set_auth);
-EXPORT_SYMBOL_GPL(ieee80211_wx_get_auth);
index cd6ce6ac635843e4598e5332c32256bb0ff93926..be1cb89a8d5a880777e6730534ee374fcad6bc64 100644 (file)
@@ -598,7 +598,7 @@ int ip_defrag(struct sk_buff *skb, u32 user)
 #ifdef CONFIG_SYSCTL
 static int zero;
 
-static struct ctl_table ip4_frags_ctl_table[] = {
+static struct ctl_table ip4_frags_ns_ctl_table[] = {
        {
                .ctl_name       = NET_IPV4_IPFRAG_HIGH_THRESH,
                .procname       = "ipfrag_high_thresh",
@@ -624,6 +624,10 @@ static struct ctl_table ip4_frags_ctl_table[] = {
                .proc_handler   = &proc_dointvec_jiffies,
                .strategy       = &sysctl_jiffies
        },
+       { }
+};
+
+static struct ctl_table ip4_frags_ctl_table[] = {
        {
                .ctl_name       = NET_IPV4_IPFRAG_SECRET_INTERVAL,
                .procname       = "ipfrag_secret_interval",
@@ -644,22 +648,20 @@ static struct ctl_table ip4_frags_ctl_table[] = {
        { }
 };
 
-static int ip4_frags_ctl_register(struct net *net)
+static int ip4_frags_ns_ctl_register(struct net *net)
 {
        struct ctl_table *table;
        struct ctl_table_header *hdr;
 
-       table = ip4_frags_ctl_table;
+       table = ip4_frags_ns_ctl_table;
        if (net != &init_net) {
-               table = kmemdup(table, sizeof(ip4_frags_ctl_table), GFP_KERNEL);
+               table = kmemdup(table, sizeof(ip4_frags_ns_ctl_table), GFP_KERNEL);
                if (table == NULL)
                        goto err_alloc;
 
                table[0].data = &net->ipv4.frags.high_thresh;
                table[1].data = &net->ipv4.frags.low_thresh;
                table[2].data = &net->ipv4.frags.timeout;
-               table[3].mode &= ~0222;
-               table[4].mode &= ~0222;
        }
 
        hdr = register_net_sysctl_table(net, net_ipv4_ctl_path, table);
@@ -676,7 +678,7 @@ err_alloc:
        return -ENOMEM;
 }
 
-static void ip4_frags_ctl_unregister(struct net *net)
+static void ip4_frags_ns_ctl_unregister(struct net *net)
 {
        struct ctl_table *table;
 
@@ -684,13 +686,22 @@ static void ip4_frags_ctl_unregister(struct net *net)
        unregister_net_sysctl_table(net->ipv4.frags_hdr);
        kfree(table);
 }
+
+static void ip4_frags_ctl_register(void)
+{
+       register_net_sysctl_rotable(net_ipv4_ctl_path, ip4_frags_ctl_table);
+}
 #else
-static inline int ip4_frags_ctl_register(struct net *net)
+static inline int ip4_frags_ns_ctl_register(struct net *net)
 {
        return 0;
 }
 
-static inline void ip4_frags_ctl_unregister(struct net *net)
+static inline void ip4_frags_ns_ctl_unregister(struct net *net)
+{
+}
+
+static inline void ip4_frags_ctl_register(void)
 {
 }
 #endif
@@ -714,12 +725,12 @@ static int ipv4_frags_init_net(struct net *net)
 
        inet_frags_init_net(&net->ipv4.frags);
 
-       return ip4_frags_ctl_register(net);
+       return ip4_frags_ns_ctl_register(net);
 }
 
 static void ipv4_frags_exit_net(struct net *net)
 {
-       ip4_frags_ctl_unregister(net);
+       ip4_frags_ns_ctl_unregister(net);
        inet_frags_exit_net(&net->ipv4.frags, &ip4_frags);
 }
 
@@ -730,6 +741,7 @@ static struct pernet_operations ip4_frags_ops = {
 
 void __init ipfrag_init(void)
 {
+       ip4_frags_ctl_register();
        register_pernet_subsys(&ip4_frags_ops);
        ip4_frags.hashfn = ip4_hashfn;
        ip4_frags.constructor = ip4_frag_init;
index 4342cba4ff823bbddfe053d9583f31b9521d735d..2a61158ea7226cdff5d6b28fa0cbb0f6b2533d96 100644 (file)
@@ -473,6 +473,8 @@ static int ipgre_rcv(struct sk_buff *skb)
        read_lock(&ipgre_lock);
        if ((tunnel = ipgre_tunnel_lookup(dev_net(skb->dev),
                                        iph->saddr, iph->daddr, key)) != NULL) {
+               struct net_device_stats *stats = &tunnel->dev->stats;
+
                secpath_reset(skb);
 
                skb->protocol = *(__be16*)(h + 2);
@@ -497,28 +499,28 @@ static int ipgre_rcv(struct sk_buff *skb)
                        /* Looped back packet, drop it! */
                        if (skb->rtable->fl.iif == 0)
                                goto drop;
-                       tunnel->stat.multicast++;
+                       stats->multicast++;
                        skb->pkt_type = PACKET_BROADCAST;
                }
 #endif
 
                if (((flags&GRE_CSUM) && csum) ||
                    (!(flags&GRE_CSUM) && tunnel->parms.i_flags&GRE_CSUM)) {
-                       tunnel->stat.rx_crc_errors++;
-                       tunnel->stat.rx_errors++;
+                       stats->rx_crc_errors++;
+                       stats->rx_errors++;
                        goto drop;
                }
                if (tunnel->parms.i_flags&GRE_SEQ) {
                        if (!(flags&GRE_SEQ) ||
                            (tunnel->i_seqno && (s32)(seqno - tunnel->i_seqno) < 0)) {
-                               tunnel->stat.rx_fifo_errors++;
-                               tunnel->stat.rx_errors++;
+                               stats->rx_fifo_errors++;
+                               stats->rx_errors++;
                                goto drop;
                        }
                        tunnel->i_seqno = seqno + 1;
                }
-               tunnel->stat.rx_packets++;
-               tunnel->stat.rx_bytes += skb->len;
+               stats->rx_packets++;
+               stats->rx_bytes += skb->len;
                skb->dev = tunnel->dev;
                dst_release(skb->dst);
                skb->dst = NULL;
@@ -540,7 +542,7 @@ drop_nolock:
 static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct ip_tunnel *tunnel = netdev_priv(dev);
-       struct net_device_stats *stats = &tunnel->stat;
+       struct net_device_stats *stats = &tunnel->dev->stats;
        struct iphdr  *old_iph = ip_hdr(skb);
        struct iphdr  *tiph;
        u8     tos;
@@ -554,7 +556,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        int    mtu;
 
        if (tunnel->recursion++) {
-               tunnel->stat.collisions++;
+               stats->collisions++;
                goto tx_error;
        }
 
@@ -570,7 +572,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
                /* NBMA tunnel */
 
                if (skb->dst == NULL) {
-                       tunnel->stat.tx_fifo_errors++;
+                       stats->tx_fifo_errors++;
                        goto tx_error;
                }
 
@@ -621,7 +623,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
                                                .tos = RT_TOS(tos) } },
                                    .proto = IPPROTO_GRE };
                if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
-                       tunnel->stat.tx_carrier_errors++;
+                       stats->tx_carrier_errors++;
                        goto tx_error;
                }
        }
@@ -629,7 +631,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 
        if (tdev == dev) {
                ip_rt_put(rt);
-               tunnel->stat.collisions++;
+               stats->collisions++;
                goto tx_error;
        }
 
@@ -954,11 +956,6 @@ done:
        return err;
 }
 
-static struct net_device_stats *ipgre_tunnel_get_stats(struct net_device *dev)
-{
-       return &(((struct ip_tunnel*)netdev_priv(dev))->stat);
-}
-
 static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu)
 {
        struct ip_tunnel *tunnel = netdev_priv(dev);
@@ -1084,7 +1081,6 @@ static void ipgre_tunnel_setup(struct net_device *dev)
        dev->uninit             = ipgre_tunnel_uninit;
        dev->destructor         = free_netdev;
        dev->hard_start_xmit    = ipgre_tunnel_xmit;
-       dev->get_stats          = ipgre_tunnel_get_stats;
        dev->do_ioctl           = ipgre_tunnel_ioctl;
        dev->change_mtu         = ipgre_tunnel_change_mtu;
 
index af5cb53da5cccdd68350c9a83a66f3fdb81f71d3..86d8836551b9ba0eeb9f3751775d802c0f63725e 100644 (file)
@@ -368,8 +368,8 @@ static int ipip_rcv(struct sk_buff *skb)
                skb->protocol = htons(ETH_P_IP);
                skb->pkt_type = PACKET_HOST;
 
-               tunnel->stat.rx_packets++;
-               tunnel->stat.rx_bytes += skb->len;
+               tunnel->dev->stats.rx_packets++;
+               tunnel->dev->stats.rx_bytes += skb->len;
                skb->dev = tunnel->dev;
                dst_release(skb->dst);
                skb->dst = NULL;
@@ -392,7 +392,7 @@ static int ipip_rcv(struct sk_buff *skb)
 static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct ip_tunnel *tunnel = netdev_priv(dev);
-       struct net_device_stats *stats = &tunnel->stat;
+       struct net_device_stats *stats = &tunnel->dev->stats;
        struct iphdr  *tiph = &tunnel->parms.iph;
        u8     tos = tunnel->parms.iph.tos;
        __be16 df = tiph->frag_off;
@@ -405,7 +405,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        int    mtu;
 
        if (tunnel->recursion++) {
-               tunnel->stat.collisions++;
+               stats->collisions++;
                goto tx_error;
        }
 
@@ -418,7 +418,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        if (!dst) {
                /* NBMA tunnel */
                if ((rt = skb->rtable) == NULL) {
-                       tunnel->stat.tx_fifo_errors++;
+                       stats->tx_fifo_errors++;
                        goto tx_error;
                }
                if ((dst = rt->rt_gateway) == 0)
@@ -433,7 +433,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
                                                .tos = RT_TOS(tos) } },
                                    .proto = IPPROTO_IPIP };
                if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
-                       tunnel->stat.tx_carrier_errors++;
+                       stats->tx_carrier_errors++;
                        goto tx_error_icmp;
                }
        }
@@ -441,7 +441,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 
        if (tdev == dev) {
                ip_rt_put(rt);
-               tunnel->stat.collisions++;
+               stats->collisions++;
                goto tx_error;
        }
 
@@ -451,7 +451,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
                mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu;
 
        if (mtu < 68) {
-               tunnel->stat.collisions++;
+               stats->collisions++;
                ip_rt_put(rt);
                goto tx_error;
        }
@@ -685,11 +685,6 @@ done:
        return err;
 }
 
-static struct net_device_stats *ipip_tunnel_get_stats(struct net_device *dev)
-{
-       return &(((struct ip_tunnel*)netdev_priv(dev))->stat);
-}
-
 static int ipip_tunnel_change_mtu(struct net_device *dev, int new_mtu)
 {
        if (new_mtu < 68 || new_mtu > 0xFFF8 - sizeof(struct iphdr))
@@ -702,7 +697,6 @@ static void ipip_tunnel_setup(struct net_device *dev)
 {
        dev->uninit             = ipip_tunnel_uninit;
        dev->hard_start_xmit    = ipip_tunnel_xmit;
-       dev->get_stats          = ipip_tunnel_get_stats;
        dev->do_ioctl           = ipip_tunnel_ioctl;
        dev->change_mtu         = ipip_tunnel_change_mtu;
        dev->destructor         = free_netdev;
index 11700a4dcd95cb493b44f94336517eb50d4d73bb..a34da4977c738fb6fe7fa08a03cd8cfa9545ad6c 100644 (file)
@@ -181,26 +181,20 @@ static int reg_vif_num = -1;
 static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        read_lock(&mrt_lock);
-       ((struct net_device_stats*)netdev_priv(dev))->tx_bytes += skb->len;
-       ((struct net_device_stats*)netdev_priv(dev))->tx_packets++;
+       dev->stats.tx_bytes += skb->len;
+       dev->stats.tx_packets++;
        ipmr_cache_report(skb, reg_vif_num, IGMPMSG_WHOLEPKT);
        read_unlock(&mrt_lock);
        kfree_skb(skb);
        return 0;
 }
 
-static struct net_device_stats *reg_vif_get_stats(struct net_device *dev)
-{
-       return (struct net_device_stats*)netdev_priv(dev);
-}
-
 static void reg_vif_setup(struct net_device *dev)
 {
        dev->type               = ARPHRD_PIMREG;
        dev->mtu                = ETH_DATA_LEN - sizeof(struct iphdr) - 8;
        dev->flags              = IFF_NOARP;
        dev->hard_start_xmit    = reg_vif_xmit;
-       dev->get_stats          = reg_vif_get_stats;
        dev->destructor         = free_netdev;
 }
 
@@ -209,8 +203,7 @@ static struct net_device *ipmr_reg_vif(void)
        struct net_device *dev;
        struct in_device *in_dev;
 
-       dev = alloc_netdev(sizeof(struct net_device_stats), "pimreg",
-                          reg_vif_setup);
+       dev = alloc_netdev(0, "pimreg", reg_vif_setup);
 
        if (dev == NULL)
                return NULL;
@@ -1170,8 +1163,8 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi)
        if (vif->flags & VIFF_REGISTER) {
                vif->pkt_out++;
                vif->bytes_out+=skb->len;
-               ((struct net_device_stats*)netdev_priv(vif->dev))->tx_bytes += skb->len;
-               ((struct net_device_stats*)netdev_priv(vif->dev))->tx_packets++;
+               vif->dev->stats.tx_bytes += skb->len;
+               vif->dev->stats.tx_packets++;
                ipmr_cache_report(skb, vifi, IGMPMSG_WHOLEPKT);
                kfree_skb(skb);
                return;
@@ -1230,8 +1223,8 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi)
        if (vif->flags & VIFF_TUNNEL) {
                ip_encap(skb, vif->local, vif->remote);
                /* FIXME: extra output firewall step used to be here. --RR */
-               ((struct ip_tunnel *)netdev_priv(vif->dev))->stat.tx_packets++;
-               ((struct ip_tunnel *)netdev_priv(vif->dev))->stat.tx_bytes+=skb->len;
+               vif->dev->stats.tx_packets++;
+               vif->dev->stats.tx_bytes += skb->len;
        }
 
        IPCB(skb)->flags |= IPSKB_FORWARDED;
@@ -1487,8 +1480,8 @@ int pim_rcv_v1(struct sk_buff * skb)
        skb->pkt_type = PACKET_HOST;
        dst_release(skb->dst);
        skb->dst = NULL;
-       ((struct net_device_stats*)netdev_priv(reg_dev))->rx_bytes += skb->len;
-       ((struct net_device_stats*)netdev_priv(reg_dev))->rx_packets++;
+       reg_dev->stats.rx_bytes += skb->len;
+       reg_dev->stats.rx_packets++;
        nf_reset(skb);
        netif_rx(skb);
        dev_put(reg_dev);
@@ -1542,8 +1535,8 @@ static int pim_rcv(struct sk_buff * skb)
        skb->ip_summed = 0;
        skb->pkt_type = PACKET_HOST;
        dst_release(skb->dst);
-       ((struct net_device_stats*)netdev_priv(reg_dev))->rx_bytes += skb->len;
-       ((struct net_device_stats*)netdev_priv(reg_dev))->rx_packets++;
+       reg_dev->stats.rx_bytes += skb->len;
+       reg_dev->stats.rx_packets++;
        skb->dst = NULL;
        nf_reset(skb);
        netif_rx(skb);
index 2767841a8cefc19377a96506e2f2c4e1c2db7586..6e251402506e6e0b6e2e3c3c705060bd7d099e09 100644 (file)
@@ -365,6 +365,18 @@ config IP_NF_RAW
          If you want to compile it as a module, say M here and read
          <file:Documentation/kbuild/modules.txt>.  If unsure, say `N'.
 
+# security table for MAC policy
+config IP_NF_SECURITY
+       tristate "Security table"
+       depends on IP_NF_IPTABLES
+       depends on SECURITY
+       default m if NETFILTER_ADVANCED=n
+       help
+         This option adds a `security' table to iptables, for use
+         with Mandatory Access Control (MAC) policy.
+        
+         If unsure, say N.
+
 # ARP tables
 config IP_NF_ARPTABLES
        tristate "ARP tables support"
index d9b92fbf5579583918a7d5f01a1ea3ce0184b60a..3f31291f37ce7c6c68513eb269ccb87de09b3dac 100644 (file)
@@ -42,6 +42,7 @@ obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o
 obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o
 obj-$(CONFIG_NF_NAT) += iptable_nat.o
 obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
+obj-$(CONFIG_IP_NF_SECURITY) += iptable_security.o
 
 # matches
 obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
index 26a37cedcf2e3ab1ecb7620e02dd66be7754d961..aa33a4a7a7154e52de8f57e9906d4f6d62d15f63 100644 (file)
@@ -156,7 +156,6 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
        case IPQ_COPY_META:
        case IPQ_COPY_NONE:
                size = NLMSG_SPACE(sizeof(*pmsg));
-               data_len = 0;
                break;
 
        case IPQ_COPY_PACKET:
@@ -224,8 +223,6 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
        return skb;
 
 nlmsg_failure:
-       if (skb)
-               kfree_skb(skb);
        *errp = -EINVAL;
        printk(KERN_ERR "ip_queue: error creating packet message\n");
        return NULL;
diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c
new file mode 100644 (file)
index 0000000..2b472ac
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * "security" table
+ *
+ * This is for use by Mandatory Access Control (MAC) security models,
+ * which need to be able to manage security policy in separate context
+ * to DAC.
+ *
+ * Based on iptable_mangle.c
+ *
+ * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ * Copyright (C) 2000-2004 Netfilter Core Team <coreteam <at> netfilter.org>
+ * Copyright (C) 2008 Red Hat, Inc., James Morris <jmorris <at> redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <net/ip.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("James Morris <jmorris <at> redhat.com>");
+MODULE_DESCRIPTION("iptables security table, for MAC rules");
+
+#define SECURITY_VALID_HOOKS   (1 << NF_INET_LOCAL_IN) | \
+                               (1 << NF_INET_FORWARD) | \
+                               (1 << NF_INET_LOCAL_OUT)
+
+static struct
+{
+       struct ipt_replace repl;
+       struct ipt_standard entries[3];
+       struct ipt_error term;
+} initial_table __initdata = {
+       .repl = {
+               .name = "security",
+               .valid_hooks = SECURITY_VALID_HOOKS,
+               .num_entries = 4,
+               .size = sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error),
+               .hook_entry = {
+                       [NF_INET_LOCAL_IN]      = 0,
+                       [NF_INET_FORWARD]       = sizeof(struct ipt_standard),
+                       [NF_INET_LOCAL_OUT]     = sizeof(struct ipt_standard) * 2,
+               },
+               .underflow = {
+                       [NF_INET_LOCAL_IN]      = 0,
+                       [NF_INET_FORWARD]       = sizeof(struct ipt_standard),
+                       [NF_INET_LOCAL_OUT]     = sizeof(struct ipt_standard) * 2,
+               },
+       },
+       .entries = {
+               IPT_STANDARD_INIT(NF_ACCEPT),   /* LOCAL_IN */
+               IPT_STANDARD_INIT(NF_ACCEPT),   /* FORWARD */
+               IPT_STANDARD_INIT(NF_ACCEPT),   /* LOCAL_OUT */
+       },
+       .term = IPT_ERROR_INIT,                 /* ERROR */
+};
+
+static struct xt_table security_table = {
+       .name           = "security",
+       .valid_hooks    = SECURITY_VALID_HOOKS,
+       .lock           = __RW_LOCK_UNLOCKED(security_table.lock),
+       .me             = THIS_MODULE,
+       .af             = AF_INET,
+};
+
+static unsigned int
+ipt_local_in_hook(unsigned int hook,
+                 struct sk_buff *skb,
+                 const struct net_device *in,
+                 const struct net_device *out,
+                 int (*okfn)(struct sk_buff *))
+{
+       return ipt_do_table(skb, hook, in, out,
+                           nf_local_in_net(in, out)->ipv4.iptable_security);
+}
+
+static unsigned int
+ipt_forward_hook(unsigned int hook,
+                struct sk_buff *skb,
+                const struct net_device *in,
+                const struct net_device *out,
+                int (*okfn)(struct sk_buff *))
+{
+       return ipt_do_table(skb, hook, in, out,
+                           nf_forward_net(in, out)->ipv4.iptable_security);
+}
+
+static unsigned int
+ipt_local_out_hook(unsigned int hook,
+                  struct sk_buff *skb,
+                  const struct net_device *in,
+                  const struct net_device *out,
+                  int (*okfn)(struct sk_buff *))
+{
+       /* Somebody is playing with raw sockets. */
+       if (skb->len < sizeof(struct iphdr)
+           || ip_hdrlen(skb) < sizeof(struct iphdr)) {
+               if (net_ratelimit())
+                       printk(KERN_INFO "iptable_security: ignoring short "
+                              "SOCK_RAW packet.\n");
+               return NF_ACCEPT;
+       }
+       return ipt_do_table(skb, hook, in, out,
+                           nf_local_out_net(in, out)->ipv4.iptable_security);
+}
+
+static struct nf_hook_ops ipt_ops[] __read_mostly = {
+       {
+               .hook           = ipt_local_in_hook,
+               .owner          = THIS_MODULE,
+               .pf             = PF_INET,
+               .hooknum        = NF_INET_LOCAL_IN,
+               .priority       = NF_IP_PRI_SECURITY,
+       },
+       {
+               .hook           = ipt_forward_hook,
+               .owner          = THIS_MODULE,
+               .pf             = PF_INET,
+               .hooknum        = NF_INET_FORWARD,
+               .priority       = NF_IP_PRI_SECURITY,
+       },
+       {
+               .hook           = ipt_local_out_hook,
+               .owner          = THIS_MODULE,
+               .pf             = PF_INET,
+               .hooknum        = NF_INET_LOCAL_OUT,
+               .priority       = NF_IP_PRI_SECURITY,
+       },
+};
+
+static int __net_init iptable_security_net_init(struct net *net)
+{
+       net->ipv4.iptable_security =
+               ipt_register_table(net, &security_table, &initial_table.repl);
+
+       if (IS_ERR(net->ipv4.iptable_security))
+               return PTR_ERR(net->ipv4.iptable_security);
+
+       return 0;
+}
+
+static void __net_exit iptable_security_net_exit(struct net *net)
+{
+       ipt_unregister_table(net->ipv4.iptable_security);
+}
+
+static struct pernet_operations iptable_security_net_ops = {
+       .init = iptable_security_net_init,
+       .exit = iptable_security_net_exit,
+};
+
+static int __init iptable_security_init(void)
+{
+       int ret;
+
+       ret = register_pernet_subsys(&iptable_security_net_ops);
+        if (ret < 0)
+               return ret;
+
+       ret = nf_register_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
+       if (ret < 0)
+               goto cleanup_table;
+
+       return ret;
+
+cleanup_table:
+       unregister_pernet_subsys(&iptable_security_net_ops);
+       return ret;
+}
+
+static void __exit iptable_security_fini(void)
+{
+       nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
+       unregister_pernet_subsys(&iptable_security_net_ops);
+}
+
+module_init(iptable_security_init);
+module_exit(iptable_security_fini);
index 78ab19accace2ee84e282c534250920fad82ebce..97791048fa9b0c3fd7afc9802025ebe6db963cf5 100644 (file)
@@ -87,9 +87,8 @@ static int icmp_packet(struct nf_conn *ct,
           means this will only run once even if count hits zero twice
           (theoretically possible with SMP) */
        if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
-               if (atomic_dec_and_test(&ct->proto.icmp.count)
-                   && del_timer(&ct->timeout))
-                       ct->timeout.function((unsigned long)ct);
+               if (atomic_dec_and_test(&ct->proto.icmp.count))
+                       nf_ct_kill_acct(ct, ctinfo, skb);
        } else {
                atomic_inc(&ct->proto.icmp.count);
                nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
index 2bda3ba100b170122edc27d843d227976a3c30e9..37814810ac4943fdaf698315592457de84355c3e 100644 (file)
@@ -711,7 +711,7 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
                }
 
                if (!ip6_tnl_rcv_ctl(t)) {
-                       t->stat.rx_dropped++;
+                       t->dev->stats.rx_dropped++;
                        read_unlock(&ip6_tnl_lock);
                        goto discard;
                }
@@ -728,8 +728,8 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
 
                dscp_ecn_decapsulate(t, ipv6h, skb);
 
-               t->stat.rx_packets++;
-               t->stat.rx_bytes += skb->len;
+               t->dev->stats.rx_packets++;
+               t->dev->stats.rx_bytes += skb->len;
                netif_rx(skb);
                read_unlock(&ip6_tnl_lock);
                return 0;
@@ -849,7 +849,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
                         __u32 *pmtu)
 {
        struct ip6_tnl *t = netdev_priv(dev);
-       struct net_device_stats *stats = &t->stat;
+       struct net_device_stats *stats = &t->dev->stats;
        struct ipv6hdr *ipv6h = ipv6_hdr(skb);
        struct ipv6_tel_txoption opt;
        struct dst_entry *dst;
@@ -1043,11 +1043,11 @@ static int
 ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct ip6_tnl *t = netdev_priv(dev);
-       struct net_device_stats *stats = &t->stat;
+       struct net_device_stats *stats = &t->dev->stats;
        int ret;
 
        if (t->recursion++) {
-               t->stat.collisions++;
+               stats->collisions++;
                goto tx_err;
        }
 
@@ -1288,19 +1288,6 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        return err;
 }
 
-/**
- * ip6_tnl_get_stats - return the stats for tunnel device
- *   @dev: virtual device associated with tunnel
- *
- * Return: stats for device
- **/
-
-static struct net_device_stats *
-ip6_tnl_get_stats(struct net_device *dev)
-{
-       return &(((struct ip6_tnl *)netdev_priv(dev))->stat);
-}
-
 /**
  * ip6_tnl_change_mtu - change mtu manually for tunnel device
  *   @dev: virtual device associated with tunnel
@@ -1334,7 +1321,6 @@ static void ip6_tnl_dev_setup(struct net_device *dev)
        dev->uninit = ip6_tnl_dev_uninit;
        dev->destructor = free_netdev;
        dev->hard_start_xmit = ip6_tnl_xmit;
-       dev->get_stats = ip6_tnl_get_stats;
        dev->do_ioctl = ip6_tnl_ioctl;
        dev->change_mtu = ip6_tnl_change_mtu;
 
index 2de3c464fe75b4e3bf1a57fd148dcc739d123761..bf268b38696301cbfa7d3e43543acab578f28123 100644 (file)
@@ -388,8 +388,8 @@ static int pim6_rcv(struct sk_buff *skb)
        skb->ip_summed = 0;
        skb->pkt_type = PACKET_HOST;
        dst_release(skb->dst);
-       ((struct net_device_stats *)netdev_priv(reg_dev))->rx_bytes += skb->len;
-       ((struct net_device_stats *)netdev_priv(reg_dev))->rx_packets++;
+       reg_dev->stats.rx_bytes += skb->len;
+       reg_dev->stats.rx_packets++;
        skb->dst = NULL;
        nf_reset(skb);
        netif_rx(skb);
@@ -409,26 +409,20 @@ static struct inet6_protocol pim6_protocol = {
 static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        read_lock(&mrt_lock);
-       ((struct net_device_stats *)netdev_priv(dev))->tx_bytes += skb->len;
-       ((struct net_device_stats *)netdev_priv(dev))->tx_packets++;
+       dev->stats.tx_bytes += skb->len;
+       dev->stats.tx_packets++;
        ip6mr_cache_report(skb, reg_vif_num, MRT6MSG_WHOLEPKT);
        read_unlock(&mrt_lock);
        kfree_skb(skb);
        return 0;
 }
 
-static struct net_device_stats *reg_vif_get_stats(struct net_device *dev)
-{
-       return (struct net_device_stats *)netdev_priv(dev);
-}
-
 static void reg_vif_setup(struct net_device *dev)
 {
        dev->type               = ARPHRD_PIMREG;
        dev->mtu                = 1500 - sizeof(struct ipv6hdr) - 8;
        dev->flags              = IFF_NOARP;
        dev->hard_start_xmit    = reg_vif_xmit;
-       dev->get_stats          = reg_vif_get_stats;
        dev->destructor         = free_netdev;
 }
 
@@ -436,9 +430,7 @@ static struct net_device *ip6mr_reg_vif(void)
 {
        struct net_device *dev;
 
-       dev = alloc_netdev(sizeof(struct net_device_stats), "pim6reg",
-                          reg_vif_setup);
-
+       dev = alloc_netdev(0, "pim6reg", reg_vif_setup);
        if (dev == NULL)
                return NULL;
 
@@ -1377,8 +1369,8 @@ static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi)
        if (vif->flags & MIFF_REGISTER) {
                vif->pkt_out++;
                vif->bytes_out += skb->len;
-               ((struct net_device_stats *)netdev_priv(vif->dev))->tx_bytes += skb->len;
-               ((struct net_device_stats *)netdev_priv(vif->dev))->tx_packets++;
+               vif->dev->stats.tx_bytes += skb->len;
+               vif->dev->stats.tx_packets++;
                ip6mr_cache_report(skb, vifi, MRT6MSG_WHOLEPKT);
                kfree_skb(skb);
                return 0;
index 6cae5475737e530c94024c9b3a70f820b020f64a..689dec899c57d441ad362fa720d35e2c055e0978 100644 (file)
@@ -208,5 +208,17 @@ config IP6_NF_RAW
          If you want to compile it as a module, say M here and read
          <file:Documentation/kbuild/modules.txt>.  If unsure, say `N'.
 
+# security table for MAC policy
+config IP6_NF_SECURITY
+       tristate "Security table"
+       depends on IP6_NF_IPTABLES
+       depends on SECURITY
+       default m if NETFILTER_ADVANCED=n
+       help
+         This option adds a `security' table to iptables, for use
+         with Mandatory Access Control (MAC) policy.
+        
+         If unsure, say N.
+
 endmenu
 
index fbf2c14ed887942aa316b274124b698010260007..3f17c948eefb10113964b24ff45fed58ccfd86b2 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
 obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
 obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
 obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
+obj-$(CONFIG_IP6_NF_SECURITY) += ip6table_security.o
 
 # objects for l3 independent conntrack
 nf_conntrack_ipv6-objs  :=  nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o nf_conntrack_reasm.o
index 2eff3ae8977dd3a0fd8b7c0d3858ac076cb27b28..1b8815f6153d14980e9e51ae2c816b1f1d9199ae 100644 (file)
@@ -159,7 +159,6 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
        case IPQ_COPY_META:
        case IPQ_COPY_NONE:
                size = NLMSG_SPACE(sizeof(*pmsg));
-               data_len = 0;
                break;
 
        case IPQ_COPY_PACKET:
@@ -226,8 +225,6 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
        return skb;
 
 nlmsg_failure:
-       if (skb)
-               kfree_skb(skb);
        *errp = -EINVAL;
        printk(KERN_ERR "ip6_queue: error creating packet message\n");
        return NULL;
diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c
new file mode 100644 (file)
index 0000000..063a3d9
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * "security" table for IPv6
+ *
+ * This is for use by Mandatory Access Control (MAC) security models,
+ * which need to be able to manage security policy in separate context
+ * to DAC.
+ *
+ * Based on iptable_mangle.c
+ *
+ * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ * Copyright (C) 2000-2004 Netfilter Core Team <coreteam <at> netfilter.org>
+ * Copyright (C) 2008 Red Hat, Inc., James Morris <jmorris <at> redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("James Morris <jmorris <at> redhat.com>");
+MODULE_DESCRIPTION("ip6tables security table, for MAC rules");
+
+#define SECURITY_VALID_HOOKS   (1 << NF_INET_LOCAL_IN) | \
+                               (1 << NF_INET_FORWARD) | \
+                               (1 << NF_INET_LOCAL_OUT)
+
+static struct
+{
+       struct ip6t_replace repl;
+       struct ip6t_standard entries[3];
+       struct ip6t_error term;
+} initial_table __initdata = {
+       .repl = {
+               .name = "security",
+               .valid_hooks = SECURITY_VALID_HOOKS,
+               .num_entries = 4,
+               .size = sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error),
+               .hook_entry = {
+                       [NF_INET_LOCAL_IN]      = 0,
+                       [NF_INET_FORWARD]       = sizeof(struct ip6t_standard),
+                       [NF_INET_LOCAL_OUT]     = sizeof(struct ip6t_standard) * 2,
+               },
+               .underflow = {
+                       [NF_INET_LOCAL_IN]      = 0,
+                       [NF_INET_FORWARD]       = sizeof(struct ip6t_standard),
+                       [NF_INET_LOCAL_OUT]     = sizeof(struct ip6t_standard) * 2,
+               },
+       },
+       .entries = {
+               IP6T_STANDARD_INIT(NF_ACCEPT),  /* LOCAL_IN */
+               IP6T_STANDARD_INIT(NF_ACCEPT),  /* FORWARD */
+               IP6T_STANDARD_INIT(NF_ACCEPT),  /* LOCAL_OUT */
+       },
+       .term = IP6T_ERROR_INIT,                /* ERROR */
+};
+
+static struct xt_table security_table = {
+       .name           = "security",
+       .valid_hooks    = SECURITY_VALID_HOOKS,
+       .lock           = __RW_LOCK_UNLOCKED(security_table.lock),
+       .me             = THIS_MODULE,
+       .af             = AF_INET6,
+};
+
+static unsigned int
+ip6t_local_in_hook(unsigned int hook,
+                  struct sk_buff *skb,
+                  const struct net_device *in,
+                  const struct net_device *out,
+                  int (*okfn)(struct sk_buff *))
+{
+       return ip6t_do_table(skb, hook, in, out,
+                            init_net.ipv6.ip6table_security);
+}
+
+static unsigned int
+ip6t_forward_hook(unsigned int hook,
+                 struct sk_buff *skb,
+                 const struct net_device *in,
+                 const struct net_device *out,
+                 int (*okfn)(struct sk_buff *))
+{
+       return ip6t_do_table(skb, hook, in, out,
+                            init_net.ipv6.ip6table_security);
+}
+
+static unsigned int
+ip6t_local_out_hook(unsigned int hook,
+                   struct sk_buff *skb,
+                   const struct net_device *in,
+                   const struct net_device *out,
+                   int (*okfn)(struct sk_buff *))
+{
+       /* TBD: handle short packets via raw socket */
+       return ip6t_do_table(skb, hook, in, out,
+                            init_net.ipv6.ip6table_security);
+}
+
+static struct nf_hook_ops ip6t_ops[] __read_mostly = {
+       {
+               .hook           = ip6t_local_in_hook,
+               .owner          = THIS_MODULE,
+               .pf             = PF_INET6,
+               .hooknum        = NF_INET_LOCAL_IN,
+               .priority       = NF_IP6_PRI_SECURITY,
+       },
+       {
+               .hook           = ip6t_forward_hook,
+               .owner          = THIS_MODULE,
+               .pf             = PF_INET6,
+               .hooknum        = NF_INET_FORWARD,
+               .priority       = NF_IP6_PRI_SECURITY,
+       },
+       {
+               .hook           = ip6t_local_out_hook,
+               .owner          = THIS_MODULE,
+               .pf             = PF_INET6,
+               .hooknum        = NF_INET_LOCAL_OUT,
+               .priority       = NF_IP6_PRI_SECURITY,
+       },
+};
+
+static int __net_init ip6table_security_net_init(struct net *net)
+{
+       net->ipv6.ip6table_security =
+               ip6t_register_table(net, &security_table, &initial_table.repl);
+
+       if (IS_ERR(net->ipv6.ip6table_security))
+               return PTR_ERR(net->ipv6.ip6table_security);
+
+       return 0;
+}
+
+static void __net_exit ip6table_security_net_exit(struct net *net)
+{
+       ip6t_unregister_table(net->ipv6.ip6table_security);
+}
+
+static struct pernet_operations ip6table_security_net_ops = {
+       .init = ip6table_security_net_init,
+       .exit = ip6table_security_net_exit,
+};
+
+static int __init ip6table_security_init(void)
+{
+       int ret;
+
+       ret = register_pernet_subsys(&ip6table_security_net_ops);
+       if (ret < 0)
+               return ret;
+
+       ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
+       if (ret < 0)
+               goto cleanup_table;
+
+       return ret;
+
+cleanup_table:
+       unregister_pernet_subsys(&ip6table_security_net_ops);
+       return ret;
+}
+
+static void __exit ip6table_security_fini(void)
+{
+       nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
+       unregister_pernet_subsys(&ip6table_security_net_ops);
+}
+
+module_init(ip6table_security_init);
+module_exit(ip6table_security_fini);
index ee713b03e9ec81f252dc0b45a499a2769583ba55..14d47d833545913d72c4453e28f7cc260689edb3 100644 (file)
@@ -89,9 +89,8 @@ static int icmpv6_packet(struct nf_conn *ct,
           means this will only run once even if count hits zero twice
           (theoretically possible with SMP) */
        if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
-               if (atomic_dec_and_test(&ct->proto.icmp.count)
-                   && del_timer(&ct->timeout))
-                       ct->timeout.function((unsigned long)ct);
+               if (atomic_dec_and_test(&ct->proto.icmp.count))
+                       nf_ct_kill_acct(ct, ctinfo, skb);
        } else {
                atomic_inc(&ct->proto.icmp.count);
                nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
index 798cabc7535b747d9193ce20e1dce1907e18eb8f..9391a6949b96f7d432f69b405fa9acf1dd5ee190 100644 (file)
@@ -632,7 +632,7 @@ static struct inet6_protocol frag_protocol =
 };
 
 #ifdef CONFIG_SYSCTL
-static struct ctl_table ip6_frags_ctl_table[] = {
+static struct ctl_table ip6_frags_ns_ctl_table[] = {
        {
                .ctl_name       = NET_IPV6_IP6FRAG_HIGH_THRESH,
                .procname       = "ip6frag_high_thresh",
@@ -658,6 +658,10 @@ static struct ctl_table ip6_frags_ctl_table[] = {
                .proc_handler   = &proc_dointvec_jiffies,
                .strategy       = &sysctl_jiffies,
        },
+       { }
+};
+
+static struct ctl_table ip6_frags_ctl_table[] = {
        {
                .ctl_name       = NET_IPV6_IP6FRAG_SECRET_INTERVAL,
                .procname       = "ip6frag_secret_interval",
@@ -670,21 +674,20 @@ static struct ctl_table ip6_frags_ctl_table[] = {
        { }
 };
 
-static int ip6_frags_sysctl_register(struct net *net)
+static int ip6_frags_ns_sysctl_register(struct net *net)
 {
        struct ctl_table *table;
        struct ctl_table_header *hdr;
 
-       table = ip6_frags_ctl_table;
+       table = ip6_frags_ns_ctl_table;
        if (net != &init_net) {
-               table = kmemdup(table, sizeof(ip6_frags_ctl_table), GFP_KERNEL);
+               table = kmemdup(table, sizeof(ip6_frags_ns_ctl_table), GFP_KERNEL);
                if (table == NULL)
                        goto err_alloc;
 
                table[0].data = &net->ipv6.frags.high_thresh;
                table[1].data = &net->ipv6.frags.low_thresh;
                table[2].data = &net->ipv6.frags.timeout;
-               table[3].mode &= ~0222;
        }
 
        hdr = register_net_sysctl_table(net, net_ipv6_ctl_path, table);
@@ -701,7 +704,7 @@ err_alloc:
        return -ENOMEM;
 }
 
-static void ip6_frags_sysctl_unregister(struct net *net)
+static void ip6_frags_ns_sysctl_unregister(struct net *net)
 {
        struct ctl_table *table;
 
@@ -709,13 +712,36 @@ static void ip6_frags_sysctl_unregister(struct net *net)
        unregister_net_sysctl_table(net->ipv6.sysctl.frags_hdr);
        kfree(table);
 }
+
+static struct ctl_table_header *ip6_ctl_header;
+
+static int ip6_frags_sysctl_register(void)
+{
+       ip6_ctl_header = register_net_sysctl_rotable(net_ipv6_ctl_path,
+                       ip6_frags_ctl_table);
+       return ip6_ctl_header == NULL ? -ENOMEM : 0;
+}
+
+static void ip6_frags_sysctl_unregister(void)
+{
+       unregister_net_sysctl_table(ip6_ctl_header);
+}
 #else
-static inline int ip6_frags_sysctl_register(struct net *net)
+static inline int ip6_frags_ns_sysctl_register(struct net *net)
 {
        return 0;
 }
 
-static inline void ip6_frags_sysctl_unregister(struct net *net)
+static inline void ip6_frags_ns_sysctl_unregister(struct net *net)
+{
+}
+
+static inline int ip6_frags_sysctl_register(void)
+{
+       return 0;
+}
+
+static inline void ip6_frags_sysctl_unregister(void)
 {
 }
 #endif
@@ -728,12 +754,12 @@ static int ipv6_frags_init_net(struct net *net)
 
        inet_frags_init_net(&net->ipv6.frags);
 
-       return ip6_frags_sysctl_register(net);
+       return ip6_frags_ns_sysctl_register(net);
 }
 
 static void ipv6_frags_exit_net(struct net *net)
 {
-       ip6_frags_sysctl_unregister(net);
+       ip6_frags_ns_sysctl_unregister(net);
        inet_frags_exit_net(&net->ipv6.frags, &ip6_frags);
 }
 
@@ -750,7 +776,13 @@ int __init ipv6_frag_init(void)
        if (ret)
                goto out;
 
-       register_pernet_subsys(&ip6_frags_ops);
+       ret = ip6_frags_sysctl_register();
+       if (ret)
+               goto err_sysctl;
+
+       ret = register_pernet_subsys(&ip6_frags_ops);
+       if (ret)
+               goto err_pernet;
 
        ip6_frags.hashfn = ip6_hashfn;
        ip6_frags.constructor = ip6_frag_init;
@@ -763,11 +795,18 @@ int __init ipv6_frag_init(void)
        inet_frags_init(&ip6_frags);
 out:
        return ret;
+
+err_pernet:
+       ip6_frags_sysctl_unregister();
+err_sysctl:
+       inet6_del_protocol(&frag_protocol, IPPROTO_FRAGMENT);
+       goto out;
 }
 
 void ipv6_frag_exit(void)
 {
        inet_frags_fini(&ip6_frags);
+       ip6_frags_sysctl_unregister();
        unregister_pernet_subsys(&ip6_frags_ops);
        inet6_del_protocol(&frag_protocol, IPPROTO_FRAGMENT);
 }
index 3de6ffdaedf2ff234a2f16ddaaacce7e4a481aef..6b8f0583b63735e53e1d8269f55a3f171d039004 100644 (file)
@@ -491,13 +491,13 @@ static int ipip6_rcv(struct sk_buff *skb)
 
                if ((tunnel->dev->priv_flags & IFF_ISATAP) &&
                    !isatap_chksrc(skb, iph, tunnel)) {
-                       tunnel->stat.rx_errors++;
+                       tunnel->dev->stats.rx_errors++;
                        read_unlock(&ipip6_lock);
                        kfree_skb(skb);
                        return 0;
                }
-               tunnel->stat.rx_packets++;
-               tunnel->stat.rx_bytes += skb->len;
+               tunnel->dev->stats.rx_packets++;
+               tunnel->dev->stats.rx_bytes += skb->len;
                skb->dev = tunnel->dev;
                dst_release(skb->dst);
                skb->dst = NULL;
@@ -537,7 +537,7 @@ static inline __be32 try_6to4(struct in6_addr *v6dst)
 static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct ip_tunnel *tunnel = netdev_priv(dev);
-       struct net_device_stats *stats = &tunnel->stat;
+       struct net_device_stats *stats = &tunnel->dev->stats;
        struct iphdr  *tiph = &tunnel->parms.iph;
        struct ipv6hdr *iph6 = ipv6_hdr(skb);
        u8     tos = tunnel->parms.iph.tos;
@@ -551,7 +551,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        int addr_type;
 
        if (tunnel->recursion++) {
-               tunnel->stat.collisions++;
+               stats->collisions++;
                goto tx_error;
        }
 
@@ -618,20 +618,20 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
                                    .oif = tunnel->parms.link,
                                    .proto = IPPROTO_IPV6 };
                if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
-                       tunnel->stat.tx_carrier_errors++;
+                       stats->tx_carrier_errors++;
                        goto tx_error_icmp;
                }
        }
        if (rt->rt_type != RTN_UNICAST) {
                ip_rt_put(rt);
-               tunnel->stat.tx_carrier_errors++;
+               stats->tx_carrier_errors++;
                goto tx_error_icmp;
        }
        tdev = rt->u.dst.dev;
 
        if (tdev == dev) {
                ip_rt_put(rt);
-               tunnel->stat.collisions++;
+               stats->collisions++;
                goto tx_error;
        }
 
@@ -641,7 +641,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
                mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu;
 
        if (mtu < 68) {
-               tunnel->stat.collisions++;
+               stats->collisions++;
                ip_rt_put(rt);
                goto tx_error;
        }
@@ -916,11 +916,6 @@ done:
        return err;
 }
 
-static struct net_device_stats *ipip6_tunnel_get_stats(struct net_device *dev)
-{
-       return &(((struct ip_tunnel*)netdev_priv(dev))->stat);
-}
-
 static int ipip6_tunnel_change_mtu(struct net_device *dev, int new_mtu)
 {
        if (new_mtu < IPV6_MIN_MTU || new_mtu > 0xFFF8 - sizeof(struct iphdr))
@@ -934,7 +929,6 @@ static void ipip6_tunnel_setup(struct net_device *dev)
        dev->uninit             = ipip6_tunnel_uninit;
        dev->destructor         = free_netdev;
        dev->hard_start_xmit    = ipip6_tunnel_xmit;
-       dev->get_stats          = ipip6_tunnel_get_stats;
        dev->do_ioctl           = ipip6_tunnel_ioctl;
        dev->change_mtu         = ipip6_tunnel_change_mtu;
 
index 3804dcbbfab0f46cc0cfcfd852482e4eb529e312..5c99274558bf40412b738c4c71484c2a082e7029 100644 (file)
@@ -37,6 +37,10 @@ static ctl_table ipv6_table_template[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec
        },
+       { .ctl_name = 0 }
+};
+
+static ctl_table ipv6_table[] = {
        {
                .ctl_name       = NET_IPV6_MLD_MAX_MSF,
                .procname       = "mld_max_msf",
@@ -80,12 +84,6 @@ static int ipv6_sysctl_net_init(struct net *net)
 
        ipv6_table[2].data = &net->ipv6.sysctl.bindv6only;
 
-       /* We don't want this value to be per namespace, it should be global
-          to all namespaces, so make it read-only when we are not in the
-          init network namespace */
-       if (net != &init_net)
-               ipv6_table[3].mode = 0444;
-
        net->ipv6.sysctl.table = register_net_sysctl_table(net, net_ipv6_ctl_path,
                                                           ipv6_table);
        if (!net->ipv6.sysctl.table)
@@ -126,12 +124,29 @@ static struct pernet_operations ipv6_sysctl_net_ops = {
        .exit = ipv6_sysctl_net_exit,
 };
 
+static struct ctl_table_header *ip6_header;
+
 int ipv6_sysctl_register(void)
 {
-       return register_pernet_subsys(&ipv6_sysctl_net_ops);
+       int err = -ENOMEM;;
+
+       ip6_header = register_net_sysctl_rotable(net_ipv6_ctl_path, ipv6_table);
+       if (ip6_header == NULL)
+               goto out;
+
+       err = register_pernet_subsys(&ipv6_sysctl_net_ops);
+       if (err)
+               goto err_pernet;
+out:
+       return err;
+
+err_pernet:
+       unregister_net_sysctl_table(ip6_header);
+       goto out;
 }
 
 void ipv6_sysctl_unregister(void)
 {
+       unregister_net_sysctl_table(ip6_header);
        unregister_pernet_subsys(&ipv6_sysctl_net_ops);
 }
index e0eab5927c4f434d6210711525ac9b14ba34599e..f6e54fa97f47286ad43e247909b15a4b22339db9 100644 (file)
@@ -628,8 +628,8 @@ dev_irnet_poll(struct file *        file,
  * This is the way pppd configure us and control us while the PPP
  * instance is active.
  */
-static int
-dev_irnet_ioctl(struct inode * inode,
+static long
+dev_irnet_ioctl(
                struct file *   file,
                unsigned int    cmd,
                unsigned long   arg)
@@ -660,6 +660,7 @@ dev_irnet_ioctl(struct inode *      inode,
        {
          DEBUG(FS_INFO, "Entering PPP discipline.\n");
          /* PPP channel setup (ap->chan in configued in dev_irnet_open())*/
+         lock_kernel();
          err = ppp_register_channel(&ap->chan);
          if(err == 0)
            {
@@ -672,12 +673,14 @@ dev_irnet_ioctl(struct inode *    inode,
            }
          else
            DERROR(FS_ERROR, "Can't setup PPP channel...\n");
+          unlock_kernel();
        }
       else
        {
          /* In theory, should be N_TTY */
          DEBUG(FS_INFO, "Exiting PPP discipline.\n");
          /* Disconnect from the generic PPP layer */
+         lock_kernel();
          if(ap->ppp_open)
            {
              ap->ppp_open = 0;
@@ -686,24 +689,20 @@ dev_irnet_ioctl(struct inode *    inode,
          else
            DERROR(FS_ERROR, "Channel not registered !\n");
          err = 0;
+         unlock_kernel();
        }
       break;
 
       /* Query PPP channel and unit number */
     case PPPIOCGCHAN:
-      if(!ap->ppp_open)
-       break;
-      if(put_user(ppp_channel_index(&ap->chan), (int __user *)argp))
-       break;
-      DEBUG(FS_INFO, "Query channel.\n");
-      err = 0;
+      if(ap->ppp_open && !put_user(ppp_channel_index(&ap->chan),
+                                               (int __user *)argp))
+       err = 0;
       break;
     case PPPIOCGUNIT:
-      if(!ap->ppp_open)
-       break;
-      if(put_user(ppp_unit_number(&ap->chan), (int __user *)argp))
-       break;
-      DEBUG(FS_INFO, "Query unit number.\n");
+      lock_kernel();
+      if(ap->ppp_open && !put_user(ppp_unit_number(&ap->chan),
+                                               (int __user *)argp))
       err = 0;
       break;
 
@@ -723,34 +722,39 @@ dev_irnet_ioctl(struct inode *    inode,
       DEBUG(FS_INFO, "Standard PPP ioctl.\n");
       if(!capable(CAP_NET_ADMIN))
        err = -EPERM;
-      else
+      else {
+       lock_kernel();
        err = ppp_irnet_ioctl(&ap->chan, cmd, arg);
+       unlock_kernel();
+      }
       break;
 
       /* TTY IOCTLs : Pretend that we are a tty, to keep pppd happy */
       /* Get termios */
     case TCGETS:
       DEBUG(FS_INFO, "Get termios.\n");
+      lock_kernel();
 #ifndef TCGETS2
-      if(kernel_termios_to_user_termios((struct termios __user *)argp, &ap->termios))
-       break;
+      if(!kernel_termios_to_user_termios((struct termios __user *)argp, &ap->termios))
+       err = 0;
 #else
       if(kernel_termios_to_user_termios_1((struct termios __user *)argp, &ap->termios))
-       break;
+       err = 0;
 #endif
-      err = 0;
+      unlock_kernel();
       break;
       /* Set termios */
     case TCSETSF:
       DEBUG(FS_INFO, "Set termios.\n");
+      lock_kernel();
 #ifndef TCGETS2
-      if(user_termios_to_kernel_termios(&ap->termios, (struct termios __user *)argp))
-       break;
+      if(!user_termios_to_kernel_termios(&ap->termios, (struct termios __user *)argp))
+       err = 0;
 #else
-      if(user_termios_to_kernel_termios_1(&ap->termios, (struct termios __user *)argp))
-       break;
+      if(!user_termios_to_kernel_termios_1(&ap->termios, (struct termios __user *)argp))
+       err = 0;
 #endif
-      err = 0;
+      unlock_kernel();
       break;
 
       /* Set DTR/RTS */
@@ -773,7 +777,9 @@ dev_irnet_ioctl(struct inode *      inode,
        * We should also worry that we don't accept junk here and that
        * we get rid of our own buffers */
 #ifdef FLUSH_TO_PPP
+      lock_kernel();
       ppp_output_wakeup(&ap->chan);
+      unlock_kernel();
 #endif /* FLUSH_TO_PPP */
       err = 0;
       break;
@@ -788,7 +794,7 @@ dev_irnet_ioctl(struct inode *      inode,
 
     default:
       DERROR(FS_ERROR, "Unsupported ioctl (0x%X)\n", cmd);
-      err = -ENOIOCTLCMD;
+      err = -ENOTTY;
     }
 
   DEXIT(FS_TRACE, " - err = 0x%X\n", err);
index d2beb7df8f7fdd5d09176efd6b3ea8e4884b6b5a..d9f8bd4ebd05fcfb5040f527c5d8cb7eee5ac738 100644 (file)
@@ -76,9 +76,8 @@ static ssize_t
 static unsigned int
        dev_irnet_poll(struct file *,
                       poll_table *);
-static int
-       dev_irnet_ioctl(struct inode *,
-                       struct file *,
+static long
+       dev_irnet_ioctl(struct file *,
                        unsigned int,
                        unsigned long);
 /* ------------------------ PPP INTERFACE ------------------------ */
@@ -102,7 +101,7 @@ static struct file_operations irnet_device_fops =
        .read           = dev_irnet_read,
        .write          = dev_irnet_write,
        .poll           = dev_irnet_poll,
-       .ioctl          = dev_irnet_ioctl,
+       .unlocked_ioctl = dev_irnet_ioctl,
        .open           = dev_irnet_open,
        .release        = dev_irnet_close
   /* Also : llseek, readdir, mmap, flush, fsync, fasync, lock, readv, writev */
index 7b0038f45b168c3aab1e2f236dd62584542c0331..58e4aee3e6961d2c37273faa830d3590a344be3b 100644 (file)
@@ -644,6 +644,7 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
                }
 
                txmsg.class = 0;
+               memcpy(&txmsg.class, skb->data, skb->len >= 4 ? 4 : skb->len);
                txmsg.tag = iucv->send_tag++;
                memcpy(skb->cb, &txmsg.tag, 4);
                skb_queue_tail(&iucv->send_skb_q, skb);
index 91897076213158bbad89db5f8cacc1b2b49acc74..531a206ce7a6ee78e4b3e7b00faaa10a7a8809bd 100644 (file)
@@ -474,14 +474,14 @@ static void iucv_setmask_mp(void)
 {
        int cpu;
 
-       preempt_disable();
+       get_online_cpus();
        for_each_online_cpu(cpu)
                /* Enable all cpus with a declared buffer. */
                if (cpu_isset(cpu, iucv_buffer_cpumask) &&
                    !cpu_isset(cpu, iucv_irq_cpumask))
                        smp_call_function_single(cpu, iucv_allow_cpu,
                                                 NULL, 0, 1);
-       preempt_enable();
+       put_online_cpus();
 }
 
 /**
@@ -521,16 +521,17 @@ static int iucv_enable(void)
                goto out;
        /* Declare per cpu buffers. */
        rc = -EIO;
-       preempt_disable();
+       get_online_cpus();
        for_each_online_cpu(cpu)
                smp_call_function_single(cpu, iucv_declare_cpu, NULL, 0, 1);
-       preempt_enable();
        if (cpus_empty(iucv_buffer_cpumask))
                /* No cpu could declare an iucv buffer. */
                goto out_path;
+       put_online_cpus();
        return 0;
 
 out_path:
+       put_online_cpus();
        kfree(iucv_path_table);
 out:
        return rc;
@@ -545,7 +546,9 @@ out:
  */
 static void iucv_disable(void)
 {
+       get_online_cpus();
        on_each_cpu(iucv_retrieve_cpu, NULL, 0, 1);
+       put_online_cpus();
        kfree(iucv_path_table);
 }
 
@@ -598,7 +601,7 @@ static int __cpuinit iucv_cpu_notify(struct notifier_block *self,
        return NOTIFY_OK;
 }
 
-static struct notifier_block __cpuinitdata iucv_cpu_notifier = {
+static struct notifier_block __refdata iucv_cpu_notifier = {
        .notifier_call = iucv_cpu_notify,
 };
 
index a24b459dd45aecf9ba8e1214fce68fe2b8330c6c..590e00b2766c8dbee2600dd33fd6d2b485d7bc46 100644 (file)
@@ -7,11 +7,23 @@ config MAC80211
        select CRC32
        select WIRELESS_EXT
        select CFG80211
-       select NET_SCH_FIFO
        ---help---
          This option enables the hardware independent IEEE 802.11
          networking stack.
 
+config MAC80211_QOS
+       def_bool y
+       depends on MAC80211
+       depends on NET_SCHED
+       depends on NETDEVICES_MULTIQUEUE
+
+comment "QoS/HT support disabled"
+       depends on MAC80211 && !MAC80211_QOS
+comment "QoS/HT support needs CONFIG_NET_SCHED"
+       depends on MAC80211 && !NET_SCHED
+comment "QoS/HT support needs CONFIG_NETDEVICES_MULTIQUEUE"
+       depends on MAC80211 && !NETDEVICES_MULTIQUEUE
+
 menu "Rate control algorithm selection"
        depends on MAC80211 != n
 
index 4e5847fd316c9870180720e815d7284793194526..1d2a4e010e5c1513cb1f51eea51dcfca49d6e637 100644 (file)
@@ -29,7 +29,7 @@ mac80211-y := \
        event.o
 
 mac80211-$(CONFIG_MAC80211_LEDS) += led.o
-mac80211-$(CONFIG_NET_SCHED) += wme.o
+mac80211-$(CONFIG_MAC80211_QOS) += wme.o
 mac80211-$(CONFIG_MAC80211_DEBUGFS) += \
        debugfs.o \
        debugfs_sta.o \
index 59f1691f62c89abcfef52f4b2bbc3156cb4c1062..4d4c2dfcf9a0340b9225531576136fd1df595c41 100644 (file)
@@ -134,7 +134,7 @@ int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
 }
 
 
-struct crypto_cipher * ieee80211_aes_key_setup_encrypt(const u8 key[])
+struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[])
 {
        struct crypto_cipher *tfm;
 
index 885f19030b29ba1260fab169a7db8cf73c0973f5..8cd0f14aab4d8adf8156c47ebefe55d965412006 100644 (file)
@@ -14,7 +14,7 @@
 
 #define AES_BLOCK_LEN 16
 
-struct crypto_cipher * ieee80211_aes_key_setup_encrypt(const u8 key[]);
+struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[]);
 void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
                               u8 *b_0, u8 *aad, u8 *data, size_t data_len,
                               u8 *cdata, u8 *mic);
index a9fce4afdf211b785753da1ea74f03546fc14d14..81087281b031834bae498c77ded78f6081d767c2 100644 (file)
@@ -256,8 +256,8 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
        case ALG_TKIP:
                params.cipher = WLAN_CIPHER_SUITE_TKIP;
 
-               iv32 = key->u.tkip.iv32;
-               iv16 = key->u.tkip.iv16;
+               iv32 = key->u.tkip.tx.iv32;
+               iv16 = key->u.tkip.tx.iv16;
 
                if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
                    sdata->local->ops->get_tkip_seq)
@@ -602,6 +602,7 @@ static void sta_apply_parameters(struct ieee80211_local *local,
         */
 
        if (params->station_flags & STATION_FLAG_CHANGED) {
+               spin_lock_bh(&sta->lock);
                sta->flags &= ~WLAN_STA_AUTHORIZED;
                if (params->station_flags & STATION_FLAG_AUTHORIZED)
                        sta->flags |= WLAN_STA_AUTHORIZED;
@@ -613,6 +614,7 @@ static void sta_apply_parameters(struct ieee80211_local *local,
                sta->flags &= ~WLAN_STA_WME;
                if (params->station_flags & STATION_FLAG_WME)
                        sta->flags |= WLAN_STA_WME;
+               spin_unlock_bh(&sta->lock);
        }
 
        /*
index 1cccbfd781f67e651dd72ff0423a2eaaae616eda..d20d90eead1f95ea90755045a87814fcecb4bb43 100644 (file)
@@ -197,45 +197,6 @@ DEBUGFS_STATS_FILE(rx_handlers_fragments, 20, "%u",
 DEBUGFS_STATS_FILE(tx_status_drop, 20, "%u",
                   local->tx_status_drop);
 
-static ssize_t stats_wme_rx_queue_read(struct file *file,
-                                      char __user *userbuf,
-                                      size_t count, loff_t *ppos)
-{
-       struct ieee80211_local *local = file->private_data;
-       char buf[NUM_RX_DATA_QUEUES*15], *p = buf;
-       int i;
-
-       for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
-               p += scnprintf(p, sizeof(buf)+buf-p,
-                              "%u\n", local->wme_rx_queue[i]);
-
-       return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf);
-}
-
-static const struct file_operations stats_wme_rx_queue_ops = {
-       .read = stats_wme_rx_queue_read,
-       .open = mac80211_open_file_generic,
-};
-
-static ssize_t stats_wme_tx_queue_read(struct file *file,
-                                      char __user *userbuf,
-                                      size_t count, loff_t *ppos)
-{
-       struct ieee80211_local *local = file->private_data;
-       char buf[NUM_TX_DATA_QUEUES*15], *p = buf;
-       int i;
-
-       for (i = 0; i < NUM_TX_DATA_QUEUES; i++)
-               p += scnprintf(p, sizeof(buf)+buf-p,
-                              "%u\n", local->wme_tx_queue[i]);
-
-       return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf);
-}
-
-static const struct file_operations stats_wme_tx_queue_ops = {
-       .read = stats_wme_tx_queue_read,
-       .open = mac80211_open_file_generic,
-};
 #endif
 
 DEBUGFS_DEVSTATS_FILE(dot11ACKFailureCount);
@@ -303,8 +264,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
        DEBUGFS_STATS_ADD(rx_expand_skb_head2);
        DEBUGFS_STATS_ADD(rx_handlers_fragments);
        DEBUGFS_STATS_ADD(tx_status_drop);
-       DEBUGFS_STATS_ADD(wme_tx_queue);
-       DEBUGFS_STATS_ADD(wme_rx_queue);
 #endif
        DEBUGFS_STATS_ADD(dot11ACKFailureCount);
        DEBUGFS_STATS_ADD(dot11RTSFailureCount);
@@ -356,8 +315,6 @@ void debugfs_hw_del(struct ieee80211_local *local)
        DEBUGFS_STATS_DEL(rx_expand_skb_head2);
        DEBUGFS_STATS_DEL(rx_handlers_fragments);
        DEBUGFS_STATS_DEL(tx_status_drop);
-       DEBUGFS_STATS_DEL(wme_tx_queue);
-       DEBUGFS_STATS_DEL(wme_rx_queue);
 #endif
        DEBUGFS_STATS_DEL(dot11ACKFailureCount);
        DEBUGFS_STATS_DEL(dot11RTSFailureCount);
index 19efc3a6a9327cfd343ab5e62de2a993ec6821bf..7439b63df5d0b72db616e3cf012e310a9720147c 100644 (file)
@@ -97,8 +97,8 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
                break;
        case ALG_TKIP:
                len = scnprintf(buf, sizeof(buf), "%08x %04x\n",
-                               key->u.tkip.iv32,
-                               key->u.tkip.iv16);
+                               key->u.tkip.tx.iv32,
+                               key->u.tkip.tx.iv16);
                break;
        case ALG_CCMP:
                tpn = key->u.ccmp.tx_pn;
@@ -128,8 +128,8 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
                for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
                        p += scnprintf(p, sizeof(buf)+buf-p,
                                       "%08x %04x\n",
-                                      key->u.tkip.iv32_rx[i],
-                                      key->u.tkip.iv16_rx[i]);
+                                      key->u.tkip.rx[i].iv32,
+                                      key->u.tkip.rx[i].iv16);
                len = p - buf;
                break;
        case ALG_CCMP:
index e3326d046944129d0b8f872591b27006cfb3f95f..b2089b2da48a2c6b0f6e963532335558109c4ecb 100644 (file)
@@ -155,7 +155,6 @@ static const struct file_operations name##_ops = {                  \
                __IEEE80211_IF_WFILE(name)
 
 /* common attributes */
-IEEE80211_IF_FILE(channel_use, channel_use, DEC);
 IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
 
 /* STA/IBSS attributes */
@@ -248,7 +247,6 @@ IEEE80211_IF_WFILE(min_discovery_timeout,
 
 static void add_sta_files(struct ieee80211_sub_if_data *sdata)
 {
-       DEBUGFS_ADD(channel_use, sta);
        DEBUGFS_ADD(drop_unencrypted, sta);
        DEBUGFS_ADD(state, sta);
        DEBUGFS_ADD(bssid, sta);
@@ -269,7 +267,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
 
 static void add_ap_files(struct ieee80211_sub_if_data *sdata)
 {
-       DEBUGFS_ADD(channel_use, ap);
        DEBUGFS_ADD(drop_unencrypted, ap);
        DEBUGFS_ADD(num_sta_ps, ap);
        DEBUGFS_ADD(dtim_count, ap);
@@ -281,14 +278,12 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
 
 static void add_wds_files(struct ieee80211_sub_if_data *sdata)
 {
-       DEBUGFS_ADD(channel_use, wds);
        DEBUGFS_ADD(drop_unencrypted, wds);
        DEBUGFS_ADD(peer, wds);
 }
 
 static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
 {
-       DEBUGFS_ADD(channel_use, vlan);
        DEBUGFS_ADD(drop_unencrypted, vlan);
 }
 
@@ -376,7 +371,6 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
 
 static void del_sta_files(struct ieee80211_sub_if_data *sdata)
 {
-       DEBUGFS_DEL(channel_use, sta);
        DEBUGFS_DEL(drop_unencrypted, sta);
        DEBUGFS_DEL(state, sta);
        DEBUGFS_DEL(bssid, sta);
@@ -397,7 +391,6 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata)
 
 static void del_ap_files(struct ieee80211_sub_if_data *sdata)
 {
-       DEBUGFS_DEL(channel_use, ap);
        DEBUGFS_DEL(drop_unencrypted, ap);
        DEBUGFS_DEL(num_sta_ps, ap);
        DEBUGFS_DEL(dtim_count, ap);
@@ -409,14 +402,12 @@ static void del_ap_files(struct ieee80211_sub_if_data *sdata)
 
 static void del_wds_files(struct ieee80211_sub_if_data *sdata)
 {
-       DEBUGFS_DEL(channel_use, wds);
        DEBUGFS_DEL(drop_unencrypted, wds);
        DEBUGFS_DEL(peer, wds);
 }
 
 static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
 {
-       DEBUGFS_DEL(channel_use, vlan);
        DEBUGFS_DEL(drop_unencrypted, vlan);
 }
 
@@ -528,7 +519,7 @@ void ieee80211_debugfs_change_if_type(struct ieee80211_sub_if_data *sdata,
        add_files(sdata);
 }
 
-static int netdev_notify(struct notifier_block * nb,
+static int netdev_notify(struct notifier_block *nb,
                         unsigned long state,
                         void *ndev)
 {
index 6d47a1d31b37a550164e424ca9571b67709418db..79a062782d52e2da757532901a29017e9f420d4e 100644 (file)
@@ -63,10 +63,9 @@ STA_FILE(tx_fragments, tx_fragments, LU);
 STA_FILE(tx_filtered, tx_filtered_count, LU);
 STA_FILE(tx_retry_failed, tx_retry_failed, LU);
 STA_FILE(tx_retry_count, tx_retry_count, LU);
-STA_FILE(last_rssi, last_rssi, D);
 STA_FILE(last_signal, last_signal, D);
+STA_FILE(last_qual, last_qual, D);
 STA_FILE(last_noise, last_noise, D);
-STA_FILE(channel_use, channel_use, D);
 STA_FILE(wep_weak_iv_count, wep_weak_iv_count, LU);
 
 static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
@@ -74,14 +73,15 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
 {
        char buf[100];
        struct sta_info *sta = file->private_data;
+       u32 staflags = get_sta_flags(sta);
        int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s",
-               sta->flags & WLAN_STA_AUTH ? "AUTH\n" : "",
-               sta->flags & WLAN_STA_ASSOC ? "ASSOC\n" : "",
-               sta->flags & WLAN_STA_PS ? "PS\n" : "",
-               sta->flags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "",
-               sta->flags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "",
-               sta->flags & WLAN_STA_WME ? "WME\n" : "",
-               sta->flags & WLAN_STA_WDS ? "WDS\n" : "");
+               staflags & WLAN_STA_AUTH ? "AUTH\n" : "",
+               staflags & WLAN_STA_ASSOC ? "ASSOC\n" : "",
+               staflags & WLAN_STA_PS ? "PS\n" : "",
+               staflags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "",
+               staflags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "",
+               staflags & WLAN_STA_WME ? "WME\n" : "",
+               staflags & WLAN_STA_WDS ? "WDS\n" : "");
        return simple_read_from_buffer(userbuf, count, ppos, buf, res);
 }
 STA_OPS(flags);
@@ -123,36 +123,6 @@ static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf,
 }
 STA_OPS(last_seq_ctrl);
 
-#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
-static ssize_t sta_wme_rx_queue_read(struct file *file, char __user *userbuf,
-                                    size_t count, loff_t *ppos)
-{
-       char buf[15*NUM_RX_DATA_QUEUES], *p = buf;
-       int i;
-       struct sta_info *sta = file->private_data;
-       for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
-               p += scnprintf(p, sizeof(buf)+buf-p, "%u ",
-                              sta->wme_rx_queue[i]);
-       p += scnprintf(p, sizeof(buf)+buf-p, "\n");
-       return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
-}
-STA_OPS(wme_rx_queue);
-
-static ssize_t sta_wme_tx_queue_read(struct file *file, char __user *userbuf,
-                                    size_t count, loff_t *ppos)
-{
-       char buf[15*NUM_TX_DATA_QUEUES], *p = buf;
-       int i;
-       struct sta_info *sta = file->private_data;
-       for (i = 0; i < NUM_TX_DATA_QUEUES; i++)
-               p += scnprintf(p, sizeof(buf)+buf-p, "%u ",
-                              sta->wme_tx_queue[i]);
-       p += scnprintf(p, sizeof(buf)+buf-p, "\n");
-       return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
-}
-STA_OPS(wme_tx_queue);
-#endif
-
 static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
                                        size_t count, loff_t *ppos)
 {
@@ -293,10 +263,6 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
        DEBUGFS_ADD(num_ps_buf_frames);
        DEBUGFS_ADD(inactive_ms);
        DEBUGFS_ADD(last_seq_ctrl);
-#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
-       DEBUGFS_ADD(wme_rx_queue);
-       DEBUGFS_ADD(wme_tx_queue);
-#endif
        DEBUGFS_ADD(agg_status);
 }
 
@@ -306,10 +272,6 @@ void ieee80211_sta_debugfs_remove(struct sta_info *sta)
        DEBUGFS_DEL(num_ps_buf_frames);
        DEBUGFS_DEL(inactive_ms);
        DEBUGFS_DEL(last_seq_ctrl);
-#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
-       DEBUGFS_DEL(wme_rx_queue);
-       DEBUGFS_DEL(wme_tx_queue);
-#endif
        DEBUGFS_DEL(agg_status);
 
        debugfs_remove(sta->debugfs.dir);
index 006486b267261fa3f18b6dc3e1bb8f53f7e46efb..884be4d100f11fe1c022f743c4d3d60690420b52 100644 (file)
@@ -2,6 +2,7 @@
  * Copyright 2002-2005, Instant802 Networks, Inc.
  * Copyright 2005, Devicescape Software, Inc.
  * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007-2008 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
@@ -82,7 +83,7 @@ struct ieee80211_sta_bss {
        u16 capability; /* host byte order */
        enum ieee80211_band band;
        int freq;
-       int rssi, signal, noise;
+       int signal, noise, qual;
        u8 *wpa_ie;
        size_t wpa_ie_len;
        u8 *rsn_ie;
@@ -91,6 +92,8 @@ struct ieee80211_sta_bss {
        size_t wmm_ie_len;
        u8 *ht_ie;
        size_t ht_ie_len;
+       u8 *ht_add_ie;
+       size_t ht_add_ie_len;
 #ifdef CONFIG_MAC80211_MESH
        u8 *mesh_id;
        size_t mesh_id_len;
@@ -147,7 +150,6 @@ typedef unsigned __bitwise__ ieee80211_tx_result;
 #define IEEE80211_TX_UNICAST           BIT(1)
 #define IEEE80211_TX_PS_BUFFERED       BIT(2)
 #define IEEE80211_TX_PROBE_LAST_FRAG   BIT(3)
-#define IEEE80211_TX_INJECTED          BIT(4)
 
 struct ieee80211_tx_data {
        struct sk_buff *skb;
@@ -157,13 +159,12 @@ struct ieee80211_tx_data {
        struct sta_info *sta;
        struct ieee80211_key *key;
 
-       struct ieee80211_tx_control *control;
        struct ieee80211_channel *channel;
-       struct ieee80211_rate *rate;
+       s8 rate_idx;
        /* use this rate (if set) for last fragment; rate can
         * be set to lower rate for the first fragments, e.g.,
         * when using CTS protection with IEEE 802.11g. */
-       struct ieee80211_rate *last_frag_rate;
+       s8 last_frag_rate_idx;
 
        /* Extra fragments (in addition to the first fragment
         * in skb) */
@@ -202,32 +203,16 @@ struct ieee80211_rx_data {
        unsigned int flags;
        int sent_ps_buffered;
        int queue;
-       int load;
        u32 tkip_iv32;
        u16 tkip_iv16;
 };
 
-/* flags used in struct ieee80211_tx_packet_data.flags */
-#define IEEE80211_TXPD_REQ_TX_STATUS   BIT(0)
-#define IEEE80211_TXPD_DO_NOT_ENCRYPT  BIT(1)
-#define IEEE80211_TXPD_REQUEUE         BIT(2)
-#define IEEE80211_TXPD_EAPOL_FRAME     BIT(3)
-#define IEEE80211_TXPD_AMPDU           BIT(4)
-/* Stored in sk_buff->cb */
-struct ieee80211_tx_packet_data {
-       int ifindex;
-       unsigned long jiffies;
-       unsigned int flags;
-       u8 queue;
-};
-
 struct ieee80211_tx_stored_packet {
-       struct ieee80211_tx_control control;
        struct sk_buff *skb;
        struct sk_buff **extra_frag;
-       struct ieee80211_rate *last_frag_rate;
+       s8 last_frag_rate_idx;
        int num_extra_frag;
-       unsigned int last_frag_rate_ctrl_probe;
+       bool last_frag_rate_ctrl_probe;
 };
 
 struct beacon_data {
@@ -464,14 +449,11 @@ struct ieee80211_sub_if_data {
                struct ieee80211_if_sta sta;
                u32 mntr_flags;
        } u;
-       int channel_use;
-       int channel_use_raw;
 
 #ifdef CONFIG_MAC80211_DEBUGFS
        struct dentry *debugfsdir;
        union {
                struct {
-                       struct dentry *channel_use;
                        struct dentry *drop_unencrypted;
                        struct dentry *state;
                        struct dentry *bssid;
@@ -490,7 +472,6 @@ struct ieee80211_sub_if_data {
                        struct dentry *num_beacons_sta;
                } sta;
                struct {
-                       struct dentry *channel_use;
                        struct dentry *drop_unencrypted;
                        struct dentry *num_sta_ps;
                        struct dentry *dtim_count;
@@ -500,12 +481,10 @@ struct ieee80211_sub_if_data {
                        struct dentry *num_buffered_multicast;
                } ap;
                struct {
-                       struct dentry *channel_use;
                        struct dentry *drop_unencrypted;
                        struct dentry *peer;
                } wds;
                struct {
-                       struct dentry *channel_use;
                        struct dentry *drop_unencrypted;
                } vlan;
                struct {
@@ -610,8 +589,8 @@ struct ieee80211_local {
        struct sta_info *sta_hash[STA_HASH_SIZE];
        struct timer_list sta_cleanup;
 
-       unsigned long state[NUM_TX_DATA_QUEUES_AMPDU];
-       struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES_AMPDU];
+       unsigned long queues_pending[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)];
+       struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_QUEUES];
        struct tasklet_struct tx_pending_tasklet;
 
        /* number of interfaces with corresponding IFF_ flags */
@@ -677,9 +656,6 @@ struct ieee80211_local {
             assoc_led_name[32], radio_led_name[32];
 #endif
 
-       u32 channel_use;
-       u32 channel_use_raw;
-
 #ifdef CONFIG_MAC80211_DEBUGFS
        struct work_struct sta_debugfs_add;
 #endif
@@ -705,8 +681,6 @@ struct ieee80211_local {
        unsigned int rx_expand_skb_head2;
        unsigned int rx_handlers_fragments;
        unsigned int tx_status_drop;
-       unsigned int wme_rx_queue[NUM_RX_DATA_QUEUES];
-       unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES];
 #define I802_DEBUG_INC(c) (c)++
 #else /* CONFIG_MAC80211_DEBUG_COUNTERS */
 #define I802_DEBUG_INC(c) do { } while (0)
@@ -764,8 +738,6 @@ struct ieee80211_local {
                        struct dentry *rx_expand_skb_head2;
                        struct dentry *rx_handlers_fragments;
                        struct dentry *tx_status_drop;
-                       struct dentry *wme_tx_queue;
-                       struct dentry *wme_rx_queue;
 #endif
                        struct dentry *dot11ACKFailureCount;
                        struct dentry *dot11RTSFailureCount;
@@ -778,6 +750,15 @@ struct ieee80211_local {
 #endif
 };
 
+static inline int ieee80211_is_multiqueue(struct ieee80211_local *local)
+{
+#ifdef CONFIG_MAC80211_QOS
+       return netif_is_multiqueue(local->mdev);
+#else
+       return 0;
+#endif
+}
+
 /* this struct represents 802.11n's RA/TID combination */
 struct ieee80211_ra_tid {
        u8 ra[ETH_ALEN];
@@ -847,11 +828,6 @@ static inline struct ieee80211_hw *local_to_hw(
        return &local->hw;
 }
 
-enum ieee80211_link_state_t {
-       IEEE80211_LINK_STATE_XOFF = 0,
-       IEEE80211_LINK_STATE_PENDING,
-};
-
 struct sta_attribute {
        struct attribute attr;
        ssize_t (*show)(const struct sta_info *, char *buf);
@@ -878,7 +854,6 @@ u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht,
 /* ieee80211_ioctl.c */
 extern const struct iw_handler_def ieee80211_iw_handler_def;
 
-
 /* Least common multiple of the used rates (in 100 kbps). This is used to
  * calculate rate_inv values for each rate so that only integers are needed. */
 #define CHAN_UTIL_RATE_LCM 95040
@@ -900,6 +875,7 @@ extern const struct iw_handler_def ieee80211_iw_handler_def;
 
 /* ieee80211_ioctl.c */
 int ieee80211_set_freq(struct net_device *dev, int freq);
+
 /* ieee80211_sta.c */
 void ieee80211_sta_timer(unsigned long data);
 void ieee80211_sta_work(struct work_struct *work);
@@ -919,9 +895,9 @@ ieee80211_rx_result ieee80211_sta_rx_scan(
 void ieee80211_rx_bss_list_init(struct net_device *dev);
 void ieee80211_rx_bss_list_deinit(struct net_device *dev);
 int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len);
-struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev,
-                                        struct sk_buff *skb, u8 *bssid,
-                                        u8 *addr);
+struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev,
+                                       struct sk_buff *skb, u8 *bssid,
+                                       u8 *addr);
 int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason);
 int ieee80211_sta_disassociate(struct net_device *dev, u16 reason);
 void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
@@ -940,7 +916,6 @@ void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
 
 void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *da,
                                u16 tid, u16 initiator, u16 reason);
-void sta_rx_agg_session_timer_expired(unsigned long data);
 void sta_addba_resp_timer_expired(unsigned long data);
 void ieee80211_sta_tear_down_BA_sessions(struct net_device *dev, u8 *addr);
 u64 ieee80211_sta_get_rates(struct ieee80211_local *local,
index 06e88a5a036d2ebce586a94f0bf7a635ca8a6405..98447270238149d7c0b8b1cdc3fab8ecba0b7aee 100644 (file)
@@ -33,9 +33,8 @@ static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata)
 {
        int i;
 
-       for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) {
+       for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
                __skb_queue_purge(&sdata->fragments[i].skb_list);
-       }
 }
 
 /* Must be called with rtnl lock held. */
@@ -167,9 +166,10 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
                ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |
                        IEEE80211_AUTH_ALG_SHARED_KEY;
                ifsta->flags |= IEEE80211_STA_CREATE_IBSS |
-                       IEEE80211_STA_WMM_ENABLED |
                        IEEE80211_STA_AUTO_BSSID_SEL |
                        IEEE80211_STA_AUTO_CHANNEL_SEL;
+               if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4)
+                       ifsta->flags |= IEEE80211_STA_WMM_ENABLED;
 
                msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev);
                sdata->bss = &msdata->u.ap;
index 150d66dbda9d22de6ca0b94c48eab7e70c3f733f..d4893bd177548a33c3cbbfd0fd54bab6d5a933e4 100644 (file)
@@ -321,8 +321,15 @@ void ieee80211_key_link(struct ieee80211_key *key,
                 * some hardware cannot handle TKIP with QoS, so
                 * we indicate whether QoS could be in use.
                 */
-               if (sta->flags & WLAN_STA_WME)
+               if (test_sta_flags(sta, WLAN_STA_WME))
                        key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA;
+
+               /*
+                * This key is for a specific sta interface,
+                * inform the driver that it should try to store
+                * this key as pairwise key.
+                */
+               key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
        } else {
                if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
                        struct sta_info *ap;
@@ -335,7 +342,7 @@ void ieee80211_key_link(struct ieee80211_key *key,
                        /* same here, the AP could be using QoS */
                        ap = sta_info_get(key->local, key->sdata->u.sta.bssid);
                        if (ap) {
-                               if (ap->flags & WLAN_STA_WME)
+                               if (test_sta_flags(ap, WLAN_STA_WME))
                                        key->conf.flags |=
                                                IEEE80211_KEY_FLAG_WMM_STA;
                        }
index f52c3df1fe9ae38795a1f8d6c99d874a819a785b..a0f774aafa455709f3184cb017a105c54d35ede3 100644 (file)
@@ -69,6 +69,13 @@ enum ieee80211_internal_key_flags {
        KEY_FLAG_TODO_ADD_DEBUGFS       = BIT(5),
 };
 
+struct tkip_ctx {
+       u32 iv32;
+       u16 iv16;
+       u16 p1k[5];
+       int initialized;
+};
+
 struct ieee80211_key {
        struct ieee80211_local *local;
        struct ieee80211_sub_if_data *sdata;
@@ -85,16 +92,10 @@ struct ieee80211_key {
        union {
                struct {
                        /* last used TSC */
-                       u32 iv32;
-                       u16 iv16;
-                       u16 p1k[5];
-                       int tx_initialized;
+                       struct tkip_ctx tx;
 
                        /* last received RSC */
-                       u32 iv32_rx[NUM_RX_DATA_QUEUES];
-                       u16 iv16_rx[NUM_RX_DATA_QUEUES];
-                       u16 p1k_rx[NUM_RX_DATA_QUEUES][5];
-                       int rx_initialized[NUM_RX_DATA_QUEUES];
+                       struct tkip_ctx rx[NUM_RX_DATA_QUEUES];
                } tkip;
                struct {
                        u8 tx_pn[6];
index 98c0b5e56ecc02e50a754dd0b77303dac9b6160c..b182f018a1878833a40c9c67f4f55e76845fe92c 100644 (file)
@@ -35,8 +35,6 @@
 #include "debugfs.h"
 #include "debugfs_netdev.h"
 
-#define SUPP_MCS_SET_LEN 16
-
 /*
  * For seeing transmitted packets on monitor interfaces
  * we have a radiotap header too.
@@ -112,7 +110,13 @@ static int ieee80211_master_open(struct net_device *dev)
                        break;
                }
        }
-       return res;
+
+       if (res)
+               return res;
+
+       netif_start_queue(local->mdev);
+
+       return 0;
 }
 
 static int ieee80211_master_stop(struct net_device *dev)
@@ -346,6 +350,7 @@ static int ieee80211_open(struct net_device *dev)
                        goto err_del_interface;
                }
 
+               /* no locking required since STA is not live yet */
                sta->flags |= WLAN_STA_AUTHORIZED;
 
                res = sta_info_insert(sta);
@@ -385,8 +390,8 @@ static int ieee80211_open(struct net_device *dev)
         * yet be effective. Trigger execution of ieee80211_sta_work
         * to fix this.
         */
-       if(sdata->vif.type == IEEE80211_IF_TYPE_STA ||
-          sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+       if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+           sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
                struct ieee80211_if_sta *ifsta = &sdata->u.sta;
                queue_work(local->hw.workqueue, &ifsta->work);
        }
@@ -585,16 +590,16 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
        sta = sta_info_get(local, ra);
        if (!sta) {
                printk(KERN_DEBUG "Could not find the station\n");
-               rcu_read_unlock();
-               return -ENOENT;
+               ret = -ENOENT;
+               goto exit;
        }
 
-       spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+       spin_lock_bh(&sta->lock);
 
        /* we have tried too many times, receiver does not want A-MPDU */
        if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
                ret = -EBUSY;
-               goto start_ba_exit;
+               goto err_unlock_sta;
        }
 
        state = &sta->ampdu_mlme.tid_state_tx[tid];
@@ -605,7 +610,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
                                 "idle on tid %u\n", tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
                ret = -EAGAIN;
-               goto start_ba_exit;
+               goto err_unlock_sta;
        }
 
        /* prepare A-MPDU MLME for Tx aggregation */
@@ -616,7 +621,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
                        printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
                                        tid);
                ret = -ENOMEM;
-               goto start_ba_exit;
+               goto err_unlock_sta;
        }
        /* Tx timer */
        sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
@@ -639,7 +644,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
                printk(KERN_DEBUG "BA request denied - queue unavailable for"
                                        " tid %d\n", tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
-               goto start_ba_err;
+               goto err_unlock_queue;
        }
        sdata = sta->sdata;
 
@@ -661,12 +666,13 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
                                        " tid %d\n", tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
                *state = HT_AGG_STATE_IDLE;
-               goto start_ba_err;
+               goto err_unlock_queue;
        }
 
        /* Will put all the packets in the new SW queue */
        ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
        spin_unlock_bh(&local->mdev->queue_lock);
+       spin_unlock_bh(&sta->lock);
 
        /* send an addBA request */
        sta->ampdu_mlme.dialog_token_allocator++;
@@ -674,25 +680,26 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
                        sta->ampdu_mlme.dialog_token_allocator;
        sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
 
+
        ieee80211_send_addba_request(sta->sdata->dev, ra, tid,
                         sta->ampdu_mlme.tid_tx[tid]->dialog_token,
                         sta->ampdu_mlme.tid_tx[tid]->ssn,
                         0x40, 5000);
-
        /* activate the timer for the recipient's addBA response */
        sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
                                jiffies + ADDBA_RESP_INTERVAL;
        add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
        printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
-       goto start_ba_exit;
+       goto exit;
 
-start_ba_err:
+err_unlock_queue:
        kfree(sta->ampdu_mlme.tid_tx[tid]);
        sta->ampdu_mlme.tid_tx[tid] = NULL;
        spin_unlock_bh(&local->mdev->queue_lock);
        ret = -EBUSY;
-start_ba_exit:
-       spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+err_unlock_sta:
+       spin_unlock_bh(&sta->lock);
+exit:
        rcu_read_unlock();
        return ret;
 }
@@ -720,7 +727,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
 
        /* check if the TID is in aggregation */
        state = &sta->ampdu_mlme.tid_state_tx[tid];
-       spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+       spin_lock_bh(&sta->lock);
 
        if (*state != HT_AGG_STATE_OPERATIONAL) {
                ret = -ENOENT;
@@ -750,7 +757,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
        }
 
 stop_BA_exit:
-       spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+       spin_unlock_bh(&sta->lock);
        rcu_read_unlock();
        return ret;
 }
@@ -779,12 +786,12 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
        }
 
        state = &sta->ampdu_mlme.tid_state_tx[tid];
-       spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+       spin_lock_bh(&sta->lock);
 
        if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
                printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
                                *state);
-               spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+               spin_unlock_bh(&sta->lock);
                rcu_read_unlock();
                return;
        }
@@ -797,7 +804,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
                printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
                ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
        }
-       spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+       spin_unlock_bh(&sta->lock);
        rcu_read_unlock();
 }
 EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
@@ -831,10 +838,11 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
        }
        state = &sta->ampdu_mlme.tid_state_tx[tid];
 
-       spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+       /* NOTE: no need to use sta->lock in this state check, as
+        * ieee80211_stop_tx_ba_session will let only
+        * one stop call to pass through per sta/tid */
        if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
                printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
-               spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
                rcu_read_unlock();
                return;
        }
@@ -857,11 +865,12 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
         * ieee80211_wake_queue is not used here as this queue is not
         * necessarily stopped */
        netif_schedule(local->mdev);
+       spin_lock_bh(&sta->lock);
        *state = HT_AGG_STATE_IDLE;
        sta->ampdu_mlme.addba_req_num[tid] = 0;
        kfree(sta->ampdu_mlme.tid_tx[tid]);
        sta->ampdu_mlme.tid_tx[tid] = NULL;
-       spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+       spin_unlock_bh(&sta->lock);
 
        rcu_read_unlock();
 }
@@ -967,8 +976,7 @@ void ieee80211_if_setup(struct net_device *dev)
 /* everything else */
 
 static int __ieee80211_if_config(struct net_device *dev,
-                                struct sk_buff *beacon,
-                                struct ieee80211_tx_control *control)
+                                struct sk_buff *beacon)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
@@ -986,13 +994,11 @@ static int __ieee80211_if_config(struct net_device *dev,
                conf.ssid_len = sdata->u.sta.ssid_len;
        } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
                conf.beacon = beacon;
-               conf.beacon_control = control;
                ieee80211_start_mesh(dev);
        } else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
                conf.ssid = sdata->u.ap.ssid;
                conf.ssid_len = sdata->u.ap.ssid_len;
                conf.beacon = beacon;
-               conf.beacon_control = control;
        }
        return local->ops->config_interface(local_to_hw(local),
                                            &sdata->vif, &conf);
@@ -1005,23 +1011,21 @@ int ieee80211_if_config(struct net_device *dev)
        if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT &&
            (local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
                return ieee80211_if_config_beacon(dev);
-       return __ieee80211_if_config(dev, NULL, NULL);
+       return __ieee80211_if_config(dev, NULL);
 }
 
 int ieee80211_if_config_beacon(struct net_device *dev)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_tx_control control;
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct sk_buff *skb;
 
        if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
                return 0;
-       skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif,
-                                  &control);
+       skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif);
        if (!skb)
                return -ENOMEM;
-       return __ieee80211_if_config(dev, skb, &control);
+       return __ieee80211_if_config(dev, skb);
 }
 
 int ieee80211_hw_config(struct ieee80211_local *local)
@@ -1068,56 +1072,84 @@ u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht,
        struct ieee80211_supported_band *sband;
        struct ieee80211_ht_info ht_conf;
        struct ieee80211_ht_bss_info ht_bss_conf;
-       int i;
        u32 changed = 0;
+       int i;
+       u8 max_tx_streams = IEEE80211_HT_CAP_MAX_STREAMS;
+       u8 tx_mcs_set_cap;
 
        sband = local->hw.wiphy->bands[conf->channel->band];
 
+       memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info));
+       memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info));
+
        /* HT is not supported */
        if (!sband->ht_info.ht_supported) {
                conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
-               return 0;
+               goto out;
        }
 
-       memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info));
-       memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info));
-
-       if (enable_ht) {
-               if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
+       /* disable HT */
+       if (!enable_ht) {
+               if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)
                        changed |= BSS_CHANGED_HT;
+               conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
+               conf->ht_conf.ht_supported = 0;
+               goto out;
+       }
 
-               conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
-               ht_conf.ht_supported = 1;
 
-               ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
-               ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS);
-               ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
+       if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
+               changed |= BSS_CHANGED_HT;
 
-               for (i = 0; i < SUPP_MCS_SET_LEN; i++)
-                       ht_conf.supp_mcs_set[i] =
-                                       sband->ht_info.supp_mcs_set[i] &
-                                       req_ht_cap->supp_mcs_set[i];
+       conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
+       ht_conf.ht_supported = 1;
 
-               ht_bss_conf.primary_channel = req_bss_cap->primary_channel;
-               ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
-               ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
+       ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
+       ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS);
+       ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
+       ht_bss_conf.primary_channel = req_bss_cap->primary_channel;
+       ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
+       ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
 
-               ht_conf.ampdu_factor = req_ht_cap->ampdu_factor;
-               ht_conf.ampdu_density = req_ht_cap->ampdu_density;
+       ht_conf.ampdu_factor = req_ht_cap->ampdu_factor;
+       ht_conf.ampdu_density = req_ht_cap->ampdu_density;
 
-               /* if bss configuration changed store the new one */
-               if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) ||
-                   memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
-                       changed |= BSS_CHANGED_HT;
-                       memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf));
-                       memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
-               }
-       } else {
-               if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)
-                       changed |= BSS_CHANGED_HT;
-               conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
-       }
+       /* Bits 96-100 */
+       tx_mcs_set_cap = sband->ht_info.supp_mcs_set[12];
+
+       /* configure suppoerted Tx MCS according to requested MCS
+        * (based in most cases on Rx capabilities of peer) and self
+        * Tx MCS capabilities (as defined by low level driver HW
+        * Tx capabilities) */
+       if (!(tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_DEFINED))
+               goto check_changed;
 
+       /* Counting from 0 therfore + 1 */
+       if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_RX_DIFF)
+               max_tx_streams = ((tx_mcs_set_cap &
+                               IEEE80211_HT_CAP_MCS_TX_STREAMS) >> 2) + 1;
+
+       for (i = 0; i < max_tx_streams; i++)
+               ht_conf.supp_mcs_set[i] =
+                       sband->ht_info.supp_mcs_set[i] &
+                                       req_ht_cap->supp_mcs_set[i];
+
+       if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_UEQM)
+               for (i = IEEE80211_SUPP_MCS_SET_UEQM;
+                    i < IEEE80211_SUPP_MCS_SET_LEN; i++)
+                       ht_conf.supp_mcs_set[i] =
+                               sband->ht_info.supp_mcs_set[i] &
+                                       req_ht_cap->supp_mcs_set[i];
+
+check_changed:
+       /* if bss configuration changed store the new one */
+       if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) ||
+           memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
+               changed |= BSS_CHANGED_HT;
+               memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf));
+               memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
+       }
+out:
        return changed;
 }
 
@@ -1148,38 +1180,20 @@ void ieee80211_reset_erp_info(struct net_device *dev)
 }
 
 void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
-                                struct sk_buff *skb,
-                                struct ieee80211_tx_status *status)
+                                struct sk_buff *skb)
 {
        struct ieee80211_local *local = hw_to_local(hw);
-       struct ieee80211_tx_status *saved;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        int tmp;
 
        skb->dev = local->mdev;
-       saved = kmalloc(sizeof(struct ieee80211_tx_status), GFP_ATOMIC);
-       if (unlikely(!saved)) {
-               if (net_ratelimit())
-                       printk(KERN_WARNING "%s: Not enough memory, "
-                              "dropping tx status", skb->dev->name);
-               /* should be dev_kfree_skb_irq, but due to this function being
-                * named _irqsafe instead of just _irq we can't be sure that
-                * people won't call it from non-irq contexts */
-               dev_kfree_skb_any(skb);
-               return;
-       }
-       memcpy(saved, status, sizeof(struct ieee80211_tx_status));
-       /* copy pointer to saved status into skb->cb for use by tasklet */
-       memcpy(skb->cb, &saved, sizeof(saved));
-
        skb->pkt_type = IEEE80211_TX_STATUS_MSG;
-       skb_queue_tail(status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS ?
+       skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ?
                       &local->skb_queue : &local->skb_queue_unreliable, skb);
        tmp = skb_queue_len(&local->skb_queue) +
                skb_queue_len(&local->skb_queue_unreliable);
        while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT &&
               (skb = skb_dequeue(&local->skb_queue_unreliable))) {
-               memcpy(&saved, skb->cb, sizeof(saved));
-               kfree(saved);
                dev_kfree_skb_irq(skb);
                tmp--;
                I802_DEBUG_INC(local->tx_status_drop);
@@ -1193,7 +1207,6 @@ static void ieee80211_tasklet_handler(unsigned long data)
        struct ieee80211_local *local = (struct ieee80211_local *) data;
        struct sk_buff *skb;
        struct ieee80211_rx_status rx_status;
-       struct ieee80211_tx_status *tx_status;
        struct ieee80211_ra_tid *ra_tid;
 
        while ((skb = skb_dequeue(&local->skb_queue)) ||
@@ -1208,12 +1221,8 @@ static void ieee80211_tasklet_handler(unsigned long data)
                        __ieee80211_rx(local_to_hw(local), skb, &rx_status);
                        break;
                case IEEE80211_TX_STATUS_MSG:
-                       /* get pointer to saved status out of skb->cb */
-                       memcpy(&tx_status, skb->cb, sizeof(tx_status));
                        skb->pkt_type = 0;
-                       ieee80211_tx_status(local_to_hw(local),
-                                           skb, tx_status);
-                       kfree(tx_status);
+                       ieee80211_tx_status(local_to_hw(local), skb);
                        break;
                case IEEE80211_DELBA_MSG:
                        ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
@@ -1242,24 +1251,15 @@ static void ieee80211_tasklet_handler(unsigned long data)
  * Also, tx_packet_data in cb is restored from tx_control. */
 static void ieee80211_remove_tx_extra(struct ieee80211_local *local,
                                      struct ieee80211_key *key,
-                                     struct sk_buff *skb,
-                                     struct ieee80211_tx_control *control)
+                                     struct sk_buff *skb)
 {
        int hdrlen, iv_len, mic_len;
-       struct ieee80211_tx_packet_data *pkt_data;
-
-       pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
-       pkt_data->ifindex = vif_to_sdata(control->vif)->dev->ifindex;
-       pkt_data->flags = 0;
-       if (control->flags & IEEE80211_TXCTL_REQ_TX_STATUS)
-               pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS;
-       if (control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)
-               pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
-       if (control->flags & IEEE80211_TXCTL_REQUEUE)
-               pkt_data->flags |= IEEE80211_TXPD_REQUEUE;
-       if (control->flags & IEEE80211_TXCTL_EAPOL_FRAME)
-               pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME;
-       pkt_data->queue = control->queue;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+       info->flags &=  IEEE80211_TX_CTL_REQ_TX_STATUS |
+                       IEEE80211_TX_CTL_DO_NOT_ENCRYPT |
+                       IEEE80211_TX_CTL_REQUEUE |
+                       IEEE80211_TX_CTL_EAPOL_FRAME;
 
        hdrlen = ieee80211_get_hdrlen_from_skb(skb);
 
@@ -1306,9 +1306,10 @@ no_key:
 
 static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
                                            struct sta_info *sta,
-                                           struct sk_buff *skb,
-                                           struct ieee80211_tx_status *status)
+                                           struct sk_buff *skb)
 {
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
        sta->tx_filtered_count++;
 
        /*
@@ -1316,7 +1317,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
         * packet. If the STA went to power save mode, this will happen
         * when it wakes up for the next time.
         */
-       sta->flags |= WLAN_STA_CLEAR_PS_FILT;
+       set_sta_flags(sta, WLAN_STA_CLEAR_PS_FILT);
 
        /*
         * This code races in the following way:
@@ -1348,20 +1349,18 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
         *      can be unknown, for example with different interrupt status
         *      bits.
         */
-       if (sta->flags & WLAN_STA_PS &&
+       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,
-                                         &status->control);
+               ieee80211_remove_tx_extra(local, sta->key, skb);
                skb_queue_tail(&sta->tx_filtered, skb);
                return;
        }
 
-       if (!(sta->flags & WLAN_STA_PS) &&
-           !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) {
+       if (!test_sta_flags(sta, WLAN_STA_PS) &&
+           !(info->flags & IEEE80211_TX_CTL_REQUEUE)) {
                /* Software retry the packet once */
-               status->control.flags |= IEEE80211_TXCTL_REQUEUE;
-               ieee80211_remove_tx_extra(local, sta->key, skb,
-                                         &status->control);
+               info->flags |= IEEE80211_TX_CTL_REQUEUE;
+               ieee80211_remove_tx_extra(local, sta->key, skb);
                dev_queue_xmit(skb);
                return;
        }
@@ -1371,61 +1370,49 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
                       "queue_len=%d PS=%d @%lu\n",
                       wiphy_name(local->hw.wiphy),
                       skb_queue_len(&sta->tx_filtered),
-                      !!(sta->flags & WLAN_STA_PS), jiffies);
+                      !!test_sta_flags(sta, WLAN_STA_PS), jiffies);
        dev_kfree_skb(skb);
 }
 
-void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
-                        struct ieee80211_tx_status *status)
+void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct sk_buff *skb2;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        u16 frag, type;
        struct ieee80211_tx_status_rtap_hdr *rthdr;
        struct ieee80211_sub_if_data *sdata;
        struct net_device *prev_dev = NULL;
 
-       if (!status) {
-               printk(KERN_ERR
-                      "%s: ieee80211_tx_status called with NULL status\n",
-                      wiphy_name(local->hw.wiphy));
-               dev_kfree_skb(skb);
-               return;
-       }
-
        rcu_read_lock();
 
-       if (status->excessive_retries) {
+       if (info->status.excessive_retries) {
                struct sta_info *sta;
                sta = sta_info_get(local, hdr->addr1);
                if (sta) {
-                       if (sta->flags & WLAN_STA_PS) {
+                       if (test_sta_flags(sta, WLAN_STA_PS)) {
                                /*
                                 * The STA is in power save mode, so assume
                                 * that this TX packet failed because of that.
                                 */
-                               status->excessive_retries = 0;
-                               status->flags |= IEEE80211_TX_STATUS_TX_FILTERED;
-                               ieee80211_handle_filtered_frame(local, sta,
-                                                               skb, status);
+                               ieee80211_handle_filtered_frame(local, sta, skb);
                                rcu_read_unlock();
                                return;
                        }
                }
        }
 
-       if (status->flags & IEEE80211_TX_STATUS_TX_FILTERED) {
+       if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
                struct sta_info *sta;
                sta = sta_info_get(local, hdr->addr1);
                if (sta) {
-                       ieee80211_handle_filtered_frame(local, sta, skb,
-                                                       status);
+                       ieee80211_handle_filtered_frame(local, sta, skb);
                        rcu_read_unlock();
                        return;
                }
        } else
-               rate_control_tx_status(local->mdev, skb, status);
+               rate_control_tx_status(local->mdev, skb);
 
        rcu_read_unlock();
 
@@ -1439,14 +1426,14 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
        frag = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
        type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE;
 
-       if (status->flags & IEEE80211_TX_STATUS_ACK) {
+       if (info->flags & IEEE80211_TX_STAT_ACK) {
                if (frag == 0) {
                        local->dot11TransmittedFrameCount++;
                        if (is_multicast_ether_addr(hdr->addr1))
                                local->dot11MulticastTransmittedFrameCount++;
-                       if (status->retry_count > 0)
+                       if (info->status.retry_count > 0)
                                local->dot11RetryCount++;
-                       if (status->retry_count > 1)
+                       if (info->status.retry_count > 1)
                                local->dot11MultipleRetryCount++;
                }
 
@@ -1483,7 +1470,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
                return;
        }
 
-       rthdr = (struct ieee80211_tx_status_rtap_hdr*)
+       rthdr = (struct ieee80211_tx_status_rtap_hdr *)
                                skb_push(skb, sizeof(*rthdr));
 
        memset(rthdr, 0, sizeof(*rthdr));
@@ -1492,17 +1479,17 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
                cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
                            (1 << IEEE80211_RADIOTAP_DATA_RETRIES));
 
-       if (!(status->flags & IEEE80211_TX_STATUS_ACK) &&
+       if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
            !is_multicast_ether_addr(hdr->addr1))
                rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
 
-       if ((status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) &&
-           (status->control.flags & IEEE80211_TXCTL_USE_CTS_PROTECT))
+       if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) &&
+           (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT))
                rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
-       else if (status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS)
+       else if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
                rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
 
-       rthdr->data_retries = status->retry_count;
+       rthdr->data_retries = info->status.retry_count;
 
        /* XXX: is this sufficient for BPF? */
        skb_set_mac_header(skb, 0);
@@ -1652,12 +1639,32 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        if (result < 0)
                return result;
 
+       /*
+        * We use the number of queues for feature tests (QoS, HT) internally
+        * so restrict them appropriately.
+        */
+#ifdef CONFIG_MAC80211_QOS
+       if (hw->queues > IEEE80211_MAX_QUEUES)
+               hw->queues = IEEE80211_MAX_QUEUES;
+       if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES)
+               hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES;
+       if (hw->queues < 4)
+               hw->ampdu_queues = 0;
+#else
+       hw->queues = 1;
+       hw->ampdu_queues = 0;
+#endif
+
        /* for now, mdev needs sub_if_data :/ */
-       mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data),
-                           "wmaster%d", ether_setup);
+       mdev = alloc_netdev_mq(sizeof(struct ieee80211_sub_if_data),
+                              "wmaster%d", ether_setup,
+                              ieee80211_num_queues(hw));
        if (!mdev)
                goto fail_mdev_alloc;
 
+       if (ieee80211_num_queues(hw) > 1)
+               mdev->features |= NETIF_F_MULTI_QUEUE;
+
        sdata = IEEE80211_DEV_TO_SUB_IF(mdev);
        mdev->ieee80211_ptr = &sdata->wdev;
        sdata->wdev.wiphy = local->hw.wiphy;
@@ -1702,13 +1709,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 
        local->hw.conf.beacon_int = 1000;
 
-       local->wstats_flags |= local->hw.max_rssi ?
-                              IW_QUAL_LEVEL_UPDATED : IW_QUAL_LEVEL_INVALID;
-       local->wstats_flags |= local->hw.max_signal ?
+       local->wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC |
+                                                 IEEE80211_HW_SIGNAL_DB |
+                                                 IEEE80211_HW_SIGNAL_DBM) ?
                               IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID;
-       local->wstats_flags |= local->hw.max_noise ?
+       local->wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ?
                               IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID;
-       if (local->hw.max_rssi < 0 || local->hw.max_noise < 0)
+       if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
                local->wstats_flags |= IW_QUAL_DBM;
 
        result = sta_info_start(local);
@@ -1858,7 +1865,9 @@ static int __init ieee80211_init(void)
        struct sk_buff *skb;
        int ret;
 
-       BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb));
+       BUILD_BUG_ON(sizeof(struct ieee80211_tx_info) > sizeof(skb->cb));
+       BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, driver_data) +
+                    IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb));
 
        ret = rc80211_pid_init();
        if (ret)
index 697ef67f96b6796bc60aaefa88720e67191ff007..b5933b271491551bc10edacdfda4416be6b8125d 100644 (file)
@@ -315,6 +315,13 @@ struct mesh_table *mesh_table_alloc(int size_order)
        return newtbl;
 }
 
+static void __mesh_table_free(struct mesh_table *tbl)
+{
+       kfree(tbl->hash_buckets);
+       kfree(tbl->hashwlock);
+       kfree(tbl);
+}
+
 void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
 {
        struct hlist_head *mesh_hash;
@@ -330,9 +337,7 @@ void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
                }
                spin_unlock(&tbl->hashwlock[i]);
        }
-       kfree(tbl->hash_buckets);
-       kfree(tbl->hashwlock);
-       kfree(tbl);
+       __mesh_table_free(tbl);
 }
 
 static void ieee80211_mesh_path_timer(unsigned long data)
@@ -349,21 +354,16 @@ struct mesh_table *mesh_table_grow(struct mesh_table *tbl)
 {
        struct mesh_table *newtbl;
        struct hlist_head *oldhash;
-       struct hlist_node *p;
-       int err = 0;
+       struct hlist_node *p, *q;
        int i;
 
        if (atomic_read(&tbl->entries)
-                       < tbl->mean_chain_len * (tbl->hash_mask + 1)) {
-               err = -EPERM;
+                       < tbl->mean_chain_len * (tbl->hash_mask + 1))
                goto endgrow;
-       }
 
        newtbl = mesh_table_alloc(tbl->size_order + 1);
-       if (!newtbl) {
-               err = -ENOMEM;
+       if (!newtbl)
                goto endgrow;
-       }
 
        newtbl->free_node = tbl->free_node;
        newtbl->mean_chain_len = tbl->mean_chain_len;
@@ -373,13 +373,19 @@ struct mesh_table *mesh_table_grow(struct mesh_table *tbl)
        oldhash = tbl->hash_buckets;
        for (i = 0; i <= tbl->hash_mask; i++)
                hlist_for_each(p, &oldhash[i])
-                       tbl->copy_node(p, newtbl);
+                       if (tbl->copy_node(p, newtbl) < 0)
+                               goto errcopy;
 
+       return newtbl;
+
+errcopy:
+       for (i = 0; i <= newtbl->hash_mask; i++) {
+               hlist_for_each_safe(p, q, &newtbl->hash_buckets[i])
+                       tbl->free_node(p, 0);
+       }
+       __mesh_table_free(tbl);
 endgrow:
-       if (err)
-               return NULL;
-       else
-               return newtbl;
+       return NULL;
 }
 
 /**
index 2e161f6d8288255d47609fb83febf9bc2faae5ba..669eafafe497e6c6db825ac0903d612268a910dc 100644 (file)
@@ -109,7 +109,7 @@ struct mesh_table {
        __u32 hash_rnd;                 /* Used for hash generation */
        atomic_t entries;               /* Up to MAX_MESH_NEIGHBOURS */
        void (*free_node) (struct hlist_node *p, bool free_leafs);
-       void (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl);
+       int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl);
        int size_order;
        int mean_chain_len;
 };
index af0cd1e3e2131136026b0851aad60f42db31825f..7fa149e230e6fc3cfecad043ad82ae4c204611fa 100644 (file)
@@ -26,7 +26,7 @@ static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae)
 {
        if (ae)
                offset += 6;
-       return le32_to_cpu(get_unaligned((__le32 *) (preq_elem + offset)));
+       return get_unaligned_le32(preq_elem + offset);
 }
 
 /* HWMP IE processing macros */
index 99c2d360888ef30cc7f0e8637b7aea9af0d474a4..947b13b40726ba5b865a876faa0eac1ed653a719 100644 (file)
@@ -158,19 +158,14 @@ int mesh_path_add(u8 *dst, struct net_device *dev)
        if (atomic_add_unless(&sdata->u.sta.mpaths, 1, MESH_MAX_MPATHS) == 0)
                return -ENOSPC;
 
+       err = -ENOMEM;
        new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL);
-       if (!new_mpath) {
-               atomic_dec(&sdata->u.sta.mpaths);
-               err = -ENOMEM;
-               goto endadd2;
-       }
+       if (!new_mpath)
+               goto err_path_alloc;
+
        new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL);
-       if (!new_node) {
-               kfree(new_mpath);
-               atomic_dec(&sdata->u.sta.mpaths);
-               err = -ENOMEM;
-               goto endadd2;
-       }
+       if (!new_node)
+               goto err_node_alloc;
 
        read_lock(&pathtbl_resize_lock);
        memcpy(new_mpath->dst, dst, ETH_ALEN);
@@ -189,16 +184,11 @@ int mesh_path_add(u8 *dst, struct net_device *dev)
 
        spin_lock(&mesh_paths->hashwlock[hash_idx]);
 
+       err = -EEXIST;
        hlist_for_each_entry(node, n, bucket, list) {
                mpath = node->mpath;
-               if (mpath->dev == dev && memcmp(dst, mpath->dst, ETH_ALEN)
-                               == 0) {
-                       err = -EEXIST;
-                       atomic_dec(&sdata->u.sta.mpaths);
-                       kfree(new_node);
-                       kfree(new_mpath);
-                       goto endadd;
-               }
+               if (mpath->dev == dev && memcmp(dst, mpath->dst, ETH_ALEN) == 0)
+                       goto err_exists;
        }
 
        hlist_add_head_rcu(&new_node->list, bucket);
@@ -206,10 +196,9 @@ int mesh_path_add(u8 *dst, struct net_device *dev)
                mesh_paths->mean_chain_len * (mesh_paths->hash_mask + 1))
                grow = 1;
 
-endadd:
        spin_unlock(&mesh_paths->hashwlock[hash_idx]);
        read_unlock(&pathtbl_resize_lock);
-       if (!err && grow) {
+       if (grow) {
                struct mesh_table *oldtbl, *newtbl;
 
                write_lock(&pathtbl_resize_lock);
@@ -217,7 +206,7 @@ endadd:
                newtbl = mesh_table_grow(mesh_paths);
                if (!newtbl) {
                        write_unlock(&pathtbl_resize_lock);
-                       return -ENOMEM;
+                       return 0;
                }
                rcu_assign_pointer(mesh_paths, newtbl);
                write_unlock(&pathtbl_resize_lock);
@@ -225,7 +214,16 @@ endadd:
                synchronize_rcu();
                mesh_table_free(oldtbl, false);
        }
-endadd2:
+       return 0;
+
+err_exists:
+       spin_unlock(&mesh_paths->hashwlock[hash_idx]);
+       read_unlock(&pathtbl_resize_lock);
+       kfree(new_node);
+err_node_alloc:
+       kfree(new_mpath);
+err_path_alloc:
+       atomic_dec(&sdata->u.sta.mpaths);
        return err;
 }
 
@@ -460,25 +458,28 @@ static void mesh_path_node_free(struct hlist_node *p, bool free_leafs)
        struct mpath_node *node = hlist_entry(p, struct mpath_node, list);
        mpath = node->mpath;
        hlist_del_rcu(p);
-       synchronize_rcu();
        if (free_leafs)
                kfree(mpath);
        kfree(node);
 }
 
-static void mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl)
+static int mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl)
 {
        struct mesh_path *mpath;
        struct mpath_node *node, *new_node;
        u32 hash_idx;
 
+       new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC);
+       if (new_node == NULL)
+               return -ENOMEM;
+
        node = hlist_entry(p, struct mpath_node, list);
        mpath = node->mpath;
-       new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL);
        new_node->mpath = mpath;
        hash_idx = mesh_table_hash(mpath->dst, mpath->dev, newtbl);
        hlist_add_head(&new_node->list,
                        &newtbl->hash_buckets[hash_idx]);
+       return 0;
 }
 
 int mesh_pathtbl_init(void)
index 37f0c2b94ae7a7524b28dff277fc8fc2c98b5b5b..9efeb1f07025f32270a8eff239fb1f043c115656 100644 (file)
@@ -79,7 +79,7 @@ void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
  *
  * @sta: mes peer link to restart
  *
- * Locking: this function must be called holding sta->plink_lock
+ * Locking: this function must be called holding sta->lock
  */
 static inline void mesh_plink_fsm_restart(struct sta_info *sta)
 {
@@ -105,7 +105,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
        if (!sta)
                return NULL;
 
-       sta->flags |= WLAN_STA_AUTHORIZED;
+       sta->flags = WLAN_STA_AUTHORIZED;
        sta->supp_rates[local->hw.conf.channel->band] = rates;
 
        return sta;
@@ -118,7 +118,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
  *
  * All mesh paths with this peer as next hop will be flushed
  *
- * Locking: the caller must hold sta->plink_lock
+ * Locking: the caller must hold sta->lock
  */
 static void __mesh_plink_deactivate(struct sta_info *sta)
 {
@@ -139,9 +139,9 @@ static void __mesh_plink_deactivate(struct sta_info *sta)
  */
 void mesh_plink_deactivate(struct sta_info *sta)
 {
-       spin_lock_bh(&sta->plink_lock);
+       spin_lock_bh(&sta->lock);
        __mesh_plink_deactivate(sta);
-       spin_unlock_bh(&sta->plink_lock);
+       spin_unlock_bh(&sta->lock);
 }
 
 static int mesh_plink_frame_tx(struct net_device *dev,
@@ -270,10 +270,10 @@ static void mesh_plink_timer(unsigned long data)
         */
        sta = (struct sta_info *) data;
 
-       spin_lock_bh(&sta->plink_lock);
+       spin_lock_bh(&sta->lock);
        if (sta->ignore_plink_timer) {
                sta->ignore_plink_timer = false;
-               spin_unlock_bh(&sta->plink_lock);
+               spin_unlock_bh(&sta->lock);
                return;
        }
        mpl_dbg("Mesh plink timer for %s fired on state %d\n",
@@ -298,7 +298,7 @@ static void mesh_plink_timer(unsigned long data)
                                             rand % sta->plink_timeout;
                        ++sta->plink_retries;
                        mod_plink_timer(sta, sta->plink_timeout);
-                       spin_unlock_bh(&sta->plink_lock);
+                       spin_unlock_bh(&sta->lock);
                        mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid,
                                            0, 0);
                        break;
@@ -311,7 +311,7 @@ static void mesh_plink_timer(unsigned long data)
                        reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT);
                sta->plink_state = PLINK_HOLDING;
                mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
-               spin_unlock_bh(&sta->plink_lock);
+               spin_unlock_bh(&sta->lock);
                mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid,
                                    reason);
                break;
@@ -319,10 +319,10 @@ static void mesh_plink_timer(unsigned long data)
                /* holding timer */
                del_timer(&sta->plink_timer);
                mesh_plink_fsm_restart(sta);
-               spin_unlock_bh(&sta->plink_lock);
+               spin_unlock_bh(&sta->lock);
                break;
        default:
-               spin_unlock_bh(&sta->plink_lock);
+               spin_unlock_bh(&sta->lock);
                break;
        }
 }
@@ -344,16 +344,16 @@ int mesh_plink_open(struct sta_info *sta)
        DECLARE_MAC_BUF(mac);
 #endif
 
-       spin_lock_bh(&sta->plink_lock);
+       spin_lock_bh(&sta->lock);
        get_random_bytes(&llid, 2);
        sta->llid = llid;
        if (sta->plink_state != PLINK_LISTEN) {
-               spin_unlock_bh(&sta->plink_lock);
+               spin_unlock_bh(&sta->lock);
                return -EBUSY;
        }
        sta->plink_state = PLINK_OPN_SNT;
        mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
-       spin_unlock_bh(&sta->plink_lock);
+       spin_unlock_bh(&sta->lock);
        mpl_dbg("Mesh plink: starting establishment with %s\n",
                print_mac(mac, sta->addr));
 
@@ -367,10 +367,10 @@ void mesh_plink_block(struct sta_info *sta)
        DECLARE_MAC_BUF(mac);
 #endif
 
-       spin_lock_bh(&sta->plink_lock);
+       spin_lock_bh(&sta->lock);
        __mesh_plink_deactivate(sta);
        sta->plink_state = PLINK_BLOCKED;
-       spin_unlock_bh(&sta->plink_lock);
+       spin_unlock_bh(&sta->lock);
 }
 
 int mesh_plink_close(struct sta_info *sta)
@@ -383,14 +383,14 @@ int mesh_plink_close(struct sta_info *sta)
 
        mpl_dbg("Mesh plink: closing link with %s\n",
                        print_mac(mac, sta->addr));
-       spin_lock_bh(&sta->plink_lock);
+       spin_lock_bh(&sta->lock);
        sta->reason = cpu_to_le16(MESH_LINK_CANCELLED);
        reason = sta->reason;
 
        if (sta->plink_state == PLINK_LISTEN ||
            sta->plink_state == PLINK_BLOCKED) {
                mesh_plink_fsm_restart(sta);
-               spin_unlock_bh(&sta->plink_lock);
+               spin_unlock_bh(&sta->lock);
                return 0;
        } else if (sta->plink_state == PLINK_ESTAB) {
                __mesh_plink_deactivate(sta);
@@ -402,7 +402,7 @@ int mesh_plink_close(struct sta_info *sta)
        sta->plink_state = PLINK_HOLDING;
        llid = sta->llid;
        plid = sta->plid;
-       spin_unlock_bh(&sta->plink_lock);
+       spin_unlock_bh(&sta->lock);
        mesh_plink_frame_tx(sta->sdata->dev, PLINK_CLOSE, sta->addr, llid,
                            plid, reason);
        return 0;
@@ -490,7 +490,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
                        /* avoid warning */
                        break;
                }
-               spin_lock_bh(&sta->plink_lock);
+               spin_lock_bh(&sta->lock);
        } else if (!sta) {
                /* ftype == PLINK_OPEN */
                u64 rates;
@@ -512,9 +512,9 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
                        return;
                }
                event = OPN_ACPT;
-               spin_lock_bh(&sta->plink_lock);
+               spin_lock_bh(&sta->lock);
        } else {
-               spin_lock_bh(&sta->plink_lock);
+               spin_lock_bh(&sta->lock);
                switch (ftype) {
                case PLINK_OPEN:
                        if (!mesh_plink_free_count(sdata) ||
@@ -551,7 +551,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
                        break;
                default:
                        mpl_dbg("Mesh plink: unknown frame subtype\n");
-                       spin_unlock_bh(&sta->plink_lock);
+                       spin_unlock_bh(&sta->lock);
                        rcu_read_unlock();
                        return;
                }
@@ -568,7 +568,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
                switch (event) {
                case CLS_ACPT:
                        mesh_plink_fsm_restart(sta);
-                       spin_unlock_bh(&sta->plink_lock);
+                       spin_unlock_bh(&sta->lock);
                        break;
                case OPN_ACPT:
                        sta->plink_state = PLINK_OPN_RCVD;
@@ -576,14 +576,14 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
                        get_random_bytes(&llid, 2);
                        sta->llid = llid;
                        mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
-                       spin_unlock_bh(&sta->plink_lock);
+                       spin_unlock_bh(&sta->lock);
                        mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid,
                                            0, 0);
                        mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr,
                                            llid, plid, 0);
                        break;
                default:
-                       spin_unlock_bh(&sta->plink_lock);
+                       spin_unlock_bh(&sta->lock);
                        break;
                }
                break;
@@ -603,7 +603,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
                                sta->ignore_plink_timer = true;
 
                        llid = sta->llid;
-                       spin_unlock_bh(&sta->plink_lock);
+                       spin_unlock_bh(&sta->lock);
                        mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
                                            plid, reason);
                        break;
@@ -612,7 +612,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
                        sta->plink_state = PLINK_OPN_RCVD;
                        sta->plid = plid;
                        llid = sta->llid;
-                       spin_unlock_bh(&sta->plink_lock);
+                       spin_unlock_bh(&sta->lock);
                        mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
                                            plid, 0);
                        break;
@@ -622,10 +622,10 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
                                             dot11MeshConfirmTimeout(sdata)))
                                sta->ignore_plink_timer = true;
 
-                       spin_unlock_bh(&sta->plink_lock);
+                       spin_unlock_bh(&sta->lock);
                        break;
                default:
-                       spin_unlock_bh(&sta->plink_lock);
+                       spin_unlock_bh(&sta->lock);
                        break;
                }
                break;
@@ -645,13 +645,13 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
                                sta->ignore_plink_timer = true;
 
                        llid = sta->llid;
-                       spin_unlock_bh(&sta->plink_lock);
+                       spin_unlock_bh(&sta->lock);
                        mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
                                            plid, reason);
                        break;
                case OPN_ACPT:
                        llid = sta->llid;
-                       spin_unlock_bh(&sta->plink_lock);
+                       spin_unlock_bh(&sta->lock);
                        mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
                                            plid, 0);
                        break;
@@ -659,12 +659,12 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
                        del_timer(&sta->plink_timer);
                        sta->plink_state = PLINK_ESTAB;
                        mesh_plink_inc_estab_count(sdata);
-                       spin_unlock_bh(&sta->plink_lock);
+                       spin_unlock_bh(&sta->lock);
                        mpl_dbg("Mesh plink with %s ESTABLISHED\n",
                                        print_mac(mac, sta->addr));
                        break;
                default:
-                       spin_unlock_bh(&sta->plink_lock);
+                       spin_unlock_bh(&sta->lock);
                        break;
                }
                break;
@@ -684,7 +684,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
                                sta->ignore_plink_timer = true;
 
                        llid = sta->llid;
-                       spin_unlock_bh(&sta->plink_lock);
+                       spin_unlock_bh(&sta->lock);
                        mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
                                            plid, reason);
                        break;
@@ -692,14 +692,14 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
                        del_timer(&sta->plink_timer);
                        sta->plink_state = PLINK_ESTAB;
                        mesh_plink_inc_estab_count(sdata);
-                       spin_unlock_bh(&sta->plink_lock);
+                       spin_unlock_bh(&sta->lock);
                        mpl_dbg("Mesh plink with %s ESTABLISHED\n",
                                        print_mac(mac, sta->addr));
                        mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
                                            plid, 0);
                        break;
                default:
-                       spin_unlock_bh(&sta->plink_lock);
+                       spin_unlock_bh(&sta->lock);
                        break;
                }
                break;
@@ -713,18 +713,18 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
                        sta->plink_state = PLINK_HOLDING;
                        llid = sta->llid;
                        mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
-                       spin_unlock_bh(&sta->plink_lock);
+                       spin_unlock_bh(&sta->lock);
                        mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
                                            plid, reason);
                        break;
                case OPN_ACPT:
                        llid = sta->llid;
-                       spin_unlock_bh(&sta->plink_lock);
+                       spin_unlock_bh(&sta->lock);
                        mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
                                            plid, 0);
                        break;
                default:
-                       spin_unlock_bh(&sta->plink_lock);
+                       spin_unlock_bh(&sta->lock);
                        break;
                }
                break;
@@ -734,7 +734,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
                        if (del_timer(&sta->plink_timer))
                                sta->ignore_plink_timer = 1;
                        mesh_plink_fsm_restart(sta);
-                       spin_unlock_bh(&sta->plink_lock);
+                       spin_unlock_bh(&sta->lock);
                        break;
                case OPN_ACPT:
                case CNF_ACPT:
@@ -742,19 +742,19 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
                case CNF_RJCT:
                        llid = sta->llid;
                        reason = sta->reason;
-                       spin_unlock_bh(&sta->plink_lock);
+                       spin_unlock_bh(&sta->lock);
                        mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
                                            plid, reason);
                        break;
                default:
-                       spin_unlock_bh(&sta->plink_lock);
+                       spin_unlock_bh(&sta->lock);
                }
                break;
        default:
                /* should not get here, PLINK_BLOCKED is dealt with at the
                 * beggining of the function
                 */
-               spin_unlock_bh(&sta->plink_lock);
+               spin_unlock_bh(&sta->lock);
                break;
        }
 
index 0f844f7895f19a20c5d9a9d7e318211a3b8f3978..1fcdf38cf60c1957f1d5faa7c8175150257ad886 100644 (file)
@@ -6,85 +6,58 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
 #include <linux/types.h>
+#include <linux/bitops.h>
+#include <asm/unaligned.h>
 
 #include "michael.h"
 
-static inline u32 rotr(u32 val, int bits)
-{
-       return (val >> bits) | (val << (32 - bits));
-}
-
-
-static inline u32 rotl(u32 val, int bits)
-{
-       return (val << bits) | (val >> (32 - bits));
-}
-
-
-static inline u32 xswap(u32 val)
-{
-       return ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8);
-}
-
-
-#define michael_block(l, r) \
-do { \
-       r ^= rotl(l, 17); \
-       l += r; \
-       r ^= xswap(l); \
-       l += r; \
-       r ^= rotl(l, 3); \
-       l += r; \
-       r ^= rotr(l, 2); \
-       l += r; \
-} while (0)
-
-
-static inline u32 michael_get32(u8 *data)
+static void michael_block(struct michael_mic_ctx *mctx, u32 val)
 {
-       return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+       mctx->l ^= val;
+       mctx->r ^= rol32(mctx->l, 17);
+       mctx->l += mctx->r;
+       mctx->r ^= ((mctx->l & 0xff00ff00) >> 8) |
+                  ((mctx->l & 0x00ff00ff) << 8);
+       mctx->l += mctx->r;
+       mctx->r ^= rol32(mctx->l, 3);
+       mctx->l += mctx->r;
+       mctx->r ^= ror32(mctx->l, 2);
+       mctx->l += mctx->r;
 }
 
-
-static inline void michael_put32(u32 val, u8 *data)
+static void michael_mic_hdr(struct michael_mic_ctx *mctx,
+                       const u8 *key, const u8 *da, const u8 *sa, u8 priority)
 {
-       data[0] = val & 0xff;
-       data[1] = (val >> 8) & 0xff;
-       data[2] = (val >> 16) & 0xff;
-       data[3] = (val >> 24) & 0xff;
+       mctx->l = get_unaligned_le32(key);
+       mctx->r = get_unaligned_le32(key + 4);
+
+       /*
+        * A pseudo header (DA, SA, Priority, 0, 0, 0) is used in Michael MIC
+        * calculation, but it is _not_ transmitted
+        */
+       michael_block(mctx, get_unaligned_le32(da));
+       michael_block(mctx, get_unaligned_le16(&da[4]) |
+                           (get_unaligned_le16(sa) << 16));
+       michael_block(mctx, get_unaligned_le32(&sa[2]));
+       michael_block(mctx, priority);
 }
 
-
-void michael_mic(u8 *key, u8 *da, u8 *sa, u8 priority,
-                u8 *data, size_t data_len, u8 *mic)
+void michael_mic(const u8 *key, const u8 *da, const u8 *sa, u8 priority,
+                const u8 *data, size_t data_len, u8 *mic)
 {
-       u32 l, r, val;
+       u32 val;
        size_t block, blocks, left;
+       struct michael_mic_ctx mctx;
 
-       l = michael_get32(key);
-       r = michael_get32(key + 4);
-
-       /* A pseudo header (DA, SA, Priority, 0, 0, 0) is used in Michael MIC
-        * calculation, but it is _not_ transmitted */
-       l ^= michael_get32(da);
-       michael_block(l, r);
-       l ^= da[4] | (da[5] << 8) | (sa[0] << 16) | (sa[1] << 24);
-       michael_block(l, r);
-       l ^= michael_get32(&sa[2]);
-       michael_block(l, r);
-       l ^= priority;
-       michael_block(l, r);
+       michael_mic_hdr(&mctx, key, da, sa, priority);
 
        /* Real data */
        blocks = data_len / 4;
        left = data_len % 4;
 
-       for (block = 0; block < blocks; block++) {
-               l ^= michael_get32(&data[block * 4]);
-               michael_block(l, r);
-       }
+       for (block = 0; block < blocks; block++)
+               michael_block(&mctx, get_unaligned_le32(&data[block * 4]));
 
        /* Partial block of 0..3 bytes and padding: 0x5a + 4..7 zeros to make
         * total length a multiple of 4. */
@@ -94,11 +67,10 @@ void michael_mic(u8 *key, u8 *da, u8 *sa, u8 priority,
                left--;
                val |= data[blocks * 4 + left];
        }
-       l ^= val;
-       michael_block(l, r);
-       /* last block is zero, so l ^ 0 = l */
-       michael_block(l, r);
 
-       michael_put32(l, mic);
-       michael_put32(r, mic + 4);
+       michael_block(&mctx, val);
+       michael_block(&mctx, 0);
+
+       put_unaligned_le32(mctx.l, mic);
+       put_unaligned_le32(mctx.r, mic + 4);
 }
index 2e6aebabeea119a90038188dbbbdeb295a562c88..69b4501f13ba0f40e5dc1dc89055303c07bcdbb2 100644 (file)
 
 #define MICHAEL_MIC_LEN 8
 
-void michael_mic(u8 *key, u8 *da, u8 *sa, u8 priority,
-                u8 *data, size_t data_len, u8 *mic);
+struct michael_mic_ctx {
+       u32 l, r;
+};
+
+void michael_mic(const u8 *key, const u8 *da, const u8 *sa, u8 priority,
+                const u8 *data, size_t data_len, u8 *mic);
 
 #endif /* MICHAEL_H */
index 4d2b582dd05587ed46ec7b8dc7d45e708e22e1a6..7f05820dc6294ce7ff96364c8e09c41e0012d603 100644 (file)
@@ -87,6 +87,7 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
                                    u8 *ssid, size_t ssid_len);
 static int ieee80211_sta_config_auth(struct net_device *dev,
                                     struct ieee80211_if_sta *ifsta);
+static void sta_rx_agg_session_timer_expired(unsigned long data);
 
 
 void ieee802_11_parse_elems(u8 *start, size_t len,
@@ -256,19 +257,8 @@ static void ieee80211_sta_def_wmm_params(struct net_device *dev,
                qparam.cw_max = 1023;
                qparam.txop = 0;
 
-               for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++)
-                       local->ops->conf_tx(local_to_hw(local),
-                                          i + IEEE80211_TX_QUEUE_DATA0,
-                                          &qparam);
-
-               if (ibss) {
-                       /* IBSS uses different parameters for Beacon sending */
-                       qparam.cw_min++;
-                       qparam.cw_min *= 2;
-                       qparam.cw_min--;
-                       local->ops->conf_tx(local_to_hw(local),
-                                          IEEE80211_TX_QUEUE_BEACON, &qparam);
-               }
+               for (i = 0; i < local_to_hw(local)->queues; i++)
+                       local->ops->conf_tx(local_to_hw(local), i, &qparam);
        }
 }
 
@@ -282,6 +272,12 @@ static void ieee80211_sta_wmm_params(struct net_device *dev,
        int count;
        u8 *pos;
 
+       if (!(ifsta->flags & IEEE80211_STA_WMM_ENABLED))
+               return;
+
+       if (!wmm_param)
+               return;
+
        if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
                return;
        count = wmm_param[6] & 0x0f;
@@ -305,29 +301,25 @@ static void ieee80211_sta_wmm_params(struct net_device *dev,
 
                switch (aci) {
                case 1:
-                       queue = IEEE80211_TX_QUEUE_DATA3;
-                       if (acm) {
+                       queue = 3;
+                       if (acm)
                                local->wmm_acm |= BIT(0) | BIT(3);
-                       }
                        break;
                case 2:
-                       queue = IEEE80211_TX_QUEUE_DATA1;
-                       if (acm) {
+                       queue = 1;
+                       if (acm)
                                local->wmm_acm |= BIT(4) | BIT(5);
-                       }
                        break;
                case 3:
-                       queue = IEEE80211_TX_QUEUE_DATA0;
-                       if (acm) {
+                       queue = 0;
+                       if (acm)
                                local->wmm_acm |= BIT(6) | BIT(7);
-                       }
                        break;
                case 0:
                default:
-                       queue = IEEE80211_TX_QUEUE_DATA2;
-                       if (acm) {
+                       queue = 2;
+                       if (acm)
                                local->wmm_acm |= BIT(1) | BIT(2);
-                       }
                        break;
                }
 
@@ -586,7 +578,7 @@ void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb,
                      int encrypt)
 {
        struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_tx_packet_data *pkt_data;
+       struct ieee80211_tx_info *info;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        skb->dev = sdata->local->mdev;
@@ -594,11 +586,11 @@ void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb,
        skb_set_network_header(skb, 0);
        skb_set_transport_header(skb, 0);
 
-       pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
-       memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
-       pkt_data->ifindex = sdata->dev->ifindex;
+       info = IEEE80211_SKB_CB(skb);
+       memset(info, 0, sizeof(struct ieee80211_tx_info));
+       info->control.ifindex = sdata->dev->ifindex;
        if (!encrypt)
-               pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
+               info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
 
        dev_queue_xmit(skb);
 }
@@ -727,9 +719,8 @@ static void ieee80211_send_assoc(struct net_device *dev,
        if (bss) {
                if (bss->capability & WLAN_CAPABILITY_PRIVACY)
                        capab |= WLAN_CAPABILITY_PRIVACY;
-               if (bss->wmm_ie) {
+               if (bss->wmm_ie)
                        wmm = 1;
-               }
 
                /* get all rates supported by the device and the AP as
                 * some APs don't like getting a superset of their rates
@@ -821,9 +812,32 @@ static void ieee80211_send_assoc(struct net_device *dev,
                *pos++ = 1; /* WME ver */
                *pos++ = 0;
        }
+
        /* wmm support is a must to HT */
-       if (wmm && sband->ht_info.ht_supported) {
-               __le16 tmp = cpu_to_le16(sband->ht_info.cap);
+       if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) &&
+           sband->ht_info.ht_supported && bss->ht_add_ie) {
+               struct ieee80211_ht_addt_info *ht_add_info =
+                       (struct ieee80211_ht_addt_info *)bss->ht_add_ie;
+               u16 cap = sband->ht_info.cap;
+               __le16 tmp;
+               u32 flags = local->hw.conf.channel->flags;
+
+               switch (ht_add_info->ht_param & IEEE80211_HT_IE_CHA_SEC_OFFSET) {
+               case IEEE80211_HT_IE_CHA_SEC_ABOVE:
+                       if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) {
+                               cap &= ~IEEE80211_HT_CAP_SUP_WIDTH;
+                               cap &= ~IEEE80211_HT_CAP_SGI_40;
+                       }
+                       break;
+               case IEEE80211_HT_IE_CHA_SEC_BELOW:
+                       if (flags & IEEE80211_CHAN_NO_FAT_BELOW) {
+                               cap &= ~IEEE80211_HT_CAP_SUP_WIDTH;
+                               cap &= ~IEEE80211_HT_CAP_SGI_40;
+                       }
+                       break;
+               }
+
+               tmp = cpu_to_le16(cap);
                pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2);
                *pos++ = WLAN_EID_HT_CAPABILITY;
                *pos++ = sizeof(struct ieee80211_ht_cap);
@@ -1141,8 +1155,8 @@ static void ieee80211_send_addba_resp(struct net_device *dev, u8 *da, u16 tid,
        struct ieee80211_mgmt *mgmt;
        u16 capab;
 
-       skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
-                                       sizeof(mgmt->u.action.u.addba_resp));
+       skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
+
        if (!skb) {
                printk(KERN_DEBUG "%s: failed to allocate buffer "
                       "for addba resp frame\n", dev->name);
@@ -1190,9 +1204,7 @@ void ieee80211_send_addba_request(struct net_device *dev, const u8 *da,
        struct ieee80211_mgmt *mgmt;
        u16 capab;
 
-       skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
-                               sizeof(mgmt->u.action.u.addba_req));
-
+       skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
 
        if (!skb) {
                printk(KERN_ERR "%s: failed to allocate buffer "
@@ -1293,7 +1305,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev,
 
 
        /* examine state machine */
-       spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
+       spin_lock_bh(&sta->lock);
 
        if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
@@ -1360,7 +1372,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev,
        tid_agg_rx->stored_mpdu_num = 0;
        status = WLAN_STATUS_SUCCESS;
 end:
-       spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
+       spin_unlock_bh(&sta->lock);
 
 end_no_lock:
        ieee80211_send_addba_resp(sta->sdata->dev, sta->addr, tid,
@@ -1392,10 +1404,10 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev,
 
        state = &sta->ampdu_mlme.tid_state_tx[tid];
 
-       spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+       spin_lock_bh(&sta->lock);
 
        if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
-               spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+               spin_unlock_bh(&sta->lock);
                printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:"
                        "%d\n", *state);
                goto addba_resp_exit;
@@ -1403,7 +1415,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev,
 
        if (mgmt->u.action.u.addba_resp.dialog_token !=
                sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
-               spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+               spin_unlock_bh(&sta->lock);
 #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
@@ -1427,7 +1439,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev,
                        ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
                }
 
-               spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+               spin_unlock_bh(&sta->lock);
                printk(KERN_DEBUG "recipient accepted agg: tid %d \n", tid);
        } else {
                printk(KERN_DEBUG "recipient rejected agg: tid %d \n", tid);
@@ -1435,7 +1447,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev,
                sta->ampdu_mlme.addba_req_num[tid]++;
                /* this will allow the state check in stop_BA_session */
                *state = HT_AGG_STATE_OPERATIONAL;
-               spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+               spin_unlock_bh(&sta->lock);
                ieee80211_stop_tx_ba_session(hw, sta->addr, tid,
                                             WLAN_BACK_INITIATOR);
        }
@@ -1454,8 +1466,7 @@ void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
        struct ieee80211_mgmt *mgmt;
        u16 params;
 
-       skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
-                                       sizeof(mgmt->u.action.u.delba));
+       skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
 
        if (!skb) {
                printk(KERN_ERR "%s: failed to allocate buffer "
@@ -1506,17 +1517,17 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid,
        }
 
        /* check if TID is in operational state */
-       spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
+       spin_lock_bh(&sta->lock);
        if (sta->ampdu_mlme.tid_state_rx[tid]
                                != HT_AGG_STATE_OPERATIONAL) {
-               spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
+               spin_unlock_bh(&sta->lock);
                rcu_read_unlock();
                return;
        }
        sta->ampdu_mlme.tid_state_rx[tid] =
                HT_AGG_STATE_REQ_STOP_BA_MSK |
                (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
-       spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
+       spin_unlock_bh(&sta->lock);
 
        /* stop HW Rx aggregation. ampdu_action existence
         * already verified in session init so we add the BUG_ON */
@@ -1593,10 +1604,10 @@ static void ieee80211_sta_process_delba(struct net_device *dev,
                ieee80211_sta_stop_rx_ba_session(dev, sta->addr, tid,
                                                 WLAN_BACK_INITIATOR, 0);
        else { /* WLAN_BACK_RECIPIENT */
-               spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+               spin_lock_bh(&sta->lock);
                sta->ampdu_mlme.tid_state_tx[tid] =
                                HT_AGG_STATE_OPERATIONAL;
-               spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+               spin_unlock_bh(&sta->lock);
                ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid,
                                             WLAN_BACK_RECIPIENT);
        }
@@ -1633,9 +1644,9 @@ void sta_addba_resp_timer_expired(unsigned long data)
 
        state = &sta->ampdu_mlme.tid_state_tx[tid];
        /* check if the TID waits for addBA response */
-       spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+       spin_lock_bh(&sta->lock);
        if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
-               spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+               spin_unlock_bh(&sta->lock);
                *state = HT_AGG_STATE_IDLE;
                printk(KERN_DEBUG "timer expired on tid %d but we are not "
                                "expecting addBA response there", tid);
@@ -1646,7 +1657,7 @@ void sta_addba_resp_timer_expired(unsigned long data)
 
        /* go through the state check in stop_BA_session */
        *state = HT_AGG_STATE_OPERATIONAL;
-       spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+       spin_unlock_bh(&sta->lock);
        ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid,
                                     WLAN_BACK_INITIATOR);
 
@@ -1659,7 +1670,7 @@ timer_expired_exit:
  * resetting it after each frame that arrives from the originator.
  * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed.
  */
-void sta_rx_agg_session_timer_expired(unsigned long data)
+static void sta_rx_agg_session_timer_expired(unsigned long data)
 {
        /* not an elegant detour, but there is no choice as the timer passes
         * only one argument, and various sta_info are needed here, so init
@@ -1848,9 +1859,8 @@ static void ieee80211_rx_mgmt_deauth(struct net_device *dev,
               " (reason=%d)\n",
               dev->name, print_mac(mac, mgmt->sa), reason_code);
 
-       if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) {
+       if (ifsta->flags & IEEE80211_STA_AUTHENTICATED)
                printk(KERN_DEBUG "%s: deauthenticated\n", dev->name);
-       }
 
        if (ifsta->state == IEEE80211_AUTHENTICATE ||
            ifsta->state == IEEE80211_ASSOCIATE ||
@@ -2013,8 +2023,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
                                           local->hw.conf.channel->center_freq,
                                           ifsta->ssid, ifsta->ssid_len);
                if (bss) {
-                       sta->last_rssi = bss->rssi;
                        sta->last_signal = bss->signal;
+                       sta->last_qual = bss->qual;
                        sta->last_noise = bss->noise;
                        ieee80211_rx_bss_put(dev, bss);
                }
@@ -2038,8 +2048,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
         *        to between the sta_info_alloc() and sta_info_insert() above.
         */
 
-       sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP |
-                     WLAN_STA_AUTHORIZED;
+       set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP |
+                          WLAN_STA_AUTHORIZED);
 
        rates = 0;
        basic_rates = 0;
@@ -2083,7 +2093,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        else
                sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
 
-       if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param) {
+       if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param &&
+           (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
                struct ieee80211_ht_bss_info bss_info;
                ieee80211_ht_cap_ie_to_ht_info(
                                (struct ieee80211_ht_cap *)
@@ -2096,8 +2107,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
 
        rate_control_rate_init(sta, local);
 
-       if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
-               sta->flags |= WLAN_STA_WME;
+       if (elems.wmm_param) {
+               set_sta_flags(sta, WLAN_STA_WME);
                rcu_read_unlock();
                ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
                                         elems.wmm_param_len);
@@ -2281,6 +2292,7 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss)
        kfree(bss->rsn_ie);
        kfree(bss->wmm_ie);
        kfree(bss->ht_ie);
+       kfree(bss->ht_add_ie);
        kfree(bss_mesh_id(bss));
        kfree(bss_mesh_cfg(bss));
        kfree(bss);
@@ -2331,7 +2343,7 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
        int res, rates, i, j;
        struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
-       struct ieee80211_tx_control control;
+       struct ieee80211_tx_info *control;
        struct rate_selection ratesel;
        u8 *pos;
        struct ieee80211_sub_if_data *sdata;
@@ -2419,21 +2431,22 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
                        memcpy(pos, &bss->supp_rates[8], rates);
                }
 
-               memset(&control, 0, sizeof(control));
+               control = IEEE80211_SKB_CB(skb);
+
                rate_control_get_rate(dev, sband, skb, &ratesel);
-               if (!ratesel.rate) {
+               if (ratesel.rate_idx < 0) {
                        printk(KERN_DEBUG "%s: Failed to determine TX rate "
                               "for IBSS beacon\n", dev->name);
                        break;
                }
-               control.vif = &sdata->vif;
-               control.tx_rate = ratesel.rate;
+               control->control.vif = &sdata->vif;
+               control->tx_rate_idx = ratesel.rate_idx;
                if (sdata->bss_conf.use_short_preamble &&
-                   ratesel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
-                       control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
-               control.antenna_sel_tx = local->hw.conf.antenna_sel_tx;
-               control.flags |= IEEE80211_TXCTL_NO_ACK;
-               control.retry_limit = 1;
+                   sband->bitrates[ratesel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE)
+                       control->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
+               control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
+               control->flags |= IEEE80211_TX_CTL_NO_ACK;
+               control->control.retry_limit = 1;
 
                ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC);
                if (ifsta->probe_resp) {
@@ -2448,8 +2461,7 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
                }
 
                if (local->ops->beacon_update &&
-                   local->ops->beacon_update(local_to_hw(local),
-                                            skb, &control) == 0) {
+                   local->ops->beacon_update(local_to_hw(local), skb) == 0) {
                        printk(KERN_DEBUG "%s: Configured IBSS beacon "
                               "template\n", dev->name);
                        skb = NULL;
@@ -2657,6 +2669,26 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
                bss->ht_ie_len = 0;
        }
 
+       if (elems.ht_info_elem &&
+            (!bss->ht_add_ie ||
+            bss->ht_add_ie_len != elems.ht_info_elem_len ||
+            memcmp(bss->ht_add_ie, elems.ht_info_elem,
+                       elems.ht_info_elem_len))) {
+               kfree(bss->ht_add_ie);
+               bss->ht_add_ie =
+                       kmalloc(elems.ht_info_elem_len + 2, GFP_ATOMIC);
+               if (bss->ht_add_ie) {
+                       memcpy(bss->ht_add_ie, elems.ht_info_elem - 2,
+                               elems.ht_info_elem_len + 2);
+                       bss->ht_add_ie_len = elems.ht_info_elem_len + 2;
+               } else
+                       bss->ht_add_ie_len = 0;
+       } else if (!elems.ht_info_elem && bss->ht_add_ie) {
+               kfree(bss->ht_add_ie);
+               bss->ht_add_ie = NULL;
+               bss->ht_add_ie_len = 0;
+       }
+
        bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int);
        bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);
 
@@ -2682,9 +2714,9 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
 
        bss->timestamp = beacon_timestamp;
        bss->last_update = jiffies;
-       bss->rssi = rx_status->ssi;
        bss->signal = rx_status->signal;
        bss->noise = rx_status->noise;
+       bss->qual = rx_status->qual;
        if (!beacon && !bss->probe_resp)
                bss->probe_resp = true;
 
@@ -2879,10 +2911,8 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
 
        ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
 
-       if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
-               ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
-                                        elems.wmm_param_len);
-       }
+       ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
+                                elems.wmm_param_len);
 
        /* Do not send changes to driver if we are scanning. This removes
         * requirement that driver's bss_info_changed function needs to be
@@ -3478,9 +3508,9 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
                    !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len))
                        continue;
 
-               if (!selected || top_rssi < bss->rssi) {
+               if (!selected || top_rssi < bss->signal) {
                        selected = bss;
-                       top_rssi = bss->rssi;
+                       top_rssi = bss->signal;
                }
        }
        if (selected)
@@ -3557,10 +3587,12 @@ static int ieee80211_sta_create_ibss(struct net_device *dev,
        bss->beacon_int = local->hw.conf.beacon_int;
        bss->last_update = jiffies;
        bss->capability = WLAN_CAPABILITY_IBSS;
-       if (sdata->default_key) {
+
+       if (sdata->default_key)
                bss->capability |= WLAN_CAPABILITY_PRIVACY;
-       else
+       else
                sdata->drop_unencrypted = 0;
+
        bss->supp_rates_len = sband->n_bitrates;
        pos = bss->supp_rates;
        for (i = 0; i < sband->n_bitrates; i++) {
@@ -4114,8 +4146,8 @@ ieee80211_sta_scan_result(struct net_device *dev,
                                          IW_EV_FREQ_LEN);
        memset(&iwe, 0, sizeof(iwe));
        iwe.cmd = IWEVQUAL;
-       iwe.u.qual.qual = bss->signal;
-       iwe.u.qual.level = bss->rssi;
+       iwe.u.qual.qual = bss->qual;
+       iwe.u.qual.level = bss->signal;
        iwe.u.qual.noise = bss->noise;
        iwe.u.qual.updated = local->wstats_flags;
        current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
@@ -4146,6 +4178,14 @@ ieee80211_sta_scan_result(struct net_device *dev,
                                                  bss->rsn_ie);
        }
 
+       if (bss && bss->ht_ie) {
+               memset(&iwe, 0, sizeof(iwe));
+               iwe.cmd = IWEVGENIE;
+               iwe.u.data.length = bss->ht_ie_len;
+               current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+                                                 bss->ht_ie);
+       }
+
        if (bss && bss->supp_rates_len > 0) {
                /* display all supported rates in readable format */
                char *p = current_ev + IW_EV_LCP_LEN;
@@ -4247,6 +4287,7 @@ int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+
        kfree(ifsta->extra_ie);
        if (len == 0) {
                ifsta->extra_ie = NULL;
@@ -4264,9 +4305,9 @@ int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len)
 }
 
 
-struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev,
-                                        struct sk_buff *skb, u8 *bssid,
-                                        u8 *addr)
+struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev,
+                                       struct sk_buff *skb, u8 *bssid,
+                                       u8 *addr)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct sta_info *sta;
@@ -4290,7 +4331,7 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev,
        if (!sta)
                return NULL;
 
-       sta->flags |= WLAN_STA_AUTHORIZED;
+       set_sta_flags(sta, WLAN_STA_AUTHORIZED);
 
        sta->supp_rates[local->hw.conf.channel->band] =
                sdata->u.sta.supp_rates_bits[local->hw.conf.channel->band];
index 841df93807fc86fa0178cf282f4d9ce11b1c7317..0388c090dfe9bb5c1d3437c1137a2abed2ca17bf 100644 (file)
@@ -176,20 +176,24 @@ void rate_control_get_rate(struct net_device *dev,
        rcu_read_lock();
        sta = sta_info_get(local, hdr->addr1);
 
-       memset(sel, 0, sizeof(struct rate_selection));
+       sel->rate_idx = -1;
+       sel->nonerp_idx = -1;
+       sel->probe_idx = -1;
 
        ref->ops->get_rate(ref->priv, dev, sband, skb, sel);
 
+       BUG_ON(sel->rate_idx < 0);
+
        /* Select a non-ERP backup rate. */
-       if (!sel->nonerp) {
+       if (sel->nonerp_idx < 0) {
                for (i = 0; i < sband->n_bitrates; i++) {
                        struct ieee80211_rate *rate = &sband->bitrates[i];
-                       if (sel->rate->bitrate < rate->bitrate)
+                       if (sband->bitrates[sel->rate_idx].bitrate < rate->bitrate)
                                break;
 
                        if (rate_supported(sta, sband->band, i) &&
                            !(rate->flags & IEEE80211_RATE_ERP_G))
-                               sel->nonerp = rate;
+                               sel->nonerp_idx = i;
                }
        }
 
index 5b45f33cb7663364f537d1316478d3b39835a446..0ed9c8a2f56fee1a478914545eb066c43a50fccd 100644 (file)
 #include "ieee80211_i.h"
 #include "sta_info.h"
 
-/* TODO: kdoc */
+/**
+ * struct rate_selection - rate selection for rate control algos
+ * @rate: selected transmission rate index
+ * @nonerp: Non-ERP rate to use instead if ERP cannot be used
+ * @probe: rate for probing (or -1)
+ *
+ */
 struct rate_selection {
-       /* Selected transmission rate */
-       struct ieee80211_rate *rate;
-       /* Non-ERP rate to use if mac80211 decides it cannot use an ERP rate */
-       struct ieee80211_rate *nonerp;
-       /* probe with this rate, or NULL for no probing */
-       struct ieee80211_rate *probe;
+       s8 rate_idx, nonerp_idx, probe_idx;
 };
 
 struct rate_control_ops {
        struct module *module;
        const char *name;
        void (*tx_status)(void *priv, struct net_device *dev,
-                         struct sk_buff *skb,
-                         struct ieee80211_tx_status *status);
+                         struct sk_buff *skb);
        void (*get_rate)(void *priv, struct net_device *dev,
                         struct ieee80211_supported_band *band,
                         struct sk_buff *skb,
@@ -76,13 +76,12 @@ struct rate_control_ref *rate_control_get(struct rate_control_ref *ref);
 void rate_control_put(struct rate_control_ref *ref);
 
 static inline void rate_control_tx_status(struct net_device *dev,
-                                         struct sk_buff *skb,
-                                         struct ieee80211_tx_status *status)
+                                         struct sk_buff *skb)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct rate_control_ref *ref = local->rate_ctrl;
 
-       ref->ops->tx_status(ref->priv, dev, skb, status);
+       ref->ops->tx_status(ref->priv, dev, skb);
 }
 
 
@@ -138,7 +137,7 @@ static inline int rate_supported(struct sta_info *sta,
        return (sta == NULL || sta->supp_rates[band] & BIT(index));
 }
 
-static inline int
+static inline s8
 rate_lowest_index(struct ieee80211_local *local,
                  struct ieee80211_supported_band *sband,
                  struct sta_info *sta)
@@ -155,14 +154,6 @@ rate_lowest_index(struct ieee80211_local *local,
        return 0;
 }
 
-static inline struct ieee80211_rate *
-rate_lowest(struct ieee80211_local *local,
-           struct ieee80211_supported_band *sband,
-           struct sta_info *sta)
-{
-       return &sband->bitrates[rate_lowest_index(local, sband, sta)];
-}
-
 
 /* functions for rate control related to a device */
 int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
index 04afc13ed82551c87c2e2aa292cc00012da7520d..2078803d3581dfdb6c4268e03f482bf0792d3c1c 100644 (file)
@@ -61,7 +61,7 @@ enum rc_pid_event_type {
 union rc_pid_event_data {
        /* RC_PID_EVENT_TX_STATUS */
        struct {
-               struct ieee80211_tx_status tx_status;
+               struct ieee80211_tx_info tx_status;
        };
        /* RC_PID_EVENT_TYPE_RATE_CHANGE */
        /* RC_PID_EVENT_TYPE_TX_RATE */
@@ -158,7 +158,7 @@ struct rc_pid_debugfs_entries {
 };
 
 void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf,
-                                            struct ieee80211_tx_status *stat);
+                                     struct ieee80211_tx_info *stat);
 
 void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf,
                                               int index, int rate);
index a849b745bdb56b6f83b19a98e73f069f42341621..e8945413e4a2b237619602912830e6d4dc33b6f8 100644 (file)
@@ -237,8 +237,7 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo,
 }
 
 static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
-                                      struct sk_buff *skb,
-                                      struct ieee80211_tx_status *status)
+                                      struct sk_buff *skb)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@@ -248,6 +247,7 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
        struct rc_pid_sta_info *spinfo;
        unsigned long period;
        struct ieee80211_supported_band *sband;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
        rcu_read_lock();
 
@@ -266,28 +266,28 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
 
        /* Ignore all frames that were sent with a different rate than the rate
         * we currently advise mac80211 to use. */
-       if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx])
+       if (info->tx_rate_idx != sta->txrate_idx)
                goto unlock;
 
        spinfo = sta->rate_ctrl_priv;
        spinfo->tx_num_xmit++;
 
 #ifdef CONFIG_MAC80211_DEBUGFS
-       rate_control_pid_event_tx_status(&spinfo->events, status);
+       rate_control_pid_event_tx_status(&spinfo->events, info);
 #endif
 
        /* We count frames that totally failed to be transmitted as two bad
         * frames, those that made it out but had some retries as one good and
         * one bad frame. */
-       if (status->excessive_retries) {
+       if (info->status.excessive_retries) {
                spinfo->tx_num_failed += 2;
                spinfo->tx_num_xmit++;
-       } else if (status->retry_count) {
+       } else if (info->status.retry_count) {
                spinfo->tx_num_failed++;
                spinfo->tx_num_xmit++;
        }
 
-       if (status->excessive_retries) {
+       if (info->status.excessive_retries) {
                sta->tx_retry_failed++;
                sta->tx_num_consecutive_failures++;
                sta->tx_num_mpdu_fail++;
@@ -295,8 +295,8 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
                sta->tx_num_consecutive_failures = 0;
                sta->tx_num_mpdu_ok++;
        }
-       sta->tx_retry_count += status->retry_count;
-       sta->tx_num_mpdu_fail += status->retry_count;
+       sta->tx_retry_count += info->status.retry_count;
+       sta->tx_num_mpdu_fail += info->status.retry_count;
 
        /* Update PID controller state. */
        period = (HZ * pinfo->sampling_period + 500) / 1000;
@@ -330,7 +330,7 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
        fc = le16_to_cpu(hdr->frame_control);
        if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
            is_multicast_ether_addr(hdr->addr1) || !sta) {
-               sel->rate = rate_lowest(local, sband, sta);
+               sel->rate_idx = rate_lowest_index(local, sband, sta);
                rcu_read_unlock();
                return;
        }
@@ -349,7 +349,7 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
 
        rcu_read_unlock();
 
-       sel->rate = &sband->bitrates[rateidx];
+       sel->rate_idx = rateidx;
 
 #ifdef CONFIG_MAC80211_DEBUGFS
        rate_control_pid_event_tx_rate(
index ff5c380f3c1343805108b1d561ed931161a8e20e..8121d3bc683585e22443f7621a90697d73edddbe 100644 (file)
@@ -39,11 +39,11 @@ static void rate_control_pid_event(struct rc_pid_event_buffer *buf,
 }
 
 void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf,
-                                            struct ieee80211_tx_status *stat)
+                                     struct ieee80211_tx_info *stat)
 {
        union rc_pid_event_data evd;
 
-       memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_status));
+       memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_info));
        rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_STATUS, &evd);
 }
 
@@ -167,8 +167,8 @@ static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf,
        switch (ev->type) {
        case RC_PID_EVENT_TYPE_TX_STATUS:
                p += snprintf(pb + p, length - p, "tx_status %u %u",
-                             ev->data.tx_status.excessive_retries,
-                             ev->data.tx_status.retry_count);
+                             ev->data.tx_status.status.excessive_retries,
+                             ev->data.tx_status.status.retry_count);
                break;
        case RC_PID_EVENT_TYPE_RATE_CHANGE:
                p += snprintf(pb + p, length - p, "rate_change %d %d",
index 0941e5d6a5222caa54a0b61c7000bda6487e0f0b..a3643fd86af96d14131d234e3f3039e291ab3aa4 100644 (file)
@@ -77,6 +77,134 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status,
        return 0;
 }
 
+static int
+ieee80211_rx_radiotap_len(struct ieee80211_local *local,
+                         struct ieee80211_rx_status *status)
+{
+       int len;
+
+       /* always present fields */
+       len = sizeof(struct ieee80211_radiotap_header) + 9;
+
+       if (status->flag & RX_FLAG_TSFT)
+               len += 8;
+       if (local->hw.flags & IEEE80211_HW_SIGNAL_DB ||
+           local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
+               len += 1;
+       if (local->hw.flags & IEEE80211_HW_NOISE_DBM)
+               len += 1;
+
+       if (len & 1) /* padding for RX_FLAGS if necessary */
+               len++;
+
+       /* make sure radiotap starts at a naturally aligned address */
+       if (len % 8)
+               len = roundup(len, 8);
+
+       return len;
+}
+
+/**
+ * ieee80211_add_rx_radiotap_header - add radiotap header
+ *
+ * add a radiotap header containing all the fields which the hardware provided.
+ */
+static void
+ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
+                                struct sk_buff *skb,
+                                struct ieee80211_rx_status *status,
+                                struct ieee80211_rate *rate,
+                                int rtap_len)
+{
+       struct ieee80211_radiotap_header *rthdr;
+       unsigned char *pos;
+
+       rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len);
+       memset(rthdr, 0, rtap_len);
+
+       /* radiotap header, set always present flags */
+       rthdr->it_present =
+               cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
+                           (1 << IEEE80211_RADIOTAP_RATE) |
+                           (1 << IEEE80211_RADIOTAP_CHANNEL) |
+                           (1 << IEEE80211_RADIOTAP_ANTENNA) |
+                           (1 << IEEE80211_RADIOTAP_RX_FLAGS));
+       rthdr->it_len = cpu_to_le16(rtap_len);
+
+       pos = (unsigned char *)(rthdr+1);
+
+       /* the order of the following fields is important */
+
+       /* IEEE80211_RADIOTAP_TSFT */
+       if (status->flag & RX_FLAG_TSFT) {
+               *(__le64 *)pos = cpu_to_le64(status->mactime);
+               rthdr->it_present |=
+                       cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT);
+               pos += 8;
+       }
+
+       /* IEEE80211_RADIOTAP_FLAGS */
+       if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
+               *pos |= IEEE80211_RADIOTAP_F_FCS;
+       pos++;
+
+       /* IEEE80211_RADIOTAP_RATE */
+       *pos = rate->bitrate / 5;
+       pos++;
+
+       /* IEEE80211_RADIOTAP_CHANNEL */
+       *(__le16 *)pos = cpu_to_le16(status->freq);
+       pos += 2;
+       if (status->band == IEEE80211_BAND_5GHZ)
+               *(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_OFDM |
+                                            IEEE80211_CHAN_5GHZ);
+       else
+               *(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_DYN |
+                                            IEEE80211_CHAN_2GHZ);
+       pos += 2;
+
+       /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */
+       if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
+               *pos = status->signal;
+               rthdr->it_present |=
+                       cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
+               pos++;
+       }
+
+       /* IEEE80211_RADIOTAP_DBM_ANTNOISE */
+       if (local->hw.flags & IEEE80211_HW_NOISE_DBM) {
+               *pos = status->noise;
+               rthdr->it_present |=
+                       cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE);
+               pos++;
+       }
+
+       /* IEEE80211_RADIOTAP_LOCK_QUALITY is missing */
+
+       /* IEEE80211_RADIOTAP_ANTENNA */
+       *pos = status->antenna;
+       pos++;
+
+       /* IEEE80211_RADIOTAP_DB_ANTSIGNAL */
+       if (local->hw.flags & IEEE80211_HW_SIGNAL_DB) {
+               *pos = status->signal;
+               rthdr->it_present |=
+                       cpu_to_le32(1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL);
+               pos++;
+       }
+
+       /* IEEE80211_RADIOTAP_DB_ANTNOISE is not used */
+
+       /* IEEE80211_RADIOTAP_RX_FLAGS */
+       /* ensure 2 byte alignment for the 2 byte field as required */
+       if ((pos - (unsigned char *)rthdr) & 1)
+               pos++;
+       /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */
+       if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
+               *(__le16 *)pos |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS);
+       pos += 2;
+}
+
 /*
  * This function copies a received frame to all monitor interfaces and
  * returns a cleaned-up SKB that no longer includes the FCS nor the
@@ -89,17 +217,6 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
 {
        struct ieee80211_sub_if_data *sdata;
        int needed_headroom = 0;
-       struct ieee80211_radiotap_header *rthdr;
-       __le64 *rttsft = NULL;
-       struct ieee80211_rtap_fixed_data {
-               u8 flags;
-               u8 rate;
-               __le16 chan_freq;
-               __le16 chan_flags;
-               u8 antsignal;
-               u8 padding_for_rxflags;
-               __le16 rx_flags;
-       } __attribute__ ((packed)) *rtfixed;
        struct sk_buff *skb, *skb2;
        struct net_device *prev_dev = NULL;
        int present_fcs_len = 0;
@@ -116,8 +233,8 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
        if (status->flag & RX_FLAG_RADIOTAP)
                rtap_len = ieee80211_get_radiotap_len(origskb->data);
        else
-               /* room for radiotap header, always present fields and TSFT */
-               needed_headroom = sizeof(*rthdr) + sizeof(*rtfixed) + 8;
+               /* room for the radiotap header based on driver features */
+               needed_headroom = ieee80211_rx_radiotap_len(local, status);
 
        if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
                present_fcs_len = FCS_LEN;
@@ -163,55 +280,9 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
        }
 
        /* if necessary, prepend radiotap information */
-       if (!(status->flag & RX_FLAG_RADIOTAP)) {
-               rtfixed = (void *) skb_push(skb, sizeof(*rtfixed));
-               rtap_len = sizeof(*rthdr) + sizeof(*rtfixed);
-               if (status->flag & RX_FLAG_TSFT) {
-                       rttsft = (void *) skb_push(skb, sizeof(*rttsft));
-                       rtap_len += 8;
-               }
-               rthdr = (void *) skb_push(skb, sizeof(*rthdr));
-               memset(rthdr, 0, sizeof(*rthdr));
-               memset(rtfixed, 0, sizeof(*rtfixed));
-               rthdr->it_present =
-                       cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
-                                   (1 << IEEE80211_RADIOTAP_RATE) |
-                                   (1 << IEEE80211_RADIOTAP_CHANNEL) |
-                                   (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |
-                                   (1 << IEEE80211_RADIOTAP_RX_FLAGS));
-               rtfixed->flags = 0;
-               if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
-                       rtfixed->flags |= IEEE80211_RADIOTAP_F_FCS;
-
-               if (rttsft) {
-                       *rttsft = cpu_to_le64(status->mactime);
-                       rthdr->it_present |=
-                               cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT);
-               }
-
-               /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */
-               rtfixed->rx_flags = 0;
-               if (status->flag &
-                   (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
-                       rtfixed->rx_flags |=
-                               cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS);
-
-               rtfixed->rate = rate->bitrate / 5;
-
-               rtfixed->chan_freq = cpu_to_le16(status->freq);
-
-               if (status->band == IEEE80211_BAND_5GHZ)
-                       rtfixed->chan_flags =
-                               cpu_to_le16(IEEE80211_CHAN_OFDM |
-                                           IEEE80211_CHAN_5GHZ);
-               else
-                       rtfixed->chan_flags =
-                               cpu_to_le16(IEEE80211_CHAN_DYN |
-                                           IEEE80211_CHAN_2GHZ);
-
-               rtfixed->antsignal = status->ssi;
-               rthdr->it_len = cpu_to_le16(rtap_len);
-       }
+       if (!(status->flag & RX_FLAG_RADIOTAP))
+               ieee80211_add_rx_radiotap_header(local, skb, status, rate,
+                                                needed_headroom);
 
        skb_reset_mac_header(skb);
        skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -275,11 +346,6 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
                }
        }
 
-       I802_DEBUG_INC(rx->local->wme_rx_queue[tid]);
-       /* only a debug counter, sta might not be assigned properly yet */
-       if (rx->sta)
-               I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]);
-
        rx->queue = tid;
        /* Set skb->priority to 1d tag if highest order bit of TID is not set.
         * For now, set skb->priority to 0 for other cases. */
@@ -321,50 +387,8 @@ static void ieee80211_verify_ip_alignment(struct ieee80211_rx_data *rx)
 }
 
 
-static u32 ieee80211_rx_load_stats(struct ieee80211_local *local,
-                                  struct sk_buff *skb,
-                                  struct ieee80211_rx_status *status,
-                                  struct ieee80211_rate *rate)
-{
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       u32 load = 0, hdrtime;
-
-       /* Estimate total channel use caused by this frame */
-
-       /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
-        * 1 usec = 1/8 * (1080 / 10) = 13.5 */
-
-       if (status->band == IEEE80211_BAND_5GHZ ||
-           (status->band == IEEE80211_BAND_5GHZ &&
-            rate->flags & IEEE80211_RATE_ERP_G))
-               hdrtime = CHAN_UTIL_HDR_SHORT;
-       else
-               hdrtime = CHAN_UTIL_HDR_LONG;
-
-       load = hdrtime;
-       if (!is_multicast_ether_addr(hdr->addr1))
-               load += hdrtime;
-
-       /* TODO: optimise again */
-       load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate;
-
-       /* Divide channel_use by 8 to avoid wrapping around the counter */
-       load >>= CHAN_UTIL_SHIFT;
-
-       return load;
-}
-
 /* rx handlers */
 
-static ieee80211_rx_result
-ieee80211_rx_h_if_stats(struct ieee80211_rx_data *rx)
-{
-       if (rx->sta)
-               rx->sta->channel_use_raw += rx->load;
-       rx->sdata->channel_use_raw += rx->load;
-       return RX_CONTINUE;
-}
-
 static ieee80211_rx_result
 ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
 {
@@ -484,7 +508,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
                      ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL &&
                       (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) &&
                     rx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
-                    (!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) {
+                    (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) {
                if ((!(rx->fc & IEEE80211_FCTL_FROMDS) &&
                     !(rx->fc & IEEE80211_FCTL_TODS) &&
                     (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)
@@ -635,8 +659,7 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
 
        if (sdata->bss)
                atomic_inc(&sdata->bss->num_sta_ps);
-       sta->flags |= WLAN_STA_PS;
-       sta->flags &= ~WLAN_STA_PSPOLL;
+       set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL);
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
        printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n",
               dev->name, print_mac(mac, sta->addr), sta->aid);
@@ -649,7 +672,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
        struct sk_buff *skb;
        int sent = 0;
        struct ieee80211_sub_if_data *sdata;
-       struct ieee80211_tx_packet_data *pkt_data;
+       struct ieee80211_tx_info *info;
        DECLARE_MAC_BUF(mac);
 
        sdata = sta->sdata;
@@ -657,7 +680,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
        if (sdata->bss)
                atomic_dec(&sdata->bss->num_sta_ps);
 
-       sta->flags &= ~(WLAN_STA_PS | WLAN_STA_PSPOLL);
+       clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL);
 
        if (!skb_queue_empty(&sta->ps_tx_buf))
                sta_info_clear_tim_bit(sta);
@@ -669,13 +692,13 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
 
        /* Send all buffered frames to the station */
        while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
-               pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+               info = IEEE80211_SKB_CB(skb);
                sent++;
-               pkt_data->flags |= IEEE80211_TXPD_REQUEUE;
+               info->flags |= IEEE80211_TX_CTL_REQUEUE;
                dev_queue_xmit(skb);
        }
        while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
-               pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+               info = IEEE80211_SKB_CB(skb);
                local->total_ps_buffered--;
                sent++;
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
@@ -683,7 +706,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
                       "since STA not sleeping anymore\n", dev->name,
                       print_mac(mac, sta->addr), sta->aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
-               pkt_data->flags |= IEEE80211_TXPD_REQUEUE;
+               info->flags |= IEEE80211_TX_CTL_REQUEUE;
                dev_queue_xmit(skb);
        }
 
@@ -725,16 +748,17 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
 
        sta->rx_fragments++;
        sta->rx_bytes += rx->skb->len;
-       sta->last_rssi = rx->status->ssi;
        sta->last_signal = rx->status->signal;
+       sta->last_qual = rx->status->qual;
        sta->last_noise = rx->status->noise;
 
        if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) {
                /* Change STA power saving mode only in the end of a frame
                 * exchange sequence */
-               if ((sta->flags & WLAN_STA_PS) && !(rx->fc & IEEE80211_FCTL_PM))
+               if (test_sta_flags(sta, WLAN_STA_PS) &&
+                   !(rx->fc & IEEE80211_FCTL_PM))
                        rx->sent_ps_buffered += ap_sta_ps_end(dev, sta);
-               else if (!(sta->flags & WLAN_STA_PS) &&
+               else if (!test_sta_flags(sta, WLAN_STA_PS) &&
                         (rx->fc & IEEE80211_FCTL_PM))
                        ap_sta_ps_start(dev, sta);
        }
@@ -988,7 +1012,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
                 * Tell TX path to send one frame even though the STA may
                 * still remain is PS mode after this frame exchange.
                 */
-               rx->sta->flags |= WLAN_STA_PSPOLL;
+               set_sta_flags(rx->sta, WLAN_STA_PSPOLL);
 
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
                printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n",
@@ -1051,7 +1075,8 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx)
 static int
 ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)
 {
-       if (unlikely(!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED))) {
+       if (unlikely(!rx->sta ||
+           !test_sta_flags(rx->sta, WLAN_STA_AUTHORIZED))) {
 #ifdef CONFIG_MAC80211_DEBUG
                if (net_ratelimit())
                        printk(KERN_DEBUG "%s: dropped frame "
@@ -1713,7 +1738,6 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx)
 typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_rx_data *);
 static ieee80211_rx_handler ieee80211_rx_handlers[] =
 {
-       ieee80211_rx_h_if_stats,
        ieee80211_rx_h_passive_scan,
        ieee80211_rx_h_check,
        ieee80211_rx_h_decrypt,
@@ -1872,7 +1896,6 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
 static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
                                         struct sk_buff *skb,
                                         struct ieee80211_rx_status *status,
-                                        u32 load,
                                         struct ieee80211_rate *rate)
 {
        struct ieee80211_local *local = hw_to_local(hw);
@@ -1891,7 +1914,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
        rx.local = local;
 
        rx.status = status;
-       rx.load = load;
        rx.rate = rate;
        rx.fc = le16_to_cpu(hdr->frame_control);
        type = rx.fc & IEEE80211_FCTL_FTYPE;
@@ -2000,7 +2022,6 @@ u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
        struct ieee80211_rx_status status;
        u16 head_seq_num, buf_size;
        int index;
-       u32 pkt_load;
        struct ieee80211_supported_band *sband;
        struct ieee80211_rate *rate;
 
@@ -2035,12 +2056,9 @@ u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
                                        sizeof(status));
                                sband = local->hw.wiphy->bands[status.band];
                                rate = &sband->bitrates[status.rate_idx];
-                               pkt_load = ieee80211_rx_load_stats(local,
-                                               tid_agg_rx->reorder_buf[index],
-                                               &status, rate);
                                __ieee80211_rx_handle_packet(hw,
                                        tid_agg_rx->reorder_buf[index],
-                                       &status, pkt_load, rate);
+                                       &status, rate);
                                tid_agg_rx->stored_mpdu_num--;
                                tid_agg_rx->reorder_buf[index] = NULL;
                        }
@@ -2082,11 +2100,8 @@ u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
                        sizeof(status));
                sband = local->hw.wiphy->bands[status.band];
                rate = &sband->bitrates[status.rate_idx];
-               pkt_load = ieee80211_rx_load_stats(local,
-                                       tid_agg_rx->reorder_buf[index],
-                                       &status, rate);
                __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index],
-                                            &status, pkt_load, rate);
+                                            &status, rate);
                tid_agg_rx->stored_mpdu_num--;
                tid_agg_rx->reorder_buf[index] = NULL;
                tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
@@ -2165,7 +2180,6 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
                    struct ieee80211_rx_status *status)
 {
        struct ieee80211_local *local = hw_to_local(hw);
-       u32 pkt_load;
        struct ieee80211_rate *rate = NULL;
        struct ieee80211_supported_band *sband;
 
@@ -2205,11 +2219,8 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
                return;
        }
 
-       pkt_load = ieee80211_rx_load_stats(local, skb, status, rate);
-       local->channel_use_raw += pkt_load;
-
        if (!ieee80211_rx_reorder_ampdu(local, skb))
-               __ieee80211_rx_handle_packet(hw, skb, status, pkt_load, rate);
+               __ieee80211_rx_handle_packet(hw, skb, status, rate);
 
        rcu_read_unlock();
 }
index 7d4fe4a52929292a685ef3cfaebfb3a07097754b..c24770cb02c5d696f160136c497f2a9544747128 100644 (file)
@@ -202,14 +202,12 @@ void sta_info_destroy(struct sta_info *sta)
                dev_kfree_skb_any(skb);
 
        for (i = 0; i <  STA_TID_NUM; i++) {
-               spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
+               spin_lock_bh(&sta->lock);
                if (sta->ampdu_mlme.tid_rx[i])
                  del_timer_sync(&sta->ampdu_mlme.tid_rx[i]->session_timer);
-               spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
-               spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
                if (sta->ampdu_mlme.tid_tx[i])
                  del_timer_sync(&sta->ampdu_mlme.tid_tx[i]->addba_resp_timer);
-               spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+               spin_unlock_bh(&sta->lock);
        }
 
        __sta_info_free(local, sta);
@@ -236,6 +234,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
        if (!sta)
                return NULL;
 
+       spin_lock_init(&sta->lock);
+
        memcpy(sta->addr, addr, ETH_ALEN);
        sta->local = local;
        sta->sdata = sdata;
@@ -249,15 +249,13 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
                return NULL;
        }
 
-       spin_lock_init(&sta->ampdu_mlme.ampdu_rx);
-       spin_lock_init(&sta->ampdu_mlme.ampdu_tx);
        for (i = 0; i < STA_TID_NUM; i++) {
                /* timer_to_tid must be initialized with identity mapping to
                 * enable session_timer's data differentiation. refer to
                 * sta_rx_agg_session_timer_expired for useage */
                sta->timer_to_tid[i] = i;
                /* tid to tx queue: initialize according to HW (0 is valid) */
-               sta->tid_to_tx_q[i] = local->hw.queues;
+               sta->tid_to_tx_q[i] = ieee80211_num_queues(&local->hw);
                /* rx */
                sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE;
                sta->ampdu_mlme.tid_rx[i] = NULL;
@@ -276,7 +274,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
 
 #ifdef CONFIG_MAC80211_MESH
        sta->plink_state = PLINK_LISTEN;
-       spin_lock_init(&sta->plink_lock);
        init_timer(&sta->plink_timer);
 #endif
 
@@ -437,8 +434,7 @@ void __sta_info_unlink(struct sta_info **sta)
 
        list_del(&(*sta)->list);
 
-       if ((*sta)->flags & WLAN_STA_PS) {
-               (*sta)->flags &= ~WLAN_STA_PS;
+       if (test_and_clear_sta_flags(*sta, WLAN_STA_PS)) {
                if (sdata->bss)
                        atomic_dec(&sdata->bss->num_sta_ps);
                __sta_info_clear_tim_bit(sdata->bss, *sta);
@@ -515,20 +511,20 @@ static inline int sta_info_buffer_expired(struct ieee80211_local *local,
                                          struct sta_info *sta,
                                          struct sk_buff *skb)
 {
-       struct ieee80211_tx_packet_data *pkt_data;
+       struct ieee80211_tx_info *info;
        int timeout;
 
        if (!skb)
                return 0;
 
-       pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+       info = IEEE80211_SKB_CB(skb);
 
        /* Timeout: (2 * listen_interval * beacon_int * 1024 / 1000000) sec */
        timeout = (sta->listen_interval * local->hw.conf.beacon_int * 32 /
                   15625) * HZ;
        if (timeout < STA_TX_BUFFER_EXPIRE)
                timeout = STA_TX_BUFFER_EXPIRE;
-       return time_after(jiffies, pkt_data->jiffies + timeout);
+       return time_after(jiffies, info->control.jiffies + timeout);
 }
 
 
index f8c95bc9659cae3065c0a58b0757dde9b4695dcc..95753f860acf311efc7bf28868ff08c633800db4 100644 (file)
@@ -32,7 +32,7 @@
  * @WLAN_STA_WDS: Station is one of our WDS peers.
  * @WLAN_STA_PSPOLL: Station has just PS-polled us.
  * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the
- *     IEEE80211_TXCTL_CLEAR_PS_FILT control flag) when the next
+ *     IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next
  *     frame to this station is transmitted.
  */
 enum ieee80211_sta_info_flags {
@@ -129,23 +129,19 @@ enum plink_state {
  *
  * @tid_state_rx: TID's state in Rx session state machine.
  * @tid_rx: aggregation info for Rx per TID
- * @ampdu_rx: for locking sections in aggregation Rx flow
  * @tid_state_tx: TID's state in Tx session state machine.
  * @tid_tx: aggregation info for Tx per TID
  * @addba_req_num: number of times addBA request has been sent.
- * @ampdu_tx: for locking sectionsi in aggregation Tx flow
  * @dialog_token_allocator: dialog token enumerator for each new session;
  */
 struct sta_ampdu_mlme {
        /* rx */
        u8 tid_state_rx[STA_TID_NUM];
        struct tid_ampdu_rx *tid_rx[STA_TID_NUM];
-       spinlock_t ampdu_rx;
        /* tx */
        u8 tid_state_tx[STA_TID_NUM];
        struct tid_ampdu_tx *tid_tx[STA_TID_NUM];
        u8 addba_req_num[STA_TID_NUM];
-       spinlock_t ampdu_tx;
        u8 dialog_token_allocator;
 };
 
@@ -177,6 +173,8 @@ struct sta_ampdu_mlme {
  * @rx_bytes: Number of bytes received from this STA
  * @supp_rates: Bitmap of supported rates (per band)
  * @ht_info: HT capabilities of this STA
+ * @lock: used for locking all fields that require locking, see comments
+ *     in the header file.
  */
 struct sta_info {
        /* General information, mostly static */
@@ -187,6 +185,7 @@ struct sta_info {
        struct ieee80211_key *key;
        struct rate_control_ref *rate_ctrl;
        void *rate_ctrl_priv;
+       spinlock_t lock;
        struct ieee80211_ht_info ht_info;
        u64 supp_rates[IEEE80211_NUM_BANDS];
        u8 addr[ETH_ALEN];
@@ -199,7 +198,7 @@ struct sta_info {
         */
        u8 pin_status;
 
-       /* frequently updated information, needs locking? */
+       /* frequently updated information, locked with lock spinlock */
        u32 flags;
 
        /*
@@ -217,8 +216,8 @@ struct sta_info {
                                       * from this STA */
        unsigned long rx_fragments; /* number of received MPDUs */
        unsigned long rx_dropped; /* number of dropped MPDUs from this STA */
-       int last_rssi; /* RSSI of last received frame from this STA */
        int last_signal; /* signal of last received frame from this STA */
+       int last_qual;  /* qual of last received frame from this STA */
        int last_noise; /* noise of last received frame from this STA */
        /* last received seq/frag number from this STA (per RX queue) */
        __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES];
@@ -246,12 +245,8 @@ struct sta_info {
        unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES];
 #endif
 
-       /* Debug counters, no locking doesn't matter */
-       int channel_use;
-       int channel_use_raw;
-
        /*
-        * Aggregation information, comes with own locking.
+        * Aggregation information, locked with lock.
         */
        struct sta_ampdu_mlme ampdu_mlme;
        u8 timer_to_tid[STA_TID_NUM];   /* identity mapping to ID timers */
@@ -270,9 +265,6 @@ struct sta_info {
        enum plink_state plink_state;
        u32 plink_timeout;
        struct timer_list plink_timer;
-       spinlock_t plink_lock;  /* For peer_state reads / updates and other
-                                  updates in the structure. Ensures robust
-                                  transitions for the peerlink FSM */
 #endif
 
 #ifdef CONFIG_MAC80211_DEBUGFS
@@ -299,6 +291,64 @@ static inline enum plink_state sta_plink_state(struct sta_info *sta)
        return PLINK_LISTEN;
 }
 
+static inline void set_sta_flags(struct sta_info *sta, const u32 flags)
+{
+       spin_lock_bh(&sta->lock);
+       sta->flags |= flags;
+       spin_unlock_bh(&sta->lock);
+}
+
+static inline void clear_sta_flags(struct sta_info *sta, const u32 flags)
+{
+       spin_lock_bh(&sta->lock);
+       sta->flags &= ~flags;
+       spin_unlock_bh(&sta->lock);
+}
+
+static inline void set_and_clear_sta_flags(struct sta_info *sta,
+                                          const u32 set, const u32 clear)
+{
+       spin_lock_bh(&sta->lock);
+       sta->flags |= set;
+       sta->flags &= ~clear;
+       spin_unlock_bh(&sta->lock);
+}
+
+static inline u32 test_sta_flags(struct sta_info *sta, const u32 flags)
+{
+       u32 ret;
+
+       spin_lock_bh(&sta->lock);
+       ret = sta->flags & flags;
+       spin_unlock_bh(&sta->lock);
+
+       return ret;
+}
+
+static inline u32 test_and_clear_sta_flags(struct sta_info *sta,
+                                          const u32 flags)
+{
+       u32 ret;
+
+       spin_lock_bh(&sta->lock);
+       ret = sta->flags & flags;
+       sta->flags &= ~flags;
+       spin_unlock_bh(&sta->lock);
+
+       return ret;
+}
+
+static inline u32 get_sta_flags(struct sta_info *sta)
+{
+       u32 ret;
+
+       spin_lock_bh(&sta->lock);
+       ret = sta->flags;
+       spin_unlock_bh(&sta->lock);
+
+       return ret;
+}
+
 
 /* Maximum number of concurrently registered stations */
 #define MAX_STA_COUNT 2007
index 09093da24af625f8d42db34d9f285734c1e7b5d3..a00cf1ea7719d1584a2d3440146d9348f1835539 100644 (file)
@@ -6,25 +6,23 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
 #include <linux/kernel.h>
+#include <linux/bitops.h>
 #include <linux/types.h>
 #include <linux/netdevice.h>
+#include <asm/unaligned.h>
 
 #include <net/mac80211.h>
 #include "key.h"
 #include "tkip.h"
 #include "wep.h"
 
-
-/* TKIP key mixing functions */
-
-
 #define PHASE1_LOOP_COUNT 8
 
-
-/* 2-byte by 2-byte subset of the full AES S-box table; second part of this
- * table is identical to first part but byte-swapped */
+/*
+ * 2-byte by 2-byte subset of the full AES S-box table; second part of this
+ * table is identical to first part but byte-swapped
+ */
 static const u16 tkip_sbox[256] =
 {
        0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
@@ -61,84 +59,48 @@ static const u16 tkip_sbox[256] =
        0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
 };
 
-
-static inline u16 Mk16(u8 x, u8 y)
-{
-       return ((u16) x << 8) | (u16) y;
-}
-
-
-static inline u8 Hi8(u16 v)
-{
-       return v >> 8;
-}
-
-
-static inline u8 Lo8(u16 v)
-{
-       return v & 0xff;
-}
-
-
-static inline u16 Hi16(u32 v)
+static u16 tkipS(u16 val)
 {
-       return v >> 16;
+       return tkip_sbox[val & 0xff] ^ swab16(tkip_sbox[val >> 8]);
 }
 
-
-static inline u16 Lo16(u32 v)
-{
-       return v & 0xffff;
-}
-
-
-static inline u16 RotR1(u16 v)
-{
-       return (v >> 1) | ((v & 0x0001) << 15);
-}
-
-
-static inline u16 tkip_S(u16 val)
-{
-       u16 a = tkip_sbox[Hi8(val)];
-
-       return tkip_sbox[Lo8(val)] ^ Hi8(a) ^ (Lo8(a) << 8);
-}
-
-
-
-/* P1K := Phase1(TA, TK, TSC)
+/*
+ * P1K := Phase1(TA, TK, TSC)
  * TA = transmitter address (48 bits)
  * TK = dot11DefaultKeyValue or dot11KeyMappingValue (128 bits)
  * TSC = TKIP sequence counter (48 bits, only 32 msb bits used)
  * P1K: 80 bits
  */
-static void tkip_mixing_phase1(const u8 *ta, const u8 *tk, u32 tsc_IV32,
-                              u16 *p1k)
+static void tkip_mixing_phase1(struct ieee80211_key *key, const u8 *ta,
+                              struct tkip_ctx *ctx, u32 tsc_IV32)
 {
        int i, j;
+       const u8 *tk = &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY];
+       u16 *p1k = ctx->p1k;
 
-       p1k[0] = Lo16(tsc_IV32);
-       p1k[1] = Hi16(tsc_IV32);
-       p1k[2] = Mk16(ta[1], ta[0]);
-       p1k[3] = Mk16(ta[3], ta[2]);
-       p1k[4] = Mk16(ta[5], ta[4]);
+       p1k[0] = tsc_IV32 & 0xFFFF;
+       p1k[1] = tsc_IV32 >> 16;
+       p1k[2] = get_unaligned_le16(ta + 0);
+       p1k[3] = get_unaligned_le16(ta + 2);
+       p1k[4] = get_unaligned_le16(ta + 4);
 
        for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
                j = 2 * (i & 1);
-               p1k[0] += tkip_S(p1k[4] ^ Mk16(tk[ 1 + j], tk[ 0 + j]));
-               p1k[1] += tkip_S(p1k[0] ^ Mk16(tk[ 5 + j], tk[ 4 + j]));
-               p1k[2] += tkip_S(p1k[1] ^ Mk16(tk[ 9 + j], tk[ 8 + j]));
-               p1k[3] += tkip_S(p1k[2] ^ Mk16(tk[13 + j], tk[12 + j]));
-               p1k[4] += tkip_S(p1k[3] ^ Mk16(tk[ 1 + j], tk[ 0 + j])) + i;
+               p1k[0] += tkipS(p1k[4] ^ get_unaligned_le16(tk + 0 + j));
+               p1k[1] += tkipS(p1k[0] ^ get_unaligned_le16(tk + 4 + j));
+               p1k[2] += tkipS(p1k[1] ^ get_unaligned_le16(tk + 8 + j));
+               p1k[3] += tkipS(p1k[2] ^ get_unaligned_le16(tk + 12 + j));
+               p1k[4] += tkipS(p1k[3] ^ get_unaligned_le16(tk + 0 + j)) + i;
        }
+       ctx->initialized = 1;
 }
 
-
-static void tkip_mixing_phase2(const u16 *p1k, const u8 *tk, u16 tsc_IV16,
-                              u8 *rc4key)
+static void tkip_mixing_phase2(struct ieee80211_key *key, struct tkip_ctx *ctx,
+                              u16 tsc_IV16, u8 *rc4key)
 {
        u16 ppk[6];
+       const u16 *p1k = ctx->p1k;
+       const u8 *tk = &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY];
        int i;
 
        ppk[0] = p1k[0];
@@ -148,70 +110,51 @@ static void tkip_mixing_phase2(const u16 *p1k, const u8 *tk, u16 tsc_IV16,
        ppk[4] = p1k[4];
        ppk[5] = p1k[4] + tsc_IV16;
 
-       ppk[0] += tkip_S(ppk[5] ^ Mk16(tk[ 1], tk[ 0]));
-       ppk[1] += tkip_S(ppk[0] ^ Mk16(tk[ 3], tk[ 2]));
-       ppk[2] += tkip_S(ppk[1] ^ Mk16(tk[ 5], tk[ 4]));
-       ppk[3] += tkip_S(ppk[2] ^ Mk16(tk[ 7], tk[ 6]));
-       ppk[4] += tkip_S(ppk[3] ^ Mk16(tk[ 9], tk[ 8]));
-       ppk[5] += tkip_S(ppk[4] ^ Mk16(tk[11], tk[10]));
-       ppk[0] +=  RotR1(ppk[5] ^ Mk16(tk[13], tk[12]));
-       ppk[1] +=  RotR1(ppk[0] ^ Mk16(tk[15], tk[14]));
-       ppk[2] +=  RotR1(ppk[1]);
-       ppk[3] +=  RotR1(ppk[2]);
-       ppk[4] +=  RotR1(ppk[3]);
-       ppk[5] +=  RotR1(ppk[4]);
-
-       rc4key[0] = Hi8(tsc_IV16);
-       rc4key[1] = (Hi8(tsc_IV16) | 0x20) & 0x7f;
-       rc4key[2] = Lo8(tsc_IV16);
-       rc4key[3] = Lo8((ppk[5] ^ Mk16(tk[1], tk[0])) >> 1);
-
-       for (i = 0; i < 6; i++) {
-               rc4key[4 + 2 * i] = Lo8(ppk[i]);
-               rc4key[5 + 2 * i] = Hi8(ppk[i]);
-       }
+       ppk[0] += tkipS(ppk[5] ^ get_unaligned_le16(tk + 0));
+       ppk[1] += tkipS(ppk[0] ^ get_unaligned_le16(tk + 2));
+       ppk[2] += tkipS(ppk[1] ^ get_unaligned_le16(tk + 4));
+       ppk[3] += tkipS(ppk[2] ^ get_unaligned_le16(tk + 6));
+       ppk[4] += tkipS(ppk[3] ^ get_unaligned_le16(tk + 8));
+       ppk[5] += tkipS(ppk[4] ^ get_unaligned_le16(tk + 10));
+       ppk[0] += ror16(ppk[5] ^ get_unaligned_le16(tk + 12), 1);
+       ppk[1] += ror16(ppk[0] ^ get_unaligned_le16(tk + 14), 1);
+       ppk[2] += ror16(ppk[1], 1);
+       ppk[3] += ror16(ppk[2], 1);
+       ppk[4] += ror16(ppk[3], 1);
+       ppk[5] += ror16(ppk[4], 1);
+
+       rc4key[0] = tsc_IV16 >> 8;
+       rc4key[1] = ((tsc_IV16 >> 8) | 0x20) & 0x7f;
+       rc4key[2] = tsc_IV16 & 0xFF;
+       rc4key[3] = ((ppk[5] ^ get_unaligned_le16(tk)) >> 1) & 0xFF;
+
+       rc4key += 4;
+       for (i = 0; i < 6; i++)
+               put_unaligned_le16(ppk[i], rc4key + 2 * i);
 }
 
-
 /* Add TKIP IV and Ext. IV at @pos. @iv0, @iv1, and @iv2 are the first octets
  * of the IV. Returns pointer to the octet following IVs (i.e., beginning of
  * the packet payload). */
-u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key,
+u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key,
                           u8 iv0, u8 iv1, u8 iv2)
 {
        *pos++ = iv0;
        *pos++ = iv1;
        *pos++ = iv2;
        *pos++ = (key->conf.keyidx << 6) | (1 << 5) /* Ext IV */;
-       *pos++ = key->u.tkip.iv32 & 0xff;
-       *pos++ = (key->u.tkip.iv32 >> 8) & 0xff;
-       *pos++ = (key->u.tkip.iv32 >> 16) & 0xff;
-       *pos++ = (key->u.tkip.iv32 >> 24) & 0xff;
-       return pos;
-}
-
-
-void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta,
-                                 u16 *phase1key)
-{
-       tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
-                          key->u.tkip.iv32, phase1key);
+       put_unaligned_le32(key->u.tkip.tx.iv32, pos);
+       return pos + 4;
 }
 
-void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta,
+static void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta,
                               u8 *rc4key)
 {
        /* Calculate per-packet key */
-       if (key->u.tkip.iv16 == 0 || !key->u.tkip.tx_initialized) {
-               /* IV16 wrapped around - perform TKIP phase 1 */
-               tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
-                                  key->u.tkip.iv32, key->u.tkip.p1k);
-               key->u.tkip.tx_initialized = 1;
-       }
+       if (key->u.tkip.tx.iv16 == 0 || !key->u.tkip.tx.initialized)
+               tkip_mixing_phase1(key, ta, &key->u.tkip.tx, key->u.tkip.tx.iv32);
 
-       tkip_mixing_phase2(key->u.tkip.p1k,
-                          &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
-                          key->u.tkip.iv16, rc4key);
+       tkip_mixing_phase2(key, &key->u.tkip.tx, key->u.tkip.tx.iv16, rc4key);
 }
 
 void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
@@ -228,18 +171,16 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
        u16 iv16;
        u32 iv32;
 
-       iv16 = data[hdr_len] << 8;
-       iv16 += data[hdr_len + 2];
-       iv32 = data[hdr_len + 4] | (data[hdr_len + 5] << 8) |
-              (data[hdr_len + 6] << 16) | (data[hdr_len + 7] << 24);
+       iv16 = data[hdr_len + 2] | (data[hdr_len] << 8);
+       iv32 = get_unaligned_le32(data + hdr_len + 4);
 
 #ifdef CONFIG_TKIP_DEBUG
        printk(KERN_DEBUG "TKIP encrypt: iv16 = 0x%04x, iv32 = 0x%08x\n",
                        iv16, iv32);
 
-       if (iv32 != key->u.tkip.iv32) {
+       if (iv32 != key->u.tkip.tx.iv32) {
                printk(KERN_DEBUG "skb: iv32 = 0x%08x key: iv32 = 0x%08x\n",
-                       iv32, key->u.tkip.iv32);
+                       iv32, key->u.tkip.tx.iv32);
                printk(KERN_DEBUG "Wrap around of iv16 in the middle of a "
                        "fragmented packet\n");
        }
@@ -248,20 +189,15 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
        /* Update the p1k only when the iv16 in the packet wraps around, this
         * might occur after the wrap around of iv16 in the key in case of
         * fragmented packets. */
-       if (iv16 == 0 || !key->u.tkip.tx_initialized) {
-               /* IV16 wrapped around - perform TKIP phase 1 */
-               tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
-                       iv32, key->u.tkip.p1k);
-               key->u.tkip.tx_initialized = 1;
-       }
+       if (iv16 == 0 || !key->u.tkip.tx.initialized)
+               tkip_mixing_phase1(key, ta, &key->u.tkip.tx, iv32);
 
        if (type == IEEE80211_TKIP_P1_KEY) {
-               memcpy(outkey, key->u.tkip.p1k, sizeof(u16) * 5);
+               memcpy(outkey, key->u.tkip.tx.p1k, sizeof(u16) * 5);
                return;
        }
 
-       tkip_mixing_phase2(key->u.tkip.p1k,
-               &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], iv16, outkey);
+       tkip_mixing_phase2(key, &key->u.tkip.tx, iv16, outkey);
 }
 EXPORT_SYMBOL(ieee80211_get_tkip_key);
 
@@ -281,7 +217,6 @@ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
        ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len);
 }
 
-
 /* Decrypt packet payload with TKIP using @key. @pos is a pointer to the
  * beginning of the buffer containing IEEE 802.11 header payload, i.e.,
  * including IV, Ext. IV, real data, Michael MIC, ICV. @payload_len is the
@@ -302,7 +237,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
 
        iv16 = (pos[0] << 8) | pos[2];
        keyid = pos[3];
-       iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
+       iv32 = get_unaligned_le32(pos + 4);
        pos += 8;
 #ifdef CONFIG_TKIP_DEBUG
        {
@@ -322,33 +257,31 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
        if ((keyid >> 6) != key->conf.keyidx)
                return TKIP_DECRYPT_INVALID_KEYIDX;
 
-       if (key->u.tkip.rx_initialized[queue] &&
-           (iv32 < key->u.tkip.iv32_rx[queue] ||
-            (iv32 == key->u.tkip.iv32_rx[queue] &&
-             iv16 <= key->u.tkip.iv16_rx[queue]))) {
+       if (key->u.tkip.rx[queue].initialized &&
+           (iv32 < key->u.tkip.rx[queue].iv32 ||
+            (iv32 == key->u.tkip.rx[queue].iv32 &&
+             iv16 <= key->u.tkip.rx[queue].iv16))) {
 #ifdef CONFIG_TKIP_DEBUG
                DECLARE_MAC_BUF(mac);
                printk(KERN_DEBUG "TKIP replay detected for RX frame from "
                       "%s (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n",
                       print_mac(mac, ta),
-                      iv32, iv16, key->u.tkip.iv32_rx[queue],
-                      key->u.tkip.iv16_rx[queue]);
+                      iv32, iv16, key->u.tkip.rx[queue].iv32,
+                      key->u.tkip.rx[queue].iv16);
 #endif /* CONFIG_TKIP_DEBUG */
                return TKIP_DECRYPT_REPLAY;
        }
 
        if (only_iv) {
                res = TKIP_DECRYPT_OK;
-               key->u.tkip.rx_initialized[queue] = 1;
+               key->u.tkip.rx[queue].initialized = 1;
                goto done;
        }
 
-       if (!key->u.tkip.rx_initialized[queue] ||
-           key->u.tkip.iv32_rx[queue] != iv32) {
-               key->u.tkip.rx_initialized[queue] = 1;
+       if (!key->u.tkip.rx[queue].initialized ||
+           key->u.tkip.rx[queue].iv32 != iv32) {
                /* IV16 wrapped around - perform TKIP phase 1 */
-               tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
-                                  iv32, key->u.tkip.p1k_rx[queue]);
+               tkip_mixing_phase1(key, ta, &key->u.tkip.rx[queue], iv32);
 #ifdef CONFIG_TKIP_DEBUG
                {
                        int i;
@@ -362,7 +295,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
                        printk("\n");
                        printk(KERN_DEBUG "TKIP decrypt: P1K=");
                        for (i = 0; i < 5; i++)
-                               printk("%04x ", key->u.tkip.p1k_rx[queue][i]);
+                               printk("%04x ", key->u.tkip.rx[queue].p1k[i]);
                        printk("\n");
                }
 #endif /* CONFIG_TKIP_DEBUG */
@@ -377,13 +310,11 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
 
                        key->local->ops->update_tkip_key(
                                local_to_hw(key->local), &key->conf,
-                               sta_addr, iv32, key->u.tkip.p1k_rx[queue]);
+                               sta_addr, iv32, key->u.tkip.rx[queue].p1k);
                }
        }
 
-       tkip_mixing_phase2(key->u.tkip.p1k_rx[queue],
-                          &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
-                          iv16, rc4key);
+       tkip_mixing_phase2(key, &key->u.tkip.rx[queue], iv16, rc4key);
 #ifdef CONFIG_TKIP_DEBUG
        {
                int i;
@@ -409,5 +340,3 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
 
        return res;
 }
-
-
index b7c2ee763d9d5d03562c3e73ad8710ff46480e00..b890427fc9590e2f84a33e0405ed4390344b47ac 100644 (file)
 #include <linux/crypto.h>
 #include "key.h"
 
-u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key,
-                          u8 iv0, u8 iv1, u8 iv2);
-void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta,
-                                 u16 *phase1key);
-void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta,
-                              u8 *rc4key);
+u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key,
+                         u8 iv0, u8 iv1, u8 iv2);
 void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
                                 struct ieee80211_key *key,
                                 u8 *pos, size_t payload_len, u8 *ta);
index 1d7dd54aacef31120fa744bef928bd7075ad72c2..1ad9e664f2875219de301106302bcc18723c5cb2 100644 (file)
@@ -91,11 +91,12 @@ static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
                              int next_frag_len)
 {
        int rate, mrate, erp, dur, i;
-       struct ieee80211_rate *txrate = tx->rate;
+       struct ieee80211_rate *txrate;
        struct ieee80211_local *local = tx->local;
        struct ieee80211_supported_band *sband;
 
-       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+       sband = local->hw.wiphy->bands[tx->channel->band];
+       txrate = &sband->bitrates[tx->rate_idx];
 
        erp = 0;
        if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
@@ -212,18 +213,6 @@ static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
        return dur;
 }
 
-static inline int __ieee80211_queue_stopped(const struct ieee80211_local *local,
-                                           int queue)
-{
-       return test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]);
-}
-
-static inline int __ieee80211_queue_pending(const struct ieee80211_local *local,
-                                           int queue)
-{
-       return test_bit(IEEE80211_LINK_STATE_PENDING, &local->state[queue]);
-}
-
 static int inline is_ieee80211_device(struct net_device *dev,
                                      struct net_device *master)
 {
@@ -237,12 +226,12 @@ static ieee80211_tx_result
 ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
 {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       struct sk_buff *skb = tx->skb;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
        u32 sta_flags;
 
-       if (unlikely(tx->flags & IEEE80211_TX_INJECTED))
+       if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED))
                return TX_CONTINUE;
 
        if (unlikely(tx->local->sta_sw_scanning) &&
@@ -256,7 +245,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
        if (tx->flags & IEEE80211_TX_PS_BUFFERED)
                return TX_CONTINUE;
 
-       sta_flags = tx->sta ? tx->sta->flags : 0;
+       sta_flags = tx->sta ? get_sta_flags(tx->sta) : 0;
 
        if (likely(tx->flags & IEEE80211_TX_UNICAST)) {
                if (unlikely(!(sta_flags & WLAN_STA_ASSOC) &&
@@ -347,6 +336,8 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
 static ieee80211_tx_result
 ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
 {
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+
        /*
         * broadcast/multicast frame
         *
@@ -382,7 +373,7 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
        }
 
        /* buffered in hardware */
-       tx->control->flags |= IEEE80211_TXCTL_SEND_AFTER_DTIM;
+       info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM;
 
        return TX_CONTINUE;
 }
@@ -391,6 +382,8 @@ static ieee80211_tx_result
 ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
 {
        struct sta_info *sta = tx->sta;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+       u32 staflags;
        DECLARE_MAC_BUF(mac);
 
        if (unlikely(!sta ||
@@ -398,9 +391,10 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
                      (tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)))
                return TX_CONTINUE;
 
-       if (unlikely((sta->flags & WLAN_STA_PS) &&
-                    !(sta->flags & WLAN_STA_PSPOLL))) {
-               struct ieee80211_tx_packet_data *pkt_data;
+       staflags = get_sta_flags(sta);
+
+       if (unlikely((staflags & WLAN_STA_PS) &&
+                    !(staflags & WLAN_STA_PSPOLL))) {
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
                printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries "
                       "before %d)\n",
@@ -424,19 +418,18 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
                if (skb_queue_empty(&sta->ps_tx_buf))
                        sta_info_set_tim_bit(sta);
 
-               pkt_data = (struct ieee80211_tx_packet_data *)tx->skb->cb;
-               pkt_data->jiffies = jiffies;
+               info->control.jiffies = jiffies;
                skb_queue_tail(&sta->ps_tx_buf, tx->skb);
                return TX_QUEUED;
        }
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-       else if (unlikely(sta->flags & WLAN_STA_PS)) {
+       else if (unlikely(test_sta_flags(sta, WLAN_STA_PS))) {
                printk(KERN_DEBUG "%s: STA %s in PS mode, but pspoll "
                       "set -> send frame\n", tx->dev->name,
                       print_mac(mac, sta->addr));
        }
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
-       sta->flags &= ~WLAN_STA_PSPOLL;
+       clear_sta_flags(sta, WLAN_STA_PSPOLL);
 
        return TX_CONTINUE;
 }
@@ -457,17 +450,18 @@ static ieee80211_tx_result
 ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
 {
        struct ieee80211_key *key;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
        u16 fc = tx->fc;
 
-       if (unlikely(tx->control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
+       if (unlikely(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT))
                tx->key = NULL;
        else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
                tx->key = key;
        else if ((key = rcu_dereference(tx->sdata->default_key)))
                tx->key = key;
        else if (tx->sdata->drop_unencrypted &&
-                !(tx->control->flags & IEEE80211_TXCTL_EAPOL_FRAME) &&
-                !(tx->flags & IEEE80211_TX_INJECTED)) {
+                !(info->flags & IEEE80211_TX_CTL_EAPOL_FRAME) &&
+                !(info->flags & IEEE80211_TX_CTL_INJECTED)) {
                I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
                return TX_DROP;
        } else
@@ -496,7 +490,156 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
        }
 
        if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
-               tx->control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
+               info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
+
+       return TX_CONTINUE;
+}
+
+static ieee80211_tx_result
+ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
+{
+       struct rate_selection rsel;
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+
+       sband = tx->local->hw.wiphy->bands[tx->channel->band];
+
+       if (likely(tx->rate_idx < 0)) {
+               rate_control_get_rate(tx->dev, sband, tx->skb, &rsel);
+               tx->rate_idx = rsel.rate_idx;
+               if (unlikely(rsel.probe_idx >= 0)) {
+                       info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+                       tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
+                       info->control.alt_retry_rate_idx = tx->rate_idx;
+                       tx->rate_idx = rsel.probe_idx;
+               } else
+                       info->control.alt_retry_rate_idx = -1;
+
+               if (unlikely(tx->rate_idx < 0))
+                       return TX_DROP;
+       } else
+               info->control.alt_retry_rate_idx = -1;
+
+       if (tx->sdata->bss_conf.use_cts_prot &&
+           (tx->flags & IEEE80211_TX_FRAGMENTED) && (rsel.nonerp_idx >= 0)) {
+               tx->last_frag_rate_idx = tx->rate_idx;
+               if (rsel.probe_idx >= 0)
+                       tx->flags &= ~IEEE80211_TX_PROBE_LAST_FRAG;
+               else
+                       tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
+               tx->rate_idx = rsel.nonerp_idx;
+               info->tx_rate_idx = rsel.nonerp_idx;
+               info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+       } else {
+               tx->last_frag_rate_idx = tx->rate_idx;
+               info->tx_rate_idx = tx->rate_idx;
+       }
+       info->tx_rate_idx = tx->rate_idx;
+
+       return TX_CONTINUE;
+}
+
+static ieee80211_tx_result
+ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
+       u16 fc = le16_to_cpu(hdr->frame_control);
+       u16 dur;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+       struct ieee80211_supported_band *sband;
+
+       sband = tx->local->hw.wiphy->bands[tx->channel->band];
+
+       if (tx->sta)
+               info->control.aid = tx->sta->aid;
+
+       if (!info->control.retry_limit) {
+               if (!is_multicast_ether_addr(hdr->addr1)) {
+                       int len = min_t(int, tx->skb->len + FCS_LEN,
+                                       tx->local->fragmentation_threshold);
+                       if (len > tx->local->rts_threshold
+                           && tx->local->rts_threshold <
+                                               IEEE80211_MAX_RTS_THRESHOLD) {
+                               info->flags |= IEEE80211_TX_CTL_USE_RTS_CTS;
+                               info->flags |=
+                                       IEEE80211_TX_CTL_LONG_RETRY_LIMIT;
+                               info->control.retry_limit =
+                                       tx->local->long_retry_limit;
+                       } else {
+                               info->control.retry_limit =
+                                       tx->local->short_retry_limit;
+                       }
+               } else {
+                       info->control.retry_limit = 1;
+               }
+       }
+
+       if (tx->flags & IEEE80211_TX_FRAGMENTED) {
+               /* Do not use multiple retry rates when sending fragmented
+                * frames.
+                * TODO: The last fragment could still use multiple retry
+                * rates. */
+               info->control.alt_retry_rate_idx = -1;
+       }
+
+       /* Use CTS protection for unicast frames sent using extended rates if
+        * there are associated non-ERP stations and RTS/CTS is not configured
+        * for the frame. */
+       if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) &&
+           (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_ERP_G) &&
+           (tx->flags & IEEE80211_TX_UNICAST) &&
+           tx->sdata->bss_conf.use_cts_prot &&
+           !(info->flags & IEEE80211_TX_CTL_USE_RTS_CTS))
+               info->flags |= IEEE80211_TX_CTL_USE_CTS_PROTECT;
+
+       /* Transmit data frames using short preambles if the driver supports
+        * short preambles at the selected rate and short preambles are
+        * available on the network at the current point in time. */
+       if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
+           (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
+           tx->sdata->bss_conf.use_short_preamble &&
+           (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) {
+               info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
+       }
+
+       /* Setup duration field for the first fragment of the frame. Duration
+        * for remaining fragments will be updated when they are being sent
+        * to low-level driver in ieee80211_tx(). */
+       dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1),
+                                (tx->flags & IEEE80211_TX_FRAGMENTED) ?
+                                tx->extra_frag[0]->len : 0);
+       hdr->duration_id = cpu_to_le16(dur);
+
+       if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
+           (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
+               struct ieee80211_rate *rate;
+               s8 baserate = -1;
+               int idx;
+
+               /* Do not use multiple retry rates when using RTS/CTS */
+               info->control.alt_retry_rate_idx = -1;
+
+               /* Use min(data rate, max base rate) as CTS/RTS rate */
+               rate = &sband->bitrates[tx->rate_idx];
+
+               for (idx = 0; idx < sband->n_bitrates; idx++) {
+                       if (sband->bitrates[idx].bitrate > rate->bitrate)
+                               continue;
+                       if (tx->sdata->basic_rates & BIT(idx) &&
+                           (baserate < 0 ||
+                            (sband->bitrates[baserate].bitrate
+                             < sband->bitrates[idx].bitrate)))
+                               baserate = idx;
+               }
+
+               if (baserate >= 0)
+                       info->control.rts_cts_rate_idx = baserate;
+               else
+                       info->control.rts_cts_rate_idx = 0;
+       }
+
+       if (tx->sta)
+               info->control.aid = tx->sta->aid;
 
        return TX_CONTINUE;
 }
@@ -515,6 +658,17 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
        if (!(tx->flags & IEEE80211_TX_FRAGMENTED))
                return TX_CONTINUE;
 
+       /*
+        * Warn when submitting a fragmented A-MPDU frame and drop it.
+        * This is an error and needs to be fixed elsewhere, but when
+        * done needs to take care of monitor interfaces (injection)
+        * etc.
+        */
+       if (WARN_ON(tx->flags & IEEE80211_TX_CTL_AMPDU ||
+                   skb_get_queue_mapping(tx->skb) >=
+                       ieee80211_num_regular_queues(&tx->local->hw)))
+               return TX_DROP;
+
        first = tx->skb;
 
        hdrlen = ieee80211_get_hdrlen(tx->fc);
@@ -602,215 +756,22 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
 }
 
 static ieee80211_tx_result
-ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
+ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
 {
-       struct rate_selection rsel;
-       struct ieee80211_supported_band *sband;
-
-       sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band];
-
-       if (likely(!tx->rate)) {
-               rate_control_get_rate(tx->dev, sband, tx->skb, &rsel);
-               tx->rate = rsel.rate;
-               if (unlikely(rsel.probe)) {
-                       tx->control->flags |=
-                               IEEE80211_TXCTL_RATE_CTRL_PROBE;
-                       tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
-                       tx->control->alt_retry_rate = tx->rate;
-                       tx->rate = rsel.probe;
-               } else
-                       tx->control->alt_retry_rate = NULL;
-
-               if (!tx->rate)
-                       return TX_DROP;
-       } else
-               tx->control->alt_retry_rate = NULL;
-
-       if (tx->sdata->bss_conf.use_cts_prot &&
-           (tx->flags & IEEE80211_TX_FRAGMENTED) && rsel.nonerp) {
-               tx->last_frag_rate = tx->rate;
-               if (rsel.probe)
-                       tx->flags &= ~IEEE80211_TX_PROBE_LAST_FRAG;
-               else
-                       tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
-               tx->rate = rsel.nonerp;
-               tx->control->tx_rate = rsel.nonerp;
-               tx->control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE;
-       } else {
-               tx->last_frag_rate = tx->rate;
-               tx->control->tx_rate = tx->rate;
-       }
-       tx->control->tx_rate = tx->rate;
-
-       return TX_CONTINUE;
-}
-
-static ieee80211_tx_result
-ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
-{
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
-       u16 fc = le16_to_cpu(hdr->frame_control);
-       u16 dur;
-       struct ieee80211_tx_control *control = tx->control;
-
-       if (!control->retry_limit) {
-               if (!is_multicast_ether_addr(hdr->addr1)) {
-                       if (tx->skb->len + FCS_LEN > tx->local->rts_threshold
-                           && tx->local->rts_threshold <
-                                       IEEE80211_MAX_RTS_THRESHOLD) {
-                               control->flags |=
-                                       IEEE80211_TXCTL_USE_RTS_CTS;
-                               control->flags |=
-                                       IEEE80211_TXCTL_LONG_RETRY_LIMIT;
-                               control->retry_limit =
-                                       tx->local->long_retry_limit;
-                       } else {
-                               control->retry_limit =
-                                       tx->local->short_retry_limit;
-                       }
-               } else {
-                       control->retry_limit = 1;
-               }
-       }
-
-       if (tx->flags & IEEE80211_TX_FRAGMENTED) {
-               /* Do not use multiple retry rates when sending fragmented
-                * frames.
-                * TODO: The last fragment could still use multiple retry
-                * rates. */
-               control->alt_retry_rate = NULL;
-       }
-
-       /* Use CTS protection for unicast frames sent using extended rates if
-        * there are associated non-ERP stations and RTS/CTS is not configured
-        * for the frame. */
-       if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) &&
-           (tx->rate->flags & IEEE80211_RATE_ERP_G) &&
-           (tx->flags & IEEE80211_TX_UNICAST) &&
-           tx->sdata->bss_conf.use_cts_prot &&
-           !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS))
-               control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT;
-
-       /* Transmit data frames using short preambles if the driver supports
-        * short preambles at the selected rate and short preambles are
-        * available on the network at the current point in time. */
-       if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
-           (tx->rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
-           tx->sdata->bss_conf.use_short_preamble &&
-           (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) {
-               tx->control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
-       }
-
-       /* Setup duration field for the first fragment of the frame. Duration
-        * for remaining fragments will be updated when they are being sent
-        * to low-level driver in ieee80211_tx(). */
-       dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1),
-                                (tx->flags & IEEE80211_TX_FRAGMENTED) ?
-                                tx->extra_frag[0]->len : 0);
-       hdr->duration_id = cpu_to_le16(dur);
-
-       if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
-           (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
-               struct ieee80211_supported_band *sband;
-               struct ieee80211_rate *rate, *baserate;
-               int idx;
-
-               sband = tx->local->hw.wiphy->bands[
-                               tx->local->hw.conf.channel->band];
-
-               /* Do not use multiple retry rates when using RTS/CTS */
-               control->alt_retry_rate = NULL;
-
-               /* Use min(data rate, max base rate) as CTS/RTS rate */
-               rate = tx->rate;
-               baserate = NULL;
-
-               for (idx = 0; idx < sband->n_bitrates; idx++) {
-                       if (sband->bitrates[idx].bitrate > rate->bitrate)
-                               continue;
-                       if (tx->sdata->basic_rates & BIT(idx) &&
-                           (!baserate ||
-                            (baserate->bitrate < sband->bitrates[idx].bitrate)))
-                               baserate = &sband->bitrates[idx];
-               }
-
-               if (baserate)
-                       control->rts_cts_rate = baserate;
-               else
-                       control->rts_cts_rate = &sband->bitrates[0];
-       }
-
-       if (tx->sta) {
-               control->aid = tx->sta->aid;
-               tx->sta->tx_packets++;
-               tx->sta->tx_fragments++;
-               tx->sta->tx_bytes += tx->skb->len;
-               if (tx->extra_frag) {
-                       int i;
-                       tx->sta->tx_fragments += tx->num_extra_frag;
-                       for (i = 0; i < tx->num_extra_frag; i++) {
-                               tx->sta->tx_bytes +=
-                                       tx->extra_frag[i]->len;
-                       }
-               }
-       }
-
-       return TX_CONTINUE;
-}
-
-static ieee80211_tx_result
-ieee80211_tx_h_load_stats(struct ieee80211_tx_data *tx)
-{
-       struct ieee80211_local *local = tx->local;
-       struct sk_buff *skb = tx->skb;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       u32 load = 0, hdrtime;
-       struct ieee80211_rate *rate = tx->rate;
-
-       /* TODO: this could be part of tx_status handling, so that the number
-        * of retries would be known; TX rate should in that case be stored
-        * somewhere with the packet */
-
-       /* Estimate total channel use caused by this frame */
-
-       /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
-        * 1 usec = 1/8 * (1080 / 10) = 13.5 */
-
-       if (tx->channel->band == IEEE80211_BAND_5GHZ ||
-           (tx->channel->band == IEEE80211_BAND_2GHZ &&
-            rate->flags & IEEE80211_RATE_ERP_G))
-               hdrtime = CHAN_UTIL_HDR_SHORT;
-       else
-               hdrtime = CHAN_UTIL_HDR_LONG;
-
-       load = hdrtime;
-       if (!is_multicast_ether_addr(hdr->addr1))
-               load += hdrtime;
-
-       if (tx->control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
-               load += 2 * hdrtime;
-       else if (tx->control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
-               load += hdrtime;
+       int i;
 
-       /* TODO: optimise again */
-       load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate;
+       if (!tx->sta)
+               return TX_CONTINUE;
 
+       tx->sta->tx_packets++;
+       tx->sta->tx_fragments++;
+       tx->sta->tx_bytes += tx->skb->len;
        if (tx->extra_frag) {
-               int i;
-               for (i = 0; i < tx->num_extra_frag; i++) {
-                       load += 2 * hdrtime;
-                       load += tx->extra_frag[i]->len *
-                               tx->rate->bitrate;
-               }
+               tx->sta->tx_fragments += tx->num_extra_frag;
+               for (i = 0; i < tx->num_extra_frag; i++)
+                       tx->sta->tx_bytes += tx->extra_frag[i]->len;
        }
 
-       /* Divide channel_use by 8 to avoid wrapping around the counter */
-       load >>= CHAN_UTIL_SHIFT;
-       local->channel_use_raw += load;
-       if (tx->sta)
-               tx->sta->channel_use_raw += load;
-       tx->sdata->channel_use_raw += load;
-
        return TX_CONTINUE;
 }
 
@@ -823,11 +784,12 @@ static ieee80211_tx_handler ieee80211_tx_handlers[] =
        ieee80211_tx_h_ps_buf,
        ieee80211_tx_h_select_key,
        ieee80211_tx_h_michael_mic_add,
-       ieee80211_tx_h_fragment,
-       ieee80211_tx_h_encrypt,
        ieee80211_tx_h_rate_ctrl,
        ieee80211_tx_h_misc,
-       ieee80211_tx_h_load_stats,
+       ieee80211_tx_h_fragment,
+       /* handlers after fragment must be aware of tx info fragmentation! */
+       ieee80211_tx_h_encrypt,
+       ieee80211_tx_h_stats,
        NULL
 };
 
@@ -854,12 +816,12 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
                (struct ieee80211_radiotap_header *) skb->data;
        struct ieee80211_supported_band *sband;
        int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len);
-       struct ieee80211_tx_control *control = tx->control;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
-       sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band];
+       sband = tx->local->hw.wiphy->bands[tx->channel->band];
 
-       control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
-       tx->flags |= IEEE80211_TX_INJECTED;
+       info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
+       info->flags |= IEEE80211_TX_CTL_INJECTED;
        tx->flags &= ~IEEE80211_TX_FRAGMENTED;
 
        /*
@@ -896,7 +858,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
                                r = &sband->bitrates[i];
 
                                if (r->bitrate == target_rate) {
-                                       tx->rate = r;
+                                       tx->rate_idx = i;
                                        break;
                                }
                        }
@@ -907,7 +869,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
                         * radiotap uses 0 for 1st ant, mac80211 is 1 for
                         * 1st ant
                         */
-                       control->antenna_sel_tx = (*iterator.this_arg) + 1;
+                       info->antenna_sel_tx = (*iterator.this_arg) + 1;
                        break;
 
 #if 0
@@ -931,8 +893,8 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
                                skb_trim(skb, skb->len - FCS_LEN);
                        }
                        if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP)
-                               control->flags &=
-                                       ~IEEE80211_TXCTL_DO_NOT_ENCRYPT;
+                               info->flags &=
+                                       ~IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
                        if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG)
                                tx->flags |= IEEE80211_TX_FRAGMENTED;
                        break;
@@ -967,12 +929,12 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
 static ieee80211_tx_result
 __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
                       struct sk_buff *skb,
-                      struct net_device *dev,
-                      struct ieee80211_tx_control *control)
+                      struct net_device *dev)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_hdr *hdr;
        struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
        int hdrlen;
 
@@ -981,7 +943,9 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
        tx->dev = dev; /* use original interface */
        tx->local = local;
        tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       tx->control = control;
+       tx->channel = local->hw.conf.channel;
+       tx->rate_idx = -1;
+       tx->last_frag_rate_idx = -1;
        /*
         * Set this flag (used below to indicate "automatic fragmentation"),
         * it will be cleared/left by radiotap as desired.
@@ -1008,10 +972,10 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
 
        if (is_multicast_ether_addr(hdr->addr1)) {
                tx->flags &= ~IEEE80211_TX_UNICAST;
-               control->flags |= IEEE80211_TXCTL_NO_ACK;
+               info->flags |= IEEE80211_TX_CTL_NO_ACK;
        } else {
                tx->flags |= IEEE80211_TX_UNICAST;
-               control->flags &= ~IEEE80211_TXCTL_NO_ACK;
+               info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
        }
 
        if (tx->flags & IEEE80211_TX_FRAGMENTED) {
@@ -1024,18 +988,16 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
        }
 
        if (!tx->sta)
-               control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT;
-       else if (tx->sta->flags & WLAN_STA_CLEAR_PS_FILT) {
-               control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT;
-               tx->sta->flags &= ~WLAN_STA_CLEAR_PS_FILT;
-       }
+               info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
+       else if (test_and_clear_sta_flags(tx->sta, WLAN_STA_CLEAR_PS_FILT))
+               info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
 
        hdrlen = ieee80211_get_hdrlen(tx->fc);
        if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) {
                u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)];
                tx->ethertype = (pos[0] << 8) | pos[1];
        }
-       control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT;
+       info->flags |= IEEE80211_TX_CTL_FIRST_FRAGMENT;
 
        return TX_CONTINUE;
 }
@@ -1045,14 +1007,12 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
  */
 static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
                                struct sk_buff *skb,
-                               struct net_device *mdev,
-                               struct ieee80211_tx_control *control)
+                               struct net_device *mdev)
 {
-       struct ieee80211_tx_packet_data *pkt_data;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct net_device *dev;
 
-       pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
-       dev = dev_get_by_index(&init_net, pkt_data->ifindex);
+       dev = dev_get_by_index(&init_net, info->control.ifindex);
        if (unlikely(dev && !is_ieee80211_device(dev, mdev))) {
                dev_put(dev);
                dev = NULL;
@@ -1060,7 +1020,7 @@ static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
        if (unlikely(!dev))
                return -ENODEV;
        /* initialises tx with control */
-       __ieee80211_tx_prepare(tx, skb, dev, control);
+       __ieee80211_tx_prepare(tx, skb, dev);
        dev_put(dev);
        return 0;
 }
@@ -1068,50 +1028,49 @@ static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
 static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
                          struct ieee80211_tx_data *tx)
 {
-       struct ieee80211_tx_control *control = tx->control;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        int ret, i;
 
-       if (!ieee80211_qdisc_installed(local->mdev) &&
-           __ieee80211_queue_stopped(local, 0)) {
-               netif_stop_queue(local->mdev);
+       if (netif_subqueue_stopped(local->mdev, skb))
                return IEEE80211_TX_AGAIN;
-       }
+
        if (skb) {
                ieee80211_dump_frame(wiphy_name(local->hw.wiphy),
                                     "TX to low-level driver", skb);
-               ret = local->ops->tx(local_to_hw(local), skb, control);
+               ret = local->ops->tx(local_to_hw(local), skb);
                if (ret)
                        return IEEE80211_TX_AGAIN;
                local->mdev->trans_start = jiffies;
                ieee80211_led_tx(local, 1);
        }
        if (tx->extra_frag) {
-               control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS |
-                                   IEEE80211_TXCTL_USE_CTS_PROTECT |
-                                   IEEE80211_TXCTL_CLEAR_PS_FILT |
-                                   IEEE80211_TXCTL_FIRST_FRAGMENT);
                for (i = 0; i < tx->num_extra_frag; i++) {
                        if (!tx->extra_frag[i])
                                continue;
-                       if (__ieee80211_queue_stopped(local, control->queue))
+                       info = IEEE80211_SKB_CB(tx->extra_frag[i]);
+                       info->flags &= ~(IEEE80211_TX_CTL_USE_RTS_CTS |
+                                        IEEE80211_TX_CTL_USE_CTS_PROTECT |
+                                        IEEE80211_TX_CTL_CLEAR_PS_FILT |
+                                        IEEE80211_TX_CTL_FIRST_FRAGMENT);
+                       if (netif_subqueue_stopped(local->mdev,
+                                                  tx->extra_frag[i]))
                                return IEEE80211_TX_FRAG_AGAIN;
                        if (i == tx->num_extra_frag) {
-                               control->tx_rate = tx->last_frag_rate;
+                               info->tx_rate_idx = tx->last_frag_rate_idx;
 
                                if (tx->flags & IEEE80211_TX_PROBE_LAST_FRAG)
-                                       control->flags |=
-                                               IEEE80211_TXCTL_RATE_CTRL_PROBE;
+                                       info->flags |=
+                                               IEEE80211_TX_CTL_RATE_CTRL_PROBE;
                                else
-                                       control->flags &=
-                                               ~IEEE80211_TXCTL_RATE_CTRL_PROBE;
+                                       info->flags &=
+                                               ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
                        }
 
                        ieee80211_dump_frame(wiphy_name(local->hw.wiphy),
                                             "TX to low-level driver",
                                             tx->extra_frag[i]);
                        ret = local->ops->tx(local_to_hw(local),
-                                           tx->extra_frag[i],
-                                           control);
+                                           tx->extra_frag[i]);
                        if (ret)
                                return IEEE80211_TX_FRAG_AGAIN;
                        local->mdev->trans_start = jiffies;
@@ -1124,17 +1083,20 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
        return IEEE80211_TX_OK;
 }
 
-static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
-                       struct ieee80211_tx_control *control)
+static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct sta_info *sta;
        ieee80211_tx_handler *handler;
        struct ieee80211_tx_data tx;
        ieee80211_tx_result res = TX_DROP, res_prepare;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        int ret, i;
+       u16 queue;
+
+       queue = skb_get_queue_mapping(skb);
 
-       WARN_ON(__ieee80211_queue_pending(local, control->queue));
+       WARN_ON(test_bit(queue, local->queues_pending));
 
        if (unlikely(skb->len < 10)) {
                dev_kfree_skb(skb);
@@ -1144,7 +1106,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
        rcu_read_lock();
 
        /* initialises tx */
-       res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control);
+       res_prepare = __ieee80211_tx_prepare(&tx, skb, dev);
 
        if (res_prepare == TX_DROP) {
                dev_kfree_skb(skb);
@@ -1154,6 +1116,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
 
        sta = tx.sta;
        tx.channel = local->hw.conf.channel;
+       info->band = tx.channel->band;
 
        for (handler = ieee80211_tx_handlers; *handler != NULL;
             handler++) {
@@ -1162,7 +1125,8 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
                        break;
        }
 
-       skb = tx.skb; /* handlers are allowed to change skb */
+       if (WARN_ON(tx.skb != skb))
+               goto drop;
 
        if (unlikely(res == TX_DROP)) {
                I802_DEBUG_INC(local->tx_handlers_drop);
@@ -1186,7 +1150,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
                                next_len = tx.extra_frag[i + 1]->len;
                        } else {
                                next_len = 0;
-                               tx.rate = tx.last_frag_rate;
+                               tx.rate_idx = tx.last_frag_rate_idx;
                        }
                        dur = ieee80211_duration(&tx, 0, next_len);
                        hdr->duration_id = cpu_to_le16(dur);
@@ -1196,34 +1160,41 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
 retry:
        ret = __ieee80211_tx(local, skb, &tx);
        if (ret) {
-               struct ieee80211_tx_stored_packet *store =
-                       &local->pending_packet[control->queue];
+               struct ieee80211_tx_stored_packet *store;
+
+               /*
+                * Since there are no fragmented frames on A-MPDU
+                * queues, there's no reason for a driver to reject
+                * a frame there, warn and drop it.
+                */
+               if (WARN_ON(queue >= ieee80211_num_regular_queues(&local->hw)))
+                       goto drop;
+
+               store = &local->pending_packet[queue];
 
                if (ret == IEEE80211_TX_FRAG_AGAIN)
                        skb = NULL;
-               set_bit(IEEE80211_LINK_STATE_PENDING,
-                       &local->state[control->queue]);
+               set_bit(queue, local->queues_pending);
                smp_mb();
-               /* When the driver gets out of buffers during sending of
-                * fragments and calls ieee80211_stop_queue, there is
-                * a small window between IEEE80211_LINK_STATE_XOFF and
-                * IEEE80211_LINK_STATE_PENDING flags are set. If a buffer
+               /*
+                * When the driver gets out of buffers during sending of
+                * fragments and calls ieee80211_stop_queue, the netif
+                * subqueue is stopped. There is, however, a small window
+                * in which the PENDING bit is not yet set. If a buffer
                 * gets available in that window (i.e. driver calls
                 * ieee80211_wake_queue), we would end up with ieee80211_tx
-                * called with IEEE80211_LINK_STATE_PENDING. Prevent this by
+                * called with the PENDING bit still set. Prevent this by
                 * continuing transmitting here when that situation is
-                * possible to have happened. */
-               if (!__ieee80211_queue_stopped(local, control->queue)) {
-                       clear_bit(IEEE80211_LINK_STATE_PENDING,
-                                 &local->state[control->queue]);
+                * possible to have happened.
+                */
+               if (!__netif_subqueue_stopped(local->mdev, queue)) {
+                       clear_bit(queue, local->queues_pending);
                        goto retry;
                }
-               memcpy(&store->control, control,
-                      sizeof(struct ieee80211_tx_control));
                store->skb = skb;
                store->extra_frag = tx.extra_frag;
                store->num_extra_frag = tx.num_extra_frag;
-               store->last_frag_rate = tx.last_frag_rate;
+               store->last_frag_rate_idx = tx.last_frag_rate_idx;
                store->last_frag_rate_ctrl_probe =
                        !!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG);
        }
@@ -1243,24 +1214,57 @@ retry:
 
 /* device xmit handlers */
 
+static int ieee80211_skb_resize(struct ieee80211_local *local,
+                               struct sk_buff *skb,
+                               int head_need, bool may_encrypt)
+{
+       int tail_need = 0;
+
+       /*
+        * This could be optimised, devices that do full hardware
+        * crypto (including TKIP MMIC) need no tailroom... But we
+        * have no drivers for such devices currently.
+        */
+       if (may_encrypt) {
+               tail_need = IEEE80211_ENCRYPT_TAILROOM;
+               tail_need -= skb_tailroom(skb);
+               tail_need = max_t(int, tail_need, 0);
+       }
+
+       if (head_need || tail_need) {
+               /* Sorry. Can't account for this any more */
+               skb_orphan(skb);
+       }
+
+       if (skb_header_cloned(skb))
+               I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
+       else
+               I802_DEBUG_INC(local->tx_expand_skb_head);
+
+       if (pskb_expand_head(skb, head_need, tail_need, GFP_ATOMIC)) {
+               printk(KERN_DEBUG "%s: failed to reallocate TX buffer\n",
+                      wiphy_name(local->hw.wiphy));
+               return -ENOMEM;
+       }
+
+       /* update truesize too */
+       skb->truesize += head_need + tail_need;
+
+       return 0;
+}
+
 int ieee80211_master_start_xmit(struct sk_buff *skb,
                                struct net_device *dev)
 {
-       struct ieee80211_tx_control control;
-       struct ieee80211_tx_packet_data *pkt_data;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct net_device *odev = NULL;
        struct ieee80211_sub_if_data *osdata;
        int headroom;
+       bool may_encrypt;
        int ret;
 
-       /*
-        * copy control out of the skb so other people can use skb->cb
-        */
-       pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
-       memset(&control, 0, sizeof(struct ieee80211_tx_control));
-
-       if (pkt_data->ifindex)
-               odev = dev_get_by_index(&init_net, pkt_data->ifindex);
+       if (info->control.ifindex)
+               odev = dev_get_by_index(&init_net, info->control.ifindex);
        if (unlikely(odev && !is_ieee80211_device(odev, dev))) {
                dev_put(odev);
                odev = NULL;
@@ -1273,32 +1277,25 @@ int ieee80211_master_start_xmit(struct sk_buff *skb,
                dev_kfree_skb(skb);
                return 0;
        }
+
        osdata = IEEE80211_DEV_TO_SUB_IF(odev);
 
-       headroom = osdata->local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM;
-       if (skb_headroom(skb) < headroom) {
-               if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) {
-                       dev_kfree_skb(skb);
-                       dev_put(odev);
-                       return 0;
-               }
+       may_encrypt = !(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT);
+
+       headroom = osdata->local->tx_headroom;
+       if (may_encrypt)
+               headroom += IEEE80211_ENCRYPT_HEADROOM;
+       headroom -= skb_headroom(skb);
+       headroom = max_t(int, 0, headroom);
+
+       if (ieee80211_skb_resize(osdata->local, skb, headroom, may_encrypt)) {
+               dev_kfree_skb(skb);
+               dev_put(odev);
+               return 0;
        }
 
-       control.vif = &osdata->vif;
-       control.type = osdata->vif.type;
-       if (pkt_data->flags & IEEE80211_TXPD_REQ_TX_STATUS)
-               control.flags |= IEEE80211_TXCTL_REQ_TX_STATUS;
-       if (pkt_data->flags & IEEE80211_TXPD_DO_NOT_ENCRYPT)
-               control.flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
-       if (pkt_data->flags & IEEE80211_TXPD_REQUEUE)
-               control.flags |= IEEE80211_TXCTL_REQUEUE;
-       if (pkt_data->flags & IEEE80211_TXPD_EAPOL_FRAME)
-               control.flags |= IEEE80211_TXCTL_EAPOL_FRAME;
-       if (pkt_data->flags & IEEE80211_TXPD_AMPDU)
-               control.flags |= IEEE80211_TXCTL_AMPDU;
-       control.queue = pkt_data->queue;
-
-       ret = ieee80211_tx(odev, skb, &control);
+       info->control.vif = &osdata->vif;
+       ret = ieee80211_tx(odev, skb);
        dev_put(odev);
 
        return ret;
@@ -1308,7 +1305,7 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
                                 struct net_device *dev)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_tx_packet_data *pkt_data;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ieee80211_radiotap_header *prthdr =
                (struct ieee80211_radiotap_header *)skb->data;
        u16 len_rthdr;
@@ -1330,12 +1327,12 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
 
        skb->dev = local->mdev;
 
-       pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
-       memset(pkt_data, 0, sizeof(*pkt_data));
        /* needed because we set skb device to master */
-       pkt_data->ifindex = dev->ifindex;
+       info->control.ifindex = dev->ifindex;
 
-       pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
+       info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
+       /* Interfaces should always request a status report */
+       info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
 
        /*
         * fix up the pointers accounting for the radiotap
@@ -1379,7 +1376,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
                               struct net_device *dev)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_tx_packet_data *pkt_data;
+       struct ieee80211_tx_info *info;
        struct ieee80211_sub_if_data *sdata;
        int ret = 1, head_need;
        u16 ethertype, hdrlen,  meshhdrlen = 0, fc;
@@ -1486,12 +1483,13 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
                rcu_read_lock();
                sta = sta_info_get(local, hdr.addr1);
                if (sta)
-                       sta_flags = sta->flags;
+                       sta_flags = get_sta_flags(sta);
                rcu_read_unlock();
        }
 
-       /* receiver is QoS enabled, use a QoS type frame */
-       if (sta_flags & WLAN_STA_WME) {
+       /* receiver and we are QoS enabled, use a QoS type frame */
+       if (sta_flags & WLAN_STA_WME &&
+           ieee80211_num_regular_queues(&local->hw) >= 4) {
                fc |= IEEE80211_STYPE_QOS_DATA;
                hdrlen += 2;
        }
@@ -1555,32 +1553,26 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
         * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and
         * alloc_skb() (net/core/skbuff.c)
         */
-       head_need = hdrlen + encaps_len + meshhdrlen + local->tx_headroom;
-       head_need -= skb_headroom(skb);
+       head_need = hdrlen + encaps_len + meshhdrlen - skb_headroom(skb);
 
-       /* We are going to modify skb data, so make a copy of it if happens to
-        * be cloned. This could happen, e.g., with Linux bridge code passing
-        * us broadcast frames. */
+       /*
+        * So we need to modify the skb header and hence need a copy of
+        * that. The head_need variable above doesn't, so far, include
+        * the needed header space that we don't need right away. If we
+        * can, then we don't reallocate right now but only after the
+        * frame arrives at the master device (if it does...)
+        *
+        * If we cannot, however, then we will reallocate to include all
+        * the ever needed space. Also, if we need to reallocate it anyway,
+        * make it big enough for everything we may ever need.
+        */
 
        if (head_need > 0 || skb_header_cloned(skb)) {
-#if 0
-               printk(KERN_DEBUG "%s: need to reallocate buffer for %d bytes "
-                      "of headroom\n", dev->name, head_need);
-#endif
-
-               if (skb_header_cloned(skb))
-                       I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
-               else
-                       I802_DEBUG_INC(local->tx_expand_skb_head);
-               /* Since we have to reallocate the buffer, make sure that there
-                * is enough room for possible WEP IV/ICV and TKIP (8 bytes
-                * before payload and 12 after). */
-               if (pskb_expand_head(skb, (head_need > 0 ? head_need + 8 : 8),
-                                    12, GFP_ATOMIC)) {
-                       printk(KERN_DEBUG "%s: failed to reallocate TX buffer"
-                              "\n", dev->name);
+               head_need += IEEE80211_ENCRYPT_HEADROOM;
+               head_need += local->tx_headroom;
+               head_need = max_t(int, 0, head_need);
+               if (ieee80211_skb_resize(local, skb, head_need, true))
                        goto fail;
-               }
        }
 
        if (encaps_data) {
@@ -1611,11 +1603,14 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
        nh_pos += hdrlen;
        h_pos += hdrlen;
 
-       pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
-       memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
-       pkt_data->ifindex = dev->ifindex;
+       info = IEEE80211_SKB_CB(skb);
+       memset(info, 0, sizeof(*info));
+       info->control.ifindex = dev->ifindex;
        if (ethertype == ETH_P_PAE)
-               pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME;
+               info->flags |= IEEE80211_TX_CTL_EAPOL_FRAME;
+
+       /* Interfaces should always request a status report */
+       info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
 
        skb->dev = local->mdev;
        dev->stats.tx_packets++;
@@ -1640,46 +1635,55 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
        return ret;
 }
 
-/* helper functions for pending packets for when queues are stopped */
 
+/*
+ * ieee80211_clear_tx_pending may not be called in a context where
+ * it is possible that it packets could come in again.
+ */
 void ieee80211_clear_tx_pending(struct ieee80211_local *local)
 {
        int i, j;
        struct ieee80211_tx_stored_packet *store;
 
-       for (i = 0; i < local->hw.queues; i++) {
-               if (!__ieee80211_queue_pending(local, i))
+       for (i = 0; i < ieee80211_num_regular_queues(&local->hw); i++) {
+               if (!test_bit(i, local->queues_pending))
                        continue;
                store = &local->pending_packet[i];
                kfree_skb(store->skb);
                for (j = 0; j < store->num_extra_frag; j++)
                        kfree_skb(store->extra_frag[j]);
                kfree(store->extra_frag);
-               clear_bit(IEEE80211_LINK_STATE_PENDING, &local->state[i]);
+               clear_bit(i, local->queues_pending);
        }
 }
 
+/*
+ * Transmit all pending packets. Called from tasklet, locks master device
+ * TX lock so that no new packets can come in.
+ */
 void ieee80211_tx_pending(unsigned long data)
 {
        struct ieee80211_local *local = (struct ieee80211_local *)data;
        struct net_device *dev = local->mdev;
        struct ieee80211_tx_stored_packet *store;
        struct ieee80211_tx_data tx;
-       int i, ret, reschedule = 0;
+       int i, ret;
 
        netif_tx_lock_bh(dev);
-       for (i = 0; i < local->hw.queues; i++) {
-               if (__ieee80211_queue_stopped(local, i))
+       for (i = 0; i < ieee80211_num_regular_queues(&local->hw); i++) {
+               /* Check that this queue is ok */
+               if (__netif_subqueue_stopped(local->mdev, i))
                        continue;
-               if (!__ieee80211_queue_pending(local, i)) {
-                       reschedule = 1;
+
+               if (!test_bit(i, local->queues_pending)) {
+                       ieee80211_wake_queue(&local->hw, i);
                        continue;
                }
+
                store = &local->pending_packet[i];
-               tx.control = &store->control;
                tx.extra_frag = store->extra_frag;
                tx.num_extra_frag = store->num_extra_frag;
-               tx.last_frag_rate = store->last_frag_rate;
+               tx.last_frag_rate_idx = store->last_frag_rate_idx;
                tx.flags = 0;
                if (store->last_frag_rate_ctrl_probe)
                        tx.flags |= IEEE80211_TX_PROBE_LAST_FRAG;
@@ -1688,19 +1692,11 @@ void ieee80211_tx_pending(unsigned long data)
                        if (ret == IEEE80211_TX_FRAG_AGAIN)
                                store->skb = NULL;
                } else {
-                       clear_bit(IEEE80211_LINK_STATE_PENDING,
-                                 &local->state[i]);
-                       reschedule = 1;
+                       clear_bit(i, local->queues_pending);
+                       ieee80211_wake_queue(&local->hw, i);
                }
        }
        netif_tx_unlock_bh(dev);
-       if (reschedule) {
-               if (!ieee80211_qdisc_installed(dev)) {
-                       if (!__ieee80211_queue_stopped(local, 0))
-                               netif_wake_queue(dev);
-               } else
-                       netif_schedule(dev);
-       }
 }
 
 /* functions for drivers to get certain frames */
@@ -1769,11 +1765,11 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
 }
 
 struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
-                                    struct ieee80211_vif *vif,
-                                    struct ieee80211_tx_control *control)
+                                    struct ieee80211_vif *vif)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        struct sk_buff *skb;
+       struct ieee80211_tx_info *info;
        struct net_device *bdev;
        struct ieee80211_sub_if_data *sdata = NULL;
        struct ieee80211_if_ap *ap = NULL;
@@ -1783,9 +1779,10 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
        struct ieee80211_mgmt *mgmt;
        int *num_beacons;
        bool err = true;
+       enum ieee80211_band band = local->hw.conf.channel->band;
        u8 *pos;
 
-       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+       sband = local->hw.wiphy->bands[band];
 
        rcu_read_lock();
 
@@ -1878,30 +1875,32 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
                goto out;
        }
 
-       if (control) {
-               rate_control_get_rate(local->mdev, sband, skb, &rsel);
-               if (!rsel.rate) {
-                       if (net_ratelimit()) {
-                               printk(KERN_DEBUG "%s: ieee80211_beacon_get: "
-                                      "no rate found\n",
-                                      wiphy_name(local->hw.wiphy));
-                       }
-                       dev_kfree_skb(skb);
-                       skb = NULL;
-                       goto out;
-               }
+       info = IEEE80211_SKB_CB(skb);
 
-               control->vif = vif;
-               control->tx_rate = rsel.rate;
-               if (sdata->bss_conf.use_short_preamble &&
-                   rsel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
-                       control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
-               control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
-               control->flags |= IEEE80211_TXCTL_NO_ACK;
-               control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
-               control->retry_limit = 1;
-               control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT;
+       info->band = band;
+       rate_control_get_rate(local->mdev, sband, skb, &rsel);
+
+       if (unlikely(rsel.rate_idx < 0)) {
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "%s: ieee80211_beacon_get: "
+                              "no rate found\n",
+                              wiphy_name(local->hw.wiphy));
+               }
+               dev_kfree_skb(skb);
+               skb = NULL;
+               goto out;
        }
+
+       info->control.vif = vif;
+       info->tx_rate_idx = rsel.rate_idx;
+       if (sdata->bss_conf.use_short_preamble &&
+           sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE)
+               info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
+       info->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
+       info->flags |= IEEE80211_TX_CTL_NO_ACK;
+       info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
+       info->control.retry_limit = 1;
+       info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
        (*num_beacons)++;
 out:
        rcu_read_unlock();
@@ -1911,7 +1910,7 @@ EXPORT_SYMBOL(ieee80211_beacon_get);
 
 void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                       const void *frame, size_t frame_len,
-                      const struct ieee80211_tx_control *frame_txctl,
+                      const struct ieee80211_tx_info *frame_txctl,
                       struct ieee80211_rts *rts)
 {
        const struct ieee80211_hdr *hdr = frame;
@@ -1928,7 +1927,7 @@ EXPORT_SYMBOL(ieee80211_rts_get);
 
 void ieee80211_ctstoself_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                             const void *frame, size_t frame_len,
-                            const struct ieee80211_tx_control *frame_txctl,
+                            const struct ieee80211_tx_info *frame_txctl,
                             struct ieee80211_cts *cts)
 {
        const struct ieee80211_hdr *hdr = frame;
@@ -1944,11 +1943,10 @@ EXPORT_SYMBOL(ieee80211_ctstoself_get);
 
 struct sk_buff *
 ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
-                         struct ieee80211_vif *vif,
-                         struct ieee80211_tx_control *control)
+                         struct ieee80211_vif *vif)
 {
        struct ieee80211_local *local = hw_to_local(hw);
-       struct sk_buff *skb;
+       struct sk_buff *skb = NULL;
        struct sta_info *sta;
        ieee80211_tx_handler *handler;
        struct ieee80211_tx_data tx;
@@ -1957,10 +1955,11 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_if_ap *bss = NULL;
        struct beacon_data *beacon;
+       struct ieee80211_tx_info *info;
 
        sdata = vif_to_sdata(vif);
        bdev = sdata->dev;
-
+       bss = &sdata->u.ap;
 
        if (!bss)
                return NULL;
@@ -1968,19 +1967,16 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
        rcu_read_lock();
        beacon = rcu_dereference(bss->beacon);
 
-       if (sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon ||
-           !beacon->head) {
-               rcu_read_unlock();
-               return NULL;
-       }
+       if (sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon || !beacon->head)
+               goto out;
 
        if (bss->dtim_count != 0)
-               return NULL; /* send buffered bc/mc only after DTIM beacon */
-       memset(control, 0, sizeof(*control));
+               goto out; /* send buffered bc/mc only after DTIM beacon */
+
        while (1) {
                skb = skb_dequeue(&bss->ps_bc_buf);
                if (!skb)
-                       return NULL;
+                       goto out;
                local->total_ps_buffered--;
 
                if (!skb_queue_empty(&bss->ps_bc_buf) && skb->len >= 2) {
@@ -1993,20 +1989,26 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
                                cpu_to_le16(IEEE80211_FCTL_MOREDATA);
                }
 
-               if (!ieee80211_tx_prepare(&tx, skb, local->mdev, control))
+               if (!ieee80211_tx_prepare(&tx, skb, local->mdev))
                        break;
                dev_kfree_skb_any(skb);
        }
+
+       info = IEEE80211_SKB_CB(skb);
+
        sta = tx.sta;
        tx.flags |= IEEE80211_TX_PS_BUFFERED;
        tx.channel = local->hw.conf.channel;
+       info->band = tx.channel->band;
 
        for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) {
                res = (*handler)(&tx);
                if (res == TX_DROP || res == TX_QUEUED)
                        break;
        }
-       skb = tx.skb; /* handlers are allowed to change skb */
+
+       if (WARN_ON(tx.skb != skb))
+               res = TX_DROP;
 
        if (res == TX_DROP) {
                I802_DEBUG_INC(local->tx_handlers_drop);
@@ -2017,6 +2019,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
                skb = NULL;
        }
 
+out:
        rcu_read_unlock();
 
        return skb;
index 4e97b266f907eca5b43bd87c99d6aadf3fef8fd9..6513bc2d2707022ed3c80228ab2128be767c4514 100644 (file)
@@ -258,7 +258,7 @@ EXPORT_SYMBOL(ieee80211_generic_frame_duration);
 
 __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
                              struct ieee80211_vif *vif, size_t frame_len,
-                             const struct ieee80211_tx_control *frame_txctl)
+                             const struct ieee80211_tx_info *frame_txctl)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_rate *rate;
@@ -266,10 +266,13 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
        bool short_preamble;
        int erp;
        u16 dur;
+       struct ieee80211_supported_band *sband;
+
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
        short_preamble = sdata->bss_conf.use_short_preamble;
 
-       rate = frame_txctl->rts_cts_rate;
+       rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx];
 
        erp = 0;
        if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
@@ -292,7 +295,7 @@ EXPORT_SYMBOL(ieee80211_rts_duration);
 __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
                                    struct ieee80211_vif *vif,
                                    size_t frame_len,
-                                   const struct ieee80211_tx_control *frame_txctl)
+                                   const struct ieee80211_tx_info *frame_txctl)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_rate *rate;
@@ -300,10 +303,13 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
        bool short_preamble;
        int erp;
        u16 dur;
+       struct ieee80211_supported_band *sband;
+
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
        short_preamble = sdata->bss_conf.use_short_preamble;
 
-       rate = frame_txctl->rts_cts_rate;
+       rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx];
        erp = 0;
        if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
                erp = rate->flags & IEEE80211_RATE_ERP_G;
@@ -311,7 +317,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
        /* Data frame duration */
        dur = ieee80211_frame_duration(local, frame_len, rate->bitrate,
                                       erp, short_preamble);
-       if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) {
+       if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) {
                /* ACK duration */
                dur += ieee80211_frame_duration(local, 10, rate->bitrate,
                                                erp, short_preamble);
@@ -325,17 +331,15 @@ void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
 {
        struct ieee80211_local *local = hw_to_local(hw);
 
-       if (test_and_clear_bit(IEEE80211_LINK_STATE_XOFF,
-                              &local->state[queue])) {
-               if (test_bit(IEEE80211_LINK_STATE_PENDING,
-                            &local->state[queue]))
-                       tasklet_schedule(&local->tx_pending_tasklet);
-               else
-                       if (!ieee80211_qdisc_installed(local->mdev)) {
-                               if (queue == 0)
-                                       netif_wake_queue(local->mdev);
-                       } else
-                               __netif_schedule(local->mdev);
+       if (test_bit(queue, local->queues_pending)) {
+               tasklet_schedule(&local->tx_pending_tasklet);
+       } else {
+               if (ieee80211_is_multiqueue(local)) {
+                       netif_wake_subqueue(local->mdev, queue);
+               } else {
+                       WARN_ON(queue != 0);
+                       netif_wake_queue(local->mdev);
+               }
        }
 }
 EXPORT_SYMBOL(ieee80211_wake_queue);
@@ -344,29 +348,20 @@ void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue)
 {
        struct ieee80211_local *local = hw_to_local(hw);
 
-       if (!ieee80211_qdisc_installed(local->mdev) && queue == 0)
+       if (ieee80211_is_multiqueue(local)) {
+               netif_stop_subqueue(local->mdev, queue);
+       } else {
+               WARN_ON(queue != 0);
                netif_stop_queue(local->mdev);
-       set_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]);
+       }
 }
 EXPORT_SYMBOL(ieee80211_stop_queue);
 
-void ieee80211_start_queues(struct ieee80211_hw *hw)
-{
-       struct ieee80211_local *local = hw_to_local(hw);
-       int i;
-
-       for (i = 0; i < local->hw.queues; i++)
-               clear_bit(IEEE80211_LINK_STATE_XOFF, &local->state[i]);
-       if (!ieee80211_qdisc_installed(local->mdev))
-               netif_start_queue(local->mdev);
-}
-EXPORT_SYMBOL(ieee80211_start_queues);
-
 void ieee80211_stop_queues(struct ieee80211_hw *hw)
 {
        int i;
 
-       for (i = 0; i < hw->queues; i++)
+       for (i = 0; i < ieee80211_num_queues(hw); i++)
                ieee80211_stop_queue(hw, i);
 }
 EXPORT_SYMBOL(ieee80211_stop_queues);
@@ -375,7 +370,7 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw)
 {
        int i;
 
-       for (i = 0; i < hw->queues; i++)
+       for (i = 0; i < hw->queues + hw->ampdu_queues; i++)
                ieee80211_wake_queue(hw, i);
 }
 EXPORT_SYMBOL(ieee80211_wake_queues);
index affcecd78c1076b09affa30e721999cd960fd926..e7b6344c900a6f15005748b1f1650ab03eb5a1ec 100644 (file)
@@ -93,13 +93,9 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local,
        fc |= IEEE80211_FCTL_PROTECTED;
        hdr->frame_control = cpu_to_le16(fc);
 
-       if ((skb_headroom(skb) < WEP_IV_LEN ||
-            skb_tailroom(skb) < WEP_ICV_LEN)) {
-               I802_DEBUG_INC(local->tx_expand_skb_head);
-               if (unlikely(pskb_expand_head(skb, WEP_IV_LEN, WEP_ICV_LEN,
-                                             GFP_ATOMIC)))
-                       return NULL;
-       }
+       if (WARN_ON(skb_tailroom(skb) < WEP_ICV_LEN ||
+                   skb_headroom(skb) < WEP_IV_LEN))
+               return NULL;
 
        hdrlen = ieee80211_get_hdrlen(fc);
        newhdr = skb_push(skb, WEP_IV_LEN);
@@ -333,11 +329,16 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx)
 
 static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
 {
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+       info->control.iv_len = WEP_IV_LEN;
+       info->control.icv_len = WEP_ICV_LEN;
+
        if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) {
                if (ieee80211_wep_encrypt(tx->local, skb, tx->key))
                        return -1;
        } else {
-               tx->control->key_idx = tx->key->conf.hw_key_idx;
+               info->control.hw_key = &tx->key->conf;
                if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) {
                        if (!ieee80211_wep_add_iv(tx->local, skb, tx->key))
                                return -1;
@@ -349,8 +350,6 @@ static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
 ieee80211_tx_result
 ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx)
 {
-       tx->control->iv_len = WEP_IV_LEN;
-       tx->control->icv_len = WEP_ICV_LEN;
        ieee80211_tx_set_protected(tx);
 
        if (wep_encrypt_skb(tx, tx->skb) < 0) {
index 363779c5065897ef39b72532e0d467424f0e6b17..e587172115b8397acc0ce4f92d401e5b288101a4 100644 (file)
@@ -26,7 +26,7 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb,
                          struct ieee80211_key *key);
 int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
                          struct ieee80211_key *key);
-u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
+u8 *ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
 
 ieee80211_rx_result
 ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx);
index a8bb8e31b1ec790c2e1e4e160ca81f8be1719d5c..4806d96b9877f353f004a7a39d837ad6feacd176 100644 (file)
@@ -169,14 +169,26 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev,
        range->num_encoding_sizes = 2;
        range->max_encoding_tokens = NUM_DEFAULT_KEYS;
 
-       range->max_qual.qual = local->hw.max_signal;
-       range->max_qual.level = local->hw.max_rssi;
-       range->max_qual.noise = local->hw.max_noise;
+       if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC ||
+           local->hw.flags & IEEE80211_HW_SIGNAL_DB)
+               range->max_qual.level = local->hw.max_signal;
+       else if  (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
+               range->max_qual.level = -110;
+       else
+               range->max_qual.level = 0;
+
+       if (local->hw.flags & IEEE80211_HW_NOISE_DBM)
+               range->max_qual.noise = -110;
+       else
+               range->max_qual.noise = 0;
+
+       range->max_qual.qual = 100;
        range->max_qual.updated = local->wstats_flags;
 
-       range->avg_qual.qual = local->hw.max_signal/2;
-       range->avg_qual.level = 0;
-       range->avg_qual.noise = 0;
+       range->avg_qual.qual = 50;
+       /* not always true but better than nothing */
+       range->avg_qual.level = range->max_qual.level / 2;
+       range->avg_qual.noise = range->max_qual.noise / 2;
        range->avg_qual.updated = local->wstats_flags;
 
        range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
@@ -1007,8 +1019,8 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev
                wstats->qual.noise = 0;
                wstats->qual.updated = IW_QUAL_ALL_INVALID;
        } else {
-               wstats->qual.level = sta->last_rssi;
-               wstats->qual.qual = sta->last_signal;
+               wstats->qual.level = sta->last_signal;
+               wstats->qual.qual = sta->last_qual;
                wstats->qual.noise = sta->last_noise;
                wstats->qual.updated = local->wstats_flags;
        }
index dc1598b86004e9df03e4eefb188b17ca292171b9..14a9ff10a1e90879e75b48e8a5332318fb3187c8 100644 (file)
 #include "wme.h"
 
 /* maximum number of hardware queues we support. */
-#define TC_80211_MAX_QUEUES 16
+#define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES)
+/* current number of hardware queues we support. */
+#define QD_NUM(hw) ((hw)->queues + (hw)->ampdu_queues)
 
+/*
+ * Default mapping in classifier to work with default
+ * queue setup.
+ */
 const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 };
 
 struct ieee80211_sched_data
 {
-       unsigned long qdisc_pool[BITS_TO_LONGS(TC_80211_MAX_QUEUES)];
+       unsigned long qdisc_pool[BITS_TO_LONGS(QD_MAX_QUEUES)];
        struct tcf_proto *filter_list;
-       struct Qdisc *queues[TC_80211_MAX_QUEUES];
-       struct sk_buff_head requeued[TC_80211_MAX_QUEUES];
+       struct Qdisc *queues[QD_MAX_QUEUES];
+       struct sk_buff_head requeued[QD_MAX_QUEUES];
 };
 
 static const char llc_ip_hdr[8] = {0xAA, 0xAA, 0x3, 0, 0, 0, 0x08, 0};
@@ -95,7 +101,7 @@ static inline int wme_downgrade_ac(struct sk_buff *skb)
 
 /* positive return value indicates which queue to use
  * negative return value indicates to drop the frame */
-static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd)
+static int classify80211(struct sk_buff *skb, struct Qdisc *qd)
 {
        struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@@ -106,7 +112,7 @@ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd)
        if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) {
                /* management frames go on AC_VO queue, but are sent
                * without QoS control fields */
-               return IEEE80211_TX_QUEUE_DATA0;
+               return 0;
        }
 
        if (0 /* injected */) {
@@ -141,29 +147,29 @@ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd)
 static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
 {
        struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+       struct ieee80211_hw *hw = &local->hw;
        struct ieee80211_sched_data *q = qdisc_priv(qd);
-       struct ieee80211_tx_packet_data *pkt_data =
-               (struct ieee80211_tx_packet_data *) skb->cb;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        unsigned short fc = le16_to_cpu(hdr->frame_control);
        struct Qdisc *qdisc;
-       int err, queue;
        struct sta_info *sta;
+       int err, queue;
        u8 tid;
 
-       if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) {
-               queue = pkt_data->queue;
+       if (info->flags & IEEE80211_TX_CTL_REQUEUE) {
+               queue = skb_get_queue_mapping(skb);
                rcu_read_lock();
                sta = sta_info_get(local, hdr->addr1);
                tid = skb->priority & QOS_CONTROL_TAG1D_MASK;
                if (sta) {
                        int ampdu_queue = sta->tid_to_tx_q[tid];
-                       if ((ampdu_queue < local->hw.queues) &&
+                       if ((ampdu_queue < QD_NUM(hw)) &&
                            test_bit(ampdu_queue, q->qdisc_pool)) {
                                queue = ampdu_queue;
-                               pkt_data->flags |= IEEE80211_TXPD_AMPDU;
+                               info->flags |= IEEE80211_TX_CTL_AMPDU;
                        } else {
-                               pkt_data->flags &= ~IEEE80211_TXPD_AMPDU;
+                               info->flags &= ~IEEE80211_TX_CTL_AMPDU;
                        }
                }
                rcu_read_unlock();
@@ -174,6 +180,9 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
 
        queue = classify80211(skb, qd);
 
+       if (unlikely(queue >= local->hw.queues))
+               queue = local->hw.queues - 1;
+
        /* now we know the 1d priority, fill in the QoS header if there is one
         */
        if (WLAN_FC_IS_QOS_DATA(fc)) {
@@ -193,35 +202,24 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
                sta = sta_info_get(local, hdr->addr1);
                if (sta) {
                        int ampdu_queue = sta->tid_to_tx_q[tid];
-                       if ((ampdu_queue < local->hw.queues) &&
-                               test_bit(ampdu_queue, q->qdisc_pool)) {
+                       if ((ampdu_queue < QD_NUM(hw)) &&
+                           test_bit(ampdu_queue, q->qdisc_pool)) {
                                queue = ampdu_queue;
-                               pkt_data->flags |= IEEE80211_TXPD_AMPDU;
+                               info->flags |= IEEE80211_TX_CTL_AMPDU;
                        } else {
-                               pkt_data->flags &= ~IEEE80211_TXPD_AMPDU;
+                               info->flags &= ~IEEE80211_TX_CTL_AMPDU;
                        }
                }
 
                rcu_read_unlock();
        }
 
-       if (unlikely(queue >= local->hw.queues)) {
-#if 0
-               if (net_ratelimit()) {
-                       printk(KERN_DEBUG "%s - queue=%d (hw does not "
-                              "support) -> %d\n",
-                              __func__, queue, local->hw.queues - 1);
-               }
-#endif
-               queue = local->hw.queues - 1;
-       }
-
        if (unlikely(queue < 0)) {
                        kfree_skb(skb);
                        err = NET_XMIT_DROP;
        } else {
                tid = skb->priority & QOS_CONTROL_TAG1D_MASK;
-               pkt_data->queue = (unsigned int) queue;
+               skb_set_queue_mapping(skb, queue);
                qdisc = q->queues[queue];
                err = qdisc->enqueue(skb, qdisc);
                if (err == NET_XMIT_SUCCESS) {
@@ -242,13 +240,11 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
 static int wme_qdiscop_requeue(struct sk_buff *skb, struct Qdisc* qd)
 {
        struct ieee80211_sched_data *q = qdisc_priv(qd);
-       struct ieee80211_tx_packet_data *pkt_data =
-               (struct ieee80211_tx_packet_data *) skb->cb;
        struct Qdisc *qdisc;
        int err;
 
        /* we recorded which queue to use earlier! */
-       qdisc = q->queues[pkt_data->queue];
+       qdisc = q->queues[skb_get_queue_mapping(skb)];
 
        if ((err = qdisc->ops->requeue(skb, qdisc)) == 0) {
                qd->q.qlen++;
@@ -270,13 +266,10 @@ static struct sk_buff *wme_qdiscop_dequeue(struct Qdisc* qd)
        int queue;
 
        /* check all the h/w queues in numeric/priority order */
-       for (queue = 0; queue < hw->queues; queue++) {
+       for (queue = 0; queue < QD_NUM(hw); queue++) {
                /* see if there is room in this hardware queue */
-               if ((test_bit(IEEE80211_LINK_STATE_XOFF,
-                               &local->state[queue])) ||
-                   (test_bit(IEEE80211_LINK_STATE_PENDING,
-                               &local->state[queue])) ||
-                        (!test_bit(queue, q->qdisc_pool)))
+               if (__netif_subqueue_stopped(local->mdev, queue) ||
+                   !test_bit(queue, q->qdisc_pool))
                        continue;
 
                /* there is space - try and get a frame */
@@ -308,7 +301,7 @@ static void wme_qdiscop_reset(struct Qdisc* qd)
 
        /* QUESTION: should we have some hardware flush functionality here? */
 
-       for (queue = 0; queue < hw->queues; queue++) {
+       for (queue = 0; queue < QD_NUM(hw); queue++) {
                skb_queue_purge(&q->requeued[queue]);
                qdisc_reset(q->queues[queue]);
        }
@@ -326,7 +319,7 @@ static void wme_qdiscop_destroy(struct Qdisc* qd)
        tcf_destroy_chain(q->filter_list);
        q->filter_list = NULL;
 
-       for (queue=0; queue < hw->queues; queue++) {
+       for (queue = 0; queue < QD_NUM(hw); queue++) {
                skb_queue_purge(&q->requeued[queue]);
                qdisc_destroy(q->queues[queue]);
                q->queues[queue] = &noop_qdisc;
@@ -337,17 +330,6 @@ static void wme_qdiscop_destroy(struct Qdisc* qd)
 /* called whenever parameters are updated on existing qdisc */
 static int wme_qdiscop_tune(struct Qdisc *qd, struct nlattr *opt)
 {
-/*     struct ieee80211_sched_data *q = qdisc_priv(qd);
-*/
-       /* check our options block is the right size */
-       /* copy any options to our local structure */
-/*     Ignore options block for now - always use static mapping
-       struct tc_ieee80211_qopt *qopt = nla_data(opt);
-
-       if (opt->nla_len < nla_attr_size(sizeof(*qopt)))
-               return -EINVAL;
-       memcpy(q->tag2queue, qopt->tag2queue, sizeof(qopt->tag2queue));
-*/
        return 0;
 }
 
@@ -358,7 +340,7 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt)
        struct ieee80211_sched_data *q = qdisc_priv(qd);
        struct net_device *dev = qd->dev;
        struct ieee80211_local *local;
-       int queues;
+       struct ieee80211_hw *hw;
        int err = 0, i;
 
        /* check that device is a mac80211 device */
@@ -366,29 +348,26 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt)
            dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
                return -EINVAL;
 
-       /* check this device is an ieee80211 master type device */
-       if (dev->type != ARPHRD_IEEE80211)
+       local = wdev_priv(dev->ieee80211_ptr);
+       hw = &local->hw;
+
+       /* only allow on master dev */
+       if (dev != local->mdev)
                return -EINVAL;
 
-       /* check that there is no qdisc currently attached to device
-        * this ensures that we will be the root qdisc. (I can't find a better
-        * way to test this explicitly) */
-       if (dev->qdisc_sleeping != &noop_qdisc)
+       /* ensure that we are root qdisc */
+       if (qd->parent != TC_H_ROOT)
                return -EINVAL;
 
        if (qd->flags & TCQ_F_INGRESS)
                return -EINVAL;
 
-       local = wdev_priv(dev->ieee80211_ptr);
-       queues = local->hw.queues;
-
        /* if options were passed in, set them */
-       if (opt) {
+       if (opt)
                err = wme_qdiscop_tune(qd, opt);
-       }
 
        /* create child queues */
-       for (i = 0; i < queues; i++) {
+       for (i = 0; i < QD_NUM(hw); i++) {
                skb_queue_head_init(&q->requeued[i]);
                q->queues[i] = qdisc_create_dflt(qd->dev, &pfifo_qdisc_ops,
                                                 qd->handle);
@@ -399,8 +378,8 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt)
                }
        }
 
-       /* reserve all legacy QoS queues */
-       for (i = 0; i < min(IEEE80211_TX_QUEUE_DATA4, queues); i++)
+       /* non-aggregation queues: reserve/mark as used */
+       for (i = 0; i < local->hw.queues; i++)
                set_bit(i, q->qdisc_pool);
 
        return err;
@@ -408,16 +387,6 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt)
 
 static int wme_qdiscop_dump(struct Qdisc *qd, struct sk_buff *skb)
 {
-/*     struct ieee80211_sched_data *q = qdisc_priv(qd);
-       unsigned char *p = skb->tail;
-       struct tc_ieee80211_qopt opt;
-
-       memcpy(&opt.tag2queue, q->tag2queue, TC_80211_MAX_TAG + 1);
-       NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
-*/     return skb->len;
-/*
-nla_put_failure:
-       skb_trim(skb, p - skb->data);*/
        return -1;
 }
 
@@ -430,7 +399,7 @@ static int wme_classop_graft(struct Qdisc *qd, unsigned long arg,
        struct ieee80211_hw *hw = &local->hw;
        unsigned long queue = arg - 1;
 
-       if (queue >= hw->queues)
+       if (queue >= QD_NUM(hw))
                return -EINVAL;
 
        if (!new)
@@ -454,7 +423,7 @@ wme_classop_leaf(struct Qdisc *qd, unsigned long arg)
        struct ieee80211_hw *hw = &local->hw;
        unsigned long queue = arg - 1;
 
-       if (queue >= hw->queues)
+       if (queue >= QD_NUM(hw))
                return NULL;
 
        return q->queues[queue];
@@ -467,7 +436,7 @@ static unsigned long wme_classop_get(struct Qdisc *qd, u32 classid)
        struct ieee80211_hw *hw = &local->hw;
        unsigned long queue = TC_H_MIN(classid);
 
-       if (queue - 1 >= hw->queues)
+       if (queue - 1 >= QD_NUM(hw))
                return 0;
 
        return queue;
@@ -493,7 +462,7 @@ static int wme_classop_change(struct Qdisc *qd, u32 handle, u32 parent,
        struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
        struct ieee80211_hw *hw = &local->hw;
 
-       if (cl - 1 > hw->queues)
+       if (cl - 1 > QD_NUM(hw))
                return -ENOENT;
 
        /* TODO: put code to program hardware queue parameters here,
@@ -510,7 +479,7 @@ static int wme_classop_delete(struct Qdisc *qd, unsigned long cl)
        struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
        struct ieee80211_hw *hw = &local->hw;
 
-       if (cl - 1 > hw->queues)
+       if (cl - 1 > QD_NUM(hw))
                return -ENOENT;
        return 0;
 }
@@ -523,7 +492,7 @@ static int wme_classop_dump_class(struct Qdisc *qd, unsigned long cl,
        struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
        struct ieee80211_hw *hw = &local->hw;
 
-       if (cl - 1 > hw->queues)
+       if (cl - 1 > QD_NUM(hw))
                return -ENOENT;
        tcm->tcm_handle = TC_H_MIN(cl);
        tcm->tcm_parent = qd->handle;
@@ -541,7 +510,7 @@ static void wme_classop_walk(struct Qdisc *qd, struct qdisc_walker *arg)
        if (arg->stop)
                return;
 
-       for (queue = 0; queue < hw->queues; queue++) {
+       for (queue = 0; queue < QD_NUM(hw); queue++) {
                if (arg->count < arg->skip) {
                        arg->count++;
                        continue;
@@ -658,10 +627,13 @@ int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
        DECLARE_MAC_BUF(mac);
 
        /* prepare the filter and save it for the SW queue
-        * matching the recieved HW queue */
+        * matching the received HW queue */
+
+       if (!local->hw.ampdu_queues)
+               return -EPERM;
 
        /* try to get a Qdisc from the pool */
-       for (i = IEEE80211_TX_QUEUE_BEACON; i < local->hw.queues; i++)
+       for (i = local->hw.queues; i < QD_NUM(&local->hw); i++)
                if (!test_and_set_bit(i, q->qdisc_pool)) {
                        ieee80211_stop_queue(local_to_hw(local), i);
                        sta->tid_to_tx_q[tid] = i;
@@ -690,13 +662,14 @@ void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local,
                                   struct sta_info *sta, u16 tid,
                                   u8 requeue)
 {
+       struct ieee80211_hw *hw = &local->hw;
        struct ieee80211_sched_data *q =
                qdisc_priv(local->mdev->qdisc_sleeping);
        int agg_queue = sta->tid_to_tx_q[tid];
 
        /* return the qdisc to the pool */
        clear_bit(agg_queue, q->qdisc_pool);
-       sta->tid_to_tx_q[tid] = local->hw.queues;
+       sta->tid_to_tx_q[tid] = QD_NUM(hw);
 
        if (requeue)
                ieee80211_requeue(local, agg_queue);
index fcc6b05508ccf06eeeb94c4ff7869c148b7168f4..bbdb53344817a96f581eebfea093128d9f4b1953 100644 (file)
@@ -31,7 +31,7 @@ static inline int WLAN_FC_IS_QOS_DATA(u16 fc)
        return (fc & 0x8C) == 0x88;
 }
 
-#ifdef CONFIG_NET_SCHED
+#ifdef CONFIG_MAC80211_QOS
 void ieee80211_install_qdisc(struct net_device *dev);
 int ieee80211_qdisc_installed(struct net_device *dev);
 int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
index 45709ada8fee2c2ba222d7e8fb5743e62b2f6d27..9f6fd20374e13fcbf9f5ecd5d971fd6e58184a92 100644 (file)
@@ -79,6 +79,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
        struct sk_buff *skb = tx->skb;
        int authenticator;
        int wpa_test = 0;
+       int tail;
 
        fc = tx->fc;
 
@@ -98,16 +99,13 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
                return TX_CONTINUE;
        }
 
-       if (skb_tailroom(skb) < MICHAEL_MIC_LEN) {
-               I802_DEBUG_INC(tx->local->tx_expand_skb_head);
-               if (unlikely(pskb_expand_head(skb, TKIP_IV_LEN,
-                                             MICHAEL_MIC_LEN + TKIP_ICV_LEN,
-                                             GFP_ATOMIC))) {
-                       printk(KERN_DEBUG "%s: failed to allocate more memory "
-                              "for Michael MIC\n", tx->dev->name);
-                       return TX_DROP;
-               }
-       }
+       tail = MICHAEL_MIC_LEN;
+       if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
+               tail += TKIP_ICV_LEN;
+
+       if (WARN_ON(skb_tailroom(skb) < tail ||
+                   skb_headroom(skb) < TKIP_IV_LEN))
+               return TX_DROP;
 
 #if 0
        authenticator = fc & IEEE80211_FCTL_FROMDS; /* FIX */
@@ -176,59 +174,65 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
        skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
 
        /* update IV in key information to be able to detect replays */
-       rx->key->u.tkip.iv32_rx[rx->queue] = rx->tkip_iv32;
-       rx->key->u.tkip.iv16_rx[rx->queue] = rx->tkip_iv16;
+       rx->key->u.tkip.rx[rx->queue].iv32 = rx->tkip_iv32;
+       rx->key->u.tkip.rx[rx->queue].iv16 = rx->tkip_iv16;
 
        return RX_CONTINUE;
 }
 
 
-static int tkip_encrypt_skb(struct ieee80211_tx_data *tx,
-                           struct sk_buff *skb, int test)
+static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        struct ieee80211_key *key = tx->key;
-       int hdrlen, len, tailneed;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       int hdrlen, len, tail;
        u16 fc;
        u8 *pos;
 
+       info->control.icv_len = TKIP_ICV_LEN;
+       info->control.iv_len = TKIP_IV_LEN;
+
+       if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
+           !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
+               /* hwaccel - with no need for preallocated room for IV/ICV */
+               info->control.hw_key = &tx->key->conf;
+               return 0;
+       }
+
        fc = le16_to_cpu(hdr->frame_control);
        hdrlen = ieee80211_get_hdrlen(fc);
        len = skb->len - hdrlen;
 
        if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
-               tailneed = 0;
+               tail = 0;
        else
-               tailneed = TKIP_ICV_LEN;
-
-       if ((skb_headroom(skb) < TKIP_IV_LEN ||
-            skb_tailroom(skb) < tailneed)) {
-               I802_DEBUG_INC(tx->local->tx_expand_skb_head);
-               if (unlikely(pskb_expand_head(skb, TKIP_IV_LEN, tailneed,
-                                             GFP_ATOMIC)))
-                       return -1;
-       }
+               tail = TKIP_ICV_LEN;
+
+       if (WARN_ON(skb_tailroom(skb) < tail ||
+                   skb_headroom(skb) < TKIP_IV_LEN))
+               return -1;
 
        pos = skb_push(skb, TKIP_IV_LEN);
        memmove(pos, pos + TKIP_IV_LEN, hdrlen);
        pos += hdrlen;
 
        /* Increase IV for the frame */
-       key->u.tkip.iv16++;
-       if (key->u.tkip.iv16 == 0)
-               key->u.tkip.iv32++;
+       key->u.tkip.tx.iv16++;
+       if (key->u.tkip.tx.iv16 == 0)
+               key->u.tkip.tx.iv32++;
 
        if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
                hdr = (struct ieee80211_hdr *)skb->data;
 
                /* hwaccel - with preallocated room for IV */
                ieee80211_tkip_add_iv(pos, key,
-                                     (u8) (key->u.tkip.iv16 >> 8),
-                                     (u8) (((key->u.tkip.iv16 >> 8) | 0x20) &
+                                     (u8) (key->u.tkip.tx.iv16 >> 8),
+                                     (u8) (((key->u.tkip.tx.iv16 >> 8) | 0x20) &
                                            0x7f),
-                                     (u8) key->u.tkip.iv16);
+                                     (u8) key->u.tkip.tx.iv16);
 
-               tx->control->key_idx = tx->key->conf.hw_key_idx;
+               info->control.hw_key = &tx->key->conf;
                return 0;
        }
 
@@ -246,28 +250,16 @@ ieee80211_tx_result
 ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx)
 {
        struct sk_buff *skb = tx->skb;
-       int wpa_test = 0, test = 0;
 
-       tx->control->icv_len = TKIP_ICV_LEN;
-       tx->control->iv_len = TKIP_IV_LEN;
        ieee80211_tx_set_protected(tx);
 
-       if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
-           !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) &&
-           !wpa_test) {
-               /* hwaccel - with no need for preallocated room for IV/ICV */
-               tx->control->key_idx = tx->key->conf.hw_key_idx;
-               return TX_CONTINUE;
-       }
-
-       if (tkip_encrypt_skb(tx, skb, test) < 0)
+       if (tkip_encrypt_skb(tx, skb) < 0)
                return TX_DROP;
 
        if (tx->extra_frag) {
                int i;
                for (i = 0; i < tx->num_extra_frag; i++) {
-                       if (tkip_encrypt_skb(tx, tx->extra_frag[i], test)
-                           < 0)
+                       if (tkip_encrypt_skb(tx, tx->extra_frag[i]) < 0)
                                return TX_DROP;
                }
        }
@@ -429,16 +421,27 @@ static inline int ccmp_hdr2pn(u8 *pn, u8 *hdr)
 }
 
 
-static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx,
-                           struct sk_buff *skb, int test)
+static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        struct ieee80211_key *key = tx->key;
-       int hdrlen, len, tailneed;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       int hdrlen, len, tail;
        u16 fc;
        u8 *pos, *pn, *b_0, *aad, *scratch;
        int i;
 
+       info->control.icv_len = CCMP_MIC_LEN;
+       info->control.iv_len = CCMP_HDR_LEN;
+
+       if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
+           !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
+               /* hwaccel - with no need for preallocated room for CCMP "
+                * header or MIC fields */
+               info->control.hw_key = &tx->key->conf;
+               return 0;
+       }
+
        scratch = key->u.ccmp.tx_crypto_buf;
        b_0 = scratch + 3 * AES_BLOCK_LEN;
        aad = scratch + 4 * AES_BLOCK_LEN;
@@ -448,17 +451,13 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx,
        len = skb->len - hdrlen;
 
        if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
-               tailneed = 0;
+               tail = 0;
        else
-               tailneed = CCMP_MIC_LEN;
-
-       if ((skb_headroom(skb) < CCMP_HDR_LEN ||
-            skb_tailroom(skb) < tailneed)) {
-               I802_DEBUG_INC(tx->local->tx_expand_skb_head);
-               if (unlikely(pskb_expand_head(skb, CCMP_HDR_LEN, tailneed,
-                                             GFP_ATOMIC)))
-                       return -1;
-       }
+               tail = CCMP_MIC_LEN;
+
+       if (WARN_ON(skb_tailroom(skb) < tail ||
+                   skb_headroom(skb) < CCMP_HDR_LEN))
+               return -1;
 
        pos = skb_push(skb, CCMP_HDR_LEN);
        memmove(pos, pos + CCMP_HDR_LEN, hdrlen);
@@ -478,7 +477,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx,
 
        if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
                /* hwaccel - with preallocated room for CCMP header */
-               tx->control->key_idx = key->conf.hw_key_idx;
+               info->control.hw_key = &tx->key->conf;
                return 0;
        }
 
@@ -495,28 +494,16 @@ ieee80211_tx_result
 ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx)
 {
        struct sk_buff *skb = tx->skb;
-       int test = 0;
 
-       tx->control->icv_len = CCMP_MIC_LEN;
-       tx->control->iv_len = CCMP_HDR_LEN;
        ieee80211_tx_set_protected(tx);
 
-       if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
-           !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
-               /* hwaccel - with no need for preallocated room for CCMP "
-                * header or MIC fields */
-               tx->control->key_idx = tx->key->conf.hw_key_idx;
-               return TX_CONTINUE;
-       }
-
-       if (ccmp_encrypt_skb(tx, skb, test) < 0)
+       if (ccmp_encrypt_skb(tx, skb) < 0)
                return TX_DROP;
 
        if (tx->extra_frag) {
                int i;
                for (i = 0; i < tx->num_extra_frag; i++) {
-                       if (ccmp_encrypt_skb(tx, tx->extra_frag[i], test)
-                           < 0)
+                       if (ccmp_encrypt_skb(tx, tx->extra_frag[i]) < 0)
                                return TX_DROP;
                }
        }
index c4b1799da5d76ac98920527e9fe85d30866ff9c8..e6d645221d5c1c0bd32faf843a7ff677b793293f 100644 (file)
@@ -848,6 +848,25 @@ acct:
 }
 EXPORT_SYMBOL_GPL(__nf_ct_refresh_acct);
 
+void __nf_ct_kill_acct(struct nf_conn *ct,
+               enum ip_conntrack_info ctinfo,
+               const struct sk_buff *skb,
+               int do_acct)
+{
+#ifdef CONFIG_NF_CT_ACCT
+       if (do_acct) {
+               spin_lock_bh(&nf_conntrack_lock);
+               ct->counters[CTINFO2DIR(ctinfo)].packets++;
+               ct->counters[CTINFO2DIR(ctinfo)].bytes +=
+                       skb->len - skb_network_offset(skb);
+               spin_unlock_bh(&nf_conntrack_lock);
+       }
+#endif
+       if (del_timer(&ct->timeout))
+               ct->timeout.function((unsigned long)ct);
+}
+EXPORT_SYMBOL_GPL(__nf_ct_kill_acct);
+
 #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
 
 #include <linux/netfilter/nfnetlink.h>
index bcc19fa4ed1e07ab4277f7c02c933235cd0dc261..ba1c4915e9eba571a0349ebee872d1a81edfd563 100644 (file)
@@ -88,13 +88,11 @@ void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp)
        newlen = newoff + t->len;
        rcu_read_unlock();
 
-       if (newlen >= ksize(ct->ext)) {
-               new = kmalloc(newlen, gfp);
-               if (!new)
-                       return NULL;
-
-               memcpy(new, ct->ext, ct->ext->len);
+       new = krealloc(ct->ext, newlen, gfp);
+       if (!new)
+               return NULL;
 
+       if (new != ct->ext) {
                for (i = 0; i < NF_CT_EXT_NUM; i++) {
                        if (!nf_ct_ext_exist(ct, i))
                                continue;
index 0edefcfc5949ccf500db459bd57297819c06749b..63c4e1f299b88d686982cd72e8c7b4565eda961d 100644 (file)
@@ -4,7 +4,7 @@
  * (C) 2001 by Jay Schulist <jschlst@samba.org>
  * (C) 2002-2006 by Harald Welte <laforge@gnumonks.org>
  * (C) 2003 by Patrick Mchardy <kaber@trash.net>
- * (C) 2005-2007 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2005-2008 by Pablo Neira Ayuso <pablo@netfilter.org>
  *
  * Initial connection tracking via netlink development funded and
  * generally made possible by Network Robots, Inc. (www.networkrobots.com)
@@ -475,14 +475,14 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
        if (ctnetlink_dump_id(skb, ct) < 0)
                goto nla_put_failure;
 
+       if (ctnetlink_dump_status(skb, ct) < 0)
+               goto nla_put_failure;
+
        if (events & IPCT_DESTROY) {
                if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
                    ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)
                        goto nla_put_failure;
        } else {
-               if (ctnetlink_dump_status(skb, ct) < 0)
-                       goto nla_put_failure;
-
                if (ctnetlink_dump_timeout(skb, ct) < 0)
                        goto nla_put_failure;
 
@@ -812,9 +812,8 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
                        return -ENOENT;
                }
        }
-       if (del_timer(&ct->timeout))
-               ct->timeout.function((unsigned long)ct);
 
+       nf_ct_kill(ct);
        nf_ct_put(ct);
 
        return 0;
@@ -891,20 +890,19 @@ ctnetlink_change_status(struct nf_conn *ct, struct nlattr *cda[])
 
        if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING))
                /* unchangeable */
-               return -EINVAL;
+               return -EBUSY;
 
        if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY))
                /* SEEN_REPLY bit can only be set */
-               return -EINVAL;
-
+               return -EBUSY;
 
        if (d & IPS_ASSURED && !(status & IPS_ASSURED))
                /* ASSURED bit can only be set */
-               return -EINVAL;
+               return -EBUSY;
 
        if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
 #ifndef CONFIG_NF_NAT_NEEDED
-               return -EINVAL;
+               return -EOPNOTSUPP;
 #else
                struct nf_nat_range range;
 
@@ -945,7 +943,7 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *cda[])
 
        /* don't change helper of sibling connections */
        if (ct->master)
-               return -EINVAL;
+               return -EBUSY;
 
        err = ctnetlink_parse_help(cda[CTA_HELP], &helpname);
        if (err < 0)
@@ -963,7 +961,7 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *cda[])
 
        helper = __nf_conntrack_helper_find_byname(helpname);
        if (helper == NULL)
-               return -EINVAL;
+               return -EOPNOTSUPP;
 
        if (help) {
                if (help->helper == helper)
@@ -1258,12 +1256,12 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
        if (!(nlh->nlmsg_flags & NLM_F_EXCL)) {
                /* we only allow nat config for new conntracks */
                if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
-                       err = -EINVAL;
+                       err = -EOPNOTSUPP;
                        goto out_unlock;
                }
                /* can't link an existing conntrack to a master */
                if (cda[CTA_TUPLE_MASTER]) {
-                       err = -EINVAL;
+                       err = -EOPNOTSUPP;
                        goto out_unlock;
                }
                err = ctnetlink_change_conntrack(nf_ct_tuplehash_to_ctrack(h),
@@ -1608,7 +1606,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
                h = __nf_conntrack_helper_find_byname(name);
                if (!h) {
                        spin_unlock_bh(&nf_conntrack_lock);
-                       return -EINVAL;
+                       return -EOPNOTSUPP;
                }
                for (i = 0; i < nf_ct_expect_hsize; i++) {
                        hlist_for_each_entry_safe(exp, n, next,
index afb4a1861d2c3708f6ae606de3095a75e0fc76c3..e7866dd3cde6cb2238f58cb9819cb3f414aa0e0f 100644 (file)
@@ -475,8 +475,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
        if (type == DCCP_PKT_RESET &&
            !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
                /* Tear down connection immediately if only reply is a RESET */
-               if (del_timer(&ct->timeout))
-                       ct->timeout.function((unsigned long)ct);
+               nf_ct_kill_acct(ct, ctinfo, skb);
                return NF_ACCEPT;
        }
 
index cbf2e27a22b298c0d3d818b3b1e85f398b259984..41183a4d2d621f41ac4662bfc411feebdd673e80 100644 (file)
@@ -463,6 +463,82 @@ static bool sctp_new(struct nf_conn *ct, const struct sk_buff *skb,
        return true;
 }
 
+#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
+
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_conntrack.h>
+
+static int sctp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
+                         const struct nf_conn *ct)
+{
+       struct nlattr *nest_parms;
+
+       read_lock_bh(&sctp_lock);
+       nest_parms = nla_nest_start(skb, CTA_PROTOINFO_SCTP | NLA_F_NESTED);
+       if (!nest_parms)
+               goto nla_put_failure;
+
+       NLA_PUT_U8(skb, CTA_PROTOINFO_SCTP_STATE, ct->proto.sctp.state);
+
+       NLA_PUT_BE32(skb,
+                    CTA_PROTOINFO_SCTP_VTAG_ORIGINAL,
+                    htonl(ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL]));
+
+       NLA_PUT_BE32(skb,
+                    CTA_PROTOINFO_SCTP_VTAG_REPLY,
+                    htonl(ct->proto.sctp.vtag[IP_CT_DIR_REPLY]));
+
+       read_unlock_bh(&sctp_lock);
+
+       nla_nest_end(skb, nest_parms);
+
+       return 0;
+
+nla_put_failure:
+       read_unlock_bh(&sctp_lock);
+       return -1;
+}
+
+static const struct nla_policy sctp_nla_policy[CTA_PROTOINFO_SCTP_MAX+1] = {
+       [CTA_PROTOINFO_SCTP_STATE]          = { .type = NLA_U8 },
+       [CTA_PROTOINFO_SCTP_VTAG_ORIGINAL]  = { .type = NLA_U32 },
+       [CTA_PROTOINFO_SCTP_VTAG_REPLY]     = { .type = NLA_U32 },
+};
+
+static int nlattr_to_sctp(struct nlattr *cda[], struct nf_conn *ct)
+{
+       struct nlattr *attr = cda[CTA_PROTOINFO_SCTP];
+       struct nlattr *tb[CTA_PROTOINFO_SCTP_MAX+1];
+       int err;
+
+       /* updates may not contain the internal protocol info, skip parsing */
+       if (!attr)
+               return 0;
+
+       err = nla_parse_nested(tb,
+                              CTA_PROTOINFO_SCTP_MAX,
+                              attr,
+                              sctp_nla_policy);
+       if (err < 0)
+               return err;
+
+       if (!tb[CTA_PROTOINFO_SCTP_STATE] ||
+           !tb[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL] ||
+           !tb[CTA_PROTOINFO_SCTP_VTAG_REPLY])
+               return -EINVAL;
+
+       write_lock_bh(&sctp_lock);
+       ct->proto.sctp.state = nla_get_u8(tb[CTA_PROTOINFO_SCTP_STATE]);
+       ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL] =
+               ntohl(nla_get_be32(tb[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL]));
+       ct->proto.sctp.vtag[IP_CT_DIR_REPLY] =
+               ntohl(nla_get_be32(tb[CTA_PROTOINFO_SCTP_VTAG_REPLY]));
+       write_unlock_bh(&sctp_lock);
+
+       return 0;
+}
+#endif
+
 #ifdef CONFIG_SYSCTL
 static unsigned int sctp_sysctl_table_users;
 static struct ctl_table_header *sctp_sysctl_header;
@@ -591,6 +667,8 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = {
        .new                    = sctp_new,
        .me                     = THIS_MODULE,
 #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
+       .to_nlattr              = sctp_to_nlattr,
+       .from_nlattr            = nlattr_to_sctp,
        .tuple_to_nlattr        = nf_ct_port_tuple_to_nlattr,
        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
        .nla_policy             = nf_ct_port_nla_policy,
@@ -617,6 +695,8 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = {
        .new                    = sctp_new,
        .me                     = THIS_MODULE,
 #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
+       .to_nlattr              = sctp_to_nlattr,
+       .from_nlattr            = nlattr_to_sctp,
        .tuple_to_nlattr        = nf_ct_port_tuple_to_nlattr,
        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
        .nla_policy             = nf_ct_port_nla_policy,
index ba94004fe323182b6a527507548a1e54e1099321..8db13fba10bc823b02c1065634b8894a0789b349 100644 (file)
@@ -843,8 +843,7 @@ static int tcp_packet(struct nf_conn *ct,
                        /* Attempt to reopen a closed/aborted connection.
                         * Delete this connection and look up again. */
                        write_unlock_bh(&tcp_lock);
-                       if (del_timer(&ct->timeout))
-                               ct->timeout.function((unsigned long)ct);
+                       nf_ct_kill(ct);
                        return -NF_REPEAT;
                }
                /* Fall through */
@@ -877,8 +876,7 @@ static int tcp_packet(struct nf_conn *ct,
                        if (LOG_INVALID(IPPROTO_TCP))
                                nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
                                          "nf_ct_tcp: killing out of sync session ");
-                       if (del_timer(&ct->timeout))
-                               ct->timeout.function((unsigned long)ct);
+                       nf_ct_kill(ct);
                        return -NF_DROP;
                }
                ct->proto.tcp.last_index = index;
@@ -961,8 +959,7 @@ static int tcp_packet(struct nf_conn *ct,
                   problem case, so we can delete the conntrack
                   immediately.  --RR */
                if (th->rst) {
-                       if (del_timer(&ct->timeout))
-                               ct->timeout.function((unsigned long)ct);
+                       nf_ct_kill_acct(ct, ctinfo, skb);
                        return NF_ACCEPT;
                }
        } else if (!test_bit(IPS_ASSURED_BIT, &ct->status)
index 3447025ce068e9216fe5b235bd4f3213573673be..04e9c965f8caaa0b06f4e3f336adabd09d5f9a4a 100644 (file)
@@ -243,7 +243,6 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
        switch ((enum nfqnl_config_mode)queue->copy_mode) {
        case NFQNL_COPY_META:
        case NFQNL_COPY_NONE:
-               data_len = 0;
                break;
 
        case NFQNL_COPY_PACKET:
index 211189eb2b679a2f4b815fbb15a3999a883128f9..76ca1f2421eb875472eb27ee2a26dd71892a0e95 100644 (file)
@@ -8,7 +8,7 @@
  *   Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
  *    by Henrik Nordstrom <hno@marasystems.com>
  *
- * (C) 2006 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ * (C) 2006,2008 Red Hat, Inc., James Morris <jmorris@redhat.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -94,6 +94,12 @@ connsecmark_tg_check(const char *tablename, const void *entry,
 {
        const struct xt_connsecmark_target_info *info = targinfo;
 
+       if (strcmp(tablename, "mangle") && strcmp(tablename, "security")) {
+               printk(KERN_INFO PFX "target only valid in the \'mangle\' "
+                      "or \'security\' tables, not \'%s\'.\n", tablename);
+               return false;
+       }
+
        switch (info->mode) {
        case CONNSECMARK_SAVE:
        case CONNSECMARK_RESTORE:
@@ -126,7 +132,6 @@ static struct xt_target connsecmark_tg_reg[] __read_mostly = {
                .destroy        = connsecmark_tg_destroy,
                .target         = connsecmark_tg,
                .targetsize     = sizeof(struct xt_connsecmark_target_info),
-               .table          = "mangle",
                .me             = THIS_MODULE,
        },
        {
@@ -136,7 +141,6 @@ static struct xt_target connsecmark_tg_reg[] __read_mostly = {
                .destroy        = connsecmark_tg_destroy,
                .target         = connsecmark_tg,
                .targetsize     = sizeof(struct xt_connsecmark_target_info),
-               .table          = "mangle",
                .me             = THIS_MODULE,
        },
 };
index c0284856ccd490bf32c23b7fafd01f04ff793d08..94f87ee7552b0708b855ce998a3a355e71b13af4 100644 (file)
@@ -5,7 +5,7 @@
  * Based on the nfmark match by:
  * (C) 1999-2001 Marc Boucher <marc@mbsi.ca>
  *
- * (C) 2006 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ * (C) 2006,2008 Red Hat, Inc., James Morris <jmorris@redhat.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -89,6 +89,12 @@ secmark_tg_check(const char *tablename, const void *entry,
 {
        struct xt_secmark_target_info *info = targinfo;
 
+       if (strcmp(tablename, "mangle") && strcmp(tablename, "security")) {
+               printk(KERN_INFO PFX "target only valid in the \'mangle\' "
+                      "or \'security\' tables, not \'%s\'.\n", tablename);
+               return false;
+       }
+
        if (mode && mode != info->mode) {
                printk(KERN_INFO PFX "mode already set to %hu cannot mix with "
                       "rules for mode %hu\n", mode, info->mode);
@@ -127,7 +133,6 @@ static struct xt_target secmark_tg_reg[] __read_mostly = {
                .destroy        = secmark_tg_destroy,
                .target         = secmark_tg,
                .targetsize     = sizeof(struct xt_secmark_target_info),
-               .table          = "mangle",
                .me             = THIS_MODULE,
        },
        {
@@ -137,7 +142,6 @@ static struct xt_target secmark_tg_reg[] __read_mostly = {
                .destroy        = secmark_tg_destroy,
                .target         = secmark_tg,
                .targetsize     = sizeof(struct xt_secmark_target_info),
-               .table          = "mangle",
                .me             = THIS_MODULE,
        },
 };
index 9b97f8006c9c6edfd0dea0dde522b6a7e64c171f..6507c02dbe0d49184aa3009764f138fad92c6dfc 100644 (file)
@@ -759,7 +759,7 @@ struct sock *netlink_getsockbyfilp(struct file *filp)
  * 0: continue
  * 1: repeat lookup - reference dropped while waiting for socket memory.
  */
-int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock,
+int netlink_attachskb(struct sock *sk, struct sk_buff *skb,
                      long *timeo, struct sock *ssk)
 {
        struct netlink_sock *nlk;
@@ -892,7 +892,7 @@ retry:
                return err;
        }
 
-       err = netlink_attachskb(sk, skb, nonblock, &timeo, ssk);
+       err = netlink_attachskb(sk, skb, &timeo, ssk);
        if (err == 1)
                goto retry;
        if (err)
index 532634861db15907ac417a7be79706615e825c6d..d5cc731b6798aab16fa80a0a83a72932f37941fa 100644 (file)
@@ -136,6 +136,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
 
        /* Set association default SACK delay */
        asoc->sackdelay = msecs_to_jiffies(sp->sackdelay);
+       asoc->sackfreq = sp->sackfreq;
 
        /* Set the association default flags controlling
         * Heartbeat, SACK delay, and Path MTU Discovery.
@@ -261,6 +262,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
         * already received one packet.]
         */
        asoc->peer.sack_needed = 1;
+       asoc->peer.sack_cnt = 0;
 
        /* Assume that the peer will tell us if he recognizes ASCONF
         * as part of INIT exchange.
@@ -615,6 +617,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
         * association configured value.
         */
        peer->sackdelay = asoc->sackdelay;
+       peer->sackfreq = asoc->sackfreq;
 
        /* Enable/disable heartbeat, SACK delay, and path MTU discovery
         * based on association setting.
index 0aba759cb9b7b269bd2bb263538e093e6a19a3a0..5dd89831eceba6ca38e3b187ac465c2cbf387dc6 100644 (file)
@@ -383,3 +383,144 @@ void sctp_assocs_proc_exit(void)
 {
        remove_proc_entry("assocs", proc_net_sctp);
 }
+
+static void *sctp_remaddr_seq_start(struct seq_file *seq, loff_t *pos)
+{
+       if (*pos >= sctp_assoc_hashsize)
+               return NULL;
+
+       if (*pos < 0)
+               *pos = 0;
+
+       if (*pos == 0)
+               seq_printf(seq, "ADDR ASSOC_ID HB_ACT RTO MAX_PATH_RTX "
+                               "REM_ADDR_RTX  START\n");
+
+       return (void *)pos;
+}
+
+static void *sctp_remaddr_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       if (++*pos >= sctp_assoc_hashsize)
+               return NULL;
+
+       return pos;
+}
+
+static void sctp_remaddr_seq_stop(struct seq_file *seq, void *v)
+{
+       return;
+}
+
+static int sctp_remaddr_seq_show(struct seq_file *seq, void *v)
+{
+       struct sctp_hashbucket *head;
+       struct sctp_ep_common *epb;
+       struct sctp_association *assoc;
+       struct hlist_node *node;
+       struct sctp_transport *tsp;
+       int    hash = *(loff_t *)v;
+
+       if (hash >= sctp_assoc_hashsize)
+               return -ENOMEM;
+
+       head = &sctp_assoc_hashtable[hash];
+       sctp_local_bh_disable();
+       read_lock(&head->lock);
+       sctp_for_each_hentry(epb, node, &head->chain) {
+               assoc = sctp_assoc(epb);
+               list_for_each_entry(tsp, &assoc->peer.transport_addr_list,
+                                       transports) {
+                       /*
+                        * The remote address (ADDR)
+                        */
+                       tsp->af_specific->seq_dump_addr(seq, &tsp->ipaddr);
+                       seq_printf(seq, " ");
+
+                       /*
+                        * The association ID (ASSOC_ID)
+                        */
+                       seq_printf(seq, "%d ", tsp->asoc->assoc_id);
+
+                       /*
+                        * If the Heartbeat is active (HB_ACT)
+                        * Note: 1 = Active, 0 = Inactive
+                        */
+                       seq_printf(seq, "%d ", timer_pending(&tsp->hb_timer));
+
+                       /*
+                        * Retransmit time out (RTO)
+                        */
+                       seq_printf(seq, "%lu ", tsp->rto);
+
+                       /*
+                        * Maximum path retransmit count (PATH_MAX_RTX)
+                        */
+                       seq_printf(seq, "%d ", tsp->pathmaxrxt);
+
+                       /*
+                        * remote address retransmit count (REM_ADDR_RTX)
+                        * Note: We don't have a way to tally this at the moment
+                        * so lets just leave it as zero for the moment
+                        */
+                       seq_printf(seq, "0 ");
+
+                       /*
+                        * remote address start time (START).  This is also not
+                        * currently implemented, but we can record it with a
+                        * jiffies marker in a subsequent patch
+                        */
+                       seq_printf(seq, "0");
+
+                       seq_printf(seq, "\n");
+               }
+       }
+
+       read_unlock(&head->lock);
+       sctp_local_bh_enable();
+
+       return 0;
+
+}
+
+static const struct seq_operations sctp_remaddr_ops = {
+       .start = sctp_remaddr_seq_start,
+       .next  = sctp_remaddr_seq_next,
+       .stop  = sctp_remaddr_seq_stop,
+       .show  = sctp_remaddr_seq_show,
+};
+
+/* Cleanup the proc fs entry for 'remaddr' object. */
+void sctp_remaddr_proc_exit(void)
+{
+       remove_proc_entry("remaddr", proc_net_sctp);
+}
+
+static int sctp_remaddr_seq_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &sctp_remaddr_ops);
+}
+
+static const struct file_operations sctp_remaddr_seq_fops = {
+       .open = sctp_remaddr_seq_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+int __init sctp_remaddr_proc_init(void)
+{
+       struct proc_dir_entry *p;
+
+       p = create_proc_entry("remaddr", S_IRUGO, proc_net_sctp);
+       if (!p)
+               return -ENOMEM;
+       p->proc_fops = &sctp_remaddr_seq_fops;
+
+       return 0;
+}
+
+void sctp_assoc_proc_exit(void)
+{
+       remove_proc_entry("remaddr", proc_net_sctp);
+}
index b435a193c5df916cd8d4ff7d0412167d17f5c99d..d6af466091d2ade2e79132979ce839247c39443e 100644 (file)
@@ -113,6 +113,8 @@ static __init int sctp_proc_init(void)
                goto out_nomem;
        if (sctp_assocs_proc_init())
                goto out_nomem;
+       if (sctp_remaddr_proc_init())
+               goto out_nomem;
 
        return 0;
 
@@ -129,6 +131,7 @@ static void sctp_proc_exit(void)
        sctp_snmp_proc_exit();
        sctp_eps_proc_exit();
        sctp_assocs_proc_exit();
+       sctp_remaddr_proc_exit();
 
        if (proc_net_sctp) {
                proc_net_sctp = NULL;
index 23a9f1a95b7d1f0f6b87c4b495880a954aa5502f..b083312c725aa03294771a5858a4840c806ef924 100644 (file)
@@ -190,20 +190,28 @@ static int sctp_gen_sack(struct sctp_association *asoc, int force,
         * unacknowledged DATA chunk. ...
         */
        if (!asoc->peer.sack_needed) {
-               /* We will need a SACK for the next packet.  */
-               asoc->peer.sack_needed = 1;
+               asoc->peer.sack_cnt++;
 
                /* Set the SACK delay timeout based on the
                 * SACK delay for the last transport
                 * data was received from, or the default
                 * for the association.
                 */
-               if (trans)
+               if (trans) {
+                       /* We will need a SACK for the next packet.  */
+                       if (asoc->peer.sack_cnt >= trans->sackfreq - 1)
+                               asoc->peer.sack_needed = 1;
+
                        asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] =
                                trans->sackdelay;
-               else
+               } else {
+                       /* We will need a SACK for the next packet.  */
+                       if (asoc->peer.sack_cnt >= asoc->sackfreq - 1)
+                               asoc->peer.sack_needed = 1;
+
                        asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] =
                                asoc->sackdelay;
+               }
 
                /* Restart the SACK timer. */
                sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
@@ -216,6 +224,7 @@ static int sctp_gen_sack(struct sctp_association *asoc, int force,
                        goto nomem;
 
                asoc->peer.sack_needed = 0;
+               asoc->peer.sack_cnt = 0;
 
                sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(sack));
 
index e7e3baf7009ed7d8bca62e4353eebd62b70be7ba..253e5ea7e1e8b7d04744e4bdb6b552d7536e87db 100644 (file)
@@ -956,7 +956,8 @@ out:
  */
 static int __sctp_connect(struct sock* sk,
                          struct sockaddr *kaddrs,
-                         int addrs_size)
+                         int addrs_size,
+                         sctp_assoc_t *assoc_id)
 {
        struct sctp_sock *sp;
        struct sctp_endpoint *ep;
@@ -1111,6 +1112,8 @@ 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)
+               *assoc_id = asoc->assoc_id;
 
        /* Don't free association on exit. */
        asoc = NULL;
@@ -1128,7 +1131,8 @@ out_free:
 /* Helper for tunneling sctp_connectx() requests through sctp_setsockopt()
  *
  * API 8.9
- * int sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt);
+ * int sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt,
+ *                     sctp_assoc_t *asoc);
  *
  * If sd is an IPv4 socket, the addresses passed must be IPv4 addresses.
  * If the sd is an IPv6 socket, the addresses passed can either be IPv4
@@ -1144,8 +1148,10 @@ out_free:
  * representation is termed a "packed array" of addresses). The caller
  * specifies the number of addresses in the array with addrcnt.
  *
- * On success, sctp_connectx() returns 0. On failure, sctp_connectx() returns
- * -1, and sets errno to the appropriate error code.
+ * On success, sctp_connectx() returns 0. It also sets the assoc_id to
+ * the association id of the new association.  On failure, sctp_connectx()
+ * returns -1, and sets errno to the appropriate error code.  The assoc_id
+ * is not touched by the kernel.
  *
  * For SCTP, the port given in each socket address must be the same, or
  * sctp_connectx() will fail, setting errno to EINVAL.
@@ -1182,11 +1188,12 @@ out_free:
  * addrs     The pointer to the addresses in user land
  * addrssize Size of the addrs buffer
  *
- * Returns 0 if ok, <0 errno code on error.
+ * Returns >=0 if ok, <0 errno code on error.
  */
-SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk,
+SCTP_STATIC int __sctp_setsockopt_connectx(struct sock* sk,
                                      struct sockaddr __user *addrs,
-                                     int addrs_size)
+                                     int addrs_size,
+                                     sctp_assoc_t *assoc_id)
 {
        int err = 0;
        struct sockaddr *kaddrs;
@@ -1209,13 +1216,46 @@ SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk,
        if (__copy_from_user(kaddrs, addrs, addrs_size)) {
                err = -EFAULT;
        } else {
-               err = __sctp_connect(sk, kaddrs, addrs_size);
+               err = __sctp_connect(sk, kaddrs, addrs_size, assoc_id);
        }
 
        kfree(kaddrs);
+
        return err;
 }
 
+/*
+ * This is an older interface.  It's kept for backward compatibility
+ * to the option that doesn't provide association id.
+ */
+SCTP_STATIC int sctp_setsockopt_connectx_old(struct sock* sk,
+                                     struct sockaddr __user *addrs,
+                                     int addrs_size)
+{
+       return __sctp_setsockopt_connectx(sk, addrs, addrs_size, NULL);
+}
+
+/*
+ * New interface for the API.  The since the API is done with a socket
+ * option, to make it simple we feed back the association id is as a return
+ * indication to the call.  Error is always negative and association id is
+ * always positive.
+ */
+SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk,
+                                     struct sockaddr __user *addrs,
+                                     int addrs_size)
+{
+       sctp_assoc_t assoc_id = 0;
+       int err = 0;
+
+       err = __sctp_setsockopt_connectx(sk, addrs, addrs_size, &assoc_id);
+
+       if (err)
+               return err;
+       else
+               return assoc_id;
+}
+
 /* 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
@@ -2305,74 +2345,98 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
        return 0;
 }
 
-/* 7.1.23. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME)
- *
- *   This options will get or set the delayed ack timer.  The time is set
- *   in milliseconds.  If the assoc_id is 0, then this sets or gets the
- *   endpoints default delayed ack timer value.  If the assoc_id field is
- *   non-zero, then the set or get effects the specified association.
- *
- *   struct sctp_assoc_value {
- *       sctp_assoc_t            assoc_id;
- *       uint32_t                assoc_value;
- *   };
+/*
+ * 7.1.23.  Get or set delayed ack timer (SCTP_DELAYED_SACK)
+ *
+ * This option will effect the way delayed acks are performed.  This
+ * option allows you to get or set the delayed ack time, in
+ * milliseconds.  It also allows changing the delayed ack frequency.
+ * Changing the frequency to 1 disables the delayed sack algorithm.  If
+ * the assoc_id is 0, then this sets or gets the endpoints default
+ * values.  If the assoc_id field is non-zero, then the set or get
+ * effects the specified association for the one to many model (the
+ * assoc_id field is ignored by the one to one model).  Note that if
+ * sack_delay or sack_freq are 0 when setting this option, then the
+ * current values will remain unchanged.
+ *
+ * struct sctp_sack_info {
+ *     sctp_assoc_t            sack_assoc_id;
+ *     uint32_t                sack_delay;
+ *     uint32_t                sack_freq;
+ * };
  *
- *     assoc_id    - This parameter, indicates which association the
- *                   user is preforming an action upon. Note that if
- *                   this field's value is zero then the endpoints
- *                   default value is changed (effecting future
- *                   associations only).
+ * sack_assoc_id -  This parameter, indicates which association the user
+ *    is performing an action upon.  Note that if this field's value is
+ *    zero then the endpoints default value is changed (effecting future
+ *    associations only).
  *
- *     assoc_value - This parameter contains the number of milliseconds
- *                   that the user is requesting the delayed ACK timer
- *                   be set to. Note that this value is defined in
- *                   the standard to be between 200 and 500 milliseconds.
+ * sack_delay -  This parameter contains the number of milliseconds that
+ *    the user is requesting the delayed ACK timer be set to.  Note that
+ *    this value is defined in the standard to be between 200 and 500
+ *    milliseconds.
  *
- *                   Note: a value of zero will leave the value alone,
- *                   but disable SACK delay. A non-zero value will also
- *                   enable SACK delay.
+ * sack_freq -  This parameter contains the number of packets that must
+ *    be received before a sack is sent without waiting for the delay
+ *    timer to expire.  The default value for this is 2, setting this
+ *    value to 1 will disable the delayed sack algorithm.
  */
 
-static int sctp_setsockopt_delayed_ack_time(struct sock *sk,
+static int sctp_setsockopt_delayed_ack(struct sock *sk,
                                            char __user *optval, int optlen)
 {
-       struct sctp_assoc_value  params;
+       struct sctp_sack_info    params;
        struct sctp_transport   *trans = NULL;
        struct sctp_association *asoc = NULL;
        struct sctp_sock        *sp = sctp_sk(sk);
 
-       if (optlen != sizeof(struct sctp_assoc_value))
-               return - EINVAL;
+       if (optlen == sizeof(struct sctp_sack_info)) {
+               if (copy_from_user(&params, optval, optlen))
+                       return -EFAULT;
 
-       if (copy_from_user(&params, optval, optlen))
-               return -EFAULT;
+               if (params.sack_delay == 0 && params.sack_freq == 0)
+                       return 0;
+       } else if (optlen == sizeof(struct sctp_assoc_value)) {
+               printk(KERN_WARNING "SCTP: Use of struct sctp_sack_info "
+                      "in delayed_ack socket option deprecated\n");
+               printk(KERN_WARNING "SCTP: struct sctp_sack_info instead\n");
+               if (copy_from_user(&params, optval, optlen))
+                       return -EFAULT;
+
+               if (params.sack_delay == 0)
+                       params.sack_freq = 1;
+               else
+                       params.sack_freq = 0;
+       } else
+               return - EINVAL;
 
        /* Validate value parameter. */
-       if (params.assoc_value > 500)
+       if (params.sack_delay > 500)
                return -EINVAL;
 
-       /* Get association, if assoc_id != 0 and the socket is a one
+       /* Get association, if sack_assoc_id != 0 and the socket is a one
         * to many style socket, and an association was not found, then
         * the id was invalid.
         */
-       asoc = sctp_id2assoc(sk, params.assoc_id);
-       if (!asoc && params.assoc_id && sctp_style(sk, UDP))
+       asoc = sctp_id2assoc(sk, params.sack_assoc_id);
+       if (!asoc && params.sack_assoc_id && sctp_style(sk, UDP))
                return -EINVAL;
 
-       if (params.assoc_value) {
+       if (params.sack_delay) {
                if (asoc) {
                        asoc->sackdelay =
-                               msecs_to_jiffies(params.assoc_value);
+                               msecs_to_jiffies(params.sack_delay);
                        asoc->param_flags =
                                (asoc->param_flags & ~SPP_SACKDELAY) |
                                SPP_SACKDELAY_ENABLE;
                } else {
-                       sp->sackdelay = params.assoc_value;
+                       sp->sackdelay = params.sack_delay;
                        sp->param_flags =
                                (sp->param_flags & ~SPP_SACKDELAY) |
                                SPP_SACKDELAY_ENABLE;
                }
-       } else {
+       }
+
+       if (params.sack_freq == 1) {
                if (asoc) {
                        asoc->param_flags =
                                (asoc->param_flags & ~SPP_SACKDELAY) |
@@ -2382,22 +2446,40 @@ static int sctp_setsockopt_delayed_ack_time(struct sock *sk,
                                (sp->param_flags & ~SPP_SACKDELAY) |
                                SPP_SACKDELAY_DISABLE;
                }
+       } else if (params.sack_freq > 1) {
+               if (asoc) {
+                       asoc->sackfreq = params.sack_freq;
+                       asoc->param_flags =
+                               (asoc->param_flags & ~SPP_SACKDELAY) |
+                               SPP_SACKDELAY_ENABLE;
+               } else {
+                       sp->sackfreq = params.sack_freq;
+                       sp->param_flags =
+                               (sp->param_flags & ~SPP_SACKDELAY) |
+                               SPP_SACKDELAY_ENABLE;
+               }
        }
 
        /* If change is for association, also apply to each transport. */
        if (asoc) {
                list_for_each_entry(trans, &asoc->peer.transport_addr_list,
                                transports) {
-                       if (params.assoc_value) {
+                       if (params.sack_delay) {
                                trans->sackdelay =
-                                       msecs_to_jiffies(params.assoc_value);
+                                       msecs_to_jiffies(params.sack_delay);
                                trans->param_flags =
                                        (trans->param_flags & ~SPP_SACKDELAY) |
                                        SPP_SACKDELAY_ENABLE;
-                       } else {
+                       }
+                       if (params.sack_freq == 1) {
                                trans->param_flags =
                                        (trans->param_flags & ~SPP_SACKDELAY) |
                                        SPP_SACKDELAY_DISABLE;
+                       } else if (params.sack_freq > 1) {
+                               trans->sackfreq = params.sack_freq;
+                               trans->param_flags =
+                                       (trans->param_flags & ~SPP_SACKDELAY) |
+                                       SPP_SACKDELAY_ENABLE;
                        }
                }
        }
@@ -3164,10 +3246,18 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
                                               optlen, SCTP_BINDX_REM_ADDR);
                break;
 
+       case SCTP_SOCKOPT_CONNECTX_OLD:
+               /* 'optlen' is the size of the addresses buffer. */
+               retval = sctp_setsockopt_connectx_old(sk,
+                                           (struct sockaddr __user *)optval,
+                                           optlen);
+               break;
+
        case SCTP_SOCKOPT_CONNECTX:
                /* 'optlen' is the size of the addresses buffer. */
-               retval = sctp_setsockopt_connectx(sk, (struct sockaddr __user *)optval,
-                                              optlen);
+               retval = sctp_setsockopt_connectx(sk,
+                                           (struct sockaddr __user *)optval,
+                                           optlen);
                break;
 
        case SCTP_DISABLE_FRAGMENTS:
@@ -3186,8 +3276,8 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
                retval = sctp_setsockopt_peer_addr_params(sk, optval, optlen);
                break;
 
-       case SCTP_DELAYED_ACK_TIME:
-               retval = sctp_setsockopt_delayed_ack_time(sk, optval, optlen);
+       case SCTP_DELAYED_ACK:
+               retval = sctp_setsockopt_delayed_ack(sk, optval, optlen);
                break;
        case SCTP_PARTIAL_DELIVERY_POINT:
                retval = sctp_setsockopt_partial_delivery_point(sk, optval, optlen);
@@ -3294,7 +3384,7 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *addr,
                /* Pass correct addr len to common routine (so it knows there
                 * is only one address being passed.
                 */
-               err = __sctp_connect(sk, addr, af->sockaddr_len);
+               err = __sctp_connect(sk, addr, af->sockaddr_len, NULL);
        }
 
        sctp_release_sock(sk);
@@ -3446,6 +3536,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
        sp->pathmaxrxt  = sctp_max_retrans_path;
        sp->pathmtu     = 0; // allow default discovery
        sp->sackdelay   = sctp_sack_timeout;
+       sp->sackfreq    = 2;
        sp->param_flags = SPP_HB_ENABLE |
                          SPP_PMTUD_ENABLE |
                          SPP_SACKDELAY_ENABLE;
@@ -3999,70 +4090,91 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
        return 0;
 }
 
-/* 7.1.23. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME)
- *
- *   This options will get or set the delayed ack timer.  The time is set
- *   in milliseconds.  If the assoc_id is 0, then this sets or gets the
- *   endpoints default delayed ack timer value.  If the assoc_id field is
- *   non-zero, then the set or get effects the specified association.
- *
- *   struct sctp_assoc_value {
- *       sctp_assoc_t            assoc_id;
- *       uint32_t                assoc_value;
- *   };
+/*
+ * 7.1.23.  Get or set delayed ack timer (SCTP_DELAYED_SACK)
+ *
+ * This option will effect the way delayed acks are performed.  This
+ * option allows you to get or set the delayed ack time, in
+ * milliseconds.  It also allows changing the delayed ack frequency.
+ * Changing the frequency to 1 disables the delayed sack algorithm.  If
+ * the assoc_id is 0, then this sets or gets the endpoints default
+ * values.  If the assoc_id field is non-zero, then the set or get
+ * effects the specified association for the one to many model (the
+ * assoc_id field is ignored by the one to one model).  Note that if
+ * sack_delay or sack_freq are 0 when setting this option, then the
+ * current values will remain unchanged.
+ *
+ * struct sctp_sack_info {
+ *     sctp_assoc_t            sack_assoc_id;
+ *     uint32_t                sack_delay;
+ *     uint32_t                sack_freq;
+ * };
  *
- *     assoc_id    - This parameter, indicates which association the
- *                   user is preforming an action upon. Note that if
- *                   this field's value is zero then the endpoints
- *                   default value is changed (effecting future
- *                   associations only).
+ * sack_assoc_id -  This parameter, indicates which association the user
+ *    is performing an action upon.  Note that if this field's value is
+ *    zero then the endpoints default value is changed (effecting future
+ *    associations only).
  *
- *     assoc_value - This parameter contains the number of milliseconds
- *                   that the user is requesting the delayed ACK timer
- *                   be set to. Note that this value is defined in
- *                   the standard to be between 200 and 500 milliseconds.
+ * sack_delay -  This parameter contains the number of milliseconds that
+ *    the user is requesting the delayed ACK timer be set to.  Note that
+ *    this value is defined in the standard to be between 200 and 500
+ *    milliseconds.
  *
- *                   Note: a value of zero will leave the value alone,
- *                   but disable SACK delay. A non-zero value will also
- *                   enable SACK delay.
+ * sack_freq -  This parameter contains the number of packets that must
+ *    be received before a sack is sent without waiting for the delay
+ *    timer to expire.  The default value for this is 2, setting this
+ *    value to 1 will disable the delayed sack algorithm.
  */
-static int sctp_getsockopt_delayed_ack_time(struct sock *sk, int len,
+static int sctp_getsockopt_delayed_ack(struct sock *sk, int len,
                                            char __user *optval,
                                            int __user *optlen)
 {
-       struct sctp_assoc_value  params;
+       struct sctp_sack_info    params;
        struct sctp_association *asoc = NULL;
        struct sctp_sock        *sp = sctp_sk(sk);
 
-       if (len < sizeof(struct sctp_assoc_value))
-               return - EINVAL;
-
-       len = sizeof(struct sctp_assoc_value);
+       if (len >= sizeof(struct sctp_sack_info)) {
+               len = sizeof(struct sctp_sack_info);
 
-       if (copy_from_user(&params, optval, len))
-               return -EFAULT;
+               if (copy_from_user(&params, optval, len))
+                       return -EFAULT;
+       } else if (len == sizeof(struct sctp_assoc_value)) {
+               printk(KERN_WARNING "SCTP: Use of struct sctp_sack_info "
+                      "in delayed_ack socket option deprecated\n");
+               printk(KERN_WARNING "SCTP: struct sctp_sack_info instead\n");
+               if (copy_from_user(&params, optval, len))
+                       return -EFAULT;
+       } else
+               return - EINVAL;
 
-       /* Get association, if assoc_id != 0 and the socket is a one
+       /* Get association, if sack_assoc_id != 0 and the socket is a one
         * to many style socket, and an association was not found, then
         * the id was invalid.
         */
-       asoc = sctp_id2assoc(sk, params.assoc_id);
-       if (!asoc && params.assoc_id && sctp_style(sk, UDP))
+       asoc = sctp_id2assoc(sk, params.sack_assoc_id);
+       if (!asoc && params.sack_assoc_id && sctp_style(sk, UDP))
                return -EINVAL;
 
        if (asoc) {
                /* Fetch association values. */
-               if (asoc->param_flags & SPP_SACKDELAY_ENABLE)
-                       params.assoc_value = jiffies_to_msecs(
+               if (asoc->param_flags & SPP_SACKDELAY_ENABLE) {
+                       params.sack_delay = jiffies_to_msecs(
                                asoc->sackdelay);
-               else
-                       params.assoc_value = 0;
+                       params.sack_freq = asoc->sackfreq;
+
+               } else {
+                       params.sack_delay = 0;
+                       params.sack_freq = 1;
+               }
        } else {
                /* Fetch socket values. */
-               if (sp->param_flags & SPP_SACKDELAY_ENABLE)
-                       params.assoc_value  = sp->sackdelay;
-               else
-                       params.assoc_value  = 0;
+               if (sp->param_flags & SPP_SACKDELAY_ENABLE) {
+                       params.sack_delay  = sp->sackdelay;
+                       params.sack_freq = sp->sackfreq;
+               } else {
+                       params.sack_delay  = 0;
+                       params.sack_freq = 1;
+               }
        }
 
        if (copy_to_user(optval, &params, len))
@@ -5218,8 +5330,8 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
                retval = sctp_getsockopt_peer_addr_params(sk, len, optval,
                                                          optlen);
                break;
-       case SCTP_DELAYED_ACK_TIME:
-               retval = sctp_getsockopt_delayed_ack_time(sk, len, optval,
+       case SCTP_DELAYED_ACK:
+               retval = sctp_getsockopt_delayed_ack(sk, len, optval,
                                                          optlen);
                break;
        case SCTP_INITMSG:
index b4f0525f91af08c4982b9e575b63527344b1c803..d8e79162724c43de225d3e9ce6b239f2adf8992b 100644 (file)
@@ -40,6 +40,27 @@ static struct ctl_table_root net_sysctl_root = {
        .lookup = net_ctl_header_lookup,
 };
 
+static LIST_HEAD(net_sysctl_ro_tables);
+static struct list_head *net_ctl_ro_header_lookup(struct ctl_table_root *root,
+               struct nsproxy *namespaces)
+{
+       return &net_sysctl_ro_tables;
+}
+
+static int net_ctl_ro_header_perms(struct ctl_table_root *root,
+               struct nsproxy *namespaces, struct ctl_table *table)
+{
+       if (namespaces->net_ns == &init_net)
+               return table->mode;
+       else
+               return table->mode & ~0222;
+}
+
+static struct ctl_table_root net_sysctl_ro_root = {
+       .lookup = net_ctl_ro_header_lookup,
+       .permissions = net_ctl_ro_header_perms,
+};
+
 static int sysctl_net_init(struct net *net)
 {
        INIT_LIST_HEAD(&net->sysctl_table_headers);
@@ -64,6 +85,7 @@ static __init int sysctl_init(void)
        if (ret)
                goto out;
        register_sysctl_root(&net_sysctl_root);
+       register_sysctl_root(&net_sysctl_ro_root);
 out:
        return ret;
 }
@@ -80,6 +102,14 @@ struct ctl_table_header *register_net_sysctl_table(struct net *net,
 }
 EXPORT_SYMBOL_GPL(register_net_sysctl_table);
 
+struct ctl_table_header *register_net_sysctl_rotable(const
+               struct ctl_path *path, struct ctl_table *table)
+{
+       return __register_sysctl_paths(&net_sysctl_ro_root,
+                       &init_nsproxy, path, table);
+}
+EXPORT_SYMBOL_GPL(register_net_sysctl_rotable);
+
 void unregister_net_sysctl_table(struct ctl_table_header *header)
 {
        unregister_sysctl_table(header);
index e7880172ef19275db1e9f0e9c7d94fdc1e1a51e9..a5883b1452ff9ddf079025511b1efe8b113b6c01 100644 (file)
@@ -276,7 +276,7 @@ static void bclink_send_nack(struct node *n_ptr)
        if (buf) {
                msg = buf_msg(buf);
                msg_init(msg, BCAST_PROTOCOL, STATE_MSG,
-                        TIPC_OK, INT_H_SIZE, n_ptr->addr);
+                        INT_H_SIZE, n_ptr->addr);
                msg_set_mc_netid(msg, tipc_net_id);
                msg_set_bcast_ack(msg, mod(n_ptr->bclink.last_in));
                msg_set_bcgap_after(msg, n_ptr->bclink.gap_after);
@@ -571,7 +571,7 @@ static int tipc_bcbearer_send(struct sk_buff *buf,
                assert(tipc_cltr_bcast_nodes.count != 0);
                bcbuf_set_acks(buf, tipc_cltr_bcast_nodes.count);
                msg = buf_msg(buf);
-               msg_set_non_seq(msg);
+               msg_set_non_seq(msg, 1);
                msg_set_mc_netid(msg, tipc_net_id);
        }
 
index 4bb3404f610b4c7f96cb74666d894efc2e2aae57..bc1db474fe01dac590da649a25ad4b00028e3822 100644 (file)
@@ -238,7 +238,7 @@ static struct sk_buff *tipc_cltr_prepare_routing_msg(u32 data_size, u32 dest)
        if (buf) {
                msg = buf_msg(buf);
                memset((char *)msg, 0, size);
-               msg_init(msg, ROUTE_DISTRIBUTOR, 0, TIPC_OK, INT_H_SIZE, dest);
+               msg_init(msg, ROUTE_DISTRIBUTOR, 0, INT_H_SIZE, dest);
        }
        return buf;
 }
index c71337a22d337acb9a8df8c6b0b1321f331d6935..ca3544d030c7f9177fbe426e9f955c4655c157cc 100644 (file)
@@ -2,7 +2,7 @@
  * net/tipc/config.c: TIPC configuration management code
  *
  * Copyright (c) 2002-2006, Ericsson AB
- * Copyright (c) 2004-2006, Wind River Systems
+ * Copyright (c) 2004-2007, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -293,7 +293,6 @@ static struct sk_buff *cfg_set_own_addr(void)
        if (tipc_mode == TIPC_NET_MODE)
                return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
                                                   " (cannot change node address once assigned)");
-       tipc_own_addr = addr;
 
        /*
         * Must release all spinlocks before calling start_net() because
@@ -306,7 +305,7 @@ static struct sk_buff *cfg_set_own_addr(void)
         */
 
        spin_unlock_bh(&config_lock);
-       tipc_core_start_net();
+       tipc_core_start_net(addr);
        spin_lock_bh(&config_lock);
        return tipc_cfg_reply_none();
 }
@@ -529,7 +528,7 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
                break;
 #endif
        case TIPC_CMD_SET_LOG_SIZE:
-               rep_tlv_buf = tipc_log_resize(req_tlv_area, req_tlv_space);
+               rep_tlv_buf = tipc_log_resize_cmd(req_tlv_area, req_tlv_space);
                break;
        case TIPC_CMD_DUMP_LOG:
                rep_tlv_buf = tipc_log_dump();
@@ -602,6 +601,10 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
        case TIPC_CMD_GET_NETID:
                rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id);
                break;
+       case TIPC_CMD_NOT_NET_ADMIN:
+               rep_tlv_buf =
+                       tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN);
+               break;
        default:
                rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
                                                          " (unknown command)");
index 740aac5cdfb678ef348c2499fa3ec9fd9114b10e..3256bd7d398fb0850a4e2fdd5a294ad2d6405c40 100644 (file)
@@ -49,7 +49,7 @@
 #include "config.h"
 
 
-#define TIPC_MOD_VER "1.6.3"
+#define TIPC_MOD_VER "1.6.4"
 
 #ifndef CONFIG_TIPC_ZONES
 #define CONFIG_TIPC_ZONES 3
@@ -117,11 +117,11 @@ void tipc_core_stop_net(void)
  * start_net - start TIPC networking sub-systems
  */
 
-int tipc_core_start_net(void)
+int tipc_core_start_net(unsigned long addr)
 {
        int res;
 
-       if ((res = tipc_net_start()) ||
+       if ((res = tipc_net_start(addr)) ||
            (res = tipc_eth_media_start())) {
                tipc_core_stop_net();
        }
@@ -164,8 +164,7 @@ int tipc_core_start(void)
        tipc_mode = TIPC_NODE_MODE;
 
        if ((res = tipc_handler_start()) ||
-           (res = tipc_ref_table_init(tipc_max_ports + tipc_max_subscriptions,
-                                      tipc_random)) ||
+           (res = tipc_ref_table_init(tipc_max_ports, tipc_random)) ||
            (res = tipc_reg_start()) ||
            (res = tipc_nametbl_init()) ||
            (res = tipc_k_signal((Handler)tipc_subscr_start, 0)) ||
@@ -182,7 +181,7 @@ static int __init tipc_init(void)
 {
        int res;
 
-       tipc_log_reinit(CONFIG_TIPC_LOG);
+       tipc_log_resize(CONFIG_TIPC_LOG);
        info("Activated (version " TIPC_MOD_VER
             " compiled " __DATE__ " " __TIME__ ")\n");
 
@@ -209,7 +208,7 @@ static void __exit tipc_exit(void)
        tipc_core_stop_net();
        tipc_core_stop();
        info("Deactivated\n");
-       tipc_log_stop();
+       tipc_log_resize(0);
 }
 
 module_init(tipc_init);
index 5a0e4878d3b72b7c44cfd7b81cb88117b691029b..a881f92a8537c71531ca7eda1421c3766c7601db 100644 (file)
@@ -2,7 +2,7 @@
  * net/tipc/core.h: Include file for TIPC global declarations
  *
  * Copyright (c) 2005-2006, Ericsson AB
- * Copyright (c) 2005-2006, Wind River Systems
+ * Copyright (c) 2005-2007, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include <linux/vmalloc.h>
 
 /*
- * TIPC debugging code
+ * TIPC sanity test macros
  */
 
 #define assert(i)  BUG_ON(!(i))
 
-struct tipc_msg;
-extern struct print_buf *TIPC_NULL, *TIPC_CONS, *TIPC_LOG;
-extern struct print_buf *TIPC_TEE(struct print_buf *, struct print_buf *);
-void tipc_msg_print(struct print_buf*,struct tipc_msg *,const char*);
-void tipc_printf(struct print_buf *, const char *fmt, ...);
-void tipc_dump(struct print_buf*,const char *fmt, ...);
-
-#ifdef CONFIG_TIPC_DEBUG
-
 /*
- * TIPC debug support included:
- * - system messages are printed to TIPC_OUTPUT print buffer
- * - debug messages are printed to DBG_OUTPUT print buffer
+ * TIPC system monitoring code
  */
 
-#define err(fmt, arg...)  tipc_printf(TIPC_OUTPUT, KERN_ERR "TIPC: " fmt, ## arg)
-#define warn(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_WARNING "TIPC: " fmt, ## arg)
-#define info(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_NOTICE "TIPC: " fmt, ## arg)
+/*
+ * TIPC's print buffer subsystem supports the following print buffers:
+ *
+ * TIPC_NULL : null buffer (i.e. print nowhere)
+ * TIPC_CONS : system console
+ * TIPC_LOG  : TIPC log buffer
+ * &buf             : user-defined buffer (struct print_buf *)
+ *
+ * Note: TIPC_LOG is configured to echo its output to the system console;
+ *       user-defined buffers can be configured to do the same thing.
+ */
 
-#define dbg(fmt, arg...)  do {if (DBG_OUTPUT != TIPC_NULL) tipc_printf(DBG_OUTPUT, fmt, ## arg);} while(0)
-#define msg_dbg(msg, txt) do {if (DBG_OUTPUT != TIPC_NULL) tipc_msg_print(DBG_OUTPUT, msg, txt);} while(0)
-#define dump(fmt, arg...) do {if (DBG_OUTPUT != TIPC_NULL) tipc_dump(DBG_OUTPUT, fmt, ##arg);} while(0)
+extern struct print_buf *const TIPC_NULL;
+extern struct print_buf *const TIPC_CONS;
+extern struct print_buf *const TIPC_LOG;
 
+void tipc_printf(struct print_buf *, const char *fmt, ...);
 
 /*
- * By default, TIPC_OUTPUT is defined to be system console and TIPC log buffer,
- * while DBG_OUTPUT is the null print buffer.  These defaults can be changed
- * here, or on a per .c file basis, by redefining these symbols.  The following
- * print buffer options are available:
- *
- * TIPC_NULL              : null buffer (i.e. print nowhere)
- * TIPC_CONS              : system console
- * TIPC_LOG               : TIPC log buffer
- * &buf                           : user-defined buffer (struct print_buf *)
- * TIPC_TEE(&buf_a,&buf_b) : list of buffers (eg. TIPC_TEE(TIPC_CONS,TIPC_LOG))
+ * TIPC_OUTPUT is the destination print buffer for system messages.
  */
 
 #ifndef TIPC_OUTPUT
-#define TIPC_OUTPUT TIPC_TEE(TIPC_CONS,TIPC_LOG)
-#endif
-
-#ifndef DBG_OUTPUT
-#define DBG_OUTPUT TIPC_NULL
+#define TIPC_OUTPUT TIPC_LOG
 #endif
 
-#else
-
 /*
- * TIPC debug support not included:
- * - system messages are printed to system console
- * - debug messages are not printed
+ * TIPC can be configured to send system messages to TIPC_OUTPUT
+ * or to the system console only.
  */
 
+#ifdef CONFIG_TIPC_DEBUG
+
+#define err(fmt, arg...)  tipc_printf(TIPC_OUTPUT, \
+                                       KERN_ERR "TIPC: " fmt, ## arg)
+#define warn(fmt, arg...) tipc_printf(TIPC_OUTPUT, \
+                                       KERN_WARNING "TIPC: " fmt, ## arg)
+#define info(fmt, arg...) tipc_printf(TIPC_OUTPUT, \
+                                       KERN_NOTICE "TIPC: " fmt, ## arg)
+
+#else
+
 #define err(fmt, arg...)  printk(KERN_ERR "TIPC: " fmt , ## arg)
 #define info(fmt, arg...) printk(KERN_INFO "TIPC: " fmt , ## arg)
 #define warn(fmt, arg...) printk(KERN_WARNING "TIPC: " fmt , ## arg)
 
-#define dbg(fmt, arg...) do {} while (0)
-#define msg_dbg(msg,txt) do {} while (0)
-#define dump(fmt,arg...) do {} while (0)
+#endif
 
+/*
+ * DBG_OUTPUT is the destination print buffer for debug messages.
+ * It defaults to the the null print buffer, but can be redefined
+ * (typically in the individual .c files being debugged) to allow
+ * selected debug messages to be generated where needed.
+ */
+
+#ifndef DBG_OUTPUT
+#define DBG_OUTPUT TIPC_NULL
+#endif
 
 /*
- * TIPC_OUTPUT is defined to be the system console, while DBG_OUTPUT is
- * the null print buffer.  Thes ensures that any system or debug messages
- * that are generated without using the above macros are handled correctly.
+ * TIPC can be configured to send debug messages to the specified print buffer
+ * (typically DBG_OUTPUT) or to suppress them entirely.
  */
 
-#undef  TIPC_OUTPUT
-#define TIPC_OUTPUT TIPC_CONS
+#ifdef CONFIG_TIPC_DEBUG
 
-#undef  DBG_OUTPUT
-#define DBG_OUTPUT TIPC_NULL
+#define dbg(fmt, arg...)  \
+       do { \
+               if (DBG_OUTPUT != TIPC_NULL) \
+                       tipc_printf(DBG_OUTPUT, fmt, ## arg); \
+       } while (0)
+#define msg_dbg(msg, txt) \
+       do { \
+               if (DBG_OUTPUT != TIPC_NULL) \
+                       tipc_msg_dbg(DBG_OUTPUT, msg, txt); \
+       } while (0)
+#define dump(fmt, arg...) \
+       do { \
+               if (DBG_OUTPUT != TIPC_NULL) \
+                       tipc_dump_dbg(DBG_OUTPUT, fmt, ##arg); \
+       } while (0)
+
+void tipc_msg_dbg(struct print_buf *, struct tipc_msg *, const char *);
+void tipc_dump_dbg(struct print_buf *, const char *fmt, ...);
+
+#else
+
+#define dbg(fmt, arg...)       do {} while (0)
+#define msg_dbg(msg, txt)      do {} while (0)
+#define dump(fmt, arg...)      do {} while (0)
+
+#define tipc_msg_dbg(...)      do {} while (0)
+#define tipc_dump_dbg(...)     do {} while (0)
 
 #endif
 
@@ -178,7 +202,7 @@ extern atomic_t tipc_user_count;
 
 extern int  tipc_core_start(void);
 extern void tipc_core_stop(void);
-extern int  tipc_core_start_net(void);
+extern int  tipc_core_start_net(unsigned long addr);
 extern void tipc_core_stop_net(void);
 extern int  tipc_handler_start(void);
 extern void tipc_handler_stop(void);
index e809d2a2ce062486f408a923dbdfa2b590ad537f..29ecae8516683df21403c78a934b44da7a714c88 100644 (file)
@@ -2,7 +2,7 @@
  * net/tipc/dbg.c: TIPC print buffer routines for debugging
  *
  * Copyright (c) 1996-2006, Ericsson AB
- * Copyright (c) 2005-2006, Wind River Systems
+ * Copyright (c) 2005-2007, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include "config.h"
 #include "dbg.h"
 
-static char print_string[TIPC_PB_MAX_STR];
-static DEFINE_SPINLOCK(print_lock);
+/*
+ * TIPC pre-defines the following print buffers:
+ *
+ * TIPC_NULL : null buffer (i.e. print nowhere)
+ * TIPC_CONS : system console
+ * TIPC_LOG  : TIPC log buffer
+ *
+ * Additional user-defined print buffers are also permitted.
+ */
 
-static struct print_buf null_buf = { NULL, 0, NULL, NULL };
-struct print_buf *TIPC_NULL = &null_buf;
+static struct print_buf null_buf = { NULL, 0, NULL, 0 };
+struct print_buf *const TIPC_NULL = &null_buf;
 
-static struct print_buf cons_buf = { NULL, 0, NULL, NULL };
-struct print_buf *TIPC_CONS = &cons_buf;
+static struct print_buf cons_buf = { NULL, 0, NULL, 1 };
+struct print_buf *const TIPC_CONS = &cons_buf;
 
-static struct print_buf log_buf = { NULL, 0, NULL, NULL };
-struct print_buf *TIPC_LOG = &log_buf;
+static struct print_buf log_buf = { NULL, 0, NULL, 1 };
+struct print_buf *const TIPC_LOG = &log_buf;
+
+/*
+ * Locking policy when using print buffers.
+ *
+ * 1) tipc_printf() uses 'print_lock' to protect against concurrent access to
+ * 'print_string' when writing to a print buffer. This also protects against
+ * concurrent writes to the print buffer being written to.
+ *
+ * 2) tipc_dump() and tipc_log_XXX() leverage the aforementioned
+ * use of 'print_lock' to protect against all types of concurrent operations
+ * on their associated print buffer (not just write operations).
+ *
+ * Note: All routines of the form tipc_printbuf_XXX() are lock-free, and rely
+ * on the caller to prevent simultaneous use of the print buffer(s) being
+ * manipulated.
+ */
+
+static char print_string[TIPC_PB_MAX_STR];
+static DEFINE_SPINLOCK(print_lock);
 
 
 #define FORMAT(PTR,LEN,FMT) \
@@ -60,27 +86,14 @@ struct print_buf *TIPC_LOG = &log_buf;
        *(PTR + LEN) = '\0';\
 }
 
-/*
- * Locking policy when using print buffers.
- *
- * The following routines use 'print_lock' for protection:
- * 1) tipc_printf()  - to protect its print buffer(s) and 'print_string'
- * 2) TIPC_TEE()     - to protect its print buffer(s)
- * 3) tipc_dump()    - to protect its print buffer(s) and 'print_string'
- * 4) tipc_log_XXX() - to protect TIPC_LOG
- *
- * All routines of the form tipc_printbuf_XXX() rely on the caller to prevent
- * simultaneous use of the print buffer(s) being manipulated.
- */
-
 /**
  * tipc_printbuf_init - initialize print buffer to empty
  * @pb: pointer to print buffer structure
  * @raw: pointer to character array used by print buffer
  * @size: size of character array
  *
- * Makes the print buffer a null device that discards anything written to it
- * if the character array is too small (or absent).
+ * Note: If the character array is too small (or absent), the print buffer
+ * becomes a null device that discards anything written to it.
  */
 
 void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 size)
@@ -88,13 +101,13 @@ void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 size)
        pb->buf = raw;
        pb->crs = raw;
        pb->size = size;
-       pb->next = NULL;
+       pb->echo = 0;
 
        if (size < TIPC_PB_MIN_SIZE) {
                pb->buf = NULL;
        } else if (raw) {
                pb->buf[0] = 0;
-               pb->buf[size-1] = ~0;
+               pb->buf[size - 1] = ~0;
        }
 }
 
@@ -105,7 +118,11 @@ void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 size)
 
 void tipc_printbuf_reset(struct print_buf *pb)
 {
-       tipc_printbuf_init(pb, pb->buf, pb->size);
+       if (pb->buf) {
+               pb->crs = pb->buf;
+               pb->buf[0] = 0;
+               pb->buf[pb->size - 1] = ~0;
+       }
 }
 
 /**
@@ -141,7 +158,7 @@ int tipc_printbuf_validate(struct print_buf *pb)
 
        if (pb->buf[pb->size - 1] == 0) {
                cp_buf = kmalloc(pb->size, GFP_ATOMIC);
-               if (cp_buf != NULL){
+               if (cp_buf{
                        tipc_printbuf_init(&cb, cp_buf, pb->size);
                        tipc_printbuf_move(&cb, pb);
                        tipc_printbuf_move(pb, &cb);
@@ -179,15 +196,16 @@ void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from)
        }
 
        if (pb_to->size < pb_from->size) {
-               tipc_printbuf_reset(pb_to);
-               tipc_printf(pb_to, "*** PRINT BUFFER MOVE ERROR ***");
+               strcpy(pb_to->buf, "*** PRINT BUFFER MOVE ERROR ***");
+               pb_to->buf[pb_to->size - 1] = ~0;
+               pb_to->crs = strchr(pb_to->buf, 0);
                return;
        }
 
        /* Copy data from char after cursor to end (if used) */
 
        len = pb_from->buf + pb_from->size - pb_from->crs - 2;
-       if ((pb_from->buf[pb_from->size-1] == 0) && (len > 0)) {
+       if ((pb_from->buf[pb_from->size - 1] == 0) && (len > 0)) {
                strcpy(pb_to->buf, pb_from->crs + 1);
                pb_to->crs = pb_to->buf + len;
        } else
@@ -203,8 +221,8 @@ void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from)
 }
 
 /**
- * tipc_printf - append formatted output to print buffer chain
- * @pb: pointer to chain of print buffers (may be NULL)
+ * tipc_printf - append formatted output to print buffer
+ * @pb: pointer to print buffer
  * @fmt: formatted info to be printed
  */
 
@@ -213,68 +231,40 @@ void tipc_printf(struct print_buf *pb, const char *fmt, ...)
        int chars_to_add;
        int chars_left;
        char save_char;
-       struct print_buf *pb_next;
 
        spin_lock_bh(&print_lock);
+
        FORMAT(print_string, chars_to_add, fmt);
        if (chars_to_add >= TIPC_PB_MAX_STR)
                strcpy(print_string, "*** PRINT BUFFER STRING TOO LONG ***");
 
-       while (pb) {
-               if (pb == TIPC_CONS)
-                       printk(print_string);
-               else if (pb->buf) {
-                       chars_left = pb->buf + pb->size - pb->crs - 1;
-                       if (chars_to_add <= chars_left) {
-                               strcpy(pb->crs, print_string);
-                               pb->crs += chars_to_add;
-                       } else if (chars_to_add >= (pb->size - 1)) {
-                               strcpy(pb->buf, print_string + chars_to_add + 1
-                                      - pb->size);
-                               pb->crs = pb->buf + pb->size - 1;
-                       } else {
-                               strcpy(pb->buf, print_string + chars_left);
-                               save_char = print_string[chars_left];
-                               print_string[chars_left] = 0;
-                               strcpy(pb->crs, print_string);
-                               print_string[chars_left] = save_char;
-                               pb->crs = pb->buf + chars_to_add - chars_left;
-                       }
+       if (pb->buf) {
+               chars_left = pb->buf + pb->size - pb->crs - 1;
+               if (chars_to_add <= chars_left) {
+                       strcpy(pb->crs, print_string);
+                       pb->crs += chars_to_add;
+               } else if (chars_to_add >= (pb->size - 1)) {
+                       strcpy(pb->buf, print_string + chars_to_add + 1
+                              - pb->size);
+                       pb->crs = pb->buf + pb->size - 1;
+               } else {
+                       strcpy(pb->buf, print_string + chars_left);
+                       save_char = print_string[chars_left];
+                       print_string[chars_left] = 0;
+                       strcpy(pb->crs, print_string);
+                       print_string[chars_left] = save_char;
+                       pb->crs = pb->buf + chars_to_add - chars_left;
                }
-               pb_next = pb->next;
-               pb->next = NULL;
-               pb = pb_next;
        }
-       spin_unlock_bh(&print_lock);
-}
 
-/**
- * TIPC_TEE - perform next output operation on both print buffers
- * @b0: pointer to chain of print buffers (may be NULL)
- * @b1: pointer to print buffer to add to chain
- *
- * Returns pointer to print buffer chain.
- */
+       if (pb->echo)
+               printk(print_string);
 
-struct print_buf *TIPC_TEE(struct print_buf *b0, struct print_buf *b1)
-{
-       struct print_buf *pb = b0;
-
-       if (!b0 || (b0 == b1))
-               return b1;
-
-       spin_lock_bh(&print_lock);
-       while (pb->next) {
-               if ((pb->next == b1) || (pb->next == b0))
-                       pb->next = pb->next->next;
-               else
-                       pb = pb->next;
-       }
-       pb->next = b1;
        spin_unlock_bh(&print_lock);
-       return b0;
 }
 
+#ifdef CONFIG_TIPC_DEBUG
+
 /**
  * print_to_console - write string of bytes to console in multiple chunks
  */
@@ -321,72 +311,66 @@ static void printbuf_dump(struct print_buf *pb)
 }
 
 /**
- * tipc_dump - dump non-console print buffer(s) to console
- * @pb: pointer to chain of print buffers
+ * tipc_dump_dbg - dump (non-console) print buffer to console
+ * @pb: pointer to print buffer
  */
 
-void tipc_dump(struct print_buf *pb, const char *fmt, ...)
+void tipc_dump_dbg(struct print_buf *pb, const char *fmt, ...)
 {
-       struct print_buf *pb_next;
        int len;
 
+       if (pb == TIPC_CONS)
+               return;
+
        spin_lock_bh(&print_lock);
+
        FORMAT(print_string, len, fmt);
        printk(print_string);
 
-       for (; pb; pb = pb->next) {
-               if (pb != TIPC_CONS) {
-                       printk("\n---- Start of %s log dump ----\n\n",
-                              (pb == TIPC_LOG) ? "global" : "local");
-                       printbuf_dump(pb);
-                       tipc_printbuf_reset(pb);
-                       printk("\n---- End of dump ----\n");
-               }
-               pb_next = pb->next;
-               pb->next = NULL;
-               pb = pb_next;
-       }
+       printk("\n---- Start of %s log dump ----\n\n",
+              (pb == TIPC_LOG) ? "global" : "local");
+       printbuf_dump(pb);
+       tipc_printbuf_reset(pb);
+       printk("\n---- End of dump ----\n");
+
        spin_unlock_bh(&print_lock);
 }
 
+#endif
+
 /**
- * tipc_log_stop - free up TIPC log print buffer
+ * tipc_log_resize - change the size of the TIPC log buffer
+ * @log_size: print buffer size to use
  */
 
-void tipc_log_stop(void)
+int tipc_log_resize(int log_size)
 {
+       int res = 0;
+
        spin_lock_bh(&print_lock);
        if (TIPC_LOG->buf) {
                kfree(TIPC_LOG->buf);
                TIPC_LOG->buf = NULL;
        }
-       spin_unlock_bh(&print_lock);
-}
-
-/**
- * tipc_log_reinit - (re)initialize TIPC log print buffer
- * @log_size: print buffer size to use
- */
-
-void tipc_log_reinit(int log_size)
-{
-       tipc_log_stop();
-
        if (log_size) {
                if (log_size < TIPC_PB_MIN_SIZE)
                        log_size = TIPC_PB_MIN_SIZE;
-               spin_lock_bh(&print_lock);
+               res = TIPC_LOG->echo;
                tipc_printbuf_init(TIPC_LOG, kmalloc(log_size, GFP_ATOMIC),
                                   log_size);
-               spin_unlock_bh(&print_lock);
+               TIPC_LOG->echo = res;
+               res = !TIPC_LOG->buf;
        }
+       spin_unlock_bh(&print_lock);
+
+       return res;
 }
 
 /**
- * tipc_log_resize - reconfigure size of TIPC log buffer
+ * tipc_log_resize_cmd - reconfigure size of TIPC log buffer
  */
 
-struct sk_buff *tipc_log_resize(const void *req_tlv_area, int req_tlv_space)
+struct sk_buff *tipc_log_resize_cmd(const void *req_tlv_area, int req_tlv_space)
 {
        u32 value;
 
@@ -397,7 +381,9 @@ struct sk_buff *tipc_log_resize(const void *req_tlv_area, int req_tlv_space)
        if (value != delimit(value, 0, 32768))
                return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
                                                   " (log size must be 0-32768)");
-       tipc_log_reinit(value);
+       if (tipc_log_resize(value))
+               return tipc_cfg_reply_error_string(
+                       "unable to create specified log (log size is now 0)");
        return tipc_cfg_reply_none();
 }
 
@@ -410,27 +396,32 @@ struct sk_buff *tipc_log_dump(void)
        struct sk_buff *reply;
 
        spin_lock_bh(&print_lock);
-       if (!TIPC_LOG->buf)
+       if (!TIPC_LOG->buf) {
+               spin_unlock_bh(&print_lock);
                reply = tipc_cfg_reply_ultra_string("log not activated\n");
-       else if (tipc_printbuf_empty(TIPC_LOG))
+       } else if (tipc_printbuf_empty(TIPC_LOG)) {
+               spin_unlock_bh(&print_lock);
                reply = tipc_cfg_reply_ultra_string("log is empty\n");
+       }
        else {
                struct tlv_desc *rep_tlv;
                struct print_buf pb;
                int str_len;
 
                str_len = min(TIPC_LOG->size, 32768u);
+               spin_unlock_bh(&print_lock);
                reply = tipc_cfg_reply_alloc(TLV_SPACE(str_len));
                if (reply) {
                        rep_tlv = (struct tlv_desc *)reply->data;
                        tipc_printbuf_init(&pb, TLV_DATA(rep_tlv), str_len);
+                       spin_lock_bh(&print_lock);
                        tipc_printbuf_move(&pb, TIPC_LOG);
+                       spin_unlock_bh(&print_lock);
                        str_len = strlen(TLV_DATA(rep_tlv)) + 1;
                        skb_put(reply, TLV_SPACE(str_len));
                        TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
                }
        }
-       spin_unlock_bh(&print_lock);
        return reply;
 }
 
index c01b085000e08622838ce5b46f1ea1023d7069c2..5ef1bc8f64ef186b5db3dfedbe839fe25ef4c52e 100644 (file)
@@ -2,7 +2,7 @@
  * net/tipc/dbg.h: Include file for TIPC print buffer routines
  *
  * Copyright (c) 1997-2006, Ericsson AB
- * Copyright (c) 2005-2006, Wind River Systems
+ * Copyright (c) 2005-2007, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * @buf: pointer to character array containing print buffer contents
  * @size: size of character array
  * @crs: pointer to first unused space in character array (i.e. final NUL)
- * @next: used to link print buffers when printing to more than one at a time
+ * @echo: echo output to system console if non-zero
  */
 
 struct print_buf {
        char *buf;
        u32 size;
        char *crs;
-       struct print_buf *next;
+       int echo;
 };
 
 #define TIPC_PB_MIN_SIZE 64    /* minimum size for a print buffer's array */
@@ -61,10 +61,10 @@ int  tipc_printbuf_empty(struct print_buf *pb);
 int  tipc_printbuf_validate(struct print_buf *pb);
 void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from);
 
-void tipc_log_reinit(int log_size);
-void tipc_log_stop(void);
+int tipc_log_resize(int log_size);
 
-struct sk_buff *tipc_log_resize(const void *req_tlv_area, int req_tlv_space);
+struct sk_buff *tipc_log_resize_cmd(const void *req_tlv_area,
+                                   int req_tlv_space);
 struct sk_buff *tipc_log_dump(void);
 
 #endif
index 5d643e5721eb45ec36d3fb43d2f205e90f1ec5b5..1657f0e795ff4c6b606d4323d9db97631129bd20 100644 (file)
@@ -120,9 +120,8 @@ static struct sk_buff *tipc_disc_init_msg(u32 type,
 
        if (buf) {
                msg = buf_msg(buf);
-               msg_init(msg, LINK_CONFIG, type, TIPC_OK, DSC_H_SIZE,
-                        dest_domain);
-               msg_set_non_seq(msg);
+               msg_init(msg, LINK_CONFIG, type, DSC_H_SIZE, dest_domain);
+               msg_set_non_seq(msg, 1);
                msg_set_req_links(msg, req_links);
                msg_set_dest_domain(msg, dest_domain);
                msg_set_bc_netid(msg, tipc_net_id);
@@ -156,11 +155,11 @@ static void disc_dupl_alert(struct bearer *b_ptr, u32 node_addr,
 /**
  * tipc_disc_recv_msg - handle incoming link setup message (request or response)
  * @buf: buffer containing message
+ * @b_ptr: bearer that message arrived on
  */
 
-void tipc_disc_recv_msg(struct sk_buff *buf)
+void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr)
 {
-       struct bearer *b_ptr = (struct bearer *)TIPC_SKB_CB(buf)->handle;
        struct link *link;
        struct tipc_media_addr media_addr;
        struct tipc_msg *msg = buf_msg(buf);
@@ -200,9 +199,8 @@ void tipc_disc_recv_msg(struct sk_buff *buf)
                dbg(" in own cluster\n");
                if (n_ptr == NULL) {
                        n_ptr = tipc_node_create(orig);
-               }
-               if (n_ptr == NULL) {
-                       return;
+                       if (!n_ptr)
+                               return;
                }
                spin_lock_bh(&n_ptr->lock);
                link = n_ptr->links[b_ptr->identity];
index 9fd7587b143a5e74dd03ec6b8a7299ae5f410f58..c36eaeb7d5d0bb2e55461468d430a0c8b15734ac 100644 (file)
@@ -48,7 +48,7 @@ struct link_req *tipc_disc_init_link_req(struct bearer *b_ptr,
 void tipc_disc_update_link_req(struct link_req *req);
 void tipc_disc_stop_link_req(struct link_req *req);
 
-void tipc_disc_recv_msg(struct sk_buff *buf);
+void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr);
 
 void tipc_disc_link_event(u32 addr, char *name, int up);
 #if 0
index 2a26a16e269feb64d5919648fb67ee081288a151..9784a8e963b4cda0c150ba67f5732f6c11026dde 100644 (file)
 #include "bcast.h"
 
 
+/*
+ * Out-of-range value for link session numbers
+ */
+
+#define INVALID_SESSION 0x10000
+
 /*
  * Limit for deferred reception queue:
  */
@@ -147,9 +153,21 @@ static void link_print(struct link *l_ptr, struct print_buf *buf,
 
 #define LINK_LOG_BUF_SIZE 0
 
-#define dbg_link(fmt, arg...)  do {if (LINK_LOG_BUF_SIZE) tipc_printf(&l_ptr->print_buf, fmt, ## arg); } while(0)
-#define dbg_link_msg(msg, txt) do {if (LINK_LOG_BUF_SIZE) tipc_msg_print(&l_ptr->print_buf, msg, txt); } while(0)
-#define dbg_link_state(txt) do {if (LINK_LOG_BUF_SIZE) link_print(l_ptr, &l_ptr->print_buf, txt); } while(0)
+#define dbg_link(fmt, arg...) \
+       do { \
+               if (LINK_LOG_BUF_SIZE) \
+                       tipc_printf(&l_ptr->print_buf, fmt, ## arg); \
+       } while (0)
+#define dbg_link_msg(msg, txt) \
+       do { \
+               if (LINK_LOG_BUF_SIZE) \
+                       tipc_msg_dbg(&l_ptr->print_buf, msg, txt); \
+       } while (0)
+#define dbg_link_state(txt) \
+       do { \
+               if (LINK_LOG_BUF_SIZE) \
+                       link_print(l_ptr, &l_ptr->print_buf, txt); \
+       } while (0)
 #define dbg_link_dump() do { \
        if (LINK_LOG_BUF_SIZE) { \
                tipc_printf(LOG, "\n\nDumping link <%s>:\n", l_ptr->name); \
@@ -450,9 +468,9 @@ struct link *tipc_link_create(struct bearer *b_ptr, const u32 peer,
 
        l_ptr->pmsg = (struct tipc_msg *)&l_ptr->proto_msg;
        msg = l_ptr->pmsg;
-       msg_init(msg, LINK_PROTOCOL, RESET_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr);
+       msg_init(msg, LINK_PROTOCOL, RESET_MSG, INT_H_SIZE, l_ptr->addr);
        msg_set_size(msg, sizeof(l_ptr->proto_msg));
-       msg_set_session(msg, tipc_random);
+       msg_set_session(msg, (tipc_random & 0xffff));
        msg_set_bearer_id(msg, b_ptr->identity);
        strcpy((char *)msg_data(msg), if_name);
 
@@ -693,10 +711,10 @@ void tipc_link_reset(struct link *l_ptr)
        u32 checkpoint = l_ptr->next_in_no;
        int was_active_link = tipc_link_is_active(l_ptr);
 
-       msg_set_session(l_ptr->pmsg, msg_session(l_ptr->pmsg) + 1);
+       msg_set_session(l_ptr->pmsg, ((msg_session(l_ptr->pmsg) + 1) & 0xffff));
 
-       /* Link is down, accept any session: */
-       l_ptr->peer_session = 0;
+       /* Link is down, accept any session */
+       l_ptr->peer_session = INVALID_SESSION;
 
        /* Prepare for max packet size negotiation */
        link_init_max_pkt(l_ptr);
@@ -1110,7 +1128,7 @@ int tipc_link_send_buf(struct link *l_ptr, struct sk_buff *buf)
 
                        if (bundler) {
                                msg_init(&bundler_hdr, MSG_BUNDLER, OPEN_MSG,
-                                        TIPC_OK, INT_H_SIZE, l_ptr->addr);
+                                        INT_H_SIZE, l_ptr->addr);
                                skb_copy_to_linear_data(bundler, &bundler_hdr,
                                                        INT_H_SIZE);
                                skb_trim(bundler, INT_H_SIZE);
@@ -1374,7 +1392,7 @@ again:
 
        msg_dbg(hdr, ">FRAGMENTING>");
        msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
-                TIPC_OK, INT_H_SIZE, msg_destnode(hdr));
+                INT_H_SIZE, msg_destnode(hdr));
        msg_set_link_selector(&fragm_hdr, sender->publ.ref);
        msg_set_size(&fragm_hdr, max_pkt);
        msg_set_fragm_no(&fragm_hdr, 1);
@@ -1651,7 +1669,7 @@ static void link_retransmit_failure(struct link *l_ptr, struct sk_buff *buf)
        struct tipc_msg *msg = buf_msg(buf);
 
        warn("Retransmission failure on link <%s>\n", l_ptr->name);
-       tipc_msg_print(TIPC_OUTPUT, msg, ">RETR-FAIL>");
+       tipc_msg_dbg(TIPC_OUTPUT, msg, ">RETR-FAIL>");
 
        if (l_ptr->addr) {
 
@@ -1748,21 +1766,6 @@ void tipc_link_retransmit(struct link *l_ptr, struct sk_buff *buf,
        l_ptr->retransm_queue_head = l_ptr->retransm_queue_size = 0;
 }
 
-/*
- * link_recv_non_seq: Receive packets which are outside
- *                    the link sequence flow
- */
-
-static void link_recv_non_seq(struct sk_buff *buf)
-{
-       struct tipc_msg *msg = buf_msg(buf);
-
-       if (msg_user(msg) ==  LINK_CONFIG)
-               tipc_disc_recv_msg(buf);
-       else
-               tipc_bclink_recv_pkt(buf);
-}
-
 /**
  * link_insert_deferred_queue - insert deferred messages back into receive chain
  */
@@ -1839,7 +1842,7 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
 {
        read_lock_bh(&tipc_net_lock);
        while (head) {
-               struct bearer *b_ptr;
+               struct bearer *b_ptr = (struct bearer *)tb_ptr;
                struct node *n_ptr;
                struct link *l_ptr;
                struct sk_buff *crs;
@@ -1850,9 +1853,6 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
                u32 released = 0;
                int type;
 
-               b_ptr = (struct bearer *)tb_ptr;
-               TIPC_SKB_CB(buf)->handle = b_ptr;
-
                head = head->next;
 
                /* Ensure message is well-formed */
@@ -1871,7 +1871,10 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
                msg = buf_msg(buf);
 
                if (unlikely(msg_non_seq(msg))) {
-                       link_recv_non_seq(buf);
+                       if (msg_user(msg) ==  LINK_CONFIG)
+                               tipc_disc_recv_msg(buf, b_ptr);
+                       else
+                               tipc_bclink_recv_pkt(buf);
                        continue;
                }
 
@@ -1978,8 +1981,6 @@ deliver:
                                                if (link_recv_changeover_msg(&l_ptr, &buf)) {
                                                        msg = buf_msg(buf);
                                                        seq_no = msg_seqno(msg);
-                                                       TIPC_SKB_CB(buf)->handle
-                                                               = b_ptr;
                                                        if (type == ORIGINAL_MSG)
                                                                goto deliver;
                                                        goto protocol_check;
@@ -2263,7 +2264,8 @@ static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf)
        switch (msg_type(msg)) {
 
        case RESET_MSG:
-               if (!link_working_unknown(l_ptr) && l_ptr->peer_session) {
+               if (!link_working_unknown(l_ptr) &&
+                   (l_ptr->peer_session != INVALID_SESSION)) {
                        if (msg_session(msg) == l_ptr->peer_session) {
                                dbg("Duplicate RESET: %u<->%u\n",
                                    msg_session(msg), l_ptr->peer_session);
@@ -2424,7 +2426,7 @@ void tipc_link_changeover(struct link *l_ptr)
        }
 
        msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
-                ORIGINAL_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr);
+                ORIGINAL_MSG, INT_H_SIZE, l_ptr->addr);
        msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
        msg_set_msgcnt(&tunnel_hdr, msgcount);
        dbg("Link changeover requires %u tunnel messages\n", msgcount);
@@ -2479,7 +2481,7 @@ void tipc_link_send_duplicate(struct link *l_ptr, struct link *tunnel)
        struct tipc_msg tunnel_hdr;
 
        msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
-                DUPLICATE_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr);
+                DUPLICATE_MSG, INT_H_SIZE, l_ptr->addr);
        msg_set_msgcnt(&tunnel_hdr, l_ptr->out_queue_size);
        msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
        iter = l_ptr->first_out;
@@ -2672,10 +2674,12 @@ int tipc_link_send_long_buf(struct link *l_ptr, struct sk_buff *buf)
        u32 pack_sz = link_max_pkt(l_ptr);
        u32 fragm_sz = pack_sz - INT_H_SIZE;
        u32 fragm_no = 1;
-       u32 destaddr = msg_destnode(inmsg);
+       u32 destaddr;
 
        if (msg_short(inmsg))
                destaddr = l_ptr->addr;
+       else
+               destaddr = msg_destnode(inmsg);
 
        if (msg_routed(inmsg))
                msg_set_prevnode(inmsg, tipc_own_addr);
@@ -2683,7 +2687,7 @@ int tipc_link_send_long_buf(struct link *l_ptr, struct sk_buff *buf)
        /* Prepare reusable fragment header: */
 
        msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
-                TIPC_OK, INT_H_SIZE, destaddr);
+                INT_H_SIZE, destaddr);
        msg_set_link_selector(&fragm_hdr, msg_link_selector(inmsg));
        msg_set_long_msgno(&fragm_hdr, mod(l_ptr->long_msg_seq_no++));
        msg_set_fragm_no(&fragm_hdr, fragm_no);
index 696a8633df757fe1558e31add35019310de361e2..73dcd00d674edc19005b9ab4dd138b611462da29 100644 (file)
@@ -41,7 +41,9 @@
 #include "bearer.h"
 
 
-void tipc_msg_print(struct print_buf *buf, struct tipc_msg *msg, const char *str)
+#ifdef CONFIG_TIPC_DEBUG
+
+void tipc_msg_dbg(struct print_buf *buf, struct tipc_msg *msg, const char *str)
 {
        u32 usr = msg_user(msg);
        tipc_printf(buf, str);
@@ -228,13 +230,10 @@ void tipc_msg_print(struct print_buf *buf, struct tipc_msg *msg, const char *str
 
        switch (usr) {
        case CONN_MANAGER:
-       case NAME_DISTRIBUTOR:
        case TIPC_LOW_IMPORTANCE:
        case TIPC_MEDIUM_IMPORTANCE:
        case TIPC_HIGH_IMPORTANCE:
        case TIPC_CRITICAL_IMPORTANCE:
-               if (msg_short(msg))
-                       break;  /* No error */
                switch (msg_errcode(msg)) {
                case TIPC_OK:
                        break;
@@ -315,9 +314,11 @@ void tipc_msg_print(struct print_buf *buf, struct tipc_msg *msg, const char *str
        }
        tipc_printf(buf, "\n");
        if ((usr == CHANGEOVER_PROTOCOL) && (msg_msgcnt(msg))) {
-               tipc_msg_print(buf,msg_get_wrapped(msg),"      /");
+               tipc_msg_dbg(buf, msg_get_wrapped(msg), "      /");
        }
        if ((usr == MSG_FRAGMENTER) && (msg_type(msg) == FIRST_FRAGMENT)) {
-               tipc_msg_print(buf,msg_get_wrapped(msg),"      /");
+               tipc_msg_dbg(buf, msg_get_wrapped(msg), "      /");
        }
 }
+
+#endif
index ad487e8abcc2f2f0bcada4432db6c25e8dbf0dee..7ee6ae23814781f8cca8c70015f3236dfec99f90 100644 (file)
@@ -2,7 +2,7 @@
  * net/tipc/msg.h: Include file for TIPC message header routines
  *
  * Copyright (c) 2000-2007, Ericsson AB
- * Copyright (c) 2005-2007, Wind River Systems
+ * Copyright (c) 2005-2008, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -75,6 +75,14 @@ static inline void msg_set_bits(struct tipc_msg *m, u32 w,
        m->hdr[w] |= htonl(val);
 }
 
+static inline void msg_swap_words(struct tipc_msg *msg, u32 a, u32 b)
+{
+       u32 temp = msg->hdr[a];
+
+       msg->hdr[a] = msg->hdr[b];
+       msg->hdr[b] = temp;
+}
+
 /*
  * Word 0
  */
@@ -119,9 +127,9 @@ static inline int msg_non_seq(struct tipc_msg *m)
        return msg_bits(m, 0, 20, 1);
 }
 
-static inline void msg_set_non_seq(struct tipc_msg *m)
+static inline void msg_set_non_seq(struct tipc_msg *m, u32 n)
 {
-       msg_set_bits(m, 0, 20, 1, 1);
+       msg_set_bits(m, 0, 20, 1, n);
 }
 
 static inline int msg_dest_droppable(struct tipc_msg *m)
@@ -224,6 +232,25 @@ static inline void msg_set_seqno(struct tipc_msg *m, u32 n)
        msg_set_bits(m, 2, 0, 0xffff, n);
 }
 
+/*
+ * TIPC may utilize the "link ack #" and "link seq #" fields of a short
+ * message header to hold the destination node for the message, since the
+ * normal "dest node" field isn't present.  This cache is only referenced
+ * when required, so populating the cache of a longer message header is
+ * harmless (as long as the header has the two link sequence fields present).
+ *
+ * Note: Host byte order is OK here, since the info never goes off-card.
+ */
+
+static inline u32 msg_destnode_cache(struct tipc_msg *m)
+{
+       return m->hdr[2];
+}
+
+static inline void msg_set_destnode_cache(struct tipc_msg *m, u32 dnode)
+{
+       m->hdr[2] = dnode;
+}
 
 /*
  * Words 3-10
@@ -325,7 +352,7 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m)
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    w0:|vers |msg usr|hdr sz |n|resrv|            packet size          |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-   w1:|m typ|rsv=0|   sequence gap    |       broadcast ack no        |
+   w1:|m typ|      sequence gap       |       broadcast ack no        |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    w2:| link level ack no/bc_gap_from |     seq no / bcast_gap_to     |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -388,12 +415,12 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m)
 
 static inline u32 msg_seq_gap(struct tipc_msg *m)
 {
-       return msg_bits(m, 1, 16, 0xff);
+       return msg_bits(m, 1, 16, 0x1fff);
 }
 
 static inline void msg_set_seq_gap(struct tipc_msg *m, u32 n)
 {
-       msg_set_bits(m, 1, 16, 0xff, n);
+       msg_set_bits(m, 1, 16, 0x1fff, n);
 }
 
 static inline u32 msg_req_links(struct tipc_msg *m)
@@ -696,7 +723,7 @@ static inline u32 msg_tot_importance(struct tipc_msg *m)
 
 
 static inline void msg_init(struct tipc_msg *m, u32 user, u32 type,
-                           u32 err, u32 hsize, u32 destnode)
+                           u32 hsize, u32 destnode)
 {
        memset(m, 0, hsize);
        msg_set_version(m);
@@ -705,7 +732,6 @@ static inline void msg_init(struct tipc_msg *m, u32 user, u32 type,
        msg_set_size(m, hsize);
        msg_set_prevnode(m, tipc_own_addr);
        msg_set_type(m, type);
-       msg_set_errcode(m, err);
        if (!msg_short(m)) {
                msg_set_orignode(m, tipc_own_addr);
                msg_set_destnode(m, destnode);
index 39fd1619febf4c1e9e4c49152fe0fb9964d02522..10a69894e2fd5e9cfc3d22e39518e1f0c82603e0 100644 (file)
@@ -41,9 +41,6 @@
 #include "msg.h"
 #include "name_distr.h"
 
-#undef  DBG_OUTPUT
-#define DBG_OUTPUT NULL
-
 #define ITEM_SIZE sizeof(struct distr_item)
 
 /**
@@ -106,8 +103,7 @@ static struct sk_buff *named_prepare_buf(u32 type, u32 size, u32 dest)
 
        if (buf != NULL) {
                msg = buf_msg(buf);
-               msg_init(msg, NAME_DISTRIBUTOR, type, TIPC_OK,
-                        LONG_H_SIZE, dest);
+               msg_init(msg, NAME_DISTRIBUTOR, type, LONG_H_SIZE, dest);
                msg_set_size(msg, LONG_H_SIZE + size);
        }
        return buf;
index ac7dfdda79737f652e540dfd0297611a986aba12..096f7bd240a0307267c30dba909b7fad2fac8471 100644 (file)
@@ -74,7 +74,7 @@ struct sub_seq {
  * @first_free: array index of first unused sub-sequence entry
  * @ns_list: links to adjacent name sequences in hash chain
  * @subscriptions: list of subscriptions for this 'type'
- * @lock: spinlock controlling access to name sequence structure
+ * @lock: spinlock controlling access to publication lists of all sub-sequences
  */
 
 struct name_seq {
@@ -905,6 +905,9 @@ static void nameseq_list(struct name_seq *seq, struct print_buf *buf, u32 depth,
        struct sub_seq *sseq;
        char typearea[11];
 
+       if (seq->first_free == 0)
+               return;
+
        sprintf(typearea, "%-10u", seq->type);
 
        if (depth == 1) {
@@ -915,7 +918,9 @@ static void nameseq_list(struct name_seq *seq, struct print_buf *buf, u32 depth,
        for (sseq = seq->sseqs; sseq != &seq->sseqs[seq->first_free]; sseq++) {
                if ((lowbound <= sseq->upper) && (upbound >= sseq->lower)) {
                        tipc_printf(buf, "%s ", typearea);
+                       spin_lock_bh(&seq->lock);
                        subseq_list(sseq, buf, depth, index);
+                       spin_unlock_bh(&seq->lock);
                        sprintf(typearea, "%10s", " ");
                }
        }
@@ -1050,15 +1055,12 @@ void tipc_nametbl_dump(void)
 
 int tipc_nametbl_init(void)
 {
-       int array_size = sizeof(struct hlist_head) * tipc_nametbl_size;
-
-       table.types = kzalloc(array_size, GFP_ATOMIC);
+       table.types = kcalloc(tipc_nametbl_size, sizeof(struct hlist_head),
+                             GFP_ATOMIC);
        if (!table.types)
                return -ENOMEM;
 
-       write_lock_bh(&tipc_nametbl_lock);
        table.local_publ_count = 0;
-       write_unlock_bh(&tipc_nametbl_lock);
        return 0;
 }
 
index c39c76201e8edb2bd343c68f4b5e6ce4de202c49..cc51fa483672a12234c5f653f1392536d4b89000 100644 (file)
@@ -266,7 +266,7 @@ void tipc_net_route_msg(struct sk_buff *buf)
        tipc_link_send(buf, dnode, msg_link_selector(msg));
 }
 
-int tipc_net_start(void)
+int tipc_net_start(u32 addr)
 {
        char addr_string[16];
        int res;
@@ -274,6 +274,10 @@ int tipc_net_start(void)
        if (tipc_mode != TIPC_NODE_MODE)
                return -ENOPROTOOPT;
 
+       tipc_subscr_stop();
+       tipc_cfg_stop();
+
+       tipc_own_addr = addr;
        tipc_mode = TIPC_NET_MODE;
        tipc_named_reinit();
        tipc_port_reinit();
@@ -284,10 +288,10 @@ int tipc_net_start(void)
            (res = tipc_bclink_init())) {
                return res;
        }
-       tipc_subscr_stop();
-       tipc_cfg_stop();
+
        tipc_k_signal((Handler)tipc_subscr_start, 0);
        tipc_k_signal((Handler)tipc_cfg_init, 0);
+
        info("Started in network mode\n");
        info("Own node address %s, network identity %u\n",
             addr_string_fill(addr_string, tipc_own_addr), tipc_net_id);
index a6a0e9976ac9e1de14395165e53ca9750f430219..d154ac2bda9a174ab3114dc3b86e0783511daf8c 100644 (file)
@@ -58,7 +58,7 @@ void tipc_net_route_msg(struct sk_buff *buf);
 struct node *tipc_net_select_remote_node(u32 addr, u32 ref);
 u32 tipc_net_select_router(u32 addr, u32 ref);
 
-int tipc_net_start(void);
+int tipc_net_start(u32 addr);
 void tipc_net_stop(void);
 
 #endif
index 6a7f7b4c2595b365ff5f3b015b23e553080baa8e..c387217bb23066d20c6324cd0c9ee0d8200a91bd 100644 (file)
@@ -2,7 +2,7 @@
  * net/tipc/netlink.c: TIPC configuration handling
  *
  * Copyright (c) 2005-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2007, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -45,15 +45,17 @@ static int handle_cmd(struct sk_buff *skb, struct genl_info *info)
        struct nlmsghdr *req_nlh = info->nlhdr;
        struct tipc_genlmsghdr *req_userhdr = info->userhdr;
        int hdr_space = NLMSG_SPACE(GENL_HDRLEN + TIPC_GENL_HDRLEN);
+       u16 cmd;
 
        if ((req_userhdr->cmd & 0xC000) && (!capable(CAP_NET_ADMIN)))
-               rep_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN);
+               cmd = TIPC_CMD_NOT_NET_ADMIN;
        else
-               rep_buf = tipc_cfg_do_cmd(req_userhdr->dest,
-                                         req_userhdr->cmd,
-                                         NLMSG_DATA(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN,
-                                         NLMSG_PAYLOAD(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN),
-                                         hdr_space);
+               cmd = req_userhdr->cmd;
+
+       rep_buf = tipc_cfg_do_cmd(req_userhdr->dest, cmd,
+                       NLMSG_DATA(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN,
+                       NLMSG_PAYLOAD(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN),
+                       hdr_space);
 
        if (rep_buf) {
                skb_push(rep_buf, hdr_space);
index 598f4d3a0098e4f9b1ba5ae5f166f5166db1e069..34e9a2bb7c19d243b5c623957a899e5c8f987607 100644 (file)
@@ -52,16 +52,40 @@ static void node_established_contact(struct node *n_ptr);
 
 struct node *tipc_nodes = NULL;        /* sorted list of nodes within cluster */
 
+static DEFINE_SPINLOCK(node_create_lock);
+
 u32 tipc_own_tag = 0;
 
+/**
+ * tipc_node_create - create neighboring node
+ *
+ * Currently, this routine is called by neighbor discovery code, which holds
+ * net_lock for reading only.  We must take node_create_lock to ensure a node
+ * isn't created twice if two different bearers discover the node at the same
+ * time.  (It would be preferable to switch to holding net_lock in write mode,
+ * but this is a non-trivial change.)
+ */
+
 struct node *tipc_node_create(u32 addr)
 {
        struct cluster *c_ptr;
        struct node *n_ptr;
        struct node **curr_node;
 
+       spin_lock_bh(&node_create_lock);
+
+       for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) {
+               if (addr < n_ptr->addr)
+                       break;
+               if (addr == n_ptr->addr) {
+                       spin_unlock_bh(&node_create_lock);
+                       return n_ptr;
+               }
+       }
+
        n_ptr = kzalloc(sizeof(*n_ptr),GFP_ATOMIC);
        if (!n_ptr) {
+               spin_unlock_bh(&node_create_lock);
                warn("Node creation failed, no memory\n");
                return NULL;
        }
@@ -71,6 +95,7 @@ struct node *tipc_node_create(u32 addr)
                c_ptr = tipc_cltr_create(addr);
        }
        if (!c_ptr) {
+               spin_unlock_bh(&node_create_lock);
                kfree(n_ptr);
                return NULL;
        }
@@ -91,6 +116,7 @@ struct node *tipc_node_create(u32 addr)
                }
        }
        (*curr_node) = n_ptr;
+       spin_unlock_bh(&node_create_lock);
        return n_ptr;
 }
 
index 2f5806410c644b5b970998a17c9630d5ccf8f5af..2e0cff408ff94ac1915ac4d9683a8228df5bbae0 100644 (file)
@@ -211,15 +211,18 @@ exit:
 }
 
 /**
- * tipc_createport_raw - create a native TIPC port
+ * tipc_createport_raw - create a generic TIPC port
  *
- * Returns local port reference
+ * Returns port reference, or 0 if unable to create it
+ *
+ * Note: The newly created port is returned in the locked state.
  */
 
 u32 tipc_createport_raw(void *usr_handle,
                        u32 (*dispatcher)(struct tipc_port *, struct sk_buff *),
                        void (*wakeup)(struct tipc_port *),
-                       const u32 importance)
+                       const u32 importance,
+                       struct tipc_port **tp_ptr)
 {
        struct port *p_ptr;
        struct tipc_msg *msg;
@@ -237,17 +240,12 @@ u32 tipc_createport_raw(void *usr_handle,
                return 0;
        }
 
-       tipc_port_lock(ref);
        p_ptr->publ.usr_handle = usr_handle;
        p_ptr->publ.max_pkt = MAX_PKT_DEFAULT;
        p_ptr->publ.ref = ref;
        msg = &p_ptr->publ.phdr;
-       msg_init(msg, TIPC_LOW_IMPORTANCE, TIPC_NAMED_MSG, TIPC_OK, LONG_H_SIZE,
-                0);
-       msg_set_orignode(msg, tipc_own_addr);
-       msg_set_prevnode(msg, tipc_own_addr);
+       msg_init(msg, importance, TIPC_NAMED_MSG, LONG_H_SIZE, 0);
        msg_set_origport(msg, ref);
-       msg_set_importance(msg,importance);
        p_ptr->last_in_seqno = 41;
        p_ptr->sent = 1;
        INIT_LIST_HEAD(&p_ptr->wait_list);
@@ -262,7 +260,7 @@ u32 tipc_createport_raw(void *usr_handle,
        INIT_LIST_HEAD(&p_ptr->port_list);
        list_add_tail(&p_ptr->port_list, &ports);
        spin_unlock_bh(&tipc_port_list_lock);
-       tipc_port_unlock(p_ptr);
+       *tp_ptr = &p_ptr->publ;
        return ref;
 }
 
@@ -402,10 +400,10 @@ static struct sk_buff *port_build_proto_msg(u32 destport, u32 destnode,
        buf = buf_acquire(LONG_H_SIZE);
        if (buf) {
                msg = buf_msg(buf);
-               msg_init(msg, usr, type, err, LONG_H_SIZE, destnode);
+               msg_init(msg, usr, type, LONG_H_SIZE, destnode);
+               msg_set_errcode(msg, err);
                msg_set_destport(msg, destport);
                msg_set_origport(msg, origport);
-               msg_set_destnode(msg, destnode);
                msg_set_orignode(msg, orignode);
                msg_set_transp_seqno(msg, seqno);
                msg_set_msgcnt(msg, ack);
@@ -446,17 +444,19 @@ int tipc_reject_msg(struct sk_buff *buf, u32 err)
                return data_sz;
        }
        rmsg = buf_msg(rbuf);
-       msg_init(rmsg, imp, msg_type(msg), err, hdr_sz, msg_orignode(msg));
+       msg_init(rmsg, imp, msg_type(msg), hdr_sz, msg_orignode(msg));
+       msg_set_errcode(rmsg, err);
        msg_set_destport(rmsg, msg_origport(msg));
-       msg_set_prevnode(rmsg, tipc_own_addr);
        msg_set_origport(rmsg, msg_destport(msg));
-       if (msg_short(msg))
+       if (msg_short(msg)) {
                msg_set_orignode(rmsg, tipc_own_addr);
-       else
+               /* leave name type & instance as zeroes */
+       } else {
                msg_set_orignode(rmsg, msg_destnode(msg));
+               msg_set_nametype(rmsg, msg_nametype(msg));
+               msg_set_nameinst(rmsg, msg_nameinst(msg));
+       }
        msg_set_size(rmsg, data_sz + hdr_sz);
-       msg_set_nametype(rmsg, msg_nametype(msg));
-       msg_set_nameinst(rmsg, msg_nameinst(msg));
        skb_copy_to_linear_data_offset(rbuf, hdr_sz, msg_data(msg), data_sz);
 
        /* send self-abort message when rejecting on a connected port */
@@ -778,6 +778,7 @@ void tipc_port_reinit(void)
                msg = &p_ptr->publ.phdr;
                if (msg_orignode(msg) == tipc_own_addr)
                        break;
+               msg_set_prevnode(msg, tipc_own_addr);
                msg_set_orignode(msg, tipc_own_addr);
        }
        spin_unlock_bh(&tipc_port_list_lock);
@@ -838,16 +839,13 @@ static void port_dispatcher_sigh(void *dummy)
                                u32 peer_node = port_peernode(p_ptr);
 
                                tipc_port_unlock(p_ptr);
+                               if (unlikely(!cb))
+                                       goto reject;
                                if (unlikely(!connected)) {
-                                       if (unlikely(published))
+                                       if (tipc_connect2port(dref, &orig))
                                                goto reject;
-                                       tipc_connect2port(dref,&orig);
-                               }
-                               if (unlikely(msg_origport(msg) != peer_port))
-                                       goto reject;
-                               if (unlikely(msg_orignode(msg) != peer_node))
-                                       goto reject;
-                               if (unlikely(!cb))
+                               } else if ((msg_origport(msg) != peer_port) ||
+                                          (msg_orignode(msg) != peer_node))
                                        goto reject;
                                if (unlikely(++p_ptr->publ.conn_unacked >=
                                             TIPC_FLOW_CONTROL_WIN))
@@ -862,9 +860,7 @@ static void port_dispatcher_sigh(void *dummy)
                                tipc_msg_event cb = up_ptr->msg_cb;
 
                                tipc_port_unlock(p_ptr);
-                               if (unlikely(connected))
-                                       goto reject;
-                               if (unlikely(!cb))
+                               if (unlikely(!cb || connected))
                                        goto reject;
                                skb_pull(buf, msg_hdr_sz(msg));
                                cb(usr_handle, dref, &buf, msg_data(msg),
@@ -877,11 +873,7 @@ static void port_dispatcher_sigh(void *dummy)
                                tipc_named_msg_event cb = up_ptr->named_msg_cb;
 
                                tipc_port_unlock(p_ptr);
-                               if (unlikely(connected))
-                                       goto reject;
-                               if (unlikely(!cb))
-                                       goto reject;
-                               if (unlikely(!published))
+                               if (unlikely(!cb || connected || !published))
                                        goto reject;
                                dseq.type =  msg_nametype(msg);
                                dseq.lower = msg_nameinst(msg);
@@ -908,11 +900,10 @@ err:
                                u32 peer_node = port_peernode(p_ptr);
 
                                tipc_port_unlock(p_ptr);
-                               if (!connected || !cb)
-                                       break;
-                               if (msg_origport(msg) != peer_port)
+                               if (!cb || !connected)
                                        break;
-                               if (msg_orignode(msg) != peer_node)
+                               if ((msg_origport(msg) != peer_port) ||
+                                   (msg_orignode(msg) != peer_node))
                                        break;
                                tipc_disconnect(dref);
                                skb_pull(buf, msg_hdr_sz(msg));
@@ -924,7 +915,7 @@ err:
                                tipc_msg_err_event cb = up_ptr->err_cb;
 
                                tipc_port_unlock(p_ptr);
-                               if (connected || !cb)
+                               if (!cb || connected)
                                        break;
                                skb_pull(buf, msg_hdr_sz(msg));
                                cb(usr_handle, dref, &buf, msg_data(msg),
@@ -937,7 +928,7 @@ err:
                                        up_ptr->named_err_cb;
 
                                tipc_port_unlock(p_ptr);
-                               if (connected || !cb)
+                               if (!cb || connected)
                                        break;
                                dseq.type =  msg_nametype(msg);
                                dseq.lower = msg_nameinst(msg);
@@ -1053,6 +1044,7 @@ int tipc_createport(u32 user_ref,
 {
        struct user_port *up_ptr;
        struct port *p_ptr;
+       struct tipc_port *tp_ptr;
        u32 ref;
 
        up_ptr = kmalloc(sizeof(*up_ptr), GFP_ATOMIC);
@@ -1060,12 +1052,13 @@ int tipc_createport(u32 user_ref,
                warn("Port creation failed, no memory\n");
                return -ENOMEM;
        }
-       ref = tipc_createport_raw(NULL, port_dispatcher, port_wakeup, importance);
-       p_ptr = tipc_port_lock(ref);
-       if (!p_ptr) {
+       ref = tipc_createport_raw(NULL, port_dispatcher, port_wakeup,
+                                 importance, &tp_ptr);
+       if (ref == 0) {
                kfree(up_ptr);
                return -ENOMEM;
        }
+       p_ptr = (struct port *)tp_ptr;
 
        p_ptr->user_port = up_ptr;
        up_ptr->user_ref = user_ref;
index 89cbab24d08fb9dbc3dcddbc541aca7112549915..a101de86824d2b1db6e485775d1d1def6bf2c1b7 100644 (file)
@@ -142,9 +142,13 @@ void tipc_ref_table_stop(void)
 /**
  * tipc_ref_acquire - create reference to an object
  *
- * Return a unique reference value which can be translated back to the pointer
- * 'object' at a later time.  Also, pass back a pointer to the lock protecting
- * the object, but without locking it.
+ * Register an object pointer in reference table and lock the object.
+ * Returns a unique reference value that is used from then on to retrieve the
+ * object pointer, or to determine that the object has been deregistered.
+ *
+ * Note: The object is returned in the locked state so that the caller can
+ * register a partially initialized object, without running the risk that
+ * the object will be accessed before initialization is complete.
  */
 
 u32 tipc_ref_acquire(void *object, spinlock_t **lock)
@@ -178,13 +182,13 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock)
                ref = (next_plus_upper & ~index_mask) + index;
                entry->ref = ref;
                entry->object = object;
-               spin_unlock_bh(&entry->lock);
                *lock = &entry->lock;
        }
        else if (tipc_ref_table.init_point < tipc_ref_table.capacity) {
                index = tipc_ref_table.init_point++;
                entry = &(tipc_ref_table.entries[index]);
                spin_lock_init(&entry->lock);
+               spin_lock_bh(&entry->lock);
                ref = tipc_ref_table.start_mask + index;
                entry->ref = ref;
                entry->object = object;
index 230f9ca2ad6b361dd4e78e6a2f1247334e9b9d22..38f48795b40eded00a7a68053dc73eff3b751eb1 100644 (file)
@@ -188,6 +188,7 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol)
        const struct proto_ops *ops;
        socket_state state;
        struct sock *sk;
+       struct tipc_port *tp_ptr;
        u32 portref;
 
        /* Validate arguments */
@@ -225,7 +226,7 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol)
        /* Allocate TIPC port for socket to use */
 
        portref = tipc_createport_raw(sk, &dispatch, &wakeupdispatch,
-                                     TIPC_LOW_IMPORTANCE);
+                                     TIPC_LOW_IMPORTANCE, &tp_ptr);
        if (unlikely(portref == 0)) {
                sk_free(sk);
                return -ENOMEM;
@@ -241,6 +242,8 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol)
        sk->sk_backlog_rcv = backlog_rcv;
        tipc_sk(sk)->p = tipc_get_port(portref);
 
+       spin_unlock_bh(tp_ptr->lock);
+
        if (sock->state == SS_READY) {
                tipc_set_portunreturnable(portref, 1);
                if (sock->type == SOCK_DGRAM)
index 8c01ccd3626ce6cc26a7da35d748c789e29a0053..0326d3060bc7acdea0b0f9f158f92518192a538d 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * net/tipc/subscr.c: TIPC subscription service
+ * net/tipc/subscr.c: TIPC network topology service
  *
  * Copyright (c) 2000-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2007, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 
 #include "core.h"
 #include "dbg.h"
-#include "subscr.h"
 #include "name_table.h"
+#include "port.h"
 #include "ref.h"
+#include "subscr.h"
 
 /**
  * struct subscriber - TIPC network topology subscriber
- * @ref: object reference to subscriber object itself
- * @lock: pointer to spinlock controlling access to subscriber object
+ * @port_ref: object reference to server port connecting to subscriber
+ * @lock: pointer to spinlock controlling access to subscriber's server port
  * @subscriber_list: adjacent subscribers in top. server's list of subscribers
  * @subscription_list: list of subscription objects for this subscriber
- * @port_ref: object reference to port used to communicate with subscriber
- * @swap: indicates if subscriber uses opposite endianness in its messages
  */
 
 struct subscriber {
-       u32 ref;
+       u32 port_ref;
        spinlock_t *lock;
        struct list_head subscriber_list;
        struct list_head subscription_list;
-       u32 port_ref;
-       int swap;
 };
 
 /**
@@ -88,13 +85,14 @@ static struct top_srv topsrv = { 0 };
 
 static u32 htohl(u32 in, int swap)
 {
-       char *c = (char *)&in;
-
-       return swap ? ((c[3] << 3) + (c[2] << 2) + (c[1] << 1) + c[0]) : in;
+       return swap ? (u32)___constant_swab32(in) : in;
 }
 
 /**
  * subscr_send_event - send a message containing a tipc_event to the subscriber
+ *
+ * Note: Must not hold subscriber's server port lock, since tipc_send() will
+ *       try to take the lock if the message is rejected and returned!
  */
 
 static void subscr_send_event(struct subscription *sub,
@@ -109,12 +107,12 @@ static void subscr_send_event(struct subscription *sub,
        msg_sect.iov_base = (void *)&sub->evt;
        msg_sect.iov_len = sizeof(struct tipc_event);
 
-       sub->evt.event = htohl(event, sub->owner->swap);
-       sub->evt.found_lower = htohl(found_lower, sub->owner->swap);
-       sub->evt.found_upper = htohl(found_upper, sub->owner->swap);
-       sub->evt.port.ref = htohl(port_ref, sub->owner->swap);
-       sub->evt.port.node = htohl(node, sub->owner->swap);
-       tipc_send(sub->owner->port_ref, 1, &msg_sect);
+       sub->evt.event = htohl(event, sub->swap);
+       sub->evt.found_lower = htohl(found_lower, sub->swap);
+       sub->evt.found_upper = htohl(found_upper, sub->swap);
+       sub->evt.port.ref = htohl(port_ref, sub->swap);
+       sub->evt.port.node = htohl(node, sub->swap);
+       tipc_send(sub->server_ref, 1, &msg_sect);
 }
 
 /**
@@ -151,13 +149,12 @@ void tipc_subscr_report_overlap(struct subscription *sub,
                                u32 node,
                                int must)
 {
-       dbg("Rep overlap %u:%u,%u<->%u,%u\n", sub->seq.type, sub->seq.lower,
-           sub->seq.upper, found_lower, found_upper);
        if (!tipc_subscr_overlap(sub, found_lower, found_upper))
                return;
        if (!must && !(sub->filter & TIPC_SUB_PORTS))
                return;
-       subscr_send_event(sub, found_lower, found_upper, event, port_ref, node);
+
+       sub->event_cb(sub, found_lower, found_upper, event, port_ref, node);
 }
 
 /**
@@ -166,20 +163,18 @@ void tipc_subscr_report_overlap(struct subscription *sub,
 
 static void subscr_timeout(struct subscription *sub)
 {
-       struct subscriber *subscriber;
-       u32 subscriber_ref;
+       struct port *server_port;
 
-       /* Validate subscriber reference (in case subscriber is terminating) */
+       /* Validate server port reference (in case subscriber is terminating) */
 
-       subscriber_ref = sub->owner->ref;
-       subscriber = (struct subscriber *)tipc_ref_lock(subscriber_ref);
-       if (subscriber == NULL)
+       server_port = tipc_port_lock(sub->server_ref);
+       if (server_port == NULL)
                return;
 
        /* Validate timeout (in case subscription is being cancelled) */
 
        if (sub->timeout == TIPC_WAIT_FOREVER) {
-               tipc_ref_unlock(subscriber_ref);
+               tipc_port_unlock(server_port);
                return;
        }
 
@@ -187,19 +182,21 @@ static void subscr_timeout(struct subscription *sub)
 
        tipc_nametbl_unsubscribe(sub);
 
-       /* Notify subscriber of timeout, then unlink subscription */
+       /* Unlink subscription from subscriber */
 
-       subscr_send_event(sub,
-                         sub->evt.s.seq.lower,
-                         sub->evt.s.seq.upper,
-                         TIPC_SUBSCR_TIMEOUT,
-                         0,
-                         0);
        list_del(&sub->subscription_list);
 
+       /* Release subscriber's server port */
+
+       tipc_port_unlock(server_port);
+
+       /* Notify subscriber of timeout */
+
+       subscr_send_event(sub, sub->evt.s.seq.lower, sub->evt.s.seq.upper,
+                         TIPC_SUBSCR_TIMEOUT, 0, 0);
+
        /* Now destroy subscription */
 
-       tipc_ref_unlock(subscriber_ref);
        k_term_timer(&sub->timer);
        kfree(sub);
        atomic_dec(&topsrv.subscription_count);
@@ -208,7 +205,7 @@ static void subscr_timeout(struct subscription *sub)
 /**
  * subscr_del - delete a subscription within a subscription list
  *
- * Called with subscriber locked.
+ * Called with subscriber port locked.
  */
 
 static void subscr_del(struct subscription *sub)
@@ -222,7 +219,7 @@ static void subscr_del(struct subscription *sub)
 /**
  * subscr_terminate - terminate communication with a subscriber
  *
- * Called with subscriber locked.  Routine must temporarily release this lock
+ * Called with subscriber port locked.  Routine must temporarily release lock
  * to enable subscription timeout routine(s) to finish without deadlocking;
  * the lock is then reclaimed to allow caller to release it upon return.
  * (This should work even in the unlikely event some other thread creates
@@ -232,14 +229,21 @@ static void subscr_del(struct subscription *sub)
 
 static void subscr_terminate(struct subscriber *subscriber)
 {
+       u32 port_ref;
        struct subscription *sub;
        struct subscription *sub_temp;
 
        /* Invalidate subscriber reference */
 
-       tipc_ref_discard(subscriber->ref);
+       port_ref = subscriber->port_ref;
+       subscriber->port_ref = 0;
        spin_unlock_bh(subscriber->lock);
 
+       /* Sever connection to subscriber */
+
+       tipc_shutdown(port_ref);
+       tipc_deleteport(port_ref);
+
        /* Destroy any existing subscriptions for subscriber */
 
        list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list,
@@ -253,27 +257,25 @@ static void subscr_terminate(struct subscriber *subscriber)
                subscr_del(sub);
        }
 
-       /* Sever connection to subscriber */
-
-       tipc_shutdown(subscriber->port_ref);
-       tipc_deleteport(subscriber->port_ref);
-
        /* Remove subscriber from topology server's subscriber list */
 
        spin_lock_bh(&topsrv.lock);
        list_del(&subscriber->subscriber_list);
        spin_unlock_bh(&topsrv.lock);
 
-       /* Now destroy subscriber */
+       /* Reclaim subscriber lock */
 
        spin_lock_bh(subscriber->lock);
+
+       /* Now destroy subscriber */
+
        kfree(subscriber);
 }
 
 /**
  * subscr_cancel - handle subscription cancellation request
  *
- * Called with subscriber locked.  Routine must temporarily release this lock
+ * Called with subscriber port locked.  Routine must temporarily release lock
  * to enable the subscription timeout routine to finish without deadlocking;
  * the lock is then reclaimed to allow caller to release it upon return.
  *
@@ -316,27 +318,25 @@ static void subscr_cancel(struct tipc_subscr *s,
 /**
  * subscr_subscribe - create subscription for subscriber
  *
- * Called with subscriber locked
+ * Called with subscriber port locked.
  */
 
-static void subscr_subscribe(struct tipc_subscr *s,
-                            struct subscriber *subscriber)
+static struct subscription *subscr_subscribe(struct tipc_subscr *s,
+                                            struct subscriber *subscriber)
 {
        struct subscription *sub;
+       int swap;
 
-       /* Determine/update subscriber's endianness */
+       /* Determine subscriber's endianness */
 
-       if (s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE))
-               subscriber->swap = 0;
-       else
-               subscriber->swap = 1;
+       swap = !(s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE));
 
        /* Detect & process a subscription cancellation request */
 
-       if (s->filter & htohl(TIPC_SUB_CANCEL, subscriber->swap)) {
-               s->filter &= ~htohl(TIPC_SUB_CANCEL, subscriber->swap);
+       if (s->filter & htohl(TIPC_SUB_CANCEL, swap)) {
+               s->filter &= ~htohl(TIPC_SUB_CANCEL, swap);
                subscr_cancel(s, subscriber);
-               return;
+               return NULL;
        }
 
        /* Refuse subscription if global limit exceeded */
@@ -345,63 +345,66 @@ static void subscr_subscribe(struct tipc_subscr *s,
                warn("Subscription rejected, subscription limit reached (%u)\n",
                     tipc_max_subscriptions);
                subscr_terminate(subscriber);
-               return;
+               return NULL;
        }
 
        /* Allocate subscription object */
 
-       sub = kzalloc(sizeof(*sub), GFP_ATOMIC);
+       sub = kmalloc(sizeof(*sub), GFP_ATOMIC);
        if (!sub) {
                warn("Subscription rejected, no memory\n");
                subscr_terminate(subscriber);
-               return;
+               return NULL;
        }
 
        /* Initialize subscription object */
 
-       sub->seq.type = htohl(s->seq.type, subscriber->swap);
-       sub->seq.lower = htohl(s->seq.lower, subscriber->swap);
-       sub->seq.upper = htohl(s->seq.upper, subscriber->swap);
-       sub->timeout = htohl(s->timeout, subscriber->swap);
-       sub->filter = htohl(s->filter, subscriber->swap);
+       sub->seq.type = htohl(s->seq.type, swap);
+       sub->seq.lower = htohl(s->seq.lower, swap);
+       sub->seq.upper = htohl(s->seq.upper, swap);
+       sub->timeout = htohl(s->timeout, swap);
+       sub->filter = htohl(s->filter, swap);
        if ((!(sub->filter & TIPC_SUB_PORTS)
             == !(sub->filter & TIPC_SUB_SERVICE))
            || (sub->seq.lower > sub->seq.upper)) {
                warn("Subscription rejected, illegal request\n");
                kfree(sub);
                subscr_terminate(subscriber);
-               return;
+               return NULL;
        }
-       memcpy(&sub->evt.s, s, sizeof(struct tipc_subscr));
-       INIT_LIST_HEAD(&sub->subscription_list);
+       sub->event_cb = subscr_send_event;
        INIT_LIST_HEAD(&sub->nameseq_list);
        list_add(&sub->subscription_list, &subscriber->subscription_list);
+       sub->server_ref = subscriber->port_ref;
+       sub->swap = swap;
+       memcpy(&sub->evt.s, s, sizeof(struct tipc_subscr));
        atomic_inc(&topsrv.subscription_count);
        if (sub->timeout != TIPC_WAIT_FOREVER) {
                k_init_timer(&sub->timer,
                             (Handler)subscr_timeout, (unsigned long)sub);
                k_start_timer(&sub->timer, sub->timeout);
        }
-       sub->owner = subscriber;
-       tipc_nametbl_subscribe(sub);
+
+       return sub;
 }
 
 /**
  * subscr_conn_shutdown_event - handle termination request from subscriber
+ *
+ * Called with subscriber's server port unlocked.
  */
 
 static void subscr_conn_shutdown_event(void *usr_handle,
-                                      u32 portref,
+                                      u32 port_ref,
                                       struct sk_buff **buf,
                                       unsigned char const *data,
                                       unsigned int size,
                                       int reason)
 {
-       struct subscriber *subscriber;
+       struct subscriber *subscriber = usr_handle;
        spinlock_t *subscriber_lock;
 
-       subscriber = tipc_ref_lock((u32)(unsigned long)usr_handle);
-       if (subscriber == NULL)
+       if (tipc_port_lock(port_ref) == NULL)
                return;
 
        subscriber_lock = subscriber->lock;
@@ -411,6 +414,8 @@ static void subscr_conn_shutdown_event(void *usr_handle,
 
 /**
  * subscr_conn_msg_event - handle new subscription request from subscriber
+ *
+ * Called with subscriber's server port unlocked.
  */
 
 static void subscr_conn_msg_event(void *usr_handle,
@@ -419,20 +424,46 @@ static void subscr_conn_msg_event(void *usr_handle,
                                  const unchar *data,
                                  u32 size)
 {
-       struct subscriber *subscriber;
+       struct subscriber *subscriber = usr_handle;
        spinlock_t *subscriber_lock;
+       struct subscription *sub;
+
+       /*
+        * Lock subscriber's server port (& make a local copy of lock pointer,
+        * in case subscriber is deleted while processing subscription request)
+        */
 
-       subscriber = tipc_ref_lock((u32)(unsigned long)usr_handle);
-       if (subscriber == NULL)
+       if (tipc_port_lock(port_ref) == NULL)
                return;
 
        subscriber_lock = subscriber->lock;
-       if (size != sizeof(struct tipc_subscr))
-               subscr_terminate(subscriber);
-       else
-               subscr_subscribe((struct tipc_subscr *)data, subscriber);
 
-       spin_unlock_bh(subscriber_lock);
+       if (size != sizeof(struct tipc_subscr)) {
+               subscr_terminate(subscriber);
+               spin_unlock_bh(subscriber_lock);
+       } else {
+               sub = subscr_subscribe((struct tipc_subscr *)data, subscriber);
+               spin_unlock_bh(subscriber_lock);
+               if (sub != NULL) {
+
+                       /*
+                        * We must release the server port lock before adding a
+                        * subscription to the name table since TIPC needs to be
+                        * able to (re)acquire the port lock if an event message
+                        * issued by the subscription process is rejected and
+                        * returned.  The subscription cannot be deleted while
+                        * it is being added to the name table because:
+                        * a) the single-threading of the native API port code
+                        *    ensures the subscription cannot be cancelled and
+                        *    the subscriber connection cannot be broken, and
+                        * b) the name table lock ensures the subscription
+                        *    timeout code cannot delete the subscription,
+                        * so the subscription object is still protected.
+                        */
+
+                       tipc_nametbl_subscribe(sub);
+               }
+       }
 }
 
 /**
@@ -448,16 +479,10 @@ static void subscr_named_msg_event(void *usr_handle,
                                   struct tipc_portid const *orig,
                                   struct tipc_name_seq const *dest)
 {
-       struct subscriber *subscriber;
-       struct iovec msg_sect = {NULL, 0};
-       spinlock_t *subscriber_lock;
+       static struct iovec msg_sect = {NULL, 0};
 
-       dbg("subscr_named_msg_event: orig = %x own = %x,\n",
-           orig->node, tipc_own_addr);
-       if (size && (size != sizeof(struct tipc_subscr))) {
-               warn("Subscriber rejected, invalid subscription size\n");
-               return;
-       }
+       struct subscriber *subscriber;
+       u32 server_port_ref;
 
        /* Create subscriber object */
 
@@ -468,17 +493,11 @@ static void subscr_named_msg_event(void *usr_handle,
        }
        INIT_LIST_HEAD(&subscriber->subscription_list);
        INIT_LIST_HEAD(&subscriber->subscriber_list);
-       subscriber->ref = tipc_ref_acquire(subscriber, &subscriber->lock);
-       if (subscriber->ref == 0) {
-               warn("Subscriber rejected, reference table exhausted\n");
-               kfree(subscriber);
-               return;
-       }
 
-       /* Establish a connection to subscriber */
+       /* Create server port & establish connection to subscriber */
 
        tipc_createport(topsrv.user_ref,
-                       (void *)(unsigned long)subscriber->ref,
+                       subscriber,
                        importance,
                        NULL,
                        NULL,
@@ -490,32 +509,36 @@ static void subscr_named_msg_event(void *usr_handle,
                        &subscriber->port_ref);
        if (subscriber->port_ref == 0) {
                warn("Subscriber rejected, unable to create port\n");
-               tipc_ref_discard(subscriber->ref);
                kfree(subscriber);
                return;
        }
        tipc_connect2port(subscriber->port_ref, orig);
 
+       /* Lock server port (& save lock address for future use) */
+
+       subscriber->lock = tipc_port_lock(subscriber->port_ref)->publ.lock;
 
        /* Add subscriber to topology server's subscriber list */
 
-       tipc_ref_lock(subscriber->ref);
        spin_lock_bh(&topsrv.lock);
        list_add(&subscriber->subscriber_list, &topsrv.subscriber_list);
        spin_unlock_bh(&topsrv.lock);
 
-       /*
-        * Subscribe now if message contains a subscription,
-        * otherwise send an empty response to complete connection handshaking
-        */
+       /* Unlock server port */
 
-       subscriber_lock = subscriber->lock;
-       if (size)
-               subscr_subscribe((struct tipc_subscr *)data, subscriber);
-       else
-               tipc_send(subscriber->port_ref, 1, &msg_sect);
+       server_port_ref = subscriber->port_ref;
+       spin_unlock_bh(subscriber->lock);
 
-       spin_unlock_bh(subscriber_lock);
+       /* Send an ACK- to complete connection handshaking */
+
+       tipc_send(server_port_ref, 1, &msg_sect);
+
+       /* Handle optional subscription request */
+
+       if (size != 0) {
+               subscr_conn_msg_event(subscriber, server_port_ref,
+                                     buf, data, size);
+       }
 }
 
 int tipc_subscr_start(void)
@@ -574,8 +597,8 @@ void tipc_subscr_stop(void)
                list_for_each_entry_safe(subscriber, subscriber_temp,
                                         &topsrv.subscriber_list,
                                         subscriber_list) {
-                       tipc_ref_lock(subscriber->ref);
                        subscriber_lock = subscriber->lock;
+                       spin_lock_bh(subscriber_lock);
                        subscr_terminate(subscriber);
                        spin_unlock_bh(subscriber_lock);
                }
index 93a8e674fac1dd4ccd370466156fab217f9d2f27..45d89bf4d202b6217b565a5c8e7730a5f6bebcfd 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * net/tipc/subscr.h: Include file for TIPC subscription service
+ * net/tipc/subscr.h: Include file for TIPC network topology service
  *
  * Copyright (c) 2003-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2007, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #ifndef _TIPC_SUBSCR_H
 #define _TIPC_SUBSCR_H
 
+struct subscription;
+
+typedef void (*tipc_subscr_event) (struct subscription *sub,
+                                  u32 found_lower, u32 found_upper,
+                                  u32 event, u32 port_ref, u32 node);
+
 /**
  * struct subscription - TIPC network topology subscription object
  * @seq: name sequence associated with subscription
  * @timeout: duration of subscription (in ms)
  * @filter: event filtering to be done for subscription
- * @evt: template for events generated by subscription
- * @subscription_list: adjacent subscriptions in subscriber's subscription list
+ * @event_cb: routine invoked when a subscription event is detected
+ * @timer: timer governing subscription duration (optional)
  * @nameseq_list: adjacent subscriptions in name sequence's subscription list
- * @timer_ref: reference to timer governing subscription duration (may be NULL)
- * @owner: pointer to subscriber object associated with this subscription
+ * @subscription_list: adjacent subscriptions in subscriber's subscription list
+ * @server_ref: object reference of server port associated with subscription
+ * @swap: indicates if subscriber uses opposite endianness in its messages
+ * @evt: template for events generated by subscription
  */
 
 struct subscription {
        struct tipc_name_seq seq;
        u32 timeout;
        u32 filter;
-       struct tipc_event evt;
-       struct list_head subscription_list;
-       struct list_head nameseq_list;
+       tipc_subscr_event event_cb;
        struct timer_list timer;
-       struct subscriber *owner;
+       struct list_head nameseq_list;
+       struct list_head subscription_list;
+       u32 server_ref;
+       int swap;
+       struct tipc_event evt;
 };
 
-int tipc_subscr_overlap(struct subscription * sub,
+int tipc_subscr_overlap(struct subscription *sub,
                        u32 found_lower,
                        u32 found_upper);
 
-void tipc_subscr_report_overlap(struct subscription * sub,
+void tipc_subscr_report_overlap(struct subscription *sub,
                                u32 found_lower,
                                u32 found_upper,
                                u32 event,
index 9ab31a3ce3ade9c4a40a3dc0f3d34ce3bfe2b192..b210a88d09608f5d776bf4e5196fcfe71adf7ad0 100644 (file)
@@ -350,9 +350,9 @@ __be16 wanrouter_type_trans(struct sk_buff *skb, struct net_device *dev)
  *     o execute requested action or pass command to the device driver
  */
 
-int wanrouter_ioctl(struct inode *inode, struct file *file,
-               unsigned int cmd, unsigned long arg)
+long wanrouter_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
+       struct inode *inode = file->f_path.dentry->d_inode;
        int err = 0;
        struct proc_dir_entry *dent;
        struct wan_device *wandev;
@@ -372,6 +372,7 @@ int wanrouter_ioctl(struct inode *inode, struct file *file,
        if (wandev->magic != ROUTER_MAGIC)
                return -EINVAL;
 
+       lock_kernel();
        switch (cmd) {
        case ROUTER_SETUP:
                err = wanrouter_device_setup(wandev, data);
@@ -403,6 +404,7 @@ int wanrouter_ioctl(struct inode *inode, struct file *file,
                        err = wandev->ioctl(wandev, cmd, arg);
                else err = -EINVAL;
        }
+       unlock_kernel();
        return err;
 }
 
index 5bebe40bf4e68584d7531eca76e89957381d2adb..267f7ff498270e3f397430d20f72cf151fb2217e 100644 (file)
@@ -278,7 +278,7 @@ static const struct file_operations wandev_fops = {
        .read    = seq_read,
        .llseek  = seq_lseek,
        .release = single_release,
-       .ioctl   = wanrouter_ioctl,
+       .unlocked_ioctl  = wanrouter_ioctl,
 };
 
 /*
index 80afacdae46c5540b0a49b01708da4c1f7b64142..f1da0b93bc56d177cae4d350ce470c29c1e4da4c 100644 (file)
@@ -143,8 +143,11 @@ void cfg80211_put_dev(struct cfg80211_registered_device *drv)
 int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
                        char *newname)
 {
+       struct cfg80211_registered_device *drv;
        int idx, taken = -1, result, digits;
 
+       mutex_lock(&cfg80211_drv_mutex);
+
        /* prohibit calling the thing phy%d when %d is not its number */
        sscanf(newname, PHY_NAME "%d%n", &idx, &taken);
        if (taken == strlen(newname) && idx != rdev->idx) {
@@ -156,14 +159,30 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
                 * deny the name if it is phy<idx> where <idx> is printed
                 * without leading zeroes. taken == strlen(newname) here
                 */
+               result = -EINVAL;
                if (taken == strlen(PHY_NAME) + digits)
-                       return -EINVAL;
+                       goto out_unlock;
+       }
+
+
+       /* Ignore nop renames */
+       result = 0;
+       if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0)
+               goto out_unlock;
+
+       /* Ensure another device does not already have this name. */
+       list_for_each_entry(drv, &cfg80211_drv_list, list) {
+               result = -EINVAL;
+               if (strcmp(newname, dev_name(&drv->wiphy.dev)) == 0)
+                       goto out_unlock;
        }
 
-       /* this will check for collisions */
+       /* this will only check for collisions in sysfs
+        * which is not even always compiled in.
+        */
        result = device_rename(&rdev->wiphy.dev, newname);
        if (result)
-               return result;
+               goto out_unlock;
 
        if (!debugfs_rename(rdev->wiphy.debugfsdir->d_parent,
                            rdev->wiphy.debugfsdir,
@@ -172,9 +191,13 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
                printk(KERN_ERR "cfg80211: failed to rename debugfs dir to %s!\n",
                       newname);
 
-       nl80211_notify_dev_rename(rdev);
+       result = 0;
+out_unlock:
+       mutex_unlock(&cfg80211_drv_mutex);
+       if (result == 0)
+               nl80211_notify_dev_rename(rdev);
 
-       return 0;
+       return result;
 }
 
 /* exported functions */
index 28fbd0b0b5688c23462641d9eeb5f918ae93be9c..f591871a7b4fe137604577d0ae0d561d5e6c8f1d 100644 (file)
@@ -59,23 +59,21 @@ int ieee80211_radiotap_iterator_init(
                return -EINVAL;
 
        /* sanity check for allowed length and radiotap length field */
-       if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len)))
+       if (max_length < get_unaligned_le16(&radiotap_header->it_len))
                return -EINVAL;
 
        iterator->rtheader = radiotap_header;
-       iterator->max_length = le16_to_cpu(get_unaligned(
-                                               &radiotap_header->it_len));
+       iterator->max_length = get_unaligned_le16(&radiotap_header->it_len);
        iterator->arg_index = 0;
-       iterator->bitmap_shifter = le32_to_cpu(get_unaligned(
-                                               &radiotap_header->it_present));
+       iterator->bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present);
        iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header);
        iterator->this_arg = NULL;
 
        /* find payload start allowing for extended bitmap(s) */
 
        if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) {
-               while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) &
-                                  (1<<IEEE80211_RADIOTAP_EXT)) {
+               while (get_unaligned_le32(iterator->arg) &
+                      (1 << IEEE80211_RADIOTAP_EXT)) {
                        iterator->arg += sizeof(u32);
 
                        /*
@@ -241,8 +239,8 @@ int ieee80211_radiotap_iterator_next(
                        if (iterator->bitmap_shifter & 1) {
                                /* b31 was set, there is more */
                                /* move to next u32 bitmap */
-                               iterator->bitmap_shifter = le32_to_cpu(
-                                       get_unaligned(iterator->next_bitmap));
+                               iterator->bitmap_shifter =
+                                   get_unaligned_le32(iterator->next_bitmap);
                                iterator->next_bitmap++;
                        } else
                                /* no more bitmaps: end */