Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
authorDavid S. Miller <davem@davemloft.net>
Mon, 26 May 2008 06:26:10 +0000 (23:26 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 26 May 2008 06:26:10 +0000 (23:26 -0700)
Conflicts:

drivers/net/cpmac.c
net/mac80211/mlme.c

203 files changed:
drivers/net/3c523.c
drivers/net/3c527.c
drivers/net/8139cp.c
drivers/net/8139too.c
drivers/net/8390.h
drivers/net/acenic.c
drivers/net/acenic.h
drivers/net/bnx2.c
drivers/net/bnx2.h
drivers/net/bnx2_fw.h
drivers/net/dm9000.c
drivers/net/gianfar.c
drivers/net/hamradio/6pack.c
drivers/net/lib8390.c
drivers/net/natsemi.c
drivers/net/niu.h
drivers/net/pcmcia/3c574_cs.c
drivers/net/pcmcia/3c589_cs.c
drivers/net/pcmcia/axnet_cs.c
drivers/net/pcnet32.c
drivers/net/qla3xxx.c
drivers/net/s2io.c
drivers/net/s2io.h
drivers/net/sb1250-mac.c
drivers/net/sis190.c
drivers/net/sis900.c
drivers/net/sky2.c
drivers/net/spider_net.c
drivers/net/tokenring/3c359.c
drivers/net/tokenring/3c359.h
drivers/net/tsi108_eth.c
drivers/net/ucc_geth_ethtool.c
drivers/net/wireless/adm8211.c
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/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/xmit.c
drivers/net/wireless/b43legacy/b43legacy.h
drivers/net/wireless/b43legacy/dma.c
drivers/net/wireless/b43legacy/main.c
drivers/net/wireless/b43legacy/phy.c
drivers/net/wireless/b43legacy/pio.c
drivers/net/wireless/b43legacy/radio.c
drivers/net/wireless/b43legacy/xmit.c
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-commands.h [deleted file]
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-4965.h [deleted file]
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 [new file with mode: 0644]
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 [new file with mode: 0644]
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-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/cmd.c
drivers/net/wireless/libertas/cmd.h
drivers/net/wireless/libertas/decl.h
drivers/net/wireless/libertas/main.c
drivers/net/wireless/p54/p54.h
drivers/net/wireless/p54/p54common.c
drivers/net/wireless/rt2x00/Kconfig
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00dev.c
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/rt2x00usb.c
drivers/net/wireless/rt2x00/rt2x00usb.h
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rtl8180_dev.c
drivers/net/wireless/rtl8187_dev.c
drivers/net/wireless/zd1211rw/zd_mac.c
drivers/ssb/pci.c
include/linux/ieee80211.h
include/linux/tipc_config.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/sctp/sctp.h
include/net/sctp/structs.h
include/net/sctp/user.h
include/net/tipc/tipc_port.h
net/bridge/br_device.c
net/bridge/br_forward.c
net/bridge/br_input.c
net/bridge/br_private.h
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/ipv6/ip6_tunnel.c
net/ipv6/ip6mr.c
net/ipv6/reassembly.c
net/ipv6/sit.c
net/ipv6/sysctl_net_ipv6.c
net/mac80211/aes_ccm.c
net/mac80211/aes_ccm.h
net/mac80211/cfg.c
net/mac80211/debugfs.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/main.c
net/mac80211/mesh_hwmp.c
net/mac80211/mesh_plink.c
net/mac80211/mlme.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/wep.c
net/mac80211/wep.h
net/mac80211/wext.c
net/mac80211/wme.c
net/mac80211/wpa.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/config.c
net/tipc/core.c
net/tipc/core.h
net/tipc/dbg.c
net/tipc/dbg.h
net/tipc/discover.c
net/tipc/link.c
net/tipc/msg.c
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/wireless/core.c
net/wireless/radiotap.c

index 239fc42..dc6e474 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 fae295b..6aca0c6 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 a453eda..934db35 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 53bd903..b23a00c 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 04ddec0..cf020d4 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 6c19265..e4483de 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 60ed183..4487f32 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 4b46e68..b32d227 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 1eaf5bb..16020a1 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 3b839d4..e4b1de4 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 864295e..08a7365 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 25bdd08..393a0f1 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 9d57212..06ad9f3 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 0c5447d..ed49527 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 46119bb..b238ed0 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 12fd570..c6fa883 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 3b78a38..7112fd5 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 1b1abb1..549a645 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 ce95c5d..d7018ff 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 1c89b97..ca8c0e0 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 b7f7b22..5f60878 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 a20693e..326c941 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;
index 4706f7f..d0a84ba 100644 (file)
@@ -752,7 +752,7 @@ struct ring_info {
 
        /* interface MTU value */
         unsigned mtu;
-    
+
        /* Buffer Address store. */
        struct buffAdd **ba;
 
index 33bb18f..fe41e4e 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 abc63b0..3fe0176 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 ec95e49..fa3a460 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 3bb6053..535f6cc 100644 (file)
@@ -3378,7 +3378,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) |
index 4776716..00aa0b1 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 45208a0..7766cde 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 74cf8e1..66b1ff6 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 6017d52..c028fac 100644 (file)
@@ -1526,7 +1526,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 +1543,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 299b7f1..5f176f2 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.
  *
@@ -159,7 +159,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 5c0d2b0..7af5d88 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;
 }
@@ -446,9 +445,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;
 
@@ -1894,9 +1893,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 */
 
index 4e1c690..17ced37 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 dbdfc9e..dec5e87 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 3ed1df7..fb3ad51 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 635b9ac..c76ada1 100644 (file)
@@ -458,13 +458,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;
@@ -1319,7 +1317,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
        pktlen = skb->len;
 
        if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) {
-               keyidx = ctl->key_idx;
+               keyidx = ctl->hw_key->hw_key_idx;
                pktlen += ctl->icv_len;
        }
 
@@ -1335,7 +1333,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 +1564,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);
@@ -1895,20 +1893,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);
@@ -1981,10 +1968,10 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
                }
 
                ieee80211_tx_status(sc->hw, skb, &txs);
-               sc->tx_stats.data[txq->qnum].count++;
+               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);
index 3a97558..ecb1749 100644 (file)
@@ -92,7 +92,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 ef2da40..f978a9d 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 37783cd..0c2bc06 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 | \
@@ -940,22 +939,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 7fca2eb..210e278 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 6eebe85..c75cff4 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 6dcbb3c..f50e201 100644 (file)
@@ -1427,18 +1427,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 d890f36..9c854d6 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 455615d..1da321c 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 8fdba94..fc23ba5 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]];
@@ -2308,7 +2308,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);
@@ -2322,16 +2322,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;
@@ -2340,14 +2335,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)
@@ -2503,6 +2490,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 */
 }
 
@@ -2609,28 +2597,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);
@@ -2682,6 +2654,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);
@@ -2693,8 +2666,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)
@@ -3025,8 +2996,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);
@@ -3668,8 +3638,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;
@@ -4496,10 +4466,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 5230aec..dad23c4 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 8695eb2..644eed9 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 de024dc..305d4cd 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 6d165d8..4aab109 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 fcacafb..08c8a08 100644 (file)
@@ -611,18 +611,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 19aefbf..afce933 100644 (file)
@@ -235,7 +235,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
 
        plcp_fragment_len = fragment_len + FCS_LEN;
        if (use_encryption) {
-               u8 key_idx = (u16) (txctl->key_idx);
+               u8 key_idx = txctl->hw_key->hw_key_idx;
                struct b43_key *key;
                int wlhdr_len;
                size_t iv_len;
@@ -581,12 +581,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)
index ded3cd3..c40078e 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 c990f87..d6686f7 100644 (file)
@@ -1455,18 +1455,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 14a5eea..7755c59 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]];
@@ -2383,8 +2383,7 @@ out:
        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;
@@ -3719,10 +3718,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 8e5c09b..768cccb 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 bcdd54e..8d3d27d 100644 (file)
@@ -525,13 +525,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 955832e..2df545c 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 dcad249..bed9e04 100644 (file)
@@ -232,7 +232,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
 
        plcp_fragment_len = fragment_len + FCS_LEN;
        if (use_encryption) {
-               u8 key_idx = (u16)(txctl->key_idx);
+               u8 key_idx = txctl->hw_key->hw_key_idx;
                struct b43legacy_key *key;
                int wlhdr_len;
                size_t iv_len;
@@ -532,12 +532,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 62fb89d..5f3e849 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 ec6187b..5c73eed 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 ad612a8..644bd9e 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 85c2264..e51eeef 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>
index 62a3d8f..ad4e7b7 100644 (file)
@@ -520,7 +520,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 +693,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 +712,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 +736,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 +748,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;
        }
 
@@ -1229,7 +1229,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 c7695a2..9fdc140 100644 (file)
@@ -886,6 +886,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 +925,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;
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h
deleted file mode 100644 (file)
index 3bcd107..0000000
+++ /dev/null
@@ -1,2716 +0,0 @@
-/******************************************************************************
- *
- * 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.
- *
- *****************************************************************************/
-/*
- * Please use this file (iwl-4965-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.
- */
-
-#ifndef __iwl4965_commands_h__
-#define __iwl4965_commands_h__
-
-enum {
-       REPLY_ALIVE = 0x1,
-       REPLY_ERROR = 0x2,
-
-       /* RXON and QOS commands */
-       REPLY_RXON = 0x10,
-       REPLY_RXON_ASSOC = 0x11,
-       REPLY_QOS_PARAM = 0x13,
-       REPLY_RXON_TIMING = 0x14,
-
-       /* Multi-Station support */
-       REPLY_ADD_STA = 0x18,
-       REPLY_REMOVE_STA = 0x19,        /* not used */
-       REPLY_REMOVE_ALL_STA = 0x1a,    /* not used */
-
-       /* Security */
-       REPLY_WEPKEY = 0x20,
-
-       /* RX, TX, LEDs */
-       REPLY_TX = 0x1c,
-       REPLY_RATE_SCALE = 0x47,        /* 3945 only */
-       REPLY_LEDS_CMD = 0x48,
-       REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */
-
-       /* 802.11h related */
-       RADAR_NOTIFICATION = 0x70,      /* not used */
-       REPLY_QUIET_CMD = 0x71,         /* not used */
-       REPLY_CHANNEL_SWITCH = 0x72,
-       CHANNEL_SWITCH_NOTIFICATION = 0x73,
-       REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74,
-       SPECTRUM_MEASURE_NOTIFICATION = 0x75,
-
-       /* Power Management */
-       POWER_TABLE_CMD = 0x77,
-       PM_SLEEP_NOTIFICATION = 0x7A,
-       PM_DEBUG_STATISTIC_NOTIFIC = 0x7B,
-
-       /* Scan commands and notifications */
-       REPLY_SCAN_CMD = 0x80,
-       REPLY_SCAN_ABORT_CMD = 0x81,
-       SCAN_START_NOTIFICATION = 0x82,
-       SCAN_RESULTS_NOTIFICATION = 0x83,
-       SCAN_COMPLETE_NOTIFICATION = 0x84,
-
-       /* IBSS/AP commands */
-       BEACON_NOTIFICATION = 0x90,
-       REPLY_TX_BEACON = 0x91,
-       WHO_IS_AWAKE_NOTIFICATION = 0x94,       /* not used */
-
-       /* Miscellaneous commands */
-       QUIET_NOTIFICATION = 0x96,              /* not used */
-       REPLY_TX_PWR_TABLE_CMD = 0x97,
-       MEASURE_ABORT_NOTIFICATION = 0x99,      /* not used */
-
-       /* Bluetooth device coexistance config command */
-       REPLY_BT_CONFIG = 0x9b,
-
-       /* Statistics */
-       REPLY_STATISTICS_CMD = 0x9c,
-       STATISTICS_NOTIFICATION = 0x9d,
-
-       /* RF-KILL commands and notifications */
-       REPLY_CARD_STATE_CMD = 0xa0,
-       CARD_STATE_NOTIFICATION = 0xa1,
-
-       /* Missed beacons notification */
-       MISSED_BEACONS_NOTIFICATION = 0xa2,
-
-       REPLY_CT_KILL_CONFIG_CMD = 0xa4,
-       SENSITIVITY_CMD = 0xa8,
-       REPLY_PHY_CALIBRATION_CMD = 0xb0,
-       REPLY_RX_PHY_CMD = 0xc0,
-       REPLY_RX_MPDU_CMD = 0xc1,
-       REPLY_RX = 0xc3,
-       REPLY_COMPRESSED_BA = 0xc5,
-       REPLY_MAX = 0xff
-};
-
-/******************************************************************************
- * (0)
- * Commonly used structures and definitions:
- * Command header, rate_n_flags, txpower
- *
- *****************************************************************************/
-
-/* iwl_cmd_header flags value */
-#define IWL_CMD_FAILED_MSK 0x40
-
-/**
- * struct iwl_cmd_header
- *
- * This header format appears in the beginning of each command sent from the
- * driver, and each response/notification received from uCode.
- */
-struct iwl_cmd_header {
-       u8 cmd;         /* Command ID:  REPLY_RXON, etc. */
-       u8 flags;       /* IWL_CMD_* */
-       /*
-        * The driver sets up the sequence number to values of its chosing.
-        * uCode does not use this value, but passes it back to the driver
-        * when sending the response to each driver-originated command, so
-        * the driver can match the response to the command.  Since the values
-        * don't get used by uCode, the driver may set up an arbitrary format.
-        *
-        * There is one exception:  uCode sets bit 15 when it originates
-        * the response/notification, i.e. when the response/notification
-        * is not a direct response to a command sent by the driver.  For
-        * example, uCode issues REPLY_3945_RX when it sends a received frame
-        * to the driver; it is not a direct response to any driver command.
-        *
-        * The Linux driver uses the following format:
-        *
-        *  0:7    index/position within Tx queue
-        *  8:13   Tx queue selection
-        * 14:14   driver sets this to indicate command is in the 'huge'
-        *         storage at the end of the command buffers, i.e. scan cmd
-        * 15:15   uCode sets this in uCode-originated response/notification
-        */
-       __le16 sequence;
-
-       /* command or response/notification data follows immediately */
-       u8 data[0];
-} __attribute__ ((packed));
-
-/**
- * 4965 rate_n_flags bit fields
- *
- * rate_n_flags format is used in following 4965 commands:
- *  REPLY_RX (response only)
- *  REPLY_TX (both command and response)
- *  REPLY_TX_LINK_QUALITY_CMD
- *
- * High-throughput (HT) rate format for bits 7:0 (bit 8 must be "1"):
- *  2-0:  0)   6 Mbps
- *        1)  12 Mbps
- *        2)  18 Mbps
- *        3)  24 Mbps
- *        4)  36 Mbps
- *        5)  48 Mbps
- *        6)  54 Mbps
- *        7)  60 Mbps
- *
- *    3:  0)  Single stream (SISO)
- *        1)  Dual stream (MIMO)
- *
- *    5:  Value of 0x20 in bits 7:0 indicates 6 Mbps FAT duplicate data
- *
- * Legacy OFDM rate format for bits 7:0 (bit 8 must be "0", bit 9 "0"):
- *  3-0:  0xD)   6 Mbps
- *        0xF)   9 Mbps
- *        0x5)  12 Mbps
- *        0x7)  18 Mbps
- *        0x9)  24 Mbps
- *        0xB)  36 Mbps
- *        0x1)  48 Mbps
- *        0x3)  54 Mbps
- *
- * Legacy CCK rate format for bits 7:0 (bit 8 must be "0", bit 9 "1"):
- *  3-0:   10)  1 Mbps
- *         20)  2 Mbps
- *         55)  5.5 Mbps
- *        110)  11 Mbps
- */
-#define RATE_MCS_CODE_MSK 0x7
-#define RATE_MCS_MIMO_POS 3
-#define RATE_MCS_MIMO_MSK 0x8
-#define RATE_MCS_HT_DUP_POS 5
-#define RATE_MCS_HT_DUP_MSK 0x20
-
-/* Bit 8: (1) HT format, (0) legacy format in bits 7:0 */
-#define RATE_MCS_FLAGS_POS 8
-#define RATE_MCS_HT_POS 8
-#define RATE_MCS_HT_MSK 0x100
-
-/* Bit 9: (1) CCK, (0) OFDM.  HT (bit 8) must be "0" for this bit to be valid */
-#define RATE_MCS_CCK_POS 9
-#define RATE_MCS_CCK_MSK 0x200
-
-/* Bit 10: (1) Use Green Field preamble */
-#define RATE_MCS_GF_POS 10
-#define RATE_MCS_GF_MSK 0x400
-
-/* Bit 11: (1) Use 40Mhz FAT chnl width, (0) use 20 MHz legacy chnl width */
-#define RATE_MCS_FAT_POS 11
-#define RATE_MCS_FAT_MSK 0x800
-
-/* Bit 12: (1) Duplicate data on both 20MHz chnls.  FAT (bit 11) must be set. */
-#define RATE_MCS_DUP_POS 12
-#define RATE_MCS_DUP_MSK 0x1000
-
-/* Bit 13: (1) Short guard interval (0.4 usec), (0) normal GI (0.8 usec) */
-#define RATE_MCS_SGI_POS 13
-#define RATE_MCS_SGI_MSK 0x2000
-
-/**
- * rate_n_flags Tx antenna masks (4965 has 2 transmitters):
- * bit14:15 01 B inactive, A active
- *          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
-
-
-/**
- * struct iwl4965_tx_power - txpower format used in REPLY_SCAN_CMD
- *
- * Scan uses only one transmitter, so only one analog/dsp gain pair is needed.
- */
-struct iwl4965_tx_power {
-       u8 tx_gain;             /* gain for analog radio */
-       u8 dsp_atten;           /* gain for DSP */
-} __attribute__ ((packed));
-
-#define POWER_TABLE_NUM_ENTRIES                        33
-#define POWER_TABLE_NUM_HT_OFDM_ENTRIES                32
-#define POWER_TABLE_CCK_ENTRY                  32
-
-/**
- * union iwl4965_tx_power_dual_stream
- *
- * Host format used for REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
- * Use __le32 version (struct tx_power_dual_stream) when building command.
- *
- * Driver provides radio gain and DSP attenuation settings to device in pairs,
- * one value for each transmitter chain.  The first value is for transmitter A,
- * second for transmitter B.
- *
- * For SISO bit rates, both values in a pair should be identical.
- * For MIMO rates, one value may be different from the other,
- * in order to balance the Tx output between the two transmitters.
- *
- * See more details in doc for TXPOWER in iwl-4965-hw.h.
- */
-union iwl4965_tx_power_dual_stream {
-       struct {
-               u8 radio_tx_gain[2];
-               u8 dsp_predis_atten[2];
-       } s;
-       u32 dw;
-};
-
-/**
- * struct tx_power_dual_stream
- *
- * Table entries in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
- *
- * Same format as iwl_tx_power_dual_stream, but __le32
- */
-struct tx_power_dual_stream {
-       __le32 dw;
-} __attribute__ ((packed));
-
-/**
- * struct iwl4965_tx_power_db
- *
- * Entire table within REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
- */
-struct iwl4965_tx_power_db {
-       struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES];
-} __attribute__ ((packed));
-
-
-/******************************************************************************
- * (0a)
- * Alive and Error Commands & Responses:
- *
- *****************************************************************************/
-
-#define UCODE_VALID_OK __constant_cpu_to_le32(0x1)
-#define INITIALIZE_SUBTYPE    (9)
-
-/*
- * ("Initialize") REPLY_ALIVE = 0x1 (response only, not a command)
- *
- * uCode issues this "initialize alive" notification once the initialization
- * uCode image has completed its work, and is ready to load the runtime image.
- * This is the *first* "alive" notification that the driver will receive after
- * rebooting uCode; the "initialize" alive is indicated by subtype field == 9.
- *
- * See comments documenting "BSM" (bootstrap state machine).
- *
- * For 4965, this notification contains important calibration data for
- * calculating txpower settings:
- *
- * 1)  Power supply voltage indication.  The voltage sensor outputs higher
- *     values for lower voltage, and vice versa.
- *
- * 2)  Temperature measurement parameters, for each of two channel widths
- *     (20 MHz and 40 MHz) supported by the radios.  Temperature sensing
- *     is done via one of the receiver chains, and channel width influences
- *     the results.
- *
- * 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 {
-       u8 ucode_minor;
-       u8 ucode_major;
-       __le16 reserved1;
-       u8 sw_rev[8];
-       u8 ver_type;
-       u8 ver_subtype;         /* "9" for initialize alive */
-       __le16 reserved2;
-       __le32 log_event_table_ptr;
-       __le32 error_event_table_ptr;
-       __le32 timestamp;
-       __le32 is_valid;
-
-       /* calibration values from "initialize" uCode */
-       __le32 voltage;         /* signed, higher value is lower voltage */
-       __le32 therm_r1[2];     /* signed, 1st for normal, 2nd for FAT channel*/
-       __le32 therm_r2[2];     /* signed */
-       __le32 therm_r3[2];     /* signed */
-       __le32 therm_r4[2];     /* signed */
-       __le32 tx_atten[5][2];  /* signed MIMO gain comp, 5 freq groups,
-                                * 2 Tx chains */
-} __attribute__ ((packed));
-
-
-/**
- * REPLY_ALIVE = 0x1 (response only, not a command)
- *
- * uCode issues this "alive" notification once the runtime image is ready
- * to receive commands from the driver.  This is the *second* "alive"
- * notification that the driver will receive after rebooting uCode;
- * this "alive" is indicated by subtype field != 9.
- *
- * See comments documenting "BSM" (bootstrap state machine).
- *
- * This response includes two pointers to structures within the device's
- * data SRAM (access via HBUS_TARG_MEM_* regs) that are useful for debugging:
- *
- * 1)  log_event_table_ptr indicates base of the event log.  This traces
- *     a 256-entry history of uCode execution within a circular buffer.
- *     Its header format is:
- *
- *     __le32 log_size;     log capacity (in number of entries)
- *     __le32 type;         (1) timestamp with each entry, (0) no timestamp
- *     __le32 wraps;        # times uCode has wrapped to top of circular buffer
- *      __le32 write_index;  next circular buffer entry that uCode would fill
- *
- *     The header is followed by the circular buffer of log entries.  Entries
- *     with timestamps have the following format:
- *
- *     __le32 event_id;     range 0 - 1500
- *     __le32 timestamp;    low 32 bits of TSF (of network, if associated)
- *     __le32 data;         event_id-specific data value
- *
- *     Entries without timestamps contain only event_id and data.
- *
- * 2)  error_event_table_ptr indicates base of the error log.  This contains
- *     information about any uCode error that occurs.  For 4965, the format
- *     of the error log is:
- *
- *     __le32 valid;        (nonzero) valid, (0) log is empty
- *     __le32 error_id;     type of error
- *     __le32 pc;           program counter
- *     __le32 blink1;       branch link
- *     __le32 blink2;       branch link
- *     __le32 ilink1;       interrupt link
- *     __le32 ilink2;       interrupt link
- *     __le32 data1;        error-specific data
- *     __le32 data2;        error-specific data
- *     __le32 line;         source code line of error
- *     __le32 bcon_time;    beacon timer
- *     __le32 tsf_low;      network timestamp function timer
- *     __le32 tsf_hi;       network timestamp function timer
- *
- * The Linux driver can print both logs to the system log when a uCode error
- * occurs.
- */
-struct iwl4965_alive_resp {
-       u8 ucode_minor;
-       u8 ucode_major;
-       __le16 reserved1;
-       u8 sw_rev[8];
-       u8 ver_type;
-       u8 ver_subtype;                 /* not "9" for runtime alive */
-       __le16 reserved2;
-       __le32 log_event_table_ptr;     /* SRAM address for event log */
-       __le32 error_event_table_ptr;   /* SRAM address for error log */
-       __le32 timestamp;
-       __le32 is_valid;
-} __attribute__ ((packed));
-
-
-union tsf {
-       u8 byte[8];
-       __le16 word[4];
-       __le32 dw[2];
-};
-
-/*
- * REPLY_ERROR = 0x2 (response only, not a command)
- */
-struct iwl4965_error_resp {
-       __le32 error_type;
-       u8 cmd_id;
-       u8 reserved1;
-       __le16 bad_cmd_seq_num;
-       __le32 error_info;
-       union tsf timestamp;
-} __attribute__ ((packed));
-
-/******************************************************************************
- * (1)
- * RXON Commands & Responses:
- *
- *****************************************************************************/
-
-/*
- * Rx config defines & structure
- */
-/* rx_config device types  */
-enum {
-       RXON_DEV_TYPE_AP = 1,
-       RXON_DEV_TYPE_ESS = 3,
-       RXON_DEV_TYPE_IBSS = 4,
-       RXON_DEV_TYPE_SNIFFER = 6,
-};
-
-
-#define RXON_RX_CHAIN_DRIVER_FORCE_MSK         __constant_cpu_to_le16(0x1 << 0)
-#define RXON_RX_CHAIN_VALID_MSK                        __constant_cpu_to_le16(0x7 << 1)
-#define RXON_RX_CHAIN_VALID_POS                        (1)
-#define RXON_RX_CHAIN_FORCE_SEL_MSK            __constant_cpu_to_le16(0x7 << 4)
-#define RXON_RX_CHAIN_FORCE_SEL_POS            (4)
-#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK       __constant_cpu_to_le16(0x7 << 7)
-#define RXON_RX_CHAIN_FORCE_MIMO_SEL_POS       (7)
-#define RXON_RX_CHAIN_CNT_MSK                  __constant_cpu_to_le16(0x3 << 10)
-#define RXON_RX_CHAIN_CNT_POS                  (10)
-#define RXON_RX_CHAIN_MIMO_CNT_MSK             __constant_cpu_to_le16(0x3 << 12)
-#define RXON_RX_CHAIN_MIMO_CNT_POS             (12)
-#define RXON_RX_CHAIN_MIMO_FORCE_MSK           __constant_cpu_to_le16(0x1 << 14)
-#define RXON_RX_CHAIN_MIMO_FORCE_POS           (14)
-
-/* rx_config flags */
-/* band & modulation selection */
-#define RXON_FLG_BAND_24G_MSK           __constant_cpu_to_le32(1 << 0)
-#define RXON_FLG_CCK_MSK                __constant_cpu_to_le32(1 << 1)
-/* auto detection enable */
-#define RXON_FLG_AUTO_DETECT_MSK        __constant_cpu_to_le32(1 << 2)
-/* TGg protection when tx */
-#define RXON_FLG_TGG_PROTECT_MSK        __constant_cpu_to_le32(1 << 3)
-/* cck short slot & preamble */
-#define RXON_FLG_SHORT_SLOT_MSK          __constant_cpu_to_le32(1 << 4)
-#define RXON_FLG_SHORT_PREAMBLE_MSK     __constant_cpu_to_le32(1 << 5)
-/* antenna selection */
-#define RXON_FLG_DIS_DIV_MSK            __constant_cpu_to_le32(1 << 7)
-#define RXON_FLG_ANT_SEL_MSK            __constant_cpu_to_le32(0x0f00)
-#define RXON_FLG_ANT_A_MSK              __constant_cpu_to_le32(1 << 8)
-#define RXON_FLG_ANT_B_MSK              __constant_cpu_to_le32(1 << 9)
-/* radar detection enable */
-#define RXON_FLG_RADAR_DETECT_MSK       __constant_cpu_to_le32(1 << 12)
-#define RXON_FLG_TGJ_NARROW_BAND_MSK    __constant_cpu_to_le32(1 << 13)
-/* rx response to host with 8-byte TSF
-* (according to ON_AIR deassertion) */
-#define RXON_FLG_TSF2HOST_MSK           __constant_cpu_to_le32(1 << 15)
-
-
-/* HT flags */
-#define RXON_FLG_CTRL_CHANNEL_LOC_POS          (22)
-#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK       __constant_cpu_to_le32(0x1 << 22)
-
-#define RXON_FLG_HT_OPERATING_MODE_POS         (23)
-
-#define RXON_FLG_HT_PROT_MSK                   __constant_cpu_to_le32(0x1 << 23)
-#define RXON_FLG_FAT_PROT_MSK                  __constant_cpu_to_le32(0x2 << 23)
-
-#define RXON_FLG_CHANNEL_MODE_POS              (25)
-#define RXON_FLG_CHANNEL_MODE_MSK              __constant_cpu_to_le32(0x3 << 25)
-#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK      __constant_cpu_to_le32(0x1 << 25)
-#define RXON_FLG_CHANNEL_MODE_MIXED_MSK                __constant_cpu_to_le32(0x2 << 25)
-
-/* rx_config filter flags */
-/* accept all data frames */
-#define RXON_FILTER_PROMISC_MSK         __constant_cpu_to_le32(1 << 0)
-/* pass control & management to host */
-#define RXON_FILTER_CTL2HOST_MSK        __constant_cpu_to_le32(1 << 1)
-/* accept multi-cast */
-#define RXON_FILTER_ACCEPT_GRP_MSK      __constant_cpu_to_le32(1 << 2)
-/* don't decrypt uni-cast frames */
-#define RXON_FILTER_DIS_DECRYPT_MSK     __constant_cpu_to_le32(1 << 3)
-/* don't decrypt multi-cast frames */
-#define RXON_FILTER_DIS_GRP_DECRYPT_MSK __constant_cpu_to_le32(1 << 4)
-/* STA is associated */
-#define RXON_FILTER_ASSOC_MSK           __constant_cpu_to_le32(1 << 5)
-/* transfer to host non bssid beacons in associated state */
-#define RXON_FILTER_BCON_AWARE_MSK      __constant_cpu_to_le32(1 << 6)
-
-/**
- * REPLY_RXON = 0x10 (command, has simple generic response)
- *
- * RXON tunes the radio tuner to a service channel, and sets up a number
- * of parameters that are used primarily for Rx, but also for Tx operations.
- *
- * NOTE:  When tuning to a new channel, driver must set the
- *        RXON_FILTER_ASSOC_MSK to 0.  This will clear station-dependent
- *        info within the device, including the station tables, tx retry
- *        rate tables, and txpower tables.  Driver must build a new station
- *        table and txpower table before transmitting anything on the RXON
- *        channel.
- *
- * NOTE:  All RXONs wipe clean the internal txpower table.  Driver must
- *        issue a new REPLY_TX_PWR_TABLE_CMD after each REPLY_RXON (0x10),
- *        regardless of whether RXON_FILTER_ASSOC_MSK is set.
- */
-struct iwl4965_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;
-} __attribute__ ((packed));
-
-/*
- * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response)
- */
-struct iwl4965_rxon_assoc_cmd {
-       __le32 flags;
-       __le32 filter_flags;
-       u8 ofdm_basic_rates;
-       u8 cck_basic_rates;
-       u8 ofdm_ht_single_stream_basic_rates;
-       u8 ofdm_ht_dual_stream_basic_rates;
-       __le16 rx_chain_select_flags;
-       __le16 reserved;
-} __attribute__ ((packed));
-
-/*
- * REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
- */
-struct iwl4965_rxon_time_cmd {
-       union tsf timestamp;
-       __le16 beacon_interval;
-       __le16 atim_window;
-       __le32 beacon_init_val;
-       __le16 listen_interval;
-       __le16 reserved;
-} __attribute__ ((packed));
-
-/*
- * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response)
- */
-struct iwl4965_channel_switch_cmd {
-       u8 band;
-       u8 expect_beacon;
-       __le16 channel;
-       __le32 rxon_flags;
-       __le32 rxon_filter_flags;
-       __le32 switch_time;
-       struct iwl4965_tx_power_db tx_power;
-} __attribute__ ((packed));
-
-/*
- * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command)
- */
-struct iwl4965_csa_notification {
-       __le16 band;
-       __le16 channel;
-       __le32 status;          /* 0 - OK, 1 - fail */
-} __attribute__ ((packed));
-
-/******************************************************************************
- * (2)
- * Quality-of-Service (QOS) Commands & Responses:
- *
- *****************************************************************************/
-
-/**
- * struct iwl_ac_qos -- QOS timing params for REPLY_QOS_PARAM
- * One for each of 4 EDCA access categories in struct iwl_qosparam_cmd
- *
- * @cw_min: Contention window, start value in numbers of slots.
- *          Should be a power-of-2, minus 1.  Device's default is 0x0f.
- * @cw_max: Contention window, max value in numbers of slots.
- *          Should be a power-of-2, minus 1.  Device's default is 0x3f.
- * @aifsn:  Number of slots in Arbitration Interframe Space (before
- *          performing random backoff timing prior to Tx).  Device default 1.
- * @edca_txop:  Length of Tx opportunity, in uSecs.  Device default is 0.
- *
- * Device will automatically increase contention window by (2*CW) + 1 for each
- * transmission retry.  Device uses cw_max as a bit mask, ANDed with new CW
- * value, to cap the CW value.
- */
-struct iwl4965_ac_qos {
-       __le16 cw_min;
-       __le16 cw_max;
-       u8 aifsn;
-       u8 reserved1;
-       __le16 edca_txop;
-} __attribute__ ((packed));
-
-/* QoS flags defines */
-#define QOS_PARAM_FLG_UPDATE_EDCA_MSK  __constant_cpu_to_le32(0x01)
-#define QOS_PARAM_FLG_TGN_MSK          __constant_cpu_to_le32(0x02)
-#define QOS_PARAM_FLG_TXOP_TYPE_MSK    __constant_cpu_to_le32(0x10)
-
-/* Number of Access Categories (AC) (EDCA), queues 0..3 */
-#define AC_NUM                4
-
-/*
- * REPLY_QOS_PARAM = 0x13 (command, has simple generic response)
- *
- * This command sets up timings for each of the 4 prioritized EDCA Tx FIFOs
- * 0: Background, 1: Best Effort, 2: Video, 3: Voice.
- */
-struct iwl4965_qosparam_cmd {
-       __le32 qos_flags;
-       struct iwl4965_ac_qos ac[AC_NUM];
-} __attribute__ ((packed));
-
-/******************************************************************************
- * (3)
- * Add/Modify Stations Commands & Responses:
- *
- *****************************************************************************/
-/*
- * Multi station support
- */
-
-/* Special, dedicated locations within device's station table */
-#define        IWL_AP_ID               0
-#define IWL_MULTICAST_ID       1
-#define        IWL_STA_ID              2
-#define IWL4965_BROADCAST_ID   31
-#define        IWL4965_STATION_COUNT   32
-
-#define        IWL_STATION_COUNT       32      /* MAX(3945,4965)*/
-#define        IWL_INVALID_STATION     255
-
-#define STA_FLG_PWR_SAVE_MSK           __constant_cpu_to_le32(1 << 8);
-#define STA_FLG_RTS_MIMO_PROT_MSK      __constant_cpu_to_le32(1 << 17)
-#define STA_FLG_AGG_MPDU_8US_MSK       __constant_cpu_to_le32(1 << 18)
-#define STA_FLG_MAX_AGG_SIZE_POS       (19)
-#define STA_FLG_MAX_AGG_SIZE_MSK       __constant_cpu_to_le32(3 << 19)
-#define STA_FLG_FAT_EN_MSK             __constant_cpu_to_le32(1 << 21)
-#define STA_FLG_MIMO_DIS_MSK           __constant_cpu_to_le32(1 << 22)
-#define STA_FLG_AGG_MPDU_DENSITY_POS   (23)
-#define STA_FLG_AGG_MPDU_DENSITY_MSK   __constant_cpu_to_le32(7 << 23)
-
-/* Use in mode field.  1: modify existing entry, 0: add new station entry */
-#define STA_CONTROL_MODIFY_MSK         0x01
-
-/* key flags __le16*/
-#define STA_KEY_FLG_ENCRYPT_MSK        __constant_cpu_to_le16(0x0007)
-#define STA_KEY_FLG_NO_ENC     __constant_cpu_to_le16(0x0000)
-#define STA_KEY_FLG_WEP                __constant_cpu_to_le16(0x0001)
-#define STA_KEY_FLG_CCMP       __constant_cpu_to_le16(0x0002)
-#define STA_KEY_FLG_TKIP       __constant_cpu_to_le16(0x0003)
-
-#define STA_KEY_FLG_KEYID_POS  8
-#define STA_KEY_FLG_INVALID    __constant_cpu_to_le16(0x0800)
-/* wep key is either from global key (0) or from station info array (1) */
-#define STA_KEY_FLG_MAP_KEY_MSK        __constant_cpu_to_le16(0x0008)
-
-/* wep key in STA: 5-bytes (0) or 13-bytes (1) */
-#define STA_KEY_FLG_KEY_SIZE_MSK     __constant_cpu_to_le16(0x1000)
-#define STA_KEY_MULTICAST_MSK        __constant_cpu_to_le16(0x4000)
-#define STA_KEY_MAX_NUM                8
-
-/* Flags indicate whether to modify vs. don't change various station params */
-#define        STA_MODIFY_KEY_MASK             0x01
-#define        STA_MODIFY_TID_DISABLE_TX       0x02
-#define        STA_MODIFY_TX_RATE_MSK          0x04
-#define STA_MODIFY_ADDBA_TID_MSK       0x08
-#define STA_MODIFY_DELBA_TID_MSK       0x10
-
-/* Receiver address (actually, Rx station's index into station table),
- * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */
-#define BUILD_RAxTID(sta_id, tid)      (((sta_id) << 4) + (tid))
-
-struct iwl4965_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 */
-} __attribute__ ((packed));
-
-/**
- * struct sta_id_modify
- * @addr[ETH_ALEN]: station's MAC address
- * @sta_id: index of station in uCode's station table
- * @modify_mask: STA_MODIFY_*, 1: modify, 0: don't change
- *
- * Driver selects unused table index when adding new station,
- * or the index to a pre-existing station entry when modifying that station.
- * Some indexes have special purposes (IWL_AP_ID, index 0, is for AP).
- *
- * modify_mask flags select which parameters to modify vs. leave alone.
- */
-struct sta_id_modify {
-       u8 addr[ETH_ALEN];
-       __le16 reserved1;
-       u8 sta_id;
-       u8 modify_mask;
-       __le16 reserved2;
-} __attribute__ ((packed));
-
-/*
- * REPLY_ADD_STA = 0x18 (command)
- *
- * The device contains an internal table of per-station information,
- * with info on security keys, aggregation parameters, and Tx rates for
- * initial Tx attempt and any retries (4965 uses REPLY_TX_LINK_QUALITY_CMD,
- * 3945 uses REPLY_RATE_SCALE to set up rate tables).
- *
- * REPLY_ADD_STA sets up the table entry for one station, either creating
- * a new entry, or modifying a pre-existing one.
- *
- * NOTE:  RXON command (without "associated" bit set) wipes the station table
- *        clean.  Moving into RF_KILL state does this also.  Driver must set up
- *        new station table before transmitting anything on the RXON channel
- *        (except active scans or active measurements; those commands carry
- *        their own txpower/rate setup data).
- *
- *        When getting started on a new channel, driver must set up the
- *        IWL_BROADCAST_ID entry (last entry in the table).  For a client
- *        station in a BSS, once an AP is selected, driver sets up the AP STA
- *        in the IWL_AP_ID entry (1st entry in the table).  BROADCAST and AP
- *        are all that are needed for a BSS client station.  If the device is
- *        used as AP, or in an IBSS network, driver must set up station table
- *        entries for all STAs in network, starting with index IWL_STA_ID.
- */
-struct iwl4965_addsta_cmd {
-       u8 mode;                /* 1: modify existing, 0: add new station */
-       u8 reserved[3];
-       struct sta_id_modify sta;
-       struct iwl4965_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
-#define ADD_STA_MODIFY_NON_EXIST_STA   0x8
-/*
- * REPLY_ADD_STA = 0x18 (response)
- */
-struct iwl4965_add_sta_resp {
-       u8 status;      /* ADD_STA_* */
-} __attribute__ ((packed));
-
-/*
- * REPLY_WEP_KEY = 0x20
- */
-struct iwl_wep_key {
-       u8 key_index;
-       u8 key_offset;
-       u8 reserved1[2];
-       u8 key_size;
-       u8 reserved2[3];
-       u8 key[16];
-} __attribute__ ((packed));
-
-struct iwl_wep_cmd {
-       u8 num_keys;
-       u8 global_key_type;
-       u8 flags;
-       u8 reserved;
-       struct iwl_wep_key key[0];
-} __attribute__ ((packed));
-
-#define WEP_KEY_WEP_TYPE 1
-#define WEP_KEYS_MAX 4
-#define WEP_INVALID_OFFSET 0xff
-#define WEP_KEY_LEN_128 13
-
-/******************************************************************************
- * (4)
- * Rx Responses:
- *
- *****************************************************************************/
-
-struct iwl4965_rx_frame_stats {
-       u8 phy_count;
-       u8 id;
-       u8 rssi;
-       u8 agc;
-       __le16 sig_avg;
-       __le16 noise_diff;
-       u8 payload[0];
-} __attribute__ ((packed));
-
-struct iwl4965_rx_frame_hdr {
-       __le16 channel;
-       __le16 phy_flags;
-       u8 reserved1;
-       u8 rate;
-       __le16 len;
-       u8 payload[0];
-} __attribute__ ((packed));
-
-#define RX_RES_STATUS_NO_CRC32_ERROR   __constant_cpu_to_le32(1 << 0)
-#define RX_RES_STATUS_NO_RXE_OVERFLOW  __constant_cpu_to_le32(1 << 1)
-
-#define RX_RES_PHY_FLAGS_BAND_24_MSK   __constant_cpu_to_le16(1 << 0)
-#define RX_RES_PHY_FLAGS_MOD_CCK_MSK           __constant_cpu_to_le16(1 << 1)
-#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK    __constant_cpu_to_le16(1 << 2)
-#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK       __constant_cpu_to_le16(1 << 3)
-#define RX_RES_PHY_FLAGS_ANTENNA_MSK           __constant_cpu_to_le16(0xf0)
-
-#define RX_RES_STATUS_SEC_TYPE_MSK     (0x7 << 8)
-#define RX_RES_STATUS_SEC_TYPE_NONE    (0x0 << 8)
-#define RX_RES_STATUS_SEC_TYPE_WEP     (0x1 << 8)
-#define RX_RES_STATUS_SEC_TYPE_CCMP    (0x2 << 8)
-#define RX_RES_STATUS_SEC_TYPE_TKIP    (0x3 << 8)
-#define        RX_RES_STATUS_SEC_TYPE_ERR      (0x7 << 8)
-
-#define RX_RES_STATUS_STATION_FOUND    (1<<6)
-#define RX_RES_STATUS_NO_STATION_INFO_MISMATCH (1<<7)
-
-#define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11)
-#define RX_RES_STATUS_NOT_DECRYPT      (0x0 << 11)
-#define RX_RES_STATUS_DECRYPT_OK       (0x3 << 11)
-#define RX_RES_STATUS_BAD_ICV_MIC      (0x1 << 11)
-#define RX_RES_STATUS_BAD_KEY_TTAK     (0x2 << 11)
-
-#define RX_MPDU_RES_STATUS_ICV_OK      (0x20)
-#define RX_MPDU_RES_STATUS_MIC_OK      (0x40)
-#define RX_MPDU_RES_STATUS_TTAK_OK     (1 << 7)
-#define RX_MPDU_RES_STATUS_DEC_DONE_MSK        (0x800)
-
-struct iwl4965_rx_frame_end {
-       __le32 status;
-       __le64 timestamp;
-       __le32 beacon_timestamp;
-} __attribute__ ((packed));
-
-/*
- * REPLY_3945_RX = 0x1b (response only, not a command)
- *
- * NOTE:  DO NOT dereference from casts to this structure
- * It is provided only for calculating minimum data set size.
- * The actual offsets of the hdr and end are dynamic based on
- * stats.phy_count
- */
-struct iwl4965_rx_frame {
-       struct iwl4965_rx_frame_stats stats;
-       struct iwl4965_rx_frame_hdr hdr;
-       struct iwl4965_rx_frame_end end;
-} __attribute__ ((packed));
-
-/* Fixed (non-configurable) rx data from phy */
-#define RX_PHY_FLAGS_ANTENNAE_OFFSET           (4)
-#define RX_PHY_FLAGS_ANTENNAE_MASK             (0x70)
-#define IWL_AGC_DB_MASK        (0x3f80)        /* MASK(7,13) */
-#define IWL_AGC_DB_POS         (7)
-struct iwl4965_rx_non_cfg_phy {
-       __le16 ant_selection;   /* ant A bit 4, ant B bit 5, ant C bit 6 */
-       __le16 agc_info;        /* agc code 0:6, agc dB 7:13, reserved 14:15 */
-       u8 rssi_info[6];        /* we use even entries, 0/2/4 for A/B/C rssi */
-       u8 pad[0];
-} __attribute__ ((packed));
-
-/*
- * REPLY_RX = 0xc3 (response only, not a command)
- * Used only for legacy (non 11n) frames.
- */
-#define RX_RES_PHY_CNT 14
-struct iwl4965_rx_phy_res {
-       u8 non_cfg_phy_cnt;     /* non configurable DSP phy data byte count */
-       u8 cfg_phy_cnt;         /* configurable DSP phy data byte count */
-       u8 stat_id;             /* configurable DSP phy data set ID */
-       u8 reserved1;
-       __le64 timestamp;       /* TSF at on air rise */
-       __le32 beacon_time_stamp; /* beacon at on-air rise */
-       __le16 phy_flags;       /* general phy flags: band, modulation, ... */
-       __le16 channel;         /* channel number */
-       __le16 non_cfg_phy[RX_RES_PHY_CNT];     /* upto 14 phy entries */
-       __le32 reserved2;
-       __le32 rate_n_flags;    /* RATE_MCS_* */
-       __le16 byte_count;      /* frame's byte-count */
-       __le16 reserved3;
-} __attribute__ ((packed));
-
-struct iwl4965_rx_mpdu_res_start {
-       __le16 byte_count;
-       __le16 reserved;
-} __attribute__ ((packed));
-
-
-/******************************************************************************
- * (5)
- * Tx Commands & Responses:
- *
- * Driver must place each REPLY_TX command into one of the prioritized Tx
- * queues in host DRAM, shared between driver and device (see comments for
- * SCD registers and Tx/Rx Queues).  When the device's Tx scheduler and uCode
- * are preparing to transmit, the device pulls the Tx command over the PCI
- * bus via one of the device's Tx DMA channels, to fill an internal FIFO
- * from which data will be transmitted.
- *
- * uCode handles all timing and protocol related to control frames
- * (RTS/CTS/ACK), based on flags in the Tx command.  uCode and Tx scheduler
- * handle reception of block-acks; uCode updates the host driver via
- * REPLY_COMPRESSED_BA (4965).
- *
- * uCode handles retrying Tx when an ACK is expected but not received.
- * This includes trying lower data rates than the one requested in the Tx
- * command, as set up by the REPLY_RATE_SCALE (for 3945) or
- * REPLY_TX_LINK_QUALITY_CMD (4965).
- *
- * Driver sets up transmit power for various rates via REPLY_TX_PWR_TABLE_CMD.
- * This command must be executed after every RXON command, before Tx can occur.
- *****************************************************************************/
-
-/* REPLY_TX Tx flags field */
-
-/* 1: Use Request-To-Send protocol before this frame.
- * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */
-#define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1)
-
-/* 1: Transmit Clear-To-Send to self before this frame.
- * Driver should set this for AUTH/DEAUTH/ASSOC-REQ/REASSOC mgmnt frames.
- * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK. */
-#define TX_CMD_FLG_CTS_MSK __constant_cpu_to_le32(1 << 2)
-
-/* 1: Expect ACK from receiving station
- * 0: Don't expect ACK (MAC header's duration field s/b 0)
- * Set this for unicast frames, but not broadcast/multicast. */
-#define TX_CMD_FLG_ACK_MSK __constant_cpu_to_le32(1 << 3)
-
-/* For 4965:
- * 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD).
- *    Tx command's initial_rate_index indicates first rate to try;
- *    uCode walks through table for additional Tx attempts.
- * 0: Use Tx rate/MCS from Tx command's rate_n_flags field.
- *    This rate will be used for all Tx attempts; it will not be scaled. */
-#define TX_CMD_FLG_STA_RATE_MSK __constant_cpu_to_le32(1 << 4)
-
-/* 1: Expect immediate block-ack.
- * Set when Txing a block-ack request frame.  Also set TX_CMD_FLG_ACK_MSK. */
-#define TX_CMD_FLG_IMM_BA_RSP_MASK  __constant_cpu_to_le32(1 << 6)
-
-/* 1: Frame requires full Tx-Op protection.
- * Set this if either RTS or CTS Tx Flag gets set. */
-#define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7)
-
-/* Tx antenna selection field; used only for 3945, reserved (0) for 4965.
- * Set field to "0" to allow 3945 uCode to select antenna (normal usage). */
-#define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00)
-#define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8)
-#define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9)
-
-/* 1: Ignore Bluetooth priority for this frame.
- * 0: Delay Tx until Bluetooth device is done (normal usage). */
-#define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12)
-
-/* 1: uCode overrides sequence control field in MAC header.
- * 0: Driver provides sequence control field in MAC header.
- * Set this for management frames, non-QOS data frames, non-unicast frames,
- * and also in Tx command embedded in REPLY_SCAN_CMD for active scans. */
-#define TX_CMD_FLG_SEQ_CTL_MSK __constant_cpu_to_le32(1 << 13)
-
-/* 1: This frame is non-last MPDU; more fragments are coming.
- * 0: Last fragment, or not using fragmentation. */
-#define TX_CMD_FLG_MORE_FRAG_MSK __constant_cpu_to_le32(1 << 14)
-
-/* 1: uCode calculates and inserts Timestamp Function (TSF) in outgoing frame.
- * 0: No TSF required in outgoing frame.
- * Set this for transmitting beacons and probe responses. */
-#define TX_CMD_FLG_TSF_MSK __constant_cpu_to_le32(1 << 16)
-
-/* 1: Driver inserted 2 bytes pad after the MAC header, for (required) dword
- *    alignment of frame's payload data field.
- * 0: No pad
- * Set this for MAC headers with 26 or 30 bytes, i.e. those with QOS or ADDR4
- * field (but not both).  Driver must align frame data (i.e. data following
- * MAC header) to DWORD boundary. */
-#define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20)
-
-/* accelerate aggregation support
- * 0 - no CCMP encryption; 1 - CCMP encryption */
-#define TX_CMD_FLG_AGG_CCMP_MSK __constant_cpu_to_le32(1 << 22)
-
-/* HCCA-AP - disable duration overwriting. */
-#define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25)
-
-
-/*
- * TX command security control
- */
-#define TX_CMD_SEC_WEP         0x01
-#define TX_CMD_SEC_CCM         0x02
-#define TX_CMD_SEC_TKIP                0x03
-#define TX_CMD_SEC_MSK         0x03
-#define TX_CMD_SEC_SHIFT       6
-#define TX_CMD_SEC_KEY128      0x08
-
-/*
- * 4965 uCode updates these Tx attempt count values in host DRAM.
- * Used for managing Tx retries when expecting block-acks.
- * Driver should set these fields to 0.
- */
-struct iwl4965_dram_scratch {
-       u8 try_cnt;             /* Tx attempts */
-       u8 bt_kill_cnt;         /* Tx attempts blocked by Bluetooth device */
-       __le16 reserved;
-} __attribute__ ((packed));
-
-/*
- * REPLY_TX = 0x1c (command)
- */
-struct iwl4965_tx_cmd {
-       /*
-        * MPDU byte count:
-        * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size,
-        * + 8 byte IV for CCM or TKIP (not used for WEP)
-        * + Data payload
-        * + 8-byte MIC (not used for CCM/WEP)
-        * NOTE:  Does not include Tx command bytes, post-MAC pad bytes,
-        *        MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.i
-        * Range: 14-2342 bytes.
-        */
-       __le16 len;
-
-       /*
-        * MPDU or MSDU byte count for next frame.
-        * Used for fragmentation and bursting, but not 11n aggregation.
-        * Same as "len", but for next frame.  Set to 0 if not applicable.
-        */
-       __le16 next_frame_len;
-
-       __le32 tx_flags;        /* TX_CMD_FLG_* */
-
-       /* 4965's uCode may modify this field of the Tx command (in host DRAM!).
-        * Driver must also set dram_lsb_ptr and dram_msb_ptr in this cmd. */
-       struct iwl4965_dram_scratch scratch;
-
-       /* Rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is cleared. */
-       __le32 rate_n_flags;    /* RATE_MCS_* */
-
-       /* Index of destination station in uCode's station table */
-       u8 sta_id;
-
-       /* Type of security encryption:  CCM or TKIP */
-       u8 sec_ctl;             /* TX_CMD_SEC_* */
-
-       /*
-        * Index into rate table (see REPLY_TX_LINK_QUALITY_CMD) for initial
-        * Tx attempt, if TX_CMD_FLG_STA_RATE_MSK is set.  Normally "0" for
-        * data frames, this field may be used to selectively reduce initial
-        * rate (via non-0 value) for special frames (e.g. management), while
-        * still supporting rate scaling for all frames.
-        */
-       u8 initial_rate_index;
-       u8 reserved;
-       u8 key[16];
-       __le16 next_frame_flags;
-       __le16 reserved2;
-       union {
-               __le32 life_time;
-               __le32 attempt;
-       } stop_time;
-
-       /* Host DRAM physical address pointer to "scratch" in this command.
-        * Must be dword aligned.  "0" in dram_lsb_ptr disables usage. */
-       __le32 dram_lsb_ptr;
-       u8 dram_msb_ptr;
-
-       u8 rts_retry_limit;     /*byte 50 */
-       u8 data_retry_limit;    /*byte 51 */
-       u8 tid_tspec;
-       union {
-               __le16 pm_frame_timeout;
-               __le16 attempt_duration;
-       } timeout;
-
-       /*
-        * Duration of EDCA burst Tx Opportunity, in 32-usec units.
-        * Set this if txop time is not specified by HCCA protocol (e.g. by AP).
-        */
-       __le16 driver_txop;
-
-       /*
-        * MAC header goes here, followed by 2 bytes padding if MAC header
-        * length is 26 or 30 bytes, followed by payload data
-        */
-       u8 payload[0];
-       struct ieee80211_hdr hdr[0];
-} __attribute__ ((packed));
-
-/* TX command response is sent after *all* transmission attempts.
- *
- * NOTES:
- *
- * TX_STATUS_FAIL_NEXT_FRAG
- *
- * If the fragment flag in the MAC header for the frame being transmitted
- * is set and there is insufficient time to transmit the next frame, the
- * TX status will be returned with 'TX_STATUS_FAIL_NEXT_FRAG'.
- *
- * TX_STATUS_FIFO_UNDERRUN
- *
- * Indicates the host did not provide bytes to the FIFO fast enough while
- * a TX was in progress.
- *
- * TX_STATUS_FAIL_MGMNT_ABORT
- *
- * This status is only possible if the ABORT ON MGMT RX parameter was
- * set to true with the TX command.
- *
- * If the MSB of the status parameter is set then an abort sequence is
- * required.  This sequence consists of the host activating the TX Abort
- * control line, and then waiting for the TX Abort command response.  This
- * indicates that a the device is no longer in a transmit state, and that the
- * command FIFO has been cleared.  The host must then deactivate the TX Abort
- * control line.  Receiving is still allowed in this case.
- */
-enum {
-       TX_STATUS_SUCCESS = 0x01,
-       TX_STATUS_DIRECT_DONE = 0x02,
-       TX_STATUS_FAIL_SHORT_LIMIT = 0x82,
-       TX_STATUS_FAIL_LONG_LIMIT = 0x83,
-       TX_STATUS_FAIL_FIFO_UNDERRUN = 0x84,
-       TX_STATUS_FAIL_MGMNT_ABORT = 0x85,
-       TX_STATUS_FAIL_NEXT_FRAG = 0x86,
-       TX_STATUS_FAIL_LIFE_EXPIRE = 0x87,
-       TX_STATUS_FAIL_DEST_PS = 0x88,
-       TX_STATUS_FAIL_ABORTED = 0x89,
-       TX_STATUS_FAIL_BT_RETRY = 0x8a,
-       TX_STATUS_FAIL_STA_INVALID = 0x8b,
-       TX_STATUS_FAIL_FRAG_DROPPED = 0x8c,
-       TX_STATUS_FAIL_TID_DISABLE = 0x8d,
-       TX_STATUS_FAIL_FRAME_FLUSHED = 0x8e,
-       TX_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f,
-       TX_STATUS_FAIL_TX_LOCKED = 0x90,
-       TX_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91,
-};
-
-#define        TX_PACKET_MODE_REGULAR          0x0000
-#define        TX_PACKET_MODE_BURST_SEQ        0x0100
-#define        TX_PACKET_MODE_BURST_FIRST      0x0200
-
-enum {
-       TX_POWER_PA_NOT_ACTIVE = 0x0,
-};
-
-enum {
-       TX_STATUS_MSK = 0x000000ff,     /* bits 0:7 */
-       TX_STATUS_DELAY_MSK = 0x00000040,
-       TX_STATUS_ABORT_MSK = 0x00000080,
-       TX_PACKET_MODE_MSK = 0x0000ff00,        /* bits 8:15 */
-       TX_FIFO_NUMBER_MSK = 0x00070000,        /* bits 16:18 */
-       TX_RESERVED = 0x00780000,       /* bits 19:22 */
-       TX_POWER_PA_DETECT_MSK = 0x7f800000,    /* bits 23:30 */
-       TX_ABORT_REQUIRED_MSK = 0x80000000,     /* bits 31:31 */
-};
-
-/* *******************************
- * TX aggregation status
- ******************************* */
-
-enum {
-       AGG_TX_STATE_TRANSMITTED = 0x00,
-       AGG_TX_STATE_UNDERRUN_MSK = 0x01,
-       AGG_TX_STATE_BT_PRIO_MSK = 0x02,
-       AGG_TX_STATE_FEW_BYTES_MSK = 0x04,
-       AGG_TX_STATE_ABORT_MSK = 0x08,
-       AGG_TX_STATE_LAST_SENT_TTL_MSK = 0x10,
-       AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK = 0x20,
-       AGG_TX_STATE_LAST_SENT_BT_KILL_MSK = 0x40,
-       AGG_TX_STATE_SCD_QUERY_MSK = 0x80,
-       AGG_TX_STATE_TEST_BAD_CRC32_MSK = 0x100,
-       AGG_TX_STATE_RESPONSE_MSK = 0x1ff,
-       AGG_TX_STATE_DUMP_TX_MSK = 0x200,
-       AGG_TX_STATE_DELAY_TX_MSK = 0x400
-};
-
-#define AGG_TX_STATE_LAST_SENT_MSK \
-(AGG_TX_STATE_LAST_SENT_TTL_MSK | \
- AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \
- AGG_TX_STATE_LAST_SENT_BT_KILL_MSK)
-
-/* # tx attempts for first frame in aggregation */
-#define AGG_TX_STATE_TRY_CNT_POS 12
-#define AGG_TX_STATE_TRY_CNT_MSK 0xf000
-
-/* Command ID and sequence number of Tx command for this frame */
-#define AGG_TX_STATE_SEQ_NUM_POS 16
-#define AGG_TX_STATE_SEQ_NUM_MSK 0xffff0000
-
-/*
- * REPLY_TX = 0x1c (response)
- *
- * This response may be in one of two slightly different formats, indicated
- * by the frame_count field:
- *
- * 1)  No aggregation (frame_count == 1).  This reports Tx results for
- *     a single frame.  Multiple attempts, at various bit rates, may have
- *     been made for this frame.
- *
- * 2)  Aggregation (frame_count > 1).  This reports Tx results for
- *     2 or more frames that used block-acknowledge.  All frames were
- *     transmitted at same rate.  Rate scaling may have been used if first
- *     frame in this new agg block failed in previous agg block(s).
- *
- *     Note that, for aggregation, ACK (block-ack) status is not delivered here;
- *     block-ack has not been received by the time the 4965 records this status.
- *     This status relates to reasons the tx might have been blocked or aborted
- *     within the sending station (this 4965), rather than whether it was
- *     received successfully by the destination station.
- */
-struct iwl4965_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;
-
-       /*
-        * 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!)
-        */
-       __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;
-       u8 failure_rts;
-       u8 failure_frame;
-       __le32 rate_n_flags;
-       __le16 wireless_media_time;
-       __le16 reserved3;
-       __le32 pa_power1;
-       __le32 pa_power2;
-       struct agg_tx_status status;    /* TX status (for aggregation status */
-                                       /* of 1st frame) */
-} __attribute__ ((packed));
-
-/*
- * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command)
- *
- * Reports Block-Acknowledge from recipient station
- */
-struct iwl4965_compressed_ba_resp {
-       __le32 sta_addr_lo32;
-       __le16 sta_addr_hi16;
-       __le16 reserved;
-
-       /* Index of recipient (BA-sending) station in uCode's station table */
-       u8 sta_id;
-       u8 tid;
-       __le16 seq_ctl;
-       __le64 bitmap;
-       __le16 scd_flow;
-       __le16 scd_ssn;
-} __attribute__ ((packed));
-
-/*
- * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response)
- *
- * See details under "TXPOWER" in iwl-4965-hw.h.
- */
-struct iwl4965_txpowertable_cmd {
-       u8 band;                /* 0: 5 GHz, 1: 2.4 GHz */
-       u8 reserved;
-       __le16 channel;
-       struct iwl4965_tx_power_db tx_power;
-} __attribute__ ((packed));
-
-/*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */
-#define  LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK   (1 << 0)
-
-/* # of EDCA prioritized tx fifos */
-#define  LINK_QUAL_AC_NUM AC_NUM
-
-/* # entries in rate scale table to support Tx retries */
-#define  LINK_QUAL_MAX_RETRY_NUM 16
-
-/* Tx antenna selection values */
-#define  LINK_QUAL_ANT_A_MSK (1 << 0)
-#define  LINK_QUAL_ANT_B_MSK (1 << 1)
-#define  LINK_QUAL_ANT_MSK   (LINK_QUAL_ANT_A_MSK|LINK_QUAL_ANT_B_MSK)
-
-
-/**
- * struct iwl_link_qual_general_params
- *
- * Used in REPLY_TX_LINK_QUALITY_CMD
- */
-struct iwl_link_qual_general_params {
-       u8 flags;
-
-       /* No entries at or above this (driver chosen) index contain MIMO */
-       u8 mimo_delimiter;
-
-       /* Best single antenna to use for single stream (legacy, SISO). */
-       u8 single_stream_ant_msk;       /* LINK_QUAL_ANT_* */
-
-       /* Best antennas to use for MIMO (unused for 4965, assumes both). */
-       u8 dual_stream_ant_msk;         /* LINK_QUAL_ANT_* */
-
-       /*
-        * If driver needs to use different initial rates for different
-        * EDCA QOS access categories (as implemented by tx fifos 0-3),
-        * this table will set that up, by indicating the indexes in the
-        * rs_table[LINK_QUAL_MAX_RETRY_NUM] rate table at which to start.
-        * Otherwise, driver should set all entries to 0.
-        *
-        * Entry usage:
-        * 0 = Background, 1 = Best Effort (normal), 2 = Video, 3 = Voice
-        * TX FIFOs above 3 use same value (typically 0) as TX FIFO 3.
-        */
-       u8 start_rate_index[LINK_QUAL_AC_NUM];
-} __attribute__ ((packed));
-
-/**
- * struct iwl_link_qual_agg_params
- *
- * Used in REPLY_TX_LINK_QUALITY_CMD
- */
-struct iwl_link_qual_agg_params {
-
-       /* Maximum number of uSec in aggregation.
-        * Driver should set this to 4000 (4 milliseconds). */
-       __le16 agg_time_limit;
-
-       /*
-        * Number of Tx retries allowed for a frame, before that frame will
-        * no longer be considered for the start of an aggregation sequence
-        * (scheduler will then try to tx it as single frame).
-        * Driver should set this to 3.
-        */
-       u8 agg_dis_start_th;
-
-       /*
-        * Maximum number of frames in aggregation.
-        * 0 = no limit (default).  1 = no aggregation.
-        * Other values = max # frames in aggregation.
-        */
-       u8 agg_frame_cnt_limit;
-
-       __le32 reserved;
-} __attribute__ ((packed));
-
-/*
- * REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response)
- *
- * For 4965 only; 3945 uses REPLY_RATE_SCALE.
- *
- * Each station in the 4965's internal station table has its own table of 16
- * Tx rates and modulation modes (e.g. legacy/SISO/MIMO) for retrying Tx when
- * an ACK is not received.  This command replaces the entire table for
- * one station.
- *
- * NOTE:  Station must already be in 4965's station table.  Use REPLY_ADD_STA.
- *
- * The rate scaling procedures described below work well.  Of course, other
- * procedures are possible, and may work better for particular environments.
- *
- *
- * FILLING THE RATE TABLE
- *
- * Given a particular initial rate and mode, as determined by the rate
- * scaling algorithm described below, the Linux driver uses the following
- * formula to fill the rs_table[LINK_QUAL_MAX_RETRY_NUM] rate table in the
- * Link Quality command:
- *
- *
- * 1)  If using High-throughput (HT) (SISO or MIMO) initial rate:
- *     a) Use this same initial rate for first 3 entries.
- *     b) Find next lower available rate using same mode (SISO or MIMO),
- *        use for next 3 entries.  If no lower rate available, switch to
- *        legacy mode (no FAT channel, no MIMO, no short guard interval).
- *     c) If using MIMO, set command's mimo_delimiter to number of entries
- *        using MIMO (3 or 6).
- *     d) After trying 2 HT rates, switch to legacy mode (no FAT channel,
- *        no MIMO, no short guard interval), at the next lower bit rate
- *        (e.g. if second HT bit rate was 54, try 48 legacy), and follow
- *        legacy procedure for remaining table entries.
- *
- * 2)  If using legacy initial rate:
- *     a) Use the initial rate for only one entry.
- *     b) For each following entry, reduce the rate to next lower available
- *        rate, until reaching the lowest available rate.
- *     c) When reducing rate, also switch antenna selection.
- *     d) Once lowest available rate is reached, repeat this rate until
- *        rate table is filled (16 entries), switching antenna each entry.
- *
- *
- * ACCUMULATING HISTORY
- *
- * The rate scaling algorithm for 4965, as implemented in Linux driver, uses
- * two sets of frame Tx success history:  One for the current/active modulation
- * mode, and one for a speculative/search mode that is being attempted.  If the
- * speculative mode turns out to be more effective (i.e. actual transfer
- * rate is better), then the driver continues to use the speculative mode
- * as the new current active mode.
- *
- * Each history set contains, separately for each possible rate, data for a
- * sliding window of the 62 most recent tx attempts at that rate.  The data
- * includes a shifting bitmap of success(1)/failure(0), and sums of successful
- * and attempted frames, from which the driver can additionally calculate a
- * success ratio (success / attempted) and number of failures
- * (attempted - success), and control the size of the window (attempted).
- * The driver uses the bit map to remove successes from the success sum, as
- * the oldest tx attempts fall out of the window.
- *
- * When the 4965 makes multiple tx attempts for a given frame, each attempt
- * might be at a different rate, and have different modulation characteristics
- * (e.g. antenna, fat channel, short guard interval), as set up in the rate
- * scaling table in the Link Quality command.  The driver must determine
- * which rate table entry was used for each tx attempt, to determine which
- * rate-specific history to update, and record only those attempts that
- * match the modulation characteristics of the history set.
- *
- * When using block-ack (aggregation), all frames are transmitted at the same
- * rate, since there is no per-attempt acknowledgement from the destination
- * station.  The Tx response struct iwl_tx_resp indicates the Tx rate in
- * rate_n_flags field.  After receiving a block-ack, the driver can update
- * history for the entire block all at once.
- *
- *
- * FINDING BEST STARTING RATE:
- *
- * When working with a selected initial modulation mode (see below), the
- * driver attempts to find a best initial rate.  The initial rate is the
- * first entry in the Link Quality command's rate table.
- *
- * 1)  Calculate actual throughput (success ratio * expected throughput, see
- *     table below) for current initial rate.  Do this only if enough frames
- *     have been attempted to make the value meaningful:  at least 6 failed
- *     tx attempts, or at least 8 successes.  If not enough, don't try rate
- *     scaling yet.
- *
- * 2)  Find available rates adjacent to current initial rate.  Available means:
- *     a)  supported by hardware &&
- *     b)  supported by association &&
- *     c)  within any constraints selected by user
- *
- * 3)  Gather measured throughputs for adjacent rates.  These might not have
- *     enough history to calculate a throughput.  That's okay, we might try
- *     using one of them anyway!
- *
- * 4)  Try decreasing rate if, for current rate:
- *     a)  success ratio is < 15% ||
- *     b)  lower adjacent rate has better measured throughput ||
- *     c)  higher adjacent rate has worse throughput, and lower is unmeasured
- *
- *     As a sanity check, if decrease was determined above, leave rate
- *     unchanged if:
- *     a)  lower rate unavailable
- *     b)  success ratio at current rate > 85% (very good)
- *     c)  current measured throughput is better than expected throughput
- *         of lower rate (under perfect 100% tx conditions, see table below)
- *
- * 5)  Try increasing rate if, for current rate:
- *     a)  success ratio is < 15% ||
- *     b)  both adjacent rates' throughputs are unmeasured (try it!) ||
- *     b)  higher adjacent rate has better measured throughput ||
- *     c)  lower adjacent rate has worse throughput, and higher is unmeasured
- *
- *     As a sanity check, if increase was determined above, leave rate
- *     unchanged if:
- *     a)  success ratio at current rate < 70%.  This is not particularly
- *         good performance; higher rate is sure to have poorer success.
- *
- * 6)  Re-evaluate the rate after each tx frame.  If working with block-
- *     acknowledge, history and statistics may be calculated for the entire
- *     block (including prior history that fits within the history windows),
- *     before re-evaluation.
- *
- * FINDING BEST STARTING MODULATION MODE:
- *
- * After working with a modulation mode for a "while" (and doing rate scaling),
- * the driver searches for a new initial mode in an attempt to improve
- * throughput.  The "while" is measured by numbers of attempted frames:
- *
- * For legacy mode, search for new mode after:
- *   480 successful frames, or 160 failed frames
- * For high-throughput modes (SISO or MIMO), search for new mode after:
- *   4500 successful frames, or 400 failed frames
- *
- * Mode switch possibilities are (3 for each mode):
- *
- * For legacy:
- *   Change antenna, try SISO (if HT association), try MIMO (if HT association)
- * For SISO:
- *   Change antenna, try MIMO, try shortened guard interval (SGI)
- * For MIMO:
- *   Try SISO antenna A, SISO antenna B, try shortened guard interval (SGI)
- *
- * When trying a new mode, use the same bit rate as the old/current mode when
- * trying antenna switches and shortened guard interval.  When switching to
- * SISO from MIMO or legacy, or to MIMO from SISO or legacy, use a rate
- * for which the expected throughput (under perfect conditions) is about the
- * same or slightly better than the actual measured throughput delivered by
- * the old/current mode.
- *
- * Actual throughput can be estimated by multiplying the expected throughput
- * by the success ratio (successful / attempted tx frames).  Frame size is
- * not considered in this calculation; it assumes that frame size will average
- * out to be fairly consistent over several samples.  The following are
- * metric values for expected throughput assuming 100% success ratio.
- * Only G band has support for CCK rates:
- *
- *           RATE:  1    2    5   11    6   9   12   18   24   36   48   54   60
- *
- *              G:  7   13   35   58   40  57   72   98  121  154  177  186  186
- *              A:  0    0    0    0   40  57   72   98  121  154  177  186  186
- *     SISO 20MHz:  0    0    0    0   42  42   76  102  124  159  183  193  202
- * SGI SISO 20MHz:  0    0    0    0   46  46   82  110  132  168  192  202  211
- *     MIMO 20MHz:  0    0    0    0   74  74  123  155  179  214  236  244  251
- * SGI MIMO 20MHz:  0    0    0    0   81  81  131  164  188  222  243  251  257
- *     SISO 40MHz:  0    0    0    0   77  77  127  160  184  220  242  250  257
- * SGI SISO 40MHz:  0    0    0    0   83  83  135  169  193  229  250  257  264
- *     MIMO 40MHz:  0    0    0    0  123 123  182  214  235  264  279  285  289
- * SGI MIMO 40MHz:  0    0    0    0  131 131  191  222  242  270  284  289  293
- *
- * After the new mode has been tried for a short while (minimum of 6 failed
- * frames or 8 successful frames), compare success ratio and actual throughput
- * estimate of the new mode with the old.  If either is better with the new
- * mode, continue to use the new mode.
- *
- * Continue comparing modes until all 3 possibilities have been tried.
- * If moving from legacy to HT, try all 3 possibilities from the new HT
- * mode.  After trying all 3, a best mode is found.  Continue to use this mode
- * for the longer "while" described above (e.g. 480 successful frames for
- * legacy), and then repeat the search process.
- *
- */
-struct iwl_link_quality_cmd {
-
-       /* Index of destination/recipient station in uCode's station table */
-       u8 sta_id;
-       u8 reserved1;
-       __le16 control;         /* not used */
-       struct iwl_link_qual_general_params general_params;
-       struct iwl_link_qual_agg_params agg_params;
-
-       /*
-        * Rate info; when using rate-scaling, Tx command's initial_rate_index
-        * specifies 1st Tx rate attempted, via index into this table.
-        * 4965 works its way through table when retrying Tx.
-        */
-       struct {
-               __le32 rate_n_flags;    /* RATE_MCS_*, IWL_RATE_* */
-       } rs_table[LINK_QUAL_MAX_RETRY_NUM];
-       __le32 reserved2;
-} __attribute__ ((packed));
-
-/*
- * REPLY_BT_CONFIG = 0x9b (command, has simple generic response)
- *
- * 3945 and 4965 support hardware handshake with Bluetooth device on
- * same platform.  Bluetooth device alerts wireless device when it will Tx;
- * wireless device can delay or kill its own Tx to accomodate.
- */
-struct iwl4965_bt_cmd {
-       u8 flags;
-       u8 lead_time;
-       u8 max_kill;
-       u8 reserved;
-       __le32 kill_ack_mask;
-       __le32 kill_cts_mask;
-} __attribute__ ((packed));
-
-/******************************************************************************
- * (6)
- * Spectrum Management (802.11h) Commands, Responses, Notifications:
- *
- *****************************************************************************/
-
-/*
- * Spectrum Management
- */
-#define MEASUREMENT_FILTER_FLAG (RXON_FILTER_PROMISC_MSK         | \
-                                RXON_FILTER_CTL2HOST_MSK        | \
-                                RXON_FILTER_ACCEPT_GRP_MSK      | \
-                                RXON_FILTER_DIS_DECRYPT_MSK     | \
-                                RXON_FILTER_DIS_GRP_DECRYPT_MSK | \
-                                RXON_FILTER_ASSOC_MSK           | \
-                                RXON_FILTER_BCON_AWARE_MSK)
-
-struct iwl4965_measure_channel {
-       __le32 duration;        /* measurement duration in extended beacon
-                                * format */
-       u8 channel;             /* channel to measure */
-       u8 type;                /* see enum iwl4965_measure_type */
-       __le16 reserved;
-} __attribute__ ((packed));
-
-/*
- * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command)
- */
-struct iwl4965_spectrum_cmd {
-       __le16 len;             /* number of bytes starting from token */
-       u8 token;               /* token id */
-       u8 id;                  /* measurement id -- 0 or 1 */
-       u8 origin;              /* 0 = TGh, 1 = other, 2 = TGk */
-       u8 periodic;            /* 1 = periodic */
-       __le16 path_loss_timeout;
-       __le32 start_time;      /* start time in extended beacon format */
-       __le32 reserved2;
-       __le32 flags;           /* rxon flags */
-       __le32 filter_flags;    /* rxon filter flags */
-       __le16 channel_count;   /* minimum 1, maximum 10 */
-       __le16 reserved3;
-       struct iwl4965_measure_channel channels[10];
-} __attribute__ ((packed));
-
-/*
- * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response)
- */
-struct iwl4965_spectrum_resp {
-       u8 token;
-       u8 id;                  /* id of the prior command replaced, or 0xff */
-       __le16 status;          /* 0 - command will be handled
-                                * 1 - cannot handle (conflicts with another
-                                *     measurement) */
-} __attribute__ ((packed));
-
-enum iwl4965_measurement_state {
-       IWL_MEASUREMENT_START = 0,
-       IWL_MEASUREMENT_STOP = 1,
-};
-
-enum iwl4965_measurement_status {
-       IWL_MEASUREMENT_OK = 0,
-       IWL_MEASUREMENT_CONCURRENT = 1,
-       IWL_MEASUREMENT_CSA_CONFLICT = 2,
-       IWL_MEASUREMENT_TGH_CONFLICT = 3,
-       /* 4-5 reserved */
-       IWL_MEASUREMENT_STOPPED = 6,
-       IWL_MEASUREMENT_TIMEOUT = 7,
-       IWL_MEASUREMENT_PERIODIC_FAILED = 8,
-};
-
-#define NUM_ELEMENTS_IN_HISTOGRAM 8
-
-struct iwl4965_measurement_histogram {
-       __le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 0.8usec counts */
-       __le32 cck[NUM_ELEMENTS_IN_HISTOGRAM];  /* in 1usec counts */
-} __attribute__ ((packed));
-
-/* clear channel availability counters */
-struct iwl4965_measurement_cca_counters {
-       __le32 ofdm;
-       __le32 cck;
-} __attribute__ ((packed));
-
-enum iwl4965_measure_type {
-       IWL_MEASURE_BASIC = (1 << 0),
-       IWL_MEASURE_CHANNEL_LOAD = (1 << 1),
-       IWL_MEASURE_HISTOGRAM_RPI = (1 << 2),
-       IWL_MEASURE_HISTOGRAM_NOISE = (1 << 3),
-       IWL_MEASURE_FRAME = (1 << 4),
-       /* bits 5:6 are reserved */
-       IWL_MEASURE_IDLE = (1 << 7),
-};
-
-/*
- * SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command)
- */
-struct iwl4965_spectrum_notification {
-       u8 id;                  /* measurement id -- 0 or 1 */
-       u8 token;
-       u8 channel_index;       /* index in measurement channel list */
-       u8 state;               /* 0 - start, 1 - stop */
-       __le32 start_time;      /* lower 32-bits of TSF */
-       u8 band;                /* 0 - 5.2GHz, 1 - 2.4GHz */
-       u8 channel;
-       u8 type;                /* see enum iwl4965_measurement_type */
-       u8 reserved1;
-       /* NOTE:  cca_ofdm, cca_cck, basic_type, and histogram are only only
-        * valid if applicable for measurement type requested. */
-       __le32 cca_ofdm;        /* cca fraction time in 40Mhz clock periods */
-       __le32 cca_cck;         /* cca fraction time in 44Mhz clock periods */
-       __le32 cca_time;        /* channel load time in usecs */
-       u8 basic_type;          /* 0 - bss, 1 - ofdm preamble, 2 -
-                                * unidentified */
-       u8 reserved2[3];
-       struct iwl4965_measurement_histogram histogram;
-       __le32 stop_time;       /* lower 32-bits of TSF */
-       __le32 status;          /* see iwl4965_measurement_status */
-} __attribute__ ((packed));
-
-/******************************************************************************
- * (7)
- * Power Management Commands, Responses, Notifications:
- *
- *****************************************************************************/
-
-/**
- * struct iwl4965_powertable_cmd - Power Table Command
- * @flags: See below:
- *
- * POWER_TABLE_CMD = 0x77 (command, has simple generic response)
- *
- * PM allow:
- *   bit 0 - '0' Driver not allow power management
- *           '1' Driver allow PM (use rest of parameters)
- * uCode send sleep notifications:
- *   bit 1 - '0' Don't send sleep notification
- *           '1' send sleep notification (SEND_PM_NOTIFICATION)
- * Sleep over DTIM
- *   bit 2 - '0' PM have to walk up every DTIM
- *           '1' PM could sleep over DTIM till listen Interval.
- * PCI power managed
- *   bit 3 - '0' (PCI_LINK_CTRL & 0x1)
- *           '1' !(PCI_LINK_CTRL & 0x1)
- * Force sleep Modes
- *   bit 31/30- '00' use both mac/xtal sleeps
- *              '01' force Mac sleep
- *              '10' force xtal sleep
- *              '11' Illegal set
- *
- * NOTE: if sleep_interval[SLEEP_INTRVL_TABLE_SIZE-1] > DTIM period then
- * ucode assume sleep over DTIM is allowed and we don't need to wakeup
- * for every DTIM.
- */
-#define IWL_POWER_VEC_SIZE 5
-
-#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)
-
-struct iwl4965_powertable_cmd {
-       __le16 flags;
-       u8 keep_alive_seconds;
-       u8 debug_flags;
-       __le32 rx_data_timeout;
-       __le32 tx_data_timeout;
-       __le32 sleep_interval[IWL_POWER_VEC_SIZE];
-       __le32 keep_alive_beacons;
-} __attribute__ ((packed));
-
-/*
- * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command)
- * 3945 and 4965 identical.
- */
-struct iwl4965_sleep_notification {
-       u8 pm_sleep_mode;
-       u8 pm_wakeup_src;
-       __le16 reserved;
-       __le32 sleep_time;
-       __le32 tsf_low;
-       __le32 bcon_timer;
-} __attribute__ ((packed));
-
-/* Sleep states.  3945 and 4965 identical. */
-enum {
-       IWL_PM_NO_SLEEP = 0,
-       IWL_PM_SLP_MAC = 1,
-       IWL_PM_SLP_FULL_MAC_UNASSOCIATE = 2,
-       IWL_PM_SLP_FULL_MAC_CARD_STATE = 3,
-       IWL_PM_SLP_PHY = 4,
-       IWL_PM_SLP_REPENT = 5,
-       IWL_PM_WAKEUP_BY_TIMER = 6,
-       IWL_PM_WAKEUP_BY_DRIVER = 7,
-       IWL_PM_WAKEUP_BY_RFKILL = 8,
-       /* 3 reserved */
-       IWL_PM_NUM_OF_MODES = 12,
-};
-
-/*
- * REPLY_CARD_STATE_CMD = 0xa0 (command, has simple generic response)
- */
-#define CARD_STATE_CMD_DISABLE 0x00    /* Put card to sleep */
-#define CARD_STATE_CMD_ENABLE  0x01    /* Wake up card */
-#define CARD_STATE_CMD_HALT    0x02    /* Power down permanently */
-struct iwl4965_card_state_cmd {
-       __le32 status;          /* CARD_STATE_CMD_* request new power state */
-} __attribute__ ((packed));
-
-/*
- * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command)
- */
-struct iwl4965_card_state_notif {
-       __le32 flags;
-} __attribute__ ((packed));
-
-#define HW_CARD_DISABLED   0x01
-#define SW_CARD_DISABLED   0x02
-#define RF_CARD_DISABLED   0x04
-#define RXON_CARD_DISABLED 0x10
-
-struct iwl4965_ct_kill_config {
-       __le32   reserved;
-       __le32   critical_temperature_M;
-       __le32   critical_temperature_R;
-}  __attribute__ ((packed));
-
-/******************************************************************************
- * (8)
- * Scan Commands, Responses, Notifications:
- *
- *****************************************************************************/
-
-/**
- * struct iwl4965_scan_channel - entry in REPLY_SCAN_CMD channel table
- *
- * One for each channel in the scan list.
- * Each channel can independently select:
- * 1)  SSID for directed active scans
- * 2)  Txpower setting (for rate specified within Tx command)
- * 3)  How long to stay on-channel (behavior may be modified by quiet_time,
- *     quiet_plcp_th, good_CRC_th)
- *
- * To avoid uCode errors, make sure the following are true (see comments
- * under struct iwl4965_scan_cmd about max_out_time and quiet_time):
- * 1)  If using passive_dwell (i.e. passive_dwell != 0):
- *     active_dwell <= passive_dwell (< max_out_time if max_out_time != 0)
- * 2)  quiet_time <= active_dwell
- * 3)  If restricting off-channel time (i.e. max_out_time !=0):
- *     passive_dwell < max_out_time
- *     active_dwell < max_out_time
- */
-struct iwl4965_scan_channel {
-       /*
-        * type is defined as:
-        * 0:0 1 = active, 0 = passive
-        * 1:4 SSID direct bit map; if a bit is set, then corresponding
-        *     SSID IE is transmitted in probe request.
-        * 5:7 reserved
-        */
-       u8 type;
-       u8 channel;     /* band is selected by iwl4965_scan_cmd "flags" field */
-       struct iwl4965_tx_power tpc;
-       __le16 active_dwell;    /* in 1024-uSec TU (time units), typ 5-50 */
-       __le16 passive_dwell;   /* in 1024-uSec TU (time units), typ 20-500 */
-} __attribute__ ((packed));
-
-/**
- * struct iwl4965_ssid_ie - directed scan network information element
- *
- * Up to 4 of these may appear in REPLY_SCAN_CMD, selected by "type" field
- * in struct iwl4965_scan_channel; each channel may select different ssids from
- * among the 4 entries.  SSID IEs get transmitted in reverse order of entry.
- */
-struct iwl4965_ssid_ie {
-       u8 id;
-       u8 len;
-       u8 ssid[32];
-} __attribute__ ((packed));
-
-#define PROBE_OPTION_MAX        0x4
-#define TX_CMD_LIFE_TIME_INFINITE      __constant_cpu_to_le32(0xFFFFFFFF)
-#define IWL_GOOD_CRC_TH                __constant_cpu_to_le16(1)
-#define IWL_MAX_SCAN_SIZE 1024
-
-/*
- * REPLY_SCAN_CMD = 0x80 (command)
- *
- * The hardware scan command is very powerful; the driver can set it up to
- * maintain (relatively) normal network traffic while doing a scan in the
- * background.  The max_out_time and suspend_time control the ratio of how
- * long the device stays on an associated network channel ("service channel")
- * vs. how long it's away from the service channel, i.e. tuned to other channels
- * for scanning.
- *
- * max_out_time is the max time off-channel (in usec), and suspend_time
- * is how long (in "extended beacon" format) that the scan is "suspended"
- * after returning to the service channel.  That is, suspend_time is the
- * time that we stay on the service channel, doing normal work, between
- * scan segments.  The driver may set these parameters differently to support
- * scanning when associated vs. not associated, and light vs. heavy traffic
- * loads when associated.
- *
- * After receiving this command, the device's scan engine does the following;
- *
- * 1)  Sends SCAN_START notification to driver
- * 2)  Checks to see if it has time to do scan for one channel
- * 3)  Sends NULL packet, with power-save (PS) bit set to 1,
- *     to tell AP that we're going off-channel
- * 4)  Tunes to first channel in scan list, does active or passive scan
- * 5)  Sends SCAN_RESULT notification to driver
- * 6)  Checks to see if it has time to do scan on *next* channel in list
- * 7)  Repeats 4-6 until it no longer has time to scan the next channel
- *     before max_out_time expires
- * 8)  Returns to service channel
- * 9)  Sends NULL packet with PS=0 to tell AP that we're back
- * 10) Stays on service channel until suspend_time expires
- * 11) Repeats entire process 2-10 until list is complete
- * 12) Sends SCAN_COMPLETE notification
- *
- * For fast, efficient scans, the scan command also has support for staying on
- * a channel for just a short time, if doing active scanning and getting no
- * responses to the transmitted probe request.  This time is controlled by
- * quiet_time, and the number of received packets below which a channel is
- * considered "quiet" is controlled by quiet_plcp_threshold.
- *
- * For active scanning on channels that have regulatory restrictions against
- * blindly transmitting, the scan can listen before transmitting, to make sure
- * that there is already legitimate activity on the channel.  If enough
- * packets are cleanly received on the channel (controlled by good_CRC_th,
- * typical value 1), the scan engine starts transmitting probe requests.
- *
- * Driver must use separate scan commands for 2.4 vs. 5 GHz bands.
- *
- * To avoid uCode errors, see timing restrictions described under
- * struct iwl4965_scan_channel.
- */
-struct iwl4965_scan_cmd {
-       __le16 len;
-       u8 reserved0;
-       u8 channel_count;       /* # channels in channel list */
-       __le16 quiet_time;      /* dwell only this # millisecs on quiet channel
-                                * (only for active scan) */
-       __le16 quiet_plcp_th;   /* quiet chnl is < this # pkts (typ. 1) */
-       __le16 good_CRC_th;     /* passive -> active promotion threshold */
-       __le16 rx_chain;        /* RXON_RX_CHAIN_* */
-       __le32 max_out_time;    /* max usec to be away from associated (service)
-                                * channel */
-       __le32 suspend_time;    /* pause scan this long (in "extended beacon
-                                * format") when returning to service chnl:
-                                * 3945; 31:24 # beacons, 19:0 additional usec,
-                                * 4965; 31:22 # beacons, 21:0 additional usec.
-                                */
-       __le32 flags;           /* RXON_FLG_* */
-       __le32 filter_flags;    /* RXON_FILTER_* */
-
-       /* 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;
-
-       /* For directed active scans (set to all-0s otherwise) */
-       struct iwl4965_ssid_ie direct_scan[PROBE_OPTION_MAX];
-
-       /*
-        * Probe request frame, followed by channel list.
-        *
-        * Size of probe request frame is specified by byte count in tx_cmd.
-        * Channel list follows immediately after probe request frame.
-        * Number of channels in list is specified by channel_count.
-        * Each channel in list is of type:
-        *
-        * struct iwl4965_scan_channel channels[0];
-        *
-        * NOTE:  Only one band of channels can be scanned per pass.  You
-        * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait
-        * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION)
-        * before requesting another scan.
-        */
-       u8 data[0];
-} __attribute__ ((packed));
-
-/* Can abort will notify by complete notification with abort status. */
-#define CAN_ABORT_STATUS       __constant_cpu_to_le32(0x1)
-/* complete notification statuses */
-#define ABORT_STATUS            0x2
-
-/*
- * REPLY_SCAN_CMD = 0x80 (response)
- */
-struct iwl4965_scanreq_notification {
-       __le32 status;          /* 1: okay, 2: cannot fulfill request */
-} __attribute__ ((packed));
-
-/*
- * SCAN_START_NOTIFICATION = 0x82 (notification only, not a command)
- */
-struct iwl4965_scanstart_notification {
-       __le32 tsf_low;
-       __le32 tsf_high;
-       __le32 beacon_timer;
-       u8 channel;
-       u8 band;
-       u8 reserved[2];
-       __le32 status;
-} __attribute__ ((packed));
-
-#define  SCAN_OWNER_STATUS 0x1;
-#define  MEASURE_OWNER_STATUS 0x2;
-
-#define NUMBER_OF_STATISTICS 1 /* first __le32 is good CRC */
-/*
- * SCAN_RESULTS_NOTIFICATION = 0x83 (notification only, not a command)
- */
-struct iwl4965_scanresults_notification {
-       u8 channel;
-       u8 band;
-       u8 reserved[2];
-       __le32 tsf_low;
-       __le32 tsf_high;
-       __le32 statistics[NUMBER_OF_STATISTICS];
-} __attribute__ ((packed));
-
-/*
- * SCAN_COMPLETE_NOTIFICATION = 0x84 (notification only, not a command)
- */
-struct iwl4965_scancomplete_notification {
-       u8 scanned_channels;
-       u8 status;
-       u8 reserved;
-       u8 last_channel;
-       __le32 tsf_low;
-       __le32 tsf_high;
-} __attribute__ ((packed));
-
-
-/******************************************************************************
- * (9)
- * IBSS/AP Commands and Notifications:
- *
- *****************************************************************************/
-
-/*
- * BEACON_NOTIFICATION = 0x90 (notification only, not a command)
- */
-struct iwl4965_beacon_notif {
-       struct iwl4965_tx_resp beacon_notify_hdr;
-       __le32 low_tsf;
-       __le32 high_tsf;
-       __le32 ibss_mgr_status;
-} __attribute__ ((packed));
-
-/*
- * REPLY_TX_BEACON = 0x91 (command, has simple generic response)
- */
-struct iwl4965_tx_beacon_cmd {
-       struct iwl4965_tx_cmd tx;
-       __le16 tim_idx;
-       u8 tim_size;
-       u8 reserved1;
-       struct ieee80211_hdr frame[0];  /* beacon frame */
-} __attribute__ ((packed));
-
-/******************************************************************************
- * (10)
- * Statistics Commands and Notifications:
- *
- *****************************************************************************/
-
-#define IWL_TEMP_CONVERT 260
-
-#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
-#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
-#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
-
-/* Used for passing to driver number of successes and failures per rate */
-struct rate_histogram {
-       union {
-               __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
-               __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
-               __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
-       } success;
-       union {
-               __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
-               __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
-               __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
-       } failed;
-} __attribute__ ((packed));
-
-/* statistics command response */
-
-struct statistics_rx_phy {
-       __le32 ina_cnt;
-       __le32 fina_cnt;
-       __le32 plcp_err;
-       __le32 crc32_err;
-       __le32 overrun_err;
-       __le32 early_overrun_err;
-       __le32 crc32_good;
-       __le32 false_alarm_cnt;
-       __le32 fina_sync_err_cnt;
-       __le32 sfd_timeout;
-       __le32 fina_timeout;
-       __le32 unresponded_rts;
-       __le32 rxe_frame_limit_overrun;
-       __le32 sent_ack_cnt;
-       __le32 sent_cts_cnt;
-       __le32 sent_ba_rsp_cnt;
-       __le32 dsp_self_kill;
-       __le32 mh_format_err;
-       __le32 re_acq_main_rssi_sum;
-       __le32 reserved3;
-} __attribute__ ((packed));
-
-struct statistics_rx_ht_phy {
-       __le32 plcp_err;
-       __le32 overrun_err;
-       __le32 early_overrun_err;
-       __le32 crc32_good;
-       __le32 crc32_err;
-       __le32 mh_format_err;
-       __le32 agg_crc32_good;
-       __le32 agg_mpdu_cnt;
-       __le32 agg_cnt;
-       __le32 reserved2;
-} __attribute__ ((packed));
-
-struct statistics_rx_non_phy {
-       __le32 bogus_cts;       /* CTS received when not expecting CTS */
-       __le32 bogus_ack;       /* ACK received when not expecting ACK */
-       __le32 non_bssid_frames;        /* number of frames with BSSID that
-                                        * doesn't belong to the STA BSSID */
-       __le32 filtered_frames; /* count frames that were dumped in the
-                                * filtering process */
-       __le32 non_channel_beacons;     /* beacons with our bss id but not on
-                                        * our serving channel */
-       __le32 channel_beacons; /* beacons with our bss id and in our
-                                * serving channel */
-       __le32 num_missed_bcon; /* number of missed beacons */
-       __le32 adc_rx_saturation_time;  /* count in 0.8us units the time the
-                                        * ADC was in saturation */
-       __le32 ina_detection_search_time;/* total time (in 0.8us) searched
-                                         * for INA */
-       __le32 beacon_silence_rssi_a;   /* RSSI silence after beacon frame */
-       __le32 beacon_silence_rssi_b;   /* RSSI silence after beacon frame */
-       __le32 beacon_silence_rssi_c;   /* RSSI silence after beacon frame */
-       __le32 interference_data_flag;  /* flag for interference data
-                                        * availability. 1 when data is
-                                        * available. */
-       __le32 channel_load;            /* counts RX Enable time in uSec */
-       __le32 dsp_false_alarms;        /* DSP false alarm (both OFDM
-                                        * and CCK) counter */
-       __le32 beacon_rssi_a;
-       __le32 beacon_rssi_b;
-       __le32 beacon_rssi_c;
-       __le32 beacon_energy_a;
-       __le32 beacon_energy_b;
-       __le32 beacon_energy_c;
-} __attribute__ ((packed));
-
-struct statistics_rx {
-       struct statistics_rx_phy ofdm;
-       struct statistics_rx_phy cck;
-       struct statistics_rx_non_phy general;
-       struct statistics_rx_ht_phy ofdm_ht;
-} __attribute__ ((packed));
-
-struct statistics_tx_non_phy_agg {
-       __le32 ba_timeout;
-       __le32 ba_reschedule_frames;
-       __le32 scd_query_agg_frame_cnt;
-       __le32 scd_query_no_agg;
-       __le32 scd_query_agg;
-       __le32 scd_query_mismatch;
-       __le32 frame_not_ready;
-       __le32 underrun;
-       __le32 bt_prio_kill;
-       __le32 rx_ba_rsp_cnt;
-       __le32 reserved2;
-       __le32 reserved3;
-} __attribute__ ((packed));
-
-struct statistics_tx {
-       __le32 preamble_cnt;
-       __le32 rx_detected_cnt;
-       __le32 bt_prio_defer_cnt;
-       __le32 bt_prio_kill_cnt;
-       __le32 few_bytes_cnt;
-       __le32 cts_timeout;
-       __le32 ack_timeout;
-       __le32 expected_ack_cnt;
-       __le32 actual_ack_cnt;
-       __le32 dump_msdu_cnt;
-       __le32 burst_abort_next_frame_mismatch_cnt;
-       __le32 burst_abort_missing_next_frame_cnt;
-       __le32 cts_timeout_collision;
-       __le32 ack_or_ba_timeout_collision;
-       struct statistics_tx_non_phy_agg agg;
-} __attribute__ ((packed));
-
-struct statistics_dbg {
-       __le32 burst_check;
-       __le32 burst_count;
-       __le32 reserved[4];
-} __attribute__ ((packed));
-
-struct statistics_div {
-       __le32 tx_on_a;
-       __le32 tx_on_b;
-       __le32 exec_time;
-       __le32 probe_time;
-       __le32 reserved1;
-       __le32 reserved2;
-} __attribute__ ((packed));
-
-struct statistics_general {
-       __le32 temperature;
-       __le32 temperature_m;
-       struct statistics_dbg dbg;
-       __le32 sleep_time;
-       __le32 slots_out;
-       __le32 slots_idle;
-       __le32 ttl_timestamp;
-       struct statistics_div div;
-       __le32 rx_enable_counter;
-       __le32 reserved1;
-       __le32 reserved2;
-       __le32 reserved3;
-} __attribute__ ((packed));
-
-/*
- * REPLY_STATISTICS_CMD = 0x9c,
- * 3945 and 4965 identical.
- *
- * This command triggers an immediate response containing uCode statistics.
- * The response is in the same format as STATISTICS_NOTIFICATION 0x9d, below.
- *
- * If the CLEAR_STATS configuration flag is set, uCode will clear its
- * internal copy of the statistics (counters) after issuing the response.
- * This flag does not affect STATISTICS_NOTIFICATIONs after beacons (see below).
- *
- * If the DISABLE_NOTIF configuration flag is set, uCode will not issue
- * STATISTICS_NOTIFICATIONs after received beacons (see below).  This flag
- * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself.
- */
-#define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1) /* see above */
-#define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */
-struct iwl4965_statistics_cmd {
-       __le32 configuration_flags;     /* IWL_STATS_CONF_* */
-} __attribute__ ((packed));
-
-/*
- * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command)
- *
- * By default, uCode issues this notification after receiving a beacon
- * while associated.  To disable this behavior, set DISABLE_NOTIF flag in the
- * REPLY_STATISTICS_CMD 0x9c, above.
- *
- * Statistics counters continue to increment beacon after beacon, but are
- * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD
- * 0x9c with CLEAR_STATS bit set (see above).
- *
- * uCode also issues this notification during scans.  uCode clears statistics
- * appropriately so that each notification contains statistics for only the
- * one channel that has just been scanned.
- */
-#define STATISTICS_REPLY_FLG_BAND_24G_MSK         __constant_cpu_to_le32(0x2)
-#define STATISTICS_REPLY_FLG_FAT_MODE_MSK         __constant_cpu_to_le32(0x8)
-struct iwl4965_notif_statistics {
-       __le32 flag;
-       struct statistics_rx rx;
-       struct statistics_tx tx;
-       struct statistics_general general;
-} __attribute__ ((packed));
-
-
-/*
- * MISSED_BEACONS_NOTIFICATION = 0xa2 (notification only, not a command)
- */
-/* if ucode missed CONSECUTIVE_MISSED_BCONS_TH beacons in a row,
- * then this notification will be sent. */
-#define CONSECUTIVE_MISSED_BCONS_TH 20
-
-struct iwl4965_missed_beacon_notif {
-       __le32 consequtive_missed_beacons;
-       __le32 total_missed_becons;
-       __le32 num_expected_beacons;
-       __le32 num_recvd_beacons;
-} __attribute__ ((packed));
-
-
-/******************************************************************************
- * (11)
- * Rx Calibration Commands:
- *
- * With the uCode used for open source drivers, most Tx calibration (except
- * for Tx Power) and most Rx calibration is done by uCode during the
- * "initialize" phase of uCode boot.  Driver must calibrate only:
- *
- * 1)  Tx power (depends on temperature), described elsewhere
- * 2)  Receiver gain balance (optimize MIMO, and detect disconnected antennas)
- * 3)  Receiver sensitivity (to optimize signal detection)
- *
- *****************************************************************************/
-
-/**
- * SENSITIVITY_CMD = 0xa8 (command, has simple generic response)
- *
- * This command sets up the Rx signal detector for a sensitivity level that
- * is high enough to lock onto all signals within the associated network,
- * but low enough to ignore signals that are below a certain threshold, so as
- * not to have too many "false alarms".  False alarms are signals that the
- * Rx DSP tries to lock onto, but then discards after determining that they
- * are noise.
- *
- * The optimum number of false alarms is between 5 and 50 per 200 TUs
- * (200 * 1024 uSecs, i.e. 204.8 milliseconds) of actual Rx time (i.e.
- * time listening, not transmitting).  Driver must adjust sensitivity so that
- * the ratio of actual false alarms to actual Rx time falls within this range.
- *
- * While associated, uCode delivers STATISTICS_NOTIFICATIONs after each
- * received beacon.  These provide information to the driver to analyze the
- * sensitivity.  Don't analyze statistics that come in from scanning, or any
- * other non-associated-network source.  Pertinent statistics include:
- *
- * From "general" statistics (struct statistics_rx_non_phy):
- *
- * (beacon_energy_[abc] & 0x0FF00) >> 8 (unsigned, higher value is lower level)
- *   Measure of energy of desired signal.  Used for establishing a level
- *   below which the device does not detect signals.
- *
- * (beacon_silence_rssi_[abc] & 0x0FF00) >> 8 (unsigned, units in dB)
- *   Measure of background noise in silent period after beacon.
- *
- * channel_load
- *   uSecs of actual Rx time during beacon period (varies according to
- *   how much time was spent transmitting).
- *
- * From "cck" and "ofdm" statistics (struct statistics_rx_phy), separately:
- *
- * false_alarm_cnt
- *   Signal locks abandoned early (before phy-level header).
- *
- * plcp_err
- *   Signal locks abandoned late (during phy-level header).
- *
- * NOTE:  Both false_alarm_cnt and plcp_err increment monotonically from
- *        beacon to beacon, i.e. each value is an accumulation of all errors
- *        before and including the latest beacon.  Values will wrap around to 0
- *        after counting up to 2^32 - 1.  Driver must differentiate vs.
- *        previous beacon's values to determine # false alarms in the current
- *        beacon period.
- *
- * Total number of false alarms = false_alarms + plcp_errs
- *
- * For OFDM, adjust the following table entries in struct iwl_sensitivity_cmd
- * (notice that the start points for OFDM are at or close to settings for
- * maximum sensitivity):
- *
- *                                             START  /  MIN  /  MAX
- *   HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX          90   /   85  /  120
- *   HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX     170   /  170  /  210
- *   HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX         105   /  105  /  140
- *   HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX     220   /  220  /  270
- *
- *   If actual rate of OFDM false alarms (+ plcp_errors) is too high
- *   (greater than 50 for each 204.8 msecs listening), reduce sensitivity
- *   by *adding* 1 to all 4 of the table entries above, up to the max for
- *   each entry.  Conversely, if false alarm rate is too low (less than 5
- *   for each 204.8 msecs listening), *subtract* 1 from each entry to
- *   increase sensitivity.
- *
- * For CCK sensitivity, keep track of the following:
- *
- *   1).  20-beacon history of maximum background noise, indicated by
- *        (beacon_silence_rssi_[abc] & 0x0FF00), units in dB, across the
- *        3 receivers.  For any given beacon, the "silence reference" is
- *        the maximum of last 60 samples (20 beacons * 3 receivers).
- *
- *   2).  10-beacon history of strongest signal level, as indicated
- *        by (beacon_energy_[abc] & 0x0FF00) >> 8, across the 3 receivers,
- *        i.e. the strength of the signal through the best receiver at the
- *        moment.  These measurements are "upside down", with lower values
- *        for stronger signals, so max energy will be *minimum* value.
- *
- *        Then for any given beacon, the driver must determine the *weakest*
- *        of the strongest signals; this is the minimum level that needs to be
- *        successfully detected, when using the best receiver at the moment.
- *        "Max cck energy" is the maximum (higher value means lower energy!)
- *        of the last 10 minima.  Once this is determined, driver must add
- *        a little margin by adding "6" to it.
- *
- *   3).  Number of consecutive beacon periods with too few false alarms.
- *        Reset this to 0 at the first beacon period that falls within the
- *        "good" range (5 to 50 false alarms per 204.8 milliseconds rx).
- *
- * Then, adjust the following CCK table entries in struct iwl_sensitivity_cmd
- * (notice that the start points for CCK are at maximum sensitivity):
- *
- *                                             START  /  MIN  /  MAX
- *   HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX         125   /  125  /  200
- *   HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX     200   /  200  /  400
- *   HD_MIN_ENERGY_CCK_DET_INDEX                100   /    0  /  100
- *
- *   If actual rate of CCK false alarms (+ plcp_errors) is too high
- *   (greater than 50 for each 204.8 msecs listening), method for reducing
- *   sensitivity is:
- *
- *   1)  *Add* 3 to value in HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX,
- *       up to max 400.
- *
- *   2)  If current value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX is < 160,
- *       sensitivity has been reduced a significant amount; bring it up to
- *       a moderate 161.  Otherwise, *add* 3, up to max 200.
- *
- *   3)  a)  If current value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX is > 160,
- *       sensitivity has been reduced only a moderate or small amount;
- *       *subtract* 2 from value in HD_MIN_ENERGY_CCK_DET_INDEX,
- *       down to min 0.  Otherwise (if gain has been significantly reduced),
- *       don't change the HD_MIN_ENERGY_CCK_DET_INDEX value.
- *
- *       b)  Save a snapshot of the "silence reference".
- *
- *   If actual rate of CCK false alarms (+ plcp_errors) is too low
- *   (less than 5 for each 204.8 msecs listening), method for increasing
- *   sensitivity is used only if:
- *
- *   1a)  Previous beacon did not have too many false alarms
- *   1b)  AND difference between previous "silence reference" and current
- *        "silence reference" (prev - current) is 2 or more,
- *   OR 2)  100 or more consecutive beacon periods have had rate of
- *          less than 5 false alarms per 204.8 milliseconds rx time.
- *
- *   Method for increasing sensitivity:
- *
- *   1)  *Subtract* 3 from value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX,
- *       down to min 125.
- *
- *   2)  *Subtract* 3 from value in HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX,
- *       down to min 200.
- *
- *   3)  *Add* 2 to value in HD_MIN_ENERGY_CCK_DET_INDEX, up to max 100.
- *
- *   If actual rate of CCK false alarms (+ plcp_errors) is within good range
- *   (between 5 and 50 for each 204.8 msecs listening):
- *
- *   1)  Save a snapshot of the silence reference.
- *
- *   2)  If previous beacon had too many CCK false alarms (+ plcp_errors),
- *       give some extra margin to energy threshold by *subtracting* 8
- *       from value in HD_MIN_ENERGY_CCK_DET_INDEX.
- *
- *   For all cases (too few, too many, good range), make sure that the CCK
- *   detection threshold (energy) is below the energy level for robust
- *   detection over the past 10 beacon periods, the "Max cck energy".
- *   Lower values mean higher energy; this means making sure that the value
- *   in HD_MIN_ENERGY_CCK_DET_INDEX is at or *above* "Max cck energy".
- *
- * Driver should set the following entries to fixed values:
- *
- *   HD_MIN_ENERGY_OFDM_DET_INDEX               100
- *   HD_BARKER_CORR_TH_ADD_MIN_INDEX            190
- *   HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX        390
- *   HD_OFDM_ENERGY_TH_IN_INDEX                  62
- */
-
-/*
- * Table entries in SENSITIVITY_CMD (struct iwl4965_sensitivity_cmd)
- */
-#define HD_TABLE_SIZE  (11)    /* number of entries */
-#define HD_MIN_ENERGY_CCK_DET_INDEX                 (0)        /* table indexes */
-#define HD_MIN_ENERGY_OFDM_DET_INDEX                (1)
-#define HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX          (2)
-#define HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX      (3)
-#define HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX      (4)
-#define HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX          (5)
-#define HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX      (6)
-#define HD_BARKER_CORR_TH_ADD_MIN_INDEX             (7)
-#define HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX         (8)
-#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 */
-#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
- * @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 {
-       __le16 control;                 /* always use "1" */
-       __le16 table[HD_TABLE_SIZE];    /* use HD_* as index */
-} __attribute__ ((packed));
-
-
-/**
- * REPLY_PHY_CALIBRATION_CMD = 0xb0 (command, has simple generic response)
- *
- * This command sets the relative gains of 4965's 3 radio receiver chains.
- *
- * After the first association, driver should accumulate signal and noise
- * statistics from the STATISTICS_NOTIFICATIONs that follow the first 20
- * beacons from the associated network (don't collect statistics that come
- * in from scanning, or any other non-network source).
- *
- * DISCONNECTED ANTENNA:
- *
- * Driver should determine which antennas are actually connected, by comparing
- * average beacon signal levels for the 3 Rx chains.  Accumulate (add) the
- * following values over 20 beacons, one accumulator for each of the chains
- * a/b/c, from struct statistics_rx_non_phy:
- *
- * beacon_rssi_[abc] & 0x0FF (unsigned, units in dB)
- *
- * Find the strongest signal from among a/b/c.  Compare the other two to the
- * strongest.  If any signal is more than 15 dB (times 20, unless you
- * divide the accumulated values by 20) below the strongest, the driver
- * considers that antenna to be disconnected, and should not try to use that
- * antenna/chain for Rx or Tx.  If both A and B seem to be disconnected,
- * driver should declare the stronger one as connected, and attempt to use it
- * (A and B are the only 2 Tx chains!).
- *
- *
- * RX BALANCE:
- *
- * Driver should balance the 3 receivers (but just the ones that are connected
- * to antennas, see above) for gain, by comparing the average signal levels
- * detected during the silence after each beacon (background noise).
- * Accumulate (add) the following values over 20 beacons, one accumulator for
- * each of the chains a/b/c, from struct statistics_rx_non_phy:
- *
- * beacon_silence_rssi_[abc] & 0x0FF (unsigned, units in dB)
- *
- * Find the weakest background noise level from among a/b/c.  This Rx chain
- * will be the reference, with 0 gain adjustment.  Attenuate other channels by
- * finding noise difference:
- *
- * (accum_noise[i] - accum_noise[reference]) / 30
- *
- * The "30" adjusts the dB in the 20 accumulated samples to units of 1.5 dB.
- * For use in diff_gain_[abc] fields of struct iwl_calibration_cmd, the
- * driver should limit the difference results to a range of 0-3 (0-4.5 dB),
- * and set bit 2 to indicate "reduce gain".  The value for the reference
- * (weakest) chain should be "0".
- *
- * diff_gain_[abc] bit fields:
- *   2: (1) reduce gain, (0) increase gain
- * 1-0: amount of gain, units of 1.5 dB
- */
-
-/* "Differential Gain" opcode used in REPLY_PHY_CALIBRATION_CMD. */
-#define PHY_CALIBRATE_DIFF_GAIN_CMD (7)
-
-struct iwl4965_calibration_cmd {
-       u8 opCode;              /* PHY_CALIBRATE_DIFF_GAIN_CMD (7) */
-       u8 flags;               /* not used */
-       __le16 reserved;
-       s8 diff_gain_a;         /* see above */
-       s8 diff_gain_b;
-       s8 diff_gain_c;
-       u8 reserved1;
-} __attribute__ ((packed));
-
-/******************************************************************************
- * (12)
- * Miscellaneous Commands:
- *
- *****************************************************************************/
-
-/*
- * LEDs Command & Response
- * REPLY_LEDS_CMD = 0x48 (command, has simple generic response)
- *
- * For each of 3 possible LEDs (Activity/Link/Tech, selected by "id" field),
- * this command turns it on or off, or sets up a periodic blinking cycle.
- */
-struct iwl4965_led_cmd {
-       __le32 interval;        /* "interval" in uSec */
-       u8 id;                  /* 1: Activity, 2: Link, 3: Tech */
-       u8 off;                 /* # intervals off while blinking;
-                                * "0", with >0 "on" value, turns LED on */
-       u8 on;                  /* # intervals on while blinking;
-                                * "0", regardless of "off", turns LED off */
-       u8 reserved;
-} __attribute__ ((packed));
-
-/******************************************************************************
- * (13)
- * Union of all expected notifications/responses:
- *
- *****************************************************************************/
-
-struct iwl4965_rx_packet {
-       __le32 len;
-       struct iwl_cmd_header hdr;
-       union {
-               struct iwl4965_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 iwl4965_card_state_notif card_state_notif;
-               struct iwl4965_beacon_notif beacon_status;
-               struct iwl4965_add_sta_resp add_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;
-               __le32 status;
-               u8 raw[0];
-       } u;
-} __attribute__ ((packed));
-
-#define IWL_RX_FRAME_SIZE        (4 + sizeof(struct iwl4965_rx_frame))
-
-#endif                         /* __iwl4965_commands_h__ */
index 1a66b50..ee55b28 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.
@@ -93,7 +98,7 @@
 #define IWL_RSSI_OFFSET        44
 
 
-#include "iwl-4965-commands.h"
+#include "iwl-commands.h"
 
 #define PCI_LINK_CTRL      0x0F0
 #define PCI_POWER_SOURCE   0x0C8
 #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 +788,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 +822,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 +848,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 +878,7 @@ struct iwl4965_tfd_frame_data {
 
 
 /**
- * struct iwl4965_tfd_frame
+ * struct iwl_tfd_frame
  *
  * Transmit Frame Descriptor (TFD)
  *
@@ -1468,7 +905,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 +914,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 +957,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 +990,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 c9847b1..8e3660e 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
@@ -349,9 +360,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 +385,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 +404,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 +422,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 +439,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 +474,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 = iwl4965_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)
-                       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)
+       } 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_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 |= iwl4965_rates[index].plcp_siso;
+               else if (is_mimo2(tbl->lq_type))
+                       rate_n_flags |= iwl4965_rates[index].plcp_mimo2;
                else
-                       mcs_rate->rate_n_flags |= RATE_MCS_FAT_MSK;
+                       rate_n_flags |= iwl4965_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 +642,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;
@@ -705,9 +718,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 +739,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,17 +760,19 @@ 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);
 }
 
 /*
@@ -780,7 +794,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
        struct ieee80211_hw *hw = local_to_hw(local);
        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;
@@ -822,15 +836,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,8 +851,8 @@ 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;
 
@@ -858,16 +863,14 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
                !!(tx_resp->control.flags & IEEE80211_TXCTL_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) ^
+           (tbl_type.ant_type ^ tx_resp->control.antenna_sel_tx) ||
+           (!!(tx_rate & RATE_MCS_HT_MSK) ^
                !!(tx_resp->control.flags & IEEE80211_TXCTL_OFDM_HT)) ||
-           (!!(tx_mcs.rate_n_flags & RATE_MCS_GF_MSK) ^
+           (!!(tx_rate & RATE_MCS_GF_MSK) ^
                !!(tx_resp->control.flags & IEEE80211_TXCTL_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);
+               IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate);
                goto out;
        }
 
@@ -875,15 +878,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 +896,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,8 +919,8 @@ 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)
@@ -929,7 +931,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
        /* 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];
@@ -945,7 +947,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
        /* 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];
@@ -982,30 +984,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 +992,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 +1014,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 +1033,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 +1063,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 +1076,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;
@@ -1172,21 +1152,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;
@@ -1195,26 +1170,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;
@@ -1224,23 +1200,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
@@ -1256,16 +1244,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)
@@ -1273,6 +1261,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;
@@ -1282,26 +1271,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 */
 }
 
@@ -1314,7 +1303,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 =
@@ -1323,41 +1311,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;
+                       }
 
                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) {
@@ -1367,16 +1349,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;
@@ -1386,7 +1367,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)
@@ -1397,7 +1378,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;
 
@@ -1412,7 +1393,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]);
@@ -1422,35 +1402,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;
+                       if (rs_toggle_antenna(valid_tx_ant,
+                                      &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");
+               case IWL_SISO_SWITCH_MIMO2:
+                       IWL_DEBUG_RATE("LQ: SISO switch to MIMO\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;
@@ -1458,29 +1433,25 @@ 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");
+                       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++;
@@ -1508,7 +1479,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]);
@@ -1517,24 +1487,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);
@@ -1545,37 +1515,26 @@ 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");
+                       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;
 
                }
@@ -1609,7 +1568,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]);
@@ -1624,9 +1585,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
@@ -1639,7 +1597,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);
@@ -1662,7 +1620,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]));
@@ -1705,7 +1663,7 @@ 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;
@@ -1761,8 +1719,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);
 
@@ -1782,27 +1739,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]);
 
@@ -1814,10 +1760,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);
 
@@ -1828,44 +1773,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;
 
@@ -1875,12 +1827,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
@@ -1892,7 +1843,7 @@ 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;
@@ -1988,15 +1939,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:
        /* 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);
        }
 
@@ -2031,12 +1982,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);
                }
 
@@ -2052,8 +2002,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
@@ -2065,12 +2015,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);
                }
 
        /*
@@ -2086,7 +2036,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;
 
@@ -2106,13 +2056,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;
@@ -2124,6 +2075,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
@@ -2134,22 +2087,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 = iwl4965_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;
@@ -2190,7 +2144,7 @@ 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) {
@@ -2220,11 +2174,13 @@ 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);
@@ -2260,7 +2216,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
@@ -2268,11 +2224,11 @@ 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) {
@@ -2301,11 +2257,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
@@ -2313,23 +2266,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*/
@@ -2343,50 +2310,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.
@@ -2394,26 +2366,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.
@@ -2423,20 +2394,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. */
@@ -2446,14 +2419,12 @@ 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_dis_start_th = 3;
        lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000);
 }
@@ -2479,10 +2450,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");
@@ -2496,54 +2469,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);
        }
 
@@ -2562,9 +2537,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,
@@ -2614,7 +2589,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",
@@ -2704,7 +2679,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;
index 866e378..7ea2041 100644 (file)
 #ifndef __iwl_4965_rs_h__
 #define __iwl_4965_rs_h__
 
-#include "iwl-4965.h"
+#include "iwl-dev.h"
 
 struct iwl4965_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 */
@@ -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" */
@@ -226,29 +242,40 @@ enum {
 
 extern const struct iwl4965_rate_info iwl4965_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)
 {
index bf19eb8..17847f9 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"
 
 /* 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[] = {
@@ -259,99 +223,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);
-
-       priv->qos_data.qos_active = 0;
-       priv->qos_data.qos_cap.val = 0;
+       /* 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);
 
-       iwlcore_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6);
+       /* 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);
 
-       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;
+       spin_unlock_irqrestore(&priv->lock, flags);
 
-       ret = iwl_init_channel_map(priv);
-       if (ret) {
-               IWL_ERROR("initializing regulatory failed: %d\n", ret);
-               goto err;
-       }
+       IWL_DEBUG_INFO("Runtime uCode pointers are set.\n");
 
-       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 +325,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 +333,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*/
@@ -410,7 +362,7 @@ void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
        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;
        if (rate_n_flags & RATE_MCS_GF_MSK)
@@ -431,41 +383,6 @@ void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
                        &priv->bands[IEEE80211_BAND_2GHZ].bitrates[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.
- */
-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)
 {
        int rc;
@@ -491,39 +408,32 @@ int iwl4965_hw_rxq_stop(struct iwl_priv *priv)
        return 0;
 }
 
-u8 iwl4965_hw_find_station(struct iwl_priv *priv, const u8 *addr)
+/*
+ * EEPROM handlers
+ */
+
+static int iwl4965_eeprom_check_version(struct iwl_priv *priv)
 {
-       int i;
-       int start = 0;
-       int ret = IWL_INVALID_STATION;
-       unsigned long flags;
-       DECLARE_MAC_BUF(mac);
+       u16 eeprom_ver;
+       u16 calib_ver;
 
-       if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) ||
-           (priv->iw_mode == IEEE80211_IF_TYPE_AP))
-               start = IWL_STA_ID;
+       eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
 
-       if (is_broadcast_ether_addr(addr))
-               return priv->hw_params.bcast_sta_id;
+       calib_ver = iwl_eeprom_query16(priv, EEPROM_4965_CALIB_VERSION_OFFSET);
 
-       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;
-               }
+       if (eeprom_ver < EEPROM_4965_EEPROM_VERSION ||
+           calib_ver < EEPROM_4965_TX_POWER_VERSION)
+               goto err;
 
-       IWL_DEBUG_ASSOC_LIMIT("can not find STA %s total %d\n",
-                       print_mac(mac, addr), priv->num_stations);
+       return 0;
+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,20 +445,21 @@ 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);
+                                      APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
+                                      ~APMG_PS_CTRL_MSK_PWR_SRC);
+       }
 
        iwl_release_nic_access(priv);
        spin_unlock_irqrestore(&priv->lock, flags);
@@ -556,313 +467,105 @@ static int iwl4965_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max)
        return ret;
 }
 
-static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq)
+static int iwl4965_disable_tx_fifo(struct iwl_priv *priv)
 {
-       int ret;
        unsigned long flags;
-       unsigned int rb_size;
+       int ret;
 
        spin_lock_irqsave(&priv->lock, flags);
+
        ret = iwl_grab_nic_access(priv);
-       if (ret) {
+       if (unlikely(ret)) {
+               IWL_ERROR("Tx fifo reset failed");
                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 +
-                           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));
-       }
-}
-
-/**
- * iwl4965_txq_ctx_reset - Reset TX queue context
- * Destroys all DMA structures and initialise them again
- *
- * @param priv
- * @return error code
- */
-static int iwl4965_txq_ctx_reset(struct iwl_priv *priv)
-{
-       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;
+       return 0;
 }
 
-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);
-
-       /* nic_init */
-       spin_lock_irqsave(&priv->lock, flags);
+       int ret = 0;
 
        iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
-                   CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+                         CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
 
+       /* 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;
 
+       /* enable DMA */
        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);
 
        udelay(20);
 
        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);
 
-       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;
-       }
-
-       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);
-
-       iwl_release_nic_access(priv);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       iwl4965_hw_card_show_info(priv);
+                   CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
+                   CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
 
-       /* 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);
+       priv->calib_info = (struct iwl_eeprom_calib_info *)
+               iwl_eeprom_query_addr(priv, EEPROM_4965_CALIB_TXPOWER_OFFSET);
 
        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)
@@ -916,16 +619,16 @@ void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv)
                }
 
                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
+                                  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 */
-       iwl4965_hw_txq_ctx_free(priv);
+       iwl_hw_txq_ctx_free(priv);
 }
 
 int iwl4965_hw_nic_reset(struct iwl_priv *priv)
@@ -973,836 +676,137 @@ int iwl4965_hw_nic_reset(struct iwl_priv *priv)
 
 #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)
-{
-       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;
-       }
-
-       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);
-
-       /* 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;
-       }
-
-       /* 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, 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 (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]);
-                       }
-               }
-
-               /*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");
-               }
-
-               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;
-
-               /* 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;
-                       }
-               }
-
-               data->delta_gain_code[min_average_noise_antenna_i] = 0;
-
-               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);
+/**
+ * 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 +823,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 +878,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 +888,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,7 +906,7 @@ 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
 };
@@ -1932,15 +930,15 @@ int iwl4965_alive_notify(struct iwl_priv *priv)
 
        spin_lock_irqsave(&priv->lock, flags);
 
-#ifdef CONFIG_IWL4965_SENSITIVITY
+#ifdef CONFIG_IWL4965_RUN_TIME_CALIB
        memset(&(priv->sensitivity_data), 0,
-              sizeof(struct iwl4965_sensitivity_data));
+              sizeof(struct iwl_sensitivity_data));
        memset(&(priv->chain_noise_data), 0,
-              sizeof(struct iwl4965_chain_noise_data));
+              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;
-#endif /* CONFIG_IWL4965_SENSITIVITY*/
+#endif /* CONFIG_IWL4965_RUN_TIME_CALIB*/
        ret = iwl_grab_nic_access(priv);
        if (ret) {
                spin_unlock_irqrestore(&priv->lock, flags);
@@ -1949,10 +947,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,18 +972,18 @@ 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,
@@ -2013,6 +1011,31 @@ int iwl4965_alive_notify(struct iwl_priv *priv)
        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,14 +1044,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.sw_crypto = priv->cfg->mod_params->sw_crypto;
        priv->hw_params.tx_cmd_len = sizeof(struct iwl4965_tx_cmd);
        priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
        priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
@@ -2040,90 +1064,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 +1193,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 +1225,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 +1242,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 +1251,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 +1572,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 +1630,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 +1662,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);
@@ -3035,7 +2004,7 @@ void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv,
        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;
@@ -3078,46 +2047,11 @@ 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)
 {
        int index, is_odd;
-       struct iwl4965_tfd_frame *tfd = ptr;
+       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 */
@@ -3147,26 +2081,35 @@ int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,
        return 0;
 }
 
-static void iwl4965_hw_card_show_info(struct iwl_priv *priv)
+static int iwl4965_alloc_shared_mem(struct iwl_priv *priv)
 {
-       u16 hw_version = priv->eeprom.board_revision_4965;
+       priv->shared_virt = pci_alloc_consistent(priv->pci_dev,
+                                       sizeof(struct iwl4965_shared),
+                                       &priv->shared_phys);
+       if (!priv->shared_virt)
+               return -ENOMEM;
+
+       memset(priv->shared_virt, 0, sizeof(struct iwl4965_shared));
 
-       IWL_DEBUG_INFO("4965ABGN HW Version %u.%u.%u\n",
-                      ((hw_version >> 8) & 0x0F),
-                      ((hw_version >> 8) >> 4), (hw_version & 0x00FF));
+       priv->rb_closed_offset = offsetof(struct iwl4965_shared, rb_closed);
 
-       IWL_DEBUG_INFO("4965ABGN PBA Number %.16s\n",
-                      priv->eeprom.board_pba_number_4965);
+       return 0;
 }
 
-#define IWL_TX_CRC_SIZE                4
-#define IWL_TX_DELIMITER_SIZE  4
+static void iwl4965_free_shared_mem(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_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 +2123,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 +2289,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 +2319,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 +2362,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;
@@ -3562,7 +2469,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;
+
+               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_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;
+       }
+       return 0;
+}
+
+static u32 iwl4965_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
 {
        u32 decrypt_out = 0;
 
@@ -3623,10 +2577,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 +2617,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 +2630,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 +2647,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 +2662,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 +2696,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 +2707,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 +2740,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 +2767,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 */
@@ -3943,11 +2870,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)
 {
@@ -3959,11 +2886,11 @@ 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)
+                               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 +2963,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 +2972,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 +2988,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);
        }
@@ -4128,19 +3062,19 @@ 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 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;
        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)
+                                          struct iwl_rx_mem_buffer *rxb)
 
 {
-#ifdef CONFIG_IWL4965_SENSITIVITY
-       struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+#ifdef CONFIG_IWL4965_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;
@@ -4150,11 +3084,10 @@ static void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv,
                    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);
+               if (!test_bit(STATUS_SCANNING, &priv->status))
+                       iwl_init_sensitivity(priv);
        }
-#endif /*CONFIG_IWL4965_SENSITIVITY*/
+#endif /*CONFIG_IWL4965_RUN_TIME_CALIB*/
 }
 #ifdef CONFIG_IWL4965_HT
 
@@ -4173,7 +3106,7 @@ static void iwl4965_sta_modify_enable_tid_tx(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);
+       iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
 }
 
 /**
@@ -4183,7 +3116,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)
 
@@ -4254,8 +3187,8 @@ 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));
 }
 
 /**
@@ -4300,7 +3233,7 @@ int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_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];
+       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:
@@ -4346,13 +3279,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 */
@@ -4398,13 +3331,16 @@ 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)) {
+               /* calculate mac80211 ampdu sw queue to wake */
+               int ampdu_q =
+                  scd_flow - IWL_BACK_QUEUE_FIRST_ID + priv->hw->queues;
                int freed = iwl4965_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 &&
                        priv->mac80211_registered &&
                        agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)
-                       ieee80211_wake_queue(priv->hw, scd_flow);
+                       ieee80211_wake_queue(priv->hw, ampdu_q);
                iwl4965_check_empty_hw_queue(priv, ba_resp->sta_id,
                        ba_resp->tid, scd_flow);
        }
@@ -4420,10 +3356,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 & IWL49_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);
 
@@ -4485,14 +3421,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));
 
@@ -4544,8 +3480,7 @@ void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
                        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;
+               rate_flags |= RATE_MCS_ANT_B_MSK; /*FIXME:RS*/
 
                link_cmd.rs_table[i].rate_n_flags =
                        iwl4965_hw_set_rate_n_flags(iwl4965_rates[r].plcp, rate_flags);
@@ -4566,101 +3501,6 @@ void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
 
 #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)
 {
@@ -4696,7 +3536,7 @@ void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index,
        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))
+       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;
@@ -4706,10 +3546,15 @@ void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index,
        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 +3564,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,7 +3585,8 @@ 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);
+       return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
+                                       CMD_ASYNC);
 }
 
 /*
@@ -4753,8 +3605,8 @@ static int iwl4965_txq_ctx_activate_free(struct iwl_priv *priv)
        return -1;
 }
 
-static int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, const u8 *da,
-                                      u16 tid, u16 *start_seq_num)
+static int iwl4965_tx_agg_start(struct ieee80211_hw *hw, const u8 *ra,
+                               u16 tid, u16 *start_seq_num)
 {
        struct iwl_priv *priv = hw->priv;
        int sta_id;
@@ -4763,7 +3615,7 @@ static int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, const u8 *da,
        int ssn = -1;
        int ret = 0;
        unsigned long flags;
-       struct iwl4965_tid_data *tid_data;
+       struct iwl_tid_data *tid_data;
        DECLARE_MAC_BUF(mac);
 
        if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
@@ -4771,10 +3623,10 @@ static int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, const u8 *da,
        else
                return -EINVAL;
 
-       IWL_WARNING("%s on da = %s tid = %d\n",
-                       __func__, print_mac(mac, da), tid);
+       IWL_WARNING("%s on ra = %s tid = %d\n",
+                       __func__, print_mac(mac, ra), tid);
 
-       sta_id = iwl4965_hw_find_station(priv, da);
+       sta_id = iwl_find_station(priv, ra);
        if (sta_id == IWL_INVALID_STATION)
                return -ENXIO;
 
@@ -4803,7 +3655,7 @@ static int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, const u8 *da,
        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);
+               ieee80211_start_tx_ba_cb_irqsafe(hw, ra, tid);
        } else {
                IWL_DEBUG_HT("HW queue is NOT empty: %d packets in HW queue\n",
                                tid_data->tfds_in_queue);
@@ -4812,19 +3664,17 @@ static int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, const u8 *da,
        return ret;
 }
 
-static int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, const u8 *da,
-                                     u16 tid)
+static int iwl4965_tx_agg_stop(struct ieee80211_hw *hw, const u8 *ra, u16 tid)
 {
-
        struct iwl_priv *priv = hw->priv;
        int tx_fifo_id, txq_id, sta_id, ssn = -1;
-       struct iwl4965_tid_data *tid_data;
+       struct iwl_tid_data *tid_data;
        int ret, write_ptr, read_ptr;
        unsigned long flags;
        DECLARE_MAC_BUF(mac);
 
-       if (!da) {
-               IWL_ERROR("da = NULL\n");
+       if (!ra) {
+               IWL_ERROR("ra = NULL\n");
                return -EINVAL;
        }
 
@@ -4833,7 +3683,7 @@ static int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, const u8 *da,
        else
                return -EINVAL;
 
-       sta_id = iwl4965_hw_find_station(priv, da);
+       sta_id = iwl_find_station(priv, ra);
 
        if (sta_id == IWL_INVALID_STATION)
                return -ENXIO;
@@ -4855,7 +3705,7 @@ static int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, const u8 *da,
                return 0;
        }
 
-       IWL_DEBUG_HT("HW queue empty\n");;
+       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);
@@ -4865,10 +3715,7 @@ static int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, const u8 *da,
        if (ret)
                return ret;
 
-       ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, da, tid);
-
-       IWL_DEBUG_INFO("iwl4965_mac_ht_tx_agg_stop on da=%s tid=%d\n",
-                       print_mac(mac, da), tid);
+       ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, ra, tid);
 
        return 0;
 }
@@ -4878,27 +3725,24 @@ int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
                             const u8 *addr, u16 tid, u16 *ssn)
 {
        struct iwl_priv *priv = hw->priv;
-       int sta_id;
        DECLARE_MAC_BUF(mac);
 
-       IWL_DEBUG_HT("A-MPDU action on da=%s tid=%d ",
-                       print_mac(mac, addr), tid);
-       sta_id = iwl4965_hw_find_station(priv, addr);
+       IWL_DEBUG_HT("A-MPDU action on addr %s tid %d\n",
+                    print_mac(mac, addr), tid);
+
        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;
+               return iwl4965_rx_agg_start(priv, addr, tid, *ssn);
        case IEEE80211_AMPDU_RX_STOP:
                IWL_DEBUG_HT("stop Rx\n");
-               iwl4965_sta_modify_del_ba_tid(priv, sta_id, tid);
-               break;
+               return iwl4965_rx_agg_stop(priv, addr, tid);
        case IEEE80211_AMPDU_TX_START:
                IWL_DEBUG_HT("start Tx\n");
-               return iwl4965_mac_ht_tx_agg_start(hw, addr, tid, ssn);
+               return iwl4965_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);
+               return iwl4965_tx_agg_stop(hw, addr, tid);
        default:
                IWL_DEBUG_HT("unknown\n");
                return -EINVAL;
@@ -4906,11 +3750,28 @@ int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
        }
        return 0;
 }
-
 #endif /* CONFIG_IWL4965_HT */
 
+
+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);
+
+       return (u16)sizeof(struct iwl4965_addsta_cmd);
+}
 /* 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;
@@ -4930,7 +3791,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);
@@ -4952,22 +3813,49 @@ static struct iwl_hcmd_ops iwl4965_hcmd = {
 
 static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
        .enqueue_hcmd = iwl4965_enqueue_hcmd,
+       .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,
+       .disable_tx_fifo = iwl4965_disable_tx_fifo,
+       .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,
+               .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 +3868,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 +3893,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-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h
deleted file mode 100644 (file)
index 581b985..0000000
+++ /dev/null
@@ -1,1262 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 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:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-/*
- * Please use this file (iwl-4965.h) for driver implementation definitions.
- * Please use iwl-4965-commands.h for uCode API definitions.
- * Please use iwl-4965-hw.h for hardware-related definitions.
- */
-
-#ifndef __iwl_4965_h__
-#define __iwl_4965_h__
-
-#include <linux/pci.h> /* for struct pci_device_id */
-#include <linux/kernel.h>
-#include <net/ieee80211_radiotap.h>
-
-#define DRV_NAME        "iwl4965"
-#include "iwl-rfkill.h"
-#include "iwl-eeprom.h"
-#include "iwl-4965-hw.h"
-#include "iwl-csr.h"
-#include "iwl-prph.h"
-#include "iwl-debug.h"
-#include "iwl-led.h"
-
-/* configuration for the iwl4965 */
-extern struct iwl_cfg iwl4965_agn_cfg;
-
-/* Change firmware file name, using "-" and incrementing number,
- *   *only* when uCode interface or architecture changes so that it
- *   is not compatible with earlier drivers.
- * This number will also appear in << 8 position of 1st dword of uCode file */
-#define IWL4965_UCODE_API "-1"
-
-
-/* Default noise level to report when noise measurement is not available.
- *   This may be because we're:
- *   1)  Not associated (4965, no beacon statistics being sent to driver)
- *   2)  Scanning (noise measurement does not apply to associated channel)
- *   3)  Receiving CCK (3945 delivers noise info only for OFDM frames)
- * Use default noise value of -127 ... this is below the range of measurable
- *   Rx dBm for either 3945 or 4965, so it can indicate "unmeasurable" to user.
- *   Also, -127 works better than 0 when averaging frames with/without
- *   noise info (e.g. averaging might be done in app); measured dBm values are
- *   always negative ... using a negative value as the default keeps all
- *   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:
- *   a value of 0 means RTS on all data/management packets
- *   a value > max MSDU size means no RTS
- * else RTS for data/management frames where MPDU is larger
- *   than RTS value.
- */
-#define DEFAULT_RTS_THRESHOLD     2347U
-#define MIN_RTS_THRESHOLD         0U
-#define MAX_RTS_THRESHOLD         2347U
-#define MAX_MSDU_SIZE            2304U
-#define MAX_MPDU_SIZE            2346U
-#define DEFAULT_BEACON_INTERVAL   100U
-#define        DEFAULT_SHORT_RETRY_LIMIT 7U
-#define        DEFAULT_LONG_RETRY_LIMIT  4U
-
-struct iwl4965_rx_mem_buffer {
-       dma_addr_t dma_addr;
-       struct sk_buff *skb;
-       struct list_head list;
-};
-
-/*
- * Generic queue structure
- *
- * Contains common data for Rx and Tx queues
- */
-struct iwl4965_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*/
-       dma_addr_t dma_addr;   /* physical addr for BD's */
-       int n_window;          /* safe queue window */
-       u32 id;
-       int low_mark;          /* low watermark, resume queue if free
-                               * space more than this */
-       int high_mark;         /* high watermark, stop queue if free
-                               * space less than this */
-} __attribute__ ((packed));
-
-#define MAX_NUM_OF_TBS          (20)
-
-/* One for each TFD */
-struct iwl4965_tx_info {
-       struct ieee80211_tx_status status;
-       struct sk_buff *skb[MAX_NUM_OF_TBS];
-};
-
-/**
- * struct iwl4965_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
- * @dma_addr_cmd: physical address of cmd/tx buffer array
- * @txb: array of per-TFD driver data
- * @need_update: indicates need to update read/write index
- * @sched_retry: indicates queue is high-throughput aggregation (HT AGG) enabled
- *
- * 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_cmd *cmd;
-       dma_addr_t dma_addr_cmd;
-       struct iwl4965_tx_info *txb;
-       int need_update;
-       int sched_retry;
-       int active;
-};
-
-#define IWL_NUM_SCAN_RATES         (2)
-
-struct iwl4965_channel_tgd_info {
-       u8 type;
-       s8 max_power;
-};
-
-struct iwl4965_channel_tgh_info {
-       s64 last_radar_time;
-};
-
-/* current Tx power values to use, one for each rate for each channel.
- * requested power is limited by:
- * -- regulatory EEPROM limits for this channel
- * -- hardware capabilities (clip-powers)
- * -- spectrum management
- * -- user preference (e.g. iwconfig)
- * when requested power is set, base power index must also be set. */
-struct iwl4965_channel_power_info {
-       struct iwl4965_tx_power tpc;    /* actual radio and DSP gain settings */
-       s8 power_table_index;   /* actual (compenst'd) index into gain table */
-       s8 base_power_index;    /* gain index for power at factory temp. */
-       s8 requested_power;     /* power (dBm) requested for this chnl/rate */
-};
-
-/* current scan Tx power values to use, one for each scan rate for each
- * channel. */
-struct iwl4965_scan_power_info {
-       struct iwl4965_tx_power tpc;    /* actual radio and DSP gain settings */
-       s8 power_table_index;   /* actual (compenst'd) index into gain table */
-       s8 requested_power;     /* scan pwr (dBm) requested for chnl/rate */
-};
-
-/* For fat_extension_channel */
-enum {
-       HT_IE_EXT_CHANNEL_NONE = 0,
-       HT_IE_EXT_CHANNEL_ABOVE,
-       HT_IE_EXT_CHANNEL_INVALID,
-       HT_IE_EXT_CHANNEL_BELOW,
-       HT_IE_EXT_CHANNEL_MAX
-};
-
-/*
- * One for each channel, holds all channel setup data
- * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant
- *     with one another!
- */
-#define IWL4965_MAX_RATE (33)
-
-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 */
-
-       u8 channel;       /* channel number */
-       u8 flags;         /* flags copied from EEPROM */
-       s8 max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
-       s8 curr_txpow;    /* (dBm) regulatory/spectrum/user (not h/w) limit */
-       s8 min_power;     /* always 0 */
-       s8 scan_power;    /* (dBm) regul. eeprom, direct scans, any rate */
-
-       u8 group_index;   /* 0-4, maps channel to group1/2/3/4/5 */
-       u8 band_index;    /* 0-4, maps channel to band1/2/3/4/5 */
-       enum ieee80211_band band;
-
-       /* Radio/DSP gain settings for each "normal" data Tx rate.
-        * These include, in addition to RF and DSP gain, a few fields for
-        *   remembering/modifying gain settings (indexes). */
-       struct iwl4965_channel_power_info power_info[IWL4965_MAX_RATE];
-
-       /* FAT channel info */
-       s8 fat_max_power_avg;   /* (dBm) regul. eeprom, normal Tx, any rate */
-       s8 fat_curr_txpow;      /* (dBm) regulatory/spectrum/user (not h/w) */
-       s8 fat_min_power;       /* always 0 */
-       s8 fat_scan_power;      /* (dBm) eeprom, direct scans, any rate */
-       u8 fat_flags;           /* flags copied from EEPROM */
-       u8 fat_extension_channel; /* HT_IE_EXT_CHANNEL_* */
-
-       /* Radio/DSP gain settings for each scan rate, for directed scans. */
-       struct iwl4965_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES];
-};
-
-struct iwl4965_clip_group {
-       /* maximum power level to prevent clipping for each rate, derived by
-        *   us from this band's saturation power in EEPROM */
-       const s8 clip_powers[IWL_MAX_RATES];
-};
-
-#include "iwl-4965-rs.h"
-
-#define IWL_TX_FIFO_AC0        0
-#define IWL_TX_FIFO_AC1        1
-#define IWL_TX_FIFO_AC2        2
-#define IWL_TX_FIFO_AC3        3
-#define IWL_TX_FIFO_HCCA_1     5
-#define IWL_TX_FIFO_HCCA_2     6
-#define IWL_TX_FIFO_NONE       7
-
-/* Minimum number of queues. MAX_NUM is defined in hw specific files */
-#define IWL_MIN_NUM_QUEUES     4
-
-/* 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;
-};
-
-#define IEEE80211_DATA_LEN              2304
-#define IEEE80211_4ADDR_LEN             30
-#define IEEE80211_HLEN                  (IEEE80211_4ADDR_LEN)
-#define IEEE80211_FRAME_LEN             (IEEE80211_DATA_LEN + IEEE80211_HLEN)
-
-struct iwl4965_frame {
-       union {
-               struct ieee80211_hdr frame;
-               struct iwl4965_tx_beacon_cmd beacon;
-               u8 raw[IEEE80211_FRAME_LEN];
-               u8 cmd[360];
-       } u;
-       struct list_head list;
-};
-
-#define SEQ_TO_QUEUE(x)  ((x >> 8) & 0xbf)
-#define QUEUE_TO_SEQ(x)  ((x & 0xbf) << 8)
-#define SEQ_TO_INDEX(x) ((u8)(x & 0xff))
-#define INDEX_TO_SEQ(x) ((u8)(x & 0xff))
-#define SEQ_HUGE_FRAME  (0x4000)
-#define SEQ_RX_FRAME    __constant_cpu_to_le16(0x8000)
-#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
-#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
-#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
-
-enum {
-       /* CMD_SIZE_NORMAL = 0, */
-       CMD_SIZE_HUGE = (1 << 0),
-       /* CMD_SYNC = 0, */
-       CMD_ASYNC = (1 << 1),
-       /* CMD_NO_SKB = 0, */
-       CMD_WANT_SKB = (1 << 2),
-};
-
-struct iwl_cmd;
-struct iwl_priv;
-
-struct iwl_cmd_meta {
-       struct iwl_cmd_meta *source;
-       union {
-               struct sk_buff *skb;
-               int (*callback)(struct iwl_priv *priv,
-                               struct iwl_cmd *cmd, struct sk_buff *skb);
-       } __attribute__ ((packed)) u;
-
-       /* The CMD_SIZE_HUGE flag bit indicates that the command
-        * structure is stored at the end of the shared queue memory. */
-       u32 flags;
-
-} __attribute__ ((packed));
-
-/**
- * struct iwl_cmd
- *
- * For allocation of the command and tx queues, this establishes the overall
- * size of the largest command we send to uCode, except for a scan command
- * (which is relatively huge; space is allocated separately).
- */
-struct iwl_cmd {
-       struct iwl_cmd_meta meta;       /* driver data */
-       struct iwl_cmd_header hdr;      /* uCode API */
-       union {
-               struct iwl4965_addsta_cmd addsta;
-               struct iwl4965_led_cmd led;
-               u32 flags;
-               u8 val8;
-               u16 val16;
-               u32 val32;
-               struct iwl4965_bt_cmd bt;
-               struct iwl4965_rxon_time_cmd rxon_time;
-               struct iwl4965_powertable_cmd powertable;
-               struct iwl4965_qosparam_cmd qosparam;
-               struct iwl4965_tx_cmd tx;
-               struct iwl4965_tx_beacon_cmd tx_beacon;
-               struct iwl4965_rxon_assoc_cmd rxon_assoc;
-               u8 *indirect;
-               u8 payload[360];
-       } __attribute__ ((packed)) cmd;
-} __attribute__ ((packed));
-
-struct iwl_host_cmd {
-       u8 id;
-       u16 len;
-       struct iwl_cmd_meta meta;
-       const void *data;
-};
-
-#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \
-                             sizeof(struct iwl_cmd_meta))
-
-/*
- * RX related structures and functions
- */
-#define RX_FREE_BUFFERS 64
-#define RX_LOW_WATERMARK 8
-
-#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
-#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
-#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
-
-/**
- * struct iwl4965_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
- * @free_count: Number of pre-allocated buffers in rx_free
- * @rx_free: list of free SKBs for use
- * @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
- */
-struct iwl4965_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];
-       u32 processed;
-       u32 read;
-       u32 write;
-       u32 free_count;
-       struct list_head rx_free;
-       struct list_head rx_used;
-       int need_update;
-       spinlock_t lock;
-};
-
-#define IWL_SUPPORTED_RATES_IE_LEN         8
-
-#define SCAN_INTERVAL 100
-
-#define MAX_A_CHANNELS  252
-#define MIN_A_CHANNELS  7
-
-#define MAX_B_CHANNELS  14
-#define MIN_B_CHANNELS  1
-
-#define MAX_TID_COUNT        9
-
-#define IWL_INVALID_RATE     0xFF
-#define IWL_INVALID_VALUE    -1
-
-#ifdef CONFIG_IWL4965_HT
-/**
- * struct iwl4965_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
- * @start_idx: Index of 1st Transmit Frame Descriptor (TFD) in Tx window
- * @bitmap0: Low order bitmap, one bit for each frame pending ACK in Tx window
- * @bitmap1: High order, one bit for each frame pending ACK in Tx window
- * @rate_n_flags: Rate at which Tx was attempted
- *
- * If REPLY_TX indicates that aggregation was attempted, driver must wait
- * for block ack (REPLY_COMPRESSED_BA).  This struct stores tx reply info
- * until block ack arrives.
- */
-struct iwl4965_ht_agg {
-       u16 txq_id;
-       u16 frame_count;
-       u16 wait_for_ba;
-       u16 start_idx;
-       u64 bitmap;
-       u32 rate_n_flags;
-#define IWL_AGG_OFF 0
-#define IWL_AGG_ON 1
-#define IWL_EMPTYING_HW_QUEUE_ADDBA 2
-#define IWL_EMPTYING_HW_QUEUE_DELBA 3
-       u8 state;
-};
-
-#endif /* CONFIG_IWL4965_HT */
-
-struct iwl4965_tid_data {
-       u16 seq_number;
-       u16 tfds_in_queue;
-#ifdef CONFIG_IWL4965_HT
-       struct iwl4965_ht_agg agg;
-#endif /* CONFIG_IWL4965_HT */
-};
-
-struct iwl4965_hw_key {
-       enum ieee80211_key_alg alg;
-       int keylen;
-       u8 keyidx;
-       struct ieee80211_key_conf *conf;
-       u8 key[32];
-};
-
-union iwl4965_ht_rate_supp {
-       u16 rates;
-       struct {
-               u8 siso_rate;
-               u8 mimo_rate;
-       };
-};
-
-#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
-
-struct iwl_ht_info {
-       /* self configuration data */
-       u8 is_ht;
-       u8 supported_chan_width;
-       u16 tx_mimo_ps_mode;
-       u8 is_green_field;
-       u8 sgf;                 /* HT_SHORT_GI_* short guard interval */
-       u8 max_amsdu_size;
-       u8 ampdu_factor;
-       u8 mpdu_density;
-       u8 supp_mcs_set[16];
-       /* BSS related data */
-       u8 control_channel;
-       u8 extension_chan_offset;
-       u8 tx_chan_width;
-       u8 ht_protection;
-       u8 non_GF_STA_present;
-};
-#endif                         /*CONFIG_IWL4965_HT */
-
-union iwl4965_qos_capabity {
-       struct {
-               u8 edca_count:4;        /* bit 0-3 */
-               u8 q_ack:1;             /* bit 4 */
-               u8 queue_request:1;     /* bit 5 */
-               u8 txop_request:1;      /* bit 6 */
-               u8 reserved:1;          /* bit 7 */
-       } q_AP;
-       struct {
-               u8 acvo_APSD:1;         /* bit 0 */
-               u8 acvi_APSD:1;         /* bit 1 */
-               u8 ac_bk_APSD:1;        /* bit 2 */
-               u8 ac_be_APSD:1;        /* bit 3 */
-               u8 q_ack:1;             /* bit 4 */
-               u8 max_len:2;           /* bit 5-6 */
-               u8 more_data_ack:1;     /* bit 7 */
-       } q_STA;
-       u8 val;
-};
-
-/* QoS structures */
-struct iwl4965_qos_info {
-       int qos_enable;
-       int qos_active;
-       union iwl4965_qos_capabity qos_cap;
-       struct iwl4965_qosparam_cmd def_qos_parm;
-};
-
-#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];
-       u8 used;
-       u8 ps_status;
-       struct iwl4965_hw_key keyinfo;
-};
-
-/* one for each uCode image (inst/data, boot/init/runtime) */
-struct fw_desc {
-       void *v_addr;           /* access by driver */
-       dma_addr_t p_addr;      /* access by card's busmaster DMA */
-       u32 len;                /* bytes */
-};
-
-/* uCode file layout */
-struct iwl4965_ucode {
-       __le32 ver;             /* major/minor/subminor */
-       __le32 inst_size;       /* bytes of runtime instructions */
-       __le32 data_size;       /* bytes of runtime data */
-       __le32 init_size;       /* bytes of initialization instructions */
-       __le32 init_data_size;  /* bytes of initialization data */
-       __le32 boot_size;       /* bytes of bootstrap instructions */
-       u8 data[0];             /* data in same order as "size" elements */
-};
-
-#define IWL_IBSS_MAC_HASH_SIZE 32
-
-struct iwl4965_ibss_seq {
-       u8 mac[ETH_ALEN];
-       u16 seq_num;
-       u16 frag_num;
-       unsigned long packet_time;
-       struct list_head list;
-};
-
-/**
- * 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
- * @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
- * @max_stations:
- * @bcast_sta_id:
- */
-struct iwl_hw_params {
-       u16 max_txq_num;
-       u16 tx_cmd_len;
-       u8  tx_chains_num;
-       u8  rx_chains_num;
-       u8  valid_tx_ant;
-       u8  valid_rx_ant;
-       u16 max_rxq_size;
-       u16 max_rxq_log;
-       u32 rx_buf_size;
-       u32 max_pkt_size;
-       u8  max_stations;
-       u8  bcast_sta_id;
-};
-
-#define HT_SHORT_GI_20MHZ_ONLY          (1 << 0)
-#define HT_SHORT_GI_40MHZ_ONLY          (1 << 1)
-
-
-#define IWL_RX_HDR(x) ((struct iwl4965_rx_frame_hdr *)(\
-                      x->u.rx_frame.stats.payload + \
-                      x->u.rx_frame.stats.phy_count))
-#define IWL_RX_END(x) ((struct iwl4965_rx_frame_end *)(\
-                      IWL_RX_HDR(x)->payload + \
-                      le16_to_cpu(IWL_RX_HDR(x)->len)))
-#define IWL_RX_STATS(x) (&x->u.rx_frame.stats)
-#define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload)
-
-
-/******************************************************************************
- *
- * Functions implemented in iwl-base.c which are forward declared here
- * 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);
-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,
-                                          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);
-int iwl4965_init_geos(struct iwl_priv *priv);
-void iwl4965_free_geos(struct iwl_priv *priv);
-
-extern const u8 iwl4965_broadcast_addr[ETH_ALEN];
-int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
-
-/*
- * Currently used by iwl-3945-rs... look at restructuring so that it doesn't
- * call this... todo... fix that.
-*/
-extern u8 iwl4965_sync_station(struct iwl_priv *priv, int sta_id,
-                          u16 tx_rate, u8 flags);
-
-/******************************************************************************
- *
- * Functions implemented in iwl-[34]*.c which are forward declared here
- * for use by iwl-base.c
- *
- * NOTE:  The implementation of these functions are hardware specific
- * which is why they are in the hardware specific files (vs. iwl-base.c)
- *
- * Naming convention --
- * iwl4965_         <-- Its part of iwlwifi (should be changed to iwl4965_)
- * iwl4965_hw_      <-- Hardware specific (implemented in iwl-XXXX.c by all HW)
- * iwlXXXX_     <-- Hardware specific (implemented in iwl-XXXX.c for XXXX)
- * iwl4965_bg_      <-- Called from work queue context
- * 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 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);
-extern 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 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);
-extern void iwl4965_disable_events(struct iwl_priv *priv);
-extern int iwl4965_get_temperature(const struct iwl_priv *priv);
-
-/**
- * iwl4965_hw_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 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);
-struct iwl_priv;
-
-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,
-                                         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);
-
-#ifdef CONFIG_IWL4965_HT
-void iwl4965_init_ht_hw_capab(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,
-                                           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 */
-
-struct iwl4965_kw {
-       dma_addr_t dma_addr;
-       void *v_addr;
-       size_t size;
-};
-
-#define IWL_CHANNEL_WIDTH_20MHZ   0
-#define IWL_CHANNEL_WIDTH_40MHZ   1
-
-#define IWL_MIMO_PS_STATIC        0
-#define IWL_MIMO_PS_NONE          3
-#define IWL_MIMO_PS_DYNAMIC       1
-#define IWL_MIMO_PS_INVALID       2
-
-#define IWL_OPERATION_MODE_AUTO     0
-#define IWL_OPERATION_MODE_HT_ONLY  1
-#define IWL_OPERATION_MODE_MIXED    2
-#define IWL_OPERATION_MODE_20MHZ    3
-
-#define IWL_EXT_CHANNEL_OFFSET_NONE      0
-#define IWL_EXT_CHANNEL_OFFSET_ABOVE     1
-#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 TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
-
-struct iwl4965_lq_mngr {
-       spinlock_t lock;
-       s32 max_window_size;
-       s32 *expected_tpt;
-       u8 *next_higher_rate;
-       u8 *next_lower_rate;
-       unsigned long stamp;
-       unsigned long stamp_last;
-       u32 flush_time;
-       u32 tx_packets;
-       u8 lq_ready;
-};
-
-/* Sensitivity and chain noise calibration */
-#define INTERFERENCE_DATA_AVAILABLE    __constant_cpu_to_le32(1)
-#define INITIALIZATION_VALUE           0xFFFF
-#define CAL_NUM_OF_BEACONS             20
-#define MAXIMUM_ALLOWED_PATHLOSS       15
-
-#define CHAIN_NOISE_MAX_DELTA_GAIN_CODE 3
-
-#define MAX_FA_OFDM  50
-#define MIN_FA_OFDM  5
-#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
-
-#define NRG_DIFF               2
-#define NRG_STEP_CCK           2
-#define NRG_MARGIN             8
-#define MAX_NUMBER_CCK_NO_FA 100
-
-#define AUTO_CORR_CCK_MIN_VAL_DEF    (125)
-
-#define CHAIN_A             0
-#define CHAIN_B             1
-#define CHAIN_C             2
-#define CHAIN_NOISE_DELTA_GAIN_INIT_VAL 4
-#define ALL_BAND_FILTER                        0xFF00
-#define IN_BAND_FILTER                 0xFF
-#define MIN_AVERAGE_NOISE_MAX_VALUE    0xFFFFFFFF
-
-enum iwl4965_false_alarm_state {
-       IWL_FA_TOO_MANY = 0,
-       IWL_FA_TOO_FEW = 1,
-       IWL_FA_GOOD_RANGE = 2,
-};
-
-enum iwl4965_chain_noise_state {
-       IWL_CHAIN_NOISE_ALIVE = 0,  /* must be 0 */
-       IWL_CHAIN_NOISE_ACCUMULATE = 1,
-       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,
-};
-
-struct statistics_general_data {
-       u32 beacon_silence_rssi_a;
-       u32 beacon_silence_rssi_b;
-       u32 beacon_silence_rssi_c;
-       u32 beacon_energy_a;
-       u32 beacon_energy_b;
-       u32 beacon_energy_c;
-};
-
-/* Sensitivity calib data */
-struct iwl4965_sensitivity_data {
-       u32 auto_corr_ofdm;
-       u32 auto_corr_ofdm_mrc;
-       u32 auto_corr_ofdm_x1;
-       u32 auto_corr_ofdm_mrc_x1;
-       u32 auto_corr_cck;
-       u32 auto_corr_cck_mrc;
-
-       u32 last_bad_plcp_cnt_ofdm;
-       u32 last_fa_cnt_ofdm;
-       u32 last_bad_plcp_cnt_cck;
-       u32 last_fa_cnt_cck;
-
-       u32 nrg_curr_state;
-       u32 nrg_prev_state;
-       u32 nrg_value[10];
-       u8  nrg_silence_rssi[NRG_NUM_PREV_STAT_L];
-       u32 nrg_silence_ref;
-       u32 nrg_energy_idx;
-       u32 nrg_silence_idx;
-       u32 nrg_th_cck;
-       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 {
-       u8 state;
-       u16 beacon_count;
-       u32 chain_noise_a;
-       u32 chain_noise_b;
-       u32 chain_noise_c;
-       u32 chain_signal_a;
-       u32 chain_signal_b;
-       u32 chain_signal_c;
-       u8 disconn_array[NUM_RX_CHAINS];
-       u8 delta_gain_code[NUM_RX_CHAINS];
-       u8 radio_write;
-};
-
-#define        EEPROM_SEM_TIMEOUT 10           /* milliseconds */
-#define EEPROM_SEM_RETRY_LIMIT 1000    /* number of attempts (not time) */
-
-
-#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
-
-enum {
-       MEASUREMENT_READY = (1 << 0),
-       MEASUREMENT_ACTIVE = (1 << 1),
-};
-
-#endif
-
-#define IWL_MAX_NUM_QUEUES     20 /* FIXME: do dynamic allocation */
-
-struct iwl_priv {
-
-       /* ieee device used by generic ieee processing code */
-       struct ieee80211_hw *hw;
-       struct ieee80211_channel *ieee_channels;
-       struct ieee80211_rate *ieee_rates;
-       struct iwl_cfg *cfg;
-
-       /* temporary frame storage list */
-       struct list_head free_frames;
-       int frames_count;
-
-       enum ieee80211_band band;
-       int alloc_rxb_skb;
-       bool add_radiotap;
-
-       void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
-                                      struct iwl4965_rx_mem_buffer *rxb);
-
-       struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
-
-#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
-       /* spectrum measurement report caching */
-       struct iwl4965_spectrum_notification measure_report;
-       u8 measurement_status;
-#endif
-       /* ucode beacon time */
-       u32 ucode_beacon_time;
-
-       /* we allocate array of iwl4965_channel_info for NIC's valid channels.
-        *    Access via channel # using indirect index array */
-       struct iwl_channel_info *channel_info;  /* channel info array */
-       u8 channel_count;       /* # of channels */
-
-       /* each calibration channel group in the EEPROM has a derived
-        * clip setting for each rate. */
-       const struct iwl4965_clip_group clip_groups[5];
-
-       /* thermal calibration */
-       s32 temperature;        /* degrees Kelvin */
-       s32 last_temperature;
-
-       /* Scan related variables */
-       unsigned long last_scan_jiffies;
-       unsigned long next_scan_jiffies;
-       unsigned long scan_start;
-       unsigned long scan_pass_start;
-       unsigned long scan_start_tsf;
-       int scan_bands;
-       int one_direct_scan;
-       u8 direct_ssid_len;
-       u8 direct_ssid[IW_ESSID_MAX_SIZE];
-       struct iwl4965_scan_cmd *scan;
-
-       /* spinlock */
-       spinlock_t lock;        /* protect general shared data */
-       spinlock_t hcmd_lock;   /* protect hcmd */
-       struct mutex mutex;
-
-       /* basic pci-network driver stuff */
-       struct pci_dev *pci_dev;
-
-       /* pci hardware address support */
-       void __iomem *hw_base;
-
-       /* uCode images, save to reload in case of failure */
-       struct fw_desc ucode_code;      /* runtime inst */
-       struct fw_desc ucode_data;      /* runtime data original */
-       struct fw_desc ucode_data_backup;       /* runtime data save/restore */
-       struct fw_desc ucode_init;      /* initialization inst */
-       struct fw_desc ucode_init_data; /* initialization data */
-       struct fw_desc ucode_boot;      /* bootstrap inst */
-
-
-       struct iwl4965_rxon_time_cmd rxon_timing;
-
-       /* We declare this const so it can only be
-        * 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;
-
-       int error_recovering;
-       struct iwl4965_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;
-#ifdef CONFIG_IWLWIFI_RFKILL
-       struct iwl_rfkill_mngr rfkill_mngr;
-#endif
-
-#ifdef CONFIG_IWLWIFI_LEDS
-       struct iwl4965_led led[IWL_LED_TRG_MAX];
-       unsigned long last_blink_time;
-       u8 last_blink_rate;
-       u8 allow_blinking;
-       u64 led_tpt;
-#endif
-
-       u16 active_rate;
-       u16 active_rate_basic;
-
-       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;
-       __le16 sensitivity_tbl[HD_TABLE_SIZE];
-#endif /*CONFIG_IWL4965_SENSITIVITY*/
-
-#ifdef CONFIG_IWL4965_HT
-       struct iwl_ht_info current_ht_config;
-#endif
-       u8 last_phy_res[100];
-
-       /* Rate scaling data */
-       struct iwl4965_lq_mngr lq_mngr;
-
-       /* Rate scaling data */
-       s8 data_retry_limit;
-       u8 retry_rate;
-
-       wait_queue_head_t wait_command_queue;
-
-       int activity_timer_active;
-
-       /* Rx and Tx DMA processing queues */
-       struct iwl4965_rx_queue rxq;
-       struct iwl4965_tx_queue txq[IWL_MAX_NUM_QUEUES];
-       unsigned long txq_ctx_active_msk;
-       struct iwl4965_kw kw;   /* keep warm address */
-       u32 scd_base_addr;      /* scheduler sram base address */
-
-       unsigned long status;
-
-       int last_rx_rssi;       /* From Rx packet statisitics */
-       int last_rx_noise;      /* From beacon statistics */
-
-       /* counts mgmt, ctl, and data packets */
-       struct traffic_stats {
-               u32 cnt;
-               u64 bytes;
-       } tx_stats[3], rx_stats[3];
-
-       struct iwl4965_power_mgr power_data;
-
-       struct iwl4965_notif_statistics statistics;
-       unsigned long last_statistics_time;
-
-       /* context information */
-       u8 essid[IW_ESSID_MAX_SIZE];
-       u8 essid_len;
-       u16 rates_mask;
-
-       u32 power_mode;
-       u32 antenna;
-       u8 bssid[ETH_ALEN];
-       u16 rts_threshold;
-       u8 mac_addr[ETH_ALEN];
-
-       /*station table variables */
-       spinlock_t sta_lock;
-       int num_stations;
-       struct iwl4965_station_entry stations[IWL_STATION_COUNT];
-       struct iwl_wep_key wep_keys[WEP_KEYS_MAX];
-       u8 default_wep_key;
-       u8 key_mapping_key;
-       unsigned long ucode_key_table;
-
-       /* Indication if ieee80211_ops->open has been called */
-       u8 is_open;
-
-       u8 mac80211_registered;
-
-       u32 notif_missed_beacons;
-
-       /* Rx'd packet timing information */
-       u32 last_beacon_time;
-       u64 last_tsf;
-
-       /* Duplicate packet detection */
-       u16 last_seq_num;
-       u16 last_frag_num;
-       unsigned long last_packet_time;
-
-       /* Hash table for finding stations in IBSS network */
-       struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE];
-
-       /* eeprom */
-       struct iwl4965_eeprom eeprom;
-
-       enum ieee80211_if_types iw_mode;
-
-       struct sk_buff *ibss_beacon;
-
-       /* Last Rx'd beacon timestamp */
-       u64 timestamp;
-       u16 beacon_int;
-       struct ieee80211_vif *vif;
-
-       struct iwl_hw_params hw_params;
-       /* driver/uCode shared Tx Byte Counts and Rx status */
-       void *shared_virt;
-       /* Physical Pointer to Tx Byte Counts and Rx status */
-       dma_addr_t shared_phys;
-
-       /* Current association information needed to configure the
-        * hardware */
-       u16 assoc_id;
-       u16 assoc_capability;
-       u8 ps_mode;
-
-       struct iwl4965_qos_info qos_data;
-
-       struct workqueue_struct *workqueue;
-
-       struct work_struct up;
-       struct work_struct restart;
-       struct work_struct calibrated_work;
-       struct work_struct scan_completed;
-       struct work_struct rx_replenish;
-       struct work_struct rf_kill;
-       struct work_struct abort_scan;
-       struct work_struct update_link_led;
-       struct work_struct auth_work;
-       struct work_struct report_work;
-       struct work_struct request_scan;
-       struct work_struct beacon_update;
-
-       struct tasklet_struct irq_tasklet;
-
-       struct delayed_work init_alive_start;
-       struct delayed_work alive_start;
-       struct delayed_work activity_timer;
-       struct delayed_work thermal_periodic;
-       struct delayed_work gather_stats;
-       struct delayed_work scan_check;
-       struct delayed_work post_associate;
-
-#define IWL_DEFAULT_TX_POWER 0x0F
-       s8 user_txpower_limit;
-       s8 max_channel_txpower_limit;
-
-#ifdef CONFIG_PM
-       u32 pm_state[16];
-#endif
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-       /* debugging info */
-       u32 framecnt_to_us;
-       atomic_t restrict_refcnt;
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-       /* debugfs */
-       struct iwl_debugfs *dbgfs;
-#endif /* CONFIG_IWLWIFI_DEBUGFS */
-#endif /* CONFIG_IWLWIFI_DEBUG */
-
-       struct work_struct txpower_work;
-#ifdef CONFIG_IWL4965_SENSITIVITY
-       struct work_struct sensitivity_work;
-#endif
-       struct timer_list statistics_periodic;
-}; /*iwl_priv */
-
-static inline int iwl_is_associated(struct iwl_priv *priv)
-{
-       return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
-}
-
-static inline int is_channel_valid(const struct iwl_channel_info *ch_info)
-{
-       if (ch_info == NULL)
-               return 0;
-       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;
-}
-
-static inline u8 is_channel_a_band(const struct iwl_channel_info *ch_info)
-{
-       return ch_info->band == IEEE80211_BAND_5GHZ;
-}
-
-static inline u8 is_channel_bg_band(const struct iwl_channel_info *ch_info)
-{
-       return ch_info->band == IEEE80211_BAND_2GHZ;
-}
-
-static inline int is_channel_passive(const struct iwl_channel_info *ch)
-{
-       return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0;
-}
-
-static inline int is_channel_ibss(const struct iwl_channel_info *ch)
-{
-       return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0;
-}
-
-extern const struct iwl_channel_info *iwl_get_channel_info(
-       const struct iwl_priv *priv, enum ieee80211_band band, u16 channel);
-
-/* Requires full declaration of iwl_priv before including */
-
-#endif                         /* __iwl4965_4965_h__ */
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..b5e28b8
--- /dev/null
@@ -0,0 +1,560 @@
+/******************************************************************************
+ *
+ * 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 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);
+
+       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);
+
+       iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
+                       APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+
+       iwl_release_nic_access(priv);
+
+       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);
+
+       /* disable L1 entry -- workaround for pre-B1 */
+       pci_write_config_byte(priv->pci_dev, PCI_LINK_CTRL, val_link & ~0x02);
+
+       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];
+}
+
+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.tx_cmd_len = sizeof(struct iwl4965_tx_cmd);
+       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 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;
+}
+
+
+static int iwl5000_disable_tx_fifo(struct iwl_priv *priv)
+{
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       ret = iwl_grab_nic_access(priv);
+       if (unlikely(ret)) {
+               IWL_ERROR("Tx fifo reset failed");
+               spin_unlock_irqrestore(&priv->lock, flags);
+               return ret;
+       }
+
+       iwl_write_prph(priv, IWL50_SCD_TXFACT, 0);
+       iwl_release_nic_access(priv);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+static struct iwl_hcmd_ops iwl5000_hcmd = {
+};
+
+static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
+       .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,
+       .disable_tx_fifo = iwl5000_disable_tx_fifo,
+       .apm_ops = {
+               .init = iwl5000_apm_init,
+               .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..1289d4c
--- /dev/null
@@ -0,0 +1,779 @@
+/******************************************************************************
+ *
+ * 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;
+
+       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;
+
+       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);
+
+       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);
+
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..933b0b0
--- /dev/null
@@ -0,0 +1,104 @@
+/******************************************************************************
+ *
+ * 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);
+
+static inline void iwl_chain_noise_reset(struct iwl_priv *priv)
+{
+       if (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)
+{
+}
+#endif
+
+#endif /* __iwl_calib_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
new file mode 100644 (file)
index 0000000..d16a853
--- /dev/null
@@ -0,0 +1,2805 @@
+/******************************************************************************
+ *
+ * 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.
+ *
+ *****************************************************************************/
+/*
+ * 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-dev.h for driver implementation definitions.
+ */
+
+#ifndef __iwl4965_commands_h__
+#define __iwl4965_commands_h__
+
+enum {
+       REPLY_ALIVE = 0x1,
+       REPLY_ERROR = 0x2,
+
+       /* RXON and QOS commands */
+       REPLY_RXON = 0x10,
+       REPLY_RXON_ASSOC = 0x11,
+       REPLY_QOS_PARAM = 0x13,
+       REPLY_RXON_TIMING = 0x14,
+
+       /* Multi-Station support */
+       REPLY_ADD_STA = 0x18,
+       REPLY_REMOVE_STA = 0x19,        /* not used */
+       REPLY_REMOVE_ALL_STA = 0x1a,    /* not used */
+
+       /* Security */
+       REPLY_WEPKEY = 0x20,
+
+       /* RX, TX, LEDs */
+       REPLY_TX = 0x1c,
+       REPLY_RATE_SCALE = 0x47,        /* 3945 only */
+       REPLY_LEDS_CMD = 0x48,
+       REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */
+
+       /* 802.11h related */
+       RADAR_NOTIFICATION = 0x70,      /* not used */
+       REPLY_QUIET_CMD = 0x71,         /* not used */
+       REPLY_CHANNEL_SWITCH = 0x72,
+       CHANNEL_SWITCH_NOTIFICATION = 0x73,
+       REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74,
+       SPECTRUM_MEASURE_NOTIFICATION = 0x75,
+
+       /* Power Management */
+       POWER_TABLE_CMD = 0x77,
+       PM_SLEEP_NOTIFICATION = 0x7A,
+       PM_DEBUG_STATISTIC_NOTIFIC = 0x7B,
+
+       /* Scan commands and notifications */
+       REPLY_SCAN_CMD = 0x80,
+       REPLY_SCAN_ABORT_CMD = 0x81,
+       SCAN_START_NOTIFICATION = 0x82,
+       SCAN_RESULTS_NOTIFICATION = 0x83,
+       SCAN_COMPLETE_NOTIFICATION = 0x84,
+
+       /* IBSS/AP commands */
+       BEACON_NOTIFICATION = 0x90,
+       REPLY_TX_BEACON = 0x91,
+       WHO_IS_AWAKE_NOTIFICATION = 0x94,       /* not used */
+
+       /* Miscellaneous commands */
+       QUIET_NOTIFICATION = 0x96,              /* not used */
+       REPLY_TX_PWR_TABLE_CMD = 0x97,
+       MEASURE_ABORT_NOTIFICATION = 0x99,      /* not used */
+
+       /* Bluetooth device coexistance config command */
+       REPLY_BT_CONFIG = 0x9b,
+
+       /* Statistics */
+       REPLY_STATISTICS_CMD = 0x9c,
+       STATISTICS_NOTIFICATION = 0x9d,
+
+       /* RF-KILL commands and notifications */
+       REPLY_CARD_STATE_CMD = 0xa0,
+       CARD_STATE_NOTIFICATION = 0xa1,
+
+       /* Missed beacons notification */
+       MISSED_BEACONS_NOTIFICATION = 0xa2,
+
+       REPLY_CT_KILL_CONFIG_CMD = 0xa4,
+       SENSITIVITY_CMD = 0xa8,
+       REPLY_PHY_CALIBRATION_CMD = 0xb0,
+       REPLY_RX_PHY_CMD = 0xc0,
+       REPLY_RX_MPDU_CMD = 0xc1,
+       REPLY_RX = 0xc3,
+       REPLY_COMPRESSED_BA = 0xc5,
+       REPLY_MAX = 0xff
+};
+
+/******************************************************************************
+ * (0)
+ * Commonly used structures and definitions:
+ * Command header, rate_n_flags, txpower
+ *
+ *****************************************************************************/
+
+/* iwl_cmd_header flags value */
+#define IWL_CMD_FAILED_MSK 0x40
+
+/**
+ * struct iwl_cmd_header
+ *
+ * This header format appears in the beginning of each command sent from the
+ * driver, and each response/notification received from uCode.
+ */
+struct iwl_cmd_header {
+       u8 cmd;         /* Command ID:  REPLY_RXON, etc. */
+       u8 flags;       /* IWL_CMD_* */
+       /*
+        * The driver sets up the sequence number to values of its chosing.
+        * uCode does not use this value, but passes it back to the driver
+        * when sending the response to each driver-originated command, so
+        * the driver can match the response to the command.  Since the values
+        * don't get used by uCode, the driver may set up an arbitrary format.
+        *
+        * There is one exception:  uCode sets bit 15 when it originates
+        * the response/notification, i.e. when the response/notification
+        * is not a direct response to a command sent by the driver.  For
+        * example, uCode issues REPLY_3945_RX when it sends a received frame
+        * to the driver; it is not a direct response to any driver command.
+        *
+        * The Linux driver uses the following format:
+        *
+        *  0:7    index/position within Tx queue
+        *  8:13   Tx queue selection
+        * 14:14   driver sets this to indicate command is in the 'huge'
+        *         storage at the end of the command buffers, i.e. scan cmd
+        * 15:15   uCode sets this in uCode-originated response/notification
+        */
+       __le16 sequence;
+
+       /* command or response/notification data follows immediately */
+       u8 data[0];
+} __attribute__ ((packed));
+
+/**
+ * 4965 rate_n_flags bit fields
+ *
+ * rate_n_flags format is used in following 4965 commands:
+ *  REPLY_RX (response only)
+ *  REPLY_TX (both command and response)
+ *  REPLY_TX_LINK_QUALITY_CMD
+ *
+ * High-throughput (HT) rate format for bits 7:0 (bit 8 must be "1"):
+ *  2-0:  0)   6 Mbps
+ *        1)  12 Mbps
+ *        2)  18 Mbps
+ *        3)  24 Mbps
+ *        4)  36 Mbps
+ *        5)  48 Mbps
+ *        6)  54 Mbps
+ *        7)  60 Mbps
+ *
+ *    3:  0)  Single stream (SISO)
+ *        1)  Dual stream (MIMO)
+ *
+ *    5:  Value of 0x20 in bits 7:0 indicates 6 Mbps FAT duplicate data
+ *
+ * Legacy OFDM rate format for bits 7:0 (bit 8 must be "0", bit 9 "0"):
+ *  3-0:  0xD)   6 Mbps
+ *        0xF)   9 Mbps
+ *        0x5)  12 Mbps
+ *        0x7)  18 Mbps
+ *        0x9)  24 Mbps
+ *        0xB)  36 Mbps
+ *        0x1)  48 Mbps
+ *        0x3)  54 Mbps
+ *
+ * Legacy CCK rate format for bits 7:0 (bit 8 must be "0", bit 9 "1"):
+ *  3-0:   10)  1 Mbps
+ *         20)  2 Mbps
+ *         55)  5.5 Mbps
+ *        110)  11 Mbps
+ */
+#define RATE_MCS_CODE_MSK 0x7
+#define RATE_MCS_MIMO_POS 3
+#define RATE_MCS_MIMO_MSK 0x8
+#define RATE_MCS_HT_DUP_POS 5
+#define RATE_MCS_HT_DUP_MSK 0x20
+
+/* Bit 8: (1) HT format, (0) legacy format in bits 7:0 */
+#define RATE_MCS_FLAGS_POS 8
+#define RATE_MCS_HT_POS 8
+#define RATE_MCS_HT_MSK 0x100
+
+/* Bit 9: (1) CCK, (0) OFDM.  HT (bit 8) must be "0" for this bit to be valid */
+#define RATE_MCS_CCK_POS 9
+#define RATE_MCS_CCK_MSK 0x200
+
+/* Bit 10: (1) Use Green Field preamble */
+#define RATE_MCS_GF_POS 10
+#define RATE_MCS_GF_MSK 0x400
+
+/* Bit 11: (1) Use 40Mhz FAT chnl width, (0) use 20 MHz legacy chnl width */
+#define RATE_MCS_FAT_POS 11
+#define RATE_MCS_FAT_MSK 0x800
+
+/* Bit 12: (1) Duplicate data on both 20MHz chnls.  FAT (bit 11) must be set. */
+#define RATE_MCS_DUP_POS 12
+#define RATE_MCS_DUP_MSK 0x1000
+
+/* Bit 13: (1) Short guard interval (0.4 usec), (0) normal GI (0.8 usec) */
+#define RATE_MCS_SGI_POS 13
+#define RATE_MCS_SGI_MSK 0x2000
+
+/**
+ * rate_n_flags Tx antenna masks (4965 has 2 transmitters):
+ * bit14:15 01 B inactive, A active
+ *          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_C_MSK    0x10000
+#define RATE_MCS_ANT_ABC_MSK  0x1C000
+
+
+/**
+ * struct iwl4965_tx_power - txpower format used in REPLY_SCAN_CMD
+ *
+ * Scan uses only one transmitter, so only one analog/dsp gain pair is needed.
+ */
+struct iwl4965_tx_power {
+       u8 tx_gain;             /* gain for analog radio */
+       u8 dsp_atten;           /* gain for DSP */
+} __attribute__ ((packed));
+
+#define POWER_TABLE_NUM_ENTRIES                        33
+#define POWER_TABLE_NUM_HT_OFDM_ENTRIES                32
+#define POWER_TABLE_CCK_ENTRY                  32
+
+/**
+ * union iwl4965_tx_power_dual_stream
+ *
+ * Host format used for REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
+ * Use __le32 version (struct tx_power_dual_stream) when building command.
+ *
+ * Driver provides radio gain and DSP attenuation settings to device in pairs,
+ * one value for each transmitter chain.  The first value is for transmitter A,
+ * second for transmitter B.
+ *
+ * For SISO bit rates, both values in a pair should be identical.
+ * For MIMO rates, one value may be different from the other,
+ * in order to balance the Tx output between the two transmitters.
+ *
+ * See more details in doc for TXPOWER in iwl-4965-hw.h.
+ */
+union iwl4965_tx_power_dual_stream {
+       struct {
+               u8 radio_tx_gain[2];
+               u8 dsp_predis_atten[2];
+       } s;
+       u32 dw;
+};
+
+/**
+ * struct tx_power_dual_stream
+ *
+ * Table entries in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
+ *
+ * Same format as iwl_tx_power_dual_stream, but __le32
+ */
+struct tx_power_dual_stream {
+       __le32 dw;
+} __attribute__ ((packed));
+
+/**
+ * struct iwl4965_tx_power_db
+ *
+ * Entire table within REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
+ */
+struct iwl4965_tx_power_db {
+       struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES];
+} __attribute__ ((packed));
+
+
+/******************************************************************************
+ * (0a)
+ * Alive and Error Commands & Responses:
+ *
+ *****************************************************************************/
+
+#define UCODE_VALID_OK __constant_cpu_to_le32(0x1)
+#define INITIALIZE_SUBTYPE    (9)
+
+/*
+ * ("Initialize") REPLY_ALIVE = 0x1 (response only, not a command)
+ *
+ * uCode issues this "initialize alive" notification once the initialization
+ * uCode image has completed its work, and is ready to load the runtime image.
+ * This is the *first* "alive" notification that the driver will receive after
+ * rebooting uCode; the "initialize" alive is indicated by subtype field == 9.
+ *
+ * See comments documenting "BSM" (bootstrap state machine).
+ *
+ * For 4965, this notification contains important calibration data for
+ * calculating txpower settings:
+ *
+ * 1)  Power supply voltage indication.  The voltage sensor outputs higher
+ *     values for lower voltage, and vice versa.
+ *
+ * 2)  Temperature measurement parameters, for each of two channel widths
+ *     (20 MHz and 40 MHz) supported by the radios.  Temperature sensing
+ *     is done via one of the receiver chains, and channel width influences
+ *     the results.
+ *
+ * 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 {
+       u8 ucode_minor;
+       u8 ucode_major;
+       __le16 reserved1;
+       u8 sw_rev[8];
+       u8 ver_type;
+       u8 ver_subtype;         /* "9" for initialize alive */
+       __le16 reserved2;
+       __le32 log_event_table_ptr;
+       __le32 error_event_table_ptr;
+       __le32 timestamp;
+       __le32 is_valid;
+
+       /* calibration values from "initialize" uCode */
+       __le32 voltage;         /* signed, higher value is lower voltage */
+       __le32 therm_r1[2];     /* signed, 1st for normal, 2nd for FAT channel*/
+       __le32 therm_r2[2];     /* signed */
+       __le32 therm_r3[2];     /* signed */
+       __le32 therm_r4[2];     /* signed */
+       __le32 tx_atten[5][2];  /* signed MIMO gain comp, 5 freq groups,
+                                * 2 Tx chains */
+} __attribute__ ((packed));
+
+
+/**
+ * REPLY_ALIVE = 0x1 (response only, not a command)
+ *
+ * uCode issues this "alive" notification once the runtime image is ready
+ * to receive commands from the driver.  This is the *second* "alive"
+ * notification that the driver will receive after rebooting uCode;
+ * this "alive" is indicated by subtype field != 9.
+ *
+ * See comments documenting "BSM" (bootstrap state machine).
+ *
+ * This response includes two pointers to structures within the device's
+ * data SRAM (access via HBUS_TARG_MEM_* regs) that are useful for debugging:
+ *
+ * 1)  log_event_table_ptr indicates base of the event log.  This traces
+ *     a 256-entry history of uCode execution within a circular buffer.
+ *     Its header format is:
+ *
+ *     __le32 log_size;     log capacity (in number of entries)
+ *     __le32 type;         (1) timestamp with each entry, (0) no timestamp
+ *     __le32 wraps;        # times uCode has wrapped to top of circular buffer
+ *      __le32 write_index;  next circular buffer entry that uCode would fill
+ *
+ *     The header is followed by the circular buffer of log entries.  Entries
+ *     with timestamps have the following format:
+ *
+ *     __le32 event_id;     range 0 - 1500
+ *     __le32 timestamp;    low 32 bits of TSF (of network, if associated)
+ *     __le32 data;         event_id-specific data value
+ *
+ *     Entries without timestamps contain only event_id and data.
+ *
+ * 2)  error_event_table_ptr indicates base of the error log.  This contains
+ *     information about any uCode error that occurs.  For 4965, the format
+ *     of the error log is:
+ *
+ *     __le32 valid;        (nonzero) valid, (0) log is empty
+ *     __le32 error_id;     type of error
+ *     __le32 pc;           program counter
+ *     __le32 blink1;       branch link
+ *     __le32 blink2;       branch link
+ *     __le32 ilink1;       interrupt link
+ *     __le32 ilink2;       interrupt link
+ *     __le32 data1;        error-specific data
+ *     __le32 data2;        error-specific data
+ *     __le32 line;         source code line of error
+ *     __le32 bcon_time;    beacon timer
+ *     __le32 tsf_low;      network timestamp function timer
+ *     __le32 tsf_hi;       network timestamp function timer
+ *
+ * The Linux driver can print both logs to the system log when a uCode error
+ * occurs.
+ */
+struct iwl4965_alive_resp {
+       u8 ucode_minor;
+       u8 ucode_major;
+       __le16 reserved1;
+       u8 sw_rev[8];
+       u8 ver_type;
+       u8 ver_subtype;                 /* not "9" for runtime alive */
+       __le16 reserved2;
+       __le32 log_event_table_ptr;     /* SRAM address for event log */
+       __le32 error_event_table_ptr;   /* SRAM address for error log */
+       __le32 timestamp;
+       __le32 is_valid;
+} __attribute__ ((packed));
+
+
+union tsf {
+       u8 byte[8];
+       __le16 word[4];
+       __le32 dw[2];
+};
+
+/*
+ * REPLY_ERROR = 0x2 (response only, not a command)
+ */
+struct iwl4965_error_resp {
+       __le32 error_type;
+       u8 cmd_id;
+       u8 reserved1;
+       __le16 bad_cmd_seq_num;
+       __le32 error_info;
+       union tsf timestamp;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (1)
+ * RXON Commands & Responses:
+ *
+ *****************************************************************************/
+
+/*
+ * Rx config defines & structure
+ */
+/* rx_config device types  */
+enum {
+       RXON_DEV_TYPE_AP = 1,
+       RXON_DEV_TYPE_ESS = 3,
+       RXON_DEV_TYPE_IBSS = 4,
+       RXON_DEV_TYPE_SNIFFER = 6,
+};
+
+
+#define RXON_RX_CHAIN_DRIVER_FORCE_MSK         __constant_cpu_to_le16(0x1 << 0)
+#define RXON_RX_CHAIN_VALID_MSK                        __constant_cpu_to_le16(0x7 << 1)
+#define RXON_RX_CHAIN_VALID_POS                        (1)
+#define RXON_RX_CHAIN_FORCE_SEL_MSK            __constant_cpu_to_le16(0x7 << 4)
+#define RXON_RX_CHAIN_FORCE_SEL_POS            (4)
+#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK       __constant_cpu_to_le16(0x7 << 7)
+#define RXON_RX_CHAIN_FORCE_MIMO_SEL_POS       (7)
+#define RXON_RX_CHAIN_CNT_MSK                  __constant_cpu_to_le16(0x3 << 10)
+#define RXON_RX_CHAIN_CNT_POS                  (10)
+#define RXON_RX_CHAIN_MIMO_CNT_MSK             __constant_cpu_to_le16(0x3 << 12)
+#define RXON_RX_CHAIN_MIMO_CNT_POS             (12)
+#define RXON_RX_CHAIN_MIMO_FORCE_MSK           __constant_cpu_to_le16(0x1 << 14)
+#define RXON_RX_CHAIN_MIMO_FORCE_POS           (14)
+
+/* rx_config flags */
+/* band & modulation selection */
+#define RXON_FLG_BAND_24G_MSK           __constant_cpu_to_le32(1 << 0)
+#define RXON_FLG_CCK_MSK                __constant_cpu_to_le32(1 << 1)
+/* auto detection enable */
+#define RXON_FLG_AUTO_DETECT_MSK        __constant_cpu_to_le32(1 << 2)
+/* TGg protection when tx */
+#define RXON_FLG_TGG_PROTECT_MSK        __constant_cpu_to_le32(1 << 3)
+/* cck short slot & preamble */
+#define RXON_FLG_SHORT_SLOT_MSK          __constant_cpu_to_le32(1 << 4)
+#define RXON_FLG_SHORT_PREAMBLE_MSK     __constant_cpu_to_le32(1 << 5)
+/* antenna selection */
+#define RXON_FLG_DIS_DIV_MSK            __constant_cpu_to_le32(1 << 7)
+#define RXON_FLG_ANT_SEL_MSK            __constant_cpu_to_le32(0x0f00)
+#define RXON_FLG_ANT_A_MSK              __constant_cpu_to_le32(1 << 8)
+#define RXON_FLG_ANT_B_MSK              __constant_cpu_to_le32(1 << 9)
+/* radar detection enable */
+#define RXON_FLG_RADAR_DETECT_MSK       __constant_cpu_to_le32(1 << 12)
+#define RXON_FLG_TGJ_NARROW_BAND_MSK    __constant_cpu_to_le32(1 << 13)
+/* rx response to host with 8-byte TSF
+* (according to ON_AIR deassertion) */
+#define RXON_FLG_TSF2HOST_MSK           __constant_cpu_to_le32(1 << 15)
+
+
+/* HT flags */
+#define RXON_FLG_CTRL_CHANNEL_LOC_POS          (22)
+#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK       __constant_cpu_to_le32(0x1 << 22)
+
+#define RXON_FLG_HT_OPERATING_MODE_POS         (23)
+
+#define RXON_FLG_HT_PROT_MSK                   __constant_cpu_to_le32(0x1 << 23)
+#define RXON_FLG_FAT_PROT_MSK                  __constant_cpu_to_le32(0x2 << 23)
+
+#define RXON_FLG_CHANNEL_MODE_POS              (25)
+#define RXON_FLG_CHANNEL_MODE_MSK              __constant_cpu_to_le32(0x3 << 25)
+#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK      __constant_cpu_to_le32(0x1 << 25)
+#define RXON_FLG_CHANNEL_MODE_MIXED_MSK                __constant_cpu_to_le32(0x2 << 25)
+
+/* rx_config filter flags */
+/* accept all data frames */
+#define RXON_FILTER_PROMISC_MSK         __constant_cpu_to_le32(1 << 0)
+/* pass control & management to host */
+#define RXON_FILTER_CTL2HOST_MSK        __constant_cpu_to_le32(1 << 1)
+/* accept multi-cast */
+#define RXON_FILTER_ACCEPT_GRP_MSK      __constant_cpu_to_le32(1 << 2)
+/* don't decrypt uni-cast frames */
+#define RXON_FILTER_DIS_DECRYPT_MSK     __constant_cpu_to_le32(1 << 3)
+/* don't decrypt multi-cast frames */
+#define RXON_FILTER_DIS_GRP_DECRYPT_MSK __constant_cpu_to_le32(1 << 4)
+/* STA is associated */
+#define RXON_FILTER_ASSOC_MSK           __constant_cpu_to_le32(1 << 5)
+/* transfer to host non bssid beacons in associated state */
+#define RXON_FILTER_BCON_AWARE_MSK      __constant_cpu_to_le32(1 << 6)
+
+/**
+ * REPLY_RXON = 0x10 (command, has simple generic response)
+ *
+ * RXON tunes the radio tuner to a service channel, and sets up a number
+ * of parameters that are used primarily for Rx, but also for Tx operations.
+ *
+ * NOTE:  When tuning to a new channel, driver must set the
+ *        RXON_FILTER_ASSOC_MSK to 0.  This will clear station-dependent
+ *        info within the device, including the station tables, tx retry
+ *        rate tables, and txpower tables.  Driver must build a new station
+ *        table and txpower table before transmitting anything on the RXON
+ *        channel.
+ *
+ * NOTE:  All RXONs wipe clean the internal txpower table.  Driver must
+ *        issue a new REPLY_TX_PWR_TABLE_CMD after each REPLY_RXON (0x10),
+ *        regardless of whether RXON_FILTER_ASSOC_MSK is set.
+ */
+struct iwl4965_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;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response)
+ */
+struct iwl4965_rxon_assoc_cmd {
+       __le32 flags;
+       __le32 filter_flags;
+       u8 ofdm_basic_rates;
+       u8 cck_basic_rates;
+       u8 ofdm_ht_single_stream_basic_rates;
+       u8 ofdm_ht_dual_stream_basic_rates;
+       __le16 rx_chain_select_flags;
+       __le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
+ */
+struct iwl4965_rxon_time_cmd {
+       union tsf timestamp;
+       __le16 beacon_interval;
+       __le16 atim_window;
+       __le32 beacon_init_val;
+       __le16 listen_interval;
+       __le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response)
+ */
+struct iwl4965_channel_switch_cmd {
+       u8 band;
+       u8 expect_beacon;
+       __le16 channel;
+       __le32 rxon_flags;
+       __le32 rxon_filter_flags;
+       __le32 switch_time;
+       struct iwl4965_tx_power_db tx_power;
+} __attribute__ ((packed));
+
+/*
+ * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command)
+ */
+struct iwl4965_csa_notification {
+       __le16 band;
+       __le16 channel;
+       __le32 status;          /* 0 - OK, 1 - fail */
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (2)
+ * Quality-of-Service (QOS) Commands & Responses:
+ *
+ *****************************************************************************/
+
+/**
+ * struct iwl_ac_qos -- QOS timing params for REPLY_QOS_PARAM
+ * One for each of 4 EDCA access categories in struct iwl_qosparam_cmd
+ *
+ * @cw_min: Contention window, start value in numbers of slots.
+ *          Should be a power-of-2, minus 1.  Device's default is 0x0f.
+ * @cw_max: Contention window, max value in numbers of slots.
+ *          Should be a power-of-2, minus 1.  Device's default is 0x3f.
+ * @aifsn:  Number of slots in Arbitration Interframe Space (before
+ *          performing random backoff timing prior to Tx).  Device default 1.
+ * @edca_txop:  Length of Tx opportunity, in uSecs.  Device default is 0.
+ *
+ * Device will automatically increase contention window by (2*CW) + 1 for each
+ * transmission retry.  Device uses cw_max as a bit mask, ANDed with new CW
+ * value, to cap the CW value.
+ */
+struct iwl4965_ac_qos {
+       __le16 cw_min;
+       __le16 cw_max;
+       u8 aifsn;
+       u8 reserved1;
+       __le16 edca_txop;
+} __attribute__ ((packed));
+
+/* QoS flags defines */
+#define QOS_PARAM_FLG_UPDATE_EDCA_MSK  __constant_cpu_to_le32(0x01)
+#define QOS_PARAM_FLG_TGN_MSK          __constant_cpu_to_le32(0x02)
+#define QOS_PARAM_FLG_TXOP_TYPE_MSK    __constant_cpu_to_le32(0x10)
+
+/* Number of Access Categories (AC) (EDCA), queues 0..3 */
+#define AC_NUM                4
+
+/*
+ * REPLY_QOS_PARAM = 0x13 (command, has simple generic response)
+ *
+ * This command sets up timings for each of the 4 prioritized EDCA Tx FIFOs
+ * 0: Background, 1: Best Effort, 2: Video, 3: Voice.
+ */
+struct iwl4965_qosparam_cmd {
+       __le32 qos_flags;
+       struct iwl4965_ac_qos ac[AC_NUM];
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (3)
+ * Add/Modify Stations Commands & Responses:
+ *
+ *****************************************************************************/
+/*
+ * Multi station support
+ */
+
+/* Special, dedicated locations within device's station table */
+#define        IWL_AP_ID               0
+#define IWL_MULTICAST_ID       1
+#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
+
+#define STA_FLG_PWR_SAVE_MSK           __constant_cpu_to_le32(1 << 8);
+#define STA_FLG_RTS_MIMO_PROT_MSK      __constant_cpu_to_le32(1 << 17)
+#define STA_FLG_AGG_MPDU_8US_MSK       __constant_cpu_to_le32(1 << 18)
+#define STA_FLG_MAX_AGG_SIZE_POS       (19)
+#define STA_FLG_MAX_AGG_SIZE_MSK       __constant_cpu_to_le32(3 << 19)
+#define STA_FLG_FAT_EN_MSK             __constant_cpu_to_le32(1 << 21)
+#define STA_FLG_MIMO_DIS_MSK           __constant_cpu_to_le32(1 << 22)
+#define STA_FLG_AGG_MPDU_DENSITY_POS   (23)
+#define STA_FLG_AGG_MPDU_DENSITY_MSK   __constant_cpu_to_le32(7 << 23)
+
+/* Use in mode field.  1: modify existing entry, 0: add new station entry */
+#define STA_CONTROL_MODIFY_MSK         0x01
+
+/* key flags __le16*/
+#define STA_KEY_FLG_ENCRYPT_MSK        __constant_cpu_to_le16(0x0007)
+#define STA_KEY_FLG_NO_ENC     __constant_cpu_to_le16(0x0000)
+#define STA_KEY_FLG_WEP                __constant_cpu_to_le16(0x0001)
+#define STA_KEY_FLG_CCMP       __constant_cpu_to_le16(0x0002)
+#define STA_KEY_FLG_TKIP       __constant_cpu_to_le16(0x0003)
+
+#define STA_KEY_FLG_KEYID_POS  8
+#define STA_KEY_FLG_INVALID    __constant_cpu_to_le16(0x0800)
+/* wep key is either from global key (0) or from station info array (1) */
+#define STA_KEY_FLG_MAP_KEY_MSK        __constant_cpu_to_le16(0x0008)
+
+/* wep key in STA: 5-bytes (0) or 13-bytes (1) */
+#define STA_KEY_FLG_KEY_SIZE_MSK     __constant_cpu_to_le16(0x1000)
+#define STA_KEY_MULTICAST_MSK        __constant_cpu_to_le16(0x4000)
+#define STA_KEY_MAX_NUM                8
+
+/* Flags indicate whether to modify vs. don't change various station params */
+#define        STA_MODIFY_KEY_MASK             0x01
+#define        STA_MODIFY_TID_DISABLE_TX       0x02
+#define        STA_MODIFY_TX_RATE_MSK          0x04
+#define STA_MODIFY_ADDBA_TID_MSK       0x08
+#define STA_MODIFY_DELBA_TID_MSK       0x10
+
+/* Receiver address (actually, Rx station's index into station table),
+ * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */
+#define BUILD_RAxTID(sta_id, tid)      (((sta_id) << 4) + (tid))
+
+struct iwl4965_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 */
+} __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
+ * @sta_id: index of station in uCode's station table
+ * @modify_mask: STA_MODIFY_*, 1: modify, 0: don't change
+ *
+ * Driver selects unused table index when adding new station,
+ * or the index to a pre-existing station entry when modifying that station.
+ * Some indexes have special purposes (IWL_AP_ID, index 0, is for AP).
+ *
+ * modify_mask flags select which parameters to modify vs. leave alone.
+ */
+struct sta_id_modify {
+       u8 addr[ETH_ALEN];
+       __le16 reserved1;
+       u8 sta_id;
+       u8 modify_mask;
+       __le16 reserved2;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_ADD_STA = 0x18 (command)
+ *
+ * The device contains an internal table of per-station information,
+ * with info on security keys, aggregation parameters, and Tx rates for
+ * initial Tx attempt and any retries (4965 uses REPLY_TX_LINK_QUALITY_CMD,
+ * 3945 uses REPLY_RATE_SCALE to set up rate tables).
+ *
+ * REPLY_ADD_STA sets up the table entry for one station, either creating
+ * a new entry, or modifying a pre-existing one.
+ *
+ * NOTE:  RXON command (without "associated" bit set) wipes the station table
+ *        clean.  Moving into RF_KILL state does this also.  Driver must set up
+ *        new station table before transmitting anything on the RXON channel
+ *        (except active scans or active measurements; those commands carry
+ *        their own txpower/rate setup data).
+ *
+ *        When getting started on a new channel, driver must set up the
+ *        IWL_BROADCAST_ID entry (last entry in the table).  For a client
+ *        station in a BSS, once an AP is selected, driver sets up the AP STA
+ *        in the IWL_AP_ID entry (1st entry in the table).  BROADCAST and AP
+ *        are all that are needed for a BSS client station.  If the device is
+ *        used as AP, or in an IBSS network, driver must set up station table
+ *        entries for all STAs in network, starting with index IWL_STA_ID.
+ */
+struct iwl4965_addsta_cmd {
+       u8 mode;                /* 1: modify existing, 0: add new station */
+       u8 reserved[3];
+       struct sta_id_modify sta;
+       struct iwl4965_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));
+
+/* 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
+#define ADD_STA_MODIFY_NON_EXIST_STA   0x8
+/*
+ * REPLY_ADD_STA = 0x18 (response)
+ */
+struct iwl4965_add_sta_resp {
+       u8 status;      /* ADD_STA_* */
+} __attribute__ ((packed));
+
+/*
+ * REPLY_WEP_KEY = 0x20
+ */
+struct iwl_wep_key {
+       u8 key_index;
+       u8 key_offset;
+       u8 reserved1[2];
+       u8 key_size;
+       u8 reserved2[3];
+       u8 key[16];
+} __attribute__ ((packed));
+
+struct iwl_wep_cmd {
+       u8 num_keys;
+       u8 global_key_type;
+       u8 flags;
+       u8 reserved;
+       struct iwl_wep_key key[0];
+} __attribute__ ((packed));
+
+#define WEP_KEY_WEP_TYPE 1
+#define WEP_KEYS_MAX 4
+#define WEP_INVALID_OFFSET 0xff
+#define WEP_KEY_LEN_128 13
+
+/******************************************************************************
+ * (4)
+ * Rx Responses:
+ *
+ *****************************************************************************/
+
+struct iwl4965_rx_frame_stats {
+       u8 phy_count;
+       u8 id;
+       u8 rssi;
+       u8 agc;
+       __le16 sig_avg;
+       __le16 noise_diff;
+       u8 payload[0];
+} __attribute__ ((packed));
+
+struct iwl4965_rx_frame_hdr {
+       __le16 channel;
+       __le16 phy_flags;
+       u8 reserved1;
+       u8 rate;
+       __le16 len;
+       u8 payload[0];
+} __attribute__ ((packed));
+
+#define RX_RES_STATUS_NO_CRC32_ERROR   __constant_cpu_to_le32(1 << 0)
+#define RX_RES_STATUS_NO_RXE_OVERFLOW  __constant_cpu_to_le32(1 << 1)
+
+#define RX_RES_PHY_FLAGS_BAND_24_MSK   __constant_cpu_to_le16(1 << 0)
+#define RX_RES_PHY_FLAGS_MOD_CCK_MSK           __constant_cpu_to_le16(1 << 1)
+#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK    __constant_cpu_to_le16(1 << 2)
+#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK       __constant_cpu_to_le16(1 << 3)
+#define RX_RES_PHY_FLAGS_ANTENNA_MSK           __constant_cpu_to_le16(0xf0)
+
+#define RX_RES_STATUS_SEC_TYPE_MSK     (0x7 << 8)
+#define RX_RES_STATUS_SEC_TYPE_NONE    (0x0 << 8)
+#define RX_RES_STATUS_SEC_TYPE_WEP     (0x1 << 8)
+#define RX_RES_STATUS_SEC_TYPE_CCMP    (0x2 << 8)
+#define RX_RES_STATUS_SEC_TYPE_TKIP    (0x3 << 8)
+#define        RX_RES_STATUS_SEC_TYPE_ERR      (0x7 << 8)
+
+#define RX_RES_STATUS_STATION_FOUND    (1<<6)
+#define RX_RES_STATUS_NO_STATION_INFO_MISMATCH (1<<7)
+
+#define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11)
+#define RX_RES_STATUS_NOT_DECRYPT      (0x0 << 11)
+#define RX_RES_STATUS_DECRYPT_OK       (0x3 << 11)
+#define RX_RES_STATUS_BAD_ICV_MIC      (0x1 << 11)
+#define RX_RES_STATUS_BAD_KEY_TTAK     (0x2 << 11)
+
+#define RX_MPDU_RES_STATUS_ICV_OK      (0x20)
+#define RX_MPDU_RES_STATUS_MIC_OK      (0x40)
+#define RX_MPDU_RES_STATUS_TTAK_OK     (1 << 7)
+#define RX_MPDU_RES_STATUS_DEC_DONE_MSK        (0x800)
+
+struct iwl4965_rx_frame_end {
+       __le32 status;
+       __le64 timestamp;
+       __le32 beacon_timestamp;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_3945_RX = 0x1b (response only, not a command)
+ *
+ * NOTE:  DO NOT dereference from casts to this structure
+ * It is provided only for calculating minimum data set size.
+ * The actual offsets of the hdr and end are dynamic based on
+ * stats.phy_count
+ */
+struct iwl4965_rx_frame {
+       struct iwl4965_rx_frame_stats stats;
+       struct iwl4965_rx_frame_hdr hdr;
+       struct iwl4965_rx_frame_end end;
+} __attribute__ ((packed));
+
+/* Fixed (non-configurable) rx data from phy */
+#define RX_PHY_FLAGS_ANTENNAE_OFFSET           (4)
+#define RX_PHY_FLAGS_ANTENNAE_MASK             (0x70)
+#define IWL_AGC_DB_MASK        (0x3f80)        /* MASK(7,13) */
+#define IWL_AGC_DB_POS         (7)
+struct iwl4965_rx_non_cfg_phy {
+       __le16 ant_selection;   /* ant A bit 4, ant B bit 5, ant C bit 6 */
+       __le16 agc_info;        /* agc code 0:6, agc dB 7:13, reserved 14:15 */
+       u8 rssi_info[6];        /* we use even entries, 0/2/4 for A/B/C rssi */
+       u8 pad[0];
+} __attribute__ ((packed));
+
+/*
+ * REPLY_RX = 0xc3 (response only, not a command)
+ * Used only for legacy (non 11n) frames.
+ */
+#define RX_RES_PHY_CNT 14
+struct iwl4965_rx_phy_res {
+       u8 non_cfg_phy_cnt;     /* non configurable DSP phy data byte count */
+       u8 cfg_phy_cnt;         /* configurable DSP phy data byte count */
+       u8 stat_id;             /* configurable DSP phy data set ID */
+       u8 reserved1;
+       __le64 timestamp;       /* TSF at on air rise */
+       __le32 beacon_time_stamp; /* beacon at on-air rise */
+       __le16 phy_flags;       /* general phy flags: band, modulation, ... */
+       __le16 channel;         /* channel number */
+       __le16 non_cfg_phy[RX_RES_PHY_CNT];     /* upto 14 phy entries */
+       __le32 reserved2;
+       __le32 rate_n_flags;    /* RATE_MCS_* */
+       __le16 byte_count;      /* frame's byte-count */
+       __le16 reserved3;
+} __attribute__ ((packed));
+
+struct iwl4965_rx_mpdu_res_start {
+       __le16 byte_count;
+       __le16 reserved;
+} __attribute__ ((packed));
+
+
+/******************************************************************************
+ * (5)
+ * Tx Commands & Responses:
+ *
+ * Driver must place each REPLY_TX command into one of the prioritized Tx
+ * queues in host DRAM, shared between driver and device (see comments for
+ * SCD registers and Tx/Rx Queues).  When the device's Tx scheduler and uCode
+ * are preparing to transmit, the device pulls the Tx command over the PCI
+ * bus via one of the device's Tx DMA channels, to fill an internal FIFO
+ * from which data will be transmitted.
+ *
+ * uCode handles all timing and protocol related to control frames
+ * (RTS/CTS/ACK), based on flags in the Tx command.  uCode and Tx scheduler
+ * handle reception of block-acks; uCode updates the host driver via
+ * REPLY_COMPRESSED_BA (4965).
+ *
+ * uCode handles retrying Tx when an ACK is expected but not received.
+ * This includes trying lower data rates than the one requested in the Tx
+ * command, as set up by the REPLY_RATE_SCALE (for 3945) or
+ * REPLY_TX_LINK_QUALITY_CMD (4965).
+ *
+ * Driver sets up transmit power for various rates via REPLY_TX_PWR_TABLE_CMD.
+ * This command must be executed after every RXON command, before Tx can occur.
+ *****************************************************************************/
+
+/* REPLY_TX Tx flags field */
+
+/* 1: Use Request-To-Send protocol before this frame.
+ * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */
+#define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1)
+
+/* 1: Transmit Clear-To-Send to self before this frame.
+ * Driver should set this for AUTH/DEAUTH/ASSOC-REQ/REASSOC mgmnt frames.
+ * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK. */
+#define TX_CMD_FLG_CTS_MSK __constant_cpu_to_le32(1 << 2)
+
+/* 1: Expect ACK from receiving station
+ * 0: Don't expect ACK (MAC header's duration field s/b 0)
+ * Set this for unicast frames, but not broadcast/multicast. */
+#define TX_CMD_FLG_ACK_MSK __constant_cpu_to_le32(1 << 3)
+
+/* For 4965:
+ * 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD).
+ *    Tx command's initial_rate_index indicates first rate to try;
+ *    uCode walks through table for additional Tx attempts.
+ * 0: Use Tx rate/MCS from Tx command's rate_n_flags field.
+ *    This rate will be used for all Tx attempts; it will not be scaled. */
+#define TX_CMD_FLG_STA_RATE_MSK __constant_cpu_to_le32(1 << 4)
+
+/* 1: Expect immediate block-ack.
+ * Set when Txing a block-ack request frame.  Also set TX_CMD_FLG_ACK_MSK. */
+#define TX_CMD_FLG_IMM_BA_RSP_MASK  __constant_cpu_to_le32(1 << 6)
+
+/* 1: Frame requires full Tx-Op protection.
+ * Set this if either RTS or CTS Tx Flag gets set. */
+#define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7)
+
+/* Tx antenna selection field; used only for 3945, reserved (0) for 4965.
+ * Set field to "0" to allow 3945 uCode to select antenna (normal usage). */
+#define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00)
+#define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8)
+#define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9)
+
+/* 1: Ignore Bluetooth priority for this frame.
+ * 0: Delay Tx until Bluetooth device is done (normal usage). */
+#define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12)
+
+/* 1: uCode overrides sequence control field in MAC header.
+ * 0: Driver provides sequence control field in MAC header.
+ * Set this for management frames, non-QOS data frames, non-unicast frames,
+ * and also in Tx command embedded in REPLY_SCAN_CMD for active scans. */
+#define TX_CMD_FLG_SEQ_CTL_MSK __constant_cpu_to_le32(1 << 13)
+
+/* 1: This frame is non-last MPDU; more fragments are coming.
+ * 0: Last fragment, or not using fragmentation. */
+#define TX_CMD_FLG_MORE_FRAG_MSK __constant_cpu_to_le32(1 << 14)
+
+/* 1: uCode calculates and inserts Timestamp Function (TSF) in outgoing frame.
+ * 0: No TSF required in outgoing frame.
+ * Set this for transmitting beacons and probe responses. */
+#define TX_CMD_FLG_TSF_MSK __constant_cpu_to_le32(1 << 16)
+
+/* 1: Driver inserted 2 bytes pad after the MAC header, for (required) dword
+ *    alignment of frame's payload data field.
+ * 0: No pad
+ * Set this for MAC headers with 26 or 30 bytes, i.e. those with QOS or ADDR4
+ * field (but not both).  Driver must align frame data (i.e. data following
+ * MAC header) to DWORD boundary. */
+#define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20)
+
+/* accelerate aggregation support
+ * 0 - no CCMP encryption; 1 - CCMP encryption */
+#define TX_CMD_FLG_AGG_CCMP_MSK __constant_cpu_to_le32(1 << 22)
+
+/* HCCA-AP - disable duration overwriting. */
+#define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25)
+
+
+/*
+ * TX command security control
+ */
+#define TX_CMD_SEC_WEP         0x01
+#define TX_CMD_SEC_CCM         0x02
+#define TX_CMD_SEC_TKIP                0x03
+#define TX_CMD_SEC_MSK         0x03
+#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.
+ * Driver should set these fields to 0.
+ */
+struct iwl4965_dram_scratch {
+       u8 try_cnt;             /* Tx attempts */
+       u8 bt_kill_cnt;         /* Tx attempts blocked by Bluetooth device */
+       __le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX = 0x1c (command)
+ */
+struct iwl4965_tx_cmd {
+       /*
+        * MPDU byte count:
+        * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size,
+        * + 8 byte IV for CCM or TKIP (not used for WEP)
+        * + Data payload
+        * + 8-byte MIC (not used for CCM/WEP)
+        * NOTE:  Does not include Tx command bytes, post-MAC pad bytes,
+        *        MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.i
+        * Range: 14-2342 bytes.
+        */
+       __le16 len;
+
+       /*
+        * MPDU or MSDU byte count for next frame.
+        * Used for fragmentation and bursting, but not 11n aggregation.
+        * Same as "len", but for next frame.  Set to 0 if not applicable.
+        */
+       __le16 next_frame_len;
+
+       __le32 tx_flags;        /* TX_CMD_FLG_* */
+
+       /* 4965's uCode may modify this field of the Tx command (in host DRAM!).
+        * Driver must also set dram_lsb_ptr and dram_msb_ptr in this cmd. */
+       struct iwl4965_dram_scratch scratch;
+
+       /* Rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is cleared. */
+       __le32 rate_n_flags;    /* RATE_MCS_* */
+
+       /* Index of destination station in uCode's station table */
+       u8 sta_id;
+
+       /* Type of security encryption:  CCM or TKIP */
+       u8 sec_ctl;             /* TX_CMD_SEC_* */
+
+       /*
+        * Index into rate table (see REPLY_TX_LINK_QUALITY_CMD) for initial
+        * Tx attempt, if TX_CMD_FLG_STA_RATE_MSK is set.  Normally "0" for
+        * data frames, this field may be used to selectively reduce initial
+        * rate (via non-0 value) for special frames (e.g. management), while
+        * still supporting rate scaling for all frames.
+        */
+       u8 initial_rate_index;
+       u8 reserved;
+       u8 key[16];
+       __le16 next_frame_flags;
+       __le16 reserved2;
+       union {
+               __le32 life_time;
+               __le32 attempt;
+       } stop_time;
+
+       /* Host DRAM physical address pointer to "scratch" in this command.
+        * Must be dword aligned.  "0" in dram_lsb_ptr disables usage. */
+       __le32 dram_lsb_ptr;
+       u8 dram_msb_ptr;
+
+       u8 rts_retry_limit;     /*byte 50 */
+       u8 data_retry_limit;    /*byte 51 */
+       u8 tid_tspec;
+       union {
+               __le16 pm_frame_timeout;
+               __le16 attempt_duration;
+       } timeout;
+
+       /*
+        * Duration of EDCA burst Tx Opportunity, in 32-usec units.
+        * Set this if txop time is not specified by HCCA protocol (e.g. by AP).
+        */
+       __le16 driver_txop;
+
+       /*
+        * MAC header goes here, followed by 2 bytes padding if MAC header
+        * length is 26 or 30 bytes, followed by payload data
+        */
+       u8 payload[0];
+       struct ieee80211_hdr hdr[0];
+} __attribute__ ((packed));
+
+/* TX command response is sent after *all* transmission attempts.
+ *
+ * NOTES:
+ *
+ * TX_STATUS_FAIL_NEXT_FRAG
+ *
+ * If the fragment flag in the MAC header for the frame being transmitted
+ * is set and there is insufficient time to transmit the next frame, the
+ * TX status will be returned with 'TX_STATUS_FAIL_NEXT_FRAG'.
+ *
+ * TX_STATUS_FIFO_UNDERRUN
+ *
+ * Indicates the host did not provide bytes to the FIFO fast enough while
+ * a TX was in progress.
+ *
+ * TX_STATUS_FAIL_MGMNT_ABORT
+ *
+ * This status is only possible if the ABORT ON MGMT RX parameter was
+ * set to true with the TX command.
+ *
+ * If the MSB of the status parameter is set then an abort sequence is
+ * required.  This sequence consists of the host activating the TX Abort
+ * control line, and then waiting for the TX Abort command response.  This
+ * indicates that a the device is no longer in a transmit state, and that the
+ * command FIFO has been cleared.  The host must then deactivate the TX Abort
+ * control line.  Receiving is still allowed in this case.
+ */
+enum {
+       TX_STATUS_SUCCESS = 0x01,
+       TX_STATUS_DIRECT_DONE = 0x02,
+       TX_STATUS_FAIL_SHORT_LIMIT = 0x82,
+       TX_STATUS_FAIL_LONG_LIMIT = 0x83,
+       TX_STATUS_FAIL_FIFO_UNDERRUN = 0x84,
+       TX_STATUS_FAIL_MGMNT_ABORT = 0x85,
+       TX_STATUS_FAIL_NEXT_FRAG = 0x86,
+       TX_STATUS_FAIL_LIFE_EXPIRE = 0x87,
+       TX_STATUS_FAIL_DEST_PS = 0x88,
+       TX_STATUS_FAIL_ABORTED = 0x89,
+       TX_STATUS_FAIL_BT_RETRY = 0x8a,
+       TX_STATUS_FAIL_STA_INVALID = 0x8b,
+       TX_STATUS_FAIL_FRAG_DROPPED = 0x8c,
+       TX_STATUS_FAIL_TID_DISABLE = 0x8d,
+       TX_STATUS_FAIL_FRAME_FLUSHED = 0x8e,
+       TX_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f,
+       TX_STATUS_FAIL_TX_LOCKED = 0x90,
+       TX_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91,
+};
+
+#define        TX_PACKET_MODE_REGULAR          0x0000
+#define        TX_PACKET_MODE_BURST_SEQ        0x0100
+#define        TX_PACKET_MODE_BURST_FIRST      0x0200
+
+enum {
+       TX_POWER_PA_NOT_ACTIVE = 0x0,
+};
+
+enum {
+       TX_STATUS_MSK = 0x000000ff,     /* bits 0:7 */
+       TX_STATUS_DELAY_MSK = 0x00000040,
+       TX_STATUS_ABORT_MSK = 0x00000080,
+       TX_PACKET_MODE_MSK = 0x0000ff00,        /* bits 8:15 */
+       TX_FIFO_NUMBER_MSK = 0x00070000,        /* bits 16:18 */
+       TX_RESERVED = 0x00780000,       /* bits 19:22 */
+       TX_POWER_PA_DETECT_MSK = 0x7f800000,    /* bits 23:30 */
+       TX_ABORT_REQUIRED_MSK = 0x80000000,     /* bits 31:31 */
+};
+
+/* *******************************
+ * TX aggregation status
+ ******************************* */
+
+enum {
+       AGG_TX_STATE_TRANSMITTED = 0x00,
+       AGG_TX_STATE_UNDERRUN_MSK = 0x01,
+       AGG_TX_STATE_BT_PRIO_MSK = 0x02,
+       AGG_TX_STATE_FEW_BYTES_MSK = 0x04,
+       AGG_TX_STATE_ABORT_MSK = 0x08,
+       AGG_TX_STATE_LAST_SENT_TTL_MSK = 0x10,
+       AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK = 0x20,
+       AGG_TX_STATE_LAST_SENT_BT_KILL_MSK = 0x40,
+       AGG_TX_STATE_SCD_QUERY_MSK = 0x80,
+       AGG_TX_STATE_TEST_BAD_CRC32_MSK = 0x100,
+       AGG_TX_STATE_RESPONSE_MSK = 0x1ff,
+       AGG_TX_STATE_DUMP_TX_MSK = 0x200,
+       AGG_TX_STATE_DELAY_TX_MSK = 0x400
+};
+
+#define AGG_TX_STATE_LAST_SENT_MSK \
+(AGG_TX_STATE_LAST_SENT_TTL_MSK | \
+ AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \
+ AGG_TX_STATE_LAST_SENT_BT_KILL_MSK)
+
+/* # tx attempts for first frame in aggregation */
+#define AGG_TX_STATE_TRY_CNT_POS 12
+#define AGG_TX_STATE_TRY_CNT_MSK 0xf000
+
+/* Command ID and sequence number of Tx command for this frame */
+#define AGG_TX_STATE_SEQ_NUM_POS 16
+#define AGG_TX_STATE_SEQ_NUM_MSK 0xffff0000
+
+/*
+ * REPLY_TX = 0x1c (response)
+ *
+ * This response may be in one of two slightly different formats, indicated
+ * by the frame_count field:
+ *
+ * 1)  No aggregation (frame_count == 1).  This reports Tx results for
+ *     a single frame.  Multiple attempts, at various bit rates, may have
+ *     been made for this frame.
+ *
+ * 2)  Aggregation (frame_count > 1).  This reports Tx results for
+ *     2 or more frames that used block-acknowledge.  All frames were
+ *     transmitted at same rate.  Rate scaling may have been used if first
+ *     frame in this new agg block failed in previous agg block(s).
+ *
+ *     Note that, for aggregation, ACK (block-ack) status is not delivered here;
+ *     block-ack has not been received by the time the 4965 records this status.
+ *     This status relates to reasons the tx might have been blocked or aborted
+ *     within the sending station (this 4965), rather than whether it was
+ *     received successfully by the destination station.
+ */
+struct iwl4965_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;
+
+       /*
+        * 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!)
+        */
+       __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;
+       u8 failure_rts;
+       u8 failure_frame;
+       __le32 rate_n_flags;
+       __le16 wireless_media_time;
+       __le16 reserved3;
+       __le32 pa_power1;
+       __le32 pa_power2;
+       struct agg_tx_status status;    /* TX status (for aggregation status */
+                                       /* of 1st frame) */
+} __attribute__ ((packed));
+
+/*
+ * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command)
+ *
+ * Reports Block-Acknowledge from recipient station
+ */
+struct iwl4965_compressed_ba_resp {
+       __le32 sta_addr_lo32;
+       __le16 sta_addr_hi16;
+       __le16 reserved;
+
+       /* Index of recipient (BA-sending) station in uCode's station table */
+       u8 sta_id;
+       u8 tid;
+       __le16 seq_ctl;
+       __le64 bitmap;
+       __le16 scd_flow;
+       __le16 scd_ssn;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response)
+ *
+ * See details under "TXPOWER" in iwl-4965-hw.h.
+ */
+struct iwl4965_txpowertable_cmd {
+       u8 band;                /* 0: 5 GHz, 1: 2.4 GHz */
+       u8 reserved;
+       __le16 channel;
+       struct iwl4965_tx_power_db tx_power;
+} __attribute__ ((packed));
+
+/*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */
+#define  LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK   (1 << 0)
+
+/* # of EDCA prioritized tx fifos */
+#define  LINK_QUAL_AC_NUM AC_NUM
+
+/* # entries in rate scale table to support Tx retries */
+#define  LINK_QUAL_MAX_RETRY_NUM 16
+
+/* Tx antenna selection values */
+#define  LINK_QUAL_ANT_A_MSK (1 << 0)
+#define  LINK_QUAL_ANT_B_MSK (1 << 1)
+#define  LINK_QUAL_ANT_MSK   (LINK_QUAL_ANT_A_MSK|LINK_QUAL_ANT_B_MSK)
+
+
+/**
+ * struct iwl_link_qual_general_params
+ *
+ * Used in REPLY_TX_LINK_QUALITY_CMD
+ */
+struct iwl_link_qual_general_params {
+       u8 flags;
+
+       /* No entries at or above this (driver chosen) index contain MIMO */
+       u8 mimo_delimiter;
+
+       /* Best single antenna to use for single stream (legacy, SISO). */
+       u8 single_stream_ant_msk;       /* LINK_QUAL_ANT_* */
+
+       /* Best antennas to use for MIMO (unused for 4965, assumes both). */
+       u8 dual_stream_ant_msk;         /* LINK_QUAL_ANT_* */
+
+       /*
+        * If driver needs to use different initial rates for different
+        * EDCA QOS access categories (as implemented by tx fifos 0-3),
+        * this table will set that up, by indicating the indexes in the
+        * rs_table[LINK_QUAL_MAX_RETRY_NUM] rate table at which to start.
+        * Otherwise, driver should set all entries to 0.
+        *
+        * Entry usage:
+        * 0 = Background, 1 = Best Effort (normal), 2 = Video, 3 = Voice
+        * TX FIFOs above 3 use same value (typically 0) as TX FIFO 3.
+        */
+       u8 start_rate_index[LINK_QUAL_AC_NUM];
+} __attribute__ ((packed));
+
+/**
+ * struct iwl_link_qual_agg_params
+ *
+ * Used in REPLY_TX_LINK_QUALITY_CMD
+ */
+struct iwl_link_qual_agg_params {
+
+       /* Maximum number of uSec in aggregation.
+        * Driver should set this to 4000 (4 milliseconds). */
+       __le16 agg_time_limit;
+
+       /*
+        * Number of Tx retries allowed for a frame, before that frame will
+        * no longer be considered for the start of an aggregation sequence
+        * (scheduler will then try to tx it as single frame).
+        * Driver should set this to 3.
+        */
+       u8 agg_dis_start_th;
+
+       /*
+        * Maximum number of frames in aggregation.
+        * 0 = no limit (default).  1 = no aggregation.
+        * Other values = max # frames in aggregation.
+        */
+       u8 agg_frame_cnt_limit;
+
+       __le32 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response)
+ *
+ * For 4965 only; 3945 uses REPLY_RATE_SCALE.
+ *
+ * Each station in the 4965's internal station table has its own table of 16
+ * Tx rates and modulation modes (e.g. legacy/SISO/MIMO) for retrying Tx when
+ * an ACK is not received.  This command replaces the entire table for
+ * one station.
+ *
+ * NOTE:  Station must already be in 4965's station table.  Use REPLY_ADD_STA.
+ *
+ * The rate scaling procedures described below work well.  Of course, other
+ * procedures are possible, and may work better for particular environments.
+ *
+ *
+ * FILLING THE RATE TABLE
+ *
+ * Given a particular initial rate and mode, as determined by the rate
+ * scaling algorithm described below, the Linux driver uses the following
+ * formula to fill the rs_table[LINK_QUAL_MAX_RETRY_NUM] rate table in the
+ * Link Quality command:
+ *
+ *
+ * 1)  If using High-throughput (HT) (SISO or MIMO) initial rate:
+ *     a) Use this same initial rate for first 3 entries.
+ *     b) Find next lower available rate using same mode (SISO or MIMO),
+ *        use for next 3 entries.  If no lower rate available, switch to
+ *        legacy mode (no FAT channel, no MIMO, no short guard interval).
+ *     c) If using MIMO, set command's mimo_delimiter to number of entries
+ *        using MIMO (3 or 6).
+ *     d) After trying 2 HT rates, switch to legacy mode (no FAT channel,
+ *        no MIMO, no short guard interval), at the next lower bit rate
+ *        (e.g. if second HT bit rate was 54, try 48 legacy), and follow
+ *        legacy procedure for remaining table entries.
+ *
+ * 2)  If using legacy initial rate:
+ *     a) Use the initial rate for only one entry.
+ *     b) For each following entry, reduce the rate to next lower available
+ *        rate, until reaching the lowest available rate.
+ *     c) When reducing rate, also switch antenna selection.
+ *     d) Once lowest available rate is reached, repeat this rate until
+ *        rate table is filled (16 entries), switching antenna each entry.
+ *
+ *
+ * ACCUMULATING HISTORY
+ *
+ * The rate scaling algorithm for 4965, as implemented in Linux driver, uses
+ * two sets of frame Tx success history:  One for the current/active modulation
+ * mode, and one for a speculative/search mode that is being attempted.  If the
+ * speculative mode turns out to be more effective (i.e. actual transfer
+ * rate is better), then the driver continues to use the speculative mode
+ * as the new current active mode.
+ *
+ * Each history set contains, separately for each possible rate, data for a
+ * sliding window of the 62 most recent tx attempts at that rate.  The data
+ * includes a shifting bitmap of success(1)/failure(0), and sums of successful
+ * and attempted frames, from which the driver can additionally calculate a
+ * success ratio (success / attempted) and number of failures
+ * (attempted - success), and control the size of the window (attempted).
+ * The driver uses the bit map to remove successes from the success sum, as
+ * the oldest tx attempts fall out of the window.
+ *
+ * When the 4965 makes multiple tx attempts for a given frame, each attempt
+ * might be at a different rate, and have different modulation characteristics
+ * (e.g. antenna, fat channel, short guard interval), as set up in the rate
+ * scaling table in the Link Quality command.  The driver must determine
+ * which rate table entry was used for each tx attempt, to determine which
+ * rate-specific history to update, and record only those attempts that
+ * match the modulation characteristics of the history set.
+ *
+ * When using block-ack (aggregation), all frames are transmitted at the same
+ * rate, since there is no per-attempt acknowledgement from the destination
+ * station.  The Tx response struct iwl_tx_resp indicates the Tx rate in
+ * rate_n_flags field.  After receiving a block-ack, the driver can update
+ * history for the entire block all at once.
+ *
+ *
+ * FINDING BEST STARTING RATE:
+ *
+ * When working with a selected initial modulation mode (see below), the
+ * driver attempts to find a best initial rate.  The initial rate is the
+ * first entry in the Link Quality command's rate table.
+ *
+ * 1)  Calculate actual throughput (success ratio * expected throughput, see
+ *     table below) for current initial rate.  Do this only if enough frames
+ *     have been attempted to make the value meaningful:  at least 6 failed
+ *     tx attempts, or at least 8 successes.  If not enough, don't try rate
+ *     scaling yet.
+ *
+ * 2)  Find available rates adjacent to current initial rate.  Available means:
+ *     a)  supported by hardware &&
+ *     b)  supported by association &&
+ *     c)  within any constraints selected by user
+ *
+ * 3)  Gather measured throughputs for adjacent rates.  These might not have
+ *     enough history to calculate a throughput.  That's okay, we might try
+ *     using one of them anyway!
+ *
+ * 4)  Try decreasing rate if, for current rate:
+ *     a)  success ratio is < 15% ||
+ *     b)  lower adjacent rate has better measured throughput ||
+ *     c)  higher adjacent rate has worse throughput, and lower is unmeasured
+ *
+ *     As a sanity check, if decrease was determined above, leave rate
+ *     unchanged if:
+ *     a)  lower rate unavailable
+ *     b)  success ratio at current rate > 85% (very good)
+ *     c)  current measured throughput is better than expected throughput
+ *         of lower rate (under perfect 100% tx conditions, see table below)
+ *
+ * 5)  Try increasing rate if, for current rate:
+ *     a)  success ratio is < 15% ||
+ *     b)  both adjacent rates' throughputs are unmeasured (try it!) ||
+ *     b)  higher adjacent rate has better measured throughput ||
+ *     c)  lower adjacent rate has worse throughput, and higher is unmeasured
+ *
+ *     As a sanity check, if increase was determined above, leave rate
+ *     unchanged if:
+ *     a)  success ratio at current rate < 70%.  This is not particularly
+ *         good performance; higher rate is sure to have poorer success.
+ *
+ * 6)  Re-evaluate the rate after each tx frame.  If working with block-
+ *     acknowledge, history and statistics may be calculated for the entire
+ *     block (including prior history that fits within the history windows),
+ *     before re-evaluation.
+ *
+ * FINDING BEST STARTING MODULATION MODE:
+ *
+ * After working with a modulation mode for a "while" (and doing rate scaling),
+ * the driver searches for a new initial mode in an attempt to improve
+ * throughput.  The "while" is measured by numbers of attempted frames:
+ *
+ * For legacy mode, search for new mode after:
+ *   480 successful frames, or 160 failed frames
+ * For high-throughput modes (SISO or MIMO), search for new mode after:
+ *   4500 successful frames, or 400 failed frames
+ *
+ * Mode switch possibilities are (3 for each mode):
+ *
+ * For legacy:
+ *   Change antenna, try SISO (if HT association), try MIMO (if HT association)
+ * For SISO:
+ *   Change antenna, try MIMO, try shortened guard interval (SGI)
+ * For MIMO:
+ *   Try SISO antenna A, SISO antenna B, try shortened guard interval (SGI)
+ *
+ * When trying a new mode, use the same bit rate as the old/current mode when
+ * trying antenna switches and shortened guard interval.  When switching to
+ * SISO from MIMO or legacy, or to MIMO from SISO or legacy, use a rate
+ * for which the expected throughput (under perfect conditions) is about the
+ * same or slightly better than the actual measured throughput delivered by
+ * the old/current mode.
+ *
+ * Actual throughput can be estimated by multiplying the expected throughput
+ * by the success ratio (successful / attempted tx frames).  Frame size is
+ * not considered in this calculation; it assumes that frame size will average
+ * out to be fairly consistent over several samples.  The following are
+ * metric values for expected throughput assuming 100% success ratio.
+ * Only G band has support for CCK rates:
+ *
+ *           RATE:  1    2    5   11    6   9   12   18   24   36   48   54   60
+ *
+ *              G:  7   13   35   58   40  57   72   98  121  154  177  186  186
+ *              A:  0    0    0    0   40  57   72   98  121  154  177  186  186
+ *     SISO 20MHz:  0    0    0    0   42  42   76  102  124  159  183  193  202
+ * SGI SISO 20MHz:  0    0    0    0   46  46   82  110  132  168  192  202  211
+ *     MIMO 20MHz:  0    0    0    0   74  74  123  155  179  214  236  244  251
+ * SGI MIMO 20MHz:  0    0    0    0   81  81  131  164  188  222  243  251  257
+ *     SISO 40MHz:  0    0    0    0   77  77  127  160  184  220  242  250  257
+ * SGI SISO 40MHz:  0    0    0    0   83  83  135  169  193  229  250  257  264
+ *     MIMO 40MHz:  0    0    0    0  123 123  182  214  235  264  279  285  289
+ * SGI MIMO 40MHz:  0    0    0    0  131 131  191  222  242  270  284  289  293
+ *
+ * After the new mode has been tried for a short while (minimum of 6 failed
+ * frames or 8 successful frames), compare success ratio and actual throughput
+ * estimate of the new mode with the old.  If either is better with the new
+ * mode, continue to use the new mode.
+ *
+ * Continue comparing modes until all 3 possibilities have been tried.
+ * If moving from legacy to HT, try all 3 possibilities from the new HT
+ * mode.  After trying all 3, a best mode is found.  Continue to use this mode
+ * for the longer "while" described above (e.g. 480 successful frames for
+ * legacy), and then repeat the search process.
+ *
+ */
+struct iwl_link_quality_cmd {
+
+       /* Index of destination/recipient station in uCode's station table */
+       u8 sta_id;
+       u8 reserved1;
+       __le16 control;         /* not used */
+       struct iwl_link_qual_general_params general_params;
+       struct iwl_link_qual_agg_params agg_params;
+
+       /*
+        * Rate info; when using rate-scaling, Tx command's initial_rate_index
+        * specifies 1st Tx rate attempted, via index into this table.
+        * 4965 works its way through table when retrying Tx.
+        */
+       struct {
+               __le32 rate_n_flags;    /* RATE_MCS_*, IWL_RATE_* */
+       } rs_table[LINK_QUAL_MAX_RETRY_NUM];
+       __le32 reserved2;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_BT_CONFIG = 0x9b (command, has simple generic response)
+ *
+ * 3945 and 4965 support hardware handshake with Bluetooth device on
+ * same platform.  Bluetooth device alerts wireless device when it will Tx;
+ * wireless device can delay or kill its own Tx to accomodate.
+ */
+struct iwl4965_bt_cmd {
+       u8 flags;
+       u8 lead_time;
+       u8 max_kill;
+       u8 reserved;
+       __le32 kill_ack_mask;
+       __le32 kill_cts_mask;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (6)
+ * Spectrum Management (802.11h) Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+/*
+ * Spectrum Management
+ */
+#define MEASUREMENT_FILTER_FLAG (RXON_FILTER_PROMISC_MSK         | \
+                                RXON_FILTER_CTL2HOST_MSK        | \
+                                RXON_FILTER_ACCEPT_GRP_MSK      | \
+                                RXON_FILTER_DIS_DECRYPT_MSK     | \
+                                RXON_FILTER_DIS_GRP_DECRYPT_MSK | \
+                                RXON_FILTER_ASSOC_MSK           | \
+                                RXON_FILTER_BCON_AWARE_MSK)
+
+struct iwl4965_measure_channel {
+       __le32 duration;        /* measurement duration in extended beacon
+                                * format */
+       u8 channel;             /* channel to measure */
+       u8 type;                /* see enum iwl4965_measure_type */
+       __le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command)
+ */
+struct iwl4965_spectrum_cmd {
+       __le16 len;             /* number of bytes starting from token */
+       u8 token;               /* token id */
+       u8 id;                  /* measurement id -- 0 or 1 */
+       u8 origin;              /* 0 = TGh, 1 = other, 2 = TGk */
+       u8 periodic;            /* 1 = periodic */
+       __le16 path_loss_timeout;
+       __le32 start_time;      /* start time in extended beacon format */
+       __le32 reserved2;
+       __le32 flags;           /* rxon flags */
+       __le32 filter_flags;    /* rxon filter flags */
+       __le16 channel_count;   /* minimum 1, maximum 10 */
+       __le16 reserved3;
+       struct iwl4965_measure_channel channels[10];
+} __attribute__ ((packed));
+
+/*
+ * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response)
+ */
+struct iwl4965_spectrum_resp {
+       u8 token;
+       u8 id;                  /* id of the prior command replaced, or 0xff */
+       __le16 status;          /* 0 - command will be handled
+                                * 1 - cannot handle (conflicts with another
+                                *     measurement) */
+} __attribute__ ((packed));
+
+enum iwl4965_measurement_state {
+       IWL_MEASUREMENT_START = 0,
+       IWL_MEASUREMENT_STOP = 1,
+};
+
+enum iwl4965_measurement_status {
+       IWL_MEASUREMENT_OK = 0,
+       IWL_MEASUREMENT_CONCURRENT = 1,
+       IWL_MEASUREMENT_CSA_CONFLICT = 2,
+       IWL_MEASUREMENT_TGH_CONFLICT = 3,
+       /* 4-5 reserved */
+       IWL_MEASUREMENT_STOPPED = 6,
+       IWL_MEASUREMENT_TIMEOUT = 7,
+       IWL_MEASUREMENT_PERIODIC_FAILED = 8,
+};
+
+#define NUM_ELEMENTS_IN_HISTOGRAM 8
+
+struct iwl4965_measurement_histogram {
+       __le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 0.8usec counts */
+       __le32 cck[NUM_ELEMENTS_IN_HISTOGRAM];  /* in 1usec counts */
+} __attribute__ ((packed));
+
+/* clear channel availability counters */
+struct iwl4965_measurement_cca_counters {
+       __le32 ofdm;
+       __le32 cck;
+} __attribute__ ((packed));
+
+enum iwl4965_measure_type {
+       IWL_MEASURE_BASIC = (1 << 0),
+       IWL_MEASURE_CHANNEL_LOAD = (1 << 1),
+       IWL_MEASURE_HISTOGRAM_RPI = (1 << 2),
+       IWL_MEASURE_HISTOGRAM_NOISE = (1 << 3),
+       IWL_MEASURE_FRAME = (1 << 4),
+       /* bits 5:6 are reserved */
+       IWL_MEASURE_IDLE = (1 << 7),
+};
+
+/*
+ * SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command)
+ */
+struct iwl4965_spectrum_notification {
+       u8 id;                  /* measurement id -- 0 or 1 */
+       u8 token;
+       u8 channel_index;       /* index in measurement channel list */
+       u8 state;               /* 0 - start, 1 - stop */
+       __le32 start_time;      /* lower 32-bits of TSF */
+       u8 band;                /* 0 - 5.2GHz, 1 - 2.4GHz */
+       u8 channel;
+       u8 type;                /* see enum iwl4965_measurement_type */
+       u8 reserved1;
+       /* NOTE:  cca_ofdm, cca_cck, basic_type, and histogram are only only
+        * valid if applicable for measurement type requested. */
+       __le32 cca_ofdm;        /* cca fraction time in 40Mhz clock periods */
+       __le32 cca_cck;         /* cca fraction time in 44Mhz clock periods */
+       __le32 cca_time;        /* channel load time in usecs */
+       u8 basic_type;          /* 0 - bss, 1 - ofdm preamble, 2 -
+                                * unidentified */
+       u8 reserved2[3];
+       struct iwl4965_measurement_histogram histogram;
+       __le32 stop_time;       /* lower 32-bits of TSF */
+       __le32 status;          /* see iwl4965_measurement_status */
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (7)
+ * Power Management Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+/**
+ * struct iwl4965_powertable_cmd - Power Table Command
+ * @flags: See below:
+ *
+ * POWER_TABLE_CMD = 0x77 (command, has simple generic response)
+ *
+ * PM allow:
+ *   bit 0 - '0' Driver not allow power management
+ *           '1' Driver allow PM (use rest of parameters)
+ * uCode send sleep notifications:
+ *   bit 1 - '0' Don't send sleep notification
+ *           '1' send sleep notification (SEND_PM_NOTIFICATION)
+ * Sleep over DTIM
+ *   bit 2 - '0' PM have to walk up every DTIM
+ *           '1' PM could sleep over DTIM till listen Interval.
+ * PCI power managed
+ *   bit 3 - '0' (PCI_LINK_CTRL & 0x1)
+ *           '1' !(PCI_LINK_CTRL & 0x1)
+ * Force sleep Modes
+ *   bit 31/30- '00' use both mac/xtal sleeps
+ *              '01' force Mac sleep
+ *              '10' force xtal sleep
+ *              '11' Illegal set
+ *
+ * NOTE: if sleep_interval[SLEEP_INTRVL_TABLE_SIZE-1] > DTIM period then
+ * ucode assume sleep over DTIM is allowed and we don't need to wakeup
+ * for every DTIM.
+ */
+#define IWL_POWER_VEC_SIZE 5
+
+#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;
+       u8 keep_alive_seconds;
+       u8 debug_flags;
+       __le32 rx_data_timeout;
+       __le32 tx_data_timeout;
+       __le32 sleep_interval[IWL_POWER_VEC_SIZE];
+       __le32 keep_alive_beacons;
+} __attribute__ ((packed));
+
+/*
+ * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command)
+ * 3945 and 4965 identical.
+ */
+struct iwl4965_sleep_notification {
+       u8 pm_sleep_mode;
+       u8 pm_wakeup_src;
+       __le16 reserved;
+       __le32 sleep_time;
+       __le32 tsf_low;
+       __le32 bcon_timer;
+} __attribute__ ((packed));
+
+/* Sleep states.  3945 and 4965 identical. */
+enum {
+       IWL_PM_NO_SLEEP = 0,
+       IWL_PM_SLP_MAC = 1,
+       IWL_PM_SLP_FULL_MAC_UNASSOCIATE = 2,
+       IWL_PM_SLP_FULL_MAC_CARD_STATE = 3,
+       IWL_PM_SLP_PHY = 4,
+       IWL_PM_SLP_REPENT = 5,
+       IWL_PM_WAKEUP_BY_TIMER = 6,
+       IWL_PM_WAKEUP_BY_DRIVER = 7,
+       IWL_PM_WAKEUP_BY_RFKILL = 8,
+       /* 3 reserved */
+       IWL_PM_NUM_OF_MODES = 12,
+};
+
+/*
+ * REPLY_CARD_STATE_CMD = 0xa0 (command, has simple generic response)
+ */
+#define CARD_STATE_CMD_DISABLE 0x00    /* Put card to sleep */
+#define CARD_STATE_CMD_ENABLE  0x01    /* Wake up card */
+#define CARD_STATE_CMD_HALT    0x02    /* Power down permanently */
+struct iwl4965_card_state_cmd {
+       __le32 status;          /* CARD_STATE_CMD_* request new power state */
+} __attribute__ ((packed));
+
+/*
+ * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command)
+ */
+struct iwl4965_card_state_notif {
+       __le32 flags;
+} __attribute__ ((packed));
+
+#define HW_CARD_DISABLED   0x01
+#define SW_CARD_DISABLED   0x02
+#define RF_CARD_DISABLED   0x04
+#define RXON_CARD_DISABLED 0x10
+
+struct iwl4965_ct_kill_config {
+       __le32   reserved;
+       __le32   critical_temperature_M;
+       __le32   critical_temperature_R;
+}  __attribute__ ((packed));
+
+/******************************************************************************
+ * (8)
+ * Scan Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+/**
+ * struct iwl4965_scan_channel - entry in REPLY_SCAN_CMD channel table
+ *
+ * One for each channel in the scan list.
+ * Each channel can independently select:
+ * 1)  SSID for directed active scans
+ * 2)  Txpower setting (for rate specified within Tx command)
+ * 3)  How long to stay on-channel (behavior may be modified by quiet_time,
+ *     quiet_plcp_th, good_CRC_th)
+ *
+ * To avoid uCode errors, make sure the following are true (see comments
+ * under struct iwl4965_scan_cmd about max_out_time and quiet_time):
+ * 1)  If using passive_dwell (i.e. passive_dwell != 0):
+ *     active_dwell <= passive_dwell (< max_out_time if max_out_time != 0)
+ * 2)  quiet_time <= active_dwell
+ * 3)  If restricting off-channel time (i.e. max_out_time !=0):
+ *     passive_dwell < max_out_time
+ *     active_dwell < max_out_time
+ */
+struct iwl4965_scan_channel {
+       /*
+        * type is defined as:
+        * 0:0 1 = active, 0 = passive
+        * 1:4 SSID direct bit map; if a bit is set, then corresponding
+        *     SSID IE is transmitted in probe request.
+        * 5:7 reserved
+        */
+       u8 type;
+       u8 channel;     /* band is selected by iwl4965_scan_cmd "flags" field */
+       struct iwl4965_tx_power tpc;
+       __le16 active_dwell;    /* in 1024-uSec TU (time units), typ 5-50 */
+       __le16 passive_dwell;   /* in 1024-uSec TU (time units), typ 20-500 */
+} __attribute__ ((packed));
+
+/**
+ * struct iwl4965_ssid_ie - directed scan network information element
+ *
+ * Up to 4 of these may appear in REPLY_SCAN_CMD, selected by "type" field
+ * in struct iwl4965_scan_channel; each channel may select different ssids from
+ * among the 4 entries.  SSID IEs get transmitted in reverse order of entry.
+ */
+struct iwl4965_ssid_ie {
+       u8 id;
+       u8 len;
+       u8 ssid[32];
+} __attribute__ ((packed));
+
+#define PROBE_OPTION_MAX        0x4
+#define TX_CMD_LIFE_TIME_INFINITE      __constant_cpu_to_le32(0xFFFFFFFF)
+#define IWL_GOOD_CRC_TH                __constant_cpu_to_le16(1)
+#define IWL_MAX_SCAN_SIZE 1024
+
+/*
+ * REPLY_SCAN_CMD = 0x80 (command)
+ *
+ * The hardware scan command is very powerful; the driver can set it up to
+ * maintain (relatively) normal network traffic while doing a scan in the
+ * background.  The max_out_time and suspend_time control the ratio of how
+ * long the device stays on an associated network channel ("service channel")
+ * vs. how long it's away from the service channel, i.e. tuned to other channels
+ * for scanning.
+ *
+ * max_out_time is the max time off-channel (in usec), and suspend_time
+ * is how long (in "extended beacon" format) that the scan is "suspended"
+ * after returning to the service channel.  That is, suspend_time is the
+ * time that we stay on the service channel, doing normal work, between
+ * scan segments.  The driver may set these parameters differently to support
+ * scanning when associated vs. not associated, and light vs. heavy traffic
+ * loads when associated.
+ *
+ * After receiving this command, the device's scan engine does the following;
+ *
+ * 1)  Sends SCAN_START notification to driver
+ * 2)  Checks to see if it has time to do scan for one channel
+ * 3)  Sends NULL packet, with power-save (PS) bit set to 1,
+ *     to tell AP that we're going off-channel
+ * 4)  Tunes to first channel in scan list, does active or passive scan
+ * 5)  Sends SCAN_RESULT notification to driver
+ * 6)  Checks to see if it has time to do scan on *next* channel in list
+ * 7)  Repeats 4-6 until it no longer has time to scan the next channel
+ *     before max_out_time expires
+ * 8)  Returns to service channel
+ * 9)  Sends NULL packet with PS=0 to tell AP that we're back
+ * 10) Stays on service channel until suspend_time expires
+ * 11) Repeats entire process 2-10 until list is complete
+ * 12) Sends SCAN_COMPLETE notification
+ *
+ * For fast, efficient scans, the scan command also has support for staying on
+ * a channel for just a short time, if doing active scanning and getting no
+ * responses to the transmitted probe request.  This time is controlled by
+ * quiet_time, and the number of received packets below which a channel is
+ * considered "quiet" is controlled by quiet_plcp_threshold.
+ *
+ * For active scanning on channels that have regulatory restrictions against
+ * blindly transmitting, the scan can listen before transmitting, to make sure
+ * that there is already legitimate activity on the channel.  If enough
+ * packets are cleanly received on the channel (controlled by good_CRC_th,
+ * typical value 1), the scan engine starts transmitting probe requests.
+ *
+ * Driver must use separate scan commands for 2.4 vs. 5 GHz bands.
+ *
+ * To avoid uCode errors, see timing restrictions described under
+ * struct iwl4965_scan_channel.
+ */
+struct iwl4965_scan_cmd {
+       __le16 len;
+       u8 reserved0;
+       u8 channel_count;       /* # channels in channel list */
+       __le16 quiet_time;      /* dwell only this # millisecs on quiet channel
+                                * (only for active scan) */
+       __le16 quiet_plcp_th;   /* quiet chnl is < this # pkts (typ. 1) */
+       __le16 good_CRC_th;     /* passive -> active promotion threshold */
+       __le16 rx_chain;        /* RXON_RX_CHAIN_* */
+       __le32 max_out_time;    /* max usec to be away from associated (service)
+                                * channel */
+       __le32 suspend_time;    /* pause scan this long (in "extended beacon
+                                * format") when returning to service chnl:
+                                * 3945; 31:24 # beacons, 19:0 additional usec,
+                                * 4965; 31:22 # beacons, 21:0 additional usec.
+                                */
+       __le32 flags;           /* RXON_FLG_* */
+       __le32 filter_flags;    /* RXON_FILTER_* */
+
+       /* 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;
+
+       /* For directed active scans (set to all-0s otherwise) */
+       struct iwl4965_ssid_ie direct_scan[PROBE_OPTION_MAX];
+
+       /*
+        * Probe request frame, followed by channel list.
+        *
+        * Size of probe request frame is specified by byte count in tx_cmd.
+        * Channel list follows immediately after probe request frame.
+        * Number of channels in list is specified by channel_count.
+        * Each channel in list is of type:
+        *
+        * struct iwl4965_scan_channel channels[0];
+        *
+        * NOTE:  Only one band of channels can be scanned per pass.  You
+        * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait
+        * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION)
+        * before requesting another scan.
+        */
+       u8 data[0];
+} __attribute__ ((packed));
+
+/* Can abort will notify by complete notification with abort status. */
+#define CAN_ABORT_STATUS       __constant_cpu_to_le32(0x1)
+/* complete notification statuses */
+#define ABORT_STATUS            0x2
+
+/*
+ * REPLY_SCAN_CMD = 0x80 (response)
+ */
+struct iwl4965_scanreq_notification {
+       __le32 status;          /* 1: okay, 2: cannot fulfill request */
+} __attribute__ ((packed));
+
+/*
+ * SCAN_START_NOTIFICATION = 0x82 (notification only, not a command)
+ */
+struct iwl4965_scanstart_notification {
+       __le32 tsf_low;
+       __le32 tsf_high;
+       __le32 beacon_timer;
+       u8 channel;
+       u8 band;
+       u8 reserved[2];
+       __le32 status;
+} __attribute__ ((packed));
+
+#define  SCAN_OWNER_STATUS 0x1;
+#define  MEASURE_OWNER_STATUS 0x2;
+
+#define NUMBER_OF_STATISTICS 1 /* first __le32 is good CRC */
+/*
+ * SCAN_RESULTS_NOTIFICATION = 0x83 (notification only, not a command)
+ */
+struct iwl4965_scanresults_notification {
+       u8 channel;
+       u8 band;
+       u8 reserved[2];
+       __le32 tsf_low;
+       __le32 tsf_high;
+       __le32 statistics[NUMBER_OF_STATISTICS];
+} __attribute__ ((packed));
+
+/*
+ * SCAN_COMPLETE_NOTIFICATION = 0x84 (notification only, not a command)
+ */
+struct iwl4965_scancomplete_notification {
+       u8 scanned_channels;
+       u8 status;
+       u8 reserved;
+       u8 last_channel;
+       __le32 tsf_low;
+       __le32 tsf_high;
+} __attribute__ ((packed));
+
+
+/******************************************************************************
+ * (9)
+ * IBSS/AP Commands and Notifications:
+ *
+ *****************************************************************************/
+
+/*
+ * BEACON_NOTIFICATION = 0x90 (notification only, not a command)
+ */
+struct iwl4965_beacon_notif {
+       struct iwl4965_tx_resp beacon_notify_hdr;
+       __le32 low_tsf;
+       __le32 high_tsf;
+       __le32 ibss_mgr_status;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX_BEACON = 0x91 (command, has simple generic response)
+ */
+struct iwl4965_tx_beacon_cmd {
+       struct iwl4965_tx_cmd tx;
+       __le16 tim_idx;
+       u8 tim_size;
+       u8 reserved1;
+       struct ieee80211_hdr frame[0];  /* beacon frame */
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (10)
+ * Statistics Commands and Notifications:
+ *
+ *****************************************************************************/
+
+#define IWL_TEMP_CONVERT 260
+
+#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
+#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
+#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
+
+/* Used for passing to driver number of successes and failures per rate */
+struct rate_histogram {
+       union {
+               __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+               __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+               __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+       } success;
+       union {
+               __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+               __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+               __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+       } failed;
+} __attribute__ ((packed));
+
+/* statistics command response */
+
+struct statistics_rx_phy {
+       __le32 ina_cnt;
+       __le32 fina_cnt;
+       __le32 plcp_err;
+       __le32 crc32_err;
+       __le32 overrun_err;
+       __le32 early_overrun_err;
+       __le32 crc32_good;
+       __le32 false_alarm_cnt;
+       __le32 fina_sync_err_cnt;
+       __le32 sfd_timeout;
+       __le32 fina_timeout;
+       __le32 unresponded_rts;
+       __le32 rxe_frame_limit_overrun;
+       __le32 sent_ack_cnt;
+       __le32 sent_cts_cnt;
+       __le32 sent_ba_rsp_cnt;
+       __le32 dsp_self_kill;
+       __le32 mh_format_err;
+       __le32 re_acq_main_rssi_sum;
+       __le32 reserved3;
+} __attribute__ ((packed));
+
+struct statistics_rx_ht_phy {
+       __le32 plcp_err;
+       __le32 overrun_err;
+       __le32 early_overrun_err;
+       __le32 crc32_good;
+       __le32 crc32_err;
+       __le32 mh_format_err;
+       __le32 agg_crc32_good;
+       __le32 agg_mpdu_cnt;
+       __le32 agg_cnt;
+       __le32 reserved2;
+} __attribute__ ((packed));
+
+struct statistics_rx_non_phy {
+       __le32 bogus_cts;       /* CTS received when not expecting CTS */
+       __le32 bogus_ack;       /* ACK received when not expecting ACK */
+       __le32 non_bssid_frames;        /* number of frames with BSSID that
+                                        * doesn't belong to the STA BSSID */
+       __le32 filtered_frames; /* count frames that were dumped in the
+                                * filtering process */
+       __le32 non_channel_beacons;     /* beacons with our bss id but not on
+                                        * our serving channel */
+       __le32 channel_beacons; /* beacons with our bss id and in our
+                                * serving channel */
+       __le32 num_missed_bcon; /* number of missed beacons */
+       __le32 adc_rx_saturation_time;  /* count in 0.8us units the time the
+                                        * ADC was in saturation */
+       __le32 ina_detection_search_time;/* total time (in 0.8us) searched
+                                         * for INA */
+       __le32 beacon_silence_rssi_a;   /* RSSI silence after beacon frame */
+       __le32 beacon_silence_rssi_b;   /* RSSI silence after beacon frame */
+       __le32 beacon_silence_rssi_c;   /* RSSI silence after beacon frame */
+       __le32 interference_data_flag;  /* flag for interference data
+                                        * availability. 1 when data is
+                                        * available. */
+       __le32 channel_load;            /* counts RX Enable time in uSec */
+       __le32 dsp_false_alarms;        /* DSP false alarm (both OFDM
+                                        * and CCK) counter */
+       __le32 beacon_rssi_a;
+       __le32 beacon_rssi_b;
+       __le32 beacon_rssi_c;
+       __le32 beacon_energy_a;
+       __le32 beacon_energy_b;
+       __le32 beacon_energy_c;
+} __attribute__ ((packed));
+
+struct statistics_rx {
+       struct statistics_rx_phy ofdm;
+       struct statistics_rx_phy cck;
+       struct statistics_rx_non_phy general;
+       struct statistics_rx_ht_phy ofdm_ht;
+} __attribute__ ((packed));
+
+struct statistics_tx_non_phy_agg {
+       __le32 ba_timeout;
+       __le32 ba_reschedule_frames;
+       __le32 scd_query_agg_frame_cnt;
+       __le32 scd_query_no_agg;
+       __le32 scd_query_agg;
+       __le32 scd_query_mismatch;
+       __le32 frame_not_ready;
+       __le32 underrun;
+       __le32 bt_prio_kill;
+       __le32 rx_ba_rsp_cnt;
+       __le32 reserved2;
+       __le32 reserved3;
+} __attribute__ ((packed));
+
+struct statistics_tx {
+       __le32 preamble_cnt;
+       __le32 rx_detected_cnt;
+       __le32 bt_prio_defer_cnt;
+       __le32 bt_prio_kill_cnt;
+       __le32 few_bytes_cnt;
+       __le32 cts_timeout;
+       __le32 ack_timeout;
+       __le32 expected_ack_cnt;
+       __le32 actual_ack_cnt;
+       __le32 dump_msdu_cnt;
+       __le32 burst_abort_next_frame_mismatch_cnt;
+       __le32 burst_abort_missing_next_frame_cnt;
+       __le32 cts_timeout_collision;
+       __le32 ack_or_ba_timeout_collision;
+       struct statistics_tx_non_phy_agg agg;
+} __attribute__ ((packed));
+
+struct statistics_dbg {
+       __le32 burst_check;
+       __le32 burst_count;
+       __le32 reserved[4];
+} __attribute__ ((packed));
+
+struct statistics_div {
+       __le32 tx_on_a;
+       __le32 tx_on_b;
+       __le32 exec_time;
+       __le32 probe_time;
+       __le32 reserved1;
+       __le32 reserved2;
+} __attribute__ ((packed));
+
+struct statistics_general {
+       __le32 temperature;
+       __le32 temperature_m;
+       struct statistics_dbg dbg;
+       __le32 sleep_time;
+       __le32 slots_out;
+       __le32 slots_idle;
+       __le32 ttl_timestamp;
+       struct statistics_div div;
+       __le32 rx_enable_counter;
+       __le32 reserved1;
+       __le32 reserved2;
+       __le32 reserved3;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_STATISTICS_CMD = 0x9c,
+ * 3945 and 4965 identical.
+ *
+ * This command triggers an immediate response containing uCode statistics.
+ * The response is in the same format as STATISTICS_NOTIFICATION 0x9d, below.
+ *
+ * If the CLEAR_STATS configuration flag is set, uCode will clear its
+ * internal copy of the statistics (counters) after issuing the response.
+ * This flag does not affect STATISTICS_NOTIFICATIONs after beacons (see below).
+ *
+ * If the DISABLE_NOTIF configuration flag is set, uCode will not issue
+ * STATISTICS_NOTIFICATIONs after received beacons (see below).  This flag
+ * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself.
+ */
+#define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1) /* see above */
+#define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */
+struct iwl4965_statistics_cmd {
+       __le32 configuration_flags;     /* IWL_STATS_CONF_* */
+} __attribute__ ((packed));
+
+/*
+ * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command)
+ *
+ * By default, uCode issues this notification after receiving a beacon
+ * while associated.  To disable this behavior, set DISABLE_NOTIF flag in the
+ * REPLY_STATISTICS_CMD 0x9c, above.
+ *
+ * Statistics counters continue to increment beacon after beacon, but are
+ * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD
+ * 0x9c with CLEAR_STATS bit set (see above).
+ *
+ * uCode also issues this notification during scans.  uCode clears statistics
+ * appropriately so that each notification contains statistics for only the
+ * one channel that has just been scanned.
+ */
+#define STATISTICS_REPLY_FLG_BAND_24G_MSK         __constant_cpu_to_le32(0x2)
+#define STATISTICS_REPLY_FLG_FAT_MODE_MSK         __constant_cpu_to_le32(0x8)
+struct iwl4965_notif_statistics {
+       __le32 flag;
+       struct statistics_rx rx;
+       struct statistics_tx tx;
+       struct statistics_general general;
+} __attribute__ ((packed));
+
+
+/*
+ * MISSED_BEACONS_NOTIFICATION = 0xa2 (notification only, not a command)
+ */
+/* if ucode missed CONSECUTIVE_MISSED_BCONS_TH beacons in a row,
+ * then this notification will be sent. */
+#define CONSECUTIVE_MISSED_BCONS_TH 20
+
+struct iwl4965_missed_beacon_notif {
+       __le32 consequtive_missed_beacons;
+       __le32 total_missed_becons;
+       __le32 num_expected_beacons;
+       __le32 num_recvd_beacons;
+} __attribute__ ((packed));
+
+
+/******************************************************************************
+ * (11)
+ * Rx Calibration Commands:
+ *
+ * With the uCode used for open source drivers, most Tx calibration (except
+ * for Tx Power) and most Rx calibration is done by uCode during the
+ * "initialize" phase of uCode boot.  Driver must calibrate only:
+ *
+ * 1)  Tx power (depends on temperature), described elsewhere
+ * 2)  Receiver gain balance (optimize MIMO, and detect disconnected antennas)
+ * 3)  Receiver sensitivity (to optimize signal detection)
+ *
+ *****************************************************************************/
+
+/**
+ * SENSITIVITY_CMD = 0xa8 (command, has simple generic response)
+ *
+ * This command sets up the Rx signal detector for a sensitivity level that
+ * is high enough to lock onto all signals within the associated network,
+ * but low enough to ignore signals that are below a certain threshold, so as
+ * not to have too many "false alarms".  False alarms are signals that the
+ * Rx DSP tries to lock onto, but then discards after determining that they
+ * are noise.
+ *
+ * The optimum number of false alarms is between 5 and 50 per 200 TUs
+ * (200 * 1024 uSecs, i.e. 204.8 milliseconds) of actual Rx time (i.e.
+ * time listening, not transmitting).  Driver must adjust sensitivity so that
+ * the ratio of actual false alarms to actual Rx time falls within this range.
+ *
+ * While associated, uCode delivers STATISTICS_NOTIFICATIONs after each
+ * received beacon.  These provide information to the driver to analyze the
+ * sensitivity.  Don't analyze statistics that come in from scanning, or any
+ * other non-associated-network source.  Pertinent statistics include:
+ *
+ * From "general" statistics (struct statistics_rx_non_phy):
+ *
+ * (beacon_energy_[abc] & 0x0FF00) >> 8 (unsigned, higher value is lower level)
+ *   Measure of energy of desired signal.  Used for establishing a level
+ *   below which the device does not detect signals.
+ *
+ * (beacon_silence_rssi_[abc] & 0x0FF00) >> 8 (unsigned, units in dB)
+ *   Measure of background noise in silent period after beacon.
+ *
+ * channel_load
+ *   uSecs of actual Rx time during beacon period (varies according to
+ *   how much time was spent transmitting).
+ *
+ * From "cck" and "ofdm" statistics (struct statistics_rx_phy), separately:
+ *
+ * false_alarm_cnt
+ *   Signal locks abandoned early (before phy-level header).
+ *
+ * plcp_err
+ *   Signal locks abandoned late (during phy-level header).
+ *
+ * NOTE:  Both false_alarm_cnt and plcp_err increment monotonically from
+ *        beacon to beacon, i.e. each value is an accumulation of all errors
+ *        before and including the latest beacon.  Values will wrap around to 0
+ *        after counting up to 2^32 - 1.  Driver must differentiate vs.
+ *        previous beacon's values to determine # false alarms in the current
+ *        beacon period.
+ *
+ * Total number of false alarms = false_alarms + plcp_errs
+ *
+ * For OFDM, adjust the following table entries in struct iwl_sensitivity_cmd
+ * (notice that the start points for OFDM are at or close to settings for
+ * maximum sensitivity):
+ *
+ *                                             START  /  MIN  /  MAX
+ *   HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX          90   /   85  /  120
+ *   HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX     170   /  170  /  210
+ *   HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX         105   /  105  /  140
+ *   HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX     220   /  220  /  270
+ *
+ *   If actual rate of OFDM false alarms (+ plcp_errors) is too high
+ *   (greater than 50 for each 204.8 msecs listening), reduce sensitivity
+ *   by *adding* 1 to all 4 of the table entries above, up to the max for
+ *   each entry.  Conversely, if false alarm rate is too low (less than 5
+ *   for each 204.8 msecs listening), *subtract* 1 from each entry to
+ *   increase sensitivity.
+ *
+ * For CCK sensitivity, keep track of the following:
+ *
+ *   1).  20-beacon history of maximum background noise, indicated by
+ *        (beacon_silence_rssi_[abc] & 0x0FF00), units in dB, across the
+ *        3 receivers.  For any given beacon, the "silence reference" is
+ *        the maximum of last 60 samples (20 beacons * 3 receivers).
+ *
+ *   2).  10-beacon history of strongest signal level, as indicated
+ *        by (beacon_energy_[abc] & 0x0FF00) >> 8, across the 3 receivers,
+ *        i.e. the strength of the signal through the best receiver at the
+ *        moment.  These measurements are "upside down", with lower values
+ *        for stronger signals, so max energy will be *minimum* value.
+ *
+ *        Then for any given beacon, the driver must determine the *weakest*
+ *        of the strongest signals; this is the minimum level that needs to be
+ *        successfully detected, when using the best receiver at the moment.
+ *        "Max cck energy" is the maximum (higher value means lower energy!)
+ *        of the last 10 minima.  Once this is determined, driver must add
+ *        a little margin by adding "6" to it.
+ *
+ *   3).  Number of consecutive beacon periods with too few false alarms.
+ *        Reset this to 0 at the first beacon period that falls within the
+ *        "good" range (5 to 50 false alarms per 204.8 milliseconds rx).
+ *
+ * Then, adjust the following CCK table entries in struct iwl_sensitivity_cmd
+ * (notice that the start points for CCK are at maximum sensitivity):
+ *
+ *                                             START  /  MIN  /  MAX
+ *   HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX         125   /  125  /  200
+ *   HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX     200   /  200  /  400
+ *   HD_MIN_ENERGY_CCK_DET_INDEX                100   /    0  /  100
+ *
+ *   If actual rate of CCK false alarms (+ plcp_errors) is too high
+ *   (greater than 50 for each 204.8 msecs listening), method for reducing
+ *   sensitivity is:
+ *
+ *   1)  *Add* 3 to value in HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX,
+ *       up to max 400.
+ *
+ *   2)  If current value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX is < 160,
+ *       sensitivity has been reduced a significant amount; bring it up to
+ *       a moderate 161.  Otherwise, *add* 3, up to max 200.
+ *
+ *   3)  a)  If current value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX is > 160,
+ *       sensitivity has been reduced only a moderate or small amount;
+ *       *subtract* 2 from value in HD_MIN_ENERGY_CCK_DET_INDEX,
+ *       down to min 0.  Otherwise (if gain has been significantly reduced),
+ *       don't change the HD_MIN_ENERGY_CCK_DET_INDEX value.
+ *
+ *       b)  Save a snapshot of the "silence reference".
+ *
+ *   If actual rate of CCK false alarms (+ plcp_errors) is too low
+ *   (less than 5 for each 204.8 msecs listening), method for increasing
+ *   sensitivity is used only if:
+ *
+ *   1a)  Previous beacon did not have too many false alarms
+ *   1b)  AND difference between previous "silence reference" and current
+ *        "silence reference" (prev - current) is 2 or more,
+ *   OR 2)  100 or more consecutive beacon periods have had rate of
+ *          less than 5 false alarms per 204.8 milliseconds rx time.
+ *
+ *   Method for increasing sensitivity:
+ *
+ *   1)  *Subtract* 3 from value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX,
+ *       down to min 125.
+ *
+ *   2)  *Subtract* 3 from value in HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX,
+ *       down to min 200.
+ *
+ *   3)  *Add* 2 to value in HD_MIN_ENERGY_CCK_DET_INDEX, up to max 100.
+ *
+ *   If actual rate of CCK false alarms (+ plcp_errors) is within good range
+ *   (between 5 and 50 for each 204.8 msecs listening):
+ *
+ *   1)  Save a snapshot of the silence reference.
+ *
+ *   2)  If previous beacon had too many CCK false alarms (+ plcp_errors),
+ *       give some extra margin to energy threshold by *subtracting* 8
+ *       from value in HD_MIN_ENERGY_CCK_DET_INDEX.
+ *
+ *   For all cases (too few, too many, good range), make sure that the CCK
+ *   detection threshold (energy) is below the energy level for robust
+ *   detection over the past 10 beacon periods, the "Max cck energy".
+ *   Lower values mean higher energy; this means making sure that the value
+ *   in HD_MIN_ENERGY_CCK_DET_INDEX is at or *above* "Max cck energy".
+ *
+ * Driver should set the following entries to fixed values:
+ *
+ *   HD_MIN_ENERGY_OFDM_DET_INDEX               100
+ *   HD_BARKER_CORR_TH_ADD_MIN_INDEX            190
+ *   HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX        390
+ *   HD_OFDM_ENERGY_TH_IN_INDEX                  62
+ */
+
+/*
+ * 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 */
+#define HD_MIN_ENERGY_OFDM_DET_INDEX                (1)
+#define HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX          (2)
+#define HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX      (3)
+#define HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX      (4)
+#define HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX          (5)
+#define HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX      (6)
+#define HD_BARKER_CORR_TH_ADD_MIN_INDEX             (7)
+#define HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX         (8)
+#define HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX          (9)
+#define HD_OFDM_ENERGY_TH_IN_INDEX                  (10)
+
+/* 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 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 iwl_sensitivity_cmd {
+       __le16 control;                 /* always use "1" */
+       __le16 table[HD_TABLE_SIZE];    /* use HD_* as index */
+} __attribute__ ((packed));
+
+
+/**
+ * REPLY_PHY_CALIBRATION_CMD = 0xb0 (command, has simple generic response)
+ *
+ * This command sets the relative gains of 4965's 3 radio receiver chains.
+ *
+ * After the first association, driver should accumulate signal and noise
+ * statistics from the STATISTICS_NOTIFICATIONs that follow the first 20
+ * beacons from the associated network (don't collect statistics that come
+ * in from scanning, or any other non-network source).
+ *
+ * DISCONNECTED ANTENNA:
+ *
+ * Driver should determine which antennas are actually connected, by comparing
+ * average beacon signal levels for the 3 Rx chains.  Accumulate (add) the
+ * following values over 20 beacons, one accumulator for each of the chains
+ * a/b/c, from struct statistics_rx_non_phy:
+ *
+ * beacon_rssi_[abc] & 0x0FF (unsigned, units in dB)
+ *
+ * Find the strongest signal from among a/b/c.  Compare the other two to the
+ * strongest.  If any signal is more than 15 dB (times 20, unless you
+ * divide the accumulated values by 20) below the strongest, the driver
+ * considers that antenna to be disconnected, and should not try to use that
+ * antenna/chain for Rx or Tx.  If both A and B seem to be disconnected,
+ * driver should declare the stronger one as connected, and attempt to use it
+ * (A and B are the only 2 Tx chains!).
+ *
+ *
+ * RX BALANCE:
+ *
+ * Driver should balance the 3 receivers (but just the ones that are connected
+ * to antennas, see above) for gain, by comparing the average signal levels
+ * detected during the silence after each beacon (background noise).
+ * Accumulate (add) the following values over 20 beacons, one accumulator for
+ * each of the chains a/b/c, from struct statistics_rx_non_phy:
+ *
+ * beacon_silence_rssi_[abc] & 0x0FF (unsigned, units in dB)
+ *
+ * Find the weakest background noise level from among a/b/c.  This Rx chain
+ * will be the reference, with 0 gain adjustment.  Attenuate other channels by
+ * finding noise difference:
+ *
+ * (accum_noise[i] - accum_noise[reference]) / 30
+ *
+ * The "30" adjusts the dB in the 20 accumulated samples to units of 1.5 dB.
+ * For use in diff_gain_[abc] fields of struct iwl_calibration_cmd, the
+ * driver should limit the difference results to a range of 0-3 (0-4.5 dB),
+ * and set bit 2 to indicate "reduce gain".  The value for the reference
+ * (weakest) chain should be "0".
+ *
+ * diff_gain_[abc] bit fields:
+ *   2: (1) reduce gain, (0) increase gain
+ * 1-0: amount of gain, units of 1.5 dB
+ */
+
+/* "Differential Gain" opcode used in REPLY_PHY_CALIBRATION_CMD. */
+#define PHY_CALIBRATE_DIFF_GAIN_CMD (7)
+
+struct iwl4965_calibration_cmd {
+       u8 opCode;              /* PHY_CALIBRATE_DIFF_GAIN_CMD (7) */
+       u8 flags;               /* not used */
+       __le16 reserved;
+       s8 diff_gain_a;         /* see above */
+       s8 diff_gain_b;
+       s8 diff_gain_c;
+       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_CHAIN_NOISE_RESET_CMD = 18,
+       IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD = 19,
+};
+
+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:
+ *
+ *****************************************************************************/
+
+/*
+ * LEDs Command & Response
+ * REPLY_LEDS_CMD = 0x48 (command, has simple generic response)
+ *
+ * For each of 3 possible LEDs (Activity/Link/Tech, selected by "id" field),
+ * this command turns it on or off, or sets up a periodic blinking cycle.
+ */
+struct iwl4965_led_cmd {
+       __le32 interval;        /* "interval" in uSec */
+       u8 id;                  /* 1: Activity, 2: Link, 3: Tech */
+       u8 off;                 /* # intervals off while blinking;
+                                * "0", with >0 "on" value, turns LED on */
+       u8 on;                  /* # intervals on while blinking;
+                                * "0", regardless of "off", turns LED off */
+       u8 reserved;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (13)
+ * Union of all expected notifications/responses:
+ *
+ *****************************************************************************/
+
+struct iwl_rx_packet {
+       __le32 len;
+       struct iwl_cmd_header hdr;
+       union {
+               struct iwl4965_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 iwl4965_card_state_notif card_state_notif;
+               struct iwl4965_beacon_notif beacon_status;
+               struct iwl4965_add_sta_resp add_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;
+               __le32 status;
+               u8 raw[0];
+       } u;
+} __attribute__ ((packed));
+
+#define IWL_RX_FRAME_SIZE        (4 + sizeof(struct iwl4965_rx_frame))
+
+#endif                         /* __iwl4965_commands_h__ */
index 2dfd982..d3cbad2 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,44 @@ 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 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 */
+       /* FIXME:RS:          ^^    should be INV (legacy) */
+};
+EXPORT_SYMBOL(iwl4965_rates);
 
 /* This function both allocates and initializes hw and priv. */
 struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
@@ -72,6 +108,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 +228,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 +314,394 @@ 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
+static void iwlcore_init_ht_hw_capab(const 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 (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;
+       }
+       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;
+       if (priv->hw_params.tx_chains_num >= 2)
+               ht_info->supp_mcs_set[1] = 0xFF;
+       if (priv->hw_params.tx_chains_num >= 3)
+               ht_info->supp_mcs_set[2] = 0xFF;
+}
+#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 = 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;
+               }
+       }
+}
+
+/**
+ * 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;
+
+                       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;
+}
+
+/*
+ * iwlcore_free_geos - undo allocations in iwlcore_init_geos
+ */
+void iwlcore_free_geos(struct iwl_priv *priv)
+{
+       kfree(priv->ieee_channels);
+       kfree(priv->ieee_rates);
+       clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
+}
+EXPORT_SYMBOL(iwlcore_free_geos);
+
+#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 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 (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 +713,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,38 +739,111 @@ 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)
 {
        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 */
 }
 
+static int iwlcore_init_drv(struct iwl_priv *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);
+
+       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;
+       }
+
+       ret = ieee80211_register_hw(priv->hw);
+       if (ret) {
+               IWL_ERROR("Failed to register network device (error %d)\n",
+                               ret);
+               goto err_free_geos;
+       }
+
+       priv->hw->conf.beacon_int = 100;
+       priv->mac80211_registered = 1;
+
+       return 0;
+
+err_free_geos:
+       iwlcore_free_geos(priv);
+err_free_channel_map:
+       iwl_free_channel_map(priv);
+err:
+       return ret;
+}
+
 int iwl_setup(struct iwl_priv *priv)
 {
        int ret = 0;
        iwlcore_init_hw(priv);
-       ret = priv->cfg->ops->lib->init_drv(priv);
+       ret = iwlcore_init_drv(priv);
        return ret;
 }
 EXPORT_SYMBOL(iwl_setup);
@@ -263,8 +861,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 +890,137 @@ 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);
+
index 7193d97..e139c8f 100644 (file)
@@ -87,19 +87,32 @@ struct iwl_hcmd_ops {
 };
 struct iwl_hcmd_utils_ops {
        int (*enqueue_hcmd)(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
+       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);
        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);
+       /* setup Rx handler */
+       void (*rx_handler_setup)(struct iwl_priv *priv);
+       /* nic Tx fifo handling */
+       int (*disable_tx_fifo)(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 +121,15 @@ 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);
+               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 +149,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 +167,49 @@ 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_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 iwlcore_free_geos(struct iwl_priv *priv);
 int iwl_setup(struct iwl_priv *priv);
+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);
+
+/* "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);
+
+/*****************************************************
+* TX
+******************************************************/
+int iwl_txq_ctx_reset(struct iwl_priv *priv);
+/* 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);
 
 /*****************************************************
  *   S e n d i n g     H o s t     C o m m a n d s   *
@@ -235,6 +294,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 +303,5 @@ static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
        return priv->cfg->ops->hcmd->rxon_assoc(priv);
 }
 
+
 #endif /* __iwl_core_h__ */
index 1272579..9d6e5d2 100644 (file)
@@ -95,8 +95,7 @@
 #define CSR_GIO_CHICKEN_BITS    (CSR_BASE+0x100)
 #define CSR_LED_REG             (CSR_BASE+0x094)
 
-/* 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_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 c60724c..2f24594 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;
@@ -57,6 +47,7 @@ struct iwl_debugfs {
        struct dentry *dir_data;
        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;
@@ -76,9 +67,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 9a30e1d..ad25806 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"
@@ -206,7 +206,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 +277,48 @@ 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;
+}
 
 DEBUGFS_READ_WRITE_FILE_OPS(sram);
+DEBUGFS_READ_FILE_OPS(eeprom);
 DEBUGFS_READ_FILE_OPS(stations);
 DEBUGFS_READ_FILE_OPS(rx_statistics);
 DEBUGFS_READ_FILE_OPS(tx_statistics);
@@ -304,6 +344,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
        }
 
        DEBUGFS_ADD_DIR(data, dbgfs->dir_drv);
+       DEBUGFS_ADD_FILE(eeprom, data);
        DEBUGFS_ADD_FILE(sram, data);
        DEBUGFS_ADD_FILE(stations, data);
        DEBUGFS_ADD_FILE(rx_statistics, data);
@@ -327,6 +368,7 @@ 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);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
new file mode 100644 (file)
index 0000000..5dccc5a
--- /dev/null
@@ -0,0 +1,1263 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 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:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+/*
+ * 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.
+ */
+
+#ifndef __iwl_4965_h__
+#define __iwl_4965_h__
+
+#include <linux/pci.h> /* for struct pci_device_id */
+#include <linux/kernel.h>
+#include <net/ieee80211_radiotap.h>
+
+#define DRV_NAME        "iwl4965"
+#include "iwl-rfkill.h"
+#include "iwl-eeprom.h"
+#include "iwl-4965-hw.h"
+#include "iwl-csr.h"
+#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
+ *   is not compatible with earlier drivers.
+ * 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:
+ *   1)  Not associated (4965, no beacon statistics being sent to driver)
+ *   2)  Scanning (noise measurement does not apply to associated channel)
+ *   3)  Receiving CCK (3945 delivers noise info only for OFDM frames)
+ * Use default noise value of -127 ... this is below the range of measurable
+ *   Rx dBm for either 3945 or 4965, so it can indicate "unmeasurable" to user.
+ *   Also, -127 works better than 0 when averaging frames with/without
+ *   noise info (e.g. averaging might be done in app); measured dBm values are
+ *   always negative ... using a negative value as the default keeps all
+ *   averages within an s8's (used in some apps) range of negative values. */
+#define IWL_NOISE_MEAS_NOT_AVAILABLE (-127)
+
+/*
+ * RTS threshold here is total size [2347] minus 4 FCS bytes
+ * Per spec:
+ *   a value of 0 means RTS on all data/management packets
+ *   a value > max MSDU size means no RTS
+ * else RTS for data/management frames where MPDU is larger
+ *   than RTS value.
+ */
+#define DEFAULT_RTS_THRESHOLD     2347U
+#define MIN_RTS_THRESHOLD         0U
+#define MAX_RTS_THRESHOLD         2347U
+#define MAX_MSDU_SIZE            2304U
+#define MAX_MPDU_SIZE            2346U
+#define DEFAULT_BEACON_INTERVAL   100U
+#define        DEFAULT_SHORT_RETRY_LIMIT 7U
+#define        DEFAULT_LONG_RETRY_LIMIT  4U
+
+struct iwl_rx_mem_buffer {
+       dma_addr_t dma_addr;
+       struct sk_buff *skb;
+       struct list_head list;
+};
+
+/*
+ * Generic queue structure
+ *
+ * Contains common data for Rx and Tx queues
+ */
+struct iwl4965_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*/
+       dma_addr_t dma_addr;   /* physical addr for BD's */
+       int n_window;          /* safe queue window */
+       u32 id;
+       int low_mark;          /* low watermark, resume queue if free
+                               * space more than this */
+       int high_mark;         /* high watermark, stop queue if free
+                               * space less than this */
+} __attribute__ ((packed));
+
+#define MAX_NUM_OF_TBS          (20)
+
+/* One for each TFD */
+struct iwl4965_tx_info {
+       struct ieee80211_tx_status status;
+       struct sk_buff *skb[MAX_NUM_OF_TBS];
+};
+
+/**
+ * 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
+ * @dma_addr_cmd: physical address of cmd/tx buffer array
+ * @txb: array of per-TFD driver data
+ * @need_update: indicates need to update read/write index
+ * @sched_retry: indicates queue is high-throughput aggregation (HT AGG) enabled
+ *
+ * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame
+ * descriptors) and required locking structures.
+ */
+struct iwl_tx_queue {
+       struct iwl4965_queue q;
+       struct iwl_tfd_frame *bd;
+       struct iwl_cmd *cmd;
+       dma_addr_t dma_addr_cmd;
+       struct iwl4965_tx_info *txb;
+       int need_update;
+       int sched_retry;
+       int active;
+};
+
+#define IWL_NUM_SCAN_RATES         (2)
+
+struct iwl4965_channel_tgd_info {
+       u8 type;
+       s8 max_power;
+};
+
+struct iwl4965_channel_tgh_info {
+       s64 last_radar_time;
+};
+
+/* current Tx power values to use, one for each rate for each channel.
+ * requested power is limited by:
+ * -- regulatory EEPROM limits for this channel
+ * -- hardware capabilities (clip-powers)
+ * -- spectrum management
+ * -- user preference (e.g. iwconfig)
+ * when requested power is set, base power index must also be set. */
+struct iwl4965_channel_power_info {
+       struct iwl4965_tx_power tpc;    /* actual radio and DSP gain settings */
+       s8 power_table_index;   /* actual (compenst'd) index into gain table */
+       s8 base_power_index;    /* gain index for power at factory temp. */
+       s8 requested_power;     /* power (dBm) requested for this chnl/rate */
+};
+
+/* current scan Tx power values to use, one for each scan rate for each
+ * channel. */
+struct iwl4965_scan_power_info {
+       struct iwl4965_tx_power tpc;    /* actual radio and DSP gain settings */
+       s8 power_table_index;   /* actual (compenst'd) index into gain table */
+       s8 requested_power;     /* scan pwr (dBm) requested for chnl/rate */
+};
+
+/* For fat_extension_channel */
+enum {
+       HT_IE_EXT_CHANNEL_NONE = 0,
+       HT_IE_EXT_CHANNEL_ABOVE,
+       HT_IE_EXT_CHANNEL_INVALID,
+       HT_IE_EXT_CHANNEL_BELOW,
+       HT_IE_EXT_CHANNEL_MAX
+};
+
+/*
+ * One for each channel, holds all channel setup data
+ * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant
+ *     with one another!
+ */
+#define IWL4965_MAX_RATE (33)
+
+struct iwl_channel_info {
+       struct iwl4965_channel_tgd_info tgd;
+       struct iwl4965_channel_tgh_info tgh;
+       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 */
+       s8 max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
+       s8 curr_txpow;    /* (dBm) regulatory/spectrum/user (not h/w) limit */
+       s8 min_power;     /* always 0 */
+       s8 scan_power;    /* (dBm) regul. eeprom, direct scans, any rate */
+
+       u8 group_index;   /* 0-4, maps channel to group1/2/3/4/5 */
+       u8 band_index;    /* 0-4, maps channel to band1/2/3/4/5 */
+       enum ieee80211_band band;
+
+       /* Radio/DSP gain settings for each "normal" data Tx rate.
+        * These include, in addition to RF and DSP gain, a few fields for
+        *   remembering/modifying gain settings (indexes). */
+       struct iwl4965_channel_power_info power_info[IWL4965_MAX_RATE];
+
+       /* FAT channel info */
+       s8 fat_max_power_avg;   /* (dBm) regul. eeprom, normal Tx, any rate */
+       s8 fat_curr_txpow;      /* (dBm) regulatory/spectrum/user (not h/w) */
+       s8 fat_min_power;       /* always 0 */
+       s8 fat_scan_power;      /* (dBm) eeprom, direct scans, any rate */
+       u8 fat_flags;           /* flags copied from EEPROM */
+       u8 fat_extension_channel; /* HT_IE_EXT_CHANNEL_* */
+
+       /* Radio/DSP gain settings for each scan rate, for directed scans. */
+       struct iwl4965_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES];
+};
+
+struct iwl4965_clip_group {
+       /* maximum power level to prevent clipping for each rate, derived by
+        *   us from this band's saturation power in EEPROM */
+       const s8 clip_powers[IWL_MAX_RATES];
+};
+
+#include "iwl-4965-rs.h"
+
+#define IWL_TX_FIFO_AC0        0
+#define IWL_TX_FIFO_AC1        1
+#define IWL_TX_FIFO_AC2        2
+#define IWL_TX_FIFO_AC3        3
+#define IWL_TX_FIFO_HCCA_1     5
+#define IWL_TX_FIFO_HCCA_2     6
+#define IWL_TX_FIFO_NONE       7
+
+/* Minimum number of queues. MAX_NUM is defined in hw specific files */
+#define IWL_MIN_NUM_QUEUES     4
+
+/* Power management (not Tx power) structures */
+
+enum iwl_pwr_src {
+       IWL_PWR_SRC_VMAIN,
+       IWL_PWR_SRC_VAUX,
+};
+
+#define IEEE80211_DATA_LEN              2304
+#define IEEE80211_4ADDR_LEN             30
+#define IEEE80211_HLEN                  (IEEE80211_4ADDR_LEN)
+#define IEEE80211_FRAME_LEN             (IEEE80211_DATA_LEN + IEEE80211_HLEN)
+
+struct iwl4965_frame {
+       union {
+               struct ieee80211_hdr frame;
+               struct iwl4965_tx_beacon_cmd beacon;
+               u8 raw[IEEE80211_FRAME_LEN];
+               u8 cmd[360];
+       } u;
+       struct list_head list;
+};
+
+#define SEQ_TO_QUEUE(x)  ((x >> 8) & 0xbf)
+#define QUEUE_TO_SEQ(x)  ((x & 0xbf) << 8)
+#define SEQ_TO_INDEX(x) ((u8)(x & 0xff))
+#define INDEX_TO_SEQ(x) ((u8)(x & 0xff))
+#define SEQ_HUGE_FRAME  (0x4000)
+#define SEQ_RX_FRAME    __constant_cpu_to_le16(0x8000)
+#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
+#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
+#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
+
+enum {
+       /* CMD_SIZE_NORMAL = 0, */
+       CMD_SIZE_HUGE = (1 << 0),
+       /* CMD_SYNC = 0, */
+       CMD_ASYNC = (1 << 1),
+       /* CMD_NO_SKB = 0, */
+       CMD_WANT_SKB = (1 << 2),
+};
+
+struct iwl_cmd;
+struct iwl_priv;
+
+struct iwl_cmd_meta {
+       struct iwl_cmd_meta *source;
+       union {
+               struct sk_buff *skb;
+               int (*callback)(struct iwl_priv *priv,
+                               struct iwl_cmd *cmd, struct sk_buff *skb);
+       } __attribute__ ((packed)) u;
+
+       /* The CMD_SIZE_HUGE flag bit indicates that the command
+        * structure is stored at the end of the shared queue memory. */
+       u32 flags;
+
+} __attribute__ ((packed));
+
+/**
+ * struct iwl_cmd
+ *
+ * For allocation of the command and tx queues, this establishes the overall
+ * size of the largest command we send to uCode, except for a scan command
+ * (which is relatively huge; space is allocated separately).
+ */
+struct iwl_cmd {
+       struct iwl_cmd_meta meta;       /* driver data */
+       struct iwl_cmd_header hdr;      /* uCode API */
+       union {
+               struct iwl_addsta_cmd addsta;
+               struct iwl4965_led_cmd led;
+               u32 flags;
+               u8 val8;
+               u16 val16;
+               u32 val32;
+               struct iwl4965_bt_cmd bt;
+               struct iwl4965_rxon_time_cmd rxon_time;
+               struct iwl4965_powertable_cmd powertable;
+               struct iwl4965_qosparam_cmd qosparam;
+               struct iwl4965_tx_cmd tx;
+               struct iwl4965_tx_beacon_cmd tx_beacon;
+               struct iwl4965_rxon_assoc_cmd rxon_assoc;
+               u8 *indirect;
+               u8 payload[360];
+       } __attribute__ ((packed)) cmd;
+} __attribute__ ((packed));
+
+struct iwl_host_cmd {
+       u8 id;
+       u16 len;
+       struct iwl_cmd_meta meta;
+       const void *data;
+};
+
+#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \
+                             sizeof(struct iwl_cmd_meta))
+
+/*
+ * RX related structures and functions
+ */
+#define RX_FREE_BUFFERS 64
+#define RX_LOW_WATERMARK 8
+
+#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
+#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
+#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
+
+/**
+ * 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
+ * @free_count: Number of pre-allocated buffers in rx_free
+ * @rx_free: list of free SKBs for use
+ * @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 iwl_rx_mem_buffers
+ */
+struct iwl_rx_queue {
+       __le32 *bd;
+       dma_addr_t dma_addr;
+       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;
+       u32 free_count;
+       struct list_head rx_free;
+       struct list_head rx_used;
+       int need_update;
+       spinlock_t lock;
+};
+
+#define IWL_SUPPORTED_RATES_IE_LEN         8
+
+#define SCAN_INTERVAL 100
+
+#define MAX_A_CHANNELS  252
+#define MIN_A_CHANNELS  7
+
+#define MAX_B_CHANNELS  14
+#define MIN_B_CHANNELS  1
+
+#define MAX_TID_COUNT        9
+
+#define IWL_INVALID_RATE     0xFF
+#define IWL_INVALID_VALUE    -1
+
+#ifdef CONFIG_IWL4965_HT
+/**
+ * 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
+ * @start_idx: Index of 1st Transmit Frame Descriptor (TFD) in Tx window
+ * @bitmap0: Low order bitmap, one bit for each frame pending ACK in Tx window
+ * @bitmap1: High order, one bit for each frame pending ACK in Tx window
+ * @rate_n_flags: Rate at which Tx was attempted
+ *
+ * If REPLY_TX indicates that aggregation was attempted, driver must wait
+ * for block ack (REPLY_COMPRESSED_BA).  This struct stores tx reply info
+ * until block ack arrives.
+ */
+struct iwl_ht_agg {
+       u16 txq_id;
+       u16 frame_count;
+       u16 wait_for_ba;
+       u16 start_idx;
+       u64 bitmap;
+       u32 rate_n_flags;
+#define IWL_AGG_OFF 0
+#define IWL_AGG_ON 1
+#define IWL_EMPTYING_HW_QUEUE_ADDBA 2
+#define IWL_EMPTYING_HW_QUEUE_DELBA 3
+       u8 state;
+};
+
+#endif /* CONFIG_IWL4965_HT */
+
+struct iwl_tid_data {
+       u16 seq_number;
+       u16 tfds_in_queue;
+#ifdef CONFIG_IWL4965_HT
+       struct iwl_ht_agg agg;
+#endif /* CONFIG_IWL4965_HT */
+};
+
+struct iwl_hw_key {
+       enum ieee80211_key_alg alg;
+       int keylen;
+       u8 keyidx;
+       struct ieee80211_key_conf *conf;
+       u8 key[32];
+};
+
+union iwl4965_ht_rate_supp {
+       u16 rates;
+       struct {
+               u8 siso_rate;
+               u8 mimo_rate;
+       };
+};
+
+#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
+
+struct iwl_ht_info {
+       /* self configuration data */
+       u8 is_ht;
+       u8 supported_chan_width;
+       u16 tx_mimo_ps_mode;
+       u8 is_green_field;
+       u8 sgf;                 /* HT_SHORT_GI_* short guard interval */
+       u8 max_amsdu_size;
+       u8 ampdu_factor;
+       u8 mpdu_density;
+       u8 supp_mcs_set[16];
+       /* BSS related data */
+       u8 control_channel;
+       u8 extension_chan_offset;
+       u8 tx_chan_width;
+       u8 ht_protection;
+       u8 non_GF_STA_present;
+};
+
+union iwl4965_qos_capabity {
+       struct {
+               u8 edca_count:4;        /* bit 0-3 */
+               u8 q_ack:1;             /* bit 4 */
+               u8 queue_request:1;     /* bit 5 */
+               u8 txop_request:1;      /* bit 6 */
+               u8 reserved:1;          /* bit 7 */
+       } q_AP;
+       struct {
+               u8 acvo_APSD:1;         /* bit 0 */
+               u8 acvi_APSD:1;         /* bit 1 */
+               u8 ac_bk_APSD:1;        /* bit 2 */
+               u8 ac_be_APSD:1;        /* bit 3 */
+               u8 q_ack:1;             /* bit 4 */
+               u8 max_len:2;           /* bit 5-6 */
+               u8 more_data_ack:1;     /* bit 7 */
+       } q_STA;
+       u8 val;
+};
+
+/* QoS structures */
+struct iwl4965_qos_info {
+       int qos_enable;
+       int qos_active;
+       union iwl4965_qos_capabity qos_cap;
+       struct iwl4965_qosparam_cmd def_qos_parm;
+};
+
+#define STA_PS_STATUS_WAKE             0
+#define STA_PS_STATUS_SLEEP            1
+
+struct iwl_station_entry {
+       struct iwl_addsta_cmd sta;
+       struct iwl_tid_data tid[MAX_TID_COUNT];
+       u8 used;
+       u8 ps_status;
+       struct iwl_hw_key keyinfo;
+};
+
+/* one for each uCode image (inst/data, boot/init/runtime) */
+struct fw_desc {
+       void *v_addr;           /* access by driver */
+       dma_addr_t p_addr;      /* access by card's busmaster DMA */
+       u32 len;                /* bytes */
+};
+
+/* uCode file layout */
+struct iwl4965_ucode {
+       __le32 ver;             /* major/minor/subminor */
+       __le32 inst_size;       /* bytes of runtime instructions */
+       __le32 data_size;       /* bytes of runtime data */
+       __le32 init_size;       /* bytes of initialization instructions */
+       __le32 init_data_size;  /* bytes of initialization data */
+       __le32 boot_size;       /* bytes of bootstrap instructions */
+       u8 data[0];             /* data in same order as "size" elements */
+};
+
+#define IWL_IBSS_MAC_HASH_SIZE 32
+
+struct iwl4965_ibss_seq {
+       u8 mac[ETH_ALEN];
+       u16 seq_num;
+       u16 frag_num;
+       unsigned long packet_time;
+       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/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)
+ * @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;
+       u8  valid_rx_ant;
+       u16 max_rxq_size;
+       u16 max_rxq_log;
+       u32 rx_buf_size;
+       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 IWL_RX_HDR(x) ((struct iwl4965_rx_frame_hdr *)(\
+                      x->u.rx_frame.stats.payload + \
+                      x->u.rx_frame.stats.phy_count))
+#define IWL_RX_END(x) ((struct iwl4965_rx_frame_end *)(\
+                      IWL_RX_HDR(x)->payload + \
+                      le16_to_cpu(IWL_RX_HDR(x)->len)))
+#define IWL_RX_STATS(x) (&x->u.rx_frame.stats)
+#define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload)
+
+
+/******************************************************************************
+ *
+ * Functions implemented in iwl-base.c which are forward declared here
+ * for use by iwl-*.c
+ *
+ *****************************************************************************/
+struct iwl_addsta_cmd;
+extern int iwl_send_add_sta(struct iwl_priv *priv,
+                           struct iwl_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);
+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 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_calc_db_from_ratio(int sig_ratio);
+extern int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm);
+extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv,
+                                       struct ieee80211_hdr *hdr,
+                                       const u8 *dest, int left);
+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];
+int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
+
+/*
+ * Currently used by iwl-3945-rs... look at restructuring so that it doesn't
+ * call this... todo... fix that.
+*/
+extern u8 iwl4965_sync_station(struct iwl_priv *priv, int sta_id,
+                          u16 tx_rate, u8 flags);
+
+/******************************************************************************
+ *
+ * Functions implemented in iwl-[34]*.c which are forward declared here
+ * for use by iwl-base.c
+ *
+ * NOTE:  The implementation of these functions are hardware specific
+ * which is why they are in the hardware specific files (vs. iwl-base.c)
+ *
+ * Naming convention --
+ * iwl4965_         <-- Its part of iwlwifi (should be changed to iwl4965_)
+ * iwl4965_hw_      <-- Hardware specific (implemented in iwl-XXXX.c by all HW)
+ * iwlXXXX_     <-- Hardware specific (implemented in iwl-XXXX.c for XXXX)
+ * iwl4965_bg_      <-- Called from work queue context
+ * iwl4965_mac_     <-- mac80211 callback
+ *
+ ****************************************************************************/
+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_stop_master(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_get_temperature(struct iwl_priv *priv);
+extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
+                                struct iwl4965_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_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 iwl_rx_mem_buffer *rxb);
+extern void iwl4965_disable_events(struct iwl_priv *priv);
+extern int iwl4965_get_temperature(const struct iwl_priv *priv);
+
+/**
+ * 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 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);
+struct iwl_priv;
+
+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 iwl_tx_queue *txq,
+                                         u16 byte_cnt);
+extern void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr,
+                               int is_ap);
+extern int iwl4965_alive_notify(struct iwl_priv *priv);
+extern void iwl4965_update_rate_scaling(struct iwl_priv *priv, u8 mode);
+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);
+
+#ifdef CONFIG_IWL4965_HT
+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(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 IWL_KW_SIZE 0x1000     /*4k */
+
+struct iwl_kw {
+       dma_addr_t dma_addr;
+       void *v_addr;
+       size_t size;
+};
+
+#define IWL_CHANNEL_WIDTH_20MHZ   0
+#define IWL_CHANNEL_WIDTH_40MHZ   1
+
+#define IWL_MIMO_PS_STATIC        0
+#define IWL_MIMO_PS_NONE          3
+#define IWL_MIMO_PS_DYNAMIC       1
+#define IWL_MIMO_PS_INVALID       2
+
+#define IWL_OPERATION_MODE_AUTO     0
+#define IWL_OPERATION_MODE_HT_ONLY  1
+#define IWL_OPERATION_MODE_MIXED    2
+#define IWL_OPERATION_MODE_20MHZ    3
+
+#define IWL_EXT_CHANNEL_OFFSET_NONE      0
+#define IWL_EXT_CHANNEL_OFFSET_ABOVE     1
+#define IWL_EXT_CHANNEL_OFFSET_RESERVE1  2
+#define IWL_EXT_CHANNEL_OFFSET_BELOW     3
+
+#define IWL_TX_CRC_SIZE 4
+#define IWL_TX_DELIMITER_SIZE 4
+
+#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
+
+struct iwl4965_lq_mngr {
+       spinlock_t lock;
+       s32 max_window_size;
+       s32 *expected_tpt;
+       u8 *next_higher_rate;
+       u8 *next_lower_rate;
+       unsigned long stamp;
+       unsigned long stamp_last;
+       u32 flush_time;
+       u32 tx_packets;
+       u8 lq_ready;
+};
+
+/* Sensitivity and chain noise calibration */
+#define INTERFERENCE_DATA_AVAILABLE    __constant_cpu_to_le32(1)
+#define INITIALIZATION_VALUE           0xFFFF
+#define CAL_NUM_OF_BEACONS             20
+#define MAXIMUM_ALLOWED_PATHLOSS       15
+
+#define CHAIN_NOISE_MAX_DELTA_GAIN_CODE 3
+
+#define MAX_FA_OFDM  50
+#define MIN_FA_OFDM  5
+#define MAX_FA_CCK   50
+#define MIN_FA_CCK   5
+
+#define AUTO_CORR_STEP_OFDM       1
+
+#define AUTO_CORR_STEP_CCK     3
+#define AUTO_CORR_MAX_TH_CCK   160
+
+#define NRG_DIFF               2
+#define NRG_STEP_CCK           2
+#define NRG_MARGIN             8
+#define MAX_NUMBER_CCK_NO_FA 100
+
+#define AUTO_CORR_CCK_MIN_VAL_DEF    (125)
+
+#define CHAIN_A             0
+#define CHAIN_B             1
+#define CHAIN_C             2
+#define CHAIN_NOISE_DELTA_GAIN_INIT_VAL 4
+#define ALL_BAND_FILTER                        0xFF00
+#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,
+       IWL_FA_GOOD_RANGE = 2,
+};
+
+enum iwl4965_chain_noise_state {
+       IWL_CHAIN_NOISE_ALIVE = 0,  /* must be 0 */
+       IWL_CHAIN_NOISE_ACCUMULATE = 1,
+       IWL_CHAIN_NOISE_CALIBRATED = 2,
+};
+
+enum iwl4965_calib_enabled_state {
+       IWL_CALIB_DISABLED = 0,  /* must be 0 */
+       IWL_CALIB_ENABLED = 1,
+};
+
+struct statistics_general_data {
+       u32 beacon_silence_rssi_a;
+       u32 beacon_silence_rssi_b;
+       u32 beacon_silence_rssi_c;
+       u32 beacon_energy_a;
+       u32 beacon_energy_b;
+       u32 beacon_energy_c;
+};
+
+#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
+/* Sensitivity calib data */
+struct iwl_sensitivity_data {
+       u32 auto_corr_ofdm;
+       u32 auto_corr_ofdm_mrc;
+       u32 auto_corr_ofdm_x1;
+       u32 auto_corr_ofdm_mrc_x1;
+       u32 auto_corr_cck;
+       u32 auto_corr_cck_mrc;
+
+       u32 last_bad_plcp_cnt_ofdm;
+       u32 last_fa_cnt_ofdm;
+       u32 last_bad_plcp_cnt_cck;
+       u32 last_fa_cnt_cck;
+
+       u32 nrg_curr_state;
+       u32 nrg_prev_state;
+       u32 nrg_value[10];
+       u8  nrg_silence_rssi[NRG_NUM_PREV_STAT_L];
+       u32 nrg_silence_ref;
+       u32 nrg_energy_idx;
+       u32 nrg_silence_idx;
+       u32 nrg_th_cck;
+       s32 nrg_auto_corr_silence_diff;
+       u32 num_in_cck_no_fa;
+       u32 nrg_th_ofdm;
+};
+
+/* Chain noise (differential Rx gain) calib data */
+struct iwl_chain_noise_data {
+       u8 state;
+       u16 beacon_count;
+       u32 chain_noise_a;
+       u32 chain_noise_b;
+       u32 chain_noise_c;
+       u32 chain_signal_a;
+       u32 chain_signal_b;
+       u32 chain_signal_c;
+       u8 disconn_array[NUM_RX_CHAINS];
+       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) */
+
+
+#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
+
+enum {
+       MEASUREMENT_READY = (1 << 0),
+       MEASUREMENT_ACTIVE = (1 << 1),
+};
+
+#endif
+
+#define IWL_MAX_NUM_QUEUES     20 /* FIXME: do dynamic allocation */
+
+struct iwl_priv {
+
+       /* ieee device used by generic ieee processing code */
+       struct ieee80211_hw *hw;
+       struct ieee80211_channel *ieee_channels;
+       struct ieee80211_rate *ieee_rates;
+       struct iwl_cfg *cfg;
+
+       /* temporary frame storage list */
+       struct list_head free_frames;
+       int frames_count;
+
+       enum ieee80211_band band;
+       int alloc_rxb_skb;
+       bool add_radiotap;
+
+       void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
+                                      struct iwl_rx_mem_buffer *rxb);
+
+       struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
+
+#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
+       /* spectrum measurement report caching */
+       struct iwl4965_spectrum_notification measure_report;
+       u8 measurement_status;
+#endif
+       /* ucode beacon time */
+       u32 ucode_beacon_time;
+
+       /* we allocate array of iwl4965_channel_info for NIC's valid channels.
+        *    Access via channel # using indirect index array */
+       struct iwl_channel_info *channel_info;  /* channel info array */
+       u8 channel_count;       /* # of channels */
+
+       /* each calibration channel group in the EEPROM has a derived
+        * clip setting for each rate. */
+       const struct iwl4965_clip_group clip_groups[5];
+
+       /* thermal calibration */
+       s32 temperature;        /* degrees Kelvin */
+       s32 last_temperature;
+
+       /* Scan related variables */
+       unsigned long last_scan_jiffies;
+       unsigned long next_scan_jiffies;
+       unsigned long scan_start;
+       unsigned long scan_pass_start;
+       unsigned long scan_start_tsf;
+       int scan_bands;
+       int one_direct_scan;
+       u8 direct_ssid_len;
+       u8 direct_ssid[IW_ESSID_MAX_SIZE];
+       struct iwl4965_scan_cmd *scan;
+
+       /* spinlock */
+       spinlock_t lock;        /* protect general shared data */
+       spinlock_t hcmd_lock;   /* protect hcmd */
+       struct mutex mutex;
+
+       /* basic pci-network driver stuff */
+       struct pci_dev *pci_dev;
+
+       /* 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 */
+       struct fw_desc ucode_data;      /* runtime data original */
+       struct fw_desc ucode_data_backup;       /* runtime data save/restore */
+       struct fw_desc ucode_init;      /* initialization inst */
+       struct fw_desc ucode_init_data; /* initialization data */
+       struct fw_desc ucode_boot;      /* bootstrap inst */
+
+
+       struct iwl4965_rxon_time_cmd rxon_timing;
+
+       /* We declare this const so it can only be
+        * 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;
+
+       int error_recovering;
+       struct iwl4965_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;
+#ifdef CONFIG_IWLWIFI_RFKILL
+       struct iwl_rfkill_mngr rfkill_mngr;
+#endif
+
+#ifdef CONFIG_IWLWIFI_LEDS
+       struct iwl4965_led led[IWL_LED_TRG_MAX];
+       unsigned long last_blink_time;
+       u8 last_blink_rate;
+       u8 allow_blinking;
+       u64 led_tpt;
+#endif
+
+       u16 active_rate;
+       u16 active_rate_basic;
+
+       u8 assoc_station_added;
+       u8 use_ant_b_for_management_frame;      /* Tx antenna selection */
+       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_IWLWIFI_RUN_TIME_CALIB*/
+
+#ifdef CONFIG_IWL4965_HT
+       struct iwl_ht_info current_ht_config;
+#endif
+       u8 last_phy_res[100];
+
+       /* Rate scaling data */
+       struct iwl4965_lq_mngr lq_mngr;
+
+       /* Rate scaling data */
+       s8 data_retry_limit;
+       u8 retry_rate;
+
+       wait_queue_head_t wait_command_queue;
+
+       int activity_timer_active;
+
+       /* Rx and Tx DMA processing queues */
+       struct iwl_rx_queue rxq;
+       struct iwl_tx_queue txq[IWL_MAX_NUM_QUEUES];
+       unsigned long txq_ctx_active_msk;
+       struct iwl_kw kw;       /* keep warm address */
+       u32 scd_base_addr;      /* scheduler sram base address */
+
+       unsigned long status;
+
+       int last_rx_rssi;       /* From Rx packet statisitics */
+       int last_rx_noise;      /* From beacon statistics */
+
+       /* counts mgmt, ctl, and data packets */
+       struct traffic_stats {
+               u32 cnt;
+               u64 bytes;
+       } tx_stats[3], rx_stats[3];
+
+       struct iwl_power_mgr power_data;
+
+       struct iwl4965_notif_statistics statistics;
+       unsigned long last_statistics_time;
+
+       /* context information */
+       u8 essid[IW_ESSID_MAX_SIZE];
+       u8 essid_len;
+       u16 rates_mask;
+
+       u32 power_mode;
+       u32 antenna;
+       u8 bssid[ETH_ALEN];
+       u16 rts_threshold;
+       u8 mac_addr[ETH_ALEN];
+
+       /*station table variables */
+       spinlock_t sta_lock;
+       int num_stations;
+       struct iwl_station_entry stations[IWL_STATION_COUNT];
+       struct iwl_wep_key wep_keys[WEP_KEYS_MAX];
+       u8 default_wep_key;
+       u8 key_mapping_key;
+       unsigned long ucode_key_table;
+
+       /* Indication if ieee80211_ops->open has been called */
+       u8 is_open;
+
+       u8 mac80211_registered;
+
+       u32 notif_missed_beacons;
+
+       /* Rx'd packet timing information */
+       u32 last_beacon_time;
+       u64 last_tsf;
+
+       /* Duplicate packet detection */
+       u16 last_seq_num;
+       u16 last_frag_num;
+       unsigned long last_packet_time;
+
+       /* Hash table for finding stations in IBSS network */
+       struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE];
+
+       /* eeprom */
+       u8 *eeprom;
+       struct iwl_eeprom_calib_info *calib_info;
+
+       enum ieee80211_if_types iw_mode;
+
+       struct sk_buff *ibss_beacon;
+
+       /* Last Rx'd beacon timestamp */
+       u64 timestamp;
+       u16 beacon_int;
+       struct ieee80211_vif *vif;
+
+       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;
+
+       /* Current association information needed to configure the
+        * hardware */
+       u16 assoc_id;
+       u16 assoc_capability;
+       u8 ps_mode;
+
+       struct iwl4965_qos_info qos_data;
+
+       struct workqueue_struct *workqueue;
+
+       struct work_struct up;
+       struct work_struct restart;
+       struct work_struct calibrated_work;
+       struct work_struct scan_completed;
+       struct work_struct rx_replenish;
+       struct work_struct rf_kill;
+       struct work_struct abort_scan;
+       struct work_struct update_link_led;
+       struct work_struct auth_work;
+       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;
+
+       struct delayed_work init_alive_start;
+       struct delayed_work alive_start;
+       struct delayed_work activity_timer;
+       struct delayed_work thermal_periodic;
+       struct delayed_work gather_stats;
+       struct delayed_work scan_check;
+       struct delayed_work post_associate;
+
+#define IWL_DEFAULT_TX_POWER 0x0F
+       s8 user_txpower_limit;
+       s8 max_channel_txpower_limit;
+
+#ifdef CONFIG_PM
+       u32 pm_state[16];
+#endif
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       /* debugging info */
+       u32 debug_level;
+       u32 framecnt_to_us;
+       atomic_t restrict_refcnt;
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+       /* debugfs */
+       struct iwl_debugfs *dbgfs;
+#endif /* CONFIG_IWLWIFI_DEBUGFS */
+#endif /* CONFIG_IWLWIFI_DEBUG */
+
+       struct work_struct txpower_work;
+#ifdef CONFIG_IWL4965_RUN_TIME_CALIB
+       struct work_struct sensitivity_work;
+#endif
+       struct timer_list statistics_periodic;
+}; /*iwl_priv */
+
+static inline int iwl_is_associated(struct iwl_priv *priv)
+{
+       return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
+}
+
+static inline int is_channel_valid(const struct iwl_channel_info *ch_info)
+{
+       if (ch_info == NULL)
+               return 0;
+       return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0;
+}
+
+static inline int is_channel_radar(const struct iwl_channel_info *ch_info)
+{
+       return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0;
+}
+
+static inline u8 is_channel_a_band(const struct iwl_channel_info *ch_info)
+{
+       return ch_info->band == IEEE80211_BAND_5GHZ;
+}
+
+static inline u8 is_channel_bg_band(const struct iwl_channel_info *ch_info)
+{
+       return ch_info->band == IEEE80211_BAND_2GHZ;
+}
+
+static inline int is_channel_passive(const struct iwl_channel_info *ch)
+{
+       return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0;
+}
+
+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);
+
+/* Requires full declaration of iwl_priv before including */
+
+#endif                         /* __iwl4965_4965_h__ */
index a07d5dc..fa30660 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:
@@ -323,7 +371,7 @@ static void iwl_init_band_reference(const struct iwl_priv *priv,
  */
 static int iwl4965_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,
index bd0a042..dc1f027 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,54 @@ 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)
+
+/* 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 +191,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 +200,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 +224,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 +249,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 +309,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 +357,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 fdb27f1..0412adf 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"
@@ -101,7 +101,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 +109,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);
index 03fdf5b..aa6ad18 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 c9cf8ee..acac629 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)
+
+/* 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 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)
+
 /*
- * 4965 Tx Scheduler registers.
- * Details are documented in iwl-4965-hw.h
+ * 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_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_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 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 IWL49_SCD_TXFIFO_POS_TID               (0)
+#define IWL49_SCD_TXFIFO_POS_RA                        (4)
+#define IWL49_SCD_QUEUE_RA_TID_MAP_RATID_MSK   (0x01FF)
+
+/* 5000 SCD */
 #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 5980a56..59c8a71 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..a2eb90d
--- /dev/null
@@ -0,0 +1,422 @@
+/******************************************************************************
+ *
+ * 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-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;
+}
+
index e4fdfaa..f226704 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"
+
+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);
+
+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.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);
 
 int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
 {
@@ -91,6 +170,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 +191,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)
@@ -138,6 +219,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,
@@ -172,15 +254,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);
 
@@ -214,8 +299,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 +313,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,
@@ -243,8 +332,13 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
        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,29 +350,51 @@ 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;
 
        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, 0);
+       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)
@@ -304,6 +420,7 @@ int iwl_set_dynamic_key(struct iwl_priv *priv,
 
        return ret;
 }
+EXPORT_SYMBOL(iwl_set_dynamic_key);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
 static void iwl_dump_lq_cmd(struct iwl_priv *priv,
index 44f272e..38b1b0a 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"
-
 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);
 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);
 #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..a1e03cc
--- /dev/null
@@ -0,0 +1,373 @@
+/******************************************************************************
+ *
+ * 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-helpers.h"
+
+/**
+ * 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);
+
+/**
+ * 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 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))
+               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));
+}
+
+/**
+ * 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_queue_init - Initialize queue's high/low-water and read/write indexes
+ */
+static int iwl_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;
+}
+
+/**
+ * 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_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;
+
+       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;
+       }
+
+       /* Turn off all Tx DMA fifos */
+       ret = priv->cfg->ops->lib->disable_tx_fifo(priv);
+       if (unlikely(ret))
+               goto error_reset;
+
+       /* 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 (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;
+               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;
+}
index 13925b6..c1234ff 100644 (file)
@@ -2391,7 +2391,8 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv,
                                      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[ctl->hw_key->hw_key_idx].keyinfo;
 
        switch (keyinfo->alg) {
        case ALG_CCMP:
@@ -2414,7 +2415,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;
+                   (ctl->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 +2423,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", ctl->hw_key->hw_key_idx);
                break;
 
        default:
@@ -4840,7 +4841,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 +4851,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 +4986,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);
 
@@ -6147,6 +6144,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)
@@ -6999,7 +7014,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 +7087,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 +7177,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 +7251,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);
@@ -7875,6 +7906,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 +8029,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;
index 883b42f..55ca752 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);
+                                 struct iwl_tx_queue *txq);
 
 /******************************************************************************
  *
@@ -98,7 +99,7 @@ __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr)
        return NULL;
 }
 
-static const struct ieee80211_supported_band *iwl4965_get_hw_mode(
+static const struct ieee80211_supported_band *iwl_get_hw_mode(
                struct iwl_priv *priv, enum ieee80211_band band)
 {
        return priv->hw->wiphy->bands[band];
@@ -144,6 +145,7 @@ static const char *iwl4965_escape_essid(const char *essid, u8 essid_len)
        return escaped;
 }
 
+
 /*************** DMA-QUEUE-GENERAL-FUNCTIONS  *****
  * DMA services
  *
@@ -205,173 +207,6 @@ static inline u8 get_cmd_index(struct iwl4965_queue *q, u32 index, int is_huge)
        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 ****
@@ -432,7 +267,7 @@ u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr,
 {
        int i;
        int index = IWL_INVALID_STATION;
-       struct iwl4965_station_entry *station;
+       struct iwl_station_entry *station;
        unsigned long flags_spin;
        DECLARE_MAC_BUF(mac);
 
@@ -475,7 +310,7 @@ u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr,
        priv->num_stations++;
 
        /* Set up the REPLY_ADD_STA command to send to device */
-       memset(&station->sta, 0, sizeof(struct iwl4965_addsta_cmd));
+       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;
@@ -492,7 +327,7 @@ u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr,
        spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
 
        /* Add station to device's station table */
-       iwl4965_send_add_station(priv, &station->sta, flags);
+       iwl_send_add_sta(priv, &station->sta, flags);
        return index;
 
 }
@@ -512,9 +347,9 @@ u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr,
  */
 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 iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
        struct iwl4965_queue *q = &txq->q;
-       struct iwl4965_tfd_frame *tfd;
+       struct iwl_tfd_frame *tfd;
        u32 *control_flags;
        struct iwl_cmd *out_cmd;
        u32 idx;
@@ -795,14 +630,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
@@ -835,7 +662,7 @@ 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);
@@ -846,13 +673,10 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
 
        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));
 
@@ -889,6 +713,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 +736,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 +751,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 +772,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,87 +794,9 @@ 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)
 {
        struct list_head *element;
@@ -1116,17 +862,29 @@ 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 = iwl4965_rates[i].next_ieee) {
                if (rate_mask & (1 << i))
                        return iwl4965_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)
@@ -1144,16 +902,7 @@ 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);
 
@@ -1171,15 +920,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
  *
@@ -1209,6 +949,91 @@ static u16 iwl4965_supported_rate_to_ie(u8 *ie, u16 supported_rate,
        return ret_rates;
 }
 
+#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");
+}
+
+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
  */
@@ -1220,10 +1045,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 */
@@ -1306,24 +1129,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,215 +1194,37 @@ 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 iwl4965_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
 {
-       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);
+       /* Filter incoming packets to determine if they are targeted toward
+        * this network, discarding packets coming from ourselves */
+       switch (priv->iw_mode) {
+       case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source    | BSSID */
+               /* packets from our adapter are dropped (echo) */
+               if (!compare_ether_addr(header->addr2, priv->mac_addr))
+                       return 0;
+               /* {broad,multi}cast packets to our IBSS go through */
+               if (is_multicast_ether_addr(header->addr1))
+                       return !compare_ether_addr(header->addr3, priv->bssid);
+               /* packets to our adapter go through */
+               return !compare_ether_addr(header->addr1, priv->mac_addr);
+       case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */
+               /* packets from our adapter are dropped (echo) */
+               if (!compare_ether_addr(header->addr3, priv->mac_addr))
+                       return 0;
+               /* {broad,multi}cast packets to our BSS go through */
+               if (is_multicast_ether_addr(header->addr1))
+                       return !compare_ether_addr(header->addr2, priv->bssid);
+               /* packets to our adapter go through */
+               return !compare_ether_addr(header->addr1, priv->mac_addr);
+       default:
+               break;
+       }
 
-       memset(pow_data, 0, sizeof(*pow_data));
+       return 1;
+}
 
-       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
-        * this network, discarding packets coming from ourselves */
-       switch (priv->iw_mode) {
-       case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source    | BSSID */
-               /* packets from our adapter are dropped (echo) */
-               if (!compare_ether_addr(header->addr2, priv->mac_addr))
-                       return 0;
-               /* {broad,multi}cast packets to our IBSS go through */
-               if (is_multicast_ether_addr(header->addr1))
-                       return !compare_ether_addr(header->addr3, priv->bssid);
-               /* packets to our adapter go through */
-               return !compare_ether_addr(header->addr1, priv->mac_addr);
-       case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */
-               /* packets from our adapter are dropped (echo) */
-               if (!compare_ether_addr(header->addr3, priv->mac_addr))
-                       return 0;
-               /* {broad,multi}cast packets to our BSS go through */
-               if (is_multicast_ether_addr(header->addr1))
-                       return !compare_ether_addr(header->addr2, priv->bssid);
-               /* packets to our adapter go through */
-               return !compare_ether_addr(header->addr1, priv->mac_addr);
-       default:
-               break;
-       }
-
-       return 1;
-}
-
-#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
 
 static const char *iwl4965_get_tx_fail_reason(u32 status)
 {
@@ -1884,7 +1524,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)
@@ -1932,11 +1572,11 @@ static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
                                      struct sk_buff *skb_frag,
                                      int sta_id)
 {
-       struct iwl4965_hw_key *keyinfo = &priv->stations[sta_id].keyinfo;
+       struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo;
        struct iwl_wep_key *wepkey;
        int keyidx = 0;
 
-       BUG_ON(ctl->key_idx > 3);
+       BUG_ON(ctl->hw_key->hw_key_idx > 3);
 
        switch (keyinfo->alg) {
        case ALG_CCMP:
@@ -1955,11 +1595,11 @@ static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
                break;
 
        case ALG_WEP:
-               wepkey = &priv->wep_keys[ctl->key_idx];
+               wepkey = &priv->wep_keys[ctl->hw_key->hw_key_idx];
                cmd->cmd.tx.sec_ctl = 0;
                if (priv->default_wep_key) {
                        /* the WEP key was sent as static */
-                       keyidx = ctl->key_idx;
+                       keyidx = ctl->hw_key->hw_key_idx;
                        memcpy(&cmd->cmd.tx.key[3], wepkey->key,
                                                        wepkey->key_size);
                        if (wepkey->key_size == WEP_KEY_LEN_128)
@@ -2086,7 +1726,7 @@ static int iwl4965_get_sta_id(struct iwl_priv *priv,
 
        /* 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);
+               sta_id = iwl_find_station(priv, hdr->addr1);
                if (sta_id != IWL_INVALID_STATION)
                        return sta_id;
                return priv->hw_params.bcast_sta_id;
@@ -2094,7 +1734,7 @@ static int iwl4965_get_sta_id(struct iwl_priv *priv,
        /* 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);
+               sta_id = iwl_find_station(priv, hdr->addr1);
                if (sta_id != IWL_INVALID_STATION)
                        return sta_id;
 
@@ -2108,7 +1748,7 @@ static int iwl4965_get_sta_id(struct iwl_priv *priv,
                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));
+               iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
                return priv->hw_params.bcast_sta_id;
 
        default:
@@ -2124,10 +1764,10 @@ 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;
+       struct iwl_tfd_frame *tfd;
        u32 *control_flags;
        int txq_id = ctl->queue;
-       struct iwl4965_tx_queue *txq = NULL;
+       struct iwl_tx_queue *txq = NULL;
        struct iwl4965_queue *q = NULL;
        dma_addr_t phys_addr;
        dma_addr_t txcmd_phys;
@@ -2196,7 +1836,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv,
                goto drop;
        }
 
-       IWL_DEBUG_RATE("station Id %d\n", sta_id);
+       IWL_DEBUG_TX("station Id %d\n", sta_id);
 
        qc = ieee80211_get_qos_ctrl(hdr);
        if (qc) {
@@ -2324,10 +1964,10 @@ static int iwl4965_tx_skb(struct iwl_priv *priv,
                txq->need_update = 0;
        }
 
-       iwl_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload,
+       iwl_print_hex_dump(priv, 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,
+       iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr,
                           ieee80211_get_hdrlen(fc));
 
        /* Set up entry for this TFD in Tx byte-count array */
@@ -2367,7 +2007,7 @@ static void iwl4965_set_rate(struct iwl_priv *priv)
        struct ieee80211_rate *rate;
        int i;
 
-       hw = iwl4965_get_hw_mode(priv, priv->band);
+       hw = iwl_get_hw_mode(priv, priv->band);
        if (!hw) {
                IWL_ERROR("Failed to set rate: unable to get hw mode\n");
                return;
@@ -2466,45 +2106,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 +2230,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 +2275,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;
@@ -2710,8 +2311,6 @@ static void iwl4965_txstatus_to_ieee(struct iwl_priv *priv,
 
        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,
@@ -2732,7 +2331,7 @@ static void iwl4965_txstatus_to_ieee(struct iwl_priv *priv,
  */
 int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
 {
-       struct iwl4965_tx_queue *txq = &priv->txq[txq_id];
+       struct iwl_tx_queue *txq = &priv->txq[txq_id];
        struct iwl4965_queue *q = &txq->q;
        int nfreed = 0;
 
@@ -2749,7 +2348,7 @@ int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
                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);
+                       iwl_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);
@@ -2758,12 +2357,6 @@ int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
                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;
 }
 
@@ -2788,7 +2381,7 @@ static inline int iwl4965_get_ra_sta_id(struct iwl_priv *priv,
                return IWL_AP_ID;
        else {
                u8 *da = ieee80211_get_DA(hdr);
-               return iwl4965_hw_find_station(priv, da);
+               return iwl_find_station(priv, da);
        }
 }
 
@@ -2813,7 +2406,7 @@ static inline u32 iwl4965_get_scd_ssn(struct iwl4965_tx_resp *tx_resp)
  * 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 iwl_ht_agg *agg,
                                      struct iwl4965_tx_resp_agg *tx_resp,
                                      u16 start_idx)
 {
@@ -2847,8 +2440,6 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
 
                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;
@@ -2934,13 +2525,13 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
  * 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 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;
        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 iwl_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);
@@ -2973,7 +2564,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
 
        if (txq->sched_retry) {
                const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp);
-               struct iwl4965_ht_agg *agg = NULL;
+               struct iwl_ht_agg *agg = NULL;
 
                if (!qc)
                        return;
@@ -2989,7 +2580,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
                }
 
                if (txq->q.read_ptr != (scd_ssn & 0xff)) {
-                       int freed;
+                       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);
@@ -2998,9 +2589,15 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
 
                        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);
-
+                           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);
+                       }
                        iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id);
                }
        } else {
@@ -3008,9 +2605,6 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
        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),
@@ -3022,20 +2616,17 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
                     tx_resp->failure_frame);
 
        IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
+#ifdef CONFIG_IWL4965_HT
        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)
+                       (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 */
 
@@ -3045,9 +2636,9 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
 
 
 static void iwl4965_rx_reply_alive(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_alive_resp *palive;
        struct delayed_work *pwork;
 
@@ -3081,18 +2672,18 @@ static void iwl4965_rx_reply_alive(struct iwl_priv *priv,
 }
 
 static void iwl4965_rx_reply_add_sta(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_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,9 +2696,9 @@ 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 iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
        struct iwl4965_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",
@@ -3117,15 +2708,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 +2726,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 +2737,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)
@@ -3181,10 +2772,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 +2795,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 +2808,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 +2825,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 +2850,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 +2908,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;
 
@@ -3425,7 +3016,7 @@ static void iwl4965_setup_rx_handlers(struct iwl_priv *priv)
        priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx;
 
        /* Set up hardware specific Rx handlers */
-       iwl4965_hw_rx_handler_setup(priv);
+       priv->cfg->ops->lib->rx_handler_setup(priv);
 }
 
 /**
@@ -3437,9 +3028,9 @@ static void iwl4965_setup_rx_handlers(struct iwl_priv *priv)
  * if the callback returns 1
  */
 static void iwl4965_tx_cmd_complete(struct iwl_priv *priv,
-                               struct iwl4965_rx_mem_buffer *rxb)
+                                   struct iwl_rx_mem_buffer *rxb)
 {
-       struct iwl4965_rx_packet *pkt = (struct iwl4965_rx_packet *)rxb->skb->data;
+       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);
@@ -3474,348 +3065,131 @@ static void iwl4965_tx_cmd_complete(struct iwl_priv *priv,
        }
 }
 
-/************************** 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)
+ * this should be called while priv->lock is locked
+*/
+static void __iwl_rx_replenish(struct iwl_priv *priv)
 {
-       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;
+       iwl_rx_allocate(priv);
+       iwl_rx_queue_restock(priv);
 }
 
+
 /**
- * iwl4965_rx_queue_update_write_ptr - Update the write pointer for the RX queue
+ * 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.
  */
-int iwl4965_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl4965_rx_queue *q)
+void iwl_rx_handle(struct iwl_priv *priv)
 {
-       u32 reg = 0;
-       int rc = 0;
+       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;
+       u8 fill_rx = 0;
+       u32 count = 8;
 
-       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;
+       /* uCode's read index (stored in shared DRAM) indicates the last Rx
+        * buffer that the driver may process (last buffer filled by ucode). */
+       r = priv->cfg->ops->lib->shared_mem_rx_idx(priv);
+       i = rxq->read;
 
-               /* Device expects a multiple of 8 */
-               iwl_write_direct32(priv, FH_RSCSR_CHNL0_WPTR,
-                                    q->write & ~0x7);
-               iwl_release_nic_access(priv);
+       /* Rx interrupt, but nothing sent from uCode */
+       if (i == r)
+               IWL_DEBUG(IWL_DL_RX, "r = %d, i = %d\n", r, i);
 
-       /* Else device is assumed to be awake */
-       } else
-               /* Device expects a multiple of 8 */
-               iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7);
+       if (iwl_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2))
+               fill_rx = 1;
 
+       while (i != r) {
+               rxb = rxq->queue[i];
 
-       q->need_update = 0;
+               /* If an RXB doesn't have a Rx queue slot associated with it,
+                * then a bug has been introduced in the queue refilling
+                * routines -- catch it here */
+               BUG_ON(rxb == NULL);
 
- exit_unlock:
-       spin_unlock_irqrestore(&q->lock, flags);
-       return rc;
-}
+               rxq->queue[i] = NULL;
 
-/**
- * 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));
-}
+               pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
+                                           priv->hw_params.rx_buf_size,
+                                           PCI_DMA_FROMDEVICE);
+               pkt = (struct iwl_rx_packet *)rxb->skb->data;
 
+               /* Reclaim a command buffer only if this packet is a response
+                *   to a (driver-originated) command.
+                * If the packet (e.g. Rx frame) originated from uCode,
+                *   there is no command buffer to reclaim.
+                * Ucode should set SEQ_RX_FRAME bit if ucode-originated,
+                *   but apparently a few don't get set; catch them here. */
+               reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
+                       (pkt->hdr.cmd != REPLY_RX_PHY_CMD) &&
+                       (pkt->hdr.cmd != REPLY_RX) &&
+                       (pkt->hdr.cmd != REPLY_COMPRESSED_BA) &&
+                       (pkt->hdr.cmd != STATISTICS_NOTIFICATION) &&
+                       (pkt->hdr.cmd != REPLY_TX);
 
-/**
- * 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);
+               /* Based on type of command response or notification,
+                *   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_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_RX,
+                               "r %d i %d No handler needed for %s, 0x%02x\n",
+                               r, i, get_cmd_string(pkt->hdr.cmd),
+                               pkt->hdr.cmd);
+               }
 
-               /* 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 (reclaim) {
+                       /* Invoke any callbacks, transfer the skb to caller, and
+                        * 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);
+                       else
+                               IWL_WARNING("Claim null rxb?\n");
+               }
 
+               /* For now we just don't re-use anything.  We can tweak this
+                * later to try and re-use notification packets and SKBs that
+                * fail to Rx correctly */
+               if (rxb->skb != NULL) {
+                       priv->alloc_rxb_skb--;
+                       dev_kfree_skb_any(rxb->skb);
+                       rxb->skb = NULL;
+               }
 
-       /* 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)) {
+               pci_unmap_single(priv->pci_dev, rxb->dma_addr,
+                                priv->hw_params.rx_buf_size,
+                                PCI_DMA_FROMDEVICE);
                spin_lock_irqsave(&rxq->lock, flags);
-               rxq->need_update = 1;
+               list_add_tail(&rxb->list, &priv->rxq.rx_used);
                spin_unlock_irqrestore(&rxq->lock, flags);
-               rc = iwl4965_rx_queue_update_write_ptr(priv, rxq);
-               if (rc)
-                       return rc;
+               i = (i + 1) & RX_QUEUE_MASK;
+               /* If there are a lot of unused frames,
+                * restock the Rx queue so ucode wont assert. */
+               if (fill_rx) {
+                       count++;
+                       if (count >= 8) {
+                               priv->rxq.read = i;
+                               __iwl_rx_replenish(priv);
+                               count = 0;
+                       }
+               }
        }
 
-       return 0;
+       /* Backtrack one entry */
+       priv->rxq.read = i;
+       iwl_rx_queue_restock(priv);
 }
-
-/**
- * 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);
-}
-
-/*
- * this should be called while priv->lock is locked
-*/
-static void __iwl4965_rx_replenish(void *data)
-{
-       struct iwl_priv *priv = data;
-
-       iwl4965_rx_allocate(priv);
-       iwl4965_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 */
@@ -3894,128 +3268,11 @@ int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm)
        return sig_qual;
 }
 
-/**
- * iwl4965_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)
-{
-       struct iwl4965_rx_mem_buffer *rxb;
-       struct iwl4965_rx_packet *pkt;
-       struct iwl4965_rx_queue *rxq = &priv->rxq;
-       u32 r, i;
-       int reclaim;
-       unsigned long flags;
-       u8 fill_rx = 0;
-       u32 count = 8;
-
-       /* 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);
-       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);
-
-       if (iwl4965_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2))
-               fill_rx = 1;
-
-       while (i != r) {
-               rxb = rxq->queue[i];
-
-               /* If an RXB doesn't have a Rx queue slot associated with it,
-                * then a bug has been introduced in the queue refilling
-                * routines -- catch it here */
-               BUG_ON(rxb == NULL);
-
-               rxq->queue[i] = NULL;
-
-               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;
-
-               /* Reclaim a command buffer only if this packet is a response
-                *   to a (driver-originated) command.
-                * If the packet (e.g. Rx frame) originated from uCode,
-                *   there is no command buffer to reclaim.
-                * Ucode should set SEQ_RX_FRAME bit if ucode-originated,
-                *   but apparently a few don't get set; catch them here. */
-               reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
-                       (pkt->hdr.cmd != REPLY_RX_PHY_CMD) &&
-                       (pkt->hdr.cmd != REPLY_RX) &&
-                       (pkt->hdr.cmd != REPLY_COMPRESSED_BA) &&
-                       (pkt->hdr.cmd != STATISTICS_NOTIFICATION) &&
-                       (pkt->hdr.cmd != REPLY_TX);
-
-               /* Based on type of command response or notification,
-                *   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);
-                       priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
-               } else {
-                       /* No handling needed */
-                       IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
-                               "r %d i %d No handler needed for %s, 0x%02x\n",
-                               r, i, get_cmd_string(pkt->hdr.cmd),
-                               pkt->hdr.cmd);
-               }
-
-               if (reclaim) {
-                       /* Invoke any callbacks, transfer the skb to caller, and
-                        * 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);
-                       else
-                               IWL_WARNING("Claim null rxb?\n");
-               }
-
-               /* For now we just don't re-use anything.  We can tweak this
-                * later to try and re-use notification packets and SKBs that
-                * fail to Rx correctly */
-               if (rxb->skb != NULL) {
-                       priv->alloc_rxb_skb--;
-                       dev_kfree_skb_any(rxb->skb);
-                       rxb->skb = NULL;
-               }
-
-               pci_unmap_single(priv->pci_dev, rxb->dma_addr,
-                                priv->hw_params.rx_buf_size,
-                                PCI_DMA_FROMDEVICE);
-               spin_lock_irqsave(&rxq->lock, flags);
-               list_add_tail(&rxb->list, &priv->rxq.rx_used);
-               spin_unlock_irqrestore(&rxq->lock, flags);
-               i = (i + 1) & RX_QUEUE_MASK;
-               /* If there are a lot of unused frames,
-                * restock the Rx queue so ucode wont assert. */
-               if (fill_rx) {
-                       count++;
-                       if (count >= 8) {
-                               priv->rxq.read = i;
-                               __iwl4965_rx_replenish(priv);
-                               count = 0;
-                       }
-               }
-       }
-
-       /* 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)
+                                 struct iwl_tx_queue *txq)
 {
        u32 reg = 0;
        int rc = 0;
@@ -4058,12 +3315,13 @@ static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv,
 }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-static void iwl4965_print_rx_config_cmd(struct iwl4965_rxon_cmd *rxon)
+static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv)
 {
+       struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon;
        DECLARE_MAC_BUF(mac);
 
        IWL_DEBUG_RADIO("RX CONFIG:\n");
-       iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
+       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",
@@ -4289,10 +3547,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) {
+       if (priv->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);
+               iwl4965_print_rx_config_cmd(priv);
        }
 #endif
 
@@ -4303,7 +3561,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 +3569,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);
        }
 }
 
@@ -4356,7 +3615,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 +3649,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 +3670,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,7 +3702,7 @@ 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);
+               iwl_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]);
@@ -4459,7 +3717,7 @@ 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);
        }
 
@@ -4483,7 +3741,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 +3878,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,352 +3910,52 @@ 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);
-
-               /* Set txpower levels to defaults */
-               scan_ch->tpc.dsp_atten = 110;
-               /* scan_pwr_info->tpc.dsp_atten; */
-
-               /*scan_pwr_info->tpc.tx_gain; */
-               if (band == IEEE80211_BAND_5GHZ)
-                       scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3;
-               else {
-                       scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3));
-                       /* NOTE: if we were doing 6Mb OFDM for scans we'd use
-                        * power level:
-                        * scan_ch->tpc.tx_gain = ((1 << 5) | (2 << 3)) | 3;
-                        */
-               }
-
-               IWL_DEBUG_SCAN("Scanning %d [%s %d]\n",
-                              scan_ch->channel,
-                              (scan_ch->type & 1) ? "ACTIVE" : "PASSIVE",
-                              (scan_ch->type & 1) ?
-                              active_dwell : passive_dwell);
-
-               scan_ch++;
-               added++;
-       }
-
-       IWL_DEBUG_SCAN("total channels to scan %d \n", added);
-       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
- *
- ******************************************************************************/
-
-static void iwl4965_dealloc_ucode_pci(struct iwl_priv *priv)
-{
-       iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code);
-       iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data);
-       iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
-       iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init);
-       iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data);
-       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;
+               scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
 
-       /* 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;
-       }
+               /* Set txpower levels to defaults */
+               scan_ch->tpc.dsp_atten = 110;
+               /* scan_pwr_info->tpc.dsp_atten; */
 
-       /* 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;
-       }
+               /*scan_pwr_info->tpc.tx_gain; */
+               if (band == IEEE80211_BAND_5GHZ)
+                       scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3;
+               else {
+                       scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3));
+                       /* NOTE: if we were doing 6Mb OFDM for scans we'd use
+                        * power level:
+                        * scan_ch->tpc.tx_gain = ((1 << 5) | (2 << 3)) | 3;
+                        */
+               }
 
-       /* 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_DEBUG_SCAN("Scanning %d [%s %d]\n",
+                              scan_ch->channel,
+                              (scan_ch->type & 1) ? "ACTIVE" : "PASSIVE",
+                              (scan_ch->type & 1) ?
+                              active_dwell : passive_dwell);
+
+               scan_ch++;
+               added++;
        }
 
-       IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
+       IWL_DEBUG_SCAN("total channels to scan %d \n", added);
+       return added;
+}
 
-       /* 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);
+/******************************************************************************
+ *
+ * uCode download functions
+ *
+ ******************************************************************************/
 
-       return rc;
+static void iwl4965_dealloc_ucode_pci(struct iwl_priv *priv)
+{
+       iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code);
+       iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data);
+       iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
+       iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init);
+       iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data);
+       iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot);
 }
 
 static void iwl4965_nic_start(struct iwl_priv *priv)
@@ -5075,34 +4033,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);
@@ -5203,105 +4161,6 @@ static int iwl4965_read_ucode(struct iwl_priv *priv)
        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;
-       }
-
-       /* 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;
-       }
-
-       /* 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;
-
- restart:
-       queue_work(priv->workqueue, &priv->restart);
-}
-
-
 /**
  * iwl4965_alive_start - called after REPLY_ALIVE notification received
  *                   from protocol/runtime uCode (initialization uCode's
@@ -5323,7 +4182,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");
@@ -5353,8 +4212,6 @@ static void iwl4965_alive_start(struct iwl_priv *priv)
        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);
@@ -5485,6 +4342,7 @@ static void __iwl4965_down(struct iwl_priv *priv)
        iwl4965_hw_nic_stop_master(priv);
        iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
        iwl4965_hw_nic_reset(priv);
+       priv->cfg->ops->lib->free_shared_mem(priv);
 
  exit:
        memset(&priv->card_alive, 0, sizeof(struct iwl4965_alive_resp));
@@ -5546,7 +4404,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;
@@ -5622,7 +4486,7 @@ 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);
 }
 
@@ -5651,7 +4515,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 +4538,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 +4569,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 +4769,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 +4825,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 +4873,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",
@@ -6040,17 +4924,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 +4972,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;
@@ -6338,7 +5221,7 @@ 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,
+       iwl_set_rxon_channel(priv, conf->channel->band,
                ieee80211_frequency_to_channel(conf->channel->center_freq));
 
        iwl4965_set_flags_for_phymode(priv, conf->channel->band);
@@ -6410,7 +5293,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);
@@ -6562,7 +5445,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 +5490,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 +5520,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 +5620,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 +5648,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 +5667,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 +5676,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));
@@ -6873,7 +5713,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 +5726,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,7 +5782,7 @@ 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 iwl_tx_queue *txq;
        struct iwl4965_queue *q;
        unsigned long flags;
 
@@ -6960,9 +5800,9 @@ static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw,
                q = &txq->q;
                avail = iwl4965_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 +5815,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 +5826,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 +5850,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 +5887,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) {
 
@@ -7089,7 +5937,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 +5962,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 +5982,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 iwl4965_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 +6245,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 +6279,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 +6297,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 +6357,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)
 {
@@ -7590,6 +6416,7 @@ 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);
@@ -7613,7 +6440,6 @@ 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,
@@ -7629,6 +6455,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 +6508,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 +6529,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 +6543,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,30 +6581,30 @@ 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;
        }
+       err = iwl_eeprom_check_version(priv);
+       if (err)
+               goto out_iounmap;
+
        /* MAC Address location in EEPROM same for 3945/4965 */
        iwl_eeprom_get_mac(priv, priv->mac_addr);
        IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr));
@@ -7778,7 +6616,7 @@ 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;
        }
 
        /*******************
@@ -7787,7 +6625,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 
        err = iwl_setup(priv);
        if (err)
-               goto out_unset_hw_params;
+               goto out_free_eeprom;
        /* At this point both hw and priv are initialized. */
 
        /**********************************
@@ -7813,7 +6651,7 @@ 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_free_eeprom;
        }
 
        err = iwl_dbgfs_register(priv, DRV_NAME);
@@ -7837,8 +6675,8 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 
  out_remove_sysfs:
        sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
- out_unset_hw_params:
-       iwl4965_unset_hw_params(priv);
+ out_free_eeprom:
+       iwl_eeprom_free(priv);
  out_iounmap:
        pci_iounmap(pdev, priv->hw_base);
  out_pci_release_regions:
@@ -7897,11 +6735,11 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
        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); */
@@ -7919,7 +6757,7 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
        pci_set_drvdata(pdev, NULL);
 
        iwl_free_channel_map(priv);
-       iwl4965_free_geos(priv);
+       iwlcore_free_geos(priv);
 
        if (priv->ibss_beacon)
                dev_kfree_skb(priv->ibss_beacon);
@@ -7969,6 +6807,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,18 +6845,11 @@ 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:
@@ -8023,9 +6859,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 6328b95..c2dd43e 100644 (file)
@@ -696,38 +696,6 @@ static int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
        return 0;
 }
 
-/**
- *  @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)
-{
-       struct cmd_ds_802_11_data_rate cmd;
-       int ret = -1;
-
-       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;
-
-       lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof (cmd));
-
-       ret = (int) lbs_fw_index_to_data_rate(cmd.rates[0]);
-       lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", ret);
-
-out:
-       lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
-       return ret;
-}
-
 /**
  *  @brief Set the data rate
  *
index 3dfc2d4..f4019c2 100644 (file)
@@ -34,7 +34,6 @@ 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);
@@ -44,7 +43,7 @@ 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_inactivity_timeout(struct lbs_private *priv,
                                      uint16_t cmd_action, uint16_t *timeout);
index b652fa3..0632b09 100644 (file)
@@ -64,9 +64,9 @@ void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str);
 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 e1f0660..02e4fb6 100644 (file)
@@ -702,7 +702,7 @@ static int lbs_thread(void *data)
 
                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);
@@ -890,7 +890,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 +906,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 +928,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;
@@ -1156,7 +1145,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 +1157,8 @@ 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);
        destroy_workqueue(priv->work_thread);
 
        if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
@@ -1191,7 +1180,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);
 
@@ -1262,15 +1250,17 @@ 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);
 
@@ -1280,6 +1270,7 @@ int lbs_stop_card(struct lbs_private *priv)
                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 +1281,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);
 
@@ -1533,10 +1524,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);
 }
 
index 06d2c67..c6f27b9 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 63f9bad..9cbef5b 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;
@@ -379,7 +379,7 @@ static void inline p54_wake_free_queues(struct ieee80211_hw *dev)
         * 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);
 }
 
@@ -417,8 +417,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
                        memcpy(&status.control, range->control,
                               sizeof(status.control));
                        kfree(range->control);
-                       priv->tx_stats.data[status.control.queue].len--;
-
+                       priv->tx_stats[status.control.queue].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)
@@ -555,7 +554,7 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
 static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
                  struct ieee80211_tx_control *control)
 {
-       struct ieee80211_tx_queue_stats_data *current_queue;
+       struct ieee80211_tx_queue_stats *current_queue;
        struct p54_common *priv = dev->priv;
        struct p54_control_hdr *hdr;
        struct p54_tx_control_allocdata *txhdr;
@@ -563,7 +562,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
        size_t padding, len;
        u8 rate;
 
-       current_queue = &priv->tx_stats.data[control->queue];
+       current_queue = &priv->tx_stats[control->queue];
        if (unlikely(current_queue->len > current_queue->limit))
                return NETDEV_TX_BUSY;
        current_queue->len++;
@@ -936,7 +935,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 +944,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 +966,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 +1000,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 ab1029e..0ace761 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 560b9c7..afa565c 100644 (file)
@@ -1055,11 +1055,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 +1071,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);
 }
 
@@ -1120,7 +1117,7 @@ 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;
@@ -1187,19 +1184,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,10 +1361,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);
@@ -1445,8 +1441,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 +1451,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))
@@ -1520,21 +1515,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.
         */
+       rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
        memcpy(priv_tx->data, skb->data, skb->len);
-       rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue);
+       rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
 
        return 0;
 }
index a5ed54b..c06f1b5 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;
 
@@ -1210,11 +1209,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 +1225,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);
 }
 
@@ -1276,7 +1272,7 @@ 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;
@@ -1343,19 +1339,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,10 +1680,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);
@@ -1833,21 +1829,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.
         */
+       rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
        memcpy(priv_tx->data, skb->data, skb->len);
-       rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue);
+       rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
 
        return 0;
 }
index fdbd0ef..88bafdf 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)
@@ -1094,11 +1094,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);
@@ -1587,10 +1587,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);
@@ -1720,12 +1720,6 @@ 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);
 
        /*
@@ -1757,7 +1751,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw,
        /*
         * Enable beacon generation.
         */
-       rt2500usb_kick_tx_queue(rt2x00dev, control->queue);
+       rt2500usb_kick_tx_queue(rt2x00dev, QID_BEACON);
 
        return 0;
 }
index 57bdc15..79bd9c9 100644 (file)
@@ -44,7 +44,7 @@
 /*
  * Module information.
  */
-#define DRV_VERSION    "2.1.4"
+#define DRV_VERSION    "2.1.5"
 #define DRV_PROJECT    "http://rt2x00.serialmonkey.com"
 
 /*
@@ -404,7 +404,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
@@ -548,7 +548,7 @@ struct rt2x00lib_ops {
        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
@@ -621,7 +621,6 @@ enum rt2x00_flags {
        /*
         * Driver features
         */
-       DRIVER_SUPPORT_MIXED_INTERFACES,
        DRIVER_REQUIRE_FIRMWARE,
        DRIVER_REQUIRE_BEACON_GUARD,
        DRIVER_REQUIRE_ATIM_QUEUE,
@@ -928,17 +927,16 @@ static inline u16 get_duration_res(const unsigned int size, const u8 rate)
 }
 
 /**
- * rt2x00queue_get_queue - Convert mac80211 queue index to rt2x00 queue
+ * 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,
@@ -947,7 +945,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
@@ -999,7 +997,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 b22c027..3a49c25 100644 (file)
@@ -525,9 +525,6 @@ void rt2x00lib_txdone(struct queue_entry *entry,
                        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)
                        rt2x00dev->low_level_stats.dot11RTSSuccessCount++;
@@ -603,9 +600,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;
 
@@ -687,8 +684,7 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev,
         * 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))
+       if (txdesc.queue == QID_BEACON || is_probe_resp(frame_control))
                __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc.flags);
 
        /*
index c206b50..767e0ff 100644 (file)
@@ -81,6 +81,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
+       enum data_queue_qid qid = mac80211_queue_to_qid(control->queue);
        struct data_queue *queue;
        struct skb_frame_desc *skbdesc;
        u16 frame_control;
@@ -101,14 +102,13 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
         */
        if (control->flags & IEEE80211_TXCTL_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;
        }
@@ -118,11 +118,16 @@ 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))) {
+                              IEEE80211_TXCTL_USE_CTS_PROTECT)) &&
+           !rt2x00dev->ops->hw->set_rts_threshold) {
                if (rt2x00queue_available(queue) <= 1) {
                        ieee80211_stop_queue(rt2x00dev->hw, control->queue);
                        return NETDEV_TX_BUSY;
@@ -149,7 +154,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
                ieee80211_stop_queue(rt2x00dev->hw, control->queue);
 
        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;
 }
@@ -182,8 +187,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;
 
@@ -196,13 +200,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;
 
        /*
@@ -454,9 +457,9 @@ int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw,
        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;
+               stats[i].len = rt2x00dev->tx[i].length;
+               stats[i].limit = rt2x00dev->tx[i].limit;
+               stats[i].count = rt2x00dev->tx[i].count;
        }
 
        return 0;
@@ -514,7 +517,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 971af25..c17078e 100644 (file)
@@ -53,7 +53,7 @@ int rt2x00pci_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;
        }
 
index 9d1cdb9..2b0ef17 100644 (file)
@@ -98,8 +98,9 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
  * struct queue_entry_priv_pci_rx: Per RX 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.
+ * @data_dma: DMA pointer to &data.
  */
 struct queue_entry_priv_pci_rx {
        __le32 *desc;
@@ -113,8 +114,9 @@ struct queue_entry_priv_pci_rx {
  * struct queue_entry_priv_pci_tx: Per TX 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.
+ * @data_dma: DMA pointer to &data.
  * @control: mac80211 control structure used to transmit data.
  */
 struct queue_entry_priv_pci_tx {
index 659e9f4..e5b861f 100644 (file)
@@ -30,7 +30,7 @@
 #include "rt2x00lib.h"
 
 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);
 
@@ -40,9 +40,9 @@ struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
        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;
index 7027c9f..d1707a7 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,22 +75,22 @@ enum data_queue_qid {
        QID_MGMT = 13,
        QID_RX = 14,
        QID_OTHER = 15,
+       QID_BEACON,
+       QID_ATIM,
 };
 
 /**
- * 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)
+ * mac80211_queue_to_qid - Convert mac80211 queue to rt2x00 qid
+ * @queue: mac80211 queue.
  */
-enum rt2x00_bcn_queue {
-       RT2X00_BCN_QUEUE_BEACON = 100,
-       RT2X00_BCN_QUEUE_ATIM = 101,
-};
+static inline enum data_queue_qid mac80211_queue_to_qid(unsigned int queue)
+{
+       /* Regular TX queues are mapped directly */
+       if (queue < 4)
+               return queue;
+       WARN_ON(1);
+       return QID_OTHER;
+}
 
 /**
  * enum skb_frame_desc_flags: Flags for &struct skb_frame_desc
@@ -105,7 +116,6 @@ enum skb_frame_desc_flags {
  *     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 {
@@ -240,7 +250,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,
index 5a33167..98aafc2 100644 (file)
@@ -186,7 +186,7 @@ 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;
        }
 
@@ -344,7 +344,7 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
        struct data_queue *queue;
        unsigned int i;
 
-       rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0x0000, 0x0000,
+       rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 00,
                                    REGISTER_TIMEOUT);
 
        /*
index 11e5518..4da9eb3 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));
 }
 
 /*
index 14bc7b2..edddbf3 100644 (file)
@@ -1591,11 +1591,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 +1613,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);
 }
 
@@ -2249,10 +2245,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);
@@ -2399,25 +2394,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.
         */
+       rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
        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;
 }
index da19a3a..51c5575 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;
        }
@@ -1331,11 +1330,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;
 
        /*
@@ -1831,10 +1830,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);
@@ -1966,7 +1964,6 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
        struct rt2x00_intf *intf = vif_to_intf(control->vif);
        struct skb_frame_desc *skbdesc;
        unsigned int beacon_base;
-       unsigned int timeout;
        u32 reg;
 
        if (unlikely(!intf->beacon))
@@ -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.
         */
+       rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
        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;
 }
index c181f23..c220998 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;
@@ -894,9 +894,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 9223ada..2351445 100644 (file)
@@ -271,8 +271,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 +750,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 69c45ca..0c73673 100644 (file)
@@ -638,7 +638,7 @@ static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr,
 
                        memset(&status, 0, sizeof(status));
                        status.flags = IEEE80211_TX_STATUS_ACK;
-                       status.ack_signal = stats->ssi;
+                       status.ack_signal = stats->signal;
                        __skb_unlink(skb, q);
                        tx_status(hw, skb, &status, 1);
                        goto out;
@@ -691,8 +691,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 +751,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 +782,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 +943,18 @@ 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 ieee80211_tx_control *ctl)
+{
+       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 +965,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 +997,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 57c4ccf..f883dcf 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");
index 0b5e03e..a9102bc 100644 (file)
@@ -552,16 +552,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 +578,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 +597,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 b0c916d..2bc6fa4 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 529816b..b31399e 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 6512d85..3780592 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 633ed4d..a85bda6 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 dae3f9e..2f98539 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;
@@ -286,8 +258,17 @@ enum mac80211_tx_control_flags {
 
 /* 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). */
-
+ * the hardware to use given values (depending on what is supported).
+ *
+ * NOTE: Be careful with using the pointers outside of the ieee80211_ops->tx()
+ * context (i.e. when defering the work to a workqueue).
+ * The vif pointer is valid until the it has been removed with the
+ * ieee80211_ops->remove_interface() callback funtion.
+ * The hw_key pointer is valid until it has been removed with the
+ * ieee80211_ops->set_key() callback function.
+ * The tx_rate and alt_retry_rate pointers are valid until the phy is
+ * deregistered.
+ */
 struct ieee80211_tx_control {
        struct ieee80211_vif *vif;
        struct ieee80211_rate *tx_rate;
@@ -298,9 +279,11 @@ struct ieee80211_tx_control {
        /* retry rate for the last retries */
        struct ieee80211_rate *alt_retry_rate;
 
+       /* Key used for hardware encryption
+        * NULL if IEEE80211_TXCTL_DO_NOT_ENCRYPT is set */
+       struct ieee80211_key_conf *hw_key;
+
        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 */
@@ -308,7 +291,7 @@ struct ieee80211_tx_control {
                                 * 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;
+       u16 queue;              /* hardware queue to use for this frame;
                                 * 0 = highest, hw->queues-1 = lowest */
        u16 aid;                /* Station AID */
        int type;       /* internal */
@@ -353,13 +336,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,9 +354,9 @@ 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;
@@ -409,9 +395,8 @@ enum ieee80211_tx_status_flags {
  *     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
+ * @ack_signal: signal strength of the ACK frame either in dBm, dB or unspec
+ *     depending on hardware capabilites flags @IEEE80211_HW_SIGNAL_*
  */
 struct ieee80211_tx_status {
        struct ieee80211_tx_control control;
@@ -421,8 +406,6 @@ struct ieee80211_tx_status {
        u8 ampdu_ack_len;
        u64 ampdu_ack_map;
        int ack_signal;
-       int queue_length;
-       int queue_number;
 };
 
 /**
@@ -610,11 +593,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 +707,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 +733,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 +767,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 +797,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;
 };
 
 /**
@@ -1063,15 +1073,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
@@ -1145,7 +1153,7 @@ 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);
index aa540e6..8df751b 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 90b1e8d..5672d48 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 0ce0443..e111517 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;
@@ -938,6 +939,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.
@@ -1542,6 +1544,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? */
@@ -1651,6 +1654,7 @@ struct sctp_association {
 
        /* SACK delay timeout */
        unsigned long sackdelay;
+       __u32 sackfreq;
 
 
        unsigned long timeouts[SCTP_NUM_TIMEOUT_TYPES];
index 9619b9d..f205b10 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 11105bc..9923e41 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 bf77873..626c779 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 bdd7c35..a471167 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 255c00f..fa0f571 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 c11b554..0243cb4 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 90e2177..dccd737 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 cf857c4..ca32ddb 100644 (file)
@@ -606,6 +606,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)
@@ -652,19 +654,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 5fc8010..a570e2a 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 200ee1e..69dbc34 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 d8b0260..d996547 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 623489a..822606b 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 cd6ce6a..be1cb89 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 4342cba..2a61158 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 af5cb53..86d8836 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 11700a4..a34da49 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 2bda3ba..3781481 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 2de3c46..bf268b3 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 798cabc..9391a69 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 3de6ffd..6b8f058 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 3804dcb..5c99274 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 59f1691..4d4c2df 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 885f190..8cd0f14 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 699d97b..3cef80d 100644 (file)
@@ -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 1cccbfd..d20d90e 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 e3326d0..3ae5493 100644 (file)
@@ -528,7 +528,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 6d47a1d..a2cc028 100644 (file)
@@ -63,8 +63,8 @@ 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);
@@ -74,14 +74,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 +124,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 +264,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 +273,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 c7314bf..ed0d9b3 100644 (file)
@@ -82,7 +82,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;
@@ -610,8 +610,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 state[IEEE80211_MAX_QUEUES + IEEE80211_MAX_AMPDU_QUEUES];
+       struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_QUEUES + IEEE80211_MAX_AMPDU_QUEUES];
        struct tasklet_struct tx_pending_tasklet;
 
        /* number of interfaces with corresponding IFF_ flags */
@@ -705,8 +705,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 +762,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;
@@ -919,9 +915,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 +936,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 06e88a5..3c64e42 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 (sdata->local->hw.queues >= 4)
+                       ifsta->flags |= IEEE80211_STA_WMM_ENABLED;
 
                msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev);
                sdata->bss = &msdata->u.ap;
index 150d66d..d4893bd 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 915afad..3601636 100644 (file)
@@ -346,6 +346,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 +386,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);
        }
@@ -588,7 +589,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
                return -ENOENT;
        }
 
-       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) {
@@ -691,7 +692,7 @@ start_ba_err:
        spin_unlock_bh(&local->mdev->queue_lock);
        ret = -EBUSY;
 start_ba_exit:
-       spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+       spin_unlock_bh(&sta->lock);
        rcu_read_unlock();
        return ret;
 }
@@ -719,7 +720,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;
@@ -749,7 +750,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;
 }
@@ -778,12 +779,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;
        }
@@ -796,7 +797,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);
@@ -830,10 +831,10 @@ 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);
+       spin_lock_bh(&sta->lock);
        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);
+               spin_unlock_bh(&sta->lock);
                rcu_read_unlock();
                return;
        }
@@ -860,7 +861,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
        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();
 }
@@ -1315,7 +1316,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
         * packet. If the STA went to power save mode, this will happen
         * 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:
@@ -1347,7 +1348,7 @@ 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);
@@ -1355,7 +1356,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
                return;
        }
 
-       if (!(sta->flags & WLAN_STA_PS) &&
+       if (!test_sta_flags(sta, WLAN_STA_PS) &&
            !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) {
                /* Software retry the packet once */
                status->control.flags |= IEEE80211_TXCTL_REQUEUE;
@@ -1370,7 +1371,7 @@ 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);
 }
 
@@ -1399,7 +1400,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
                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.
@@ -1482,7 +1483,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));
@@ -1701,13 +1702,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);
@@ -1745,6 +1746,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                goto fail_wep;
        }
 
+       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;
+
        ieee80211_install_qdisc(local->mdev);
 
        /* add one default STA interface */
index af0cd1e..7fa149e 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 37f0c2b..9efeb1f 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 7cfd12e..3f7f92a 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;
                }
 
@@ -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,8 +812,10 @@ 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) {
+       if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) &&
+           sband->ht_info.ht_supported) {
                __le16 tmp = cpu_to_le16(sband->ht_info.cap);
                pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2);
                *pos++ = WLAN_EID_HT_CAPABILITY;
@@ -1141,8 +1134,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 +1183,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 +1284,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 +1351,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 +1383,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 +1394,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 +1418,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 +1426,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 +1445,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 +1496,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 +1583,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 +1623,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 +1636,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 +1649,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 verious sta_info are needed here, so init
@@ -1848,9 +1838,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 +2002,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 +2027,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 +2072,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 +2086,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);
@@ -2682,9 +2672,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 +2869,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 +3466,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)
@@ -3556,10 +3544,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++) {
@@ -4109,8 +4099,8 @@ ieee80211_sta_scan_result(struct net_device *dev,
 
        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,
@@ -4242,6 +4232,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;
@@ -4259,9 +4250,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;
@@ -4285,7 +4276,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 1958bfb..fa68305 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. */
@@ -484,7 +550,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 +701,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);
@@ -657,7 +722,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);
@@ -725,16 +790,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 +1054,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 +1117,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 "
index 7d4fe4a..baf5e47 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] = local->hw.queues + local->hw.ampdu_queues;
                /* 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);
index f8c95bc..e89cc16 100644 (file)
@@ -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];
@@ -251,7 +250,7 @@ struct sta_info {
        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 +269,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 +295,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 09093da..a7c3feb 100644 (file)
@@ -8,23 +8,22 @@
  */
 
 #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,53 +60,13 @@ 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)
-{
-       return v >> 16;
-}
-
-
-static inline u16 Lo16(u32 v)
-{
-       return v & 0xffff;
-}
-
-
-static inline u16 RotR1(u16 v)
+static u16 tkipS(u16 val)
 {
-       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);
+       return tkip_sbox[val & 0xff] ^ swab16(tkip_sbox[val >> 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)
@@ -118,23 +77,22 @@ static void tkip_mixing_phase1(const u8 *ta, const u8 *tk, u32 tsc_IV32,
 {
        int i, j;
 
-       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;
        }
 }
 
-
 static void tkip_mixing_phase2(const u16 *p1k, const u8 *tk, u16 tsc_IV16,
                               u8 *rc4key)
 {
@@ -148,31 +106,29 @@ 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). */
@@ -183,14 +139,10 @@ u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key,
        *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;
+       put_unaligned_le32(key->u.tkip.iv32, pos);
+       return pos + 4;
 }
 
-
 void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta,
                                  u16 *phase1key)
 {
@@ -228,10 +180,8 @@ 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",
@@ -281,7 +231,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 +251,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
        {
@@ -409,5 +358,3 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
 
        return res;
 }
-
-
index b7c2ee7..1fa0bb4 100644 (file)
@@ -13,8 +13,8 @@
 #include <linux/crypto.h>
 #include "key.h"
 
-u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key,
-                          u8 iv0, u8 iv1, u8 iv2);
+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,
index 1d7dd54..aecec2a 100644 (file)
@@ -256,7 +256,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) &&
@@ -391,6 +391,7 @@ static ieee80211_tx_result
 ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
 {
        struct sta_info *sta = tx->sta;
+       u32 staflags;
        DECLARE_MAC_BUF(mac);
 
        if (unlikely(!sta ||
@@ -398,8 +399,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))) {
+       staflags = get_sta_flags(sta);
+
+       if (unlikely((staflags & WLAN_STA_PS) &&
+                    !(staflags & WLAN_STA_PSPOLL))) {
                struct ieee80211_tx_packet_data *pkt_data;
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
                printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries "
@@ -430,13 +433,13 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
                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;
 }
@@ -697,7 +700,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
        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->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) {
                tx->control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
        }
 
@@ -1025,10 +1028,8 @@ __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) {
+       else if (test_and_clear_sta_flags(tx->sta, WLAN_STA_CLEAR_PS_FILT))
                control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT;
-               tx->sta->flags &= ~WLAN_STA_CLEAR_PS_FILT;
-       }
 
        hdrlen = ieee80211_get_hdrlen(tx->fc);
        if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) {
@@ -1336,6 +1337,8 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
        pkt_data->ifindex = dev->ifindex;
 
        pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
+       /* Interfaces should always request a status report */
+       pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS;
 
        /*
         * fix up the pointers accounting for the radiotap
@@ -1486,12 +1489,12 @@ 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 && local->hw.queues >= 4) {
                fc |= IEEE80211_STYPE_QOS_DATA;
                hdrlen += 2;
        }
@@ -1617,6 +1620,9 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
        if (ethertype == ETH_P_PAE)
                pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME;
 
+       /* Interfaces should always request a status report */
+       pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS;
+
        skb->dev = local->mdev;
        dev->stats.tx_packets++;
        dev->stats.tx_bytes += skb->len;
index affcecd..3cbae42 100644 (file)
@@ -337,7 +337,7 @@ static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
                if (ieee80211_wep_encrypt(tx->local, skb, tx->key))
                        return -1;
        } else {
-               tx->control->key_idx = tx->key->conf.hw_key_idx;
+               tx->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;
index 363779c..e587172 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 457ebf9..c2e2378 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 |
@@ -995,8 +1007,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 dc1598b..c87baf4 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,14 +147,15 @@ 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_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) {
@@ -158,7 +165,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
                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;
@@ -174,6 +181,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,8 +203,8 @@ 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;
                        } else {
@@ -205,17 +215,6 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
                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;
@@ -270,7 +269,7 @@ 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])) ||
@@ -308,7 +307,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 +325,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 +336,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 +346,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 +354,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 +384,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 +393,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 +405,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 +429,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 +442,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 +468,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 +485,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 +498,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 +516,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 +633,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 +668,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 45709ad..42f3654 100644 (file)
@@ -228,7 +228,7 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx,
                                            0x7f),
                                      (u8) key->u.tkip.iv16);
 
-               tx->control->key_idx = tx->key->conf.hw_key_idx;
+               tx->control->hw_key = &tx->key->conf;
                return 0;
        }
 
@@ -256,7 +256,7 @@ ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx)
            !(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;
+               tx->control->hw_key = &tx->key->conf;
                return TX_CONTINUE;
        }
 
@@ -478,7 +478,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;
+               tx->control->hw_key = &tx->key->conf;
                return 0;
        }
 
@@ -505,7 +505,7 @@ ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx)
            !(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;
+               tx->control->hw_key = &tx->key->conf;
                return TX_CONTINUE;
        }
 
index b4cd2b7..7b79d1e 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 0aba759..5dd8983 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 0ec234b..b8bd9e0 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 23a9f1a..b083312 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 e7e3baf..81600ee 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_delay == 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    = 3;
        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 b4f0525..d8e7916 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 c71337a..ca3544d 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 740aac5..3256bd7 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 5a0e487..a881f92 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 e809d2a..29ecae8 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 c01b085..5ef1bc8 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 5d643e5..faeaf06 100644 (file)
@@ -200,9 +200,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 2a26a16..bd206eb 100644 (file)
@@ -147,9 +147,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); \
@@ -1651,7 +1663,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) {
 
index 696a863..38abeba 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);
@@ -315,9 +317,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 39fd161..aecba5c 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)
 
 /**
index ac7dfdd..892373e 100644 (file)
@@ -1050,15 +1050,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 c39c762..cc51fa4 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 a6a0e99..d154ac2 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 6a7f7b4..c387217 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 598f4d3..34e9a2b 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 2f58064..2c64ad8 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,7 +240,6 @@ 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;
@@ -262,7 +264,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;
 }
 
@@ -778,6 +780,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);
@@ -1053,6 +1056,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 +1064,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 89cbab2..a101de8 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 230f9ca..38f4879 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 8c01ccd..0326d30 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 93a8e67..45d89bf 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 80afacd..f1da0b9 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 28fbd0b..f591871 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 */