Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
Conflicts:
drivers/net/wireless/iwlwifi/iwl-4965-rs.c
drivers/net/wireless/rt2x00/rt61pci.c
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index 239fc42..dc6e474 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -202,7 +202,6 @@
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 @@
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 @@
{
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 @@
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 @@
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;
}
/********************************************************
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
index fae295b..6aca0c6 100644
--- a/drivers/net/3c527.c
+++ b/drivers/net/3c527.c
@@ -158,7 +158,6 @@
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 @@
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 @@
skb=dev_alloc_skb(length+2);
if(skb==NULL) {
- lp->net_stats.rx_dropped++;
+ dev->stats.rx_dropped++;
goto dropped;
}
@@ -1189,8 +1188,8 @@
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 @@
/* 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 @@
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 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;
}
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index a453eda..934db35 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -340,7 +340,6 @@
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 @@
{
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 @@
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 @@
* 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 @@
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 @@
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_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 @@
__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 @@
PCI_DMA_TODEVICE);
if (le32_to_cpu(desc->opts1) & LastFrag)
dev_kfree_skb(skb);
- cp->net_stats.tx_dropped++;
+ cp->dev->stats.tx_dropped++;
}
}
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 53bd903..b23a00c 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -574,7 +574,6 @@
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 @@
dev_kfree_skb(skb);
} else {
dev_kfree_skb(skb);
- tp->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
return 0;
}
@@ -1762,27 +1761,27 @@
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 @@
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 @@
/* 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 @@
/* 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 @@
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 @@
printk (KERN_WARNING
"%s: Memory squeeze, dropping packet.\n",
dev->name);
- tp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
}
received++;
@@ -2072,7 +2071,7 @@
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 @@
}
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 @@
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 @@
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 @@
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);
diff --git a/drivers/net/8390.h b/drivers/net/8390.h
index 04ddec0..cf020d4 100644
--- a/drivers/net/8390.h
+++ b/drivers/net/8390.h
@@ -69,7 +69,6 @@
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. */
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index 6c19265..e4483de 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -1457,11 +1457,6 @@
ace_set_txprd(regs, ap, 0);
writel(0, ®s->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 @@
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 @@
}
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 @@
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;
}
diff --git a/drivers/net/acenic.h b/drivers/net/acenic.h
index 60ed183..4487f327 100644
--- a/drivers/net/acenic.h
+++ b/drivers/net/acenic.h
@@ -693,7 +693,6 @@
__attribute__ ((aligned (SMP_CACHE_BYTES)));
u32 last_tx, last_std_rx, last_mini_rx;
#endif
- struct net_device_stats stats;
int pci_using_dac;
};
diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c
index 2b5740b..ae07100 100644
--- a/drivers/net/cpmac.c
+++ b/drivers/net/cpmac.c
@@ -708,7 +708,7 @@
spin_unlock(&priv->lock);
if (netif_msg_tx_err(priv) && net_ratelimit())
printk(KERN_WARNING "%s: transmit timeout\n", dev->name);
- /*
+ /*
* FIXME: waking up random queue is not the best thing to
* do... on the other hand why we got here at all?
*/
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index d45bcd2..32a9a92 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -718,7 +718,7 @@
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 @@
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 @@
/* 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
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 25bdd08..393a0f1 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -928,7 +928,7 @@
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:
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 9d57212..06ad9f3 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -99,9 +99,6 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
count--;
if (fp && *fp++) {
if (!test_and_set_bit(SIXPF_ERROR, &sp->flags))
- sp->stats.rx_errors++;
+ sp->dev->stats.rx_errors++;
continue;
}
}
diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c
index 0c5447d..ed49527 100644
--- a/drivers/net/lib8390.c
+++ b/drivers/net/lib8390.c
@@ -150,19 +150,19 @@
* 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 @@
* [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 @@
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 @@
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 @@
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 @@
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 @@
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_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 @@
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 @@
/* 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 @@
&& 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 @@
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 @@
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 @@
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 @@
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 @@
{
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 @@
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 @@
/* 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;
}
/*
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 46119bb..b238ed0 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -664,7 +664,7 @@
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 @@
|| !strncmp("0", buf, count - 1))
new_setting = 0;
else
- return count;
+ return count;
spin_lock_irqsave(&np->lock, flags);
diff --git a/drivers/net/niu.h b/drivers/net/niu.h
index 12fd570..c6fa883 100644
--- a/drivers/net/niu.h
+++ b/drivers/net/niu.h
@@ -281,7 +281,7 @@
#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
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index 3b78a38..7112fd5 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -208,7 +208,6 @@
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 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 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 @@
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 @@
update_stats(dev);
spin_unlock_irqrestore(&lp->window_lock, flags);
}
- return &lp->stats;
+ return &dev->stats;
}
/* Update statistics.
@@ -996,7 +993,6 @@
*/
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 @@
/* 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 @@
/* 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 @@
(--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 @@
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);
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 1b1abb1..549a645 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -107,7 +107,6 @@
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 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 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 @@
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 @@
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 @@
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 @@
update_stats(dev);
spin_unlock_irqrestore(&lp->lock, flags);
}
- return &lp->stats;
+ return &dev->stats;
}
/*
@@ -827,7 +824,6 @@
*/
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 @@
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 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 @@
(--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 @@
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 @@
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. */
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index ce95c5d..d7018ff 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -1021,7 +1021,7 @@
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 @@
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 @@
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 @@
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 @@
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 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 @@
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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/* 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;
}
/*
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index a1c454d..81fd852 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -1973,7 +1973,7 @@
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 @@
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 @@
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;
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index b7f7b22..5f60878 100644
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -1437,9 +1437,9 @@
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;
}
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 523478e..75bde64 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -2547,7 +2547,7 @@
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",
@@ -2593,7 +2593,7 @@
first_rxdp->Control_1 |= RXD_OWN_XENA;
}
stats->mem_alloc_fail_cnt++;
-
+
return -ENOMEM ;
}
stats->mem_allocated += skb->truesize;
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 0709ebae..58229dc 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -747,7 +747,7 @@
/* interface MTU value */
unsigned mtu;
-
+
/* Buffer Address store. */
struct buffAdd **ba;
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
index 888b7de..2951990 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -1063,7 +1063,7 @@
((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
}
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index abc63b0..3fe017637 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -1656,7 +1656,7 @@
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;
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index ec95e493..fa3a460 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -1766,7 +1766,7 @@
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
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index f226bca..4b0f033 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -3369,7 +3369,7 @@
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) |
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index 4776716..00aa0b1 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -1704,7 +1704,7 @@
*
* 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_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);
diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c
index 45208a0..7766cde 100644
--- a/drivers/net/tokenring/3c359.c
+++ b/drivers/net/tokenring/3c359.c
@@ -132,7 +132,6 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 ;
diff --git a/drivers/net/tokenring/3c359.h b/drivers/net/tokenring/3c359.h
index b880cba..0f8b4ec 100644
--- a/drivers/net/tokenring/3c359.h
+++ b/drivers/net/tokenring/3c359.h
@@ -273,8 +273,6 @@
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 ;
diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c
index 6017d52..c028fac 100644
--- a/drivers/net/tsi108_eth.c
+++ b/drivers/net/tsi108_eth.c
@@ -1526,7 +1526,7 @@
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 @@
spin_lock_irqsave(&data->txlock, flags);
rc = mii_ethtool_sset(&data->mii_if, cmd);
spin_unlock_irqrestore(&data->txlock, flags);
-
+
return rc;
}
diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c
index 299b7f1..5f176f2 100644
--- a/drivers/net/ucc_geth_ethtool.c
+++ b/drivers/net/ucc_geth_ethtool.c
@@ -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 @@
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 */
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index 5c0d2b0..d93a1de 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -306,11 +306,10 @@
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;
}
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index 4e5c8fc..3201c16 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -1319,7 +1319,7 @@
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 +1335,7 @@
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 +1566,7 @@
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);
@@ -1979,10 +1979,10 @@
}
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);
diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h
index 3a97558..ecb1749 100644
--- a/drivers/net/wireless/ath5k/base.h
+++ b/drivers/net/wireless/ath5k/base.h
@@ -92,7 +92,8 @@
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];
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 37783cd..7d034df 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -410,8 +410,7 @@
#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 | \
diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c
index 7fca2eb..210e278 100644
--- a/drivers/net/wireless/b43/debugfs.c
+++ b/drivers/net/wireless/b43/debugfs.c
@@ -270,24 +270,22 @@
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;
+ expire = time + expire;
- 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));
- }
+ 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 @@
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 @@
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 @@
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 @@
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
}
diff --git a/drivers/net/wireless/b43/debugfs.h b/drivers/net/wireless/b43/debugfs.h
index 6eebe858..c75cff4 100644
--- a/drivers/net/wireless/b43/debugfs.h
+++ b/drivers/net/wireless/b43/debugfs.h
@@ -10,6 +10,7 @@
B43_DBG_DMAVERBOSE,
B43_DBG_PWORK_FAST,
B43_DBG_PWORK_STOP,
+ B43_DBG_LO,
__B43_NR_DYNDBG,
};
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index 6dcbb3c..f50e201 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -1427,18 +1427,16 @@
{
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);
}
}
diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c
index d890f36..4ce1e35 100644
--- a/drivers/net/wireless/b43/lo.c
+++ b/drivers/net/wireless/b43/lo.c
@@ -36,17 +36,28 @@
#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 @@
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,
@@ -438,48 +271,26 @@
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 */
@@ -609,8 +420,6 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
} 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->att);
+ b43_radio_write16(dev, txctl_reg,
+ (b43_radio_read16(dev, txctl_reg) & ~txctl_value)
+ | (rfatt->with_padmix) ? txctl_value : 0);
- 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));
+ 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));
- 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;
+ b43_phy_set_baseband_attenuation(dev, bbatt->att);
+ lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain);
- 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));
+ lo_measure_restore(dev, &saved_regs);
+ b43_mac_enable(dev);
- 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(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 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;
-
- 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;
- }
+ cal = kmalloc(sizeof(*cal), GFP_KERNEL);
+ if (!cal) {
+ b43warn(dev->wl, "LO calib: out of memory\n");
+ return NULL;
}
- if (is_initializing && control->used)
- goto error;
+ 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;
-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);
+ return cal;
}
-static void validate_all_loctls(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_validate_loctl);
+ 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;
}
-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;
- }
-}
-
-static void reset_all_loctl_calibration_states(struct b43_wldev *dev)
-{
- b43_call_for_each_loctl(dev, do_reset_calib);
-}
-
-#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);
+ 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;
- B43_WARN_ON((phy->type != B43_PHYTYPE_B) &&
- (phy->type != B43_PHYTYPE_G));
+ BUILD_BUG_ON(B43_DC_LT_SIZE != 32);
+ B43_WARN_ON(lo->rfatt_list.len * lo->bbatt_list.len > 64);
- sav.old_channel = phy->channel;
- lo_measure_setup(dev, &sav);
- reset_all_loctl_calibration_states(dev);
- lo_measure(dev);
- lo_measure_restore(dev, &sav);
+ power_vector = lo->power_vector;
+ if (!update_all && !power_vector)
+ return; /* Nothing to do. */
- validate_all_loctls(dev);
+ /* Suspend the MAC now to avoid continuous suspend/enable
+ * cycles in the loop. */
+ b43_mac_suspend(dev);
- phy->lo_control->lo_measured = 1;
- phy->lo_control->rebuild = 0;
-}
+ for (i = 0; i < B43_DC_LT_SIZE * 2; i++) {
+ struct b43_lo_calib *cal;
+ int idx;
+ u16 val;
-#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;
+ 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)
-{
-}
-#endif
-
-static inline void fixup_rfatt_for_txcontrol(struct b43_rfatt *rf,
- u8 tx_control)
-{
- if (tx_control & B43_TXCTL_TXMIX) {
- if (rf->att < 5)
- rf->att = 4;
+ 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);
+}
+
+/* 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 (!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 @@
{
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)
-{
- control->used = 0;
-}
-
-void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev)
+/* Periodic LO maintanance work */
+void b43_lo_g_maintanance_work(struct b43_wldev *dev)
{
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;
- b43_call_for_each_loctl(dev, do_mark_unused);
- lo->rebuild = 1;
+ 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_cur_used(struct b43_wldev *dev)
+void b43_lo_g_cleanup(struct b43_wldev *dev)
+{
+ struct b43_txpower_lo_control *lo = dev->phy.lo_control;
+ struct b43_lo_calib *cal, *tmp;
+
+ if (!lo)
+ return;
+ list_for_each_entry_safe(cal, tmp, &lo->calib_list, list) {
+ list_del(&cal->list);
+ kfree(cal);
+ }
+}
+
+/* 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);
+ }
}
diff --git a/drivers/net/wireless/b43/lo.h b/drivers/net/wireless/b43/lo.h
index 455615d..1da321c 100644
--- a/drivers/net/wireless/b43/lo.h
+++ b/drivers/net/wireless/b43/lo.h
@@ -10,82 +10,63 @@
/* 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
+/* 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;
+};
-/* 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.
- */
+/* 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_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_ */
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 8fdba94..c6e79a1 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -2308,7 +2308,7 @@
}
/* 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 @@
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 @@
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 @@
{
b43_radio_turn_off(dev, 1);
b43_gpio_cleanup(dev);
+ b43_lo_g_cleanup(dev);
/* firmware is released later */
}
@@ -2609,28 +2597,12 @@
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 @@
}
}
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 @@
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 @@
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 @@
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;
diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h
index 5230aec..dad23c4 100644
--- a/drivers/net/wireless/b43/main.h
+++ b/drivers/net/wireless/b43/main.h
@@ -114,4 +114,7 @@
#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_ */
diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c
index de024dc..8b3c24d 100644
--- a/drivers/net/wireless/b43/phy.c
+++ b/drivers/net/wireless/b43/phy.c
@@ -145,8 +145,7 @@
{.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 +157,7 @@
/* 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 +345,7 @@
/* 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 +559,6 @@
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 +576,6 @@
}
}
-/* 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 +602,7 @@
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 +890,6 @@
}
}
-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 +1115,9 @@
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 +1380,31 @@
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);
@@ -1821,10 +1664,8 @@
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 +1711,6 @@
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;
@@ -2007,24 +1847,6 @@
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;
diff --git a/drivers/net/wireless/b43/phy.h b/drivers/net/wireless/b43/phy.h
index 6d165d8..4aab109 100644
--- a/drivers/net/wireless/b43/phy.h
+++ b/drivers/net/wireless/b43/phy.h
@@ -225,7 +225,6 @@
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 @@
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 @@
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 */
diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c
index fcacafb..08c8a08 100644
--- a/drivers/net/wireless/b43/pio.c
+++ b/drivers/net/wireless/b43/pio.c
@@ -611,18 +611,16 @@
{
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);
}
}
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
index 19aefbf..8849194 100644
--- a/drivers/net/wireless/b43/xmit.c
+++ b/drivers/net/wireless/b43/xmit.c
@@ -235,7 +235,7 @@
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;
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
index c990f87..d6686f7 100644
--- a/drivers/net/wireless/b43legacy/dma.c
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -1455,18 +1455,16 @@
{
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);
}
}
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 14a5eea..1ccc51e 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -2383,8 +2383,7 @@
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;
diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c
index bcdd54e..8d3d27d 100644
--- a/drivers/net/wireless/b43legacy/pio.c
+++ b/drivers/net/wireless/b43legacy/pio.c
@@ -525,13 +525,11 @@
{
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,
diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c
index dcad249..fc83dab 100644
--- a/drivers/net/wireless/b43legacy/xmit.c
+++ b/drivers/net/wireless/b43legacy/xmit.c
@@ -232,7 +232,7 @@
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;
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index 62fb89d..995dd53 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -14,6 +14,15 @@
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 @@
---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"
@@ -100,6 +111,23 @@
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
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index ec6187b..b0b2b5e 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -1,8 +1,9 @@
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-$(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
@@ -11,3 +12,8 @@
obj-$(CONFIG_IWL4965) += iwl4965.o
iwl4965-objs := iwl4965-base.o iwl-4965.o iwl-4965-rs.o iwl-sta.o
+ifeq ($(CONFIG_IWL5000),y)
+ iwl4965-objs += iwl-5000.o
+endif
+
+
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
index ad612a8..644bd9e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
@@ -126,7 +126,7 @@
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 @@
#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)
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
index 85c2264..e51eeef 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
@@ -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>
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 62a3d8f..9df48b3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -1229,7 +1229,7 @@
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);
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index c7695a2..fb96c62 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -924,11 +924,6 @@
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-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
index 1a66b50..29749e2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
@@ -62,13 +62,18 @@
*****************************************************************************/
/*
* 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
@@ -131,10 +136,8 @@
#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 @@
/********************* 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,11 +822,11 @@
* 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
@@ -1520,10 +957,10 @@
* 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_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; */
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
index c9847b1..24dee00 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
@@ -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>
@@ -38,13 +37,13 @@
#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 @@
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 @@
* 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 @@
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 @@
/* 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 @@
#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 @@
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 @@
* 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 @@
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 @@
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
@@ -374,6 +385,13 @@
#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 @@
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 @@
* 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 @@
/* 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 @@
/*
* 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)
+ } else if (is_Ht(tbl->lq_type)) {
+ if (index > IWL_LAST_OFDM_RATE) {
+ IWL_ERROR("invalid HT rate index %d\n", index);
index = IWL_LAST_OFDM_RATE;
- mcs_rate->rate_n_flags = iwl4965_rates[index].plcp_siso |
- RATE_MCS_HT_MSK;
- } else {
- if (index > IWL_LAST_OFDM_RATE)
- index = IWL_LAST_OFDM_RATE;
- mcs_rate->rate_n_flags = iwl4965_rates[index].plcp_mimo |
- RATE_MCS_HT_MSK;
- }
+ }
+ rate_n_flags = 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;
-
- if (tbl->is_fat) {
- if (tbl->is_dup)
- mcs_rate->rate_n_flags |= RATE_MCS_DUP_MSK;
- else
- mcs_rate->rate_n_flags |= RATE_MCS_FAT_MSK;
- }
- 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 |= iwl4965_rates[index].plcp_siso;
+ else if (is_mimo2(tbl->lq_type))
+ rate_n_flags |= iwl4965_rates[index].plcp_mimo2;
+ else
+ rate_n_flags |= iwl4965_rates[index].plcp_mimo3;
+ } else {
+ IWL_ERROR("Invalid tbl->lq_type %d\n", tbl->lq_type);
}
+
+ 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,23 +642,23 @@
* 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 (is_siso(rate_type))
- *data_rate = lq_sta->active_siso_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;
+ 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))
+ return lq_sta->active_siso_rate;
+ else if (is_mimo2(rate_type))
+ return lq_sta->active_mimo2_rate;
+ else
+ return lq_sta->active_mimo3_rate;
}
}
@@ -705,9 +717,9 @@
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 +738,14 @@
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 +759,18 @@
/* 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);
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 +792,7 @@
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 +834,6 @@
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 +849,8 @@
* 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 +861,14 @@
!!(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 +876,14 @@
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 +894,7 @@
/* 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 +917,8 @@
* 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 +929,7 @@
/* 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 +945,7 @@
/* 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 +982,6 @@
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.
@@ -1017,7 +993,7 @@
static void rs_set_stay_in_table(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 +1012,7 @@
/*
* 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 +1031,7 @@
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 +1061,7 @@
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,6 +1074,7 @@
s32 new_rate, high, low, start_hi;
u16 high_low;
+ s8 rate = index;
new_rate = high = low = start_hi = IWL_RATE_INVALID;
@@ -1172,21 +1149,16 @@
}
#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 +1167,27 @@
!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 +1197,35 @@
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
- return -1;
-#endif /*CONFIG_IWL4965_HT */
}
+#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 */
/*
* Set up search table for SISO
@@ -1256,16 +1241,16 @@
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 +1258,7 @@
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 +1268,26 @@
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 +1300,6 @@
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 +1308,35 @@
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 +1346,15 @@
}
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 +1364,7 @@
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 +1375,7 @@
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 +1390,6 @@
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 +1399,30 @@
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;
+ if (rs_toggle_antenna(valid_tx_ant,
+ &search_tbl->current_rate, search_tbl)) {
+ lq_sta->search_better_tbl = 1;
+ goto out;
+ }
- 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 +1430,25 @@
}
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)) {
- 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 (is_green) {
+ if (!tbl->is_SGI)
+ break;
+ else
+ IWL_ERROR("SGI was set in GF+SISO\n");
}
- rs_get_expected_tpt_table(lq_sta, search_tbl);
- rs_mcs_from_tbl(&search_tbl->current_rate,
- search_tbl, index, is_green);
+ 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 (tpt >= search_tbl->expected_tpt[index])
+ break;
+ }
+ 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 +1476,6 @@
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 +1484,24 @@
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 +1512,26 @@
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;
}
@@ -1624,9 +1580,6 @@
(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 +1592,7 @@
(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 +1615,7 @@
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 +1658,7 @@
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 +1714,7 @@
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 +1734,16 @@
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 +1755,9 @@
* 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 +1768,51 @@
* 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 +1822,11 @@
/* 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
@@ -1988,15 +1934,15 @@
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 +1977,11 @@
/* 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,7 +1997,7 @@
#endif
(lq_sta->action_counter >= 1)) {
lq_sta->action_counter = 0;
- IWL_DEBUG_HT("LQ: STAY in legacy table\n");
+ IWL_DEBUG_RATE("LQ: STAY in legacy table\n");
rs_set_stay_in_table(1, lq_sta);
}
@@ -2065,7 +2010,7 @@
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 */
@@ -2086,7 +2031,7 @@
}
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 +2051,14 @@
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 +2070,8 @@
(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 +2082,23 @@
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 +2139,7 @@
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) {
@@ -2260,7 +2209,7 @@
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 +2217,11 @@
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 +2250,8 @@
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 +2259,37 @@
* 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] & 0x1);
- lq_sta->active_siso_rate &= ~((u16)0x2);
lq_sta->active_siso_rate =
- lq_sta->active_siso_rate << IWL_FIRST_OFDM_RATE;
+ priv->current_ht_config.supp_mcs_set[0] << 1;
+ lq_sta->active_siso_rate |=
+ priv->current_ht_config.supp_mcs_set[0] & 0x1;
+ lq_sta->active_siso_rate &= ~((u16)0x2);
+ 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 +2303,55 @@
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 +2359,25 @@
* 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 +2387,22 @@
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 +2412,12 @@
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);
}
@@ -2496,25 +2460,21 @@
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;
-
- 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;
+ 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,
@@ -2531,19 +2491,20 @@
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 +2523,9 @@
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 +2575,7 @@
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 +2665,7 @@
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;
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h
index 866e378..7ea2041 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h
@@ -27,12 +27,13 @@
#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 @@
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 @@
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 @@
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 @@
/* 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 @@
#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 @@
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))
+#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 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)
{
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index bf19eb8..5d675e3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -39,14 +39,15 @@
#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,
/* the rest are 0 by default */
@@ -54,42 +55,6 @@
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,120 +224,12 @@
return 0;
}
-static int iwl4965_init_drv(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);
-
- priv->shared_virt = pci_alloc_consistent(priv->pci_dev,
- sizeof(struct iwl4965_shared),
- &priv->shared_phys);
-
- if (!priv->shared_virt) {
- ret = -ENOMEM;
- goto err;
- }
-
- 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;
-
- iwlcore_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 = iwl4965_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:
- iwl4965_free_geos(priv);
-err_free_channel_map:
- iwl_free_channel_map(priv);
-err:
- return ret;
-}
-
static int is_fat_channel(__le32 rxon_flags)
{
return (rxon_flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) ||
(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 +238,8 @@
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 +267,7 @@
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 +288,6 @@
&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 +313,32 @@
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 +350,21 @@
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);
@@ -619,7 +435,7 @@
if (rc)
goto out;
- iwl_write_direct32(priv, IWL_FH_KW_MEM_ADDR_REG,
+ iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG,
priv->kw.dma_addr >> 4);
iwl_release_nic_access(priv);
out:
@@ -722,107 +538,106 @@
error_kw:
return rc;
}
-
-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;
+ int ret = 0;
- iwl4965_power_init_handle(priv);
-
- /* nic_init */
spin_lock_irqsave(&priv->lock, flags);
-
iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
- CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+ 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);
+
+ /* 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 rc;
+ goto out;
}
- rc = iwl_grab_nic_access(priv);
- if (rc) {
- spin_unlock_irqrestore(&priv->lock, flags);
- return rc;
- }
+ ret = iwl_grab_nic_access(priv);
+ if (ret)
+ goto out;
- iwl_read_prph(priv, APMG_CLK_CTRL_REG);
-
+ /* enable DMA */
iwl_write_prph(priv, APMG_CLK_CTRL_REG,
APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT);
- 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);
+out:
spin_unlock_irqrestore(&priv->lock, flags);
+ 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);
+
+ /* 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);
+ CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
+ CSR_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;
- }
+ priv->calib_info = (struct iwl_eeprom_calib_info *)
+ iwl_eeprom_query_addr(priv, EEPROM_4965_CALIB_TXPOWER_OFFSET);
- 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);
+}
+
+
+int iwl4965_hw_nic_init(struct iwl_priv *priv)
+{
+ unsigned long flags;
+ struct iwl4965_rx_queue *rxq = &priv->rxq;
+ int ret;
+
+ /* nic_init */
+ priv->cfg->ops->lib->apm_ops.init(priv);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ 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);
iwl4965_hw_card_show_info(priv);
@@ -830,8 +645,8 @@
/* Allocate the RX queue, or reset if it is already allocated */
if (!rxq->bd) {
- rc = iwl4965_rx_queue_alloc(priv);
- if (rc) {
+ ret = iwl4965_rx_queue_alloc(priv);
+ if (ret) {
IWL_ERROR("Unable to initialize Rx queue\n");
return -ENOMEM;
}
@@ -850,15 +665,9 @@
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");
+ ret = iwl4965_txq_ctx_reset(priv);
+ if (ret)
+ return ret;
set_bit(STATUS_INIT, &priv->status);
@@ -916,9 +725,9 @@
}
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);
@@ -993,15 +802,9 @@
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;
@@ -1010,440 +813,28 @@
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]);
- }
+ cmd.critical_temperature_R =
+ cpu_to_le32(priv->hw_params.ct_kill_threshold);
- 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");
+ IWL_DEBUG_INFO("REPLY_CT_KILL_CONFIG_CMD succeeded, "
+ "critical temperature is %d\n",
+ cmd.critical_temperature_R);
}
-#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;
-}
-
+#ifdef CONFIG_IWL4965_RUN_TIME_CALIB
/* 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)
+static void iwl4965_chain_noise_reset(struct iwl_priv *priv)
{
- struct iwl4965_chain_noise_data *data = NULL;
+ struct iwl_chain_noise_data *data = &(priv->chain_noise_data);
- data = &(priv->chain_noise_data);
if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
struct iwl4965_calibration_cmd cmd;
@@ -1452,357 +843,76 @@
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);
+ 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");
}
- 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)
+static void iwl4965_gain_computation(struct iwl_priv *priv,
+ u32 *average_noise,
+ u16 min_average_noise_antenna_i,
+ u32 min_average_noise)
{
- struct iwl4965_chain_noise_data *data = NULL;
- int ret = 0;
+ int i, ret;
+ struct iwl_chain_noise_data *data = &priv->chain_noise_data;
- 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->delta_gain_code[min_average_noise_antenna_i] = 0;
- data = &(priv->chain_noise_data);
+ for (i = 0; i < NUM_RX_CHAINS; i++) {
+ s32 delta_g = 0;
- /* 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);
-
- for (i = 0; i < NUM_RX_CHAINS; i++) {
- s32 delta_g = 0;
-
- if (!(data->disconn_array[i]) &&
- (data->delta_gain_code[i] ==
+ 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;
+ 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;
+ 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_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]);
-static void iwl4965_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 iwl4965_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;
- int ret;
+ /* Differential gain gets sent to uCode only once */
+ if (!data->radio_write) {
+ struct iwl4965_calibration_cmd cmd;
+ data->radio_write = 1;
- data = &(priv->sensitivity_data);
+ 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");
- if (!iwl_is_associated(priv)) {
- IWL_DEBUG_CALIB("<< - not associated\n");
- return;
+ /* TODO we might want recalculate
+ * rx_chain in rxon cmd */
+
+ /* Mark so we run this algo only once! */
+ data->state = IWL_CHAIN_NOISE_CALIBRATED;
}
-
- 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);
-
- 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);
-
- return;
+ 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 +929,15 @@
}
if (priv->start_calib) {
- iwl4965_noise_calibration(priv, &priv->statistics);
+ iwl_chain_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_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)
{
@@ -1890,11 +994,11 @@
/* 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 +1012,7 @@
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 +1036,15 @@
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 +1053,10 @@
/* 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 +1078,18 @@
/* 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 +1117,31 @@
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 +1150,15 @@
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,10 +1170,20 @@
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);
+ 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);
+
+#ifdef CONFIG_IWL4965_RUN_TIME_CALIB
+ priv->hw_params.sens = &iwl4965_sensitivity;
+#endif
return 0;
}
@@ -2124,6 +1264,17 @@
return 0;
}
+/* set card power command */
+static int iwl4965_set_power(struct iwl_priv *priv,
+ void *cmd)
+{
+ int ret = 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 +1375,11 @@
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 +1407,14 @@
* 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 +1424,8 @@
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 +1433,9 @@
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 +1754,8 @@
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 +1812,9 @@
/* 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 +1844,7 @@
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);
@@ -3104,9 +2255,9 @@
/* 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);
+ 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);
@@ -3149,18 +2300,37 @@
static void iwl4965_hw_card_show_info(struct iwl_priv *priv)
{
- u16 hw_version = priv->eeprom.board_revision_4965;
+ u16 hw_version = iwl_eeprom_query16(priv, EEPROM_4965_BOARD_REVISION);
IWL_DEBUG_INFO("4965ABGN HW Version %u.%u.%u\n",
((hw_version >> 8) & 0x0F),
((hw_version >> 8) >> 4), (hw_version & 0x00FF));
IWL_DEBUG_INFO("4965ABGN PBA Number %.16s\n",
- priv->eeprom.board_pba_number_4965);
+ &priv->eeprom[EEPROM_4965_BOARD_PBA]);
}
-#define IWL_TX_CRC_SIZE 4
-#define IWL_TX_DELIMITER_SIZE 4
+static int iwl4965_alloc_shared_mem(struct iwl_priv *priv)
+{
+ 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));
+
+ return 0;
+}
+
+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
@@ -3180,50 +2350,13 @@
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
*
* Example: sign_extend(9, 3) would return -7 as bit3 of 1001b is 1
@@ -3412,7 +2545,7 @@
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
}
@@ -3562,6 +2695,53 @@
priv->rx_stats[idx].bytes += len;
}
+/*
+ * 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(u32 decrypt_in)
{
u32 decrypt_out = 0;
@@ -3691,8 +2871,10 @@
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);
@@ -3737,38 +2919,6 @@
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;
@@ -3786,7 +2936,7 @@
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].
@@ -4139,7 +3289,7 @@
struct iwl4965_rx_mem_buffer *rxb)
{
-#ifdef CONFIG_IWL4965_SENSITIVITY
+#ifdef CONFIG_IWL4965_RUN_TIME_CALIB
struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
struct iwl4965_missed_beacon_notif *missed_beacon;
@@ -4150,11 +3300,10 @@
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
@@ -4254,8 +3403,8 @@
* 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));
}
/**
@@ -4420,10 +3569,10 @@
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 +3634,14 @@
/* 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 +3693,7 @@
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);
@@ -4648,13 +3796,15 @@
rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS);
- iwl4965_set_rxon_chain(priv);
+ iwl_set_rxon_chain(priv);
- IWL_DEBUG_ASSOC("supported HT rate 0x%X %X "
+ 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[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);
@@ -4706,10 +3856,15 @@
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 +3874,19 @@
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 iwl4965_send_add_station(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 +3895,8 @@
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 iwl4965_send_add_station(priv, &priv->stations[sta_id].sta,
+ CMD_ASYNC);
}
/*
@@ -4753,8 +3915,8 @@
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;
@@ -4771,10 +3933,10 @@
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 +3965,7 @@
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,10 +3974,8 @@
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;
@@ -4823,8 +3983,8 @@
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 +3993,7 @@
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 +4015,7 @@
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 +4025,7 @@
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 +4035,24 @@
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;
@@ -4910,7 +4064,7 @@
#endif /* CONFIG_IWL4965_HT */
/* Set up 4965-specific Rx frame reply handlers */
-void iwl4965_hw_rx_handler_setup(struct iwl_priv *priv)
+static void iwl4965_rx_handler_setup(struct iwl_priv *priv)
{
/* Legacy Rx frames */
priv->rx_handlers[REPLY_RX] = iwl4965_rx_reply_rx;
@@ -4930,7 +4084,7 @@
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 +4106,46 @@
static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
.enqueue_hcmd = iwl4965_enqueue_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,
.txq_update_byte_cnt_tbl = iwl4965_txq_update_byte_cnt_tbl,
.hw_nic_init = iwl4965_hw_nic_init,
+ .rx_handler_setup = iwl4965_rx_handler_setup,
.is_valid_rtc_data_addr = iwl4965_hw_valid_rtc_data_addr,
.alive_notify = iwl4965_alive_notify,
.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 +4158,7 @@
.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,
};
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
new file mode 100644
index 0000000..9e557ce
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
@@ -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
index 0000000..0d8ef63
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -0,0 +1,519 @@
+/******************************************************************************
+ *
+ * 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_init(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));
+
+ 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);
+}
+
+/**
+ * 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 iwl4965_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 struct iwl_hcmd_ops iwl5000_hcmd = {
+};
+
+static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
+#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,
+ .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
+ .apm_ops = {
+ .init = iwl5000_apm_init,
+ .config = iwl5000_nic_init,
+ .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,
+ /* 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");
+
+
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c
new file mode 100644
index 0000000..1289d4c
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.c
@@ -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
index 0000000..933b0b0
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.h
@@ -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-4965-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
similarity index 98%
rename from drivers/net/wireless/iwlwifi/iwl-4965-commands.h
rename to drivers/net/wireless/iwlwifi/iwl-commands.h
index 3bcd107..5afa7b7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -61,9 +61,9 @@
*
*****************************************************************************/
/*
- * Please use this file (iwl-4965-commands.h) only for uCode API definitions.
+ * Please use this file (iwl-commands.h) only for uCode API definitions.
* Please use iwl-4965-hw.h for hardware-related definitions.
- * Please use iwl-4965.h for driver implementation definitions.
+ * Please use iwl-dev.h for driver implementation definitions.
*/
#ifndef __iwl4965_commands_h__
@@ -269,10 +269,11 @@
* 10 B active, A inactive
* 11 Both active
*/
-#define RATE_MCS_ANT_POS 14
-#define RATE_MCS_ANT_A_MSK 0x04000
-#define RATE_MCS_ANT_B_MSK 0x08000
-#define RATE_MCS_ANT_AB_MSK 0x0C000
+#define RATE_MCS_ANT_POS 14
+#define RATE_MCS_ANT_A_MSK 0x04000
+#define RATE_MCS_ANT_B_MSK 0x08000
+#define RATE_MCS_ANT_C_MSK 0x10000
+#define RATE_MCS_ANT_ABC_MSK 0x1C000
/**
@@ -711,6 +712,8 @@
#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
@@ -1100,6 +1103,14 @@
#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.
@@ -1853,6 +1864,7 @@
#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;
@@ -2559,7 +2571,7 @@
*/
/*
- * Table entries in SENSITIVITY_CMD (struct iwl4965_sensitivity_cmd)
+ * Table entries in SENSITIVITY_CMD (struct iwl_sensitivity_cmd)
*/
#define HD_TABLE_SIZE (11) /* number of entries */
#define HD_MIN_ENERGY_CCK_DET_INDEX (0) /* table indexes */
@@ -2574,18 +2586,18 @@
#define HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX (9)
#define HD_OFDM_ENERGY_TH_IN_INDEX (10)
-/* Control field in struct iwl4965_sensitivity_cmd */
+/* Control field in struct iwl_sensitivity_cmd */
#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE __constant_cpu_to_le16(0)
#define SENSITIVITY_CMD_CONTROL_WORK_TABLE __constant_cpu_to_le16(1)
/**
- * struct iwl4965_sensitivity_cmd
+ * struct iwl_sensitivity_cmd
* @control: (1) updates working table, (0) updates default table
* @table: energy threshold values, use HD_* as index into table
*
* Always use "1" in "control" to update uCode's working table and DSP.
*/
-struct iwl4965_sensitivity_cmd {
+struct iwl_sensitivity_cmd {
__le16 control; /* always use "1" */
__le16 table[HD_TABLE_SIZE]; /* use HD_* as index */
} __attribute__ ((packed));
@@ -2659,6 +2671,37 @@
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:
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 2dfd982..c4b5c1a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -34,9 +34,11 @@
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");
@@ -49,6 +51,45 @@
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,
struct ieee80211_ops *hw_ops)
@@ -72,6 +113,14 @@
}
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);
+
/**
* iwlcore_clear_stations_table - Clear the driver's station table
*
@@ -90,7 +139,7 @@
}
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 +225,289 @@
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;
+}
+#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;
+}
+#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 +519,7 @@
* 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,7 +545,7 @@
return 0;
}
-EXPORT_SYMBOL(iwlcore_set_rxon_channel);
+EXPORT_SYMBOL(iwl_set_rxon_channel);
static void iwlcore_init_hw(struct iwl_priv *priv)
{
@@ -237,15 +568,96 @@
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 +675,10 @@
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 +704,137 @@
}
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);
+
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 7193d97..369f182 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -87,17 +87,26 @@
};
struct iwl_hcmd_utils_ops {
int (*enqueue_hcmd)(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
+#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);
void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv,
struct iwl4965_tx_queue *txq,
u16 byte_cnt);
+ /* setup Rx handler */
+ void (*rx_handler_setup)(struct iwl_priv *priv);
/* nic init */
int (*hw_nic_init)(struct iwl_priv *priv);
/* alive notification */
@@ -108,6 +117,15 @@
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;
};
@@ -133,6 +151,7 @@
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,13 +162,15 @@
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);
/*****************************************************
@@ -235,6 +256,7 @@
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);
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index 1272579..9d6e5d2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -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.
@@ -107,9 +106,9 @@
/* 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)
@@ -170,6 +169,10 @@
#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)
@@ -191,6 +194,16 @@
#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)
@@ -206,11 +219,6 @@
#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)
@@ -220,6 +228,10 @@
#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)
/*
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 9a30e1d..3091445 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -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"
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
similarity index 91%
rename from drivers/net/wireless/iwlwifi/iwl-4965.h
rename to drivers/net/wireless/iwlwifi/iwl-dev.h
index 581b985..78aba21 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -24,8 +24,8 @@
*
*****************************************************************************/
/*
- * Please use this file (iwl-4965.h) for driver implementation definitions.
- * Please use iwl-4965-commands.h for uCode API definitions.
+ * Please use this file (iwl-dev.h) for driver implementation definitions.
+ * Please use iwl-commands.h for uCode API definitions.
* Please use iwl-4965-hw.h for hardware-related definitions.
*/
@@ -44,9 +44,13 @@
#include "iwl-prph.h"
#include "iwl-debug.h"
#include "iwl-led.h"
+#include "iwl-power.h"
/* configuration for the iwl4965 */
extern struct iwl_cfg iwl4965_agn_cfg;
+extern struct iwl_cfg iwl5300_agn_cfg;
+extern struct iwl_cfg iwl5100_agn_cfg;
+extern struct iwl_cfg iwl5350_agn_cfg;
/* Change firmware file name, using "-" and incrementing number,
* *only* when uCode interface or architecture changes so that it
@@ -54,6 +58,8 @@
* This number will also appear in << 8 position of 1st dword of uCode file */
#define IWL4965_UCODE_API "-1"
+/* CT-KILL constants */
+#define CT_KILL_THRESHOLD 110 /* in Celsius */
/* Default noise level to report when noise measurement is not available.
* This may be because we're:
@@ -68,12 +74,6 @@
* 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:
@@ -199,9 +199,9 @@
struct iwl_channel_info {
struct iwl4965_channel_tgd_info tgd;
struct iwl4965_channel_tgh_info tgh;
- struct iwl4965_eeprom_channel eeprom; /* EEPROM regulatory limit */
- struct iwl4965_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for
- * FAT channel */
+ struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */
+ struct iwl_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for
+ * FAT channel */
u8 channel; /* channel number */
u8 flags; /* flags copied from EEPROM */
@@ -252,29 +252,9 @@
/* Power management (not Tx power) structures */
-struct iwl4965_power_vec_entry {
- struct iwl4965_powertable_cmd cmd;
- u8 no_dtim;
-};
-#define IWL_POWER_RANGE_0 (0)
-#define IWL_POWER_RANGE_1 (1)
-
-#define IWL_POWER_MODE_CAM 0x00 /* Continuously Aware Mode, always on */
-#define IWL_POWER_INDEX_3 0x03
-#define IWL_POWER_INDEX_5 0x05
-#define IWL_POWER_AC 0x06
-#define IWL_POWER_BATTERY 0x07
-#define IWL_POWER_LIMIT 0x07
-#define IWL_POWER_MASK 0x0F
-#define IWL_POWER_ENABLED 0x10
-#define IWL_POWER_LEVEL(x) ((x) & IWL_POWER_MASK)
-
-struct iwl4965_power_mgr {
- spinlock_t lock;
- struct iwl4965_power_vec_entry pwr_range_0[IWL_POWER_AC];
- struct iwl4965_power_vec_entry pwr_range_1[IWL_POWER_AC];
- u8 active_index;
- u32 dtim_val;
+enum iwl_pwr_src {
+ IWL_PWR_SRC_VMAIN,
+ IWL_PWR_SRC_VAUX,
};
#define IEEE80211_DATA_LEN 2304
@@ -566,16 +546,49 @@
struct list_head list;
};
+struct iwl_sensitivity_ranges {
+ u16 min_nrg_cck;
+ u16 max_nrg_cck;
+
+ u16 nrg_th_cck;
+ u16 nrg_th_ofdm;
+
+ u16 auto_corr_min_ofdm;
+ u16 auto_corr_min_ofdm_mrc;
+ u16 auto_corr_min_ofdm_x1;
+ u16 auto_corr_min_ofdm_mrc_x1;
+
+ u16 auto_corr_max_ofdm;
+ u16 auto_corr_max_ofdm_mrc;
+ u16 auto_corr_max_ofdm_x1;
+ u16 auto_corr_max_ofdm_mrc_x1;
+
+ u16 auto_corr_max_cck;
+ u16 auto_corr_max_cck_mrc;
+ u16 auto_corr_min_cck;
+ u16 auto_corr_min_cck_mrc;
+};
+
+
+#define IWL_FAT_CHANNEL_52 BIT(IEEE80211_BAND_5GHZ)
+
/**
* struct iwl_hw_params
* @max_txq_num: Max # Tx queues supported
* @tx_cmd_len: Size of Tx command (but not including frame itself)
- * @tx_ant_num: Number of TX antennas
+ * @tx/rx_chains_num: Number of TX/RX chains
+ * @valid_tx/rx_ant: usable antennas
* @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2)
- * @rx_buffer_size:
* @max_rxq_log: Log-base-2 of max_rxq_size
+ * @rx_buf_size: Rx buffer size
* @max_stations:
* @bcast_sta_id:
+ * @fat_channel: is 40MHz width possible in band 2.4
+ * BIT(IEEE80211_BAND_5GHZ) BIT(IEEE80211_BAND_5GHZ)
+ * @sw_crypto: 0 for hw, 1 for sw
+ * @max_xxx_size: for ucode uses
+ * @ct_kill_threshold: temperature threshold
+ * @struct iwl_sensitivity_ranges: range of sensitivity values
*/
struct iwl_hw_params {
u16 max_txq_num;
@@ -590,10 +603,19 @@
u32 max_pkt_size;
u8 max_stations;
u8 bcast_sta_id;
+ u8 fat_channel;
+ u8 sw_crypto;
+ u32 max_inst_size;
+ u32 max_data_size;
+ u32 max_bsm_size;
+ u32 ct_kill_threshold; /* value in hw-dependent units */
+#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
+ const struct iwl_sensitivity_ranges *sens;
+#endif
};
-#define HT_SHORT_GI_20MHZ_ONLY (1 << 0)
-#define HT_SHORT_GI_40MHZ_ONLY (1 << 1)
+#define HT_SHORT_GI_20MHZ_ONLY (1 << 0)
+#define HT_SHORT_GI_40MHZ_ONLY (1 << 1)
#define IWL_RX_HDR(x) ((struct iwl4965_rx_frame_hdr *)(\
@@ -641,10 +663,10 @@
const u8 *dest, int left);
extern int iwl4965_rx_queue_update_write_ptr(struct iwl_priv *priv,
struct iwl4965_rx_queue *q);
-extern void iwl4965_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
- u32 decrypt_res,
- struct ieee80211_rx_status *stats);
extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr);
+extern void iwl4965_update_chain_flags(struct iwl_priv *priv);
+int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src);
+
int iwl4965_init_geos(struct iwl_priv *priv);
void iwl4965_free_geos(struct iwl_priv *priv);
@@ -674,7 +696,6 @@
* 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);
@@ -706,14 +727,14 @@
extern int iwl4965_get_temperature(const struct iwl_priv *priv);
/**
- * iwl4965_hw_find_station - Find station id for a given BSSID
+ * iwl_find_station - Find station id for a given BSSID
* @bssid: MAC address of station ID to find
*
* NOTE: This should not be hardware specific but the code has
* not yet been merged into a single common layer for managing the
* station tables.
*/
-extern u8 iwl4965_hw_find_station(struct iwl_priv *priv, const u8 *bssid);
+extern u8 iwl_find_station(struct iwl_priv *priv, const u8 *bssid);
extern int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel);
extern int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
@@ -729,21 +750,17 @@
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);
+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,
@@ -754,7 +771,7 @@
int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id,
u8 tid, int txq_id);
#else
-static inline void iwl4965_init_ht_hw_capab(struct iwl_priv *priv,
+static inline void iwl4965_init_ht_hw_capab(const struct iwl_priv *priv,
struct ieee80211_ht_info *ht_info,
enum ieee80211_band band) {}
@@ -787,8 +804,8 @@
#define IWL_EXT_CHANNEL_OFFSET_RESERVE1 2
#define IWL_EXT_CHANNEL_OFFSET_BELOW 3
-#define NRG_NUM_PREV_STAT_L 20
-#define NUM_RX_CHAINS (3)
+#define IWL_TX_CRC_SIZE 4
+#define IWL_TX_DELIMITER_SIZE 4
#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
@@ -818,23 +835,8 @@
#define MAX_FA_CCK 50
#define MIN_FA_CCK 5
-#define NRG_MIN_CCK 97
-#define NRG_MAX_CCK 0
-
-#define AUTO_CORR_MIN_OFDM 85
-#define AUTO_CORR_MIN_OFDM_MRC 170
-#define AUTO_CORR_MIN_OFDM_X1 105
-#define AUTO_CORR_MIN_OFDM_MRC_X1 220
-#define AUTO_CORR_MAX_OFDM 120
-#define AUTO_CORR_MAX_OFDM_MRC 210
-#define AUTO_CORR_MAX_OFDM_X1 140
-#define AUTO_CORR_MAX_OFDM_MRC_X1 270
#define AUTO_CORR_STEP_OFDM 1
-#define AUTO_CORR_MIN_CCK (125)
-#define AUTO_CORR_MAX_CCK (200)
-#define AUTO_CORR_MIN_CCK_MRC 200
-#define AUTO_CORR_MAX_CCK_MRC 400
#define AUTO_CORR_STEP_CCK 3
#define AUTO_CORR_MAX_TH_CCK 160
@@ -853,6 +855,9 @@
#define IN_BAND_FILTER 0xFF
#define MIN_AVERAGE_NOISE_MAX_VALUE 0xFFFFFFFF
+#define NRG_NUM_PREV_STAT_L 20
+#define NUM_RX_CHAINS 3
+
enum iwl4965_false_alarm_state {
IWL_FA_TOO_MANY = 0,
IWL_FA_TOO_FEW = 1,
@@ -865,11 +870,6 @@
IWL_CHAIN_NOISE_CALIBRATED = 2,
};
-enum iwl4965_sensitivity_state {
- IWL_SENS_CALIB_ALLOWED = 0,
- IWL_SENS_CALIB_NEED_REINIT = 1,
-};
-
enum iwl4965_calib_enabled_state {
IWL_CALIB_DISABLED = 0, /* must be 0 */
IWL_CALIB_ENABLED = 1,
@@ -884,8 +884,9 @@
u32 beacon_energy_c;
};
+#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
/* Sensitivity calib data */
-struct iwl4965_sensitivity_data {
+struct iwl_sensitivity_data {
u32 auto_corr_ofdm;
u32 auto_corr_ofdm_mrc;
u32 auto_corr_ofdm_x1;
@@ -909,12 +910,10 @@
s32 nrg_auto_corr_silence_diff;
u32 num_in_cck_no_fa;
u32 nrg_th_ofdm;
-
- u8 state;
};
/* Chain noise (differential Rx gain) calib data */
-struct iwl4965_chain_noise_data {
+struct iwl_chain_noise_data {
u8 state;
u16 beacon_count;
u32 chain_noise_a;
@@ -927,6 +926,7 @@
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) */
@@ -1007,6 +1007,9 @@
/* 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 */
@@ -1050,13 +1053,12 @@
u8 assoc_station_added;
u8 use_ant_b_for_management_frame; /* Tx antenna selection */
- u8 valid_antenna; /* Bit mask of antennas actually connected */
-#ifdef CONFIG_IWL4965_SENSITIVITY
- struct iwl4965_sensitivity_data sensitivity_data;
- struct iwl4965_chain_noise_data chain_noise_data;
u8 start_calib;
+#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
+ struct iwl_sensitivity_data sensitivity_data;
+ struct iwl_chain_noise_data chain_noise_data;
__le16 sensitivity_tbl[HD_TABLE_SIZE];
-#endif /*CONFIG_IWL4965_SENSITIVITY*/
+#endif /*CONFIG_IWLWIFI_RUN_TIME_CALIB*/
#ifdef CONFIG_IWL4965_HT
struct iwl_ht_info current_ht_config;
@@ -1092,7 +1094,7 @@
u64 bytes;
} tx_stats[3], rx_stats[3];
- struct iwl4965_power_mgr power_data;
+ struct iwl_power_mgr power_data;
struct iwl4965_notif_statistics statistics;
unsigned long last_statistics_time;
@@ -1137,7 +1139,8 @@
struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE];
/* eeprom */
- struct iwl4965_eeprom eeprom;
+ u8 *eeprom;
+ struct iwl_eeprom_calib_info *calib_info;
enum ieee80211_if_types iw_mode;
@@ -1206,7 +1209,7 @@
#endif /* CONFIG_IWLWIFI_DEBUG */
struct work_struct txpower_work;
-#ifdef CONFIG_IWL4965_SENSITIVITY
+#ifdef CONFIG_IWL4965_RUN_TIME_CALIB
struct work_struct sensitivity_work;
#endif
struct timer_list statistics_periodic;
@@ -1224,11 +1227,6 @@
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;
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index a07d5dc..fa30660 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -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 @@
}
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 @@
*/
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 @@
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 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 @@
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 @@
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 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 @@
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 @@
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 @@
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,
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index bd0a042..dc1f027 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -106,7 +106,7 @@
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 @@
/* *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 @@
* 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 */
-/* 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)
+/* 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 */
+
/* 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 @@
*
* 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 @@
/*
- * 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 @@
*
* 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 @@
* 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));
+#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
-/*
- * 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 */
+/* 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 @@
*
* 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 @@
*
* 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
index 0000000..9446424
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-fh.h
@@ -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 */
+
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
index fdb27f1..acb5a8a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -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"
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index 03fdf5b..aa6ad18 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -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
index 0000000..2e71803
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -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
index 0000000..b066724
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-power.h
@@ -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__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index c9cf8ee..acac629 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -239,40 +239,284 @@
#define ALM_SCD_SBYP_MODE_1_REG (ALM_SCD_BASE + 0x02C)
#define ALM_SCD_SBYP_MODE_2_REG (ALM_SCD_BASE + 0x030)
-/*
- * 4965 Tx Scheduler registers.
- * Details are documented in iwl-4965-hw.h
+/**
+ * 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!):
*/
-#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)
+/**
+ * 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
-/* SP SCD */
+/* 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)
+
+/*
+ * Tx Status Bitmap
+ *
+ * Driver should clear this entire area (size 0x100) to 0 after receiving
+ * "Alive" notification from uCode. Area is used only by device itself;
+ * no other support (besides clearing) is required from driver.
+ */
+#define IWL49_SCD_TX_STTS_BITMAP_OFFSET 0x400
+
+/*
+ * 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)
@@ -287,4 +531,6 @@
#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__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c
index 5980a56..59c8a71 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c
@@ -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-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index e4fdfaa..31b37a1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -28,15 +28,48 @@
*****************************************************************************/
#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_get_free_ucode_key_index(struct iwl_priv *priv)
{
@@ -172,10 +205,14 @@
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;
@@ -214,8 +251,13 @@
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;
@@ -243,8 +285,13 @@
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,13 +303,31 @@
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",
@@ -271,13 +336,16 @@
sizeof(struct iwl4965_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 = iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0);
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return ret;
}
int iwl_set_dynamic_key(struct iwl_priv *priv,
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h
index 44f272e..38b1b0a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.h
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.h
@@ -29,21 +29,14 @@
#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/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 13925b6..7040cde 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -2391,7 +2391,8 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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);
@@ -7146,7 +7143,7 @@
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 +7217,9 @@
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);
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 883b42f..4406fc7 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -46,11 +46,12 @@
#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);
@@ -98,7 +99,7 @@
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];
@@ -795,14 +796,6 @@
/* 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 +828,7 @@
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 +839,10 @@
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 +879,13 @@
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 = {
@@ -944,13 +941,6 @@
return rc;
}
-static int iwl4965_card_state_sync_callback(struct iwl_priv *priv,
- struct iwl_cmd *cmd,
- struct sk_buff *skb)
-{
- return 1;
-}
-
/*
* CARD_STATE_CMD
*
@@ -970,40 +960,9 @@
.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)
{
@@ -1016,9 +975,7 @@
.data = sta,
};
- if (flags & CMD_ASYNC)
- cmd.meta.u.callback = iwl4965_add_sta_sync_callback;
- else
+ if (!(flags & CMD_ASYNC))
cmd.meta.flags |= CMD_WANT_SKB;
rc = iwl_send_cmd(priv, &cmd);
@@ -1116,17 +1073,29 @@
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 +1113,7 @@
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 +1131,6 @@
*
******************************************************************************/
-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 +1160,91 @@
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 +1256,8 @@
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 +1340,19 @@
if (*pos > 0)
len += 2 + *pos;
-#ifdef CONFIG_IWL4965_HT
- if (sband && sband->ht_info.ht_supported) {
- struct ieee80211_ht_cap *ht_cap;
- pos += (*pos) + 1;
- *pos++ = WLAN_EID_HT_CAPABILITY;
- *pos++ = sizeof(struct ieee80211_ht_cap);
- ht_cap = (struct ieee80211_ht_cap *)pos;
- ht_cap->cap_info = cpu_to_le16(sband->ht_info.cap);
- memcpy(ht_cap->supp_mcs_set, sband->ht_info.supp_mcs_set, 16);
- ht_cap->ampdu_params_info =(sband->ht_info.ampdu_factor &
- IEEE80211_HT_CAP_AMPDU_FACTOR) |
- ((sband->ht_info.ampdu_density << 2) &
- IEEE80211_HT_CAP_AMPDU_DENSITY);
- len += 2 + sizeof(struct ieee80211_ht_cap);
- }
-#endif /*CONFIG_IWL4965_HT */
-
fill_end:
+ /* fill in HT IE */
+ left -= 2;
+ if (left < 0)
+ return 0;
+
+ *pos++ = WLAN_EID_HT_CAPABILITY;
+ *pos = 0;
+
+ iwl_ht_cap_to_ie(sband, pos, &left);
+
+ if (*pos > 0)
+ len += 2 + *pos;
return (u16)len;
}
@@ -1376,184 +1405,6 @@
}
}
-/*
- * Power management (not Tx power!) functions
- */
-#define MSEC_TO_USEC 1024
-
-#define NOSLP __constant_cpu_to_le16(0), 0, 0
-#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0
-#define SLP_TIMEOUT(T) __constant_cpu_to_le32((T) * MSEC_TO_USEC)
-#define SLP_VEC(X0, X1, X2, X3, X4) {__constant_cpu_to_le32(X0), \
- __constant_cpu_to_le32(X1), \
- __constant_cpu_to_le32(X2), \
- __constant_cpu_to_le32(X3), \
- __constant_cpu_to_le32(X4)}
-
-
-/* default power management (not Tx power) table values */
-/* for tim 0-10 */
-static struct iwl4965_power_vec_entry range_0[IWL_POWER_AC] = {
- {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
- {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
- {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0},
- {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), SLP_VEC(2, 6, 9, 9, 10)}, 0},
- {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 10)}, 1},
- {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1}
-};
-
-/* for tim > 10 */
-static struct iwl4965_power_vec_entry range_1[IWL_POWER_AC] = {
- {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
- {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500),
- SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
- {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300),
- SLP_VEC(2, 4, 6, 7, 0xFF)}, 0},
- {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100),
- SLP_VEC(2, 6, 9, 9, 0xFF)}, 0},
- {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
- {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25),
- SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
-};
-
-int iwl4965_power_init_handle(struct iwl_priv *priv)
-{
- int rc = 0, i;
- struct iwl4965_power_mgr *pow_data;
- int size = sizeof(struct iwl4965_power_vec_entry) * IWL_POWER_AC;
- u16 pci_pm;
-
- IWL_DEBUG_POWER("Initialize power \n");
-
- pow_data = &(priv->power_data);
-
- memset(pow_data, 0, sizeof(*pow_data));
-
- pow_data->active_index = IWL_POWER_RANGE_0;
- pow_data->dtim_val = 0xffff;
-
- memcpy(&pow_data->pwr_range_0[0], &range_0[0], size);
- memcpy(&pow_data->pwr_range_1[0], &range_1[0], size);
-
- rc = pci_read_config_word(priv->pci_dev, PCI_LINK_CTRL, &pci_pm);
- if (rc != 0)
- return 0;
- else {
- struct iwl4965_powertable_cmd *cmd;
-
- IWL_DEBUG_POWER("adjust power command flags\n");
-
- for (i = 0; i < IWL_POWER_AC; i++) {
- cmd = &pow_data->pwr_range_0[i].cmd;
-
- if (pci_pm & 0x1)
- cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
- else
- cmd->flags |= IWL_POWER_PCI_PM_MSK;
- }
- }
- return rc;
-}
-
-static int iwl4965_update_power_cmd(struct iwl_priv *priv,
- struct iwl4965_powertable_cmd *cmd, u32 mode)
-{
- int rc = 0, i;
- u8 skip;
- u32 max_sleep = 0;
- struct iwl4965_power_vec_entry *range;
- u8 period = 0;
- struct iwl4965_power_mgr *pow_data;
-
- if (mode > IWL_POWER_INDEX_5) {
- IWL_DEBUG_POWER("Error invalid power mode \n");
- return -1;
- }
- pow_data = &(priv->power_data);
-
- if (pow_data->active_index == IWL_POWER_RANGE_0)
- range = &pow_data->pwr_range_0[0];
- else
- range = &pow_data->pwr_range_1[1];
-
- memcpy(cmd, &range[mode].cmd, sizeof(struct iwl4965_powertable_cmd));
-
-#ifdef IWL_MAC80211_DISABLE
- if (priv->assoc_network != NULL) {
- unsigned long flags;
-
- period = priv->assoc_network->tim.tim_period;
- }
-#endif /*IWL_MAC80211_DISABLE */
- skip = range[mode].no_dtim;
-
- if (period == 0) {
- period = 1;
- skip = 0;
- }
-
- if (skip == 0) {
- max_sleep = period;
- cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
- } else {
- __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1];
- max_sleep = (le32_to_cpu(slp_itrvl) / period) * period;
- cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
- }
-
- for (i = 0; i < IWL_POWER_VEC_SIZE; i++) {
- if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep)
- cmd->sleep_interval[i] = cpu_to_le32(max_sleep);
- }
-
- IWL_DEBUG_POWER("Flags value = 0x%08X\n", cmd->flags);
- IWL_DEBUG_POWER("Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout));
- IWL_DEBUG_POWER("Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout));
- IWL_DEBUG_POWER("Sleep interval vector = { %d , %d , %d , %d , %d }\n",
- le32_to_cpu(cmd->sleep_interval[0]),
- le32_to_cpu(cmd->sleep_interval[1]),
- le32_to_cpu(cmd->sleep_interval[2]),
- le32_to_cpu(cmd->sleep_interval[3]),
- le32_to_cpu(cmd->sleep_interval[4]));
-
- return rc;
-}
-
-static int iwl4965_send_power_mode(struct iwl_priv *priv, u32 mode)
-{
- u32 uninitialized_var(final_mode);
- int rc;
- struct iwl4965_powertable_cmd cmd;
-
- /* If on battery, set to 3,
- * if plugged into AC power, set to CAM ("continuously aware mode"),
- * else user level */
- switch (mode) {
- case IWL_POWER_BATTERY:
- final_mode = IWL_POWER_INDEX_3;
- break;
- case IWL_POWER_AC:
- final_mode = IWL_POWER_MODE_CAM;
- break;
- default:
- final_mode = mode;
- break;
- }
-
- cmd.keep_alive_beacons = 0;
-
- iwl4965_update_power_cmd(priv, &cmd, final_mode);
-
- rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd);
-
- if (final_mode == IWL_POWER_MODE_CAM)
- clear_bit(STATUS_POWER_PMI, &priv->status);
- else
- set_bit(STATUS_POWER_PMI, &priv->status);
-
- return rc;
-}
-
int iwl4965_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
{
/* Filter incoming packets to determine if they are targeted toward
@@ -1884,7 +1735,7 @@
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)
@@ -1936,7 +1787,7 @@
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 +1806,11 @@
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 +1937,7 @@
/* 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 +1945,7 @@
/* 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;
@@ -2196,7 +2047,7 @@
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) {
@@ -2367,7 +2218,7 @@
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 +2317,6 @@
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)
@@ -2710,8 +2522,6 @@
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,
@@ -2788,7 +2598,7 @@
return IWL_AP_ID;
else {
u8 *da = ieee80211_get_DA(hdr);
- return iwl4965_hw_find_station(priv, da);
+ return iwl_find_station(priv, da);
}
}
@@ -2847,8 +2657,6 @@
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;
@@ -3008,9 +2816,6 @@
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),
@@ -3425,7 +3230,7 @@
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);
}
/**
@@ -4620,7 +4425,7 @@
u16 active_dwell = 0;
int added, i;
- sband = iwl4965_get_hw_mode(priv, band);
+ sband = iwl_get_hw_mode(priv, band);
if (!sband)
return 0;
@@ -4652,9 +4457,6 @@
if (scan_ch->type & 1)
scan_ch->type |= (direct_mask << 1);
- if (is_channel_narrow(ch_info))
- scan_ch->type |= (1 << 7);
-
scan_ch->active_dwell = cpu_to_le16(active_dwell);
scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
@@ -4687,163 +4489,6 @@
return added;
}
-static void iwl4965_init_hw_rates(struct iwl_priv *priv,
- struct ieee80211_rate *rates)
-{
- int i;
-
- for (i = 0; i < IWL_RATE_COUNT; i++) {
- rates[i].bitrate = iwl4965_rates[i].ieee * 5;
- rates[i].hw_value = i; /* Rate scaling will work on indexes */
- rates[i].hw_value_short = i;
- rates[i].flags = 0;
- if ((i > IWL_LAST_OFDM_RATE) || (i < IWL_FIRST_OFDM_RATE)) {
- /*
- * If CCK != 1M then set short preamble rate flag.
- */
- rates[i].flags |=
- (iwl4965_rates[i].plcp == IWL_RATE_1M_PLCP) ?
- 0 : IEEE80211_RATE_SHORT_PREAMBLE;
- }
- }
-}
-
-/**
- * iwl4965_init_geos - Initialize mac80211's geo/channel info based from eeprom
- */
-int iwl4965_init_geos(struct iwl_priv *priv)
-{
- struct iwl_channel_info *ch;
- struct ieee80211_supported_band *sband;
- struct ieee80211_channel *channels;
- struct ieee80211_channel *geo_ch;
- struct ieee80211_rate *rates;
- int i = 0;
-
- if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates ||
- priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) {
- IWL_DEBUG_INFO("Geography modes already initialized.\n");
- set_bit(STATUS_GEO_CONFIGURED, &priv->status);
- return 0;
- }
-
- channels = kzalloc(sizeof(struct ieee80211_channel) *
- priv->channel_count, GFP_KERNEL);
- if (!channels)
- return -ENOMEM;
-
- rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_RATE_COUNT + 1)),
- GFP_KERNEL);
- if (!rates) {
- kfree(channels);
- return -ENOMEM;
- }
-
- /* 5.2GHz channels start after the 2.4GHz channels */
- sband = &priv->bands[IEEE80211_BAND_5GHZ];
- sband->channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
- /* just OFDM */
- sband->bitrates = &rates[IWL_FIRST_OFDM_RATE];
- sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE;
-
- iwl4965_init_ht_hw_capab(priv, &sband->ht_info, IEEE80211_BAND_5GHZ);
-
- sband = &priv->bands[IEEE80211_BAND_2GHZ];
- sband->channels = channels;
- /* OFDM & CCK */
- sband->bitrates = rates;
- sband->n_bitrates = IWL_RATE_COUNT;
-
- iwl4965_init_ht_hw_capab(priv, &sband->ht_info, IEEE80211_BAND_2GHZ);
-
- priv->ieee_channels = channels;
- priv->ieee_rates = rates;
-
- iwl4965_init_hw_rates(priv, rates);
-
- for (i = 0; i < priv->channel_count; i++) {
- ch = &priv->channel_info[i];
-
- /* FIXME: might be removed if scan is OK */
- if (!is_channel_valid(ch))
- continue;
-
- if (is_channel_a_band(ch))
- sband = &priv->bands[IEEE80211_BAND_5GHZ];
- else
- sband = &priv->bands[IEEE80211_BAND_2GHZ];
-
- geo_ch = &sband->channels[sband->n_channels++];
-
- geo_ch->center_freq = ieee80211_channel_to_frequency(ch->channel);
- geo_ch->max_power = ch->max_power_avg;
- geo_ch->max_antenna_gain = 0xff;
- geo_ch->hw_value = ch->channel;
-
- if (is_channel_valid(ch)) {
- if (!(ch->flags & EEPROM_CHANNEL_IBSS))
- geo_ch->flags |= IEEE80211_CHAN_NO_IBSS;
-
- if (!(ch->flags & EEPROM_CHANNEL_ACTIVE))
- geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
-
- if (ch->flags & EEPROM_CHANNEL_RADAR)
- geo_ch->flags |= IEEE80211_CHAN_RADAR;
-
- if (ch->max_power_avg > priv->max_channel_txpower_limit)
- priv->max_channel_txpower_limit =
- ch->max_power_avg;
- } else {
- geo_ch->flags |= IEEE80211_CHAN_DISABLED;
- }
-
- /* Save flags for reg domain usage */
- geo_ch->orig_flags = geo_ch->flags;
-
- IWL_DEBUG_INFO("Channel %d Freq=%d[%sGHz] %s flag=0%X\n",
- ch->channel, geo_ch->center_freq,
- is_channel_a_band(ch) ? "5.2" : "2.4",
- geo_ch->flags & IEEE80211_CHAN_DISABLED ?
- "restricted" : "valid",
- geo_ch->flags);
- }
-
- if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) &&
- priv->cfg->sku & IWL_SKU_A) {
- printk(KERN_INFO DRV_NAME
- ": Incorrectly detected BG card as ABG. Please send "
- "your PCI ID 0x%04X:0x%04X to maintainer.\n",
- priv->pci_dev->device, priv->pci_dev->subsystem_device);
- priv->cfg->sku &= ~IWL_SKU_A;
- }
-
- printk(KERN_INFO DRV_NAME
- ": Tunable channels: %d 802.11bg, %d 802.11a channels\n",
- priv->bands[IEEE80211_BAND_2GHZ].n_channels,
- priv->bands[IEEE80211_BAND_5GHZ].n_channels);
-
- if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
- priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
- &priv->bands[IEEE80211_BAND_2GHZ];
- if (priv->bands[IEEE80211_BAND_5GHZ].n_channels)
- priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
- &priv->bands[IEEE80211_BAND_5GHZ];
-
- set_bit(STATUS_GEO_CONFIGURED, &priv->status);
-
- return 0;
-}
-
-/*
- * iwl4965_free_geos - undo allocations in iwl4965_init_geos
- */
-void iwl4965_free_geos(struct iwl_priv *priv)
-{
- kfree(priv->ieee_channels);
- kfree(priv->ieee_rates);
- clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
-}
-
/******************************************************************************
*
* uCode download functions
@@ -4860,146 +4505,6 @@
iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot);
}
-/**
- * iwl4965_verify_inst_full - verify runtime uCode image in card vs. host,
- * looking at all data.
- */
-static int iwl4965_verify_inst_full(struct iwl_priv *priv, __le32 *image,
- u32 len)
-{
- u32 val;
- u32 save_len = len;
- int rc = 0;
- u32 errcnt;
-
- IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
-
- rc = iwl_grab_nic_access(priv);
- if (rc)
- return rc;
-
- iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND);
-
- errcnt = 0;
- for (; len > 0; len -= sizeof(u32), image++) {
- /* read data comes through single port, auto-incr addr */
- /* NOTE: Use the debugless read so we don't flood kernel log
- * if IWL_DL_IO is set */
- val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
- if (val != le32_to_cpu(*image)) {
- IWL_ERROR("uCode INST section is invalid at "
- "offset 0x%x, is 0x%x, s/b 0x%x\n",
- save_len - len, val, le32_to_cpu(*image));
- rc = -EIO;
- errcnt++;
- if (errcnt >= 20)
- break;
- }
- }
-
- iwl_release_nic_access(priv);
-
- if (!errcnt)
- IWL_DEBUG_INFO
- ("ucode image in INSTRUCTION memory is good\n");
-
- return rc;
-}
-
-
-/**
- * iwl4965_verify_inst_sparse - verify runtime uCode image in card vs. host,
- * using sample data 100 bytes apart. If these sample points are good,
- * it's a pretty good bet that everything between them is good, too.
- */
-static int iwl4965_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
-{
- u32 val;
- int rc = 0;
- u32 errcnt = 0;
- u32 i;
-
- IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
-
- rc = iwl_grab_nic_access(priv);
- if (rc)
- return rc;
-
- for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
- /* read data comes through single port, auto-incr addr */
- /* NOTE: Use the debugless read so we don't flood kernel log
- * if IWL_DL_IO is set */
- iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
- i + RTC_INST_LOWER_BOUND);
- val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
- if (val != le32_to_cpu(*image)) {
-#if 0 /* Enable this if you want to see details */
- IWL_ERROR("uCode INST section is invalid at "
- "offset 0x%x, is 0x%x, s/b 0x%x\n",
- i, val, *image);
-#endif
- rc = -EIO;
- errcnt++;
- if (errcnt >= 3)
- break;
- }
- }
-
- iwl_release_nic_access(priv);
-
- return rc;
-}
-
-
-/**
- * iwl4965_verify_ucode - determine which instruction image is in SRAM,
- * and verify its contents
- */
-static int iwl4965_verify_ucode(struct iwl_priv *priv)
-{
- __le32 *image;
- u32 len;
- int rc = 0;
-
- /* Try bootstrap */
- image = (__le32 *)priv->ucode_boot.v_addr;
- len = priv->ucode_boot.len;
- rc = iwl4965_verify_inst_sparse(priv, image, len);
- if (rc == 0) {
- IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n");
- return 0;
- }
-
- /* Try initialize */
- image = (__le32 *)priv->ucode_init.v_addr;
- len = priv->ucode_init.len;
- rc = iwl4965_verify_inst_sparse(priv, image, len);
- if (rc == 0) {
- IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n");
- return 0;
- }
-
- /* Try runtime/protocol */
- image = (__le32 *)priv->ucode_code.v_addr;
- len = priv->ucode_code.len;
- rc = iwl4965_verify_inst_sparse(priv, image, len);
- if (rc == 0) {
- IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n");
- return 0;
- }
-
- IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
-
- /* Since nothing seems to match, show first several data entries in
- * instruction SRAM, so maybe visual inspection will give a clue.
- * Selection of bootstrap image (vs. other images) is arbitrary. */
- image = (__le32 *)priv->ucode_boot.v_addr;
- len = priv->ucode_boot.len;
- rc = iwl4965_verify_inst_full(priv, image, len);
-
- return rc;
-}
-
static void iwl4965_nic_start(struct iwl_priv *priv)
{
/* Remove all resets to allow NIC to operate */
@@ -5075,34 +4580,34 @@
}
/* 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);
@@ -5275,7 +4780,7 @@
/* 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)) {
+ 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");
@@ -5323,7 +4828,7 @@
/* 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 +4858,6 @@
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 +4988,7 @@
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,6 +5050,12 @@
iwl_rfkill_set_hw_state(priv);
iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+ ret = priv->cfg->ops->lib->alloc_shared_mem(priv);
+ if (ret) {
+ IWL_ERROR("Unable to allocate shared memory\n");
+ return ret;
+ }
+
ret = priv->cfg->ops->lib->hw_nic_init(priv);
if (ret) {
IWL_ERROR("Unable to init nic\n");
@@ -5887,6 +5397,8 @@
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;
@@ -5991,7 +5503,7 @@
if (priv->current_ht_config.is_ht)
iwl4965_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 +5552,16 @@
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;
}
@@ -6338,7 +5849,7 @@
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 +5921,7 @@
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);
@@ -6592,64 +6103,6 @@
}
-
-#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 +6133,7 @@
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 +6233,7 @@
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));
@@ -6827,7 +6280,7 @@
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 +6289,7 @@
/* 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 +6326,7 @@
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 +6339,7 @@
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;
@@ -6960,9 +6413,9 @@
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);
@@ -7004,7 +6457,7 @@
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 +6494,8 @@
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 +6544,7 @@
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);
@@ -7372,20 +6827,11 @@
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 +6861,7 @@
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 +6879,14 @@
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 +6939,6 @@
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)
{
@@ -7613,7 +7021,6 @@
}
static struct attribute *iwl4965_sysfs_entries[] = {
- &dev_attr_antenna.attr,
&dev_attr_channels.attr,
&dev_attr_dump_errors.attr,
&dev_attr_dump_events.attr,
@@ -7711,13 +7118,19 @@
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 +7156,30 @@
(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);
+ /* amp init */
+ err = priv->cfg->ops->lib->apm_ops.init(priv);
+ if (err < 0) {
+ IWL_DEBUG_INFO("Failed to init APMG\n");
+ goto out_iounmap;
+ }
/*****************
* 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);
- if (err < 0) {
- IWL_DEBUG_INFO("Failed to init the card\n");
- goto out_iounmap;
- }
/* 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 +7191,7 @@
/* 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 +7200,7 @@
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 +7226,7 @@
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 +7250,8 @@
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:
@@ -7900,8 +7313,8 @@
iwl4965_rx_queue_free(priv, &priv->rxq);
iwl4965_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 +7332,7 @@
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 +7382,11 @@
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);
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h
index 3dfc2d4..4295bc6 100644
--- a/drivers/net/wireless/libertas/cmd.h
+++ b/drivers/net/wireless/libertas/cmd.h
@@ -44,7 +44,7 @@
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);
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index b652fa3..0632b09 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -64,9 +64,9 @@
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);
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 406f54d..0be8957 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -702,7 +702,7 @@
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);
@@ -889,7 +889,7 @@
}
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);
@@ -905,7 +905,6 @@
netif_device_attach(priv->mesh_dev);
lbs_deb_leave(LBS_DEB_FW);
- return 0;
}
EXPORT_SYMBOL_GPL(lbs_resume);
@@ -1155,7 +1154,7 @@
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;
@@ -1167,8 +1166,8 @@
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) {
@@ -1190,7 +1189,6 @@
free_netdev(dev);
lbs_deb_leave(LBS_DEB_MAIN);
- return 0;
}
EXPORT_SYMBOL_GPL(lbs_remove_card);
@@ -1261,15 +1259,17 @@
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);
@@ -1279,6 +1279,7 @@
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;
@@ -1289,8 +1290,8 @@
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);
@@ -1532,10 +1533,11 @@
{
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);
}
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
index 06d2c67..c6f27b9 100644
--- a/drivers/net/wireless/p54/p54.h
+++ b/drivers/net/wireless/p54/p54.h
@@ -64,7 +64,7 @@
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);
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
index 63f9bad..33d608a 100644
--- a/drivers/net/wireless/p54/p54common.c
+++ b/drivers/net/wireless/p54/p54common.c
@@ -146,10 +146,10 @@
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;
}
}
@@ -379,7 +379,7 @@
* 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 @@
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 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 @@
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 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 @@
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 @@
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;
}
@@ -1008,7 +1004,7 @@
dev->channel_change_time = 1000; /* TODO: find actual value */
dev->max_rssi = 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 +
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index ab1029e..0ace761 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -5,12 +5,16 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
---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"
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 560b9c7..247fbbf 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -1055,11 +1055,11 @@
* 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, ®);
if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) {
rt2x00_set_field32(®, CSR14_TSF_COUNT, 1);
@@ -1071,12 +1071,9 @@
}
rt2x00pci_register_read(rt2x00dev, TXCSR0, ®);
- rt2x00_set_field32(®, TXCSR0_KICK_PRIO,
- (queue == IEEE80211_TX_QUEUE_DATA0));
- rt2x00_set_field32(®, TXCSR0_KICK_TX,
- (queue == IEEE80211_TX_QUEUE_DATA1));
- rt2x00_set_field32(®, TXCSR0_KICK_ATIM,
- (queue == RT2X00_BCN_QUEUE_ATIM));
+ rt2x00_set_field32(®, TXCSR0_KICK_PRIO, (queue == QID_AC_BE));
+ rt2x00_set_field32(®, TXCSR0_KICK_TX, (queue == QID_AC_BK));
+ rt2x00_set_field32(®, TXCSR0_KICK_ATIM, (queue == QID_ATIM));
rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
}
@@ -1120,7 +1117,7 @@
* 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 @@
* 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;
}
@@ -1445,8 +1442,7 @@
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 +1452,7 @@
* 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))
@@ -1521,20 +1517,13 @@
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;
}
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index a5ed54b..0d53c75 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -317,8 +317,7 @@
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 @@
* 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, ®);
if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) {
rt2x00_set_field32(®, CSR14_TSF_COUNT, 1);
@@ -1226,12 +1225,9 @@
}
rt2x00pci_register_read(rt2x00dev, TXCSR0, ®);
- rt2x00_set_field32(®, TXCSR0_KICK_PRIO,
- (queue == IEEE80211_TX_QUEUE_DATA0));
- rt2x00_set_field32(®, TXCSR0_KICK_TX,
- (queue == IEEE80211_TX_QUEUE_DATA1));
- rt2x00_set_field32(®, TXCSR0_KICK_ATIM,
- (queue == RT2X00_BCN_QUEUE_ATIM));
+ rt2x00_set_field32(®, TXCSR0_KICK_PRIO, (queue == QID_AC_BE));
+ rt2x00_set_field32(®, TXCSR0_KICK_TX, (queue == QID_AC_BK));
+ rt2x00_set_field32(®, TXCSR0_KICK_ATIM, (queue == QID_ATIM));
rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
}
@@ -1276,7 +1272,7 @@
* 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 @@
* 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;
}
@@ -1834,20 +1830,13 @@
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;
}
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index fdbd0ef..80b34d4 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -76,10 +76,10 @@
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 @@
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 @@
* 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, ®);
@@ -1720,12 +1720,6 @@
rt2x00_set_field16(®, 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 @@
/*
* Enable beacon generation.
*/
- rt2500usb_kick_tx_queue(rt2x00dev, control->queue);
+ rt2500usb_kick_tx_queue(rt2x00dev, QID_BEACON);
return 0;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 57bdc15..79bd9c9 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -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 @@
* @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 @@
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 @@
/*
* Driver features
*/
- DRIVER_SUPPORT_MIXED_INTERFACES,
DRIVER_REQUIRE_FIRMWARE,
DRIVER_REQUIRE_BEACON_GUARD,
DRIVER_REQUIRE_ATIM_QUEUE,
@@ -928,17 +927,16 @@
}
/**
- * 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 @@
/**
* 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 @@
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);
/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index b22c027..61510c5 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -525,9 +525,6 @@
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++;
@@ -687,8 +684,7 @@
* 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);
/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index c206b50..767e0ff 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -81,6 +81,7 @@
{
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 @@
*/
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 @@
* 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 @@
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 @@
{
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 @@
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 @@
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 @@
}
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;
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index 971af25..c17078e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -53,7 +53,7 @@
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;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h
index 9d1cdb9..2b0ef17 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.h
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.h
@@ -98,8 +98,9 @@
* 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_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 {
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 659e9f4..e5b861f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -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 @@
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;
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index 7027c9f..d1707a7 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -54,6 +54,17 @@
/**
* 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 @@
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 @@
* 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 @@
* 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,
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 5a33167..98aafc2 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -186,7 +186,7 @@
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 @@
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, 0, 0,
REGISTER_TIMEOUT);
/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h
index 11e5518..4da9eb3 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.h
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.h
@@ -47,6 +47,20 @@
#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 @@
* 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));
}
/*
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 14bc7b2..b64f2f5 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1591,11 +1591,11 @@
* 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 @@
}
rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, ®);
- rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC0,
- (queue == IEEE80211_TX_QUEUE_DATA0));
- rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC1,
- (queue == IEEE80211_TX_QUEUE_DATA1));
- rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC2,
- (queue == IEEE80211_TX_QUEUE_DATA2));
- rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC3,
- (queue == IEEE80211_TX_QUEUE_DATA3));
+ rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC0, (queue == QID_AC_BE));
+ rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC1, (queue == QID_AC_BK));
+ rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC2, (queue == QID_AC_VI));
+ rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC3, (queue == QID_AC_VO));
rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
}
@@ -2400,24 +2396,17 @@
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;
}
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index da19a3a..351d95c 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -74,10 +74,10 @@
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 @@
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 @@
char *ptr = data;
char *cache;
int buflen;
- int timeout;
/*
* Wait for stable hardware.
@@ -907,14 +906,14 @@
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 @@
* 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;
/*
@@ -1966,7 +1965,6 @@
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))
@@ -2001,23 +1999,16 @@
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;
}
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
index 57c4ccf..f883dcf 100644
--- a/drivers/ssb/pci.c
+++ b/drivers/ssb/pci.c
@@ -510,17 +510,15 @@
sprom_do_read(bus, buf);
err = sprom_check_crc(buf, bus->sprom_size);
if (err) {
- /* check for rev 4 sprom - has special signature */
- if (buf[32] == 0x5372) {
- kfree(buf);
- buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
- GFP_KERNEL);
- if (!buf)
- goto out;
- bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
- sprom_do_read(bus, buf);
- err = sprom_check_crc(buf, bus->sprom_size);
- }
+ /* try for a 440 byte SPROM - revision 4 and higher */
+ kfree(buf);
+ buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
+ GFP_KERNEL);
+ if (!buf)
+ goto out;
+ bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
+ sprom_do_read(bus, buf);
+ err = sprom_check_crc(buf, bus->sprom_size);
if (err)
ssb_printk(KERN_WARNING PFX "WARNING: Invalid"
" SPROM CRC (corrupt SPROM)\n");
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index 529816b..b31399e 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -1262,9 +1262,6 @@
/* 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_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)
{
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 4a80d74..75a3460 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -98,6 +98,18 @@
};
/**
+ * 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
*
* The information provided in this structure is required for QoS
@@ -117,58 +129,18 @@
};
/**
- * 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 @@
/* 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 @@
/* 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 @@
* 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 */
@@ -410,8 +393,6 @@
* @ampdu_ack_map: block ack bit map for the aggregation.
* relevant only if IEEE80211_TX_STATUS_AMPDU was set.
* @ack_signal: signal strength of the ACK frame
- * @queue_length: ?? REMOVE
- * @queue_number: ?? REMOVE
*/
struct ieee80211_tx_status {
struct ieee80211_tx_control control;
@@ -421,8 +402,6 @@
u8 ampdu_ack_len;
u64 ampdu_ack_map;
int ack_signal;
- int queue_length;
- int queue_number;
};
/**
@@ -610,11 +589,14 @@
* @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,
};
/**
@@ -766,7 +748,14 @@
* @max_noise: like @max_rssi, but for the noise value.
*
* @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,7 +774,7 @@
unsigned int extra_tx_headroom;
int channel_change_time;
int vif_data_size;
- u8 queues;
+ u16 queues, ampdu_queues;
s8 max_rssi;
s8 max_signal;
s8 max_noise;
@@ -1063,15 +1052,13 @@
* 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 +1132,7 @@
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);
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index 90b1e8d..5672d48 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -179,6 +179,8 @@
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);
/*
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 0ce0443..e111517 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -300,6 +300,7 @@
/* 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 @@
/* 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 @@
* : 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 @@
/* SACK delay timeout */
unsigned long sackdelay;
+ __u32 sackfreq;
unsigned long timeouts[SCTP_NUM_TIMEOUT_TYPES];
diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h
index 9619b9d..f205b10 100644
--- a/include/net/sctp/user.h
+++ b/include/net/sctp/user.h
@@ -93,8 +93,9 @@
#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 @@
#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 @@
};
-/* 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;
diff --git a/include/net/tipc/tipc_port.h b/include/net/tipc/tipc_port.h
index 11105bc..9923e41 100644
--- a/include/net/tipc/tipc_port.h
+++ b/include/net/tipc/tipc_port.h
@@ -84,7 +84,8 @@
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);
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c
index d8b0260..d996547 100644
--- a/net/ieee80211/ieee80211_tx.c
+++ b/net/ieee80211/ieee80211_tx.c
@@ -542,90 +542,4 @@
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);
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
index 623489a..822606b 100644
--- a/net/ieee80211/ieee80211_wx.c
+++ b/net/ieee80211/ieee80211_wx.c
@@ -744,98 +744,9 @@
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);
diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c
index 59f1691..4d4c2df 100644
--- a/net/mac80211/aes_ccm.c
+++ b/net/mac80211/aes_ccm.c
@@ -134,7 +134,7 @@
}
-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;
diff --git a/net/mac80211/aes_ccm.h b/net/mac80211/aes_ccm.h
index 885f190..8cd0f14 100644
--- a/net/mac80211/aes_ccm.h
+++ b/net/mac80211/aes_ccm.h
@@ -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);
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 1cccbfd..d20d90e 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -197,45 +197,6 @@
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 @@
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 @@
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);
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index e3326d0..3ae5493 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -528,7 +528,7 @@
add_files(sdata);
}
-static int netdev_notify(struct notifier_block * nb,
+static int netdev_notify(struct notifier_block *nb,
unsigned long state,
void *ndev)
{
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 6d47a1d..676a932 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -123,36 +123,6 @@
}
STA_OPS(last_seq_ctrl);
-#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
-static ssize_t sta_wme_rx_queue_read(struct file *file, char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- char buf[15*NUM_RX_DATA_QUEUES], *p = buf;
- int i;
- struct sta_info *sta = file->private_data;
- for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
- p += scnprintf(p, sizeof(buf)+buf-p, "%u ",
- sta->wme_rx_queue[i]);
- p += scnprintf(p, sizeof(buf)+buf-p, "\n");
- return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
-}
-STA_OPS(wme_rx_queue);
-
-static ssize_t sta_wme_tx_queue_read(struct file *file, char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- char buf[15*NUM_TX_DATA_QUEUES], *p = buf;
- int i;
- struct sta_info *sta = file->private_data;
- for (i = 0; i < NUM_TX_DATA_QUEUES; i++)
- p += scnprintf(p, sizeof(buf)+buf-p, "%u ",
- sta->wme_tx_queue[i]);
- p += scnprintf(p, sizeof(buf)+buf-p, "\n");
- return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
-}
-STA_OPS(wme_tx_queue);
-#endif
-
static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
@@ -293,10 +263,6 @@
DEBUGFS_ADD(num_ps_buf_frames);
DEBUGFS_ADD(inactive_ms);
DEBUGFS_ADD(last_seq_ctrl);
-#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
- DEBUGFS_ADD(wme_rx_queue);
- DEBUGFS_ADD(wme_tx_queue);
-#endif
DEBUGFS_ADD(agg_status);
}
@@ -306,10 +272,6 @@
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);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index c7314bf..d82ed20 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -610,8 +610,8 @@
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_AMPDU_QUEUES + IEEE80211_MAX_AMPDU_QUEUES];
+ struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_AMPDU_QUEUES];
struct tasklet_struct tx_pending_tasklet;
/* number of interfaces with corresponding IFF_ flags */
@@ -705,8 +705,6 @@
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 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 @@
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_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,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 06e88a5..4a8062f 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -33,9 +33,8 @@
{
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. */
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 150d66d..88b211a 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -323,6 +323,13 @@
*/
if (sta->flags & 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;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 915afad..eb347ec 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -385,8 +385,8 @@
* 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);
}
@@ -1482,7 +1482,7 @@
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));
@@ -1745,6 +1745,11 @@
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 */
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 4adba09..5d7719f 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -87,6 +87,7 @@
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 @@
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);
}
}
@@ -305,29 +295,25 @@
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 +713,8 @@
if (bss) {
if (bss->capability & WLAN_CAPABILITY_PRIVACY)
capab |= WLAN_CAPABILITY_PRIVACY;
- if (bss->wmm_ie) {
+ if (bss->wmm_ie)
wmm = 1;
- }
ieee80211_rx_bss_put(dev, bss);
}
@@ -1134,8 +1119,8 @@
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);
@@ -1183,9 +1168,7 @@
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 "
@@ -1447,8 +1430,7 @@
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 "
@@ -1652,7 +1634,7 @@
* 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
@@ -1841,9 +1823,8 @@
" (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 ||
@@ -3553,10 +3534,12 @@
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++) {
@@ -4239,6 +4222,7 @@
{
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;
@@ -4256,9 +4240,9 @@
}
-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;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 1958bfb..9b5a3cb 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -275,11 +275,6 @@
}
}
- 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. */
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 7d4fe4a..631943e 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -257,7 +257,7 @@
* 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;
diff --git a/net/mac80211/tkip.h b/net/mac80211/tkip.h
index b7c2ee7..1fa0bb4 100644
--- a/net/mac80211/tkip.h
+++ b/net/mac80211/tkip.h
@@ -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,
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c
index affcecd..3cbae42 100644
--- a/net/mac80211/wep.c
+++ b/net/mac80211/wep.c
@@ -337,7 +337,7 @@
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;
diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h
index 363779c..e587172 100644
--- a/net/mac80211/wep.h
+++ b/net/mac80211/wep.h
@@ -26,7 +26,7 @@
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);
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index dc1598b..c87baf4 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -19,16 +19,22 @@
#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 @@
/* 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 @@
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 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/* 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 @@
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 @@
/* 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 @@
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 @@
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 @@
}
}
- /* 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_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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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);
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 45709ad..42f3654 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -228,7 +228,7 @@
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 @@
!(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 @@
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 @@
!(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;
}
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index b4cd2b7..7b79d1e 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -136,6 +136,7 @@
/* 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 @@
* 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 @@
* association configured value.
*/
peer->sackdelay = asoc->sackdelay;
+ peer->sackfreq = asoc->sackfreq;
/* Enable/disable heartbeat, SACK delay, and path MTU discovery
* based on association setting.
diff --git a/net/sctp/proc.c b/net/sctp/proc.c
index 0aba759..5dd8983 100644
--- a/net/sctp/proc.c
+++ b/net/sctp/proc.c
@@ -383,3 +383,144 @@
{
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);
+}
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 0ec234b..b8bd9e0 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -113,6 +113,8 @@
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 @@
sctp_snmp_proc_exit();
sctp_eps_proc_exit();
sctp_assocs_proc_exit();
+ sctp_remaddr_proc_exit();
if (proc_net_sctp) {
proc_net_sctp = NULL;
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index 23a9f1a..b083312 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -190,20 +190,28 @@
* 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 @@
goto nomem;
asoc->peer.sack_needed = 0;
+ asoc->peer.sack_cnt = 0;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(sack));
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index e7e3baf..81600eea0 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -956,7 +956,8 @@
*/
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 @@
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 @@
/* 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 @@
* 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 @@
* 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 @@
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 @@
return 0;
}
-/* 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_assoc_value {
- * sctp_assoc_t assoc_id;
- * uint32_t assoc_value;
- * };
+ * 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))
+ if (optlen == sizeof(struct sctp_sack_info)) {
+ if (copy_from_user(¶ms, 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(¶ms, optval, optlen))
+ return -EFAULT;
+
+ if (params.sack_delay == 0)
+ params.sack_freq = 1;
+ else
+ params.sack_freq = 0;
+ } else
return - EINVAL;
- if (copy_from_user(¶ms, optval, optlen))
- return -EFAULT;
-
/* 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 @@
(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 @@
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 @@
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 @@
/* 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 @@
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 @@
return 0;
}
-/* 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_assoc_value {
- * sctp_assoc_t assoc_id;
- * uint32_t assoc_value;
- * };
+ * 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))
+ if (len >= sizeof(struct sctp_sack_info)) {
+ len = sizeof(struct sctp_sack_info);
+
+ if (copy_from_user(¶ms, 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(¶ms, optval, len))
+ return -EFAULT;
+ } else
return - EINVAL;
- len = sizeof(struct sctp_assoc_value);
-
- if (copy_from_user(¶ms, optval, len))
- return -EFAULT;
-
- /* 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, ¶ms, len))
@@ -5218,8 +5330,8 @@
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:
diff --git a/net/tipc/config.c b/net/tipc/config.c
index c71337a..91d56f8 100644
--- a/net/tipc/config.c
+++ b/net/tipc/config.c
@@ -529,7 +529,7 @@
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();
diff --git a/net/tipc/core.c b/net/tipc/core.c
index 740aac5..6d6aa5a 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -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
@@ -182,7 +182,7 @@
{
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 +209,7 @@
tipc_core_stop_net();
tipc_core_stop();
info("Deactivated\n");
- tipc_log_stop();
+ tipc_log_resize(0);
}
module_init(tipc_init);
diff --git a/net/tipc/core.h b/net/tipc/core.h
index 5a0e487..bd78d17 100644
--- a/net/tipc/core.h
+++ b/net/tipc/core.h
@@ -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
@@ -59,84 +59,108 @@
#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)
+#define TIPC_OUTPUT TIPC_LOG
#endif
-#ifndef DBG_OUTPUT
-#define DBG_OUTPUT TIPC_NULL
-#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
/*
- * 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.
+ * 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.
*/
-#undef TIPC_OUTPUT
-#define TIPC_OUTPUT TIPC_CONS
-
-#undef DBG_OUTPUT
+#ifndef DBG_OUTPUT
#define DBG_OUTPUT TIPC_NULL
+#endif
+
+/*
+ * TIPC can be configured to send debug messages to the specified print buffer
+ * (typically DBG_OUTPUT) or to suppress them entirely.
+ */
+
+#ifdef CONFIG_TIPC_DEBUG
+
+#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
diff --git a/net/tipc/dbg.c b/net/tipc/dbg.c
index e809d2a..29ecae8 100644
--- a/net/tipc/dbg.c
+++ b/net/tipc/dbg.c
@@ -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
@@ -38,18 +38,44 @@
#include "config.h"
#include "dbg.h"
+/*
+ * 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, 0 };
+struct print_buf *const TIPC_NULL = &null_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, 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);
-static struct print_buf null_buf = { NULL, 0, NULL, NULL };
-struct print_buf *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 log_buf = { NULL, 0, NULL, NULL };
-struct print_buf *TIPC_LOG = &log_buf;
-
#define FORMAT(PTR,LEN,FMT) \
{\
@@ -60,27 +86,14 @@
*(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 @@
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_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 @@
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 @@
}
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 @@
}
/**
- * 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,67 +231,39 @@
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;
}
+
+ if (pb->echo)
+ printk(print_string);
+
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.
- */
-
-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 @@
}
/**
- * 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 @@
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 *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;
}
diff --git a/net/tipc/dbg.h b/net/tipc/dbg.h
index c01b085..5ef1bc8 100644
--- a/net/tipc/dbg.h
+++ b/net/tipc/dbg.h
@@ -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
@@ -42,14 +42,14 @@
* @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_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
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 2a26a16..bd206eb 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -147,9 +147,21 @@
#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 @@
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) {
diff --git a/net/tipc/msg.c b/net/tipc/msg.c
index 696a863..38abeba 100644
--- a/net/tipc/msg.c
+++ b/net/tipc/msg.c
@@ -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 @@
}
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
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
index 39fd161..aecba5c 100644
--- a/net/tipc/name_distr.c
+++ b/net/tipc/name_distr.c
@@ -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)
/**
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index ac7dfdd..892373e 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -1050,15 +1050,12 @@
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;
}
diff --git a/net/tipc/port.c b/net/tipc/port.c
index 2f58064..757de38 100644
--- a/net/tipc/port.c
+++ b/net/tipc/port.c
@@ -211,15 +211,18 @@
}
/**
- * 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 @@
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 @@
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;
}
@@ -1053,6 +1055,7 @@
{
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 +1063,13 @@
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;
diff --git a/net/tipc/ref.c b/net/tipc/ref.c
index 89cbab2..a101de8 100644
--- a/net/tipc/ref.c
+++ b/net/tipc/ref.c
@@ -142,9 +142,13 @@
/**
* 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 @@
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;
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 230f9ca..38f4879 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -188,6 +188,7 @@
const struct proto_ops *ops;
socket_state state;
struct sock *sk;
+ struct tipc_port *tp_ptr;
u32 portref;
/* Validate arguments */
@@ -225,7 +226,7 @@
/* 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 @@
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)
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c
index 8c01ccd..8f8d0a6 100644
--- a/net/tipc/subscr.c
+++ b/net/tipc/subscr.c
@@ -474,6 +474,7 @@
kfree(subscriber);
return;
}
+ spin_unlock_bh(subscriber->lock);
/* Establish a connection to subscriber */