Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
Conflicts:
drivers/net/smc911x.c
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index a0cda06..8e6b8d3 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -289,35 +289,73 @@
fail_over_mac
Specifies whether active-backup mode should set all slaves to
- the same MAC address (the traditional behavior), or, when
- enabled, change the bond's MAC address when changing the
- active interface (i.e., fail over the MAC address itself).
+ the same MAC address at enslavement (the traditional
+ behavior), or, when enabled, perform special handling of the
+ bond's MAC address in accordance with the selected policy.
- Fail over MAC is useful for devices that cannot ever alter
- their MAC address, or for devices that refuse incoming
- broadcasts with their own source MAC (which interferes with
- the ARP monitor).
+ Possible values are:
- The down side of fail over MAC is that every device on the
- network must be updated via gratuitous ARP, vs. just updating
- a switch or set of switches (which often takes place for any
- traffic, not just ARP traffic, if the switch snoops incoming
- traffic to update its tables) for the traditional method. If
- the gratuitous ARP is lost, communication may be disrupted.
+ none or 0
- When fail over MAC is used in conjuction with the mii monitor,
- devices which assert link up prior to being able to actually
- transmit and receive are particularly susecptible to loss of
- the gratuitous ARP, and an appropriate updelay setting may be
- required.
+ This setting disables fail_over_mac, and causes
+ bonding to set all slaves of an active-backup bond to
+ the same MAC address at enslavement time. This is the
+ default.
- A value of 0 disables fail over MAC, and is the default. A
- value of 1 enables fail over MAC. This option is enabled
- automatically if the first slave added cannot change its MAC
- address. This option may be modified via sysfs only when no
- slaves are present in the bond.
+ active or 1
- This option was added in bonding version 3.2.0.
+ The "active" fail_over_mac policy indicates that the
+ MAC address of the bond should always be the MAC
+ address of the currently active slave. The MAC
+ address of the slaves is not changed; instead, the MAC
+ address of the bond changes during a failover.
+
+ This policy is useful for devices that cannot ever
+ alter their MAC address, or for devices that refuse
+ incoming broadcasts with their own source MAC (which
+ interferes with the ARP monitor).
+
+ The down side of this policy is that every device on
+ the network must be updated via gratuitous ARP,
+ vs. just updating a switch or set of switches (which
+ often takes place for any traffic, not just ARP
+ traffic, if the switch snoops incoming traffic to
+ update its tables) for the traditional method. If the
+ gratuitous ARP is lost, communication may be
+ disrupted.
+
+ When this policy is used in conjuction with the mii
+ monitor, devices which assert link up prior to being
+ able to actually transmit and receive are particularly
+ susecptible to loss of the gratuitous ARP, and an
+ appropriate updelay setting may be required.
+
+ follow or 2
+
+ The "follow" fail_over_mac policy causes the MAC
+ address of the bond to be selected normally (normally
+ the MAC address of the first slave added to the bond).
+ However, the second and subsequent slaves are not set
+ to this MAC address while they are in a backup role; a
+ slave is programmed with the bond's MAC address at
+ failover time (and the formerly active slave receives
+ the newly active slave's MAC address).
+
+ This policy is useful for multiport devices that
+ either become confused or incur a performance penalty
+ when multiple ports are programmed with the same MAC
+ address.
+
+
+ The default policy is none, unless the first slave cannot
+ change its MAC address, in which case the active policy is
+ selected by default.
+
+ This option may be modified via sysfs only when no slaves are
+ present in the bond.
+
+ This option was added in bonding version 3.2.0. The "follow"
+ policy was added in bonding version 3.3.0.
lacp_rate
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index 1d2a7725..46a9dba 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -58,6 +58,7 @@
o) Xilinx IP cores
p) Freescale Synchronous Serial Interface
q) USB EHCI controllers
+ r) MDIO on GPIOs
VII - Marvell Discovery mv64[345]6x System Controller chips
1) The /system-controller node
@@ -2870,6 +2871,26 @@
reg = <0xe8000000 32>;
};
+ r) MDIO on GPIOs
+
+ Currently defined compatibles:
+ - virtual,gpio-mdio
+
+ MDC and MDIO lines connected to GPIO controllers are listed in the
+ gpios property as described in section VIII.1 in the following order:
+
+ MDC, MDIO.
+
+ Example:
+
+ mdio {
+ compatible = "virtual,mdio-gpio";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ gpios = <&qe_pio_a 11
+ &qe_pio_c 6>;
+ };
+
VII - Marvell Discovery mv64[345]6x System Controller chips
===========================================================
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 075598e..71a58a4 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -71,6 +71,7 @@
config BT_HCIUART_BCSP
bool "BCSP protocol support"
depends on BT_HCIUART
+ select CONFIG_BITREVERSE
help
BCSP (BlueCore Serial Protocol) is serial protocol for communication
between Bluetooth device and host. This protocol is required for non
diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c
index 696f752..4d37bb3 100644
--- a/drivers/bluetooth/hci_bcsp.c
+++ b/drivers/bluetooth/hci_bcsp.c
@@ -39,6 +39,8 @@
#include <linux/signal.h>
#include <linux/ioctl.h>
#include <linux/skbuff.h>
+#include <linux/bitrev.h>
+#include <asm/unaligned.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -124,27 +126,6 @@
*crc = reg;
}
-/*
- Get reverse of generated crc
-
- Implementation note
- The crc generator (bcsp_crc_init() and bcsp_crc_update())
- creates a reversed crc, so it needs to be swapped back before
- being passed on.
-*/
-static u16 bcsp_crc_reverse(u16 crc)
-{
- u16 b, rev;
-
- for (b = 0, rev = 0; b < 16; b++) {
- rev = rev << 1;
- rev |= (crc & 1);
- crc = crc >> 1;
- }
-
- return (rev);
-}
-
/* ---- BCSP core ---- */
static void bcsp_slip_msgdelim(struct sk_buff *skb)
@@ -235,10 +216,10 @@
}
if (hciextn && chan == 5) {
- struct hci_command_hdr *hdr = (struct hci_command_hdr *) data;
+ __le16 opcode = ((struct hci_command_hdr *)data)->opcode;
/* Vendor specific commands */
- if (hci_opcode_ogf(__le16_to_cpu(hdr->opcode)) == 0x3f) {
+ if (hci_opcode_ogf(__le16_to_cpu(opcode)) == 0x3f) {
u8 desc = *(data + HCI_COMMAND_HDR_SIZE);
if ((desc & 0xf0) == 0xc0) {
data += HCI_COMMAND_HDR_SIZE + 1;
@@ -296,7 +277,7 @@
/* Put CRC */
if (bcsp->use_crc) {
- bcsp_txmsg_crc = bcsp_crc_reverse(bcsp_txmsg_crc);
+ bcsp_txmsg_crc = bitrev16(bcsp_txmsg_crc);
bcsp_slip_one_byte(nskb, (u8) ((bcsp_txmsg_crc >> 8) & 0x00ff));
bcsp_slip_one_byte(nskb, (u8) (bcsp_txmsg_crc & 0x00ff));
}
@@ -566,6 +547,11 @@
bcsp->rx_skb = NULL;
}
+static u16 bscp_get_crc(struct bcsp_struct *bcsp)
+{
+ return get_unaligned_be16(&bcsp->rx_skb->data[bcsp->rx_skb->len - 2]);
+}
+
/* Recv data */
static int bcsp_recv(struct hci_uart *hu, void *data, int count)
{
@@ -624,14 +610,10 @@
continue;
case BCSP_W4_CRC:
- if (bcsp_crc_reverse(bcsp->message_crc) !=
- (bcsp->rx_skb->data[bcsp->rx_skb->len - 2] << 8) +
- bcsp->rx_skb->data[bcsp->rx_skb->len - 1]) {
-
+ if (bitrev16(bcsp->message_crc) != bscp_get_crc(bcsp)) {
BT_ERR ("Checksum failed: computed %04x received %04x",
- bcsp_crc_reverse(bcsp->message_crc),
- (bcsp->rx_skb-> data[bcsp->rx_skb->len - 2] << 8) +
- bcsp->rx_skb->data[bcsp->rx_skb->len - 1]);
+ bitrev16(bcsp->message_crc),
+ bscp_get_crc(bcsp));
kfree_skb(bcsp->rx_skb);
bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index 105a8c7..e4e3241 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -572,12 +572,16 @@
int irq;
DECLARE_MAC_BUF(mac);
+#ifdef __ISAPNP__
if (idev) {
irq = pnp_irq(idev, 0);
vp->dev = &idev->dev;
} else {
irq = inw(ioaddr + 0x2002) & 15;
}
+#else
+ irq = inw(ioaddr + 0x2002) & 15;
+#endif
dev->base_addr = ioaddr;
dev->irq = irq;
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/Kconfig b/drivers/net/Kconfig
index f4182cf..20b5367 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -524,6 +524,18 @@
If unsure, say N.
+config SH_ETH
+ tristate "Renesas SuperH Ethernet support"
+ depends on SUPERH && \
+ (CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712)
+ select CRC32
+ select MII
+ select MDIO_BITBANG
+ select PHYLIB
+ help
+ Renesas SuperH Ethernet device driver.
+ This driver support SH7710 and SH7712.
+
config SUNLANCE
tristate "Sun LANCE support"
depends on SBUS
@@ -955,7 +967,7 @@
tristate "SMSC LAN911[5678] support"
select CRC32
select MII
- depends on ARCH_PXA || SH_MAGIC_PANEL_R2
+ depends on ARCH_PXA || SUPERH
help
This is a driver for SMSC's LAN911x series of Ethernet chipsets
including the new LAN9115, LAN9116, LAN9117, and LAN9118.
@@ -1670,7 +1682,7 @@
config TLAN
tristate "TI ThunderLAN support"
- depends on NET_PCI && (PCI || EISA) && !64BIT
+ depends on NET_PCI && (PCI || EISA)
---help---
If you have a PCI Ethernet network card based on the ThunderLAN chip
which is supported by this driver, say Y and read the
@@ -2228,6 +2240,7 @@
config TIGON3
tristate "Broadcom Tigon3 support"
depends on PCI
+ select PHYLIB
help
This driver supports Broadcom Tigon3 based gigabit Ethernet cards.
@@ -2283,6 +2296,19 @@
the driver automatically distinguishes the models, you can
safely enable this option even if you have a wireless-less model.
+config GELIC_WIRELESS_OLD_PSK_INTERFACE
+ bool "PS3 Wireless private PSK interface (OBSOLETE)"
+ depends on GELIC_WIRELESS
+ help
+ This option retains the obsolete private interface to pass
+ the PSK from user space programs to the driver. The PSK
+ stands for 'Pre Shared Key' and is used for WPA[2]-PSK
+ (WPA-Personal) environment.
+ If WPA[2]-PSK is used and you need to use old programs that
+ support only this old interface, say Y. Otherwise N.
+
+ If unsure, say N.
+
config GIANFAR
tristate "Gianfar Ethernet"
depends on FSL_SOC
@@ -2407,8 +2433,9 @@
config CHELSIO_T3
tristate "Chelsio Communications T3 10Gb Ethernet support"
- depends on PCI
+ depends on PCI && INET
select FW_LOADER
+ select INET_LRO
help
This driver supports Chelsio T3-based gigabit and 10Gb Ethernet
adapters.
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index dcbfe84..c96fe20 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -80,6 +80,7 @@
obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o
obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
obj-$(CONFIG_RIONET) += rionet.o
+obj-$(CONFIG_SH_ETH) += sh_eth.o
#
# end link order section
@@ -236,6 +237,7 @@
obj-$(CONFIG_USB_KAWETH) += usb/
obj-$(CONFIG_USB_PEGASUS) += usb/
obj-$(CONFIG_USB_RTL8150) += usb/
+obj-$(CONFIG_USB_HSO) += usb/
obj-$(CONFIG_USB_USBNET) += usb/
obj-$(CONFIG_USB_ZD1201) += usb/
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index 6c5719a..9c08374 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -475,16 +475,12 @@
return IRQ_HANDLED;
}
-struct net_device *last_dev;
-
static int lance_open (struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
volatile struct lance_regs *ll = lp->ll;
int ret;
- last_dev = dev;
-
/* Stop the Lance */
ll->rap = LE_CSR0;
ll->rdp = LE_C0_STOP;
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/atarilance.c b/drivers/net/atarilance.c
index 4cceaac..0860cc280 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/atarilance.c
@@ -243,7 +243,7 @@
/* Possible memory/IO addresses for probing */
-struct lance_addr {
+static struct lance_addr {
unsigned long memaddr;
unsigned long ioaddr;
int slow_flag;
diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c
index 99e0b4c..919ffb9 100644
--- a/drivers/net/atlx/atl1.c
+++ b/drivers/net/atlx/atl1.c
@@ -1860,7 +1860,8 @@
rfd_desc = ATL1_RFD_DESC(rfd_ring, rfd_next_to_use);
- skb = dev_alloc_skb(adapter->rx_buffer_len + NET_IP_ALIGN);
+ skb = netdev_alloc_skb(adapter->netdev,
+ adapter->rx_buffer_len + NET_IP_ALIGN);
if (unlikely(!skb)) {
/* Better luck next round */
adapter->net_stats.rx_dropped++;
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 367b6d4..2c52d2c 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -56,8 +56,8 @@
#define DRV_MODULE_NAME "bnx2"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "1.7.5"
-#define DRV_MODULE_RELDATE "April 29, 2008"
+#define DRV_MODULE_VERSION "1.7.6"
+#define DRV_MODULE_RELDATE "May 16, 2008"
#define RUN_AT(x) (jiffies + (x))
@@ -1875,7 +1875,7 @@
}
static int
-bnx2_init_5709s_phy(struct bnx2 *bp)
+bnx2_init_5709s_phy(struct bnx2 *bp, int reset_phy)
{
u32 val;
@@ -1890,7 +1890,8 @@
bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD);
bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
- bnx2_reset_phy(bp);
+ if (reset_phy)
+ bnx2_reset_phy(bp);
bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG);
@@ -1924,11 +1925,12 @@
}
static int
-bnx2_init_5708s_phy(struct bnx2 *bp)
+bnx2_init_5708s_phy(struct bnx2 *bp, int reset_phy)
{
u32 val;
- bnx2_reset_phy(bp);
+ if (reset_phy)
+ bnx2_reset_phy(bp);
bp->mii_up1 = BCM5708S_UP1;
@@ -1981,9 +1983,10 @@
}
static int
-bnx2_init_5706s_phy(struct bnx2 *bp)
+bnx2_init_5706s_phy(struct bnx2 *bp, int reset_phy)
{
- bnx2_reset_phy(bp);
+ if (reset_phy)
+ bnx2_reset_phy(bp);
bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
@@ -2018,11 +2021,12 @@
}
static int
-bnx2_init_copper_phy(struct bnx2 *bp)
+bnx2_init_copper_phy(struct bnx2 *bp, int reset_phy)
{
u32 val;
- bnx2_reset_phy(bp);
+ if (reset_phy)
+ bnx2_reset_phy(bp);
if (bp->phy_flags & BNX2_PHY_FLAG_CRC_FIX) {
bnx2_write_phy(bp, 0x18, 0x0c00);
@@ -2070,7 +2074,7 @@
static int
-bnx2_init_phy(struct bnx2 *bp)
+bnx2_init_phy(struct bnx2 *bp, int reset_phy)
{
u32 val;
int rc = 0;
@@ -2096,14 +2100,14 @@
if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
if (CHIP_NUM(bp) == CHIP_NUM_5706)
- rc = bnx2_init_5706s_phy(bp);
+ rc = bnx2_init_5706s_phy(bp, reset_phy);
else if (CHIP_NUM(bp) == CHIP_NUM_5708)
- rc = bnx2_init_5708s_phy(bp);
+ rc = bnx2_init_5708s_phy(bp, reset_phy);
else if (CHIP_NUM(bp) == CHIP_NUM_5709)
- rc = bnx2_init_5709s_phy(bp);
+ rc = bnx2_init_5709s_phy(bp, reset_phy);
}
else {
- rc = bnx2_init_copper_phy(bp);
+ rc = bnx2_init_copper_phy(bp, reset_phy);
}
setup_phy:
@@ -2620,7 +2624,7 @@
pci_dma_sync_single_for_device(bp->pdev,
pci_unmap_addr(cons_rx_buf, mapping),
- bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
+ BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
bnapi->rx_prod_bseq += bp->rx_buf_use_size;
@@ -2658,7 +2662,7 @@
return err;
}
- skb_reserve(skb, bp->rx_offset);
+ skb_reserve(skb, BNX2_RX_OFFSET);
pci_unmap_single(bp->pdev, dma_addr, bp->rx_buf_use_size,
PCI_DMA_FROMDEVICE);
@@ -2773,7 +2777,8 @@
dma_addr = pci_unmap_addr(rx_buf, mapping);
pci_dma_sync_single_for_cpu(bp->pdev, dma_addr,
- bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
+ BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH,
+ PCI_DMA_FROMDEVICE);
rx_hdr = (struct l2_fhdr *) skb->data;
len = rx_hdr->l2_fhdr_pkt_len;
@@ -2811,7 +2816,8 @@
}
/* aligned copy */
- skb_copy_from_linear_data_offset(skb, bp->rx_offset - 2,
+ skb_copy_from_linear_data_offset(skb,
+ BNX2_RX_OFFSET - 2,
new_skb->data, len + 2);
skb_reserve(new_skb, 2);
skb_put(new_skb, len);
@@ -3213,7 +3219,7 @@
}
static int
-load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
+load_cpu_fw(struct bnx2 *bp, const struct cpu_reg *cpu_reg, struct fw_info *fw)
{
u32 offset;
u32 val;
@@ -3297,7 +3303,6 @@
static int
bnx2_init_cpus(struct bnx2 *bp)
{
- struct cpu_reg cpu_reg;
struct fw_info *fw;
int rc, rv2p_len;
void *text, *rv2p;
@@ -3333,122 +3338,57 @@
load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC2);
/* Initialize the RX Processor. */
- cpu_reg.mode = BNX2_RXP_CPU_MODE;
- cpu_reg.mode_value_halt = BNX2_RXP_CPU_MODE_SOFT_HALT;
- cpu_reg.mode_value_sstep = BNX2_RXP_CPU_MODE_STEP_ENA;
- cpu_reg.state = BNX2_RXP_CPU_STATE;
- cpu_reg.state_value_clear = 0xffffff;
- cpu_reg.gpr0 = BNX2_RXP_CPU_REG_FILE;
- cpu_reg.evmask = BNX2_RXP_CPU_EVENT_MASK;
- cpu_reg.pc = BNX2_RXP_CPU_PROGRAM_COUNTER;
- cpu_reg.inst = BNX2_RXP_CPU_INSTRUCTION;
- cpu_reg.bp = BNX2_RXP_CPU_HW_BREAKPOINT;
- cpu_reg.spad_base = BNX2_RXP_SCRATCH;
- cpu_reg.mips_view_base = 0x8000000;
-
if (CHIP_NUM(bp) == CHIP_NUM_5709)
fw = &bnx2_rxp_fw_09;
else
fw = &bnx2_rxp_fw_06;
fw->text = text;
- rc = load_cpu_fw(bp, &cpu_reg, fw);
+ rc = load_cpu_fw(bp, &cpu_reg_rxp, fw);
if (rc)
goto init_cpu_err;
/* Initialize the TX Processor. */
- cpu_reg.mode = BNX2_TXP_CPU_MODE;
- cpu_reg.mode_value_halt = BNX2_TXP_CPU_MODE_SOFT_HALT;
- cpu_reg.mode_value_sstep = BNX2_TXP_CPU_MODE_STEP_ENA;
- cpu_reg.state = BNX2_TXP_CPU_STATE;
- cpu_reg.state_value_clear = 0xffffff;
- cpu_reg.gpr0 = BNX2_TXP_CPU_REG_FILE;
- cpu_reg.evmask = BNX2_TXP_CPU_EVENT_MASK;
- cpu_reg.pc = BNX2_TXP_CPU_PROGRAM_COUNTER;
- cpu_reg.inst = BNX2_TXP_CPU_INSTRUCTION;
- cpu_reg.bp = BNX2_TXP_CPU_HW_BREAKPOINT;
- cpu_reg.spad_base = BNX2_TXP_SCRATCH;
- cpu_reg.mips_view_base = 0x8000000;
-
if (CHIP_NUM(bp) == CHIP_NUM_5709)
fw = &bnx2_txp_fw_09;
else
fw = &bnx2_txp_fw_06;
fw->text = text;
- rc = load_cpu_fw(bp, &cpu_reg, fw);
+ rc = load_cpu_fw(bp, &cpu_reg_txp, fw);
if (rc)
goto init_cpu_err;
/* Initialize the TX Patch-up Processor. */
- cpu_reg.mode = BNX2_TPAT_CPU_MODE;
- cpu_reg.mode_value_halt = BNX2_TPAT_CPU_MODE_SOFT_HALT;
- cpu_reg.mode_value_sstep = BNX2_TPAT_CPU_MODE_STEP_ENA;
- cpu_reg.state = BNX2_TPAT_CPU_STATE;
- cpu_reg.state_value_clear = 0xffffff;
- cpu_reg.gpr0 = BNX2_TPAT_CPU_REG_FILE;
- cpu_reg.evmask = BNX2_TPAT_CPU_EVENT_MASK;
- cpu_reg.pc = BNX2_TPAT_CPU_PROGRAM_COUNTER;
- cpu_reg.inst = BNX2_TPAT_CPU_INSTRUCTION;
- cpu_reg.bp = BNX2_TPAT_CPU_HW_BREAKPOINT;
- cpu_reg.spad_base = BNX2_TPAT_SCRATCH;
- cpu_reg.mips_view_base = 0x8000000;
-
if (CHIP_NUM(bp) == CHIP_NUM_5709)
fw = &bnx2_tpat_fw_09;
else
fw = &bnx2_tpat_fw_06;
fw->text = text;
- rc = load_cpu_fw(bp, &cpu_reg, fw);
+ rc = load_cpu_fw(bp, &cpu_reg_tpat, fw);
if (rc)
goto init_cpu_err;
/* Initialize the Completion Processor. */
- cpu_reg.mode = BNX2_COM_CPU_MODE;
- cpu_reg.mode_value_halt = BNX2_COM_CPU_MODE_SOFT_HALT;
- cpu_reg.mode_value_sstep = BNX2_COM_CPU_MODE_STEP_ENA;
- cpu_reg.state = BNX2_COM_CPU_STATE;
- cpu_reg.state_value_clear = 0xffffff;
- cpu_reg.gpr0 = BNX2_COM_CPU_REG_FILE;
- cpu_reg.evmask = BNX2_COM_CPU_EVENT_MASK;
- cpu_reg.pc = BNX2_COM_CPU_PROGRAM_COUNTER;
- cpu_reg.inst = BNX2_COM_CPU_INSTRUCTION;
- cpu_reg.bp = BNX2_COM_CPU_HW_BREAKPOINT;
- cpu_reg.spad_base = BNX2_COM_SCRATCH;
- cpu_reg.mips_view_base = 0x8000000;
-
if (CHIP_NUM(bp) == CHIP_NUM_5709)
fw = &bnx2_com_fw_09;
else
fw = &bnx2_com_fw_06;
fw->text = text;
- rc = load_cpu_fw(bp, &cpu_reg, fw);
+ rc = load_cpu_fw(bp, &cpu_reg_com, fw);
if (rc)
goto init_cpu_err;
/* Initialize the Command Processor. */
- cpu_reg.mode = BNX2_CP_CPU_MODE;
- cpu_reg.mode_value_halt = BNX2_CP_CPU_MODE_SOFT_HALT;
- cpu_reg.mode_value_sstep = BNX2_CP_CPU_MODE_STEP_ENA;
- cpu_reg.state = BNX2_CP_CPU_STATE;
- cpu_reg.state_value_clear = 0xffffff;
- cpu_reg.gpr0 = BNX2_CP_CPU_REG_FILE;
- cpu_reg.evmask = BNX2_CP_CPU_EVENT_MASK;
- cpu_reg.pc = BNX2_CP_CPU_PROGRAM_COUNTER;
- cpu_reg.inst = BNX2_CP_CPU_INSTRUCTION;
- cpu_reg.bp = BNX2_CP_CPU_HW_BREAKPOINT;
- cpu_reg.spad_base = BNX2_CP_SCRATCH;
- cpu_reg.mips_view_base = 0x8000000;
-
if (CHIP_NUM(bp) == CHIP_NUM_5709)
fw = &bnx2_cp_fw_09;
else
fw = &bnx2_cp_fw_06;
fw->text = text;
- rc = load_cpu_fw(bp, &cpu_reg, fw);
+ rc = load_cpu_fw(bp, &cpu_reg_cp, fw);
init_cpu_err:
vfree(text);
@@ -4750,12 +4690,12 @@
u32 rx_size, rx_space, jumbo_size;
/* 8 for CRC and VLAN */
- rx_size = bp->dev->mtu + ETH_HLEN + bp->rx_offset + 8;
+ rx_size = bp->dev->mtu + ETH_HLEN + BNX2_RX_OFFSET + 8;
rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD +
sizeof(struct skb_shared_info);
- bp->rx_copy_thresh = RX_COPY_THRESH;
+ bp->rx_copy_thresh = BNX2_RX_COPY_THRESH;
bp->rx_pg_ring_size = 0;
bp->rx_max_pg_ring = 0;
bp->rx_max_pg_ring_idx = 0;
@@ -4770,14 +4710,14 @@
bp->rx_max_pg_ring = bnx2_find_max_ring(jumbo_size,
MAX_RX_PG_RINGS);
bp->rx_max_pg_ring_idx = (bp->rx_max_pg_ring * RX_DESC_CNT) - 1;
- rx_size = RX_COPY_THRESH + bp->rx_offset;
+ rx_size = BNX2_RX_COPY_THRESH + BNX2_RX_OFFSET;
bp->rx_copy_thresh = 0;
}
bp->rx_buf_use_size = rx_size;
/* hw alignment */
bp->rx_buf_size = bp->rx_buf_use_size + BNX2_RX_ALIGN;
- bp->rx_jumbo_thresh = rx_size - bp->rx_offset;
+ bp->rx_jumbo_thresh = rx_size - BNX2_RX_OFFSET;
bp->rx_ring_size = size;
bp->rx_max_ring = bnx2_find_max_ring(size, MAX_RX_RINGS);
bp->rx_max_ring_idx = (bp->rx_max_ring * RX_DESC_CNT) - 1;
@@ -4873,7 +4813,7 @@
}
static int
-bnx2_init_nic(struct bnx2 *bp)
+bnx2_init_nic(struct bnx2 *bp, int reset_phy)
{
int rc;
@@ -4881,7 +4821,7 @@
return rc;
spin_lock_bh(&bp->phy_lock);
- bnx2_init_phy(bp);
+ bnx2_init_phy(bp, reset_phy);
bnx2_set_link(bp);
if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
bnx2_remote_phy_event(bp);
@@ -5221,7 +5161,7 @@
rx_skb = rx_buf->skb;
rx_hdr = (struct l2_fhdr *) rx_skb->data;
- skb_reserve(rx_skb, bp->rx_offset);
+ skb_reserve(rx_skb, BNX2_RX_OFFSET);
pci_dma_sync_single_for_cpu(bp->pdev,
pci_unmap_addr(rx_buf, mapping),
@@ -5269,7 +5209,7 @@
bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
spin_lock_bh(&bp->phy_lock);
- bnx2_init_phy(bp);
+ bnx2_init_phy(bp, 1);
spin_unlock_bh(&bp->phy_lock);
if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK))
rc |= BNX2_MAC_LOOPBACK_FAILED;
@@ -5659,7 +5599,7 @@
return rc;
}
- rc = bnx2_init_nic(bp);
+ rc = bnx2_init_nic(bp, 1);
if (rc) {
bnx2_napi_disable(bp);
@@ -5691,7 +5631,7 @@
bnx2_setup_int_mode(bp, 1);
- rc = bnx2_init_nic(bp);
+ rc = bnx2_init_nic(bp, 0);
if (!rc)
rc = bnx2_request_irq(bp);
@@ -5726,7 +5666,7 @@
bnx2_netif_stop(bp);
- bnx2_init_nic(bp);
+ bnx2_init_nic(bp, 1);
atomic_set(&bp->intr_sem, 1);
bnx2_netif_start(bp);
@@ -6414,7 +6354,7 @@
if (netif_running(bp->dev)) {
bnx2_netif_stop(bp);
- bnx2_init_nic(bp);
+ bnx2_init_nic(bp, 0);
bnx2_netif_start(bp);
}
@@ -6457,7 +6397,7 @@
rc = bnx2_alloc_mem(bp);
if (rc)
return rc;
- bnx2_init_nic(bp);
+ bnx2_init_nic(bp, 0);
bnx2_netif_start(bp);
}
return 0;
@@ -6725,7 +6665,7 @@
bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
}
else {
- bnx2_init_nic(bp);
+ bnx2_init_nic(bp, 1);
bnx2_netif_start(bp);
}
@@ -7108,6 +7048,7 @@
}
pci_set_master(pdev);
+ pci_save_state(pdev);
bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
if (bp->pm_cap == 0) {
@@ -7294,8 +7235,6 @@
bp->mac_addr[4] = (u8) (reg >> 8);
bp->mac_addr[5] = (u8) reg;
- bp->rx_offset = sizeof(struct l2_fhdr) + 2;
-
bp->tx_ring_size = MAX_TX_DESC_CNT;
bnx2_set_rx_ring_size(bp, 255);
@@ -7612,11 +7551,97 @@
bnx2_set_power_state(bp, PCI_D0);
netif_device_attach(dev);
- bnx2_init_nic(bp);
+ bnx2_init_nic(bp, 1);
bnx2_netif_start(bp);
return 0;
}
+/**
+ * bnx2_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci connection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t bnx2_io_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct bnx2 *bp = netdev_priv(dev);
+
+ rtnl_lock();
+ netif_device_detach(dev);
+
+ if (netif_running(dev)) {
+ bnx2_netif_stop(bp);
+ del_timer_sync(&bp->timer);
+ bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
+ }
+
+ pci_disable_device(pdev);
+ rtnl_unlock();
+
+ /* Request a slot slot reset. */
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * bnx2_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot.
+ */
+static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct bnx2 *bp = netdev_priv(dev);
+
+ rtnl_lock();
+ if (pci_enable_device(pdev)) {
+ dev_err(&pdev->dev,
+ "Cannot re-enable PCI device after reset.\n");
+ rtnl_unlock();
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+ pci_set_master(pdev);
+ pci_restore_state(pdev);
+
+ if (netif_running(dev)) {
+ bnx2_set_power_state(bp, PCI_D0);
+ bnx2_init_nic(bp, 1);
+ }
+
+ rtnl_unlock();
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * bnx2_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells us that
+ * its OK to resume normal operation.
+ */
+static void bnx2_io_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct bnx2 *bp = netdev_priv(dev);
+
+ rtnl_lock();
+ if (netif_running(dev))
+ bnx2_netif_start(bp);
+
+ netif_device_attach(dev);
+ rtnl_unlock();
+}
+
+static struct pci_error_handlers bnx2_err_handler = {
+ .error_detected = bnx2_io_error_detected,
+ .slot_reset = bnx2_io_slot_reset,
+ .resume = bnx2_io_resume,
+};
+
static struct pci_driver bnx2_pci_driver = {
.name = DRV_MODULE_NAME,
.id_table = bnx2_pci_tbl,
@@ -7624,6 +7649,7 @@
.remove = __devexit_p(bnx2_remove_one),
.suspend = bnx2_suspend,
.resume = bnx2_resume,
+ .err_handler = &bnx2_err_handler,
};
static int __init bnx2_init(void)
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index 2377cc1..be7ccb5 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -309,6 +309,7 @@
#endif
};
+#define BNX2_RX_OFFSET (sizeof(struct l2_fhdr) + 2)
/*
* l2_context definition
@@ -6412,7 +6413,7 @@
#define MAX_ETHERNET_PACKET_SIZE 1514
#define MAX_ETHERNET_JUMBO_PACKET_SIZE 9014
-#define RX_COPY_THRESH 128
+#define BNX2_RX_COPY_THRESH 128
#define BNX2_MISC_ENABLE_DEFAULT 0x17ffffff
@@ -6627,7 +6628,6 @@
struct vlan_group *vlgrp;
#endif
- u32 rx_offset;
u32 rx_buf_use_size; /* useable size */
u32 rx_buf_size; /* with alignment */
u32 rx_copy_thresh;
diff --git a/drivers/net/bnx2_fw.h b/drivers/net/bnx2_fw.h
index 3b839d4..e4b1de4 100644
--- a/drivers/net/bnx2_fw.h
+++ b/drivers/net/bnx2_fw.h
@@ -886,6 +886,23 @@
.rodata = bnx2_COM_b06FwRodata,
};
+/* Initialized Values for the Completion Processor. */
+static const struct cpu_reg cpu_reg_com = {
+ .mode = BNX2_COM_CPU_MODE,
+ .mode_value_halt = BNX2_COM_CPU_MODE_SOFT_HALT,
+ .mode_value_sstep = BNX2_COM_CPU_MODE_STEP_ENA,
+ .state = BNX2_COM_CPU_STATE,
+ .state_value_clear = 0xffffff,
+ .gpr0 = BNX2_COM_CPU_REG_FILE,
+ .evmask = BNX2_COM_CPU_EVENT_MASK,
+ .pc = BNX2_COM_CPU_PROGRAM_COUNTER,
+ .inst = BNX2_COM_CPU_INSTRUCTION,
+ .bp = BNX2_COM_CPU_HW_BREAKPOINT,
+ .spad_base = BNX2_COM_SCRATCH,
+ .mips_view_base = 0x8000000,
+};
+
+
static u8 bnx2_CP_b06FwText[] = {
0x9d, 0xbc, 0x0d, 0x78, 0x13, 0xe7, 0x99, 0x2e, 0x7c, 0xcf, 0x48, 0xb2,
0x65, 0x5b, 0xb6, 0xc7, 0xb6, 0x0c, 0x22, 0x65, 0x41, 0x83, 0x47, 0x20,
@@ -2167,6 +2184,22 @@
.rodata = bnx2_CP_b06FwRodata,
};
+/* Initialized Values the Command Processor. */
+static const struct cpu_reg cpu_reg_cp = {
+ .mode = BNX2_CP_CPU_MODE,
+ .mode_value_halt = BNX2_CP_CPU_MODE_SOFT_HALT,
+ .mode_value_sstep = BNX2_CP_CPU_MODE_STEP_ENA,
+ .state = BNX2_CP_CPU_STATE,
+ .state_value_clear = 0xffffff,
+ .gpr0 = BNX2_CP_CPU_REG_FILE,
+ .evmask = BNX2_CP_CPU_EVENT_MASK,
+ .pc = BNX2_CP_CPU_PROGRAM_COUNTER,
+ .inst = BNX2_CP_CPU_INSTRUCTION,
+ .bp = BNX2_CP_CPU_HW_BREAKPOINT,
+ .spad_base = BNX2_CP_SCRATCH,
+ .mips_view_base = 0x8000000,
+};
+
static u8 bnx2_RXP_b06FwText[] = {
0xec, 0x5b, 0x5d, 0x70, 0x5c, 0xd7, 0x5d, 0xff, 0xdf, 0xb3, 0x2b, 0x69,
0x2d, 0x4b, 0xf2, 0x95, 0xbc, 0x71, 0x56, 0xa9, 0x92, 0xec, 0x5a, 0x57,
@@ -2946,6 +2979,22 @@
.rodata = bnx2_RXP_b06FwRodata,
};
+/* Initialized Values for the RX Processor. */
+static const struct cpu_reg cpu_reg_rxp = {
+ .mode = BNX2_RXP_CPU_MODE,
+ .mode_value_halt = BNX2_RXP_CPU_MODE_SOFT_HALT,
+ .mode_value_sstep = BNX2_RXP_CPU_MODE_STEP_ENA,
+ .state = BNX2_RXP_CPU_STATE,
+ .state_value_clear = 0xffffff,
+ .gpr0 = BNX2_RXP_CPU_REG_FILE,
+ .evmask = BNX2_RXP_CPU_EVENT_MASK,
+ .pc = BNX2_RXP_CPU_PROGRAM_COUNTER,
+ .inst = BNX2_RXP_CPU_INSTRUCTION,
+ .bp = BNX2_RXP_CPU_HW_BREAKPOINT,
+ .spad_base = BNX2_RXP_SCRATCH,
+ .mips_view_base = 0x8000000,
+};
+
static u8 bnx2_rv2p_proc1[] = {
/* Date: 12/07/2007 15:02 */
0xd5, 0x56, 0x41, 0x6b, 0x13, 0x51, 0x10, 0x9e, 0xdd, 0x6c, 0xbb, 0xdb,
@@ -3651,6 +3700,22 @@
.rodata = bnx2_TPAT_b06FwRodata,
};
+/* Initialized Values for the TX Patch-up Processor. */
+static const struct cpu_reg cpu_reg_tpat = {
+ .mode = BNX2_TPAT_CPU_MODE,
+ .mode_value_halt = BNX2_TPAT_CPU_MODE_SOFT_HALT,
+ .mode_value_sstep = BNX2_TPAT_CPU_MODE_STEP_ENA,
+ .state = BNX2_TPAT_CPU_STATE,
+ .state_value_clear = 0xffffff,
+ .gpr0 = BNX2_TPAT_CPU_REG_FILE,
+ .evmask = BNX2_TPAT_CPU_EVENT_MASK,
+ .pc = BNX2_TPAT_CPU_PROGRAM_COUNTER,
+ .inst = BNX2_TPAT_CPU_INSTRUCTION,
+ .bp = BNX2_TPAT_CPU_HW_BREAKPOINT,
+ .spad_base = BNX2_TPAT_SCRATCH,
+ .mips_view_base = 0x8000000,
+};
+
static u8 bnx2_TXP_b06FwText[] = {
0xad, 0x7b, 0x7f, 0x70, 0x9b, 0x75, 0x7a, 0xe7, 0xe7, 0xd5, 0x0f, 0x5b,
0xb2, 0x65, 0x59, 0x0e, 0x4a, 0x90, 0x77, 0xbd, 0x8d, 0x5e, 0xf4, 0xca,
@@ -4531,3 +4596,18 @@
.rodata = bnx2_TXP_b06FwRodata,
};
+/* Initialized Values for the TX Processor. */
+static const struct cpu_reg cpu_reg_txp = {
+ .mode = BNX2_TXP_CPU_MODE,
+ .mode_value_halt = BNX2_TXP_CPU_MODE_SOFT_HALT,
+ .mode_value_sstep = BNX2_TXP_CPU_MODE_STEP_ENA,
+ .state = BNX2_TXP_CPU_STATE,
+ .state_value_clear = 0xffffff,
+ .gpr0 = BNX2_TXP_CPU_REG_FILE,
+ .evmask = BNX2_TXP_CPU_EVENT_MASK,
+ .pc = BNX2_TXP_CPU_PROGRAM_COUNTER,
+ .inst = BNX2_TXP_CPU_INSTRUCTION,
+ .bp = BNX2_TXP_CPU_HW_BREAKPOINT,
+ .spad_base = BNX2_TXP_SCRATCH,
+ .mips_view_base = 0x8000000,
+};
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 50a40e4..5b4af3c 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -88,6 +88,7 @@
#define BOND_LINK_ARP_INTERV 0
static int max_bonds = BOND_DEFAULT_MAX_BONDS;
+static int num_grat_arp = 1;
static int miimon = BOND_LINK_MON_INTERV;
static int updelay = 0;
static int downdelay = 0;
@@ -99,11 +100,13 @@
static int arp_interval = BOND_LINK_ARP_INTERV;
static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, };
static char *arp_validate = NULL;
-static int fail_over_mac = 0;
+static char *fail_over_mac = NULL;
struct bond_params bonding_defaults;
module_param(max_bonds, int, 0);
MODULE_PARM_DESC(max_bonds, "Max number of bonded devices");
+module_param(num_grat_arp, int, 0644);
+MODULE_PARM_DESC(num_grat_arp, "Number of gratuitous ARP packets to send on failover event");
module_param(miimon, int, 0);
MODULE_PARM_DESC(miimon, "Link check interval in milliseconds");
module_param(updelay, int, 0);
@@ -133,8 +136,8 @@
MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form");
module_param(arp_validate, charp, 0);
MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all");
-module_param(fail_over_mac, int, 0);
-MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the same MAC. 0 of off (default), 1 for on.");
+module_param(fail_over_mac, charp, 0);
+MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the same MAC. none (default), active or follow");
/*----------------------------- Global variables ----------------------------*/
@@ -187,6 +190,13 @@
{ NULL, -1},
};
+struct bond_parm_tbl fail_over_mac_tbl[] = {
+{ "none", BOND_FOM_NONE},
+{ "active", BOND_FOM_ACTIVE},
+{ "follow", BOND_FOM_FOLLOW},
+{ NULL, -1},
+};
+
/*-------------------------- Forward declarations ---------------------------*/
static void bond_send_gratuitous_arp(struct bonding *bond);
@@ -261,14 +271,14 @@
*/
static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id)
{
- struct vlan_entry *vlan, *next;
+ struct vlan_entry *vlan;
int res = -ENODEV;
dprintk("bond: %s, vlan id %d\n", bond->dev->name, vlan_id);
write_lock_bh(&bond->lock);
- list_for_each_entry_safe(vlan, next, &bond->vlan_list, vlan_list) {
+ list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
if (vlan->vlan_id == vlan_id) {
list_del(&vlan->vlan_list);
@@ -970,6 +980,82 @@
}
}
+/*
+ * bond_do_fail_over_mac
+ *
+ * Perform special MAC address swapping for fail_over_mac settings
+ *
+ * Called with RTNL, bond->lock for read, curr_slave_lock for write_bh.
+ */
+static void bond_do_fail_over_mac(struct bonding *bond,
+ struct slave *new_active,
+ struct slave *old_active)
+{
+ u8 tmp_mac[ETH_ALEN];
+ struct sockaddr saddr;
+ int rv;
+
+ switch (bond->params.fail_over_mac) {
+ case BOND_FOM_ACTIVE:
+ if (new_active)
+ memcpy(bond->dev->dev_addr, new_active->dev->dev_addr,
+ new_active->dev->addr_len);
+ break;
+ case BOND_FOM_FOLLOW:
+ /*
+ * if new_active && old_active, swap them
+ * if just old_active, do nothing (going to no active slave)
+ * if just new_active, set new_active to bond's MAC
+ */
+ if (!new_active)
+ return;
+
+ write_unlock_bh(&bond->curr_slave_lock);
+ read_unlock(&bond->lock);
+
+ if (old_active) {
+ memcpy(tmp_mac, new_active->dev->dev_addr, ETH_ALEN);
+ memcpy(saddr.sa_data, old_active->dev->dev_addr,
+ ETH_ALEN);
+ saddr.sa_family = new_active->dev->type;
+ } else {
+ memcpy(saddr.sa_data, bond->dev->dev_addr, ETH_ALEN);
+ saddr.sa_family = bond->dev->type;
+ }
+
+ rv = dev_set_mac_address(new_active->dev, &saddr);
+ if (rv) {
+ printk(KERN_ERR DRV_NAME
+ ": %s: Error %d setting MAC of slave %s\n",
+ bond->dev->name, -rv, new_active->dev->name);
+ goto out;
+ }
+
+ if (!old_active)
+ goto out;
+
+ memcpy(saddr.sa_data, tmp_mac, ETH_ALEN);
+ saddr.sa_family = old_active->dev->type;
+
+ rv = dev_set_mac_address(old_active->dev, &saddr);
+ if (rv)
+ printk(KERN_ERR DRV_NAME
+ ": %s: Error %d setting MAC of slave %s\n",
+ bond->dev->name, -rv, new_active->dev->name);
+out:
+ read_lock(&bond->lock);
+ write_lock_bh(&bond->curr_slave_lock);
+ break;
+ default:
+ printk(KERN_ERR DRV_NAME
+ ": %s: bond_do_fail_over_mac impossible: bad policy %d\n",
+ bond->dev->name, bond->params.fail_over_mac);
+ break;
+ }
+
+}
+
+
/**
* find_best_interface - select the best available slave to be the active one
* @bond: our bonding struct
@@ -1037,7 +1123,8 @@
* because it is apparently the best available slave we have, even though its
* updelay hasn't timed out yet.
*
- * Warning: Caller must hold curr_slave_lock for writing.
+ * If new_active is not NULL, caller must hold bond->lock for read and
+ * curr_slave_lock for write_bh.
*/
void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
{
@@ -1048,6 +1135,8 @@
}
if (new_active) {
+ new_active->jiffies = jiffies;
+
if (new_active->link == BOND_LINK_BACK) {
if (USES_PRIMARY(bond->params.mode)) {
printk(KERN_INFO DRV_NAME
@@ -1059,7 +1148,6 @@
new_active->delay = 0;
new_active->link = BOND_LINK_UP;
- new_active->jiffies = jiffies;
if (bond->params.mode == BOND_MODE_8023AD) {
bond_3ad_handle_link_change(new_active, BOND_LINK_UP);
@@ -1103,20 +1191,21 @@
bond_set_slave_active_flags(new_active);
}
- /* when bonding does not set the slave MAC address, the bond MAC
- * address is the one of the active slave.
- */
if (new_active && bond->params.fail_over_mac)
- memcpy(bond->dev->dev_addr, new_active->dev->dev_addr,
- new_active->dev->addr_len);
+ bond_do_fail_over_mac(bond, new_active, old_active);
+
+ bond->send_grat_arp = bond->params.num_grat_arp;
if (bond->curr_active_slave &&
test_bit(__LINK_STATE_LINKWATCH_PENDING,
&bond->curr_active_slave->dev->state)) {
dprintk("delaying gratuitous arp on %s\n",
bond->curr_active_slave->dev->name);
- bond->send_grat_arp = 1;
- } else
- bond_send_gratuitous_arp(bond);
+ } else {
+ if (bond->send_grat_arp > 0) {
+ bond_send_gratuitous_arp(bond);
+ bond->send_grat_arp--;
+ }
+ }
}
}
@@ -1129,7 +1218,7 @@
* - The primary_slave has got its link back.
* - A slave has got its link back and there's no old curr_active_slave.
*
- * Warning: Caller must hold curr_slave_lock for writing.
+ * Caller must hold bond->lock for read and curr_slave_lock for write_bh.
*/
void bond_select_active_slave(struct bonding *bond)
{
@@ -1376,14 +1465,14 @@
printk(KERN_WARNING DRV_NAME
": %s: Warning: The first slave device "
"specified does not support setting the MAC "
- "address. Enabling the fail_over_mac option.",
+ "address. Setting fail_over_mac to active.",
bond_dev->name);
- bond->params.fail_over_mac = 1;
- } else if (!bond->params.fail_over_mac) {
+ bond->params.fail_over_mac = BOND_FOM_ACTIVE;
+ } else if (bond->params.fail_over_mac != BOND_FOM_ACTIVE) {
printk(KERN_ERR DRV_NAME
": %s: Error: The slave device specified "
"does not support setting the MAC address, "
- "but fail_over_mac is not enabled.\n"
+ "but fail_over_mac is not set to active.\n"
, bond_dev->name);
res = -EOPNOTSUPP;
goto err_undo_flags;
@@ -1490,6 +1579,10 @@
bond_compute_features(bond);
+ write_unlock_bh(&bond->lock);
+
+ read_lock(&bond->lock);
+
new_slave->last_arp_rx = jiffies;
if (bond->params.miimon && !bond->params.use_carrier) {
@@ -1566,6 +1659,8 @@
}
}
+ write_lock_bh(&bond->curr_slave_lock);
+
switch (bond->params.mode) {
case BOND_MODE_ACTIVEBACKUP:
bond_set_slave_inactive_flags(new_slave);
@@ -1613,9 +1708,11 @@
break;
} /* switch(bond_mode) */
+ write_unlock_bh(&bond->curr_slave_lock);
+
bond_set_carrier(bond);
- write_unlock_bh(&bond->lock);
+ read_unlock(&bond->lock);
res = bond_create_slave_symlinks(bond_dev, slave_dev);
if (res)
@@ -1639,6 +1736,10 @@
err_restore_mac:
if (!bond->params.fail_over_mac) {
+ /* XXX TODO - fom follow mode needs to change master's
+ * MAC if this slave's MAC is in use by the bond, or at
+ * least print a warning.
+ */
memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN);
addr.sa_family = slave_dev->type;
dev_set_mac_address(slave_dev, &addr);
@@ -1693,20 +1794,18 @@
return -EINVAL;
}
- mac_addr_differ = memcmp(bond_dev->dev_addr,
- slave->perm_hwaddr,
- ETH_ALEN);
- if (!mac_addr_differ && (bond->slave_cnt > 1)) {
- printk(KERN_WARNING DRV_NAME
- ": %s: Warning: the permanent HWaddr of %s - "
- "%s - is still in use by %s. "
- "Set the HWaddr of %s to a different address "
- "to avoid conflicts.\n",
- bond_dev->name,
- slave_dev->name,
- print_mac(mac, slave->perm_hwaddr),
- bond_dev->name,
- slave_dev->name);
+ if (!bond->params.fail_over_mac) {
+ mac_addr_differ = memcmp(bond_dev->dev_addr, slave->perm_hwaddr,
+ ETH_ALEN);
+ if (!mac_addr_differ && (bond->slave_cnt > 1))
+ printk(KERN_WARNING DRV_NAME
+ ": %s: Warning: the permanent HWaddr of %s - "
+ "%s - is still in use by %s. "
+ "Set the HWaddr of %s to a different address "
+ "to avoid conflicts.\n",
+ bond_dev->name, slave_dev->name,
+ print_mac(mac, slave->perm_hwaddr),
+ bond_dev->name, slave_dev->name);
}
/* Inform AD package of unbinding of slave. */
@@ -1833,7 +1932,7 @@
/* close slave before restoring its mac address */
dev_close(slave_dev);
- if (!bond->params.fail_over_mac) {
+ if (bond->params.fail_over_mac != BOND_FOM_ACTIVE) {
/* restore original ("permanent") mac address */
memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
addr.sa_family = slave_dev->type;
@@ -2144,7 +2243,7 @@
dprintk("sending delayed gratuitous arp on on %s\n",
bond->curr_active_slave->dev->name);
bond_send_gratuitous_arp(bond);
- bond->send_grat_arp = 0;
+ bond->send_grat_arp--;
}
}
read_lock(&bond->curr_slave_lock);
@@ -2397,7 +2496,7 @@
read_lock(&bond->lock);
}
- delay = ((bond->params.miimon * HZ) / 1000) ? : 1;
+ delay = msecs_to_jiffies(bond->params.miimon);
read_unlock(&bond->lock);
queue_delayed_work(bond->wq, &bond->mii_work, delay);
}
@@ -2426,37 +2525,14 @@
return addr;
}
-static int bond_has_ip(struct bonding *bond)
-{
- struct vlan_entry *vlan, *vlan_next;
-
- if (bond->master_ip)
- return 1;
-
- if (list_empty(&bond->vlan_list))
- return 0;
-
- list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list,
- vlan_list) {
- if (vlan->vlan_ip)
- return 1;
- }
-
- return 0;
-}
-
static int bond_has_this_ip(struct bonding *bond, __be32 ip)
{
- struct vlan_entry *vlan, *vlan_next;
+ struct vlan_entry *vlan;
if (ip == bond->master_ip)
return 1;
- if (list_empty(&bond->vlan_list))
- return 0;
-
- list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list,
- vlan_list) {
+ list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
if (ip == vlan->vlan_ip)
return 1;
}
@@ -2498,7 +2574,7 @@
{
int i, vlan_id, rv;
__be32 *targets = bond->params.arp_targets;
- struct vlan_entry *vlan, *vlan_next;
+ struct vlan_entry *vlan;
struct net_device *vlan_dev;
struct flowi fl;
struct rtable *rt;
@@ -2545,8 +2621,7 @@
}
vlan_id = 0;
- list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list,
- vlan_list) {
+ list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id);
if (vlan_dev == rt->u.dst.dev) {
vlan_id = vlan->vlan_id;
@@ -2707,7 +2782,7 @@
read_lock(&bond->lock);
- delta_in_ticks = (bond->params.arp_interval * HZ) / 1000;
+ delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
if (bond->kill_timers) {
goto out;
@@ -2764,8 +2839,7 @@
* if we don't know our ip yet
*/
if (time_after_eq(jiffies, slave->dev->trans_start + 2*delta_in_ticks) ||
- (time_after_eq(jiffies, slave->dev->last_rx + 2*delta_in_ticks) &&
- bond_has_ip(bond))) {
+ (time_after_eq(jiffies, slave->dev->last_rx + 2*delta_in_ticks))) {
slave->link = BOND_LINK_DOWN;
slave->state = BOND_STATE_BACKUP;
@@ -2813,245 +2887,298 @@
}
/*
- * When using arp monitoring in active-backup mode, this function is
- * called to determine if any backup slaves have went down or a new
- * current slave needs to be found.
- * The backup slaves never generate traffic, they are considered up by merely
- * receiving traffic. If the current slave goes down, each backup slave will
- * be given the opportunity to tx/rx an arp before being taken down - this
- * prevents all slaves from being taken down due to the current slave not
- * sending any traffic for the backups to receive. The arps are not necessarily
- * necessary, any tx and rx traffic will keep the current slave up. While any
- * rx traffic will keep the backup slaves up, the current slave is responsible
- * for generating traffic to keep them up regardless of any other traffic they
- * may have received.
- * see loadbalance_arp_monitor for arp monitoring in load balancing mode
+ * Called to inspect slaves for active-backup mode ARP monitor link state
+ * changes. Sets new_link in slaves to specify what action should take
+ * place for the slave. Returns 0 if no changes are found, >0 if changes
+ * to link states must be committed.
+ *
+ * Called with bond->lock held for read.
*/
-void bond_activebackup_arp_mon(struct work_struct *work)
+static int bond_ab_arp_inspect(struct bonding *bond, int delta_in_ticks)
{
- struct bonding *bond = container_of(work, struct bonding,
- arp_work.work);
struct slave *slave;
- int delta_in_ticks;
- int i;
+ int i, commit = 0;
- read_lock(&bond->lock);
-
- delta_in_ticks = (bond->params.arp_interval * HZ) / 1000;
-
- if (bond->kill_timers) {
- goto out;
- }
-
- if (bond->slave_cnt == 0) {
- goto re_arm;
- }
-
- /* determine if any slave has come up or any backup slave has
- * gone down
- * TODO: what about up/down delay in arp mode? it wasn't here before
- * so it can wait
- */
bond_for_each_slave(bond, slave, i) {
+ slave->new_link = BOND_LINK_NOCHANGE;
+
if (slave->link != BOND_LINK_UP) {
- if (time_before_eq(jiffies,
- slave_last_rx(bond, slave) + delta_in_ticks)) {
-
- slave->link = BOND_LINK_UP;
-
- write_lock_bh(&bond->curr_slave_lock);
-
- if ((!bond->curr_active_slave) &&
- time_before_eq(jiffies, slave->dev->trans_start + delta_in_ticks)) {
- bond_change_active_slave(bond, slave);
- bond->current_arp_slave = NULL;
- } else if (bond->curr_active_slave != slave) {
- /* this slave has just come up but we
- * already have a current slave; this
- * can also happen if bond_enslave adds
- * a new slave that is up while we are
- * searching for a new slave
- */
- bond_set_slave_inactive_flags(slave);
- bond->current_arp_slave = NULL;
- }
-
- bond_set_carrier(bond);
-
- if (slave == bond->curr_active_slave) {
- printk(KERN_INFO DRV_NAME
- ": %s: %s is up and now the "
- "active interface\n",
- bond->dev->name,
- slave->dev->name);
- netif_carrier_on(bond->dev);
- } else {
- printk(KERN_INFO DRV_NAME
- ": %s: backup interface %s is "
- "now up\n",
- bond->dev->name,
- slave->dev->name);
- }
-
- write_unlock_bh(&bond->curr_slave_lock);
+ if (time_before_eq(jiffies, slave_last_rx(bond, slave) +
+ delta_in_ticks)) {
+ slave->new_link = BOND_LINK_UP;
+ commit++;
}
- } else {
- read_lock(&bond->curr_slave_lock);
- if ((slave != bond->curr_active_slave) &&
- (!bond->current_arp_slave) &&
- (time_after_eq(jiffies, slave_last_rx(bond, slave) + 3*delta_in_ticks) &&
- bond_has_ip(bond))) {
- /* a backup slave has gone down; three times
- * the delta allows the current slave to be
- * taken out before the backup slave.
- * note: a non-null current_arp_slave indicates
- * the curr_active_slave went down and we are
- * searching for a new one; under this
- * condition we only take the curr_active_slave
- * down - this gives each slave a chance to
- * tx/rx traffic before being taken out
- */
+ continue;
+ }
- read_unlock(&bond->curr_slave_lock);
+ /*
+ * Give slaves 2*delta after being enslaved or made
+ * active. This avoids bouncing, as the last receive
+ * times need a full ARP monitor cycle to be updated.
+ */
+ if (!time_after_eq(jiffies, slave->jiffies +
+ 2 * delta_in_ticks))
+ continue;
- slave->link = BOND_LINK_DOWN;
+ /*
+ * Backup slave is down if:
+ * - No current_arp_slave AND
+ * - more than 3*delta since last receive AND
+ * - the bond has an IP address
+ *
+ * Note: a non-null current_arp_slave indicates
+ * the curr_active_slave went down and we are
+ * searching for a new one; under this condition
+ * we only take the curr_active_slave down - this
+ * gives each slave a chance to tx/rx traffic
+ * before being taken out
+ */
+ if (slave->state == BOND_STATE_BACKUP &&
+ !bond->current_arp_slave &&
+ time_after(jiffies, slave_last_rx(bond, slave) +
+ 3 * delta_in_ticks)) {
+ slave->new_link = BOND_LINK_DOWN;
+ commit++;
+ }
- if (slave->link_failure_count < UINT_MAX) {
- slave->link_failure_count++;
- }
-
- bond_set_slave_inactive_flags(slave);
-
- printk(KERN_INFO DRV_NAME
- ": %s: backup interface %s is now down\n",
- bond->dev->name,
- slave->dev->name);
- } else {
- read_unlock(&bond->curr_slave_lock);
- }
+ /*
+ * Active slave is down if:
+ * - more than 2*delta since transmitting OR
+ * - (more than 2*delta since receive AND
+ * the bond has an IP address)
+ */
+ if ((slave->state == BOND_STATE_ACTIVE) &&
+ (time_after_eq(jiffies, slave->dev->trans_start +
+ 2 * delta_in_ticks) ||
+ (time_after_eq(jiffies, slave_last_rx(bond, slave)
+ + 2 * delta_in_ticks)))) {
+ slave->new_link = BOND_LINK_DOWN;
+ commit++;
}
}
read_lock(&bond->curr_slave_lock);
- slave = bond->curr_active_slave;
+
+ /*
+ * Trigger a commit if the primary option setting has changed.
+ */
+ if (bond->primary_slave &&
+ (bond->primary_slave != bond->curr_active_slave) &&
+ (bond->primary_slave->link == BOND_LINK_UP))
+ commit++;
+
read_unlock(&bond->curr_slave_lock);
- if (slave) {
- /* if we have sent traffic in the past 2*arp_intervals but
- * haven't xmit and rx traffic in that time interval, select
- * a different slave. slave->jiffies is only updated when
- * a slave first becomes the curr_active_slave - not necessarily
- * after every arp; this ensures the slave has a full 2*delta
- * before being taken out. if a primary is being used, check
- * if it is up and needs to take over as the curr_active_slave
- */
- if ((time_after_eq(jiffies, slave->dev->trans_start + 2*delta_in_ticks) ||
- (time_after_eq(jiffies, slave_last_rx(bond, slave) + 2*delta_in_ticks) &&
- bond_has_ip(bond))) &&
- time_after_eq(jiffies, slave->jiffies + 2*delta_in_ticks)) {
+ return commit;
+}
- slave->link = BOND_LINK_DOWN;
+/*
+ * Called to commit link state changes noted by inspection step of
+ * active-backup mode ARP monitor.
+ *
+ * Called with RTNL and bond->lock for read.
+ */
+static void bond_ab_arp_commit(struct bonding *bond, int delta_in_ticks)
+{
+ struct slave *slave;
+ int i;
- if (slave->link_failure_count < UINT_MAX) {
+ bond_for_each_slave(bond, slave, i) {
+ switch (slave->new_link) {
+ case BOND_LINK_NOCHANGE:
+ continue;
+
+ case BOND_LINK_UP:
+ write_lock_bh(&bond->curr_slave_lock);
+
+ if (!bond->curr_active_slave &&
+ time_before_eq(jiffies, slave->dev->trans_start +
+ delta_in_ticks)) {
+ slave->link = BOND_LINK_UP;
+ bond_change_active_slave(bond, slave);
+ bond->current_arp_slave = NULL;
+
+ printk(KERN_INFO DRV_NAME
+ ": %s: %s is up and now the "
+ "active interface\n",
+ bond->dev->name, slave->dev->name);
+
+ } else if (bond->curr_active_slave != slave) {
+ /* this slave has just come up but we
+ * already have a current slave; this can
+ * also happen if bond_enslave adds a new
+ * slave that is up while we are searching
+ * for a new slave
+ */
+ slave->link = BOND_LINK_UP;
+ bond_set_slave_inactive_flags(slave);
+ bond->current_arp_slave = NULL;
+
+ printk(KERN_INFO DRV_NAME
+ ": %s: backup interface %s is now up\n",
+ bond->dev->name, slave->dev->name);
+ }
+
+ write_unlock_bh(&bond->curr_slave_lock);
+
+ break;
+
+ case BOND_LINK_DOWN:
+ if (slave->link_failure_count < UINT_MAX)
slave->link_failure_count++;
- }
- printk(KERN_INFO DRV_NAME
- ": %s: link status down for active interface "
- "%s, disabling it\n",
- bond->dev->name,
+ slave->link = BOND_LINK_DOWN;
+
+ if (slave == bond->curr_active_slave) {
+ printk(KERN_INFO DRV_NAME
+ ": %s: link status down for active "
+ "interface %s, disabling it\n",
+ bond->dev->name, slave->dev->name);
+
+ bond_set_slave_inactive_flags(slave);
+
+ write_lock_bh(&bond->curr_slave_lock);
+
+ bond_select_active_slave(bond);
+ if (bond->curr_active_slave)
+ bond->curr_active_slave->jiffies =
+ jiffies;
+
+ write_unlock_bh(&bond->curr_slave_lock);
+
+ bond->current_arp_slave = NULL;
+
+ } else if (slave->state == BOND_STATE_BACKUP) {
+ printk(KERN_INFO DRV_NAME
+ ": %s: backup interface %s is now down\n",
+ bond->dev->name, slave->dev->name);
+
+ bond_set_slave_inactive_flags(slave);
+ }
+ break;
+
+ default:
+ printk(KERN_ERR DRV_NAME
+ ": %s: impossible: new_link %d on slave %s\n",
+ bond->dev->name, slave->new_link,
slave->dev->name);
-
- write_lock_bh(&bond->curr_slave_lock);
-
- bond_select_active_slave(bond);
- slave = bond->curr_active_slave;
-
- write_unlock_bh(&bond->curr_slave_lock);
-
- bond->current_arp_slave = slave;
-
- if (slave) {
- slave->jiffies = jiffies;
- }
- } else if ((bond->primary_slave) &&
- (bond->primary_slave != slave) &&
- (bond->primary_slave->link == BOND_LINK_UP)) {
- /* at this point, slave is the curr_active_slave */
- printk(KERN_INFO DRV_NAME
- ": %s: changing from interface %s to primary "
- "interface %s\n",
- bond->dev->name,
- slave->dev->name,
- bond->primary_slave->dev->name);
-
- /* primary is up so switch to it */
- write_lock_bh(&bond->curr_slave_lock);
- bond_change_active_slave(bond, bond->primary_slave);
- write_unlock_bh(&bond->curr_slave_lock);
-
- slave = bond->primary_slave;
- slave->jiffies = jiffies;
- } else {
- bond->current_arp_slave = NULL;
- }
-
- /* the current slave must tx an arp to ensure backup slaves
- * rx traffic
- */
- if (slave && bond_has_ip(bond)) {
- bond_arp_send_all(bond, slave);
}
}
+ /*
+ * No race with changes to primary via sysfs, as we hold rtnl.
+ */
+ if (bond->primary_slave &&
+ (bond->primary_slave != bond->curr_active_slave) &&
+ (bond->primary_slave->link == BOND_LINK_UP)) {
+ write_lock_bh(&bond->curr_slave_lock);
+ bond_change_active_slave(bond, bond->primary_slave);
+ write_unlock_bh(&bond->curr_slave_lock);
+ }
+
+ bond_set_carrier(bond);
+}
+
+/*
+ * Send ARP probes for active-backup mode ARP monitor.
+ *
+ * Called with bond->lock held for read.
+ */
+static void bond_ab_arp_probe(struct bonding *bond)
+{
+ struct slave *slave;
+ int i;
+
+ read_lock(&bond->curr_slave_lock);
+
+ if (bond->current_arp_slave && bond->curr_active_slave)
+ printk("PROBE: c_arp %s && cas %s BAD\n",
+ bond->current_arp_slave->dev->name,
+ bond->curr_active_slave->dev->name);
+
+ if (bond->curr_active_slave) {
+ bond_arp_send_all(bond, bond->curr_active_slave);
+ read_unlock(&bond->curr_slave_lock);
+ return;
+ }
+
+ read_unlock(&bond->curr_slave_lock);
+
/* if we don't have a curr_active_slave, search for the next available
* backup slave from the current_arp_slave and make it the candidate
* for becoming the curr_active_slave
*/
- if (!slave) {
- if (!bond->current_arp_slave) {
- bond->current_arp_slave = bond->first_slave;
+
+ if (!bond->current_arp_slave) {
+ bond->current_arp_slave = bond->first_slave;
+ if (!bond->current_arp_slave)
+ return;
+ }
+
+ bond_set_slave_inactive_flags(bond->current_arp_slave);
+
+ /* search for next candidate */
+ bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave->next) {
+ if (IS_UP(slave->dev)) {
+ slave->link = BOND_LINK_BACK;
+ bond_set_slave_active_flags(slave);
+ bond_arp_send_all(bond, slave);
+ slave->jiffies = jiffies;
+ bond->current_arp_slave = slave;
+ break;
}
- if (bond->current_arp_slave) {
- bond_set_slave_inactive_flags(bond->current_arp_slave);
+ /* if the link state is up at this point, we
+ * mark it down - this can happen if we have
+ * simultaneous link failures and
+ * reselect_active_interface doesn't make this
+ * one the current slave so it is still marked
+ * up when it is actually down
+ */
+ if (slave->link == BOND_LINK_UP) {
+ slave->link = BOND_LINK_DOWN;
+ if (slave->link_failure_count < UINT_MAX)
+ slave->link_failure_count++;
- /* search for next candidate */
- bond_for_each_slave_from(bond, slave, i, bond->current_arp_slave->next) {
- if (IS_UP(slave->dev)) {
- slave->link = BOND_LINK_BACK;
- bond_set_slave_active_flags(slave);
- bond_arp_send_all(bond, slave);
- slave->jiffies = jiffies;
- bond->current_arp_slave = slave;
- break;
- }
+ bond_set_slave_inactive_flags(slave);
- /* if the link state is up at this point, we
- * mark it down - this can happen if we have
- * simultaneous link failures and
- * reselect_active_interface doesn't make this
- * one the current slave so it is still marked
- * up when it is actually down
- */
- if (slave->link == BOND_LINK_UP) {
- slave->link = BOND_LINK_DOWN;
- if (slave->link_failure_count < UINT_MAX) {
- slave->link_failure_count++;
- }
-
- bond_set_slave_inactive_flags(slave);
-
- printk(KERN_INFO DRV_NAME
- ": %s: backup interface %s is "
- "now down.\n",
- bond->dev->name,
- slave->dev->name);
- }
- }
+ printk(KERN_INFO DRV_NAME
+ ": %s: backup interface %s is now down.\n",
+ bond->dev->name, slave->dev->name);
}
}
+}
+
+void bond_activebackup_arp_mon(struct work_struct *work)
+{
+ struct bonding *bond = container_of(work, struct bonding,
+ arp_work.work);
+ int delta_in_ticks;
+
+ read_lock(&bond->lock);
+
+ if (bond->kill_timers)
+ goto out;
+
+ delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
+
+ if (bond->slave_cnt == 0)
+ goto re_arm;
+
+ if (bond_ab_arp_inspect(bond, delta_in_ticks)) {
+ read_unlock(&bond->lock);
+ rtnl_lock();
+ read_lock(&bond->lock);
+
+ bond_ab_arp_commit(bond, delta_in_ticks);
+
+ read_unlock(&bond->lock);
+ rtnl_unlock();
+ read_lock(&bond->lock);
+ }
+
+ bond_ab_arp_probe(bond);
re_arm:
if (bond->params.arp_interval) {
@@ -3128,7 +3255,8 @@
if (bond->params.mode == BOND_MODE_ACTIVEBACKUP &&
bond->params.fail_over_mac)
- seq_printf(seq, " (fail_over_mac)");
+ seq_printf(seq, " (fail_over_mac %s)",
+ fail_over_mac_tbl[bond->params.fail_over_mac].modename);
seq_printf(seq, "\n");
@@ -3500,13 +3628,13 @@
{
struct in_ifaddr *ifa = ptr;
struct net_device *vlan_dev, *event_dev = ifa->ifa_dev->dev;
- struct bonding *bond, *bond_next;
- struct vlan_entry *vlan, *vlan_next;
+ struct bonding *bond;
+ struct vlan_entry *vlan;
if (dev_net(ifa->ifa_dev->dev) != &init_net)
return NOTIFY_DONE;
- list_for_each_entry_safe(bond, bond_next, &bond_dev_list, bond_list) {
+ list_for_each_entry(bond, &bond_dev_list, bond_list) {
if (bond->dev == event_dev) {
switch (event) {
case NETDEV_UP:
@@ -3520,11 +3648,7 @@
}
}
- if (list_empty(&bond->vlan_list))
- continue;
-
- list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list,
- vlan_list) {
+ list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id);
if (vlan_dev == event_dev) {
switch (event) {
@@ -4060,10 +4184,10 @@
dprintk("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None"));
/*
- * If fail_over_mac is enabled, do nothing and return success.
- * Returning an error causes ifenslave to fail.
+ * If fail_over_mac is set to active, do nothing and return
+ * success. Returning an error causes ifenslave to fail.
*/
- if (bond->params.fail_over_mac)
+ if (bond->params.fail_over_mac == BOND_FOM_ACTIVE)
return 0;
if (!is_valid_ether_addr(sa->sa_data)) {
@@ -4568,7 +4692,7 @@
static int bond_check_params(struct bond_params *params)
{
- int arp_validate_value;
+ int arp_validate_value, fail_over_mac_value;
/*
* Convert string parameters.
@@ -4658,6 +4782,13 @@
use_carrier = 1;
}
+ if (num_grat_arp < 0 || num_grat_arp > 255) {
+ printk(KERN_WARNING DRV_NAME
+ ": Warning: num_grat_arp (%d) not in range 0-255 so it "
+ "was reset to 1 \n", num_grat_arp);
+ num_grat_arp = 1;
+ }
+
/* reset values for 802.3ad */
if (bond_mode == BOND_MODE_8023AD) {
if (!miimon) {
@@ -4836,15 +4967,29 @@
primary = NULL;
}
- if (fail_over_mac && (bond_mode != BOND_MODE_ACTIVEBACKUP))
- printk(KERN_WARNING DRV_NAME
- ": Warning: fail_over_mac only affects "
- "active-backup mode.\n");
+ if (fail_over_mac) {
+ fail_over_mac_value = bond_parse_parm(fail_over_mac,
+ fail_over_mac_tbl);
+ if (fail_over_mac_value == -1) {
+ printk(KERN_ERR DRV_NAME
+ ": Error: invalid fail_over_mac \"%s\"\n",
+ arp_validate == NULL ? "NULL" : arp_validate);
+ return -EINVAL;
+ }
+
+ if (bond_mode != BOND_MODE_ACTIVEBACKUP)
+ printk(KERN_WARNING DRV_NAME
+ ": Warning: fail_over_mac only affects "
+ "active-backup mode.\n");
+ } else {
+ fail_over_mac_value = BOND_FOM_NONE;
+ }
/* fill params struct with the proper values */
params->mode = bond_mode;
params->xmit_policy = xmit_hashtype;
params->miimon = miimon;
+ params->num_grat_arp = num_grat_arp;
params->arp_interval = arp_interval;
params->arp_validate = arp_validate_value;
params->updelay = updelay;
@@ -4852,7 +4997,7 @@
params->use_carrier = use_carrier;
params->lacp_fast = lacp_fast;
params->primary[0] = 0;
- params->fail_over_mac = fail_over_mac;
+ params->fail_over_mac = fail_over_mac_value;
if (primary) {
strncpy(params->primary, primary, IFNAMSIZ);
@@ -4871,10 +5016,10 @@
* Caller must NOT hold rtnl_lock; we need to release it here before we
* set up our sysfs entries.
*/
-int bond_create(char *name, struct bond_params *params, struct bonding **newbond)
+int bond_create(char *name, struct bond_params *params)
{
struct net_device *bond_dev;
- struct bonding *bond, *nxt;
+ struct bonding *bond;
int res;
rtnl_lock();
@@ -4882,7 +5027,7 @@
/* Check to see if the bond already exists. */
if (name) {
- list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list)
+ list_for_each_entry(bond, &bond_dev_list, bond_list)
if (strnicmp(bond->dev->name, name, IFNAMSIZ) == 0) {
printk(KERN_ERR DRV_NAME
": cannot add bond %s; it already exists\n",
@@ -4925,9 +5070,6 @@
lockdep_set_class(&bond_dev->_xmit_lock, &bonding_netdev_xmit_lock_key);
- if (newbond)
- *newbond = bond_dev->priv;
-
netif_carrier_off(bond_dev);
up_write(&bonding_rwsem);
@@ -4957,7 +5099,7 @@
{
int i;
int res;
- struct bonding *bond, *nxt;
+ struct bonding *bond;
printk(KERN_INFO "%s", version);
@@ -4973,7 +5115,7 @@
init_rwsem(&bonding_rwsem);
for (i = 0; i < max_bonds; i++) {
- res = bond_create(NULL, &bonding_defaults, NULL);
+ res = bond_create(NULL, &bonding_defaults);
if (res)
goto err;
}
@@ -4987,7 +5129,7 @@
goto out;
err:
- list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) {
+ list_for_each_entry(bond, &bond_dev_list, bond_list) {
bond_work_cancel_all(bond);
destroy_workqueue(bond->wq);
}
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 08f3d39..dd265c6 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -50,6 +50,7 @@
extern struct bond_parm_tbl bond_lacp_tbl[];
extern struct bond_parm_tbl xmit_hashtype_tbl[];
extern struct bond_parm_tbl arp_validate_tbl[];
+extern struct bond_parm_tbl fail_over_mac_tbl[];
static int expected_refcount = -1;
static struct class *netdev_class;
@@ -111,7 +112,6 @@
char *ifname;
int rv, res = count;
struct bonding *bond;
- struct bonding *nxt;
sscanf(buffer, "%16s", command); /* IFNAMSIZ*/
ifname = command + 1;
@@ -122,7 +122,7 @@
if (command[0] == '+') {
printk(KERN_INFO DRV_NAME
": %s is being created...\n", ifname);
- rv = bond_create(ifname, &bonding_defaults, &bond);
+ rv = bond_create(ifname, &bonding_defaults);
if (rv) {
printk(KERN_INFO DRV_NAME ": Bond creation failed.\n");
res = rv;
@@ -134,7 +134,7 @@
rtnl_lock();
down_write(&bonding_rwsem);
- list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list)
+ list_for_each_entry(bond, &bond_dev_list, bond_list)
if (strnicmp(bond->dev->name, ifname, IFNAMSIZ) == 0) {
/* check the ref count on the bond's kobject.
* If it's > expected, then there's a file open,
@@ -548,42 +548,37 @@
{
struct bonding *bond = to_bond(d);
- return sprintf(buf, "%d\n", bond->params.fail_over_mac) + 1;
+ return sprintf(buf, "%s %d\n",
+ fail_over_mac_tbl[bond->params.fail_over_mac].modename,
+ bond->params.fail_over_mac);
}
static ssize_t bonding_store_fail_over_mac(struct device *d, struct device_attribute *attr, const char *buf, size_t count)
{
int new_value;
- int ret = count;
struct bonding *bond = to_bond(d);
if (bond->slave_cnt != 0) {
printk(KERN_ERR DRV_NAME
": %s: Can't alter fail_over_mac with slaves in bond.\n",
bond->dev->name);
- ret = -EPERM;
- goto out;
+ return -EPERM;
}
- if (sscanf(buf, "%d", &new_value) != 1) {
+ new_value = bond_parse_parm(buf, fail_over_mac_tbl);
+ if (new_value < 0) {
printk(KERN_ERR DRV_NAME
- ": %s: no fail_over_mac value specified.\n",
- bond->dev->name);
- ret = -EINVAL;
- goto out;
+ ": %s: Ignoring invalid fail_over_mac value %s.\n",
+ bond->dev->name, buf);
+ return -EINVAL;
}
- if ((new_value == 0) || (new_value == 1)) {
- bond->params.fail_over_mac = new_value;
- printk(KERN_INFO DRV_NAME ": %s: Setting fail_over_mac to %d.\n",
- bond->dev->name, new_value);
- } else {
- printk(KERN_INFO DRV_NAME
- ": %s: Ignoring invalid fail_over_mac value %d.\n",
- bond->dev->name, new_value);
- }
-out:
- return ret;
+ bond->params.fail_over_mac = new_value;
+ printk(KERN_INFO DRV_NAME ": %s: Setting fail_over_mac to %s (%d).\n",
+ bond->dev->name, fail_over_mac_tbl[new_value].modename,
+ new_value);
+
+ return count;
}
static DEVICE_ATTR(fail_over_mac, S_IRUGO | S_IWUSR, bonding_show_fail_over_mac, bonding_store_fail_over_mac);
@@ -952,6 +947,45 @@
static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp);
/*
+ * Show and set the number of grat ARP to send after a failover event.
+ */
+static ssize_t bonding_show_n_grat_arp(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct bonding *bond = to_bond(d);
+
+ return sprintf(buf, "%d\n", bond->params.num_grat_arp);
+}
+
+static ssize_t bonding_store_n_grat_arp(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int new_value, ret = count;
+ struct bonding *bond = to_bond(d);
+
+ if (sscanf(buf, "%d", &new_value) != 1) {
+ printk(KERN_ERR DRV_NAME
+ ": %s: no num_grat_arp value specified.\n",
+ bond->dev->name);
+ ret = -EINVAL;
+ goto out;
+ }
+ if (new_value < 0 || new_value > 255) {
+ printk(KERN_ERR DRV_NAME
+ ": %s: Invalid num_grat_arp value %d not in range 0-255; rejected.\n",
+ bond->dev->name, new_value);
+ ret = -EINVAL;
+ goto out;
+ } else {
+ bond->params.num_grat_arp = new_value;
+ }
+out:
+ return ret;
+}
+static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, bonding_show_n_grat_arp, bonding_store_n_grat_arp);
+/*
* Show and set the MII monitor interval. There are two tricky bits
* here. First, if MII monitoring is activated, then we must disable
* ARP monitoring. Second, if the timer isn't running, we must
@@ -1388,6 +1422,7 @@
&dev_attr_updelay.attr,
&dev_attr_lacp_rate.attr,
&dev_attr_xmit_hash_policy.attr,
+ &dev_attr_num_grat_arp.attr,
&dev_attr_miimon.attr,
&dev_attr_primary.attr,
&dev_attr_use_carrier.attr,
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index a3c74e2..89fd996 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -125,6 +125,7 @@
int mode;
int xmit_policy;
int miimon;
+ int num_grat_arp;
int arp_interval;
int arp_validate;
int use_carrier;
@@ -157,6 +158,7 @@
unsigned long jiffies;
unsigned long last_arp_rx;
s8 link; /* one of BOND_LINK_XXXX */
+ s8 new_link;
s8 state; /* one of BOND_STATE_XXXX */
u32 original_flags;
u32 original_mtu;
@@ -169,6 +171,11 @@
};
/*
+ * Link pseudo-state only used internally by monitors
+ */
+#define BOND_LINK_NOCHANGE -1
+
+/*
* Here are the locking policies for the two bonding locks:
*
* 1) Get bond->lock when reading/writing slave list.
@@ -241,6 +248,10 @@
return (struct bonding *)slave->dev->master->priv;
}
+#define BOND_FOM_NONE 0
+#define BOND_FOM_ACTIVE 1
+#define BOND_FOM_FOLLOW 2
+
#define BOND_ARP_VALIDATE_NONE 0
#define BOND_ARP_VALIDATE_ACTIVE (1 << BOND_STATE_ACTIVE)
#define BOND_ARP_VALIDATE_BACKUP (1 << BOND_STATE_BACKUP)
@@ -301,7 +312,7 @@
struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr);
int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev);
-int bond_create(char *name, struct bond_params *params, struct bonding **newbond);
+int bond_create(char *name, struct bond_params *params);
void bond_destroy(struct bonding *bond);
int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev);
int bond_create_sysfs(void);
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
index acebe43..2711404 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/cxgb3/adapter.h
@@ -42,6 +42,7 @@
#include <linux/cache.h>
#include <linux/mutex.h>
#include <linux/bitops.h>
+#include <linux/inet_lro.h>
#include "t3cdev.h"
#include <asm/io.h>
@@ -92,6 +93,7 @@
unsigned int gen; /* free list generation */
struct fl_pg_chunk pg_chunk;/* page chunk cache */
unsigned int use_pages; /* whether FL uses pages or sk_buffs */
+ unsigned int order; /* order of page allocations */
struct rx_desc *desc; /* address of HW Rx descriptor ring */
struct rx_sw_desc *sdesc; /* address of SW Rx descriptor ring */
dma_addr_t phys_addr; /* physical address of HW ring start */
@@ -116,12 +118,15 @@
unsigned int polling; /* is the queue serviced through NAPI? */
unsigned int holdoff_tmr; /* interrupt holdoff timer in 100ns */
unsigned int next_holdoff; /* holdoff time for next interrupt */
+ unsigned int rx_recycle_buf; /* whether recycling occurred
+ within current sop-eop */
struct rsp_desc *desc; /* address of HW response ring */
dma_addr_t phys_addr; /* physical address of the ring */
unsigned int cntxt_id; /* SGE context id for the response q */
spinlock_t lock; /* guards response processing */
struct sk_buff *rx_head; /* offload packet receive queue head */
struct sk_buff *rx_tail; /* offload packet receive queue tail */
+ struct sk_buff *pg_skb; /* used to build frag list in napi handler */
unsigned long offload_pkts;
unsigned long offload_bundles;
@@ -169,16 +174,29 @@
SGE_PSTAT_TX_CSUM, /* # of TX checksum offloads */
SGE_PSTAT_VLANEX, /* # of VLAN tag extractions */
SGE_PSTAT_VLANINS, /* # of VLAN tag insertions */
+ SGE_PSTAT_LRO_AGGR, /* # of page chunks added to LRO sessions */
+ SGE_PSTAT_LRO_FLUSHED, /* # of flushed LRO sessions */
+ SGE_PSTAT_LRO_NO_DESC, /* # of overflown LRO sessions */
SGE_PSTAT_MAX /* must be last */
};
+#define T3_MAX_LRO_SES 8
+#define T3_MAX_LRO_MAX_PKTS 64
+
struct sge_qset { /* an SGE queue set */
struct adapter *adap;
struct napi_struct napi;
struct sge_rspq rspq;
struct sge_fl fl[SGE_RXQ_PER_SET];
struct sge_txq txq[SGE_TXQ_PER_SET];
+ struct net_lro_mgr lro_mgr;
+ struct net_lro_desc lro_desc[T3_MAX_LRO_SES];
+ struct skb_frag_struct *lro_frag_tbl;
+ int lro_nfrags;
+ int lro_enabled;
+ int lro_frag_len;
+ void *lro_va;
struct net_device *netdev;
unsigned long txq_stopped; /* which Tx queues are stopped */
struct timer_list tx_reclaim_timer; /* reclaims TX buffers */
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
index 579bee4..d444f58 100644
--- a/drivers/net/cxgb3/common.h
+++ b/drivers/net/cxgb3/common.h
@@ -351,6 +351,7 @@
struct qset_params { /* SGE queue set parameters */
unsigned int polling; /* polling/interrupt service for rspq */
+ unsigned int lro; /* large receive offload */
unsigned int coalesce_usecs; /* irq coalescing timer */
unsigned int rspq_size; /* # of entries in response queue */
unsigned int fl_size; /* # of entries in regular free list */
diff --git a/drivers/net/cxgb3/cxgb3_ioctl.h b/drivers/net/cxgb3/cxgb3_ioctl.h
index 0a82fcd..68200a1 100644
--- a/drivers/net/cxgb3/cxgb3_ioctl.h
+++ b/drivers/net/cxgb3/cxgb3_ioctl.h
@@ -90,6 +90,7 @@
int32_t fl_size[2];
int32_t intr_lat;
int32_t polling;
+ int32_t lro;
int32_t cong_thres;
};
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index 3a31272..5447f3e 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -1212,6 +1212,9 @@
"VLANinsertions ",
"TxCsumOffload ",
"RxCsumGood ",
+ "LroAggregated ",
+ "LroFlushed ",
+ "LroNoDesc ",
"RxDrops ",
"CheckTXEnToggled ",
@@ -1340,6 +1343,9 @@
*data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANINS);
*data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TX_CSUM);
*data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_RX_CSUM_GOOD);
+ *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_LRO_AGGR);
+ *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_LRO_FLUSHED);
+ *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_LRO_NO_DESC);
*data++ = s->rx_cong_drops;
*data++ = s->num_toggled;
@@ -1558,6 +1564,13 @@
struct port_info *p = netdev_priv(dev);
p->rx_csum_offload = data;
+ if (!data) {
+ struct adapter *adap = p->adapter;
+ int i;
+
+ for (i = p->first_qset; i < p->first_qset + p->nqsets; i++)
+ adap->sge.qs[i].lro_enabled = 0;
+ }
return 0;
}
@@ -1830,6 +1843,11 @@
}
}
}
+ if (t.lro >= 0) {
+ struct sge_qset *qs = &adapter->sge.qs[t.qset_idx];
+ q->lro = t.lro;
+ qs->lro_enabled = t.lro;
+ }
break;
}
case CHELSIO_GET_QSET_PARAMS:{
@@ -1849,6 +1867,7 @@
t.fl_size[0] = q->fl_size;
t.fl_size[1] = q->jumbo_size;
t.polling = q->polling;
+ t.lro = q->lro;
t.intr_lat = q->coalesce_usecs;
t.cong_thres = q->cong_thres;
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index 796eb30..a96331c 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -55,6 +55,9 @@
* directly.
*/
#define FL0_PG_CHUNK_SIZE 2048
+#define FL0_PG_ORDER 0
+#define FL1_PG_CHUNK_SIZE (PAGE_SIZE > 8192 ? 16384 : 8192)
+#define FL1_PG_ORDER (PAGE_SIZE > 8192 ? 0 : 1)
#define SGE_RX_DROP_THRES 16
@@ -359,7 +362,7 @@
}
if (q->pg_chunk.page) {
- __free_page(q->pg_chunk.page);
+ __free_pages(q->pg_chunk.page, q->order);
q->pg_chunk.page = NULL;
}
}
@@ -376,13 +379,16 @@
* Add a buffer of the given length to the supplied HW and SW Rx
* descriptors.
*/
-static inline void add_one_rx_buf(void *va, unsigned int len,
- struct rx_desc *d, struct rx_sw_desc *sd,
- unsigned int gen, struct pci_dev *pdev)
+static inline int add_one_rx_buf(void *va, unsigned int len,
+ struct rx_desc *d, struct rx_sw_desc *sd,
+ unsigned int gen, struct pci_dev *pdev)
{
dma_addr_t mapping;
mapping = pci_map_single(pdev, va, len, PCI_DMA_FROMDEVICE);
+ if (unlikely(pci_dma_mapping_error(mapping)))
+ return -ENOMEM;
+
pci_unmap_addr_set(sd, dma_addr, mapping);
d->addr_lo = cpu_to_be32(mapping);
@@ -390,12 +396,14 @@
wmb();
d->len_gen = cpu_to_be32(V_FLD_GEN1(gen));
d->gen2 = cpu_to_be32(V_FLD_GEN2(gen));
+ return 0;
}
-static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp)
+static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp,
+ unsigned int order)
{
if (!q->pg_chunk.page) {
- q->pg_chunk.page = alloc_page(gfp);
+ q->pg_chunk.page = alloc_pages(gfp, order);
if (unlikely(!q->pg_chunk.page))
return -ENOMEM;
q->pg_chunk.va = page_address(q->pg_chunk.page);
@@ -404,7 +412,7 @@
sd->pg_chunk = q->pg_chunk;
q->pg_chunk.offset += q->buf_size;
- if (q->pg_chunk.offset == PAGE_SIZE)
+ if (q->pg_chunk.offset == (PAGE_SIZE << order))
q->pg_chunk.page = NULL;
else {
q->pg_chunk.va += q->buf_size;
@@ -424,15 +432,18 @@
* allocated with the supplied gfp flags. The caller must assure that
* @n does not exceed the queue's capacity.
*/
-static void refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp)
+static int refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp)
{
void *buf_start;
struct rx_sw_desc *sd = &q->sdesc[q->pidx];
struct rx_desc *d = &q->desc[q->pidx];
+ unsigned int count = 0;
while (n--) {
+ int err;
+
if (q->use_pages) {
- if (unlikely(alloc_pg_chunk(q, sd, gfp))) {
+ if (unlikely(alloc_pg_chunk(q, sd, gfp, q->order))) {
nomem: q->alloc_failed++;
break;
}
@@ -447,8 +458,16 @@
buf_start = skb->data;
}
- add_one_rx_buf(buf_start, q->buf_size, d, sd, q->gen,
- adap->pdev);
+ err = add_one_rx_buf(buf_start, q->buf_size, d, sd, q->gen,
+ adap->pdev);
+ if (unlikely(err)) {
+ if (!q->use_pages) {
+ kfree_skb(sd->skb);
+ sd->skb = NULL;
+ }
+ break;
+ }
+
d++;
sd++;
if (++q->pidx == q->size) {
@@ -458,14 +477,19 @@
d = q->desc;
}
q->credits++;
+ count++;
}
wmb();
- t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id));
+ if (likely(count))
+ t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id));
+
+ return count;
}
static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl)
{
- refill_fl(adap, fl, min(16U, fl->size - fl->credits), GFP_ATOMIC);
+ refill_fl(adap, fl, min(16U, fl->size - fl->credits),
+ GFP_ATOMIC | __GFP_COMP);
}
/**
@@ -560,6 +584,8 @@
memset(q->txq, 0, sizeof(struct sge_txq) * SGE_TXQ_PER_SET);
q->txq_stopped = 0;
memset(&q->tx_reclaim_timer, 0, sizeof(q->tx_reclaim_timer));
+ kfree(q->lro_frag_tbl);
+ q->lro_nfrags = q->lro_frag_len = 0;
}
@@ -740,19 +766,22 @@
* that are page chunks rather than sk_buffs.
*/
static struct sk_buff *get_packet_pg(struct adapter *adap, struct sge_fl *fl,
- unsigned int len, unsigned int drop_thres)
+ struct sge_rspq *q, unsigned int len,
+ unsigned int drop_thres)
{
- struct sk_buff *skb = NULL;
+ struct sk_buff *newskb, *skb;
struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
- if (len <= SGE_RX_COPY_THRES) {
- skb = alloc_skb(len, GFP_ATOMIC);
- if (likely(skb != NULL)) {
- __skb_put(skb, len);
+ newskb = skb = q->pg_skb;
+
+ if (!skb && (len <= SGE_RX_COPY_THRES)) {
+ newskb = alloc_skb(len, GFP_ATOMIC);
+ if (likely(newskb != NULL)) {
+ __skb_put(newskb, len);
pci_dma_sync_single_for_cpu(adap->pdev,
pci_unmap_addr(sd, dma_addr), len,
PCI_DMA_FROMDEVICE);
- memcpy(skb->data, sd->pg_chunk.va, len);
+ memcpy(newskb->data, sd->pg_chunk.va, len);
pci_dma_sync_single_for_device(adap->pdev,
pci_unmap_addr(sd, dma_addr), len,
PCI_DMA_FROMDEVICE);
@@ -761,14 +790,16 @@
recycle:
fl->credits--;
recycle_rx_buf(adap, fl, fl->cidx);
- return skb;
+ q->rx_recycle_buf++;
+ return newskb;
}
- if (unlikely(fl->credits <= drop_thres))
+ if (unlikely(q->rx_recycle_buf || (!skb && fl->credits <= drop_thres)))
goto recycle;
- skb = alloc_skb(SGE_RX_PULL_LEN, GFP_ATOMIC);
- if (unlikely(!skb)) {
+ if (!skb)
+ newskb = alloc_skb(SGE_RX_PULL_LEN, GFP_ATOMIC);
+ if (unlikely(!newskb)) {
if (!drop_thres)
return NULL;
goto recycle;
@@ -776,21 +807,29 @@
pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr),
fl->buf_size, PCI_DMA_FROMDEVICE);
- __skb_put(skb, SGE_RX_PULL_LEN);
- memcpy(skb->data, sd->pg_chunk.va, SGE_RX_PULL_LEN);
- skb_fill_page_desc(skb, 0, sd->pg_chunk.page,
- sd->pg_chunk.offset + SGE_RX_PULL_LEN,
- len - SGE_RX_PULL_LEN);
- skb->len = len;
- skb->data_len = len - SGE_RX_PULL_LEN;
- skb->truesize += skb->data_len;
+ if (!skb) {
+ __skb_put(newskb, SGE_RX_PULL_LEN);
+ memcpy(newskb->data, sd->pg_chunk.va, SGE_RX_PULL_LEN);
+ skb_fill_page_desc(newskb, 0, sd->pg_chunk.page,
+ sd->pg_chunk.offset + SGE_RX_PULL_LEN,
+ len - SGE_RX_PULL_LEN);
+ newskb->len = len;
+ newskb->data_len = len - SGE_RX_PULL_LEN;
+ } else {
+ skb_fill_page_desc(newskb, skb_shinfo(newskb)->nr_frags,
+ sd->pg_chunk.page,
+ sd->pg_chunk.offset, len);
+ newskb->len += len;
+ newskb->data_len += len;
+ }
+ newskb->truesize += newskb->data_len;
fl->credits--;
/*
* We do not refill FLs here, we let the caller do it to overlap a
* prefetch.
*/
- return skb;
+ return newskb;
}
/**
@@ -1831,9 +1870,10 @@
* if it was immediate data in a response.
*/
static void rx_eth(struct adapter *adap, struct sge_rspq *rq,
- struct sk_buff *skb, int pad)
+ struct sk_buff *skb, int pad, int lro)
{
struct cpl_rx_pkt *p = (struct cpl_rx_pkt *)(skb->data + pad);
+ struct sge_qset *qs = rspq_to_qset(rq);
struct port_info *pi;
skb_pull(skb, sizeof(*p) + pad);
@@ -1850,18 +1890,202 @@
if (unlikely(p->vlan_valid)) {
struct vlan_group *grp = pi->vlan_grp;
- rspq_to_qset(rq)->port_stats[SGE_PSTAT_VLANEX]++;
+ qs->port_stats[SGE_PSTAT_VLANEX]++;
if (likely(grp))
- __vlan_hwaccel_rx(skb, grp, ntohs(p->vlan),
- rq->polling);
+ if (lro)
+ lro_vlan_hwaccel_receive_skb(&qs->lro_mgr, skb,
+ grp,
+ ntohs(p->vlan),
+ p);
+ else
+ __vlan_hwaccel_rx(skb, grp, ntohs(p->vlan),
+ rq->polling);
else
dev_kfree_skb_any(skb);
- } else if (rq->polling)
- netif_receive_skb(skb);
- else
+ } else if (rq->polling) {
+ if (lro)
+ lro_receive_skb(&qs->lro_mgr, skb, p);
+ else
+ netif_receive_skb(skb);
+ } else
netif_rx(skb);
}
+static inline int is_eth_tcp(u32 rss)
+{
+ return G_HASHTYPE(ntohl(rss)) == RSS_HASH_4_TUPLE;
+}
+
+/**
+ * lro_frame_ok - check if an ingress packet is eligible for LRO
+ * @p: the CPL header of the packet
+ *
+ * Returns true if a received packet is eligible for LRO.
+ * The following conditions must be true:
+ * - packet is TCP/IP Ethernet II (checked elsewhere)
+ * - not an IP fragment
+ * - no IP options
+ * - TCP/IP checksums are correct
+ * - the packet is for this host
+ */
+static inline int lro_frame_ok(const struct cpl_rx_pkt *p)
+{
+ const struct ethhdr *eh = (struct ethhdr *)(p + 1);
+ const struct iphdr *ih = (struct iphdr *)(eh + 1);
+
+ return (*((u8 *)p + 1) & 0x90) == 0x10 && p->csum == htons(0xffff) &&
+ eh->h_proto == htons(ETH_P_IP) && ih->ihl == (sizeof(*ih) >> 2);
+}
+
+#define TCP_FLAG_MASK (TCP_FLAG_CWR | TCP_FLAG_ECE | TCP_FLAG_URG |\
+ TCP_FLAG_ACK | TCP_FLAG_PSH | TCP_FLAG_RST |\
+ TCP_FLAG_SYN | TCP_FLAG_FIN)
+#define TSTAMP_WORD ((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |\
+ (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)
+
+/**
+ * lro_segment_ok - check if a TCP segment is eligible for LRO
+ * @tcph: the TCP header of the packet
+ *
+ * Returns true if a TCP packet is eligible for LRO. This requires that
+ * the packet have only the ACK flag set and no TCP options besides
+ * time stamps.
+ */
+static inline int lro_segment_ok(const struct tcphdr *tcph)
+{
+ int optlen;
+
+ if (unlikely((tcp_flag_word(tcph) & TCP_FLAG_MASK) != TCP_FLAG_ACK))
+ return 0;
+
+ optlen = (tcph->doff << 2) - sizeof(*tcph);
+ if (optlen) {
+ const u32 *opt = (const u32 *)(tcph + 1);
+
+ if (optlen != TCPOLEN_TSTAMP_ALIGNED ||
+ *opt != htonl(TSTAMP_WORD) || !opt[2])
+ return 0;
+ }
+ return 1;
+}
+
+static int t3_get_lro_header(void **eh, void **iph, void **tcph,
+ u64 *hdr_flags, void *priv)
+{
+ const struct cpl_rx_pkt *cpl = priv;
+
+ if (!lro_frame_ok(cpl))
+ return -1;
+
+ *eh = (struct ethhdr *)(cpl + 1);
+ *iph = (struct iphdr *)((struct ethhdr *)*eh + 1);
+ *tcph = (struct tcphdr *)((struct iphdr *)*iph + 1);
+
+ if (!lro_segment_ok(*tcph))
+ return -1;
+
+ *hdr_flags = LRO_IPV4 | LRO_TCP;
+ return 0;
+}
+
+static int t3_get_skb_header(struct sk_buff *skb,
+ void **iph, void **tcph, u64 *hdr_flags,
+ void *priv)
+{
+ void *eh;
+
+ return t3_get_lro_header(&eh, iph, tcph, hdr_flags, priv);
+}
+
+static int t3_get_frag_header(struct skb_frag_struct *frag, void **eh,
+ void **iph, void **tcph, u64 *hdr_flags,
+ void *priv)
+{
+ return t3_get_lro_header(eh, iph, tcph, hdr_flags, priv);
+}
+
+/**
+ * lro_add_page - add a page chunk to an LRO session
+ * @adap: the adapter
+ * @qs: the associated queue set
+ * @fl: the free list containing the page chunk to add
+ * @len: packet length
+ * @complete: Indicates the last fragment of a frame
+ *
+ * Add a received packet contained in a page chunk to an existing LRO
+ * session.
+ */
+static void lro_add_page(struct adapter *adap, struct sge_qset *qs,
+ struct sge_fl *fl, int len, int complete)
+{
+ struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
+ struct cpl_rx_pkt *cpl;
+ struct skb_frag_struct *rx_frag = qs->lro_frag_tbl;
+ int nr_frags = qs->lro_nfrags, frag_len = qs->lro_frag_len;
+ int offset = 0;
+
+ if (!nr_frags) {
+ offset = 2 + sizeof(struct cpl_rx_pkt);
+ qs->lro_va = cpl = sd->pg_chunk.va + 2;
+ }
+
+ fl->credits--;
+
+ len -= offset;
+ pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr),
+ fl->buf_size, PCI_DMA_FROMDEVICE);
+
+ rx_frag += nr_frags;
+ rx_frag->page = sd->pg_chunk.page;
+ rx_frag->page_offset = sd->pg_chunk.offset + offset;
+ rx_frag->size = len;
+ frag_len += len;
+ qs->lro_nfrags++;
+ qs->lro_frag_len = frag_len;
+
+ if (!complete)
+ return;
+
+ qs->lro_nfrags = qs->lro_frag_len = 0;
+ cpl = qs->lro_va;
+
+ if (unlikely(cpl->vlan_valid)) {
+ struct net_device *dev = qs->netdev;
+ struct port_info *pi = netdev_priv(dev);
+ struct vlan_group *grp = pi->vlan_grp;
+
+ if (likely(grp != NULL)) {
+ lro_vlan_hwaccel_receive_frags(&qs->lro_mgr,
+ qs->lro_frag_tbl,
+ frag_len, frag_len,
+ grp, ntohs(cpl->vlan),
+ cpl, 0);
+ return;
+ }
+ }
+ lro_receive_frags(&qs->lro_mgr, qs->lro_frag_tbl,
+ frag_len, frag_len, cpl, 0);
+}
+
+/**
+ * init_lro_mgr - initialize a LRO manager object
+ * @lro_mgr: the LRO manager object
+ */
+static void init_lro_mgr(struct sge_qset *qs, struct net_lro_mgr *lro_mgr)
+{
+ lro_mgr->dev = qs->netdev;
+ lro_mgr->features = LRO_F_NAPI;
+ lro_mgr->ip_summed = CHECKSUM_UNNECESSARY;
+ lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY;
+ lro_mgr->max_desc = T3_MAX_LRO_SES;
+ lro_mgr->lro_arr = qs->lro_desc;
+ lro_mgr->get_frag_header = t3_get_frag_header;
+ lro_mgr->get_skb_header = t3_get_skb_header;
+ lro_mgr->max_aggr = T3_MAX_LRO_MAX_PKTS;
+ if (lro_mgr->max_aggr > MAX_SKB_FRAGS)
+ lro_mgr->max_aggr = MAX_SKB_FRAGS;
+}
+
/**
* handle_rsp_cntrl_info - handles control information in a response
* @qs: the queue set corresponding to the response
@@ -1947,6 +2171,12 @@
return (r->intr_gen & F_RSPD_GEN2) == q->gen;
}
+static inline void clear_rspq_bufstate(struct sge_rspq * const q)
+{
+ q->pg_skb = NULL;
+ q->rx_recycle_buf = 0;
+}
+
#define RSPD_GTS_MASK (F_RSPD_TXQ0_GTS | F_RSPD_TXQ1_GTS)
#define RSPD_CTRL_MASK (RSPD_GTS_MASK | \
V_RSPD_TXQ0_CR(M_RSPD_TXQ0_CR) | \
@@ -1984,10 +2214,11 @@
q->next_holdoff = q->holdoff_tmr;
while (likely(budget_left && is_new_response(r, q))) {
- int eth, ethpad = 2;
+ int packet_complete, eth, ethpad = 2, lro = qs->lro_enabled;
struct sk_buff *skb = NULL;
u32 len, flags = ntohl(r->flags);
- __be32 rss_hi = *(const __be32 *)r, rss_lo = r->rss_hdr.rss_hash_val;
+ __be32 rss_hi = *(const __be32 *)r,
+ rss_lo = r->rss_hdr.rss_hash_val;
eth = r->rss_hdr.opcode == CPL_RX_PKT;
@@ -2015,6 +2246,9 @@
} else if ((len = ntohl(r->len_cq)) != 0) {
struct sge_fl *fl;
+ if (eth)
+ lro = qs->lro_enabled && is_eth_tcp(rss_hi);
+
fl = (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0];
if (fl->use_pages) {
void *addr = fl->sdesc[fl->cidx].pg_chunk.va;
@@ -2024,9 +2258,18 @@
prefetch(addr + L1_CACHE_BYTES);
#endif
__refill_fl(adap, fl);
+ if (lro > 0) {
+ lro_add_page(adap, qs, fl,
+ G_RSPD_LEN(len),
+ flags & F_RSPD_EOP);
+ goto next_fl;
+ }
- skb = get_packet_pg(adap, fl, G_RSPD_LEN(len),
- eth ? SGE_RX_DROP_THRES : 0);
+ skb = get_packet_pg(adap, fl, q,
+ G_RSPD_LEN(len),
+ eth ?
+ SGE_RX_DROP_THRES : 0);
+ q->pg_skb = skb;
} else
skb = get_packet(adap, fl, G_RSPD_LEN(len),
eth ? SGE_RX_DROP_THRES : 0);
@@ -2036,7 +2279,7 @@
q->rx_drops++;
} else if (unlikely(r->rss_hdr.opcode == CPL_TRACE_PKT))
__skb_pull(skb, 2);
-
+next_fl:
if (++fl->cidx == fl->size)
fl->cidx = 0;
} else
@@ -2060,9 +2303,13 @@
q->credits = 0;
}
- if (likely(skb != NULL)) {
+ packet_complete = flags &
+ (F_RSPD_EOP | F_RSPD_IMM_DATA_VALID |
+ F_RSPD_ASYNC_NOTIF);
+
+ if (skb != NULL && packet_complete) {
if (eth)
- rx_eth(adap, q, skb, ethpad);
+ rx_eth(adap, q, skb, ethpad, lro);
else {
q->offload_pkts++;
/* Preserve the RSS info in csum & priority */
@@ -2072,11 +2319,19 @@
offload_skbs,
ngathered);
}
+
+ if (flags & F_RSPD_EOP)
+ clear_rspq_bufstate(q);
}
--budget_left;
}
deliver_partial_bundle(&adap->tdev, q, offload_skbs, ngathered);
+ lro_flush_all(&qs->lro_mgr);
+ qs->port_stats[SGE_PSTAT_LRO_AGGR] = qs->lro_mgr.stats.aggregated;
+ qs->port_stats[SGE_PSTAT_LRO_FLUSHED] = qs->lro_mgr.stats.flushed;
+ qs->port_stats[SGE_PSTAT_LRO_NO_DESC] = qs->lro_mgr.stats.no_desc;
+
if (sleeping)
check_ring_db(adap, qs, sleeping);
@@ -2618,8 +2873,9 @@
int irq_vec_idx, const struct qset_params *p,
int ntxq, struct net_device *dev)
{
- int i, ret = -ENOMEM;
+ int i, avail, ret = -ENOMEM;
struct sge_qset *q = &adapter->sge.qs[id];
+ struct net_lro_mgr *lro_mgr = &q->lro_mgr;
init_qset_cntxt(q, id);
init_timer(&q->tx_reclaim_timer);
@@ -2687,11 +2943,23 @@
#else
q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + sizeof(struct cpl_rx_data);
#endif
- q->fl[0].use_pages = FL0_PG_CHUNK_SIZE > 0;
+#if FL1_PG_CHUNK_SIZE > 0
+ q->fl[1].buf_size = FL1_PG_CHUNK_SIZE;
+#else
q->fl[1].buf_size = is_offload(adapter) ?
(16 * 1024) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) :
MAX_FRAME_SIZE + 2 + sizeof(struct cpl_rx_pkt);
+#endif
+ q->fl[0].use_pages = FL0_PG_CHUNK_SIZE > 0;
+ q->fl[1].use_pages = FL1_PG_CHUNK_SIZE > 0;
+ q->fl[0].order = FL0_PG_ORDER;
+ q->fl[1].order = FL1_PG_ORDER;
+
+ q->lro_frag_tbl = kcalloc(MAX_FRAME_SIZE / FL1_PG_CHUNK_SIZE + 1,
+ sizeof(struct skb_frag_struct),
+ GFP_KERNEL);
+ q->lro_nfrags = q->lro_frag_len = 0;
spin_lock_irq(&adapter->sge.reg_lock);
/* FL threshold comparison uses < */
@@ -2742,8 +3010,23 @@
q->netdev = dev;
t3_update_qset_coalesce(q, p);
- refill_fl(adapter, &q->fl[0], q->fl[0].size, GFP_KERNEL);
- refill_fl(adapter, &q->fl[1], q->fl[1].size, GFP_KERNEL);
+ init_lro_mgr(q, lro_mgr);
+
+ avail = refill_fl(adapter, &q->fl[0], q->fl[0].size,
+ GFP_KERNEL | __GFP_COMP);
+ if (!avail) {
+ CH_ALERT(adapter, "free list queue 0 initialization failed\n");
+ goto err;
+ }
+ if (avail < q->fl[0].size)
+ CH_WARN(adapter, "free list queue 0 enabled with %d credits\n",
+ avail);
+
+ avail = refill_fl(adapter, &q->fl[1], q->fl[1].size,
+ GFP_KERNEL | __GFP_COMP);
+ if (avail < q->fl[1].size)
+ CH_WARN(adapter, "free list queue 1 enabled with %d credits\n",
+ avail);
refill_rspq(adapter, &q->rspq, q->rspq.size - 1);
t3_write_reg(adapter, A_SG_GTS, V_RSPQ(q->rspq.cntxt_id) |
@@ -2752,9 +3035,9 @@
mod_timer(&q->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD);
return 0;
- err_unlock:
+err_unlock:
spin_unlock_irq(&adapter->sge.reg_lock);
- err:
+err:
t3_free_qset(adapter, q);
return ret;
}
@@ -2876,7 +3159,7 @@
q->coalesce_usecs = 5;
q->rspq_size = 1024;
q->fl_size = 1024;
- q->jumbo_size = 512;
+ q->jumbo_size = 512;
q->txq_size[TXQ_ETH] = 1024;
q->txq_size[TXQ_OFLD] = 1024;
q->txq_size[TXQ_CTRL] = 256;
diff --git a/drivers/net/cxgb3/t3_cpl.h b/drivers/net/cxgb3/t3_cpl.h
index b7a1a31..a666c5d 100644
--- a/drivers/net/cxgb3/t3_cpl.h
+++ b/drivers/net/cxgb3/t3_cpl.h
@@ -174,6 +174,13 @@
CONG_ALG_HIGHSPEED
};
+enum { /* RSS hash type */
+ RSS_HASH_NONE = 0,
+ RSS_HASH_2_TUPLE = 1,
+ RSS_HASH_4_TUPLE = 2,
+ RSS_HASH_TCPV6 = 3
+};
+
union opcode_tid {
__be32 opcode_tid;
__u8 opcode;
@@ -184,6 +191,10 @@
#define G_OPCODE(x) (((x) >> S_OPCODE) & 0xFF)
#define G_TID(x) ((x) & 0xFFFFFF)
+#define S_HASHTYPE 22
+#define M_HASHTYPE 0x3
+#define G_HASHTYPE(x) (((x) >> S_HASHTYPE) & M_HASHTYPE)
+
/* tid is assumed to be 24-bits */
#define MK_OPCODE_TID(opcode, tid) (V_OPCODE(opcode) | (tid))
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index 6b1e77c..3e35064 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -773,8 +773,6 @@
return IRQ_HANDLED;
}
-struct net_device *last_dev = 0;
-
static int lance_open(struct net_device *dev)
{
volatile u16 *ib = (volatile u16 *)dev->mem_start;
@@ -782,8 +780,6 @@
volatile struct lance_regs *ll = lp->ll;
int status = 0;
- last_dev = dev;
-
/* Stop the Lance */
writereg(&ll->rap, LE_CSR0);
writereg(&ll->rdp, LE_C0_STOP);
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
index e233d04..8277e89 100644
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -499,7 +499,7 @@
entry = np->old_rx % RX_RING_SIZE;
/* Dropped packets don't need to re-allocate */
if (np->rx_skbuff[entry] == NULL) {
- skb = dev_alloc_skb (np->rx_buf_sz);
+ skb = netdev_alloc_skb (dev, np->rx_buf_sz);
if (skb == NULL) {
np->rx_ring[entry].fraginfo = 0;
printk (KERN_INFO
@@ -570,7 +570,7 @@
/* Allocate the rx buffers */
for (i = 0; i < RX_RING_SIZE; i++) {
/* Allocated fixed size of skbuff */
- struct sk_buff *skb = dev_alloc_skb (np->rx_buf_sz);
+ struct sk_buff *skb = netdev_alloc_skb (dev, np->rx_buf_sz);
np->rx_skbuff[i] = skb;
if (skb == NULL) {
printk (KERN_ERR
@@ -867,7 +867,7 @@
PCI_DMA_FROMDEVICE);
skb_put (skb = np->rx_skbuff[entry], pkt_len);
np->rx_skbuff[entry] = NULL;
- } else if ((skb = dev_alloc_skb (pkt_len + 2)) != NULL) {
+ } else if ((skb = netdev_alloc_skb(dev, pkt_len + 2))) {
pci_dma_sync_single_for_cpu(np->pdev,
desc_to_dma(desc),
np->rx_buf_sz,
@@ -904,7 +904,7 @@
struct sk_buff *skb;
/* Dropped packets don't need to re-allocate */
if (np->rx_skbuff[entry] == NULL) {
- skb = dev_alloc_skb (np->rx_buf_sz);
+ skb = netdev_alloc_skb(dev, np->rx_buf_sz);
if (skb == NULL) {
np->rx_ring[entry].fraginfo = 0;
printk (KERN_INFO
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index 864295e..08a7365a 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/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index cab1835..ccb8ca2 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -4343,6 +4343,11 @@
netdev->features |= NETIF_F_TSO;
netdev->features |= NETIF_F_TSO6;
+ netdev->vlan_features |= NETIF_F_TSO;
+ netdev->vlan_features |= NETIF_F_TSO6;
+ netdev->vlan_features |= NETIF_F_HW_CSUM;
+ netdev->vlan_features |= NETIF_F_SG;
+
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 2cb2447..c980ce97 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -426,6 +426,7 @@
#define NV_PCI_REGSZ_VER1 0x270
#define NV_PCI_REGSZ_VER2 0x2d4
#define NV_PCI_REGSZ_VER3 0x604
+#define NV_PCI_REGSZ_MAX 0x604
/* various timeout delays: all in usec */
#define NV_TXRX_RESET_DELAY 4
@@ -784,6 +785,9 @@
/* flow control */
u32 pause_flags;
+
+ /* power saved state */
+ u32 saved_config_space[NV_PCI_REGSZ_MAX/4];
};
/*
@@ -5805,50 +5809,66 @@
{
struct net_device *dev = pci_get_drvdata(pdev);
struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+ int i;
- if (!netif_running(dev))
- goto out;
-
+ if (netif_running(dev)) {
+ // Gross.
+ nv_close(dev);
+ }
netif_device_detach(dev);
- // Gross.
- nv_close(dev);
+ /* save non-pci configuration space */
+ for (i = 0;i <= np->register_size/sizeof(u32); i++)
+ np->saved_config_space[i] = readl(base + i*sizeof(u32));
pci_save_state(pdev);
pci_enable_wake(pdev, pci_choose_state(pdev, state), np->wolenabled);
+ pci_disable_device(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
-out:
return 0;
}
static int nv_resume(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
- int rc = 0;
- u32 txreg;
-
- if (!netif_running(dev))
- goto out;
-
- netif_device_attach(dev);
+ int i, rc = 0;
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
+ /* ack any pending wake events, disable PME */
pci_enable_wake(pdev, PCI_D0, 0);
- /* restore mac address reverse flag */
- txreg = readl(base + NvRegTransmitPoll);
- txreg |= NVREG_TRANSMITPOLL_MAC_ADDR_REV;
- writel(txreg, base + NvRegTransmitPoll);
+ /* restore non-pci configuration space */
+ for (i = 0;i <= np->register_size/sizeof(u32); i++)
+ writel(np->saved_config_space[i], base+i*sizeof(u32));
- rc = nv_open(dev);
- nv_set_multicast(dev);
-out:
+ netif_device_attach(dev);
+ if (netif_running(dev)) {
+ rc = nv_open(dev);
+ nv_set_multicast(dev);
+ }
return rc;
}
+
+static void nv_shutdown(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct fe_priv *np = netdev_priv(dev);
+
+ if (netif_running(dev))
+ nv_close(dev);
+
+ pci_enable_wake(pdev, PCI_D3hot, np->wolenabled);
+ pci_enable_wake(pdev, PCI_D3cold, np->wolenabled);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
+}
#else
#define nv_suspend NULL
+#define nv_shutdown NULL
#define nv_resume NULL
#endif /* CONFIG_PM */
@@ -6019,6 +6039,7 @@
.remove = __devexit_p(nv_remove),
.suspend = nv_suspend,
.resume = nv_resume,
+ .shutdown = nv_shutdown,
};
static int __init init_nic(void)
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index a5baaf5..fb7c477 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -43,6 +43,7 @@
#include <asm/uaccess.h>
#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <linux/of_gpio.h>
#include <asm/of_platform.h>
#endif
@@ -1172,8 +1173,7 @@
struct fs_platform_info *fpi)
{
struct device_node *phynode, *mdionode;
- struct resource res;
- int ret = 0, len;
+ int ret = 0, len, bus_id;
const u32 *data;
data = of_get_property(np, "fixed-link", NULL);
@@ -1190,19 +1190,28 @@
if (!phynode)
return -EINVAL;
- mdionode = of_get_parent(phynode);
- if (!mdionode)
- goto out_put_phy;
-
- ret = of_address_to_resource(mdionode, 0, &res);
- if (ret)
- goto out_put_mdio;
-
data = of_get_property(phynode, "reg", &len);
- if (!data || len != 4)
- goto out_put_mdio;
+ if (!data || len != 4) {
+ ret = -EINVAL;
+ goto out_put_phy;
+ }
- snprintf(fpi->bus_id, 16, "%x:%02x", res.start, *data);
+ mdionode = of_get_parent(phynode);
+ if (!mdionode) {
+ ret = -EINVAL;
+ goto out_put_phy;
+ }
+
+ bus_id = of_get_gpio(mdionode, 0);
+ if (bus_id < 0) {
+ struct resource res;
+ ret = of_address_to_resource(mdionode, 0, &res);
+ if (ret)
+ goto out_put_mdio;
+ bus_id = res.start;
+ }
+
+ snprintf(fpi->bus_id, 16, "%x:%02x", bus_id, *data);
out_put_mdio:
of_node_put(mdionode);
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/hamachi.c b/drivers/net/hamachi.c
index e5c2380..3199526 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -1140,11 +1140,11 @@
}
/* Fill in the Rx buffers. Handle allocation failure gracefully. */
for (i = 0; i < RX_RING_SIZE; i++) {
- struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz);
+ struct sk_buff *skb = netdev_alloc_skb(dev, hmp->rx_buf_sz);
hmp->rx_skbuff[i] = skb;
if (skb == NULL)
break;
- skb->dev = dev; /* Mark as being used by this device. */
+
skb_reserve(skb, 2); /* 16 byte align the IP header. */
hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev,
skb->data, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE));
@@ -1178,14 +1178,6 @@
hmp->cur_rx = hmp->cur_tx = 0;
hmp->dirty_rx = hmp->dirty_tx = 0;
-#if 0
- /* This is wrong. I'm not sure what the original plan was, but this
- * is wrong. An MTU of 1 gets you a buffer of 1536, while an MTU
- * of 1501 gets a buffer of 1533? -KDU
- */
- hmp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
-#endif
- /* My attempt at a reasonable correction */
/* +26 gets the maximum ethernet encapsulation, +7 & ~7 because the
* card needs room to do 8 byte alignment, +2 so we can reserve
* the first 2 bytes, and +16 gets room for the status word from the
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/hplance.c b/drivers/net/hplance.c
index be6e5bc..2e80263 100644
--- a/drivers/net/hplance.c
+++ b/drivers/net/hplance.c
@@ -220,12 +220,12 @@
return 0;
}
-int __init hplance_init_module(void)
+static int __init hplance_init_module(void)
{
return dio_register_driver(&hplance_driver);
}
-void __exit hplance_cleanup_module(void)
+static void __exit hplance_cleanup_module(void)
{
dio_unregister_driver(&hplance_driver);
}
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index ae398f0..7b6b780 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -967,8 +967,13 @@
NETIF_F_HW_VLAN_FILTER;
netdev->features |= NETIF_F_TSO;
-
netdev->features |= NETIF_F_TSO6;
+
+ netdev->vlan_features |= NETIF_F_TSO;
+ netdev->vlan_features |= NETIF_F_TSO6;
+ netdev->vlan_features |= NETIF_F_HW_CSUM;
+ netdev->vlan_features |= NETIF_F_SG;
+
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
index 1257e1a..34ad189 100644
--- a/drivers/net/irda/donauboe.c
+++ b/drivers/net/irda/donauboe.c
@@ -49,10 +49,6 @@
/* Look at toshoboe.h (currently in include/net/irda) for details of */
/* Where to get documentation on the chip */
-
-static char *rcsid =
- "$Id: donauboe.c V2.18 ven jan 10 03:14:16 2003$";
-
/* See below for a description of the logic in this driver */
/* User servicable parts */
@@ -1677,7 +1673,7 @@
pci_set_drvdata(pci_dev,self);
- printk (KERN_INFO DRIVER_NAME ": Using multiple tasks, version %s\n", rcsid);
+ printk (KERN_INFO DRIVER_NAME ": Using multiple tasks\n");
return 0;
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index cfe0194..78dc8e7 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -1,5 +1,4 @@
/*********************************************************************
- * $Id: smsc-ircc2.c,v 1.19.2.5 2002/10/27 11:34:26 dip Exp $
*
* Description: Driver for the SMC Infrared Communications Controller
* Status: Experimental.
diff --git a/drivers/net/irda/smsc-ircc2.h b/drivers/net/irda/smsc-ircc2.h
index 0c36286..317b7fd 100644
--- a/drivers/net/irda/smsc-ircc2.h
+++ b/drivers/net/irda/smsc-ircc2.h
@@ -1,5 +1,4 @@
/*********************************************************************
- * $Id: smsc-ircc2.h,v 1.12.2.1 2002/10/27 10:52:37 dip Exp $
*
* Description: Definitions for the SMC IrCC chipset
* Status: Experimental.
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 7b85922..0d37c90 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -3518,8 +3518,13 @@
NETIF_F_HW_VLAN_FILTER;
netdev->features |= NETIF_F_TSO;
-
netdev->features |= NETIF_F_TSO6;
+
+ netdev->vlan_features |= NETIF_F_TSO;
+ netdev->vlan_features |= NETIF_F_TSO6;
+ netdev->vlan_features |= NETIF_F_HW_CSUM;
+ netdev->vlan_features |= NETIF_F_SG;
+
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c
index 484cb2b..7111c65 100644
--- a/drivers/net/ixp2000/ixpdev.c
+++ b/drivers/net/ixp2000/ixpdev.c
@@ -108,14 +108,14 @@
if (unlikely(!netif_running(nds[desc->channel])))
goto err;
- skb = dev_alloc_skb(desc->pkt_length + 2);
+ skb = netdev_alloc_skb(dev, desc->pkt_length + 2);
if (likely(skb != NULL)) {
skb_reserve(skb, 2);
skb_copy_to_linear_data(skb, buf, desc->pkt_length);
skb_put(skb, desc->pkt_length);
skb->protocol = eth_type_trans(skb, nds[desc->channel]);
- skb->dev->last_rx = jiffies;
+ dev->last_rx = jiffies;
netif_receive_skb(skb);
}
diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c
index 0c5447d..00d59ab 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,8 @@
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);
+ /* ei_local is used on some platforms via the EI_SHIFT macro */
+ struct ei_device *ei_local __maybe_unused = 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 +579,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 +646,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 +731,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 +741,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 +754,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 +765,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 +777,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 +817,8 @@
{
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);
+ /* ei_local is used on some platforms via the EI_SHIFT macro */
+ struct ei_device *ei_local __maybe_unused = netdev_priv(dev);
/*
* Record whether a Tx was in progress and then issue the
@@ -827,7 +829,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 +891,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/mac8390.c b/drivers/net/mac8390.c
index 9e70074..98e3eb2 100644
--- a/drivers/net/mac8390.c
+++ b/drivers/net/mac8390.c
@@ -117,8 +117,6 @@
ACCESS_16,
};
-extern enum mac8390_type mac8390_ident(struct nubus_dev * dev);
-extern int mac8390_memsize(unsigned long membase);
extern int mac8390_memtest(struct net_device * dev);
static int mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev,
enum mac8390_type type);
@@ -163,7 +161,7 @@
static void word_memcpy_tocard(void *tp, const void *fp, int count);
static void word_memcpy_fromcard(void *tp, const void *fp, int count);
-enum mac8390_type __init mac8390_ident(struct nubus_dev * dev)
+static enum mac8390_type __init mac8390_ident(struct nubus_dev *dev)
{
switch (dev->dr_sw) {
case NUBUS_DRSW_3COM:
@@ -234,7 +232,7 @@
return MAC8390_NONE;
}
-enum mac8390_access __init mac8390_testio(volatile unsigned long membase)
+static enum mac8390_access __init mac8390_testio(volatile unsigned long membase)
{
unsigned long outdata = 0xA5A0B5B0;
unsigned long indata = 0x00000000;
@@ -252,7 +250,7 @@
return ACCESS_UNKNOWN;
}
-int __init mac8390_memsize(unsigned long membase)
+static int __init mac8390_memsize(unsigned long membase)
{
unsigned long flags;
int i, j;
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 92dccd4..e346302 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -80,8 +80,12 @@
addr[4] = top & 0xff;
addr[5] = (top >> 8) & 0xff;
- if (is_valid_ether_addr(addr))
+ if (is_valid_ether_addr(addr)) {
memcpy(bp->dev->dev_addr, addr, sizeof(addr));
+ } else {
+ dev_info(&bp->pdev->dev, "invalid hw address, using random\n");
+ random_ether_addr(bp->dev->dev_addr);
+ }
}
static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c
index b267161..e64c208 100644
--- a/drivers/net/macsonic.c
+++ b/drivers/net/macsonic.c
@@ -83,9 +83,6 @@
static int sonic_version_printed;
-extern int mac_onboard_sonic_probe(struct net_device* dev);
-extern int mac_nubus_sonic_probe(struct net_device* dev);
-
/* For onboard SONIC */
#define ONBOARD_SONIC_REGISTERS 0x50F0A000
#define ONBOARD_SONIC_PROM_BASE 0x50f08000
@@ -170,7 +167,7 @@
return err;
}
-int __init macsonic_init(struct net_device* dev)
+static int __init macsonic_init(struct net_device *dev)
{
struct sonic_local* lp = netdev_priv(dev);
@@ -218,7 +215,7 @@
return 0;
}
-int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev)
+static int __init mac_onboard_sonic_ethernet_addr(struct net_device *dev)
{
struct sonic_local *lp = netdev_priv(dev);
const int prom_addr = ONBOARD_SONIC_PROM_BASE;
@@ -284,7 +281,7 @@
} else return 0;
}
-int __init mac_onboard_sonic_probe(struct net_device* dev)
+static int __init mac_onboard_sonic_probe(struct net_device *dev)
{
/* Bwahahaha */
static int once_is_more_than_enough;
@@ -405,9 +402,9 @@
return macsonic_init(dev);
}
-int __init mac_nubus_sonic_ethernet_addr(struct net_device* dev,
- unsigned long prom_addr,
- int id)
+static int __init mac_nubus_sonic_ethernet_addr(struct net_device *dev,
+ unsigned long prom_addr,
+ int id)
{
int i;
for(i = 0; i < 6; i++)
@@ -420,7 +417,7 @@
return 0;
}
-int __init macsonic_ident(struct nubus_dev* ndev)
+static int __init macsonic_ident(struct nubus_dev *ndev)
{
if (ndev->dr_hw == NUBUS_DRHW_ASANTE_LC &&
ndev->dr_sw == NUBUS_DRSW_SONIC_LC)
@@ -445,7 +442,7 @@
return -1;
}
-int __init mac_nubus_sonic_probe(struct net_device* dev)
+static int __init mac_nubus_sonic_probe(struct net_device *dev)
{
static int slots;
struct nubus_dev* ndev = NULL;
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index e0d76c7..9a68d2e 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -49,6 +49,7 @@
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/inet_lro.h>
+#include <linux/dca.h>
#include <linux/ip.h>
#include <linux/inet.h>
#include <linux/in.h>
@@ -185,11 +186,18 @@
dma_addr_t fw_stats_bus;
int watchdog_tx_done;
int watchdog_tx_req;
+#ifdef CONFIG_DCA
+ int cached_dca_tag;
+ int cpu;
+ __be32 __iomem *dca_tag;
+#endif
+ char irq_desc[32];
};
struct myri10ge_priv {
- struct myri10ge_slice_state ss;
+ struct myri10ge_slice_state *ss;
int tx_boundary; /* boundary transmits cannot cross */
+ int num_slices;
int running; /* running? */
int csum_flag; /* rx_csums? */
int small_bytes;
@@ -208,6 +216,11 @@
dma_addr_t cmd_bus;
struct pci_dev *pdev;
int msi_enabled;
+ int msix_enabled;
+ struct msix_entry *msix_vectors;
+#ifdef CONFIG_DCA
+ int dca_enabled;
+#endif
u32 link_state;
unsigned int rdma_tags_available;
int intr_coal_delay;
@@ -244,6 +257,8 @@
static char *myri10ge_fw_unaligned = "myri10ge_ethp_z8e.dat";
static char *myri10ge_fw_aligned = "myri10ge_eth_z8e.dat";
+static char *myri10ge_fw_rss_unaligned = "myri10ge_rss_ethp_z8e.dat";
+static char *myri10ge_fw_rss_aligned = "myri10ge_rss_eth_z8e.dat";
static char *myri10ge_fw_name = NULL;
module_param(myri10ge_fw_name, charp, S_IRUGO | S_IWUSR);
@@ -321,6 +336,18 @@
module_param(myri10ge_wcfifo, int, S_IRUGO);
MODULE_PARM_DESC(myri10ge_wcfifo, "Enable WC Fifo when WC is enabled");
+static int myri10ge_max_slices = 1;
+module_param(myri10ge_max_slices, int, S_IRUGO);
+MODULE_PARM_DESC(myri10ge_max_slices, "Max tx/rx queues");
+
+static int myri10ge_rss_hash = MXGEFW_RSS_HASH_TYPE_SRC_PORT;
+module_param(myri10ge_rss_hash, int, S_IRUGO);
+MODULE_PARM_DESC(myri10ge_rss_hash, "Type of RSS hashing to do");
+
+static int myri10ge_dca = 1;
+module_param(myri10ge_dca, int, S_IRUGO);
+MODULE_PARM_DESC(myri10ge_dca, "Enable DCA if possible");
+
#define MYRI10GE_FW_OFFSET 1024*1024
#define MYRI10GE_HIGHPART_TO_U32(X) \
(sizeof (X) == 8) ? ((u32)((u64)(X) >> 32)) : (0)
@@ -657,7 +684,7 @@
return 0;
}
-static int myri10ge_load_firmware(struct myri10ge_priv *mgp)
+static int myri10ge_load_firmware(struct myri10ge_priv *mgp, int adopt)
{
char __iomem *submit;
__be32 buf[16] __attribute__ ((__aligned__(8)));
@@ -667,6 +694,8 @@
size = 0;
status = myri10ge_load_hotplug_firmware(mgp, &size);
if (status) {
+ if (!adopt)
+ return status;
dev_warn(&mgp->pdev->dev, "hotplug firmware loading failed\n");
/* Do not attempt to adopt firmware if there
@@ -859,8 +888,12 @@
static int myri10ge_reset(struct myri10ge_priv *mgp)
{
struct myri10ge_cmd cmd;
- int status;
+ struct myri10ge_slice_state *ss;
+ int i, status;
size_t bytes;
+#ifdef CONFIG_DCA
+ unsigned long dca_tag_off;
+#endif
/* try to send a reset command to the card to see if it
* is alive */
@@ -872,20 +905,74 @@
}
(void)myri10ge_dma_test(mgp, MXGEFW_DMA_TEST);
+ /*
+ * Use non-ndis mcp_slot (eg, 4 bytes total,
+ * no toeplitz hash value returned. Older firmware will
+ * not understand this command, but will use the correct
+ * sized mcp_slot, so we ignore error returns
+ */
+ cmd.data0 = MXGEFW_RSS_MCP_SLOT_TYPE_MIN;
+ (void)myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_RSS_MCP_SLOT_TYPE, &cmd, 0);
/* Now exchange information about interrupts */
- bytes = mgp->max_intr_slots * sizeof(*mgp->ss.rx_done.entry);
- memset(mgp->ss.rx_done.entry, 0, bytes);
+ bytes = mgp->max_intr_slots * sizeof(*mgp->ss[0].rx_done.entry);
cmd.data0 = (u32) bytes;
status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd, 0);
- cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->ss.rx_done.bus);
- cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->ss.rx_done.bus);
- status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_DMA, &cmd, 0);
+
+ /*
+ * Even though we already know how many slices are supported
+ * via myri10ge_probe_slices() MXGEFW_CMD_GET_MAX_RSS_QUEUES
+ * has magic side effects, and must be called after a reset.
+ * It must be called prior to calling any RSS related cmds,
+ * including assigning an interrupt queue for anything but
+ * slice 0. It must also be called *after*
+ * MXGEFW_CMD_SET_INTRQ_SIZE, since the intrq size is used by
+ * the firmware to compute offsets.
+ */
+
+ if (mgp->num_slices > 1) {
+
+ /* ask the maximum number of slices it supports */
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_RSS_QUEUES,
+ &cmd, 0);
+ if (status != 0) {
+ dev_err(&mgp->pdev->dev,
+ "failed to get number of slices\n");
+ }
+
+ /*
+ * MXGEFW_CMD_ENABLE_RSS_QUEUES must be called prior
+ * to setting up the interrupt queue DMA
+ */
+
+ cmd.data0 = mgp->num_slices;
+ cmd.data1 = 1; /* use MSI-X */
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ENABLE_RSS_QUEUES,
+ &cmd, 0);
+ if (status != 0) {
+ dev_err(&mgp->pdev->dev,
+ "failed to set number of slices\n");
+
+ return status;
+ }
+ }
+ for (i = 0; i < mgp->num_slices; i++) {
+ ss = &mgp->ss[i];
+ cmd.data0 = MYRI10GE_LOWPART_TO_U32(ss->rx_done.bus);
+ cmd.data1 = MYRI10GE_HIGHPART_TO_U32(ss->rx_done.bus);
+ cmd.data2 = i;
+ status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_DMA,
+ &cmd, 0);
+ };
status |=
myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd, 0);
- mgp->ss.irq_claim = (__iomem __be32 *) (mgp->sram + cmd.data0);
+ for (i = 0; i < mgp->num_slices; i++) {
+ ss = &mgp->ss[i];
+ ss->irq_claim =
+ (__iomem __be32 *) (mgp->sram + cmd.data0 + 8 * i);
+ }
status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET,
&cmd, 0);
mgp->irq_deassert = (__iomem __be32 *) (mgp->sram + cmd.data0);
@@ -899,24 +986,116 @@
}
put_be32(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr);
- memset(mgp->ss.rx_done.entry, 0, bytes);
+#ifdef CONFIG_DCA
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_DCA_OFFSET, &cmd, 0);
+ dca_tag_off = cmd.data0;
+ for (i = 0; i < mgp->num_slices; i++) {
+ ss = &mgp->ss[i];
+ if (status == 0) {
+ ss->dca_tag = (__iomem __be32 *)
+ (mgp->sram + dca_tag_off + 4 * i);
+ } else {
+ ss->dca_tag = NULL;
+ }
+ }
+#endif /* CONFIG_DCA */
/* reset mcp/driver shared state back to 0 */
- mgp->ss.tx.req = 0;
- mgp->ss.tx.done = 0;
- mgp->ss.tx.pkt_start = 0;
- mgp->ss.tx.pkt_done = 0;
- mgp->ss.rx_big.cnt = 0;
- mgp->ss.rx_small.cnt = 0;
- mgp->ss.rx_done.idx = 0;
- mgp->ss.rx_done.cnt = 0;
+
mgp->link_changes = 0;
+ for (i = 0; i < mgp->num_slices; i++) {
+ ss = &mgp->ss[i];
+
+ memset(ss->rx_done.entry, 0, bytes);
+ ss->tx.req = 0;
+ ss->tx.done = 0;
+ ss->tx.pkt_start = 0;
+ ss->tx.pkt_done = 0;
+ ss->rx_big.cnt = 0;
+ ss->rx_small.cnt = 0;
+ ss->rx_done.idx = 0;
+ ss->rx_done.cnt = 0;
+ ss->tx.wake_queue = 0;
+ ss->tx.stop_queue = 0;
+ }
+
status = myri10ge_update_mac_address(mgp, mgp->dev->dev_addr);
myri10ge_change_pause(mgp, mgp->pause);
myri10ge_set_multicast_list(mgp->dev);
return status;
}
+#ifdef CONFIG_DCA
+static void
+myri10ge_write_dca(struct myri10ge_slice_state *ss, int cpu, int tag)
+{
+ ss->cpu = cpu;
+ ss->cached_dca_tag = tag;
+ put_be32(htonl(tag), ss->dca_tag);
+}
+
+static inline void myri10ge_update_dca(struct myri10ge_slice_state *ss)
+{
+ int cpu = get_cpu();
+ int tag;
+
+ if (cpu != ss->cpu) {
+ tag = dca_get_tag(cpu);
+ if (ss->cached_dca_tag != tag)
+ myri10ge_write_dca(ss, cpu, tag);
+ }
+ put_cpu();
+}
+
+static void myri10ge_setup_dca(struct myri10ge_priv *mgp)
+{
+ int err, i;
+ struct pci_dev *pdev = mgp->pdev;
+
+ if (mgp->ss[0].dca_tag == NULL || mgp->dca_enabled)
+ return;
+ if (!myri10ge_dca) {
+ dev_err(&pdev->dev, "dca disabled by administrator\n");
+ return;
+ }
+ err = dca_add_requester(&pdev->dev);
+ if (err) {
+ dev_err(&pdev->dev,
+ "dca_add_requester() failed, err=%d\n", err);
+ return;
+ }
+ mgp->dca_enabled = 1;
+ for (i = 0; i < mgp->num_slices; i++)
+ myri10ge_write_dca(&mgp->ss[i], -1, 0);
+}
+
+static void myri10ge_teardown_dca(struct myri10ge_priv *mgp)
+{
+ struct pci_dev *pdev = mgp->pdev;
+ int err;
+
+ if (!mgp->dca_enabled)
+ return;
+ mgp->dca_enabled = 0;
+ err = dca_remove_requester(&pdev->dev);
+}
+
+static int myri10ge_notify_dca_device(struct device *dev, void *data)
+{
+ struct myri10ge_priv *mgp;
+ unsigned long event;
+
+ mgp = dev_get_drvdata(dev);
+ event = *(unsigned long *)data;
+
+ if (event == DCA_PROVIDER_ADD)
+ myri10ge_setup_dca(mgp);
+ else if (event == DCA_PROVIDER_REMOVE)
+ myri10ge_teardown_dca(mgp);
+ return 0;
+}
+#endif /* CONFIG_DCA */
+
static inline void
myri10ge_submit_8rx(struct mcp_kreq_ether_recv __iomem * dst,
struct mcp_kreq_ether_recv *src)
@@ -1095,9 +1274,10 @@
rx_frags[0].size -= MXGEFW_PAD;
len -= MXGEFW_PAD;
lro_receive_frags(&ss->rx_done.lro_mgr, rx_frags,
- len, len,
/* opaque, will come back in get_frag_header */
+ len, len,
(void *)(__force unsigned long)csum, csum);
+
return 1;
}
@@ -1236,7 +1416,7 @@
static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp)
{
- struct mcp_irq_data *stats = mgp->ss.fw_stats;
+ struct mcp_irq_data *stats = mgp->ss[0].fw_stats;
if (unlikely(stats->stats_updated)) {
unsigned link_up = ntohl(stats->link_up);
@@ -1283,6 +1463,11 @@
struct net_device *netdev = ss->mgp->dev;
int work_done;
+#ifdef CONFIG_DCA
+ if (ss->mgp->dca_enabled)
+ myri10ge_update_dca(ss);
+#endif
+
/* process as many rx events as NAPI will allow */
work_done = myri10ge_clean_rx_done(ss, budget);
@@ -1302,6 +1487,13 @@
u32 send_done_count;
int i;
+ /* an interrupt on a non-zero slice is implicitly valid
+ * since MSI-X irqs are not shared */
+ if (ss != mgp->ss) {
+ netif_rx_schedule(ss->dev, &ss->napi);
+ return (IRQ_HANDLED);
+ }
+
/* make sure it is our IRQ, and that the DMA has finished */
if (unlikely(!stats->valid))
return (IRQ_NONE);
@@ -1311,7 +1503,7 @@
if (stats->valid & 1)
netif_rx_schedule(ss->dev, &ss->napi);
- if (!mgp->msi_enabled) {
+ if (!mgp->msi_enabled && !mgp->msix_enabled) {
put_be32(0, mgp->irq_deassert);
if (!myri10ge_deassert_wait)
stats->valid = 0;
@@ -1446,10 +1638,10 @@
{
struct myri10ge_priv *mgp = netdev_priv(netdev);
- ring->rx_mini_max_pending = mgp->ss.rx_small.mask + 1;
- ring->rx_max_pending = mgp->ss.rx_big.mask + 1;
+ ring->rx_mini_max_pending = mgp->ss[0].rx_small.mask + 1;
+ ring->rx_max_pending = mgp->ss[0].rx_big.mask + 1;
ring->rx_jumbo_max_pending = 0;
- ring->tx_max_pending = mgp->ss.rx_small.mask + 1;
+ ring->tx_max_pending = mgp->ss[0].rx_small.mask + 1;
ring->rx_mini_pending = ring->rx_mini_max_pending;
ring->rx_pending = ring->rx_max_pending;
ring->rx_jumbo_pending = ring->rx_jumbo_max_pending;
@@ -1497,9 +1689,12 @@
"tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
"tx_heartbeat_errors", "tx_window_errors",
/* device-specific stats */
- "tx_boundary", "WC", "irq", "MSI",
+ "tx_boundary", "WC", "irq", "MSI", "MSIX",
"read_dma_bw_MBs", "write_dma_bw_MBs", "read_write_dma_bw_MBs",
"serial_number", "watchdog_resets",
+#ifdef CONFIG_DCA
+ "dca_capable", "dca_enabled",
+#endif
"link_changes", "link_up", "dropped_link_overflow",
"dropped_link_error_or_filtered",
"dropped_pause", "dropped_bad_phy", "dropped_bad_crc32",
@@ -1524,23 +1719,31 @@
static void
myri10ge_get_strings(struct net_device *netdev, u32 stringset, u8 * data)
{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+ int i;
+
switch (stringset) {
case ETH_SS_STATS:
memcpy(data, *myri10ge_gstrings_main_stats,
sizeof(myri10ge_gstrings_main_stats));
data += sizeof(myri10ge_gstrings_main_stats);
- memcpy(data, *myri10ge_gstrings_slice_stats,
- sizeof(myri10ge_gstrings_slice_stats));
- data += sizeof(myri10ge_gstrings_slice_stats);
+ for (i = 0; i < mgp->num_slices; i++) {
+ memcpy(data, *myri10ge_gstrings_slice_stats,
+ sizeof(myri10ge_gstrings_slice_stats));
+ data += sizeof(myri10ge_gstrings_slice_stats);
+ }
break;
}
}
static int myri10ge_get_sset_count(struct net_device *netdev, int sset)
{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+
switch (sset) {
case ETH_SS_STATS:
- return MYRI10GE_MAIN_STATS_LEN + MYRI10GE_SLICE_STATS_LEN;
+ return MYRI10GE_MAIN_STATS_LEN +
+ mgp->num_slices * MYRI10GE_SLICE_STATS_LEN;
default:
return -EOPNOTSUPP;
}
@@ -1552,6 +1755,7 @@
{
struct myri10ge_priv *mgp = netdev_priv(netdev);
struct myri10ge_slice_state *ss;
+ int slice;
int i;
for (i = 0; i < MYRI10GE_NET_STATS_LEN; i++)
@@ -1561,15 +1765,20 @@
data[i++] = (unsigned int)mgp->wc_enabled;
data[i++] = (unsigned int)mgp->pdev->irq;
data[i++] = (unsigned int)mgp->msi_enabled;
+ data[i++] = (unsigned int)mgp->msix_enabled;
data[i++] = (unsigned int)mgp->read_dma;
data[i++] = (unsigned int)mgp->write_dma;
data[i++] = (unsigned int)mgp->read_write_dma;
data[i++] = (unsigned int)mgp->serial_number;
data[i++] = (unsigned int)mgp->watchdog_resets;
+#ifdef CONFIG_DCA
+ data[i++] = (unsigned int)(mgp->ss[0].dca_tag != NULL);
+ data[i++] = (unsigned int)(mgp->dca_enabled);
+#endif
data[i++] = (unsigned int)mgp->link_changes;
/* firmware stats are useful only in the first slice */
- ss = &mgp->ss;
+ ss = &mgp->ss[0];
data[i++] = (unsigned int)ntohl(ss->fw_stats->link_up);
data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_link_overflow);
data[i++] =
@@ -1585,24 +1794,27 @@
data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_no_small_buffer);
data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_no_big_buffer);
- data[i++] = 0;
- data[i++] = (unsigned int)ss->tx.pkt_start;
- data[i++] = (unsigned int)ss->tx.pkt_done;
- data[i++] = (unsigned int)ss->tx.req;
- data[i++] = (unsigned int)ss->tx.done;
- data[i++] = (unsigned int)ss->rx_small.cnt;
- data[i++] = (unsigned int)ss->rx_big.cnt;
- data[i++] = (unsigned int)ss->tx.wake_queue;
- data[i++] = (unsigned int)ss->tx.stop_queue;
- data[i++] = (unsigned int)ss->tx.linearized;
- data[i++] = ss->rx_done.lro_mgr.stats.aggregated;
- data[i++] = ss->rx_done.lro_mgr.stats.flushed;
- if (ss->rx_done.lro_mgr.stats.flushed)
- data[i++] = ss->rx_done.lro_mgr.stats.aggregated /
- ss->rx_done.lro_mgr.stats.flushed;
- else
- data[i++] = 0;
- data[i++] = ss->rx_done.lro_mgr.stats.no_desc;
+ for (slice = 0; slice < mgp->num_slices; slice++) {
+ ss = &mgp->ss[slice];
+ data[i++] = slice;
+ data[i++] = (unsigned int)ss->tx.pkt_start;
+ data[i++] = (unsigned int)ss->tx.pkt_done;
+ data[i++] = (unsigned int)ss->tx.req;
+ data[i++] = (unsigned int)ss->tx.done;
+ data[i++] = (unsigned int)ss->rx_small.cnt;
+ data[i++] = (unsigned int)ss->rx_big.cnt;
+ data[i++] = (unsigned int)ss->tx.wake_queue;
+ data[i++] = (unsigned int)ss->tx.stop_queue;
+ data[i++] = (unsigned int)ss->tx.linearized;
+ data[i++] = ss->rx_done.lro_mgr.stats.aggregated;
+ data[i++] = ss->rx_done.lro_mgr.stats.flushed;
+ if (ss->rx_done.lro_mgr.stats.flushed)
+ data[i++] = ss->rx_done.lro_mgr.stats.aggregated /
+ ss->rx_done.lro_mgr.stats.flushed;
+ else
+ data[i++] = 0;
+ data[i++] = ss->rx_done.lro_mgr.stats.no_desc;
+ }
}
static void myri10ge_set_msglevel(struct net_device *netdev, u32 value)
@@ -1645,12 +1857,15 @@
struct net_device *dev = mgp->dev;
int tx_ring_size, rx_ring_size;
int tx_ring_entries, rx_ring_entries;
- int i, status;
+ int i, slice, status;
size_t bytes;
/* get ring sizes */
+ slice = ss - mgp->ss;
+ cmd.data0 = slice;
status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_RING_SIZE, &cmd, 0);
tx_ring_size = cmd.data0;
+ cmd.data0 = slice;
status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd, 0);
if (status != 0)
return status;
@@ -1715,15 +1930,17 @@
mgp->small_bytes + MXGEFW_PAD, 0);
if (ss->rx_small.fill_cnt < ss->rx_small.mask + 1) {
- printk(KERN_ERR "myri10ge: %s: alloced only %d small bufs\n",
- dev->name, ss->rx_small.fill_cnt);
+ printk(KERN_ERR
+ "myri10ge: %s:slice-%d: alloced only %d small bufs\n",
+ dev->name, slice, ss->rx_small.fill_cnt);
goto abort_with_rx_small_ring;
}
myri10ge_alloc_rx_pages(mgp, &ss->rx_big, mgp->big_bytes, 0);
if (ss->rx_big.fill_cnt < ss->rx_big.mask + 1) {
- printk(KERN_ERR "myri10ge: %s: alloced only %d big bufs\n",
- dev->name, ss->rx_big.fill_cnt);
+ printk(KERN_ERR
+ "myri10ge: %s:slice-%d: alloced only %d big bufs\n",
+ dev->name, slice, ss->rx_big.fill_cnt);
goto abort_with_rx_big_ring;
}
@@ -1775,6 +1992,10 @@
struct myri10ge_tx_buf *tx;
int i, len, idx;
+ /* If not allocated, skip it */
+ if (ss->tx.req_list == NULL)
+ return;
+
for (i = ss->rx_big.cnt; i < ss->rx_big.fill_cnt; i++) {
idx = i & ss->rx_big.mask;
if (i == ss->rx_big.fill_cnt - 1)
@@ -1837,25 +2058,67 @@
static int myri10ge_request_irq(struct myri10ge_priv *mgp)
{
struct pci_dev *pdev = mgp->pdev;
+ struct myri10ge_slice_state *ss;
+ struct net_device *netdev = mgp->dev;
+ int i;
int status;
+ mgp->msi_enabled = 0;
+ mgp->msix_enabled = 0;
+ status = 0;
if (myri10ge_msi) {
- status = pci_enable_msi(pdev);
- if (status != 0)
- dev_err(&pdev->dev,
- "Error %d setting up MSI; falling back to xPIC\n",
- status);
- else
- mgp->msi_enabled = 1;
- } else {
- mgp->msi_enabled = 0;
+ if (mgp->num_slices > 1) {
+ status =
+ pci_enable_msix(pdev, mgp->msix_vectors,
+ mgp->num_slices);
+ if (status == 0) {
+ mgp->msix_enabled = 1;
+ } else {
+ dev_err(&pdev->dev,
+ "Error %d setting up MSI-X\n", status);
+ return status;
+ }
+ }
+ if (mgp->msix_enabled == 0) {
+ status = pci_enable_msi(pdev);
+ if (status != 0) {
+ dev_err(&pdev->dev,
+ "Error %d setting up MSI; falling back to xPIC\n",
+ status);
+ } else {
+ mgp->msi_enabled = 1;
+ }
+ }
}
- status = request_irq(pdev->irq, myri10ge_intr, IRQF_SHARED,
- mgp->dev->name, mgp);
- if (status != 0) {
- dev_err(&pdev->dev, "failed to allocate IRQ\n");
- if (mgp->msi_enabled)
- pci_disable_msi(pdev);
+ if (mgp->msix_enabled) {
+ for (i = 0; i < mgp->num_slices; i++) {
+ ss = &mgp->ss[i];
+ snprintf(ss->irq_desc, sizeof(ss->irq_desc),
+ "%s:slice-%d", netdev->name, i);
+ status = request_irq(mgp->msix_vectors[i].vector,
+ myri10ge_intr, 0, ss->irq_desc,
+ ss);
+ if (status != 0) {
+ dev_err(&pdev->dev,
+ "slice %d failed to allocate IRQ\n", i);
+ i--;
+ while (i >= 0) {
+ free_irq(mgp->msix_vectors[i].vector,
+ &mgp->ss[i]);
+ i--;
+ }
+ pci_disable_msix(pdev);
+ return status;
+ }
+ }
+ } else {
+ status = request_irq(pdev->irq, myri10ge_intr, IRQF_SHARED,
+ mgp->dev->name, &mgp->ss[0]);
+ if (status != 0) {
+ dev_err(&pdev->dev, "failed to allocate IRQ\n");
+ if (mgp->msi_enabled)
+ pci_disable_msi(pdev);
+ }
}
return status;
}
@@ -1863,10 +2126,18 @@
static void myri10ge_free_irq(struct myri10ge_priv *mgp)
{
struct pci_dev *pdev = mgp->pdev;
+ int i;
- free_irq(pdev->irq, mgp);
+ if (mgp->msix_enabled) {
+ for (i = 0; i < mgp->num_slices; i++)
+ free_irq(mgp->msix_vectors[i].vector, &mgp->ss[i]);
+ } else {
+ free_irq(pdev->irq, &mgp->ss[0]);
+ }
if (mgp->msi_enabled)
pci_disable_msi(pdev);
+ if (mgp->msix_enabled)
+ pci_disable_msix(pdev);
}
static int
@@ -1928,12 +2199,82 @@
return 0;
}
+static int myri10ge_get_txrx(struct myri10ge_priv *mgp, int slice)
+{
+ struct myri10ge_cmd cmd;
+ struct myri10ge_slice_state *ss;
+ int status;
+
+ ss = &mgp->ss[slice];
+ cmd.data0 = 0; /* single slice for now */
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET, &cmd, 0);
+ ss->tx.lanai = (struct mcp_kreq_ether_send __iomem *)
+ (mgp->sram + cmd.data0);
+
+ cmd.data0 = slice;
+ status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SMALL_RX_OFFSET,
+ &cmd, 0);
+ ss->rx_small.lanai = (struct mcp_kreq_ether_recv __iomem *)
+ (mgp->sram + cmd.data0);
+
+ cmd.data0 = slice;
+ status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd, 0);
+ ss->rx_big.lanai = (struct mcp_kreq_ether_recv __iomem *)
+ (mgp->sram + cmd.data0);
+
+ if (myri10ge_wcfifo && mgp->wc_enabled) {
+ ss->tx.wc_fifo = (u8 __iomem *)
+ mgp->sram + MXGEFW_ETH_SEND_4 + 64 * slice;
+ ss->rx_small.wc_fifo = (u8 __iomem *)
+ mgp->sram + MXGEFW_ETH_RECV_SMALL + 64 * slice;
+ ss->rx_big.wc_fifo = (u8 __iomem *)
+ mgp->sram + MXGEFW_ETH_RECV_BIG + 64 * slice;
+ } else {
+ ss->tx.wc_fifo = NULL;
+ ss->rx_small.wc_fifo = NULL;
+ ss->rx_big.wc_fifo = NULL;
+ }
+ return status;
+
+}
+
+static int myri10ge_set_stats(struct myri10ge_priv *mgp, int slice)
+{
+ struct myri10ge_cmd cmd;
+ struct myri10ge_slice_state *ss;
+ int status;
+
+ ss = &mgp->ss[slice];
+ cmd.data0 = MYRI10GE_LOWPART_TO_U32(ss->fw_stats_bus);
+ cmd.data1 = MYRI10GE_HIGHPART_TO_U32(ss->fw_stats_bus);
+ cmd.data2 = sizeof(struct mcp_irq_data);
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd, 0);
+ if (status == -ENOSYS) {
+ dma_addr_t bus = ss->fw_stats_bus;
+ if (slice != 0)
+ return -EINVAL;
+ bus += offsetof(struct mcp_irq_data, send_done_count);
+ cmd.data0 = MYRI10GE_LOWPART_TO_U32(bus);
+ cmd.data1 = MYRI10GE_HIGHPART_TO_U32(bus);
+ status = myri10ge_send_cmd(mgp,
+ MXGEFW_CMD_SET_STATS_DMA_OBSOLETE,
+ &cmd, 0);
+ /* Firmware cannot support multicast without STATS_DMA_V2 */
+ mgp->fw_multicast_support = 0;
+ } else {
+ mgp->fw_multicast_support = 1;
+ }
+ return 0;
+}
+
static int myri10ge_open(struct net_device *dev)
{
+ struct myri10ge_slice_state *ss;
struct myri10ge_priv *mgp = netdev_priv(dev);
struct myri10ge_cmd cmd;
+ int i, status, big_pow2, slice;
+ u8 *itable;
struct net_lro_mgr *lro_mgr;
- int status, big_pow2;
if (mgp->running != MYRI10GE_ETH_STOPPED)
return -EBUSY;
@@ -1945,6 +2286,48 @@
goto abort_with_nothing;
}
+ if (mgp->num_slices > 1) {
+ cmd.data0 = mgp->num_slices;
+ cmd.data1 = 1; /* use MSI-X */
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ENABLE_RSS_QUEUES,
+ &cmd, 0);
+ if (status != 0) {
+ printk(KERN_ERR
+ "myri10ge: %s: failed to set number of slices\n",
+ dev->name);
+ goto abort_with_nothing;
+ }
+ /* setup the indirection table */
+ cmd.data0 = mgp->num_slices;
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_RSS_TABLE_SIZE,
+ &cmd, 0);
+
+ status |= myri10ge_send_cmd(mgp,
+ MXGEFW_CMD_GET_RSS_TABLE_OFFSET,
+ &cmd, 0);
+ if (status != 0) {
+ printk(KERN_ERR
+ "myri10ge: %s: failed to setup rss tables\n",
+ dev->name);
+ }
+
+ /* just enable an identity mapping */
+ itable = mgp->sram + cmd.data0;
+ for (i = 0; i < mgp->num_slices; i++)
+ __raw_writeb(i, &itable[i]);
+
+ cmd.data0 = 1;
+ cmd.data1 = myri10ge_rss_hash;
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_RSS_ENABLE,
+ &cmd, 0);
+ if (status != 0) {
+ printk(KERN_ERR
+ "myri10ge: %s: failed to enable slices\n",
+ dev->name);
+ goto abort_with_nothing;
+ }
+ }
+
status = myri10ge_request_irq(mgp);
if (status != 0)
goto abort_with_nothing;
@@ -1968,41 +2351,6 @@
if (myri10ge_small_bytes > 0)
mgp->small_bytes = myri10ge_small_bytes;
- /* get the lanai pointers to the send and receive rings */
-
- status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET, &cmd, 0);
- mgp->ss.tx.lanai =
- (struct mcp_kreq_ether_send __iomem *)(mgp->sram + cmd.data0);
-
- status |=
- myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SMALL_RX_OFFSET, &cmd, 0);
- mgp->ss.rx_small.lanai =
- (struct mcp_kreq_ether_recv __iomem *)(mgp->sram + cmd.data0);
-
- status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd, 0);
- mgp->ss.rx_big.lanai =
- (struct mcp_kreq_ether_recv __iomem *)(mgp->sram + cmd.data0);
-
- if (status != 0) {
- printk(KERN_ERR
- "myri10ge: %s: failed to get ring sizes or locations\n",
- dev->name);
- mgp->running = MYRI10GE_ETH_STOPPED;
- goto abort_with_irq;
- }
-
- if (myri10ge_wcfifo && mgp->wc_enabled) {
- mgp->ss.tx.wc_fifo = (u8 __iomem *) mgp->sram + MXGEFW_ETH_SEND_4;
- mgp->ss.rx_small.wc_fifo =
- (u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_SMALL;
- mgp->ss.rx_big.wc_fifo =
- (u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_BIG;
- } else {
- mgp->ss.tx.wc_fifo = NULL;
- mgp->ss.rx_small.wc_fifo = NULL;
- mgp->ss.rx_big.wc_fifo = NULL;
- }
-
/* Firmware needs the big buff size as a power of 2. Lie and
* tell him the buffer is larger, because we only use 1
* buffer/pkt, and the mtu will prevent overruns.
@@ -2017,9 +2365,44 @@
mgp->big_bytes = big_pow2;
}
- status = myri10ge_allocate_rings(&mgp->ss);
- if (status != 0)
- goto abort_with_irq;
+ /* setup the per-slice data structures */
+ for (slice = 0; slice < mgp->num_slices; slice++) {
+ ss = &mgp->ss[slice];
+
+ status = myri10ge_get_txrx(mgp, slice);
+ if (status != 0) {
+ printk(KERN_ERR
+ "myri10ge: %s: failed to get ring sizes or locations\n",
+ dev->name);
+ goto abort_with_rings;
+ }
+ status = myri10ge_allocate_rings(ss);
+ if (status != 0)
+ goto abort_with_rings;
+ if (slice == 0)
+ status = myri10ge_set_stats(mgp, slice);
+ if (status) {
+ printk(KERN_ERR
+ "myri10ge: %s: Couldn't set stats DMA\n",
+ dev->name);
+ goto abort_with_rings;
+ }
+
+ lro_mgr = &ss->rx_done.lro_mgr;
+ lro_mgr->dev = dev;
+ lro_mgr->features = LRO_F_NAPI;
+ lro_mgr->ip_summed = CHECKSUM_COMPLETE;
+ lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY;
+ lro_mgr->max_desc = MYRI10GE_MAX_LRO_DESCRIPTORS;
+ lro_mgr->lro_arr = ss->rx_done.lro_desc;
+ lro_mgr->get_frag_header = myri10ge_get_frag_header;
+ lro_mgr->max_aggr = myri10ge_lro_max_pkts;
+ if (lro_mgr->max_aggr > MAX_SKB_FRAGS)
+ lro_mgr->max_aggr = MAX_SKB_FRAGS;
+
+ /* must happen prior to any irq */
+ napi_enable(&(ss)->napi);
+ }
/* now give firmware buffers sizes, and MTU */
cmd.data0 = dev->mtu + ETH_HLEN + VLAN_HLEN;
@@ -2036,25 +2419,15 @@
goto abort_with_rings;
}
- cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->ss.fw_stats_bus);
- cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->ss.fw_stats_bus);
- cmd.data2 = sizeof(struct mcp_irq_data);
- status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd, 0);
- if (status == -ENOSYS) {
- dma_addr_t bus = mgp->ss.fw_stats_bus;
- bus += offsetof(struct mcp_irq_data, send_done_count);
- cmd.data0 = MYRI10GE_LOWPART_TO_U32(bus);
- cmd.data1 = MYRI10GE_HIGHPART_TO_U32(bus);
- status = myri10ge_send_cmd(mgp,
- MXGEFW_CMD_SET_STATS_DMA_OBSOLETE,
- &cmd, 0);
- /* Firmware cannot support multicast without STATS_DMA_V2 */
- mgp->fw_multicast_support = 0;
- } else {
- mgp->fw_multicast_support = 1;
- }
- if (status) {
- printk(KERN_ERR "myri10ge: %s: Couldn't set stats DMA\n",
+ /*
+ * Set Linux style TSO mode; this is needed only on newer
+ * firmware versions. Older versions default to Linux
+ * style TSO
+ */
+ cmd.data0 = 0;
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_TSO_MODE, &cmd, 0);
+ if (status && status != -ENOSYS) {
+ printk(KERN_ERR "myri10ge: %s: Couldn't set TSO mode\n",
dev->name);
goto abort_with_rings;
}
@@ -2062,21 +2435,6 @@
mgp->link_state = ~0U;
mgp->rdma_tags_available = 15;
- lro_mgr = &mgp->ss.rx_done.lro_mgr;
- lro_mgr->dev = dev;
- lro_mgr->features = LRO_F_NAPI;
- lro_mgr->ip_summed = CHECKSUM_COMPLETE;
- lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY;
- lro_mgr->max_desc = MYRI10GE_MAX_LRO_DESCRIPTORS;
- lro_mgr->lro_arr = mgp->ss.rx_done.lro_desc;
- lro_mgr->get_frag_header = myri10ge_get_frag_header;
- lro_mgr->max_aggr = myri10ge_lro_max_pkts;
- lro_mgr->frag_align_pad = 2;
- if (lro_mgr->max_aggr > MAX_SKB_FRAGS)
- lro_mgr->max_aggr = MAX_SKB_FRAGS;
-
- napi_enable(&mgp->ss.napi); /* must happen prior to any irq */
-
status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_UP, &cmd, 0);
if (status) {
printk(KERN_ERR "myri10ge: %s: Couldn't bring up link\n",
@@ -2084,8 +2442,6 @@
goto abort_with_rings;
}
- mgp->ss.tx.wake_queue = 0;
- mgp->ss.tx.stop_queue = 0;
mgp->running = MYRI10GE_ETH_RUNNING;
mgp->watchdog_timer.expires = jiffies + myri10ge_watchdog_timeout * HZ;
add_timer(&mgp->watchdog_timer);
@@ -2093,9 +2449,9 @@
return 0;
abort_with_rings:
- myri10ge_free_rings(&mgp->ss);
+ for (i = 0; i < mgp->num_slices; i++)
+ myri10ge_free_rings(&mgp->ss[i]);
-abort_with_irq:
myri10ge_free_irq(mgp);
abort_with_nothing:
@@ -2108,16 +2464,19 @@
struct myri10ge_priv *mgp = netdev_priv(dev);
struct myri10ge_cmd cmd;
int status, old_down_cnt;
+ int i;
if (mgp->running != MYRI10GE_ETH_RUNNING)
return 0;
- if (mgp->ss.tx.req_bytes == NULL)
+ if (mgp->ss[0].tx.req_bytes == NULL)
return 0;
del_timer_sync(&mgp->watchdog_timer);
mgp->running = MYRI10GE_ETH_STOPPING;
- napi_disable(&mgp->ss.napi);
+ for (i = 0; i < mgp->num_slices; i++) {
+ napi_disable(&mgp->ss[i].napi);
+ }
netif_carrier_off(dev);
netif_stop_queue(dev);
old_down_cnt = mgp->down_cnt;
@@ -2133,7 +2492,8 @@
netif_tx_disable(dev);
myri10ge_free_irq(mgp);
- myri10ge_free_rings(&mgp->ss);
+ for (i = 0; i < mgp->num_slices; i++)
+ myri10ge_free_rings(&mgp->ss[i]);
mgp->running = MYRI10GE_ETH_STOPPED;
return 0;
@@ -2254,7 +2614,7 @@
u8 flags, odd_flag;
/* always transmit through slot 0 */
- ss = &mgp->ss;
+ ss = mgp->ss;
tx = &ss->tx;
again:
req = tx->req_list;
@@ -2559,7 +2919,21 @@
static struct net_device_stats *myri10ge_get_stats(struct net_device *dev)
{
struct myri10ge_priv *mgp = netdev_priv(dev);
- return &mgp->stats;
+ struct myri10ge_slice_netstats *slice_stats;
+ struct net_device_stats *stats = &mgp->stats;
+ int i;
+
+ memset(stats, 0, sizeof(*stats));
+ for (i = 0; i < mgp->num_slices; i++) {
+ slice_stats = &mgp->ss[i].stats;
+ stats->rx_packets += slice_stats->rx_packets;
+ stats->tx_packets += slice_stats->tx_packets;
+ stats->rx_bytes += slice_stats->rx_bytes;
+ stats->tx_bytes += slice_stats->tx_bytes;
+ stats->rx_dropped += slice_stats->rx_dropped;
+ stats->tx_dropped += slice_stats->tx_dropped;
+ }
+ return stats;
}
static void myri10ge_set_multicast_list(struct net_device *dev)
@@ -2770,10 +3144,10 @@
*
* If the driver can neither enable ECRC nor verify that it has
* already been enabled, then it must use a firmware image which works
- * around unaligned completion packets (myri10ge_ethp_z8e.dat), and it
+ * around unaligned completion packets (myri10ge_rss_ethp_z8e.dat), and it
* should also ensure that it never gives the device a Read-DMA which is
* larger than 2KB by setting the tx_boundary to 2KB. If ECRC is
- * enabled, then the driver should use the aligned (myri10ge_eth_z8e.dat)
+ * enabled, then the driver should use the aligned (myri10ge_rss_eth_z8e.dat)
* firmware image, and set tx_boundary to 4KB.
*/
@@ -2802,7 +3176,7 @@
* completions) in order to see if it works on this host.
*/
mgp->fw_name = myri10ge_fw_aligned;
- status = myri10ge_load_firmware(mgp);
+ status = myri10ge_load_firmware(mgp, 1);
if (status != 0) {
goto abort;
}
@@ -2983,6 +3357,7 @@
struct myri10ge_tx_buf *tx;
u32 reboot;
int status;
+ int i;
u16 cmd, vendor;
mgp->watchdog_resets++;
@@ -3030,20 +3405,26 @@
printk(KERN_ERR "myri10ge: %s: device timeout, resetting\n",
mgp->dev->name);
- tx = &mgp->ss.tx;
- printk(KERN_INFO "myri10ge: %s: %d %d %d %d %d\n",
- mgp->dev->name, tx->req, tx->done,
- tx->pkt_start, tx->pkt_done,
- (int)ntohl(mgp->ss.fw_stats->send_done_count));
- msleep(2000);
- printk(KERN_INFO "myri10ge: %s: %d %d %d %d %d\n",
- mgp->dev->name, tx->req, tx->done,
- tx->pkt_start, tx->pkt_done,
- (int)ntohl(mgp->ss.fw_stats->send_done_count));
+ for (i = 0; i < mgp->num_slices; i++) {
+ tx = &mgp->ss[i].tx;
+ printk(KERN_INFO
+ "myri10ge: %s: (%d): %d %d %d %d %d\n",
+ mgp->dev->name, i, tx->req, tx->done,
+ tx->pkt_start, tx->pkt_done,
+ (int)ntohl(mgp->ss[i].fw_stats->
+ send_done_count));
+ msleep(2000);
+ printk(KERN_INFO
+ "myri10ge: %s: (%d): %d %d %d %d %d\n",
+ mgp->dev->name, i, tx->req, tx->done,
+ tx->pkt_start, tx->pkt_done,
+ (int)ntohl(mgp->ss[i].fw_stats->
+ send_done_count));
+ }
}
rtnl_lock();
myri10ge_close(mgp->dev);
- status = myri10ge_load_firmware(mgp);
+ status = myri10ge_load_firmware(mgp, 1);
if (status != 0)
printk(KERN_ERR "myri10ge: %s: failed to load firmware\n",
mgp->dev->name);
@@ -3063,47 +3444,241 @@
{
struct myri10ge_priv *mgp;
struct myri10ge_slice_state *ss;
+ int i, reset_needed;
u32 rx_pause_cnt;
mgp = (struct myri10ge_priv *)arg;
- rx_pause_cnt = ntohl(mgp->ss.fw_stats->dropped_pause);
+ rx_pause_cnt = ntohl(mgp->ss[0].fw_stats->dropped_pause);
+ for (i = 0, reset_needed = 0;
+ i < mgp->num_slices && reset_needed == 0; ++i) {
- ss = &mgp->ss;
- if (ss->rx_small.watchdog_needed) {
- myri10ge_alloc_rx_pages(mgp, &ss->rx_small,
- mgp->small_bytes + MXGEFW_PAD, 1);
- if (ss->rx_small.fill_cnt - ss->rx_small.cnt >=
- myri10ge_fill_thresh)
- ss->rx_small.watchdog_needed = 0;
- }
- if (ss->rx_big.watchdog_needed) {
- myri10ge_alloc_rx_pages(mgp, &ss->rx_big, mgp->big_bytes, 1);
- if (ss->rx_big.fill_cnt - ss->rx_big.cnt >=
- myri10ge_fill_thresh)
- ss->rx_big.watchdog_needed = 0;
- }
+ ss = &mgp->ss[i];
+ if (ss->rx_small.watchdog_needed) {
+ myri10ge_alloc_rx_pages(mgp, &ss->rx_small,
+ mgp->small_bytes + MXGEFW_PAD,
+ 1);
+ if (ss->rx_small.fill_cnt - ss->rx_small.cnt >=
+ myri10ge_fill_thresh)
+ ss->rx_small.watchdog_needed = 0;
+ }
+ if (ss->rx_big.watchdog_needed) {
+ myri10ge_alloc_rx_pages(mgp, &ss->rx_big,
+ mgp->big_bytes, 1);
+ if (ss->rx_big.fill_cnt - ss->rx_big.cnt >=
+ myri10ge_fill_thresh)
+ ss->rx_big.watchdog_needed = 0;
+ }
- if (ss->tx.req != ss->tx.done &&
- ss->tx.done == ss->watchdog_tx_done &&
- ss->watchdog_tx_req != ss->watchdog_tx_done) {
- /* nic seems like it might be stuck.. */
- if (rx_pause_cnt != mgp->watchdog_pause) {
- if (net_ratelimit())
- printk(KERN_WARNING "myri10ge %s:"
- "TX paused, check link partner\n",
- mgp->dev->name);
- } else {
- schedule_work(&mgp->watchdog_work);
- return;
+ if (ss->tx.req != ss->tx.done &&
+ ss->tx.done == ss->watchdog_tx_done &&
+ ss->watchdog_tx_req != ss->watchdog_tx_done) {
+ /* nic seems like it might be stuck.. */
+ if (rx_pause_cnt != mgp->watchdog_pause) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "myri10ge %s:"
+ "TX paused, check link partner\n",
+ mgp->dev->name);
+ } else {
+ reset_needed = 1;
+ }
+ }
+ ss->watchdog_tx_done = ss->tx.done;
+ ss->watchdog_tx_req = ss->tx.req;
+ }
+ mgp->watchdog_pause = rx_pause_cnt;
+
+ if (reset_needed) {
+ schedule_work(&mgp->watchdog_work);
+ } else {
+ /* rearm timer */
+ mod_timer(&mgp->watchdog_timer,
+ jiffies + myri10ge_watchdog_timeout * HZ);
+ }
+}
+
+static void myri10ge_free_slices(struct myri10ge_priv *mgp)
+{
+ struct myri10ge_slice_state *ss;
+ struct pci_dev *pdev = mgp->pdev;
+ size_t bytes;
+ int i;
+
+ if (mgp->ss == NULL)
+ return;
+
+ for (i = 0; i < mgp->num_slices; i++) {
+ ss = &mgp->ss[i];
+ if (ss->rx_done.entry != NULL) {
+ bytes = mgp->max_intr_slots *
+ sizeof(*ss->rx_done.entry);
+ dma_free_coherent(&pdev->dev, bytes,
+ ss->rx_done.entry, ss->rx_done.bus);
+ ss->rx_done.entry = NULL;
+ }
+ if (ss->fw_stats != NULL) {
+ bytes = sizeof(*ss->fw_stats);
+ dma_free_coherent(&pdev->dev, bytes,
+ ss->fw_stats, ss->fw_stats_bus);
+ ss->fw_stats = NULL;
}
}
- /* rearm timer */
- mod_timer(&mgp->watchdog_timer,
- jiffies + myri10ge_watchdog_timeout * HZ);
- ss->watchdog_tx_done = ss->tx.done;
- ss->watchdog_tx_req = ss->tx.req;
- mgp->watchdog_pause = rx_pause_cnt;
+ kfree(mgp->ss);
+ mgp->ss = NULL;
+}
+
+static int myri10ge_alloc_slices(struct myri10ge_priv *mgp)
+{
+ struct myri10ge_slice_state *ss;
+ struct pci_dev *pdev = mgp->pdev;
+ size_t bytes;
+ int i;
+
+ bytes = sizeof(*mgp->ss) * mgp->num_slices;
+ mgp->ss = kzalloc(bytes, GFP_KERNEL);
+ if (mgp->ss == NULL) {
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < mgp->num_slices; i++) {
+ ss = &mgp->ss[i];
+ bytes = mgp->max_intr_slots * sizeof(*ss->rx_done.entry);
+ ss->rx_done.entry = dma_alloc_coherent(&pdev->dev, bytes,
+ &ss->rx_done.bus,
+ GFP_KERNEL);
+ if (ss->rx_done.entry == NULL)
+ goto abort;
+ memset(ss->rx_done.entry, 0, bytes);
+ bytes = sizeof(*ss->fw_stats);
+ ss->fw_stats = dma_alloc_coherent(&pdev->dev, bytes,
+ &ss->fw_stats_bus,
+ GFP_KERNEL);
+ if (ss->fw_stats == NULL)
+ goto abort;
+ ss->mgp = mgp;
+ ss->dev = mgp->dev;
+ netif_napi_add(ss->dev, &ss->napi, myri10ge_poll,
+ myri10ge_napi_weight);
+ }
+ return 0;
+abort:
+ myri10ge_free_slices(mgp);
+ return -ENOMEM;
+}
+
+/*
+ * This function determines the number of slices supported.
+ * The number slices is the minumum of the number of CPUS,
+ * the number of MSI-X irqs supported, the number of slices
+ * supported by the firmware
+ */
+static void myri10ge_probe_slices(struct myri10ge_priv *mgp)
+{
+ struct myri10ge_cmd cmd;
+ struct pci_dev *pdev = mgp->pdev;
+ char *old_fw;
+ int i, status, ncpus, msix_cap;
+
+ mgp->num_slices = 1;
+ msix_cap = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
+ ncpus = num_online_cpus();
+
+ if (myri10ge_max_slices == 1 || msix_cap == 0 ||
+ (myri10ge_max_slices == -1 && ncpus < 2))
+ return;
+
+ /* try to load the slice aware rss firmware */
+ old_fw = mgp->fw_name;
+ if (old_fw == myri10ge_fw_aligned)
+ mgp->fw_name = myri10ge_fw_rss_aligned;
+ else
+ mgp->fw_name = myri10ge_fw_rss_unaligned;
+ status = myri10ge_load_firmware(mgp, 0);
+ if (status != 0) {
+ dev_info(&pdev->dev, "Rss firmware not found\n");
+ return;
+ }
+
+ /* hit the board with a reset to ensure it is alive */
+ memset(&cmd, 0, sizeof(cmd));
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_RESET, &cmd, 0);
+ if (status != 0) {
+ dev_err(&mgp->pdev->dev, "failed reset\n");
+ goto abort_with_fw;
+ return;
+ }
+
+ mgp->max_intr_slots = cmd.data0 / sizeof(struct mcp_slot);
+
+ /* tell it the size of the interrupt queues */
+ cmd.data0 = mgp->max_intr_slots * sizeof(struct mcp_slot);
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd, 0);
+ if (status != 0) {
+ dev_err(&mgp->pdev->dev, "failed MXGEFW_CMD_SET_INTRQ_SIZE\n");
+ goto abort_with_fw;
+ }
+
+ /* ask the maximum number of slices it supports */
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_RSS_QUEUES, &cmd, 0);
+ if (status != 0)
+ goto abort_with_fw;
+ else
+ mgp->num_slices = cmd.data0;
+
+ /* Only allow multiple slices if MSI-X is usable */
+ if (!myri10ge_msi) {
+ goto abort_with_fw;
+ }
+
+ /* if the admin did not specify a limit to how many
+ * slices we should use, cap it automatically to the
+ * number of CPUs currently online */
+ if (myri10ge_max_slices == -1)
+ myri10ge_max_slices = ncpus;
+
+ if (mgp->num_slices > myri10ge_max_slices)
+ mgp->num_slices = myri10ge_max_slices;
+
+ /* Now try to allocate as many MSI-X vectors as we have
+ * slices. We give up on MSI-X if we can only get a single
+ * vector. */
+
+ mgp->msix_vectors = kzalloc(mgp->num_slices *
+ sizeof(*mgp->msix_vectors), GFP_KERNEL);
+ if (mgp->msix_vectors == NULL)
+ goto disable_msix;
+ for (i = 0; i < mgp->num_slices; i++) {
+ mgp->msix_vectors[i].entry = i;
+ }
+
+ while (mgp->num_slices > 1) {
+ /* make sure it is a power of two */
+ while (!is_power_of_2(mgp->num_slices))
+ mgp->num_slices--;
+ if (mgp->num_slices == 1)
+ goto disable_msix;
+ status = pci_enable_msix(pdev, mgp->msix_vectors,
+ mgp->num_slices);
+ if (status == 0) {
+ pci_disable_msix(pdev);
+ return;
+ }
+ if (status > 0)
+ mgp->num_slices = status;
+ else
+ goto disable_msix;
+ }
+
+disable_msix:
+ if (mgp->msix_vectors != NULL) {
+ kfree(mgp->msix_vectors);
+ mgp->msix_vectors = NULL;
+ }
+
+abort_with_fw:
+ mgp->num_slices = 1;
+ mgp->fw_name = old_fw;
+ myri10ge_load_firmware(mgp, 0);
}
static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -3111,7 +3686,6 @@
struct net_device *netdev;
struct myri10ge_priv *mgp;
struct device *dev = &pdev->dev;
- size_t bytes;
int i;
int status = -ENXIO;
int dac_enabled;
@@ -3126,7 +3700,6 @@
mgp = netdev_priv(netdev);
mgp->dev = netdev;
- netif_napi_add(netdev, &mgp->ss.napi, myri10ge_poll, myri10ge_napi_weight);
mgp->pdev = pdev;
mgp->csum_flag = MXGEFW_FLAGS_CKSUM;
mgp->pause = myri10ge_flow_control;
@@ -3172,11 +3745,6 @@
if (mgp->cmd == NULL)
goto abort_with_netdev;
- mgp->ss.fw_stats = dma_alloc_coherent(&pdev->dev, sizeof(*mgp->ss.fw_stats),
- &mgp->ss.fw_stats_bus, GFP_KERNEL);
- if (mgp->ss.fw_stats == NULL)
- goto abort_with_cmd;
-
mgp->board_span = pci_resource_len(pdev, 0);
mgp->iomem_base = pci_resource_start(pdev, 0);
mgp->mtrr = -1;
@@ -3213,28 +3781,28 @@
for (i = 0; i < ETH_ALEN; i++)
netdev->dev_addr[i] = mgp->mac_addr[i];
- /* allocate rx done ring */
- bytes = mgp->max_intr_slots * sizeof(*mgp->ss.rx_done.entry);
- mgp->ss.rx_done.entry = dma_alloc_coherent(&pdev->dev, bytes,
- &mgp->ss.rx_done.bus, GFP_KERNEL);
- if (mgp->ss.rx_done.entry == NULL)
- goto abort_with_ioremap;
- memset(mgp->ss.rx_done.entry, 0, bytes);
-
myri10ge_select_firmware(mgp);
- status = myri10ge_load_firmware(mgp);
+ status = myri10ge_load_firmware(mgp, 1);
if (status != 0) {
dev_err(&pdev->dev, "failed to load firmware\n");
- goto abort_with_rx_done;
+ goto abort_with_ioremap;
+ }
+ myri10ge_probe_slices(mgp);
+ status = myri10ge_alloc_slices(mgp);
+ if (status != 0) {
+ dev_err(&pdev->dev, "failed to alloc slice state\n");
+ goto abort_with_firmware;
}
status = myri10ge_reset(mgp);
if (status != 0) {
dev_err(&pdev->dev, "failed reset\n");
- goto abort_with_firmware;
+ goto abort_with_slices;
}
-
+#ifdef CONFIG_DCA
+ myri10ge_setup_dca(mgp);
+#endif
pci_set_drvdata(pdev, mgp);
if ((myri10ge_initial_mtu + ETH_HLEN) > MYRI10GE_MAX_ETHER_MTU)
myri10ge_initial_mtu = MYRI10GE_MAX_ETHER_MTU - ETH_HLEN;
@@ -3277,24 +3845,27 @@
dev_err(&pdev->dev, "register_netdev failed: %d\n", status);
goto abort_with_state;
}
- dev_info(dev, "%s IRQ %d, tx bndry %d, fw %s, WC %s\n",
- (mgp->msi_enabled ? "MSI" : "xPIC"),
- netdev->irq, mgp->tx_boundary, mgp->fw_name,
- (mgp->wc_enabled ? "Enabled" : "Disabled"));
+ if (mgp->msix_enabled)
+ dev_info(dev, "%d MSI-X IRQs, tx bndry %d, fw %s, WC %s\n",
+ mgp->num_slices, mgp->tx_boundary, mgp->fw_name,
+ (mgp->wc_enabled ? "Enabled" : "Disabled"));
+ else
+ dev_info(dev, "%s IRQ %d, tx bndry %d, fw %s, WC %s\n",
+ mgp->msi_enabled ? "MSI" : "xPIC",
+ netdev->irq, mgp->tx_boundary, mgp->fw_name,
+ (mgp->wc_enabled ? "Enabled" : "Disabled"));
return 0;
abort_with_state:
pci_restore_state(pdev);
+abort_with_slices:
+ myri10ge_free_slices(mgp);
+
abort_with_firmware:
myri10ge_dummy_rdma(mgp, 0);
-abort_with_rx_done:
- bytes = mgp->max_intr_slots * sizeof(*mgp->ss.rx_done.entry);
- dma_free_coherent(&pdev->dev, bytes,
- mgp->ss.rx_done.entry, mgp->ss.rx_done.bus);
-
abort_with_ioremap:
iounmap(mgp->sram);
@@ -3303,10 +3874,6 @@
if (mgp->mtrr >= 0)
mtrr_del(mgp->mtrr, mgp->iomem_base, mgp->board_span);
#endif
- dma_free_coherent(&pdev->dev, sizeof(*mgp->ss.fw_stats),
- mgp->ss.fw_stats, mgp->ss.fw_stats_bus);
-
-abort_with_cmd:
dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd),
mgp->cmd, mgp->cmd_bus);
@@ -3327,7 +3894,6 @@
{
struct myri10ge_priv *mgp;
struct net_device *netdev;
- size_t bytes;
mgp = pci_get_drvdata(pdev);
if (mgp == NULL)
@@ -3337,24 +3903,23 @@
netdev = mgp->dev;
unregister_netdev(netdev);
+#ifdef CONFIG_DCA
+ myri10ge_teardown_dca(mgp);
+#endif
myri10ge_dummy_rdma(mgp, 0);
/* avoid a memory leak */
pci_restore_state(pdev);
- bytes = mgp->max_intr_slots * sizeof(*mgp->ss.rx_done.entry);
- dma_free_coherent(&pdev->dev, bytes,
- mgp->ss.rx_done.entry, mgp->ss.rx_done.bus);
-
iounmap(mgp->sram);
#ifdef CONFIG_MTRR
if (mgp->mtrr >= 0)
mtrr_del(mgp->mtrr, mgp->iomem_base, mgp->board_span);
#endif
- dma_free_coherent(&pdev->dev, sizeof(*mgp->ss.fw_stats),
- mgp->ss.fw_stats, mgp->ss.fw_stats_bus);
-
+ myri10ge_free_slices(mgp);
+ if (mgp->msix_vectors != NULL)
+ kfree(mgp->msix_vectors);
dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd),
mgp->cmd, mgp->cmd_bus);
@@ -3383,10 +3948,42 @@
#endif
};
+#ifdef CONFIG_DCA
+static int
+myri10ge_notify_dca(struct notifier_block *nb, unsigned long event, void *p)
+{
+ int err = driver_for_each_device(&myri10ge_driver.driver,
+ NULL, &event,
+ myri10ge_notify_dca_device);
+
+ if (err)
+ return NOTIFY_BAD;
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block myri10ge_dca_notifier = {
+ .notifier_call = myri10ge_notify_dca,
+ .next = NULL,
+ .priority = 0,
+};
+#endif /* CONFIG_DCA */
+
static __init int myri10ge_init_module(void)
{
printk(KERN_INFO "%s: Version %s\n", myri10ge_driver.name,
MYRI10GE_VERSION_STR);
+
+ if (myri10ge_rss_hash > MXGEFW_RSS_HASH_TYPE_SRC_PORT ||
+ myri10ge_rss_hash < MXGEFW_RSS_HASH_TYPE_IPV4) {
+ printk(KERN_ERR
+ "%s: Illegal rssh hash type %d, defaulting to source port\n",
+ myri10ge_driver.name, myri10ge_rss_hash);
+ myri10ge_rss_hash = MXGEFW_RSS_HASH_TYPE_SRC_PORT;
+ }
+#ifdef CONFIG_DCA
+ dca_register_notify(&myri10ge_dca_notifier);
+#endif
+
return pci_register_driver(&myri10ge_driver);
}
@@ -3394,6 +3991,9 @@
static __exit void myri10ge_cleanup_module(void)
{
+#ifdef CONFIG_DCA
+ dca_unregister_notify(&myri10ge_dca_notifier);
+#endif
pci_unregister_driver(&myri10ge_driver);
}
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/ns83820.c b/drivers/net/ns83820.c
index b42c05f..ff44961 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -585,16 +585,13 @@
for (i=0; i<NR_RX_DESC; i++) {
struct sk_buff *skb;
long res;
+
/* extra 16 bytes for alignment */
- skb = __dev_alloc_skb(REAL_RX_BUF_SIZE+16, gfp);
+ skb = __netdev_alloc_skb(ndev, REAL_RX_BUF_SIZE+16, gfp);
if (unlikely(!skb))
break;
- res = (long)skb->data & 0xf;
- res = 0x10 - res;
- res &= 0xf;
- skb_reserve(skb, res);
-
+ skb_reserve(skb, skb->data - PTR_ALIGN(skb->data, 16));
if (gfp != GFP_ATOMIC)
spin_lock_irqsave(&dev->rx_info.lock, flags);
res = ns83820_add_rx_skb(dev, skb);
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 1c89b97..ca8c0e0 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/phy/Kconfig b/drivers/net/phy/Kconfig
index 6eb2d31..d55932a 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -53,7 +53,8 @@
config BROADCOM_PHY
tristate "Drivers for Broadcom PHYs"
---help---
- Currently supports the BCM5411, BCM5421 and BCM5461 PHYs.
+ Currently supports the BCM5411, BCM5421, BCM5461, BCM5464, BCM5481
+ and BCM5482 PHYs.
config ICPLUS_PHY
tristate "Drivers for ICPlus PHYs"
@@ -83,4 +84,10 @@
If in doubt, say N.
+config MDIO_OF_GPIO
+ tristate "Support for GPIO lib-based bitbanged MDIO buses"
+ depends on MDIO_BITBANG && OF_GPIO
+ ---help---
+ Supports GPIO lib-based MDIO busses.
+
endif # PHYLIB
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 5997d6e..eee329f 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -15,3 +15,4 @@
obj-$(CONFIG_REALTEK_PHY) += realtek.o
obj-$(CONFIG_FIXED_PHY) += fixed.o
obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
+obj-$(CONFIG_MDIO_OF_GPIO) += mdio-ofgpio.o
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index 60c5cfe..4b4dc98 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -24,6 +24,12 @@
#define MII_BCM54XX_ESR 0x11 /* BCM54xx extended status register */
#define MII_BCM54XX_ESR_IS 0x1000 /* Interrupt status */
+#define MII_BCM54XX_EXP_DATA 0x15 /* Expansion register data */
+#define MII_BCM54XX_EXP_SEL 0x17 /* Expansion register select */
+#define MII_BCM54XX_EXP_SEL_SSD 0x0e00 /* Secondary SerDes select */
+#define MII_BCM54XX_EXP_SEL_ER 0x0f00 /* Expansion register select */
+
+#define MII_BCM54XX_AUX_CTL 0x18 /* Auxiliary control register */
#define MII_BCM54XX_ISR 0x1a /* BCM54xx interrupt status register */
#define MII_BCM54XX_IMR 0x1b /* BCM54xx interrupt mask register */
#define MII_BCM54XX_INT_CRCERR 0x0001 /* CRC error */
@@ -42,10 +48,120 @@
#define MII_BCM54XX_INT_MDIX 0x2000 /* MDIX status change */
#define MII_BCM54XX_INT_PSERR 0x4000 /* Pair swap error */
+#define MII_BCM54XX_SHD 0x1c /* 0x1c shadow registers */
+#define MII_BCM54XX_SHD_WRITE 0x8000
+#define MII_BCM54XX_SHD_VAL(x) ((x & 0x1f) << 10)
+#define MII_BCM54XX_SHD_DATA(x) ((x & 0x3ff) << 0)
+
+/*
+ * Broadcom LED source encodings. These are used in BCM5461, BCM5481,
+ * BCM5482, and possibly some others.
+ */
+#define BCM_LED_SRC_LINKSPD1 0x0
+#define BCM_LED_SRC_LINKSPD2 0x1
+#define BCM_LED_SRC_XMITLED 0x2
+#define BCM_LED_SRC_ACTIVITYLED 0x3
+#define BCM_LED_SRC_FDXLED 0x4
+#define BCM_LED_SRC_SLAVE 0x5
+#define BCM_LED_SRC_INTR 0x6
+#define BCM_LED_SRC_QUALITY 0x7
+#define BCM_LED_SRC_RCVLED 0x8
+#define BCM_LED_SRC_MULTICOLOR1 0xa
+#define BCM_LED_SRC_OPENSHORT 0xb
+#define BCM_LED_SRC_OFF 0xe /* Tied high */
+#define BCM_LED_SRC_ON 0xf /* Tied low */
+
+/*
+ * BCM5482: Shadow registers
+ * Shadow values go into bits [14:10] of register 0x1c to select a shadow
+ * register to access.
+ */
+#define BCM5482_SHD_LEDS1 0x0d /* 01101: LED Selector 1 */
+ /* LED3 / ~LINKSPD[2] selector */
+#define BCM5482_SHD_LEDS1_LED3(src) ((src & 0xf) << 4)
+ /* LED1 / ~LINKSPD[1] selector */
+#define BCM5482_SHD_LEDS1_LED1(src) ((src & 0xf) << 0)
+#define BCM5482_SHD_SSD 0x14 /* 10100: Secondary SerDes control */
+#define BCM5482_SHD_SSD_LEDM 0x0008 /* SSD LED Mode enable */
+#define BCM5482_SHD_SSD_EN 0x0001 /* SSD enable */
+#define BCM5482_SHD_MODE 0x1f /* 11111: Mode Control Register */
+#define BCM5482_SHD_MODE_1000BX 0x0001 /* Enable 1000BASE-X registers */
+
+/*
+ * BCM5482: Secondary SerDes registers
+ */
+#define BCM5482_SSD_1000BX_CTL 0x00 /* 1000BASE-X Control */
+#define BCM5482_SSD_1000BX_CTL_PWRDOWN 0x0800 /* Power-down SSD */
+#define BCM5482_SSD_SGMII_SLAVE 0x15 /* SGMII Slave Register */
+#define BCM5482_SSD_SGMII_SLAVE_EN 0x0002 /* Slave mode enable */
+#define BCM5482_SSD_SGMII_SLAVE_AD 0x0001 /* Slave auto-detection */
+
+/*
+ * Device flags for PHYs that can be configured for different operating
+ * modes.
+ */
+#define PHY_BCM_FLAGS_VALID 0x80000000
+#define PHY_BCM_FLAGS_INTF_XAUI 0x00000020
+#define PHY_BCM_FLAGS_INTF_SGMII 0x00000010
+#define PHY_BCM_FLAGS_MODE_1000BX 0x00000002
+#define PHY_BCM_FLAGS_MODE_COPPER 0x00000001
+
MODULE_DESCRIPTION("Broadcom PHY driver");
MODULE_AUTHOR("Maciej W. Rozycki");
MODULE_LICENSE("GPL");
+/*
+ * Indirect register access functions for the 1000BASE-T/100BASE-TX/10BASE-T
+ * 0x1c shadow registers.
+ */
+static int bcm54xx_shadow_read(struct phy_device *phydev, u16 shadow)
+{
+ phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow));
+ return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD));
+}
+
+static int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow, u16 val)
+{
+ return phy_write(phydev, MII_BCM54XX_SHD,
+ MII_BCM54XX_SHD_WRITE |
+ MII_BCM54XX_SHD_VAL(shadow) |
+ MII_BCM54XX_SHD_DATA(val));
+}
+
+/*
+ * Indirect register access functions for the Expansion Registers
+ * and Secondary SerDes registers (when sec_serdes=1).
+ */
+static int bcm54xx_exp_read(struct phy_device *phydev,
+ int sec_serdes, u8 regnum)
+{
+ int val;
+
+ phy_write(phydev, MII_BCM54XX_EXP_SEL,
+ (sec_serdes ? MII_BCM54XX_EXP_SEL_SSD :
+ MII_BCM54XX_EXP_SEL_ER) |
+ regnum);
+ val = phy_read(phydev, MII_BCM54XX_EXP_DATA);
+ phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
+
+ return val;
+}
+
+static int bcm54xx_exp_write(struct phy_device *phydev,
+ int sec_serdes, u8 regnum, u16 val)
+{
+ int ret;
+
+ phy_write(phydev, MII_BCM54XX_EXP_SEL,
+ (sec_serdes ? MII_BCM54XX_EXP_SEL_SSD :
+ MII_BCM54XX_EXP_SEL_ER) |
+ regnum);
+ ret = phy_write(phydev, MII_BCM54XX_EXP_DATA, val);
+ phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
+
+ return ret;
+}
+
static int bcm54xx_config_init(struct phy_device *phydev)
{
int reg, err;
@@ -70,6 +186,87 @@
return 0;
}
+static int bcm5482_config_init(struct phy_device *phydev)
+{
+ int err, reg;
+
+ err = bcm54xx_config_init(phydev);
+
+ if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
+ /*
+ * Enable secondary SerDes and its use as an LED source
+ */
+ reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_SSD);
+ bcm54xx_shadow_write(phydev, BCM5482_SHD_SSD,
+ reg |
+ BCM5482_SHD_SSD_LEDM |
+ BCM5482_SHD_SSD_EN);
+
+ /*
+ * Enable SGMII slave mode and auto-detection
+ */
+ reg = bcm54xx_exp_read(phydev, 1, BCM5482_SSD_SGMII_SLAVE);
+ bcm54xx_exp_write(phydev, 1, BCM5482_SSD_SGMII_SLAVE,
+ reg |
+ BCM5482_SSD_SGMII_SLAVE_EN |
+ BCM5482_SSD_SGMII_SLAVE_AD);
+
+ /*
+ * Disable secondary SerDes powerdown
+ */
+ reg = bcm54xx_exp_read(phydev, 1, BCM5482_SSD_1000BX_CTL);
+ bcm54xx_exp_write(phydev, 1, BCM5482_SSD_1000BX_CTL,
+ reg & ~BCM5482_SSD_1000BX_CTL_PWRDOWN);
+
+ /*
+ * Select 1000BASE-X register set (primary SerDes)
+ */
+ reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_MODE);
+ bcm54xx_shadow_write(phydev, BCM5482_SHD_MODE,
+ reg | BCM5482_SHD_MODE_1000BX);
+
+ /*
+ * LED1=ACTIVITYLED, LED3=LINKSPD[2]
+ * (Use LED1 as secondary SerDes ACTIVITY LED)
+ */
+ bcm54xx_shadow_write(phydev, BCM5482_SHD_LEDS1,
+ BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) |
+ BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2));
+
+ /*
+ * Auto-negotiation doesn't seem to work quite right
+ * in this mode, so we disable it and force it to the
+ * right speed/duplex setting. Only 'link status'
+ * is important.
+ */
+ phydev->autoneg = AUTONEG_DISABLE;
+ phydev->speed = SPEED_1000;
+ phydev->duplex = DUPLEX_FULL;
+ }
+
+ return err;
+}
+
+static int bcm5482_read_status(struct phy_device *phydev)
+{
+ int err;
+
+ err = genphy_read_status(phydev);
+
+ if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
+ /*
+ * Only link status matters for 1000Base-X mode, so force
+ * 1000 Mbit/s full-duplex status
+ */
+ if (phydev->link) {
+ phydev->speed = SPEED_1000;
+ phydev->duplex = DUPLEX_FULL;
+ }
+ }
+
+ return err;
+}
+
static int bcm54xx_ack_interrupt(struct phy_device *phydev)
{
int reg;
@@ -210,9 +407,9 @@
.name = "Broadcom BCM5482",
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
- .config_init = bcm54xx_config_init,
+ .config_init = bcm5482_config_init,
.config_aneg = genphy_config_aneg,
- .read_status = genphy_read_status,
+ .read_status = bcm5482_read_status,
.ack_interrupt = bcm54xx_ack_interrupt,
.config_intr = bcm54xx_config_intr,
.driver = { .owner = THIS_MODULE },
diff --git a/drivers/net/phy/mdio-ofgpio.c b/drivers/net/phy/mdio-ofgpio.c
new file mode 100644
index 0000000..7edfc0c
--- /dev/null
+++ b/drivers/net/phy/mdio-ofgpio.c
@@ -0,0 +1,205 @@
+/*
+ * OpenFirmware GPIO based MDIO bitbang driver.
+ *
+ * Copyright (c) 2008 CSE Semaphore Belgium.
+ * by Laurent Pinchart <laurentp@cse-semaphore.com>
+ *
+ * Based on earlier work by
+ *
+ * Copyright (c) 2003 Intracom S.A.
+ * by Pantelis Antoniou <panto@intracom.gr>
+ *
+ * 2005 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/mdio-bitbang.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+
+struct mdio_gpio_info {
+ struct mdiobb_ctrl ctrl;
+ int mdc, mdio;
+};
+
+static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
+{
+ struct mdio_gpio_info *bitbang =
+ container_of(ctrl, struct mdio_gpio_info, ctrl);
+
+ if (dir)
+ gpio_direction_output(bitbang->mdio, 1);
+ else
+ gpio_direction_input(bitbang->mdio);
+}
+
+static int mdio_read(struct mdiobb_ctrl *ctrl)
+{
+ struct mdio_gpio_info *bitbang =
+ container_of(ctrl, struct mdio_gpio_info, ctrl);
+
+ return gpio_get_value(bitbang->mdio);
+}
+
+static void mdio(struct mdiobb_ctrl *ctrl, int what)
+{
+ struct mdio_gpio_info *bitbang =
+ container_of(ctrl, struct mdio_gpio_info, ctrl);
+
+ gpio_set_value(bitbang->mdio, what);
+}
+
+static void mdc(struct mdiobb_ctrl *ctrl, int what)
+{
+ struct mdio_gpio_info *bitbang =
+ container_of(ctrl, struct mdio_gpio_info, ctrl);
+
+ gpio_set_value(bitbang->mdc, what);
+}
+
+static struct mdiobb_ops mdio_gpio_ops = {
+ .owner = THIS_MODULE,
+ .set_mdc = mdc,
+ .set_mdio_dir = mdio_dir,
+ .set_mdio_data = mdio,
+ .get_mdio_data = mdio_read,
+};
+
+static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus,
+ struct device_node *np)
+{
+ struct mdio_gpio_info *bitbang = bus->priv;
+
+ bitbang->mdc = of_get_gpio(np, 0);
+ bitbang->mdio = of_get_gpio(np, 1);
+
+ if (bitbang->mdc < 0 || bitbang->mdio < 0)
+ return -ENODEV;
+
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%x", bitbang->mdc);
+ return 0;
+}
+
+static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
+{
+ const u32 *data;
+ int len, id, irq;
+
+ data = of_get_property(np, "reg", &len);
+ if (!data || len != 4)
+ return;
+
+ id = *data;
+ bus->phy_mask &= ~(1 << id);
+
+ irq = of_irq_to_resource(np, 0, NULL);
+ if (irq != NO_IRQ)
+ bus->irq[id] = irq;
+}
+
+static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device_node *np = NULL;
+ struct mii_bus *new_bus;
+ struct mdio_gpio_info *bitbang;
+ int ret = -ENOMEM;
+ int i;
+
+ bitbang = kzalloc(sizeof(struct mdio_gpio_info), GFP_KERNEL);
+ if (!bitbang)
+ goto out;
+
+ bitbang->ctrl.ops = &mdio_gpio_ops;
+
+ new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
+ if (!new_bus)
+ goto out_free_priv;
+
+ new_bus->name = "GPIO Bitbanged MII",
+
+ ret = mdio_ofgpio_bitbang_init(new_bus, ofdev->node);
+ if (ret)
+ goto out_free_bus;
+
+ new_bus->phy_mask = ~0;
+ new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+ if (!new_bus->irq)
+ goto out_free_bus;
+
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ new_bus->irq[i] = -1;
+
+ while ((np = of_get_next_child(ofdev->node, np)))
+ if (!strcmp(np->type, "ethernet-phy"))
+ add_phy(new_bus, np);
+
+ new_bus->dev = &ofdev->dev;
+ dev_set_drvdata(&ofdev->dev, new_bus);
+
+ ret = mdiobus_register(new_bus);
+ if (ret)
+ goto out_free_irqs;
+
+ return 0;
+
+out_free_irqs:
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(new_bus->irq);
+out_free_bus:
+ kfree(new_bus);
+out_free_priv:
+ free_mdio_bitbang(new_bus);
+out:
+ return ret;
+}
+
+static int mdio_ofgpio_remove(struct of_device *ofdev)
+{
+ struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
+ struct mdio_gpio_info *bitbang = bus->priv;
+
+ mdiobus_unregister(bus);
+ free_mdio_bitbang(bus);
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(bus->irq);
+ kfree(bitbang);
+ kfree(bus);
+
+ return 0;
+}
+
+static struct of_device_id mdio_ofgpio_match[] = {
+ {
+ .compatible = "virtual,mdio-gpio",
+ },
+ {},
+};
+
+static struct of_platform_driver mdio_ofgpio_driver = {
+ .name = "mdio-gpio",
+ .match_table = mdio_ofgpio_match,
+ .probe = mdio_ofgpio_probe,
+ .remove = mdio_ofgpio_remove,
+};
+
+static int mdio_ofgpio_init(void)
+{
+ return of_register_platform_driver(&mdio_ofgpio_driver);
+}
+
+static void mdio_ofgpio_exit(void)
+{
+ of_unregister_platform_driver(&mdio_ofgpio_driver);
+}
+
+module_init(mdio_ofgpio_init);
+module_exit(mdio_ofgpio_exit);
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 1f4ca2b..c926bf0 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -361,7 +361,7 @@
return 0;
}
-static int ppp_release(struct inode *inode, struct file *file)
+static int ppp_release(struct inode *unused, struct file *file)
{
struct ppp_file *pf = file->private_data;
struct ppp *ppp;
@@ -545,8 +545,7 @@
}
#endif /* CONFIG_PPP_FILTER */
-static int ppp_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct ppp_file *pf = file->private_data;
struct ppp *ppp;
@@ -574,24 +573,29 @@
* this fd and reopening /dev/ppp.
*/
err = -EINVAL;
+ lock_kernel();
if (pf->kind == INTERFACE) {
ppp = PF_TO_PPP(pf);
if (file == ppp->owner)
ppp_shutdown_interface(ppp);
}
if (atomic_read(&file->f_count) <= 2) {
- ppp_release(inode, file);
+ ppp_release(NULL, file);
err = 0;
} else
printk(KERN_DEBUG "PPPIOCDETACH file->f_count=%d\n",
atomic_read(&file->f_count));
+ unlock_kernel();
return err;
}
if (pf->kind == CHANNEL) {
- struct channel *pch = PF_TO_CHANNEL(pf);
+ struct channel *pch;
struct ppp_channel *chan;
+ lock_kernel();
+ pch = PF_TO_CHANNEL(pf);
+
switch (cmd) {
case PPPIOCCONNECT:
if (get_user(unit, p))
@@ -611,6 +615,7 @@
err = chan->ops->ioctl(chan, cmd, arg);
up_read(&pch->chan_sem);
}
+ unlock_kernel();
return err;
}
@@ -620,6 +625,7 @@
return -EINVAL;
}
+ lock_kernel();
ppp = PF_TO_PPP(pf);
switch (cmd) {
case PPPIOCSMRU:
@@ -767,7 +773,7 @@
default:
err = -ENOTTY;
}
-
+ unlock_kernel();
return err;
}
@@ -779,6 +785,7 @@
struct channel *chan;
int __user *p = (int __user *)arg;
+ lock_kernel();
switch (cmd) {
case PPPIOCNEWUNIT:
/* Create a new ppp unit */
@@ -827,6 +834,7 @@
default:
err = -ENOTTY;
}
+ unlock_kernel();
return err;
}
@@ -835,7 +843,7 @@
.read = ppp_read,
.write = ppp_write,
.poll = ppp_poll,
- .ioctl = ppp_ioctl,
+ .unlocked_ioctl = ppp_ioctl,
.open = ppp_open,
.release = ppp_release
};
diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c
index e365efb..2eb54fd 100644
--- a/drivers/net/ps3_gelic_net.c
+++ b/drivers/net/ps3_gelic_net.c
@@ -110,7 +110,7 @@
void gelic_card_up(struct gelic_card *card)
{
pr_debug("%s: called\n", __func__);
- down(&card->updown_lock);
+ mutex_lock(&card->updown_lock);
if (atomic_inc_return(&card->users) == 1) {
pr_debug("%s: real do\n", __func__);
/* enable irq */
@@ -120,7 +120,7 @@
napi_enable(&card->napi);
}
- up(&card->updown_lock);
+ mutex_unlock(&card->updown_lock);
pr_debug("%s: done\n", __func__);
}
@@ -128,7 +128,7 @@
{
u64 mask;
pr_debug("%s: called\n", __func__);
- down(&card->updown_lock);
+ mutex_lock(&card->updown_lock);
if (atomic_dec_if_positive(&card->users) == 0) {
pr_debug("%s: real do\n", __func__);
napi_disable(&card->napi);
@@ -146,7 +146,7 @@
/* stop tx */
gelic_card_disable_txdmac(card);
}
- up(&card->updown_lock);
+ mutex_unlock(&card->updown_lock);
pr_debug("%s: done\n", __func__);
}
@@ -1534,7 +1534,7 @@
INIT_WORK(&card->tx_timeout_task, gelic_net_tx_timeout_task);
init_waitqueue_head(&card->waitq);
atomic_set(&card->tx_timeout_task_counter, 0);
- init_MUTEX(&card->updown_lock);
+ mutex_init(&card->updown_lock);
atomic_set(&card->users, 0);
return card;
diff --git a/drivers/net/ps3_gelic_net.h b/drivers/net/ps3_gelic_net.h
index 520f143..8b41386 100644
--- a/drivers/net/ps3_gelic_net.h
+++ b/drivers/net/ps3_gelic_net.h
@@ -298,7 +298,7 @@
wait_queue_head_t waitq;
/* only first user should up the card */
- struct semaphore updown_lock;
+ struct mutex updown_lock;
atomic_t users;
u64 ether_port_status;
diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c
index 1dae1f2..aa963ac 100644
--- a/drivers/net/ps3_gelic_wireless.c
+++ b/drivers/net/ps3_gelic_wireless.c
@@ -45,7 +45,8 @@
#include "ps3_gelic_wireless.h"
-static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan);
+static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan,
+ u8 *essid, size_t essid_len);
static int gelic_wl_try_associate(struct net_device *netdev);
/*
@@ -105,6 +106,7 @@
[GELIC_EURUS_CMD_GET_WEP_CFG] = { .post_arg = 1},
[GELIC_EURUS_CMD_GET_WPA_CFG] = { .post_arg = 1},
[GELIC_EURUS_CMD_GET_RSSI_CFG] = { .post_arg = 1},
+ [GELIC_EURUS_CMD_START_SCAN] = { .pre_arg = 1},
[GELIC_EURUS_CMD_GET_SCAN] = { .post_arg = 1},
};
@@ -163,7 +165,9 @@
card = port_to_card(wl_port(wl));
if (cmd_info[cmd->cmd].pre_arg) {
- arg1 = ps3_mm_phys_to_lpar(__pa(cmd->buffer));
+ arg1 = (cmd->buffer) ?
+ ps3_mm_phys_to_lpar(__pa(cmd->buffer)) :
+ 0;
arg2 = cmd->buf_size;
} else {
arg1 = 0;
@@ -240,12 +244,12 @@
u32 ret;
pr_debug("%s: <-\n", __func__);
- down(&wl->assoc_stat_lock);
+ mutex_lock(&wl->assoc_stat_lock);
if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED)
ret = 1;
else
ret = 0;
- up(&wl->assoc_stat_lock);
+ mutex_unlock(&wl->assoc_stat_lock);
pr_debug("%s: ->\n", __func__);
return ret;
}
@@ -350,7 +354,8 @@
/* encryption capability */
range->enc_capa = IW_ENC_CAPA_WPA |
- IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
+ IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP |
+ IW_ENC_CAPA_4WAY_HANDSHAKE;
if (wpa2_capable())
range->enc_capa |= IW_ENC_CAPA_WPA2;
range->encoding_size[0] = 5; /* 40bit WEP */
@@ -359,6 +364,9 @@
range->num_encoding_sizes = 3;
range->max_encoding_tokens = GELIC_WEP_KEYS;
+ /* scan capability */
+ range->scan_capa = IW_SCAN_CAPA_ESSID;
+
pr_debug("%s: ->\n", __func__);
return 0;
@@ -370,8 +378,18 @@
union iwreq_data *wrqu, char *extra)
{
struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
+ struct iw_scan_req *req;
+ u8 *essid = NULL;
+ size_t essid_len = 0;
- return gelic_wl_start_scan(wl, 1);
+ if (wrqu->data.length == sizeof(struct iw_scan_req) &&
+ wrqu->data.flags & IW_SCAN_THIS_ESSID) {
+ req = (struct iw_scan_req*)extra;
+ essid = req->essid;
+ essid_len = req->essid_len;
+ pr_debug("%s: ESSID scan =%s\n", __func__, essid);
+ }
+ return gelic_wl_start_scan(wl, 1, essid, essid_len);
}
#define OUI_LEN 3
@@ -695,7 +713,7 @@
unsigned long this_time = jiffies;
pr_debug("%s: <-\n", __func__);
- if (down_interruptible(&wl->scan_lock))
+ if (mutex_lock_interruptible(&wl->scan_lock))
return -EAGAIN;
switch (wl->scan_stat) {
@@ -733,7 +751,7 @@
wrqu->data.length = ev - extra;
wrqu->data.flags = 0;
out:
- up(&wl->scan_lock);
+ mutex_unlock(&wl->scan_lock);
pr_debug("%s: -> %d %d\n", __func__, ret, wrqu->data.length);
return ret;
}
@@ -979,7 +997,7 @@
unsigned long irqflag;
pr_debug("%s: <- \n", __func__);
- down(&wl->assoc_stat_lock);
+ mutex_lock(&wl->assoc_stat_lock);
spin_lock_irqsave(&wl->lock, irqflag);
if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat) ||
wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) {
@@ -989,7 +1007,7 @@
} else
data->essid.flags = 0;
- up(&wl->assoc_stat_lock);
+ mutex_unlock(&wl->assoc_stat_lock);
spin_unlock_irqrestore(&wl->lock, irqflag);
pr_debug("%s: -> len=%d \n", __func__, data->essid.length);
@@ -1170,7 +1188,7 @@
unsigned long irqflag;
pr_debug("%s: <-\n", __func__);
- down(&wl->assoc_stat_lock);
+ mutex_lock(&wl->assoc_stat_lock);
spin_lock_irqsave(&wl->lock, irqflag);
if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) {
data->ap_addr.sa_family = ARPHRD_ETHER;
@@ -1180,7 +1198,7 @@
memset(data->ap_addr.sa_data, 0, ETH_ALEN);
spin_unlock_irqrestore(&wl->lock, irqflag);
- up(&wl->assoc_stat_lock);
+ mutex_unlock(&wl->assoc_stat_lock);
pr_debug("%s: ->\n", __func__);
return 0;
}
@@ -1256,42 +1274,19 @@
set_bit(key_index, &wl->key_enabled);
/* remember wep info changed */
set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
- } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
- pr_debug("%s: TKIP/CCMP requested alg=%d\n", __func__, alg);
- /* check key length */
- if (IW_ENCODING_TOKEN_MAX < ext->key_len) {
- pr_info("%s: key is too long %d\n", __func__,
- ext->key_len);
+ } else if (alg == IW_ENCODE_ALG_PMK) {
+ if (ext->key_len != WPA_PSK_LEN) {
+ pr_err("%s: PSK length wrong %d\n", __func__,
+ ext->key_len);
ret = -EINVAL;
goto done;
}
- if (alg == IW_ENCODE_ALG_CCMP) {
- pr_debug("%s: AES selected\n", __func__);
- wl->group_cipher_method = GELIC_WL_CIPHER_AES;
- wl->pairwise_cipher_method = GELIC_WL_CIPHER_AES;
- wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA2;
- } else {
- pr_debug("%s: TKIP selected, WPA forced\n", __func__);
- wl->group_cipher_method = GELIC_WL_CIPHER_TKIP;
- wl->pairwise_cipher_method = GELIC_WL_CIPHER_TKIP;
- /* FIXME: how do we do if WPA2 + TKIP? */
- wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA;
- }
- if (flags & IW_ENCODE_RESTRICTED)
- BUG();
- wl->auth_method = GELIC_EURUS_AUTH_OPEN;
- /* We should use same key for both and unicast */
- if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
- pr_debug("%s: group key \n", __func__);
- else
- pr_debug("%s: unicast key \n", __func__);
- /* OK, update the key */
- wl->key_len[key_index] = ext->key_len;
- memset(wl->key[key_index], 0, IW_ENCODING_TOKEN_MAX);
- memcpy(wl->key[key_index], ext->key, ext->key_len);
- set_bit(key_index, &wl->key_enabled);
- /* remember info changed */
- set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
+ memset(wl->psk, 0, sizeof(wl->psk));
+ memcpy(wl->psk, ext->key, ext->key_len);
+ wl->psk_len = ext->key_len;
+ wl->psk_type = GELIC_EURUS_WPA_PSK_BIN;
+ /* remember PSK configured */
+ set_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat);
}
done:
spin_unlock_irqrestore(&wl->lock, irqflag);
@@ -1397,6 +1392,7 @@
return 0;
}
+#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE
/* SIOCIWFIRSTPRIV */
static int hex2bin(u8 *str, u8 *bin, unsigned int len)
{
@@ -1501,6 +1497,7 @@
pr_debug("%s:-> %d\n", __func__, data->data.length);
return 0;
}
+#endif
/* SIOCGIWNICKN */
static int gelic_wl_get_nick(struct net_device *net_dev,
@@ -1524,15 +1521,20 @@
struct gelic_eurus_cmd *cmd;
struct iw_statistics *is;
struct gelic_eurus_rssi_info *rssi;
+ void *buf;
pr_debug("%s: <-\n", __func__);
+ buf = (void *)__get_free_page(GFP_KERNEL);
+ if (!buf)
+ return NULL;
+
is = &wl->iwstat;
memset(is, 0, sizeof(*is));
cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_GET_RSSI_CFG,
- wl->buf, sizeof(*rssi));
+ buf, sizeof(*rssi));
if (cmd && !cmd->status && !cmd->cmd_status) {
- rssi = wl->buf;
+ rssi = buf;
is->qual.level = be16_to_cpu(rssi->rssi);
is->qual.updated = IW_QUAL_LEVEL_UPDATED |
IW_QUAL_QUAL_INVALID | IW_QUAL_NOISE_INVALID;
@@ -1541,6 +1543,7 @@
is->qual.updated = IW_QUAL_ALL_INVALID;
kfree(cmd);
+ free_page((unsigned long)buf);
pr_debug("%s: ->\n", __func__);
return is;
}
@@ -1548,13 +1551,16 @@
/*
* scanning helpers
*/
-static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan)
+static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan,
+ u8 *essid, size_t essid_len)
{
struct gelic_eurus_cmd *cmd;
int ret = 0;
+ void *buf = NULL;
+ size_t len;
pr_debug("%s: <- always=%d\n", __func__, always_scan);
- if (down_interruptible(&wl->scan_lock))
+ if (mutex_lock_interruptible(&wl->scan_lock))
return -ERESTARTSYS;
/*
@@ -1574,12 +1580,27 @@
complete(&wl->scan_done);
goto out;
}
+
+ /* ESSID scan ? */
+ if (essid_len && essid) {
+ buf = (void *)__get_free_page(GFP_KERNEL);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ len = IW_ESSID_MAX_SIZE; /* hypervisor always requires 32 */
+ memset(buf, 0, len);
+ memcpy(buf, essid, essid_len);
+ pr_debug("%s: essid scan='%s'\n", __func__, (char *)buf);
+ } else
+ len = 0;
+
/*
* issue start scan request
*/
wl->scan_stat = GELIC_WL_SCAN_STAT_SCANNING;
cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_START_SCAN,
- NULL, 0);
+ buf, len);
if (!cmd || cmd->status || cmd->cmd_status) {
wl->scan_stat = GELIC_WL_SCAN_STAT_INIT;
complete(&wl->scan_done);
@@ -1588,7 +1609,8 @@
}
kfree(cmd);
out:
- up(&wl->scan_lock);
+ free_page((unsigned long)buf);
+ mutex_unlock(&wl->scan_lock);
pr_debug("%s: ->\n", __func__);
return ret;
}
@@ -1607,10 +1629,17 @@
union iwreq_data data;
unsigned long this_time = jiffies;
unsigned int data_len, i, found, r;
+ void *buf;
DECLARE_MAC_BUF(mac);
pr_debug("%s:start\n", __func__);
- down(&wl->scan_lock);
+ mutex_lock(&wl->scan_lock);
+
+ buf = (void *)__get_free_page(GFP_KERNEL);
+ if (!buf) {
+ pr_info("%s: scan buffer alloc failed\n", __func__);
+ goto out;
+ }
if (wl->scan_stat != GELIC_WL_SCAN_STAT_SCANNING) {
/*
@@ -1622,7 +1651,7 @@
}
cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_GET_SCAN,
- wl->buf, PAGE_SIZE);
+ buf, PAGE_SIZE);
if (!cmd || cmd->status || cmd->cmd_status) {
wl->scan_stat = GELIC_WL_SCAN_STAT_INIT;
pr_info("%s:cmd failed\n", __func__);
@@ -1649,7 +1678,7 @@
}
/* put them in the newtork_list */
- for (i = 0, scan_info_size = 0, scan_info = wl->buf;
+ for (i = 0, scan_info_size = 0, scan_info = buf;
scan_info_size < data_len;
i++, scan_info_size += be16_to_cpu(scan_info->size),
scan_info = (void *)scan_info + be16_to_cpu(scan_info->size)) {
@@ -1726,8 +1755,9 @@
wireless_send_event(port_to_netdev(wl_port(wl)), SIOCGIWSCAN, &data,
NULL);
out:
+ free_page((unsigned long)buf);
complete(&wl->scan_done);
- up(&wl->scan_lock);
+ mutex_unlock(&wl->scan_lock);
pr_debug("%s:end\n", __func__);
}
@@ -1848,7 +1878,10 @@
pr_debug("%s: <-\n", __func__);
/* we can assume no one should uses the buffer */
- wep = wl->buf;
+ wep = (struct gelic_eurus_wep_cfg *)__get_free_page(GFP_KERNEL);
+ if (!wep)
+ return -ENOMEM;
+
memset(wep, 0, sizeof(*wep));
if (wl->group_cipher_method == GELIC_WL_CIPHER_WEP) {
@@ -1898,6 +1931,7 @@
kfree(cmd);
out:
+ free_page((unsigned long)wep);
pr_debug("%s: ->\n", __func__);
return ret;
}
@@ -1941,7 +1975,10 @@
pr_debug("%s: <-\n", __func__);
/* we can assume no one should uses the buffer */
- wpa = wl->buf;
+ wpa = (struct gelic_eurus_wpa_cfg *)__get_free_page(GFP_KERNEL);
+ if (!wpa)
+ return -ENOMEM;
+
memset(wpa, 0, sizeof(*wpa));
if (!test_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat))
@@ -2000,6 +2037,7 @@
else if (cmd->status || cmd->cmd_status)
ret = -ENXIO;
kfree(cmd);
+ free_page((unsigned long)wpa);
pr_debug("%s: --> %d\n", __func__, ret);
return ret;
}
@@ -2018,7 +2056,10 @@
pr_debug("%s: <-\n", __func__);
/* do common config */
- common = wl->buf;
+ common = (struct gelic_eurus_common_cfg *)__get_free_page(GFP_KERNEL);
+ if (!common)
+ return -ENOMEM;
+
memset(common, 0, sizeof(*common));
common->bss_type = cpu_to_be16(GELIC_EURUS_BSS_INFRA);
common->op_mode = cpu_to_be16(GELIC_EURUS_OPMODE_11BG);
@@ -2104,6 +2145,7 @@
pr_info("%s: connected\n", __func__);
}
out:
+ free_page((unsigned long)common);
pr_debug("%s: ->\n", __func__);
return ret;
}
@@ -2151,7 +2193,7 @@
* As it waits with timeout, just leave assoc_done
* uncompleted, then it terminates with timeout
*/
- if (down_trylock(&wl->assoc_stat_lock)) {
+ if (!mutex_trylock(&wl->assoc_stat_lock)) {
pr_debug("%s: already locked\n", __func__);
lock = 0;
} else {
@@ -2170,7 +2212,7 @@
netif_carrier_off(port_to_netdev(wl_port(wl)));
if (lock)
- up(&wl->assoc_stat_lock);
+ mutex_unlock(&wl->assoc_stat_lock);
}
/*
* event worker
@@ -2255,15 +2297,30 @@
struct gelic_wl_scan_info *best_bss;
int ret;
+ unsigned long irqflag;
+ u8 *essid;
+ size_t essid_len;
wl = container_of(work, struct gelic_wl_info, assoc_work.work);
- down(&wl->assoc_stat_lock);
+ mutex_lock(&wl->assoc_stat_lock);
if (wl->assoc_stat != GELIC_WL_ASSOC_STAT_DISCONN)
goto out;
- ret = gelic_wl_start_scan(wl, 0);
+ spin_lock_irqsave(&wl->lock, irqflag);
+ if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat)) {
+ pr_debug("%s: assoc ESSID configured %s\n", __func__,
+ wl->essid);
+ essid = wl->essid;
+ essid_len = wl->essid_len;
+ } else {
+ essid = NULL;
+ essid_len = 0;
+ }
+ spin_unlock_irqrestore(&wl->lock, irqflag);
+
+ ret = gelic_wl_start_scan(wl, 0, essid, essid_len);
if (ret == -ERESTARTSYS) {
pr_debug("%s: scan start failed association\n", __func__);
schedule_delayed_work(&wl->assoc_work, HZ/10); /*FIXME*/
@@ -2282,7 +2339,7 @@
wait_for_completion(&wl->scan_done);
pr_debug("%s: scan done\n", __func__);
- down(&wl->scan_lock);
+ mutex_lock(&wl->scan_lock);
if (wl->scan_stat != GELIC_WL_SCAN_STAT_GOT_LIST) {
gelic_wl_send_iwap_event(wl, NULL);
pr_info("%s: no scan list. association failed\n", __func__);
@@ -2302,9 +2359,9 @@
if (ret)
pr_info("%s: association failed %d\n", __func__, ret);
scan_lock_out:
- up(&wl->scan_lock);
+ mutex_unlock(&wl->scan_lock);
out:
- up(&wl->assoc_stat_lock);
+ mutex_unlock(&wl->assoc_stat_lock);
}
/*
* Interrupt handler
@@ -2351,6 +2408,7 @@
IW_IOCTL(SIOCGIWNICKN) = gelic_wl_get_nick,
};
+#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE
static struct iw_priv_args gelic_wl_private_args[] =
{
{
@@ -2372,15 +2430,18 @@
gelic_wl_priv_set_psk,
gelic_wl_priv_get_psk,
};
+#endif
static const struct iw_handler_def gelic_wl_wext_handler_def = {
.num_standard = ARRAY_SIZE(gelic_wl_wext_handler),
.standard = gelic_wl_wext_handler,
.get_wireless_stats = gelic_wl_get_wireless_stats,
+#ifdef CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE
.num_private = ARRAY_SIZE(gelic_wl_private_handler),
.num_private_args = ARRAY_SIZE(gelic_wl_private_args),
.private = gelic_wl_private_handler,
.private_args = gelic_wl_private_args,
+#endif
};
static struct net_device *gelic_wl_alloc(struct gelic_card *card)
@@ -2431,8 +2492,8 @@
INIT_DELAYED_WORK(&wl->event_work, gelic_wl_event_worker);
INIT_DELAYED_WORK(&wl->assoc_work, gelic_wl_assoc_worker);
- init_MUTEX(&wl->scan_lock);
- init_MUTEX(&wl->assoc_stat_lock);
+ mutex_init(&wl->scan_lock);
+ mutex_init(&wl->assoc_stat_lock);
init_completion(&wl->scan_done);
/* for the case that no scan request is issued and stop() is called */
@@ -2446,16 +2507,9 @@
BUILD_BUG_ON(PAGE_SIZE <
sizeof(struct gelic_eurus_scan_info) *
GELIC_EURUS_MAX_SCAN);
- wl->buf = (void *)get_zeroed_page(GFP_KERNEL);
- if (!wl->buf) {
- pr_info("%s:buffer allocation failed\n", __func__);
- goto fail_getpage;
- }
pr_debug("%s:end\n", __func__);
return netdev;
-fail_getpage:
- destroy_workqueue(wl->event_queue);
fail_event_workqueue:
destroy_workqueue(wl->eurus_cmd_queue);
fail_cmd_workqueue:
@@ -2474,8 +2528,6 @@
pr_debug("%s: <-\n", __func__);
- free_page((unsigned long)wl->buf);
-
pr_debug("%s: destroy queues\n", __func__);
destroy_workqueue(wl->eurus_cmd_queue);
destroy_workqueue(wl->event_queue);
diff --git a/drivers/net/ps3_gelic_wireless.h b/drivers/net/ps3_gelic_wireless.h
index 1036971..5339e00 100644
--- a/drivers/net/ps3_gelic_wireless.h
+++ b/drivers/net/ps3_gelic_wireless.h
@@ -241,7 +241,7 @@
#define GELIC_WEP_KEYS 4
struct gelic_wl_info {
/* bss list */
- struct semaphore scan_lock;
+ struct mutex scan_lock;
struct list_head network_list;
struct list_head network_free_list;
struct gelic_wl_scan_info *networks;
@@ -266,7 +266,7 @@
enum gelic_wl_wpa_level wpa_level; /* wpa/wpa2 */
/* association handling */
- struct semaphore assoc_stat_lock;
+ struct mutex assoc_stat_lock;
struct delayed_work assoc_work;
enum gelic_wl_assoc_state assoc_stat;
struct completion assoc_done;
@@ -288,9 +288,6 @@
u8 active_bssid[ETH_ALEN]; /* associated bssid */
unsigned int essid_len;
- /* buffer for hypervisor IO */
- void *buf;
-
struct iw_public_data wireless_data;
struct iw_statistics iwstat;
};
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 b5c1e66..5694e89 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -2566,7 +2566,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",
@@ -2612,7 +2612,7 @@
first_rxdp->Control_1 |= RXD_OWN_XENA;
}
stats->mem_alloc_fail_cnt++;
-
+
return -ENOMEM ;
}
stats->mem_allocated += skb->truesize;
@@ -6999,7 +6999,7 @@
&skb,(u64 *)&temp0_64,
(u64 *)&temp1_64,
(u64 *)&temp2_64,
- size) == ENOMEM) {
+ size) == -ENOMEM) {
return 0;
}
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 4706f7f..d0a84ba 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -752,7 +752,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 33bb18f..fe41e4e 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -1064,7 +1064,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/sfc/Kconfig b/drivers/net/sfc/Kconfig
index dbad95c..3be13b5 100644
--- a/drivers/net/sfc/Kconfig
+++ b/drivers/net/sfc/Kconfig
@@ -4,6 +4,8 @@
select MII
select INET_LRO
select CRC32
+ select I2C
+ select I2C_ALGOBIT
help
This driver supports 10-gigabit Ethernet cards based on
the Solarflare Communications Solarstorm SFC4000 controller.
diff --git a/drivers/net/sfc/Makefile b/drivers/net/sfc/Makefile
index 1d2daee..c8f5704 100644
--- a/drivers/net/sfc/Makefile
+++ b/drivers/net/sfc/Makefile
@@ -1,5 +1,5 @@
sfc-y += efx.o falcon.o tx.o rx.o falcon_xmac.o \
- i2c-direct.o selftest.o ethtool.o xfp_phy.o \
+ selftest.o ethtool.o xfp_phy.o \
mdio_10g.o tenxpress.o boards.o sfe4001.o
obj-$(CONFIG_SFC) += sfc.o
diff --git a/drivers/net/sfc/boards.c b/drivers/net/sfc/boards.c
index 7fc0328..d3d3dd0 100644
--- a/drivers/net/sfc/boards.c
+++ b/drivers/net/sfc/boards.c
@@ -109,7 +109,7 @@
[EFX_BOARD_INVALID] =
{NULL, NULL, dummy_init},
[EFX_BOARD_SFE4001] =
- {"SFE4001", "10GBASE-T adapter", sfe4001_poweron},
+ {"SFE4001", "10GBASE-T adapter", sfe4001_init},
[EFX_BOARD_SFE4002] =
{"SFE4002", "XFP adapter", sfe4002_init},
};
diff --git a/drivers/net/sfc/boards.h b/drivers/net/sfc/boards.h
index 695764d..e5e8443 100644
--- a/drivers/net/sfc/boards.h
+++ b/drivers/net/sfc/boards.h
@@ -20,8 +20,7 @@
};
extern int efx_set_board_info(struct efx_nic *efx, u16 revision_info);
-extern int sfe4001_poweron(struct efx_nic *efx);
-extern void sfe4001_poweroff(struct efx_nic *efx);
+extern int sfe4001_init(struct efx_nic *efx);
/* Are we putting the PHY into flash config mode */
extern unsigned int sfe4001_phy_flash_cfg;
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 4497606..74265d8 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1815,6 +1815,7 @@
.init = efx_nic_dummy_op_int,
.init_leds = efx_port_dummy_op_int,
.set_fault_led = efx_port_dummy_op_blink,
+ .fini = efx_port_dummy_op_void,
};
/**************************************************************************
@@ -1941,6 +1942,7 @@
efx_fini_port(efx);
/* Shutdown the board, then the NIC and board state */
+ efx->board_info.fini(efx);
falcon_fini_interrupt(efx);
efx_fini_napi(efx);
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 790db89..630406e 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -13,6 +13,8 @@
#include <linux/pci.h>
#include <linux/module.h>
#include <linux/seq_file.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
#include "net_driver.h"
#include "bitfield.h"
#include "efx.h"
@@ -36,10 +38,12 @@
* struct falcon_nic_data - Falcon NIC state
* @next_buffer_table: First available buffer table id
* @pci_dev2: The secondary PCI device if present
+ * @i2c_data: Operations and state for I2C bit-bashing algorithm
*/
struct falcon_nic_data {
unsigned next_buffer_table;
struct pci_dev *pci_dev2;
+ struct i2c_algo_bit_data i2c_data;
};
/**************************************************************************
@@ -175,39 +179,57 @@
*
**************************************************************************
*/
-static void falcon_setsdascl(struct efx_i2c_interface *i2c)
+static void falcon_setsda(void *data, int state)
{
+ struct efx_nic *efx = (struct efx_nic *)data;
efx_oword_t reg;
- falcon_read(i2c->efx, ®, GPIO_CTL_REG_KER);
- EFX_SET_OWORD_FIELD(reg, GPIO0_OEN, (i2c->scl ? 0 : 1));
- EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, (i2c->sda ? 0 : 1));
- falcon_write(i2c->efx, ®, GPIO_CTL_REG_KER);
+ falcon_read(efx, ®, GPIO_CTL_REG_KER);
+ EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, !state);
+ falcon_write(efx, ®, GPIO_CTL_REG_KER);
}
-static int falcon_getsda(struct efx_i2c_interface *i2c)
+static void falcon_setscl(void *data, int state)
{
+ struct efx_nic *efx = (struct efx_nic *)data;
efx_oword_t reg;
- falcon_read(i2c->efx, ®, GPIO_CTL_REG_KER);
+ falcon_read(efx, ®, GPIO_CTL_REG_KER);
+ EFX_SET_OWORD_FIELD(reg, GPIO0_OEN, !state);
+ falcon_write(efx, ®, GPIO_CTL_REG_KER);
+}
+
+static int falcon_getsda(void *data)
+{
+ struct efx_nic *efx = (struct efx_nic *)data;
+ efx_oword_t reg;
+
+ falcon_read(efx, ®, GPIO_CTL_REG_KER);
return EFX_OWORD_FIELD(reg, GPIO3_IN);
}
-static int falcon_getscl(struct efx_i2c_interface *i2c)
+static int falcon_getscl(void *data)
{
+ struct efx_nic *efx = (struct efx_nic *)data;
efx_oword_t reg;
- falcon_read(i2c->efx, ®, GPIO_CTL_REG_KER);
- return EFX_DWORD_FIELD(reg, GPIO0_IN);
+ falcon_read(efx, ®, GPIO_CTL_REG_KER);
+ return EFX_OWORD_FIELD(reg, GPIO0_IN);
}
-static struct efx_i2c_bit_operations falcon_i2c_bit_operations = {
- .setsda = falcon_setsdascl,
- .setscl = falcon_setsdascl,
+static struct i2c_algo_bit_data falcon_i2c_bit_operations = {
+ .setsda = falcon_setsda,
+ .setscl = falcon_setscl,
.getsda = falcon_getsda,
.getscl = falcon_getscl,
- .udelay = 100,
- .mdelay = 10,
+ .udelay = 5,
+ /*
+ * This is the number of system clock ticks after which
+ * i2c-algo-bit gives up waiting for SCL to become high.
+ * It must be at least 2 since the first tick can happen
+ * immediately after it starts waiting.
+ */
+ .timeout = 2,
};
/**************************************************************************
@@ -2405,12 +2427,6 @@
struct falcon_nic_data *nic_data;
int rc;
- /* Initialise I2C interface state */
- efx->i2c.efx = efx;
- efx->i2c.op = &falcon_i2c_bit_operations;
- efx->i2c.sda = 1;
- efx->i2c.scl = 1;
-
/* Allocate storage for hardware specific data */
nic_data = kzalloc(sizeof(*nic_data), GFP_KERNEL);
efx->nic_data = nic_data;
@@ -2461,6 +2477,18 @@
if (rc)
goto fail5;
+ /* Initialise I2C adapter */
+ efx->i2c_adap.owner = THIS_MODULE;
+ efx->i2c_adap.class = I2C_CLASS_HWMON;
+ nic_data->i2c_data = falcon_i2c_bit_operations;
+ nic_data->i2c_data.data = efx;
+ efx->i2c_adap.algo_data = &nic_data->i2c_data;
+ efx->i2c_adap.dev.parent = &efx->pci_dev->dev;
+ strcpy(efx->i2c_adap.name, "SFC4000 GPIO");
+ rc = i2c_bit_add_bus(&efx->i2c_adap);
+ if (rc)
+ goto fail5;
+
return 0;
fail5:
@@ -2635,6 +2663,10 @@
void falcon_remove_nic(struct efx_nic *efx)
{
struct falcon_nic_data *nic_data = efx->nic_data;
+ int rc;
+
+ rc = i2c_del_adapter(&efx->i2c_adap);
+ BUG_ON(rc);
falcon_free_buffer(efx, &efx->irq_status);
diff --git a/drivers/net/sfc/i2c-direct.c b/drivers/net/sfc/i2c-direct.c
deleted file mode 100644
index b6c62d0e..0000000
--- a/drivers/net/sfc/i2c-direct.c
+++ /dev/null
@@ -1,381 +0,0 @@
-/****************************************************************************
- * Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2005 Fen Systems Ltd.
- * Copyright 2006-2008 Solarflare Communications Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation, incorporated herein by reference.
- */
-
-#include <linux/delay.h>
-#include "net_driver.h"
-#include "i2c-direct.h"
-
-/*
- * I2C data (SDA) and clock (SCL) line read/writes with appropriate
- * delays.
- */
-
-static inline void setsda(struct efx_i2c_interface *i2c, int state)
-{
- udelay(i2c->op->udelay);
- i2c->sda = state;
- i2c->op->setsda(i2c);
- udelay(i2c->op->udelay);
-}
-
-static inline void setscl(struct efx_i2c_interface *i2c, int state)
-{
- udelay(i2c->op->udelay);
- i2c->scl = state;
- i2c->op->setscl(i2c);
- udelay(i2c->op->udelay);
-}
-
-static inline int getsda(struct efx_i2c_interface *i2c)
-{
- int sda;
-
- udelay(i2c->op->udelay);
- sda = i2c->op->getsda(i2c);
- udelay(i2c->op->udelay);
- return sda;
-}
-
-static inline int getscl(struct efx_i2c_interface *i2c)
-{
- int scl;
-
- udelay(i2c->op->udelay);
- scl = i2c->op->getscl(i2c);
- udelay(i2c->op->udelay);
- return scl;
-}
-
-/*
- * I2C low-level protocol operations
- *
- */
-
-static inline void i2c_release(struct efx_i2c_interface *i2c)
-{
- EFX_WARN_ON_PARANOID(!i2c->scl);
- EFX_WARN_ON_PARANOID(!i2c->sda);
- /* Devices may time out if operations do not end */
- setscl(i2c, 1);
- setsda(i2c, 1);
- EFX_BUG_ON_PARANOID(getsda(i2c) != 1);
- EFX_BUG_ON_PARANOID(getscl(i2c) != 1);
-}
-
-static inline void i2c_start(struct efx_i2c_interface *i2c)
-{
- /* We may be restarting immediately after a {send,recv}_bit,
- * so SCL will not necessarily already be high.
- */
- EFX_WARN_ON_PARANOID(!i2c->sda);
- setscl(i2c, 1);
- setsda(i2c, 0);
- setscl(i2c, 0);
- setsda(i2c, 1);
-}
-
-static inline void i2c_send_bit(struct efx_i2c_interface *i2c, int bit)
-{
- EFX_WARN_ON_PARANOID(i2c->scl != 0);
- setsda(i2c, bit);
- setscl(i2c, 1);
- setscl(i2c, 0);
- setsda(i2c, 1);
-}
-
-static inline int i2c_recv_bit(struct efx_i2c_interface *i2c)
-{
- int bit;
-
- EFX_WARN_ON_PARANOID(i2c->scl != 0);
- EFX_WARN_ON_PARANOID(!i2c->sda);
- setscl(i2c, 1);
- bit = getsda(i2c);
- setscl(i2c, 0);
- return bit;
-}
-
-static inline void i2c_stop(struct efx_i2c_interface *i2c)
-{
- EFX_WARN_ON_PARANOID(i2c->scl != 0);
- setsda(i2c, 0);
- setscl(i2c, 1);
- setsda(i2c, 1);
-}
-
-/*
- * I2C mid-level protocol operations
- *
- */
-
-/* Sends a byte via the I2C bus and checks for an acknowledgement from
- * the slave device.
- */
-static int i2c_send_byte(struct efx_i2c_interface *i2c, u8 byte)
-{
- int i;
-
- /* Send byte */
- for (i = 0; i < 8; i++) {
- i2c_send_bit(i2c, !!(byte & 0x80));
- byte <<= 1;
- }
-
- /* Check for acknowledgement from slave */
- return (i2c_recv_bit(i2c) == 0 ? 0 : -EIO);
-}
-
-/* Receives a byte via the I2C bus and sends ACK/NACK to the slave device. */
-static u8 i2c_recv_byte(struct efx_i2c_interface *i2c, int ack)
-{
- u8 value = 0;
- int i;
-
- /* Receive byte */
- for (i = 0; i < 8; i++)
- value = (value << 1) | i2c_recv_bit(i2c);
-
- /* Send ACK/NACK */
- i2c_send_bit(i2c, (ack ? 0 : 1));
-
- return value;
-}
-
-/* Calculate command byte for a read operation */
-static inline u8 i2c_read_cmd(u8 device_id)
-{
- return ((device_id << 1) | 1);
-}
-
-/* Calculate command byte for a write operation */
-static inline u8 i2c_write_cmd(u8 device_id)
-{
- return ((device_id << 1) | 0);
-}
-
-int efx_i2c_check_presence(struct efx_i2c_interface *i2c, u8 device_id)
-{
- int rc;
-
- /* If someone is driving the bus low we just give up. */
- if (getsda(i2c) == 0 || getscl(i2c) == 0) {
- EFX_ERR(i2c->efx, "%s someone is holding the I2C bus low."
- " Giving up.\n", __func__);
- return -EFAULT;
- }
-
- /* Pretend to initiate a device write */
- i2c_start(i2c);
- rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
- if (rc)
- goto out;
-
- out:
- i2c_stop(i2c);
- i2c_release(i2c);
-
- return rc;
-}
-
-/* This performs a fast read of one or more consecutive bytes from an
- * I2C device. Not all devices support consecutive reads of more than
- * one byte; for these devices use efx_i2c_read() instead.
- */
-int efx_i2c_fast_read(struct efx_i2c_interface *i2c,
- u8 device_id, u8 offset, u8 *data, unsigned int len)
-{
- int i;
- int rc;
-
- EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
- EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
- EFX_WARN_ON_PARANOID(data == NULL);
- EFX_WARN_ON_PARANOID(len < 1);
-
- /* Select device and starting offset */
- i2c_start(i2c);
- rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
- if (rc)
- goto out;
- rc = i2c_send_byte(i2c, offset);
- if (rc)
- goto out;
-
- /* Read data from device */
- i2c_start(i2c);
- rc = i2c_send_byte(i2c, i2c_read_cmd(device_id));
- if (rc)
- goto out;
- for (i = 0; i < (len - 1); i++)
- /* Read and acknowledge all but the last byte */
- data[i] = i2c_recv_byte(i2c, 1);
- /* Read last byte with no acknowledgement */
- data[i] = i2c_recv_byte(i2c, 0);
-
- out:
- i2c_stop(i2c);
- i2c_release(i2c);
-
- return rc;
-}
-
-/* This performs a fast write of one or more consecutive bytes to an
- * I2C device. Not all devices support consecutive writes of more
- * than one byte; for these devices use efx_i2c_write() instead.
- */
-int efx_i2c_fast_write(struct efx_i2c_interface *i2c,
- u8 device_id, u8 offset,
- const u8 *data, unsigned int len)
-{
- int i;
- int rc;
-
- EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
- EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
- EFX_WARN_ON_PARANOID(len < 1);
-
- /* Select device and starting offset */
- i2c_start(i2c);
- rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
- if (rc)
- goto out;
- rc = i2c_send_byte(i2c, offset);
- if (rc)
- goto out;
-
- /* Write data to device */
- for (i = 0; i < len; i++) {
- rc = i2c_send_byte(i2c, data[i]);
- if (rc)
- goto out;
- }
-
- out:
- i2c_stop(i2c);
- i2c_release(i2c);
-
- return rc;
-}
-
-/* I2C byte-by-byte read */
-int efx_i2c_read(struct efx_i2c_interface *i2c,
- u8 device_id, u8 offset, u8 *data, unsigned int len)
-{
- int rc;
-
- /* i2c_fast_read with length 1 is a single byte read */
- for (; len > 0; offset++, data++, len--) {
- rc = efx_i2c_fast_read(i2c, device_id, offset, data, 1);
- if (rc)
- return rc;
- }
-
- return 0;
-}
-
-/* I2C byte-by-byte write */
-int efx_i2c_write(struct efx_i2c_interface *i2c,
- u8 device_id, u8 offset, const u8 *data, unsigned int len)
-{
- int rc;
-
- /* i2c_fast_write with length 1 is a single byte write */
- for (; len > 0; offset++, data++, len--) {
- rc = efx_i2c_fast_write(i2c, device_id, offset, data, 1);
- if (rc)
- return rc;
- mdelay(i2c->op->mdelay);
- }
-
- return 0;
-}
-
-
-/* This is just a slightly neater wrapper round efx_i2c_fast_write
- * in the case where the target doesn't take an offset
- */
-int efx_i2c_send_bytes(struct efx_i2c_interface *i2c,
- u8 device_id, const u8 *data, unsigned int len)
-{
- return efx_i2c_fast_write(i2c, device_id, data[0], data + 1, len - 1);
-}
-
-/* I2C receiving of bytes - does not send an offset byte */
-int efx_i2c_recv_bytes(struct efx_i2c_interface *i2c, u8 device_id,
- u8 *bytes, unsigned int len)
-{
- int i;
- int rc;
-
- EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
- EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
- EFX_WARN_ON_PARANOID(len < 1);
-
- /* Select device */
- i2c_start(i2c);
-
- /* Read data from device */
- rc = i2c_send_byte(i2c, i2c_read_cmd(device_id));
- if (rc)
- goto out;
-
- for (i = 0; i < (len - 1); i++)
- /* Read and acknowledge all but the last byte */
- bytes[i] = i2c_recv_byte(i2c, 1);
- /* Read last byte with no acknowledgement */
- bytes[i] = i2c_recv_byte(i2c, 0);
-
- out:
- i2c_stop(i2c);
- i2c_release(i2c);
-
- return rc;
-}
-
-/* SMBus and some I2C devices will time out if the I2C clock is
- * held low for too long. This is most likely to happen in virtualised
- * systems (when the entire domain is descheduled) but could in
- * principle happen due to preemption on any busy system (and given the
- * potential length of an I2C operation turning preemption off is not
- * a sensible option). The following functions deal with the failure by
- * retrying up to a fixed number of times.
- */
-
-#define I2C_MAX_RETRIES (10)
-
-/* The timeout problem will result in -EIO. If the wrapped function
- * returns any other error, pass this up and do not retry. */
-#define RETRY_WRAPPER(_f) \
- int retries = I2C_MAX_RETRIES; \
- int rc; \
- while (retries) { \
- rc = _f; \
- if (rc != -EIO) \
- return rc; \
- retries--; \
- } \
- return rc; \
-
-int efx_i2c_check_presence_retry(struct efx_i2c_interface *i2c, u8 device_id)
-{
- RETRY_WRAPPER(efx_i2c_check_presence(i2c, device_id))
-}
-
-int efx_i2c_read_retry(struct efx_i2c_interface *i2c,
- u8 device_id, u8 offset, u8 *data, unsigned int len)
-{
- RETRY_WRAPPER(efx_i2c_read(i2c, device_id, offset, data, len))
-}
-
-int efx_i2c_write_retry(struct efx_i2c_interface *i2c,
- u8 device_id, u8 offset, const u8 *data, unsigned int len)
-{
- RETRY_WRAPPER(efx_i2c_write(i2c, device_id, offset, data, len))
-}
diff --git a/drivers/net/sfc/i2c-direct.h b/drivers/net/sfc/i2c-direct.h
deleted file mode 100644
index 291e561..0000000
--- a/drivers/net/sfc/i2c-direct.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/****************************************************************************
- * Driver for Solarflare Solarstorm network controllers and boards
- * Copyright 2005 Fen Systems Ltd.
- * Copyright 2006 Solarflare Communications Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation, incorporated herein by reference.
- */
-
-#ifndef EFX_I2C_DIRECT_H
-#define EFX_I2C_DIRECT_H
-
-#include "net_driver.h"
-
-/*
- * Direct control of an I2C bus
- */
-
-struct efx_i2c_interface;
-
-/**
- * struct efx_i2c_bit_operations - I2C bus direct control methods
- *
- * I2C bus direct control methods.
- *
- * @setsda: Set state of SDA line
- * @setscl: Set state of SCL line
- * @getsda: Get state of SDA line
- * @getscl: Get state of SCL line
- * @udelay: Delay between each bit operation
- * @mdelay: Delay between each byte write
- */
-struct efx_i2c_bit_operations {
- void (*setsda) (struct efx_i2c_interface *i2c);
- void (*setscl) (struct efx_i2c_interface *i2c);
- int (*getsda) (struct efx_i2c_interface *i2c);
- int (*getscl) (struct efx_i2c_interface *i2c);
- unsigned int udelay;
- unsigned int mdelay;
-};
-
-/**
- * struct efx_i2c_interface - an I2C interface
- *
- * An I2C interface.
- *
- * @efx: Attached Efx NIC
- * @op: I2C bus control methods
- * @sda: Current output state of SDA line
- * @scl: Current output state of SCL line
- */
-struct efx_i2c_interface {
- struct efx_nic *efx;
- struct efx_i2c_bit_operations *op;
- unsigned int sda:1;
- unsigned int scl:1;
-};
-
-extern int efx_i2c_check_presence(struct efx_i2c_interface *i2c, u8 device_id);
-extern int efx_i2c_fast_read(struct efx_i2c_interface *i2c,
- u8 device_id, u8 offset,
- u8 *data, unsigned int len);
-extern int efx_i2c_fast_write(struct efx_i2c_interface *i2c,
- u8 device_id, u8 offset,
- const u8 *data, unsigned int len);
-extern int efx_i2c_read(struct efx_i2c_interface *i2c,
- u8 device_id, u8 offset, u8 *data, unsigned int len);
-extern int efx_i2c_write(struct efx_i2c_interface *i2c,
- u8 device_id, u8 offset,
- const u8 *data, unsigned int len);
-
-extern int efx_i2c_send_bytes(struct efx_i2c_interface *i2c, u8 device_id,
- const u8 *bytes, unsigned int len);
-
-extern int efx_i2c_recv_bytes(struct efx_i2c_interface *i2c, u8 device_id,
- u8 *bytes, unsigned int len);
-
-
-/* Versions of the API that retry on failure. */
-extern int efx_i2c_check_presence_retry(struct efx_i2c_interface *i2c,
- u8 device_id);
-
-extern int efx_i2c_read_retry(struct efx_i2c_interface *i2c,
- u8 device_id, u8 offset, u8 *data, unsigned int len);
-
-extern int efx_i2c_write_retry(struct efx_i2c_interface *i2c,
- u8 device_id, u8 offset,
- const u8 *data, unsigned int len);
-
-#endif /* EFX_I2C_DIRECT_H */
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 5e20e75..d803b86 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -26,10 +26,10 @@
#include <linux/highmem.h>
#include <linux/workqueue.h>
#include <linux/inet_lro.h>
+#include <linux/i2c.h>
#include "enum.h"
#include "bitfield.h"
-#include "i2c-direct.h"
#define EFX_MAX_LRO_DESCRIPTORS 8
#define EFX_MAX_LRO_AGGR MAX_SKB_FRAGS
@@ -418,7 +418,10 @@
* @init_leds: Sets up board LEDs
* @set_fault_led: Turns the fault LED on or off
* @blink: Starts/stops blinking
+ * @fini: Cleanup function
* @blinker: used to blink LEDs in software
+ * @hwmon_client: I2C client for hardware monitor
+ * @ioexp_client: I2C client for power/port control
*/
struct efx_board {
int type;
@@ -431,7 +434,9 @@
int (*init_leds)(struct efx_nic *efx);
void (*set_fault_led) (struct efx_nic *efx, int state);
void (*blink) (struct efx_nic *efx, int start);
+ void (*fini) (struct efx_nic *nic);
struct efx_blinker blinker;
+ struct i2c_client *hwmon_client, *ioexp_client;
};
#define STRING_TABLE_LOOKUP(val, member) \
@@ -618,7 +623,7 @@
* @membase: Memory BAR value
* @biu_lock: BIU (bus interface unit) lock
* @interrupt_mode: Interrupt mode
- * @i2c: I2C interface
+ * @i2c_adap: I2C adapter
* @board_info: Board-level information
* @state: Device state flag. Serialised by the rtnl_lock.
* @reset_pending: Pending reset method (normally RESET_TYPE_NONE)
@@ -686,7 +691,7 @@
spinlock_t biu_lock;
enum efx_int_mode interrupt_mode;
- struct efx_i2c_interface i2c;
+ struct i2c_adapter i2c_adap;
struct efx_board board_info;
enum nic_state state;
diff --git a/drivers/net/sfc/sfe4001.c b/drivers/net/sfc/sfe4001.c
index 66a0d14..b278495 100644
--- a/drivers/net/sfc/sfe4001.c
+++ b/drivers/net/sfc/sfe4001.c
@@ -106,28 +106,27 @@
static const u8 xgphy_max_temperature = 90;
-void sfe4001_poweroff(struct efx_nic *efx)
+static void sfe4001_poweroff(struct efx_nic *efx)
{
- struct efx_i2c_interface *i2c = &efx->i2c;
+ struct i2c_client *ioexp_client = efx->board_info.ioexp_client;
+ struct i2c_client *hwmon_client = efx->board_info.hwmon_client;
- u8 cfg, out, in;
-
- EFX_INFO(efx, "%s\n", __func__);
-
- /* Turn off all power rails */
- out = 0xff;
- efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
-
- /* Disable port 1 outputs on IO expander */
- cfg = 0xff;
- efx_i2c_write(i2c, PCA9539, P1_CONFIG, &cfg, 1);
-
- /* Disable port 0 outputs on IO expander */
- cfg = 0xff;
- efx_i2c_write(i2c, PCA9539, P0_CONFIG, &cfg, 1);
+ /* Turn off all power rails and disable outputs */
+ i2c_smbus_write_byte_data(ioexp_client, P0_OUT, 0xff);
+ i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG, 0xff);
+ i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0xff);
/* Clear any over-temperature alert */
- efx_i2c_read(i2c, MAX6647, RSL, &in, 1);
+ i2c_smbus_read_byte_data(hwmon_client, RSL);
+}
+
+static void sfe4001_fini(struct efx_nic *efx)
+{
+ EFX_INFO(efx, "%s\n", __func__);
+
+ sfe4001_poweroff(efx);
+ i2c_unregister_device(efx->board_info.ioexp_client);
+ i2c_unregister_device(efx->board_info.hwmon_client);
}
/* The P0_EN_3V3X line on SFE4001 boards (from A2 onward) is connected
@@ -143,14 +142,26 @@
* be turned on before the PHY can be used.
* Context: Process context, rtnl lock held
*/
-int sfe4001_poweron(struct efx_nic *efx)
+int sfe4001_init(struct efx_nic *efx)
{
- struct efx_i2c_interface *i2c = &efx->i2c;
+ struct i2c_client *hwmon_client, *ioexp_client;
unsigned int count;
int rc;
- u8 out, in, cfg;
+ u8 out;
efx_dword_t reg;
+ hwmon_client = i2c_new_dummy(&efx->i2c_adap, MAX6647);
+ if (!hwmon_client)
+ return -EIO;
+ efx->board_info.hwmon_client = hwmon_client;
+
+ ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539);
+ if (!ioexp_client) {
+ rc = -EIO;
+ goto fail_hwmon;
+ }
+ efx->board_info.ioexp_client = ioexp_client;
+
/* 10Xpress has fixed-function LED pins, so there is no board-specific
* blink code. */
efx->board_info.blink = tenxpress_phy_blink;
@@ -166,44 +177,45 @@
falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC);
udelay(10);
+ efx->board_info.fini = sfe4001_fini;
+
/* Set DSP over-temperature alert threshold */
EFX_INFO(efx, "DSP cut-out at %dC\n", xgphy_max_temperature);
- rc = efx_i2c_write(i2c, MAX6647, WLHO,
- &xgphy_max_temperature, 1);
+ rc = i2c_smbus_write_byte_data(hwmon_client, WLHO,
+ xgphy_max_temperature);
if (rc)
- goto fail1;
+ goto fail_ioexp;
/* Read it back and verify */
- rc = efx_i2c_read(i2c, MAX6647, RLHN, &in, 1);
- if (rc)
- goto fail1;
- if (in != xgphy_max_temperature) {
+ rc = i2c_smbus_read_byte_data(hwmon_client, RLHN);
+ if (rc < 0)
+ goto fail_ioexp;
+ if (rc != xgphy_max_temperature) {
rc = -EFAULT;
- goto fail1;
+ goto fail_ioexp;
}
/* Clear any previous over-temperature alert */
- rc = efx_i2c_read(i2c, MAX6647, RSL, &in, 1);
- if (rc)
- goto fail1;
+ rc = i2c_smbus_read_byte_data(hwmon_client, RSL);
+ if (rc < 0)
+ goto fail_ioexp;
/* Enable port 0 and port 1 outputs on IO expander */
- cfg = 0x00;
- rc = efx_i2c_write(i2c, PCA9539, P0_CONFIG, &cfg, 1);
+ rc = i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0x00);
if (rc)
- goto fail1;
- cfg = 0xff & ~(1 << P1_SPARE_LBN);
- rc = efx_i2c_write(i2c, PCA9539, P1_CONFIG, &cfg, 1);
+ goto fail_ioexp;
+ rc = i2c_smbus_write_byte_data(ioexp_client, P1_CONFIG,
+ 0xff & ~(1 << P1_SPARE_LBN));
if (rc)
- goto fail2;
+ goto fail_on;
/* Turn all power off then wait 1 sec. This ensures PHY is reset */
out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) |
(0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) |
(0 << P0_EN_1V0X_LBN));
- rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
+ rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
if (rc)
- goto fail3;
+ goto fail_on;
schedule_timeout_uninterruptible(HZ);
count = 0;
@@ -215,26 +227,26 @@
if (sfe4001_phy_flash_cfg)
out |= 1 << P0_EN_3V3X_LBN;
- rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
+ rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
if (rc)
- goto fail3;
+ goto fail_on;
msleep(10);
/* Turn on 1V power rail */
out &= ~(1 << P0_EN_1V0X_LBN);
- rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
+ rc = i2c_smbus_write_byte_data(ioexp_client, P0_OUT, out);
if (rc)
- goto fail3;
+ goto fail_on;
EFX_INFO(efx, "waiting for power (attempt %d)...\n", count);
schedule_timeout_uninterruptible(HZ);
/* Check DSP is powered */
- rc = efx_i2c_read(i2c, PCA9539, P1_IN, &in, 1);
- if (rc)
- goto fail3;
- if (in & (1 << P1_AFE_PWD_LBN))
+ rc = i2c_smbus_read_byte_data(ioexp_client, P1_IN);
+ if (rc < 0)
+ goto fail_on;
+ if (rc & (1 << P1_AFE_PWD_LBN))
goto done;
/* DSP doesn't look powered in flash config mode */
@@ -244,23 +256,17 @@
EFX_INFO(efx, "timed out waiting for power\n");
rc = -ETIMEDOUT;
- goto fail3;
+ goto fail_on;
done:
EFX_INFO(efx, "PHY is powered on\n");
return 0;
-fail3:
- /* Turn off all power rails */
- out = 0xff;
- efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
- /* Disable port 1 outputs on IO expander */
- out = 0xff;
- efx_i2c_write(i2c, PCA9539, P1_CONFIG, &out, 1);
-fail2:
- /* Disable port 0 outputs on IO expander */
- out = 0xff;
- efx_i2c_write(i2c, PCA9539, P0_CONFIG, &out, 1);
-fail1:
+fail_on:
+ sfe4001_poweroff(efx);
+fail_ioexp:
+ i2c_unregister_device(ioexp_client);
+fail_hwmon:
+ i2c_unregister_device(hwmon_client);
return rc;
}
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
new file mode 100644
index 0000000..f64d987
--- /dev/null
+++ b/drivers/net/sh_eth.c
@@ -0,0 +1,1174 @@
+/*
+ * SuperH Ethernet device driver
+ *
+ * Copyright (C) 2006,2007 Nobuhiro Iwamatsu
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ */
+
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/mdio-bitbang.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <linux/cache.h>
+#include <linux/io.h>
+
+#include "sh_eth.h"
+
+/*
+ * Program the hardware MAC address from dev->dev_addr.
+ */
+static void update_mac_address(struct net_device *ndev)
+{
+ u32 ioaddr = ndev->base_addr;
+
+ ctrl_outl((ndev->dev_addr[0] << 24) | (ndev->dev_addr[1] << 16) |
+ (ndev->dev_addr[2] << 8) | (ndev->dev_addr[3]),
+ ioaddr + MAHR);
+ ctrl_outl((ndev->dev_addr[4] << 8) | (ndev->dev_addr[5]),
+ ioaddr + MALR);
+}
+
+/*
+ * Get MAC address from SuperH MAC address register
+ *
+ * SuperH's Ethernet device doesn't have 'ROM' to MAC address.
+ * This driver get MAC address that use by bootloader(U-boot or sh-ipl+g).
+ * When you want use this device, you must set MAC address in bootloader.
+ *
+ */
+static void read_mac_address(struct net_device *ndev)
+{
+ u32 ioaddr = ndev->base_addr;
+
+ ndev->dev_addr[0] = (ctrl_inl(ioaddr + MAHR) >> 24);
+ ndev->dev_addr[1] = (ctrl_inl(ioaddr + MAHR) >> 16) & 0xFF;
+ ndev->dev_addr[2] = (ctrl_inl(ioaddr + MAHR) >> 8) & 0xFF;
+ ndev->dev_addr[3] = (ctrl_inl(ioaddr + MAHR) & 0xFF);
+ ndev->dev_addr[4] = (ctrl_inl(ioaddr + MALR) >> 8) & 0xFF;
+ ndev->dev_addr[5] = (ctrl_inl(ioaddr + MALR) & 0xFF);
+}
+
+struct bb_info {
+ struct mdiobb_ctrl ctrl;
+ u32 addr;
+ u32 mmd_msk;/* MMD */
+ u32 mdo_msk;
+ u32 mdi_msk;
+ u32 mdc_msk;
+};
+
+/* PHY bit set */
+static void bb_set(u32 addr, u32 msk)
+{
+ ctrl_outl(ctrl_inl(addr) | msk, addr);
+}
+
+/* PHY bit clear */
+static void bb_clr(u32 addr, u32 msk)
+{
+ ctrl_outl((ctrl_inl(addr) & ~msk), addr);
+}
+
+/* PHY bit read */
+static int bb_read(u32 addr, u32 msk)
+{
+ return (ctrl_inl(addr) & msk) != 0;
+}
+
+/* Data I/O pin control */
+static void sh_mmd_ctrl(struct mdiobb_ctrl *ctrl, int bit)
+{
+ struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
+ if (bit)
+ bb_set(bitbang->addr, bitbang->mmd_msk);
+ else
+ bb_clr(bitbang->addr, bitbang->mmd_msk);
+}
+
+/* Set bit data*/
+static void sh_set_mdio(struct mdiobb_ctrl *ctrl, int bit)
+{
+ struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
+
+ if (bit)
+ bb_set(bitbang->addr, bitbang->mdo_msk);
+ else
+ bb_clr(bitbang->addr, bitbang->mdo_msk);
+}
+
+/* Get bit data*/
+static int sh_get_mdio(struct mdiobb_ctrl *ctrl)
+{
+ struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
+ return bb_read(bitbang->addr, bitbang->mdi_msk);
+}
+
+/* MDC pin control */
+static void sh_mdc_ctrl(struct mdiobb_ctrl *ctrl, int bit)
+{
+ struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
+
+ if (bit)
+ bb_set(bitbang->addr, bitbang->mdc_msk);
+ else
+ bb_clr(bitbang->addr, bitbang->mdc_msk);
+}
+
+/* mdio bus control struct */
+static struct mdiobb_ops bb_ops = {
+ .owner = THIS_MODULE,
+ .set_mdc = sh_mdc_ctrl,
+ .set_mdio_dir = sh_mmd_ctrl,
+ .set_mdio_data = sh_set_mdio,
+ .get_mdio_data = sh_get_mdio,
+};
+
+static void sh_eth_reset(struct net_device *ndev)
+{
+ u32 ioaddr = ndev->base_addr;
+
+ ctrl_outl(ctrl_inl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR);
+ mdelay(3);
+ ctrl_outl(ctrl_inl(ioaddr + EDMR) & ~EDMR_SRST, ioaddr + EDMR);
+}
+
+/* free skb and descriptor buffer */
+static void sh_eth_ring_free(struct net_device *ndev)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+ int i;
+
+ /* Free Rx skb ringbuffer */
+ if (mdp->rx_skbuff) {
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ if (mdp->rx_skbuff[i])
+ dev_kfree_skb(mdp->rx_skbuff[i]);
+ }
+ }
+ kfree(mdp->rx_skbuff);
+
+ /* Free Tx skb ringbuffer */
+ if (mdp->tx_skbuff) {
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ if (mdp->tx_skbuff[i])
+ dev_kfree_skb(mdp->tx_skbuff[i]);
+ }
+ }
+ kfree(mdp->tx_skbuff);
+}
+
+/* format skb and descriptor buffer */
+static void sh_eth_ring_format(struct net_device *ndev)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+ int i;
+ struct sk_buff *skb;
+ struct sh_eth_rxdesc *rxdesc = NULL;
+ struct sh_eth_txdesc *txdesc = NULL;
+ int rx_ringsize = sizeof(*rxdesc) * RX_RING_SIZE;
+ int tx_ringsize = sizeof(*txdesc) * TX_RING_SIZE;
+
+ mdp->cur_rx = mdp->cur_tx = 0;
+ mdp->dirty_rx = mdp->dirty_tx = 0;
+
+ memset(mdp->rx_ring, 0, rx_ringsize);
+
+ /* build Rx ring buffer */
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ /* skb */
+ mdp->rx_skbuff[i] = NULL;
+ skb = dev_alloc_skb(mdp->rx_buf_sz);
+ mdp->rx_skbuff[i] = skb;
+ if (skb == NULL)
+ break;
+ skb->dev = ndev; /* Mark as being used by this device. */
+ skb_reserve(skb, RX_OFFSET);
+
+ /* RX descriptor */
+ rxdesc = &mdp->rx_ring[i];
+ rxdesc->addr = (u32)skb->data & ~0x3UL;
+ rxdesc->status = cpu_to_le32(RD_RACT | RD_RFP);
+
+ /* The size of the buffer is 16 byte boundary. */
+ rxdesc->buffer_length = (mdp->rx_buf_sz + 16) & ~0x0F;
+ }
+
+ mdp->dirty_rx = (u32) (i - RX_RING_SIZE);
+
+ /* Mark the last entry as wrapping the ring. */
+ rxdesc->status |= cpu_to_le32(RC_RDEL);
+
+ memset(mdp->tx_ring, 0, tx_ringsize);
+
+ /* build Tx ring buffer */
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ mdp->tx_skbuff[i] = NULL;
+ txdesc = &mdp->tx_ring[i];
+ txdesc->status = cpu_to_le32(TD_TFP);
+ txdesc->buffer_length = 0;
+ }
+
+ txdesc->status |= cpu_to_le32(TD_TDLE);
+}
+
+/* Get skb and descriptor buffer */
+static int sh_eth_ring_init(struct net_device *ndev)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+ int rx_ringsize, tx_ringsize, ret = 0;
+
+ /*
+ * +26 gets the maximum ethernet encapsulation, +7 & ~7 because the
+ * card needs room to do 8 byte alignment, +2 so we can reserve
+ * the first 2 bytes, and +16 gets room for the status word from the
+ * card.
+ */
+ mdp->rx_buf_sz = (ndev->mtu <= 1492 ? PKT_BUF_SZ :
+ (((ndev->mtu + 26 + 7) & ~7) + 2 + 16));
+
+ /* Allocate RX and TX skb rings */
+ mdp->rx_skbuff = kmalloc(sizeof(*mdp->rx_skbuff) * RX_RING_SIZE,
+ GFP_KERNEL);
+ if (!mdp->rx_skbuff) {
+ printk(KERN_ERR "%s: Cannot allocate Rx skb\n", ndev->name);
+ ret = -ENOMEM;
+ return ret;
+ }
+
+ mdp->tx_skbuff = kmalloc(sizeof(*mdp->tx_skbuff) * TX_RING_SIZE,
+ GFP_KERNEL);
+ if (!mdp->tx_skbuff) {
+ printk(KERN_ERR "%s: Cannot allocate Tx skb\n", ndev->name);
+ ret = -ENOMEM;
+ goto skb_ring_free;
+ }
+
+ /* Allocate all Rx descriptors. */
+ rx_ringsize = sizeof(struct sh_eth_rxdesc) * RX_RING_SIZE;
+ mdp->rx_ring = dma_alloc_coherent(NULL, rx_ringsize, &mdp->rx_desc_dma,
+ GFP_KERNEL);
+
+ if (!mdp->rx_ring) {
+ printk(KERN_ERR "%s: Cannot allocate Rx Ring (size %d bytes)\n",
+ ndev->name, rx_ringsize);
+ ret = -ENOMEM;
+ goto desc_ring_free;
+ }
+
+ mdp->dirty_rx = 0;
+
+ /* Allocate all Tx descriptors. */
+ tx_ringsize = sizeof(struct sh_eth_txdesc) * TX_RING_SIZE;
+ mdp->tx_ring = dma_alloc_coherent(NULL, tx_ringsize, &mdp->tx_desc_dma,
+ GFP_KERNEL);
+ if (!mdp->tx_ring) {
+ printk(KERN_ERR "%s: Cannot allocate Tx Ring (size %d bytes)\n",
+ ndev->name, tx_ringsize);
+ ret = -ENOMEM;
+ goto desc_ring_free;
+ }
+ return ret;
+
+desc_ring_free:
+ /* free DMA buffer */
+ dma_free_coherent(NULL, rx_ringsize, mdp->rx_ring, mdp->rx_desc_dma);
+
+skb_ring_free:
+ /* Free Rx and Tx skb ring buffer */
+ sh_eth_ring_free(ndev);
+
+ return ret;
+}
+
+static int sh_eth_dev_init(struct net_device *ndev)
+{
+ int ret = 0;
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+ u32 ioaddr = ndev->base_addr;
+ u_int32_t rx_int_var, tx_int_var;
+ u32 val;
+
+ /* Soft Reset */
+ sh_eth_reset(ndev);
+
+ ctrl_outl(RPADIR_PADS1, ioaddr + RPADIR); /* SH7712-DMA-RX-PAD2 */
+
+ /* all sh_eth int mask */
+ ctrl_outl(0, ioaddr + EESIPR);
+
+ /* FIFO size set */
+ ctrl_outl(0, ioaddr + EDMR); /* Endian change */
+
+ ctrl_outl((FIFO_SIZE_T | FIFO_SIZE_R), ioaddr + FDR);
+ ctrl_outl(0, ioaddr + TFTR);
+
+ ctrl_outl(RMCR_RST, ioaddr + RMCR);
+
+ rx_int_var = mdp->rx_int_var = DESC_I_RINT8 | DESC_I_RINT5;
+ tx_int_var = mdp->tx_int_var = DESC_I_TINT2;
+ ctrl_outl(rx_int_var | tx_int_var, ioaddr + TRSCER);
+
+ ctrl_outl((FIFO_F_D_RFF | FIFO_F_D_RFD), ioaddr + FCFTR);
+ ctrl_outl(0, ioaddr + TRIMD);
+
+ /* Descriptor format */
+ sh_eth_ring_format(ndev);
+
+ ctrl_outl((u32)mdp->rx_ring, ioaddr + RDLAR);
+ ctrl_outl((u32)mdp->tx_ring, ioaddr + TDLAR);
+
+ ctrl_outl(ctrl_inl(ioaddr + EESR), ioaddr + EESR);
+ ctrl_outl((DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff), ioaddr + EESIPR);
+
+ /* PAUSE Prohibition */
+ val = (ctrl_inl(ioaddr + ECMR) & ECMR_DM) |
+ ECMR_ZPF | (mdp->duplex ? ECMR_DM : 0) | ECMR_TE | ECMR_RE;
+
+ ctrl_outl(val, ioaddr + ECMR);
+ ctrl_outl(ECSR_BRCRX | ECSR_PSRTO | ECSR_LCHNG | ECSR_ICD |
+ ECSIPR_MPDIP, ioaddr + ECSR);
+ ctrl_outl(ECSIPR_BRCRXIP | ECSIPR_PSRTOIP | ECSIPR_LCHNGIP |
+ ECSIPR_ICDIP | ECSIPR_MPDIP, ioaddr + ECSIPR);
+
+ /* Set MAC address */
+ update_mac_address(ndev);
+
+ /* mask reset */
+#if defined(CONFIG_CPU_SUBTYPE_SH7710)
+ ctrl_outl(APR_AP, ioaddr + APR);
+ ctrl_outl(MPR_MP, ioaddr + MPR);
+ ctrl_outl(TPAUSER_UNLIMITED, ioaddr + TPAUSER);
+ ctrl_outl(BCFR_UNLIMITED, ioaddr + BCFR);
+#endif
+ /* Setting the Rx mode will start the Rx process. */
+ ctrl_outl(EDRRR_R, ioaddr + EDRRR);
+
+ netif_start_queue(ndev);
+
+ return ret;
+}
+
+/* free Tx skb function */
+static int sh_eth_txfree(struct net_device *ndev)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+ struct sh_eth_txdesc *txdesc;
+ int freeNum = 0;
+ int entry = 0;
+
+ for (; mdp->cur_tx - mdp->dirty_tx > 0; mdp->dirty_tx++) {
+ entry = mdp->dirty_tx % TX_RING_SIZE;
+ txdesc = &mdp->tx_ring[entry];
+ if (txdesc->status & cpu_to_le32(TD_TACT))
+ break;
+ /* Free the original skb. */
+ if (mdp->tx_skbuff[entry]) {
+ dev_kfree_skb_irq(mdp->tx_skbuff[entry]);
+ mdp->tx_skbuff[entry] = NULL;
+ freeNum++;
+ }
+ txdesc->status = cpu_to_le32(TD_TFP);
+ if (entry >= TX_RING_SIZE - 1)
+ txdesc->status |= cpu_to_le32(TD_TDLE);
+
+ mdp->stats.tx_packets++;
+ mdp->stats.tx_bytes += txdesc->buffer_length;
+ }
+ return freeNum;
+}
+
+/* Packet receive function */
+static int sh_eth_rx(struct net_device *ndev)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+ struct sh_eth_rxdesc *rxdesc;
+
+ int entry = mdp->cur_rx % RX_RING_SIZE;
+ int boguscnt = (mdp->dirty_rx + RX_RING_SIZE) - mdp->cur_rx;
+ struct sk_buff *skb;
+ u16 pkt_len = 0;
+ u32 desc_status;
+
+ rxdesc = &mdp->rx_ring[entry];
+ while (!(rxdesc->status & cpu_to_le32(RD_RACT))) {
+ desc_status = le32_to_cpu(rxdesc->status);
+ pkt_len = rxdesc->frame_length;
+
+ if (--boguscnt < 0)
+ break;
+
+ if (!(desc_status & RDFEND))
+ mdp->stats.rx_length_errors++;
+
+ if (desc_status & (RD_RFS1 | RD_RFS2 | RD_RFS3 | RD_RFS4 |
+ RD_RFS5 | RD_RFS6 | RD_RFS10)) {
+ mdp->stats.rx_errors++;
+ if (desc_status & RD_RFS1)
+ mdp->stats.rx_crc_errors++;
+ if (desc_status & RD_RFS2)
+ mdp->stats.rx_frame_errors++;
+ if (desc_status & RD_RFS3)
+ mdp->stats.rx_length_errors++;
+ if (desc_status & RD_RFS4)
+ mdp->stats.rx_length_errors++;
+ if (desc_status & RD_RFS6)
+ mdp->stats.rx_missed_errors++;
+ if (desc_status & RD_RFS10)
+ mdp->stats.rx_over_errors++;
+ } else {
+ swaps((char *)(rxdesc->addr & ~0x3), pkt_len + 2);
+ skb = mdp->rx_skbuff[entry];
+ mdp->rx_skbuff[entry] = NULL;
+ skb_put(skb, pkt_len);
+ skb->protocol = eth_type_trans(skb, ndev);
+ netif_rx(skb);
+ ndev->last_rx = jiffies;
+ mdp->stats.rx_packets++;
+ mdp->stats.rx_bytes += pkt_len;
+ }
+ rxdesc->status |= cpu_to_le32(RD_RACT);
+ entry = (++mdp->cur_rx) % RX_RING_SIZE;
+ }
+
+ /* Refill the Rx ring buffers. */
+ for (; mdp->cur_rx - mdp->dirty_rx > 0; mdp->dirty_rx++) {
+ entry = mdp->dirty_rx % RX_RING_SIZE;
+ rxdesc = &mdp->rx_ring[entry];
+ if (mdp->rx_skbuff[entry] == NULL) {
+ skb = dev_alloc_skb(mdp->rx_buf_sz);
+ mdp->rx_skbuff[entry] = skb;
+ if (skb == NULL)
+ break; /* Better luck next round. */
+ skb->dev = ndev;
+ skb_reserve(skb, RX_OFFSET);
+ rxdesc->addr = (u32)skb->data & ~0x3UL;
+ }
+ /* The size of the buffer is 16 byte boundary. */
+ rxdesc->buffer_length = (mdp->rx_buf_sz + 16) & ~0x0F;
+ if (entry >= RX_RING_SIZE - 1)
+ rxdesc->status |=
+ cpu_to_le32(RD_RACT | RD_RFP | RC_RDEL);
+ else
+ rxdesc->status |=
+ cpu_to_le32(RD_RACT | RD_RFP);
+ }
+
+ /* Restart Rx engine if stopped. */
+ /* If we don't need to check status, don't. -KDU */
+ ctrl_outl(EDRRR_R, ndev->base_addr + EDRRR);
+
+ return 0;
+}
+
+/* error control function */
+static void sh_eth_error(struct net_device *ndev, int intr_status)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+ u32 ioaddr = ndev->base_addr;
+ u32 felic_stat;
+
+ if (intr_status & EESR_ECI) {
+ felic_stat = ctrl_inl(ioaddr + ECSR);
+ ctrl_outl(felic_stat, ioaddr + ECSR); /* clear int */
+ if (felic_stat & ECSR_ICD)
+ mdp->stats.tx_carrier_errors++;
+ if (felic_stat & ECSR_LCHNG) {
+ /* Link Changed */
+ u32 link_stat = (ctrl_inl(ioaddr + PSR));
+ if (!(link_stat & PHY_ST_LINK)) {
+ /* Link Down : disable tx and rx */
+ ctrl_outl(ctrl_inl(ioaddr + ECMR) &
+ ~(ECMR_RE | ECMR_TE), ioaddr + ECMR);
+ } else {
+ /* Link Up */
+ ctrl_outl(ctrl_inl(ioaddr + EESIPR) &
+ ~DMAC_M_ECI, ioaddr + EESIPR);
+ /*clear int */
+ ctrl_outl(ctrl_inl(ioaddr + ECSR),
+ ioaddr + ECSR);
+ ctrl_outl(ctrl_inl(ioaddr + EESIPR) |
+ DMAC_M_ECI, ioaddr + EESIPR);
+ /* enable tx and rx */
+ ctrl_outl(ctrl_inl(ioaddr + ECMR) |
+ (ECMR_RE | ECMR_TE), ioaddr + ECMR);
+ }
+ }
+ }
+
+ if (intr_status & EESR_TWB) {
+ /* Write buck end. unused write back interrupt */
+ if (intr_status & EESR_TABT) /* Transmit Abort int */
+ mdp->stats.tx_aborted_errors++;
+ }
+
+ if (intr_status & EESR_RABT) {
+ /* Receive Abort int */
+ if (intr_status & EESR_RFRMER) {
+ /* Receive Frame Overflow int */
+ mdp->stats.rx_frame_errors++;
+ printk(KERN_ERR "Receive Frame Overflow\n");
+ }
+ }
+
+ if (intr_status & EESR_ADE) {
+ if (intr_status & EESR_TDE) {
+ if (intr_status & EESR_TFE)
+ mdp->stats.tx_fifo_errors++;
+ }
+ }
+
+ if (intr_status & EESR_RDE) {
+ /* Receive Descriptor Empty int */
+ mdp->stats.rx_over_errors++;
+
+ if (ctrl_inl(ioaddr + EDRRR) ^ EDRRR_R)
+ ctrl_outl(EDRRR_R, ioaddr + EDRRR);
+ printk(KERN_ERR "Receive Descriptor Empty\n");
+ }
+ if (intr_status & EESR_RFE) {
+ /* Receive FIFO Overflow int */
+ mdp->stats.rx_fifo_errors++;
+ printk(KERN_ERR "Receive FIFO Overflow\n");
+ }
+ if (intr_status &
+ (EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | EESR_TFE)) {
+ /* Tx error */
+ u32 edtrr = ctrl_inl(ndev->base_addr + EDTRR);
+ /* dmesg */
+ printk(KERN_ERR "%s:TX error. status=%8.8x cur_tx=%8.8x ",
+ ndev->name, intr_status, mdp->cur_tx);
+ printk(KERN_ERR "dirty_tx=%8.8x state=%8.8x EDTRR=%8.8x.\n",
+ mdp->dirty_tx, (u32) ndev->state, edtrr);
+ /* dirty buffer free */
+ sh_eth_txfree(ndev);
+
+ /* SH7712 BUG */
+ if (edtrr ^ EDTRR_TRNS) {
+ /* tx dma start */
+ ctrl_outl(EDTRR_TRNS, ndev->base_addr + EDTRR);
+ }
+ /* wakeup */
+ netif_wake_queue(ndev);
+ }
+}
+
+static irqreturn_t sh_eth_interrupt(int irq, void *netdev)
+{
+ struct net_device *ndev = netdev;
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+ u32 ioaddr, boguscnt = RX_RING_SIZE;
+ u32 intr_status = 0;
+
+ ioaddr = ndev->base_addr;
+ spin_lock(&mdp->lock);
+
+ intr_status = ctrl_inl(ioaddr + EESR);
+ /* Clear interrupt */
+ ctrl_outl(intr_status, ioaddr + EESR);
+
+ if (intr_status & (EESR_FRC | EESR_RINT8 |
+ EESR_RINT5 | EESR_RINT4 | EESR_RINT3 | EESR_RINT2 |
+ EESR_RINT1))
+ sh_eth_rx(ndev);
+ if (intr_status & (EESR_FTC |
+ EESR_TINT4 | EESR_TINT3 | EESR_TINT2 | EESR_TINT1)) {
+
+ sh_eth_txfree(ndev);
+ netif_wake_queue(ndev);
+ }
+
+ if (intr_status & EESR_ERR_CHECK)
+ sh_eth_error(ndev, intr_status);
+
+ if (--boguscnt < 0) {
+ printk(KERN_WARNING
+ "%s: Too much work at interrupt, status=0x%4.4x.\n",
+ ndev->name, intr_status);
+ }
+
+ spin_unlock(&mdp->lock);
+
+ return IRQ_HANDLED;
+}
+
+static void sh_eth_timer(unsigned long data)
+{
+ struct net_device *ndev = (struct net_device *)data;
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+
+ mod_timer(&mdp->timer, jiffies + (10 * HZ));
+}
+
+/* PHY state control function */
+static void sh_eth_adjust_link(struct net_device *ndev)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+ struct phy_device *phydev = mdp->phydev;
+ u32 ioaddr = ndev->base_addr;
+ int new_state = 0;
+
+ if (phydev->link != PHY_DOWN) {
+ if (phydev->duplex != mdp->duplex) {
+ new_state = 1;
+ mdp->duplex = phydev->duplex;
+ }
+
+ if (phydev->speed != mdp->speed) {
+ new_state = 1;
+ mdp->speed = phydev->speed;
+ }
+ if (mdp->link == PHY_DOWN) {
+ ctrl_outl((ctrl_inl(ioaddr + ECMR) & ~ECMR_TXF)
+ | ECMR_DM, ioaddr + ECMR);
+ new_state = 1;
+ mdp->link = phydev->link;
+ netif_schedule(ndev);
+ netif_carrier_on(ndev);
+ netif_start_queue(ndev);
+ }
+ } else if (mdp->link) {
+ new_state = 1;
+ mdp->link = PHY_DOWN;
+ mdp->speed = 0;
+ mdp->duplex = -1;
+ netif_stop_queue(ndev);
+ netif_carrier_off(ndev);
+ }
+
+ if (new_state)
+ phy_print_status(phydev);
+}
+
+/* PHY init function */
+static int sh_eth_phy_init(struct net_device *ndev)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+ char phy_id[BUS_ID_SIZE];
+ struct phy_device *phydev = NULL;
+
+ snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT,
+ mdp->mii_bus->id , mdp->phy_id);
+
+ mdp->link = PHY_DOWN;
+ mdp->speed = 0;
+ mdp->duplex = -1;
+
+ /* Try connect to PHY */
+ phydev = phy_connect(ndev, phy_id, &sh_eth_adjust_link,
+ 0, PHY_INTERFACE_MODE_MII);
+ if (IS_ERR(phydev)) {
+ dev_err(&ndev->dev, "phy_connect failed\n");
+ return PTR_ERR(phydev);
+ }
+ dev_info(&ndev->dev, "attached phy %i to driver %s\n",
+ phydev->addr, phydev->drv->name);
+
+ mdp->phydev = phydev;
+
+ return 0;
+}
+
+/* PHY control start function */
+static int sh_eth_phy_start(struct net_device *ndev)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+ int ret;
+
+ ret = sh_eth_phy_init(ndev);
+ if (ret)
+ return ret;
+
+ /* reset phy - this also wakes it from PDOWN */
+ phy_write(mdp->phydev, MII_BMCR, BMCR_RESET);
+ phy_start(mdp->phydev);
+
+ return 0;
+}
+
+/* network device open function */
+static int sh_eth_open(struct net_device *ndev)
+{
+ int ret = 0;
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+
+ ret = request_irq(ndev->irq, &sh_eth_interrupt, 0, ndev->name, ndev);
+ if (ret) {
+ printk(KERN_ERR "Can not assign IRQ number to %s\n", CARDNAME);
+ return ret;
+ }
+
+ /* Descriptor set */
+ ret = sh_eth_ring_init(ndev);
+ if (ret)
+ goto out_free_irq;
+
+ /* device init */
+ ret = sh_eth_dev_init(ndev);
+ if (ret)
+ goto out_free_irq;
+
+ /* PHY control start*/
+ ret = sh_eth_phy_start(ndev);
+ if (ret)
+ goto out_free_irq;
+
+ /* Set the timer to check for link beat. */
+ init_timer(&mdp->timer);
+ mdp->timer.expires = (jiffies + (24 * HZ)) / 10;/* 2.4 sec. */
+ setup_timer(&mdp->timer, sh_eth_timer, ndev);
+
+ return ret;
+
+out_free_irq:
+ free_irq(ndev->irq, ndev);
+ return ret;
+}
+
+/* Timeout function */
+static void sh_eth_tx_timeout(struct net_device *ndev)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+ u32 ioaddr = ndev->base_addr;
+ struct sh_eth_rxdesc *rxdesc;
+ int i;
+
+ netif_stop_queue(ndev);
+
+ /* worning message out. */
+ printk(KERN_WARNING "%s: transmit timed out, status %8.8x,"
+ " resetting...\n", ndev->name, (int)ctrl_inl(ioaddr + EESR));
+
+ /* tx_errors count up */
+ mdp->stats.tx_errors++;
+
+ /* timer off */
+ del_timer_sync(&mdp->timer);
+
+ /* Free all the skbuffs in the Rx queue. */
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ rxdesc = &mdp->rx_ring[i];
+ rxdesc->status = 0;
+ rxdesc->addr = 0xBADF00D0;
+ if (mdp->rx_skbuff[i])
+ dev_kfree_skb(mdp->rx_skbuff[i]);
+ mdp->rx_skbuff[i] = NULL;
+ }
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ if (mdp->tx_skbuff[i])
+ dev_kfree_skb(mdp->tx_skbuff[i]);
+ mdp->tx_skbuff[i] = NULL;
+ }
+
+ /* device init */
+ sh_eth_dev_init(ndev);
+
+ /* timer on */
+ mdp->timer.expires = (jiffies + (24 * HZ)) / 10;/* 2.4 sec. */
+ add_timer(&mdp->timer);
+}
+
+/* Packet transmit function */
+static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+ struct sh_eth_txdesc *txdesc;
+ u32 entry;
+ int flags;
+
+ spin_lock_irqsave(&mdp->lock, flags);
+ if ((mdp->cur_tx - mdp->dirty_tx) >= (TX_RING_SIZE - 4)) {
+ if (!sh_eth_txfree(ndev)) {
+ netif_stop_queue(ndev);
+ spin_unlock_irqrestore(&mdp->lock, flags);
+ return 1;
+ }
+ }
+ spin_unlock_irqrestore(&mdp->lock, flags);
+
+ entry = mdp->cur_tx % TX_RING_SIZE;
+ mdp->tx_skbuff[entry] = skb;
+ txdesc = &mdp->tx_ring[entry];
+ txdesc->addr = (u32)(skb->data);
+ /* soft swap. */
+ swaps((char *)(txdesc->addr & ~0x3), skb->len + 2);
+ /* write back */
+ __flush_purge_region(skb->data, skb->len);
+ if (skb->len < ETHERSMALL)
+ txdesc->buffer_length = ETHERSMALL;
+ else
+ txdesc->buffer_length = skb->len;
+
+ if (entry >= TX_RING_SIZE - 1)
+ txdesc->status |= cpu_to_le32(TD_TACT | TD_TDLE);
+ else
+ txdesc->status |= cpu_to_le32(TD_TACT);
+
+ mdp->cur_tx++;
+
+ ctrl_outl(EDTRR_TRNS, ndev->base_addr + EDTRR);
+ ndev->trans_start = jiffies;
+
+ return 0;
+}
+
+/* device close function */
+static int sh_eth_close(struct net_device *ndev)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+ u32 ioaddr = ndev->base_addr;
+ int ringsize;
+
+ netif_stop_queue(ndev);
+
+ /* Disable interrupts by clearing the interrupt mask. */
+ ctrl_outl(0x0000, ioaddr + EESIPR);
+
+ /* Stop the chip's Tx and Rx processes. */
+ ctrl_outl(0, ioaddr + EDTRR);
+ ctrl_outl(0, ioaddr + EDRRR);
+
+ /* PHY Disconnect */
+ if (mdp->phydev) {
+ phy_stop(mdp->phydev);
+ phy_disconnect(mdp->phydev);
+ }
+
+ free_irq(ndev->irq, ndev);
+
+ del_timer_sync(&mdp->timer);
+
+ /* Free all the skbuffs in the Rx queue. */
+ sh_eth_ring_free(ndev);
+
+ /* free DMA buffer */
+ ringsize = sizeof(struct sh_eth_rxdesc) * RX_RING_SIZE;
+ dma_free_coherent(NULL, ringsize, mdp->rx_ring, mdp->rx_desc_dma);
+
+ /* free DMA buffer */
+ ringsize = sizeof(struct sh_eth_txdesc) * TX_RING_SIZE;
+ dma_free_coherent(NULL, ringsize, mdp->tx_ring, mdp->tx_desc_dma);
+
+ return 0;
+}
+
+static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+ u32 ioaddr = ndev->base_addr;
+
+ mdp->stats.tx_dropped += ctrl_inl(ioaddr + TROCR);
+ ctrl_outl(0, ioaddr + TROCR); /* (write clear) */
+ mdp->stats.collisions += ctrl_inl(ioaddr + CDCR);
+ ctrl_outl(0, ioaddr + CDCR); /* (write clear) */
+ mdp->stats.tx_carrier_errors += ctrl_inl(ioaddr + LCCR);
+ ctrl_outl(0, ioaddr + LCCR); /* (write clear) */
+ mdp->stats.tx_carrier_errors += ctrl_inl(ioaddr + CNDCR);
+ ctrl_outl(0, ioaddr + CNDCR); /* (write clear) */
+
+ return &mdp->stats;
+}
+
+/* ioctl to device funciotn*/
+static int sh_eth_do_ioctl(struct net_device *ndev, struct ifreq *rq,
+ int cmd)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+ struct phy_device *phydev = mdp->phydev;
+
+ if (!netif_running(ndev))
+ return -EINVAL;
+
+ if (!phydev)
+ return -ENODEV;
+
+ return phy_mii_ioctl(phydev, if_mii(rq), cmd);
+}
+
+
+/* Multicast reception directions set */
+static void sh_eth_set_multicast_list(struct net_device *ndev)
+{
+ u32 ioaddr = ndev->base_addr;
+
+ if (ndev->flags & IFF_PROMISC) {
+ /* Set promiscuous. */
+ ctrl_outl((ctrl_inl(ioaddr + ECMR) & ~ECMR_MCT) | ECMR_PRM,
+ ioaddr + ECMR);
+ } else {
+ /* Normal, unicast/broadcast-only mode. */
+ ctrl_outl((ctrl_inl(ioaddr + ECMR) & ~ECMR_PRM) | ECMR_MCT,
+ ioaddr + ECMR);
+ }
+}
+
+/* SuperH's TSU register init function */
+static void sh_eth_tsu_init(u32 ioaddr)
+{
+ ctrl_outl(0, ioaddr + TSU_FWEN0); /* Disable forward(0->1) */
+ ctrl_outl(0, ioaddr + TSU_FWEN1); /* Disable forward(1->0) */
+ ctrl_outl(0, ioaddr + TSU_FCM); /* forward fifo 3k-3k */
+ ctrl_outl(0xc, ioaddr + TSU_BSYSL0);
+ ctrl_outl(0xc, ioaddr + TSU_BSYSL1);
+ ctrl_outl(0, ioaddr + TSU_PRISL0);
+ ctrl_outl(0, ioaddr + TSU_PRISL1);
+ ctrl_outl(0, ioaddr + TSU_FWSL0);
+ ctrl_outl(0, ioaddr + TSU_FWSL1);
+ ctrl_outl(TSU_FWSLC_POSTENU | TSU_FWSLC_POSTENL, ioaddr + TSU_FWSLC);
+ ctrl_outl(0, ioaddr + TSU_QTAGM0); /* Disable QTAG(0->1) */
+ ctrl_outl(0, ioaddr + TSU_QTAGM1); /* Disable QTAG(1->0) */
+ ctrl_outl(0, ioaddr + TSU_FWSR); /* all interrupt status clear */
+ ctrl_outl(0, ioaddr + TSU_FWINMK); /* Disable all interrupt */
+ ctrl_outl(0, ioaddr + TSU_TEN); /* Disable all CAM entry */
+ ctrl_outl(0, ioaddr + TSU_POST1); /* Disable CAM entry [ 0- 7] */
+ ctrl_outl(0, ioaddr + TSU_POST2); /* Disable CAM entry [ 8-15] */
+ ctrl_outl(0, ioaddr + TSU_POST3); /* Disable CAM entry [16-23] */
+ ctrl_outl(0, ioaddr + TSU_POST4); /* Disable CAM entry [24-31] */
+}
+
+/* MDIO bus release function */
+static int sh_mdio_release(struct net_device *ndev)
+{
+ struct mii_bus *bus = dev_get_drvdata(&ndev->dev);
+
+ /* unregister mdio bus */
+ mdiobus_unregister(bus);
+
+ /* remove mdio bus info from net_device */
+ dev_set_drvdata(&ndev->dev, NULL);
+
+ /* free bitbang info */
+ free_mdio_bitbang(bus);
+
+ return 0;
+}
+
+/* MDIO bus init function */
+static int sh_mdio_init(struct net_device *ndev, int id)
+{
+ int ret, i;
+ struct bb_info *bitbang;
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+
+ /* create bit control struct for PHY */
+ bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL);
+ if (!bitbang) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* bitbang init */
+ bitbang->addr = ndev->base_addr + PIR;
+ bitbang->mdi_msk = 0x08;
+ bitbang->mdo_msk = 0x04;
+ bitbang->mmd_msk = 0x02;/* MMD */
+ bitbang->mdc_msk = 0x01;
+ bitbang->ctrl.ops = &bb_ops;
+
+ /* MII contorller setting */
+ mdp->mii_bus = alloc_mdio_bitbang(&bitbang->ctrl);
+ if (!mdp->mii_bus) {
+ ret = -ENOMEM;
+ goto out_free_bitbang;
+ }
+
+ /* Hook up MII support for ethtool */
+ mdp->mii_bus->name = "sh_mii";
+ mdp->mii_bus->dev = &ndev->dev;
+ mdp->mii_bus->id = id;
+
+ /* PHY IRQ */
+ mdp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+ if (!mdp->mii_bus->irq) {
+ ret = -ENOMEM;
+ goto out_free_bus;
+ }
+
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ mdp->mii_bus->irq[i] = PHY_POLL;
+
+ /* regist mdio bus */
+ ret = mdiobus_register(mdp->mii_bus);
+ if (ret)
+ goto out_free_irq;
+
+ dev_set_drvdata(&ndev->dev, mdp->mii_bus);
+
+ return 0;
+
+out_free_irq:
+ kfree(mdp->mii_bus->irq);
+
+out_free_bus:
+ kfree(mdp->mii_bus);
+
+out_free_bitbang:
+ kfree(bitbang);
+
+out:
+ return ret;
+}
+
+static int sh_eth_drv_probe(struct platform_device *pdev)
+{
+ int ret, i, devno = 0;
+ struct resource *res;
+ struct net_device *ndev = NULL;
+ struct sh_eth_private *mdp;
+
+ /* get base addr */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (unlikely(res == NULL)) {
+ dev_err(&pdev->dev, "invalid resource\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ndev = alloc_etherdev(sizeof(struct sh_eth_private));
+ if (!ndev) {
+ printk(KERN_ERR "%s: could not allocate device.\n", CARDNAME);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* The sh Ether-specific entries in the device structure. */
+ ndev->base_addr = res->start;
+ devno = pdev->id;
+ if (devno < 0)
+ devno = 0;
+
+ ndev->dma = -1;
+ ndev->irq = platform_get_irq(pdev, 0);
+ if (ndev->irq < 0) {
+ ret = -ENODEV;
+ goto out_release;
+ }
+
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+
+ /* Fill in the fields of the device structure with ethernet values. */
+ ether_setup(ndev);
+
+ mdp = netdev_priv(ndev);
+ spin_lock_init(&mdp->lock);
+
+ /* get PHY ID */
+ mdp->phy_id = (int)pdev->dev.platform_data;
+
+ /* set function */
+ ndev->open = sh_eth_open;
+ ndev->hard_start_xmit = sh_eth_start_xmit;
+ ndev->stop = sh_eth_close;
+ ndev->get_stats = sh_eth_get_stats;
+ ndev->set_multicast_list = sh_eth_set_multicast_list;
+ ndev->do_ioctl = sh_eth_do_ioctl;
+ ndev->tx_timeout = sh_eth_tx_timeout;
+ ndev->watchdog_timeo = TX_TIMEOUT;
+
+ mdp->post_rx = POST_RX >> (devno << 1);
+ mdp->post_fw = POST_FW >> (devno << 1);
+
+ /* read and set MAC address */
+ read_mac_address(ndev);
+
+ /* First device only init */
+ if (!devno) {
+ /* reset device */
+ ctrl_outl(ARSTR_ARSTR, ndev->base_addr + ARSTR);
+ mdelay(1);
+
+ /* TSU init (Init only)*/
+ sh_eth_tsu_init(SH_TSU_ADDR);
+ }
+
+ /* network device register */
+ ret = register_netdev(ndev);
+ if (ret)
+ goto out_release;
+
+ /* mdio bus init */
+ ret = sh_mdio_init(ndev, pdev->id);
+ if (ret)
+ goto out_unregister;
+
+ /* pritnt device infomation */
+ printk(KERN_INFO "%s: %s at 0x%x, ",
+ ndev->name, CARDNAME, (u32) ndev->base_addr);
+
+ for (i = 0; i < 5; i++)
+ printk(KERN_INFO "%2.2x:", ndev->dev_addr[i]);
+ printk(KERN_INFO "%2.2x, IRQ %d.\n", ndev->dev_addr[i], ndev->irq);
+
+ platform_set_drvdata(pdev, ndev);
+
+ return ret;
+
+out_unregister:
+ unregister_netdev(ndev);
+
+out_release:
+ /* net_dev free */
+ if (ndev)
+ free_netdev(ndev);
+
+out:
+ return ret;
+}
+
+static int sh_eth_drv_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+
+ sh_mdio_release(ndev);
+ unregister_netdev(ndev);
+ flush_scheduled_work();
+
+ free_netdev(ndev);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver sh_eth_driver = {
+ .probe = sh_eth_drv_probe,
+ .remove = sh_eth_drv_remove,
+ .driver = {
+ .name = CARDNAME,
+ },
+};
+
+static int __init sh_eth_init(void)
+{
+ return platform_driver_register(&sh_eth_driver);
+}
+
+static void __exit sh_eth_cleanup(void)
+{
+ platform_driver_unregister(&sh_eth_driver);
+}
+
+module_init(sh_eth_init);
+module_exit(sh_eth_cleanup);
+
+MODULE_AUTHOR("Nobuhiro Iwamatsu, Yoshihiro Shimoda");
+MODULE_DESCRIPTION("Renesas SuperH Ethernet driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h
new file mode 100644
index 0000000..ca2db6b
--- /dev/null
+++ b/drivers/net/sh_eth.h
@@ -0,0 +1,464 @@
+/*
+ * SuperH Ethernet device driver
+ *
+ * Copyright (C) 2006-2008 Nobuhiro Iwamatsu
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ */
+
+#ifndef __SH_ETH_H__
+#define __SH_ETH_H__
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+
+#define CARDNAME "sh-eth"
+#define TX_TIMEOUT (5*HZ)
+
+#define TX_RING_SIZE 128 /* Tx ring size */
+#define RX_RING_SIZE 128 /* Rx ring size */
+#define RX_OFFSET 2 /* skb offset */
+#define ETHERSMALL 60
+#define PKT_BUF_SZ 1538
+
+/* Chip Base Address */
+#define SH_ETH0_BASE 0xA7000000
+#define SH_ETH1_BASE 0xA7000400
+#define SH_TSU_ADDR 0xA7000804
+
+/* Chip Registers */
+/* E-DMAC */
+#define EDMR 0x0000
+#define EDTRR 0x0004
+#define EDRRR 0x0008
+#define TDLAR 0x000C
+#define RDLAR 0x0010
+#define EESR 0x0014
+#define EESIPR 0x0018
+#define TRSCER 0x001C
+#define RMFCR 0x0020
+#define TFTR 0x0024
+#define FDR 0x0028
+#define RMCR 0x002C
+#define EDOCR 0x0030
+#define FCFTR 0x0034
+#define RPADIR 0x0038
+#define TRIMD 0x003C
+#define RBWAR 0x0040
+#define RDFAR 0x0044
+#define TBRAR 0x004C
+#define TDFAR 0x0050
+/* Ether Register */
+#define ECMR 0x0160
+#define ECSR 0x0164
+#define ECSIPR 0x0168
+#define PIR 0x016C
+#define MAHR 0x0170
+#define MALR 0x0174
+#define RFLR 0x0178
+#define PSR 0x017C
+#define TROCR 0x0180
+#define CDCR 0x0184
+#define LCCR 0x0188
+#define CNDCR 0x018C
+#define CEFCR 0x0194
+#define FRECR 0x0198
+#define TSFRCR 0x019C
+#define TLFRCR 0x01A0
+#define RFCR 0x01A4
+#define MAFCR 0x01A8
+#define IPGR 0x01B4
+#if defined(CONFIG_CPU_SUBTYPE_SH7710)
+#define APR 0x01B8
+#define MPR 0x01BC
+#define TPAUSER 0x1C4
+#define BCFR 0x1CC
+#endif /* CONFIG_CPU_SH7710 */
+
+#define ARSTR 0x0800
+
+/* TSU */
+#define TSU_CTRST 0x004
+#define TSU_FWEN0 0x010
+#define TSU_FWEN1 0x014
+#define TSU_FCM 0x018
+#define TSU_BSYSL0 0x020
+#define TSU_BSYSL1 0x024
+#define TSU_PRISL0 0x028
+#define TSU_PRISL1 0x02C
+#define TSU_FWSL0 0x030
+#define TSU_FWSL1 0x034
+#define TSU_FWSLC 0x038
+#define TSU_QTAGM0 0x040
+#define TSU_QTAGM1 0x044
+#define TSU_ADQT0 0x048
+#define TSU_ADQT1 0x04C
+#define TSU_FWSR 0x050
+#define TSU_FWINMK 0x054
+#define TSU_ADSBSY 0x060
+#define TSU_TEN 0x064
+#define TSU_POST1 0x070
+#define TSU_POST2 0x074
+#define TSU_POST3 0x078
+#define TSU_POST4 0x07C
+#define TXNLCR0 0x080
+#define TXALCR0 0x084
+#define RXNLCR0 0x088
+#define RXALCR0 0x08C
+#define FWNLCR0 0x090
+#define FWALCR0 0x094
+#define TXNLCR1 0x0A0
+#define TXALCR1 0x0A4
+#define RXNLCR1 0x0A8
+#define RXALCR1 0x0AC
+#define FWNLCR1 0x0B0
+#define FWALCR1 0x0B4
+
+#define TSU_ADRH0 0x0100
+#define TSU_ADRL0 0x0104
+#define TSU_ADRL31 0x01FC
+
+/* Register's bits */
+
+/* EDMR */
+enum DMAC_M_BIT {
+ EDMR_DL1 = 0x20, EDMR_DL0 = 0x10, EDMR_SRST = 0x01,
+};
+
+/* EDTRR */
+enum DMAC_T_BIT {
+ EDTRR_TRNS = 0x01,
+};
+
+/* EDRRR*/
+enum EDRRR_R_BIT {
+ EDRRR_R = 0x01,
+};
+
+/* TPAUSER */
+enum TPAUSER_BIT {
+ TPAUSER_TPAUSE = 0x0000ffff,
+ TPAUSER_UNLIMITED = 0,
+};
+
+/* BCFR */
+enum BCFR_BIT {
+ BCFR_RPAUSE = 0x0000ffff,
+ BCFR_UNLIMITED = 0,
+};
+
+/* PIR */
+enum PIR_BIT {
+ PIR_MDI = 0x08, PIR_MDO = 0x04, PIR_MMD = 0x02, PIR_MDC = 0x01,
+};
+
+/* PSR */
+enum PHY_STATUS_BIT { PHY_ST_LINK = 0x01, };
+
+/* EESR */
+enum EESR_BIT {
+ EESR_TWB = 0x40000000, EESR_TABT = 0x04000000,
+ EESR_RABT = 0x02000000, EESR_RFRMER = 0x01000000,
+ EESR_ADE = 0x00800000, EESR_ECI = 0x00400000,
+ EESR_FTC = 0x00200000, EESR_TDE = 0x00100000,
+ EESR_TFE = 0x00080000, EESR_FRC = 0x00040000,
+ EESR_RDE = 0x00020000, EESR_RFE = 0x00010000,
+ EESR_TINT4 = 0x00000800, EESR_TINT3 = 0x00000400,
+ EESR_TINT2 = 0x00000200, EESR_TINT1 = 0x00000100,
+ EESR_RINT8 = 0x00000080, EESR_RINT5 = 0x00000010,
+ EESR_RINT4 = 0x00000008, EESR_RINT3 = 0x00000004,
+ EESR_RINT2 = 0x00000002, EESR_RINT1 = 0x00000001,
+};
+
+#define EESR_ERR_CHECK (EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE \
+ | EESR_RFRMER | EESR_ADE | EESR_TFE | EESR_TDE | EESR_ECI)
+
+/* EESIPR */
+enum DMAC_IM_BIT {
+ DMAC_M_TWB = 0x40000000, DMAC_M_TABT = 0x04000000,
+ DMAC_M_RABT = 0x02000000,
+ DMAC_M_RFRMER = 0x01000000, DMAC_M_ADF = 0x00800000,
+ DMAC_M_ECI = 0x00400000, DMAC_M_FTC = 0x00200000,
+ DMAC_M_TDE = 0x00100000, DMAC_M_TFE = 0x00080000,
+ DMAC_M_FRC = 0x00040000, DMAC_M_RDE = 0x00020000,
+ DMAC_M_RFE = 0x00010000, DMAC_M_TINT4 = 0x00000800,
+ DMAC_M_TINT3 = 0x00000400, DMAC_M_TINT2 = 0x00000200,
+ DMAC_M_TINT1 = 0x00000100, DMAC_M_RINT8 = 0x00000080,
+ DMAC_M_RINT5 = 0x00000010, DMAC_M_RINT4 = 0x00000008,
+ DMAC_M_RINT3 = 0x00000004, DMAC_M_RINT2 = 0x00000002,
+ DMAC_M_RINT1 = 0x00000001,
+};
+
+/* Receive descriptor bit */
+enum RD_STS_BIT {
+ RD_RACT = 0x80000000, RC_RDEL = 0x40000000,
+ RC_RFP1 = 0x20000000, RC_RFP0 = 0x10000000,
+ RD_RFE = 0x08000000, RD_RFS10 = 0x00000200,
+ RD_RFS9 = 0x00000100, RD_RFS8 = 0x00000080,
+ RD_RFS7 = 0x00000040, RD_RFS6 = 0x00000020,
+ RD_RFS5 = 0x00000010, RD_RFS4 = 0x00000008,
+ RD_RFS3 = 0x00000004, RD_RFS2 = 0x00000002,
+ RD_RFS1 = 0x00000001,
+};
+#define RDF1ST RC_RFP1
+#define RDFEND RC_RFP0
+#define RD_RFP (RC_RFP1|RC_RFP0)
+
+/* FCFTR */
+enum FCFTR_BIT {
+ FCFTR_RFF2 = 0x00040000, FCFTR_RFF1 = 0x00020000,
+ FCFTR_RFF0 = 0x00010000, FCFTR_RFD2 = 0x00000004,
+ FCFTR_RFD1 = 0x00000002, FCFTR_RFD0 = 0x00000001,
+};
+#define FIFO_F_D_RFF (FCFTR_RFF2|FCFTR_RFF1|FCFTR_RFF0)
+#define FIFO_F_D_RFD (FCFTR_RFD2|FCFTR_RFD1|FCFTR_RFD0)
+
+/* Transfer descriptor bit */
+enum TD_STS_BIT {
+ TD_TACT = 0x80000000, TD_TDLE = 0x40000000, TD_TFP1 = 0x20000000,
+ TD_TFP0 = 0x10000000,
+};
+#define TDF1ST TD_TFP1
+#define TDFEND TD_TFP0
+#define TD_TFP (TD_TFP1|TD_TFP0)
+
+/* RMCR */
+enum RECV_RST_BIT { RMCR_RST = 0x01, };
+/* ECMR */
+enum FELIC_MODE_BIT {
+ ECMR_ZPF = 0x00080000, ECMR_PFR = 0x00040000, ECMR_RXF = 0x00020000,
+ ECMR_TXF = 0x00010000, ECMR_MCT = 0x00002000, ECMR_PRCEF = 0x00001000,
+ ECMR_PMDE = 0x00000200, ECMR_RE = 0x00000040, ECMR_TE = 0x00000020,
+ ECMR_ILB = 0x00000008, ECMR_ELB = 0x00000004, ECMR_DM = 0x00000002,
+ ECMR_PRM = 0x00000001,
+};
+
+/* ECSR */
+enum ECSR_STATUS_BIT {
+ ECSR_BRCRX = 0x20, ECSR_PSRTO = 0x10, ECSR_LCHNG = 0x04,
+ ECSR_MPD = 0x02, ECSR_ICD = 0x01,
+};
+
+/* ECSIPR */
+enum ECSIPR_STATUS_MASK_BIT {
+ ECSIPR_BRCRXIP = 0x20, ECSIPR_PSRTOIP = 0x10, ECSIPR_LCHNGIP = 0x04,
+ ECSIPR_MPDIP = 0x02, ECSIPR_ICDIP = 0x01,
+};
+
+/* APR */
+enum APR_BIT {
+ APR_AP = 0x00000001,
+};
+
+/* MPR */
+enum MPR_BIT {
+ MPR_MP = 0x00000001,
+};
+
+/* TRSCER */
+enum DESC_I_BIT {
+ DESC_I_TINT4 = 0x0800, DESC_I_TINT3 = 0x0400, DESC_I_TINT2 = 0x0200,
+ DESC_I_TINT1 = 0x0100, DESC_I_RINT8 = 0x0080, DESC_I_RINT5 = 0x0010,
+ DESC_I_RINT4 = 0x0008, DESC_I_RINT3 = 0x0004, DESC_I_RINT2 = 0x0002,
+ DESC_I_RINT1 = 0x0001,
+};
+
+/* RPADIR */
+enum RPADIR_BIT {
+ RPADIR_PADS1 = 0x20000, RPADIR_PADS0 = 0x10000,
+ RPADIR_PADR = 0x0003f,
+};
+
+/* FDR */
+enum FIFO_SIZE_BIT {
+ FIFO_SIZE_T = 0x00000700, FIFO_SIZE_R = 0x00000007,
+};
+enum phy_offsets {
+ PHY_CTRL = 0, PHY_STAT = 1, PHY_IDT1 = 2, PHY_IDT2 = 3,
+ PHY_ANA = 4, PHY_ANL = 5, PHY_ANE = 6,
+ PHY_16 = 16,
+};
+
+/* PHY_CTRL */
+enum PHY_CTRL_BIT {
+ PHY_C_RESET = 0x8000, PHY_C_LOOPBK = 0x4000, PHY_C_SPEEDSL = 0x2000,
+ PHY_C_ANEGEN = 0x1000, PHY_C_PWRDN = 0x0800, PHY_C_ISO = 0x0400,
+ PHY_C_RANEG = 0x0200, PHY_C_DUPLEX = 0x0100, PHY_C_COLT = 0x0080,
+};
+#define DM9161_PHY_C_ANEGEN 0 /* auto nego special */
+
+/* PHY_STAT */
+enum PHY_STAT_BIT {
+ PHY_S_100T4 = 0x8000, PHY_S_100X_F = 0x4000, PHY_S_100X_H = 0x2000,
+ PHY_S_10T_F = 0x1000, PHY_S_10T_H = 0x0800, PHY_S_ANEGC = 0x0020,
+ PHY_S_RFAULT = 0x0010, PHY_S_ANEGA = 0x0008, PHY_S_LINK = 0x0004,
+ PHY_S_JAB = 0x0002, PHY_S_EXTD = 0x0001,
+};
+
+/* PHY_ANA */
+enum PHY_ANA_BIT {
+ PHY_A_NP = 0x8000, PHY_A_ACK = 0x4000, PHY_A_RF = 0x2000,
+ PHY_A_FCS = 0x0400, PHY_A_T4 = 0x0200, PHY_A_FDX = 0x0100,
+ PHY_A_HDX = 0x0080, PHY_A_10FDX = 0x0040, PHY_A_10HDX = 0x0020,
+ PHY_A_SEL = 0x001f,
+};
+/* PHY_ANL */
+enum PHY_ANL_BIT {
+ PHY_L_NP = 0x8000, PHY_L_ACK = 0x4000, PHY_L_RF = 0x2000,
+ PHY_L_FCS = 0x0400, PHY_L_T4 = 0x0200, PHY_L_FDX = 0x0100,
+ PHY_L_HDX = 0x0080, PHY_L_10FDX = 0x0040, PHY_L_10HDX = 0x0020,
+ PHY_L_SEL = 0x001f,
+};
+
+/* PHY_ANE */
+enum PHY_ANE_BIT {
+ PHY_E_PDF = 0x0010, PHY_E_LPNPA = 0x0008, PHY_E_NPA = 0x0004,
+ PHY_E_PRX = 0x0002, PHY_E_LPANEGA = 0x0001,
+};
+
+/* DM9161 */
+enum PHY_16_BIT {
+ PHY_16_BP4B45 = 0x8000, PHY_16_BPSCR = 0x4000, PHY_16_BPALIGN = 0x2000,
+ PHY_16_BP_ADPOK = 0x1000, PHY_16_Repeatmode = 0x0800,
+ PHY_16_TXselect = 0x0400,
+ PHY_16_Rsvd = 0x0200, PHY_16_RMIIEnable = 0x0100,
+ PHY_16_Force100LNK = 0x0080,
+ PHY_16_APDLED_CTL = 0x0040, PHY_16_COLLED_CTL = 0x0020,
+ PHY_16_RPDCTR_EN = 0x0010,
+ PHY_16_ResetStMch = 0x0008, PHY_16_PreamSupr = 0x0004,
+ PHY_16_Sleepmode = 0x0002,
+ PHY_16_RemoteLoopOut = 0x0001,
+};
+
+#define POST_RX 0x08
+#define POST_FW 0x04
+#define POST0_RX (POST_RX)
+#define POST0_FW (POST_FW)
+#define POST1_RX (POST_RX >> 2)
+#define POST1_FW (POST_FW >> 2)
+#define POST_ALL (POST0_RX | POST0_FW | POST1_RX | POST1_FW)
+
+/* ARSTR */
+enum ARSTR_BIT { ARSTR_ARSTR = 0x00000001, };
+
+/* TSU_FWEN0 */
+enum TSU_FWEN0_BIT {
+ TSU_FWEN0_0 = 0x00000001,
+};
+
+/* TSU_ADSBSY */
+enum TSU_ADSBSY_BIT {
+ TSU_ADSBSY_0 = 0x00000001,
+};
+
+/* TSU_TEN */
+enum TSU_TEN_BIT {
+ TSU_TEN_0 = 0x80000000,
+};
+
+/* TSU_FWSL0 */
+enum TSU_FWSL0_BIT {
+ TSU_FWSL0_FW50 = 0x1000, TSU_FWSL0_FW40 = 0x0800,
+ TSU_FWSL0_FW30 = 0x0400, TSU_FWSL0_FW20 = 0x0200,
+ TSU_FWSL0_FW10 = 0x0100, TSU_FWSL0_RMSA0 = 0x0010,
+};
+
+/* TSU_FWSLC */
+enum TSU_FWSLC_BIT {
+ TSU_FWSLC_POSTENU = 0x2000, TSU_FWSLC_POSTENL = 0x1000,
+ TSU_FWSLC_CAMSEL03 = 0x0080, TSU_FWSLC_CAMSEL02 = 0x0040,
+ TSU_FWSLC_CAMSEL01 = 0x0020, TSU_FWSLC_CAMSEL00 = 0x0010,
+ TSU_FWSLC_CAMSEL13 = 0x0008, TSU_FWSLC_CAMSEL12 = 0x0004,
+ TSU_FWSLC_CAMSEL11 = 0x0002, TSU_FWSLC_CAMSEL10 = 0x0001,
+};
+
+/*
+ * The sh ether Tx buffer descriptors.
+ * This structure should be 20 bytes.
+ */
+struct sh_eth_txdesc {
+ u32 status; /* TD0 */
+#if defined(CONFIG_CPU_LITTLE_ENDIAN)
+ u16 pad0; /* TD1 */
+ u16 buffer_length; /* TD1 */
+#else
+ u16 buffer_length; /* TD1 */
+ u16 pad0; /* TD1 */
+#endif
+ u32 addr; /* TD2 */
+ u32 pad1; /* padding data */
+};
+
+/*
+ * The sh ether Rx buffer descriptors.
+ * This structure should be 20 bytes.
+ */
+struct sh_eth_rxdesc {
+ u32 status; /* RD0 */
+#if defined(CONFIG_CPU_LITTLE_ENDIAN)
+ u16 frame_length; /* RD1 */
+ u16 buffer_length; /* RD1 */
+#else
+ u16 buffer_length; /* RD1 */
+ u16 frame_length; /* RD1 */
+#endif
+ u32 addr; /* RD2 */
+ u32 pad0; /* padding data */
+};
+
+struct sh_eth_private {
+ dma_addr_t rx_desc_dma;
+ dma_addr_t tx_desc_dma;
+ struct sh_eth_rxdesc *rx_ring;
+ struct sh_eth_txdesc *tx_ring;
+ struct sk_buff **rx_skbuff;
+ struct sk_buff **tx_skbuff;
+ struct net_device_stats stats;
+ struct timer_list timer;
+ spinlock_t lock;
+ u32 cur_rx, dirty_rx; /* Producer/consumer ring indices */
+ u32 cur_tx, dirty_tx;
+ u32 rx_buf_sz; /* Based on MTU+slack. */
+ /* MII transceiver section. */
+ u32 phy_id; /* PHY ID */
+ struct mii_bus *mii_bus; /* MDIO bus control */
+ struct phy_device *phydev; /* PHY device control */
+ enum phy_state link;
+ int msg_enable;
+ int speed;
+ int duplex;
+ u32 rx_int_var, tx_int_var; /* interrupt control variables */
+ char post_rx; /* POST receive */
+ char post_fw; /* POST forward */
+ struct net_device_stats tsu_stats; /* TSU forward status */
+};
+
+static void swaps(char *src, int len)
+{
+#ifdef __LITTLE_ENDIAN__
+ u32 *p = (u32 *)src;
+ u32 *maxp;
+ maxp = p + ((len + sizeof(u32) - 1) / sizeof(u32));
+
+ for (; p < maxp; p++)
+ *p = swab32(*p);
+#endif
+}
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index abc63b0..3fe0176 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 62436b3..7f1cfc4 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -284,6 +284,86 @@
PC_VAUX_ON | PC_VCC_OFF));
}
+static void sky2_power_state(struct sky2_hw *hw, pci_power_t state)
+{
+ u16 power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_CTRL);
+ int pex = pci_find_capability(hw->pdev, PCI_CAP_ID_EXP);
+ u32 reg;
+
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+
+ switch (state) {
+ case PCI_D0:
+ break;
+
+ case PCI_D1:
+ power_control |= 1;
+ break;
+
+ case PCI_D2:
+ power_control |= 2;
+ break;
+
+ case PCI_D3hot:
+ case PCI_D3cold:
+ power_control |= 3;
+ if (hw->flags & SKY2_HW_ADV_POWER_CTL) {
+ /* additional power saving measurements */
+ reg = sky2_pci_read32(hw, PCI_DEV_REG4);
+
+ /* set gating core clock for LTSSM in L1 state */
+ reg |= P_PEX_LTSSM_STAT(P_PEX_LTSSM_L1_STAT) |
+ /* auto clock gated scheme controlled by CLKREQ */
+ P_ASPM_A1_MODE_SELECT |
+ /* enable Gate Root Core Clock */
+ P_CLK_GATE_ROOT_COR_ENA;
+
+ if (pex && (hw->flags & SKY2_HW_CLK_POWER)) {
+ /* enable Clock Power Management (CLKREQ) */
+ u16 ctrl = sky2_pci_read16(hw, pex + PCI_EXP_DEVCTL);
+
+ ctrl |= PCI_EXP_DEVCTL_AUX_PME;
+ sky2_pci_write16(hw, pex + PCI_EXP_DEVCTL, ctrl);
+ } else
+ /* force CLKREQ Enable in Our4 (A1b only) */
+ reg |= P_ASPM_FORCE_CLKREQ_ENA;
+
+ /* set Mask Register for Release/Gate Clock */
+ sky2_pci_write32(hw, PCI_DEV_REG5,
+ P_REL_PCIE_EXIT_L1_ST | P_GAT_PCIE_ENTER_L1_ST |
+ P_REL_PCIE_RX_EX_IDLE | P_GAT_PCIE_RX_EL_IDLE |
+ P_REL_GPHY_LINK_UP | P_GAT_GPHY_LINK_DOWN);
+ } else
+ sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_CLK_HALT);
+
+ /* put CPU into reset state */
+ sky2_write8(hw, B28_Y2_ASF_STAT_CMD, HCU_CCSR_ASF_RESET);
+ if (hw->chip_id == CHIP_ID_YUKON_SUPR && hw->chip_rev == CHIP_REV_YU_SU_A0)
+ /* put CPU into halt state */
+ sky2_write8(hw, B28_Y2_ASF_STAT_CMD, HCU_CCSR_ASF_HALTED);
+
+ if (pex && !(hw->flags & SKY2_HW_RAM_BUFFER)) {
+ reg = sky2_pci_read32(hw, PCI_DEV_REG1);
+ /* force to PCIe L1 */
+ reg |= PCI_FORCE_PEX_L1;
+ sky2_pci_write32(hw, PCI_DEV_REG1, reg);
+ }
+ break;
+
+ default:
+ dev_warn(&hw->pdev->dev, PFX "Invalid power state (%d) ",
+ state);
+ return;
+ }
+
+ power_control |= PCI_PM_CTRL_PME_ENABLE;
+ /* Finally, set the new power state. */
+ sky2_pci_write32(hw, hw->pm_cap + PCI_PM_CTRL, power_control);
+
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+ sky2_pci_read32(hw, B0_CTST);
+}
+
static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port)
{
u16 reg;
@@ -619,28 +699,71 @@
gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
}
-static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff)
+static const u32 phy_power[] = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD };
+static const u32 coma_mode[] = { PCI_Y2_PHY1_COMA, PCI_Y2_PHY2_COMA };
+
+static void sky2_phy_power_up(struct sky2_hw *hw, unsigned port)
{
u32 reg1;
- static const u32 phy_power[] = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD };
- static const u32 coma_mode[] = { PCI_Y2_PHY1_COMA, PCI_Y2_PHY2_COMA };
sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
- /* Turn on/off phy power saving */
- if (onoff)
- reg1 &= ~phy_power[port];
- else
- reg1 |= phy_power[port];
+ reg1 &= ~phy_power[port];
- if (onoff && hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+ if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
reg1 |= coma_mode[port];
sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
sky2_pci_read32(hw, PCI_DEV_REG1);
+}
- udelay(100);
+static void sky2_phy_power_down(struct sky2_hw *hw, unsigned port)
+{
+ u32 reg1;
+ u16 ctrl;
+
+ /* release GPHY Control reset */
+ sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR);
+
+ /* release GMAC reset */
+ sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR);
+
+ if (hw->flags & SKY2_HW_NEWER_PHY) {
+ /* select page 2 to access MAC control register */
+ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 2);
+
+ ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
+ /* allow GMII Power Down */
+ ctrl &= ~PHY_M_MAC_GMIF_PUP;
+ gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
+
+ /* set page register back to 0 */
+ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 0);
+ }
+
+ /* setup General Purpose Control Register */
+ gma_write16(hw, port, GM_GP_CTRL,
+ GM_GPCR_FL_PASS | GM_GPCR_SPEED_100 | GM_GPCR_AU_ALL_DIS);
+
+ if (hw->chip_id != CHIP_ID_YUKON_EC) {
+ if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
+ ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
+
+ /* enable Power Down */
+ ctrl |= PHY_M_PC_POW_D_ENA;
+ gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
+ }
+
+ /* set IEEE compatible Power Down Mode (dev. #4.99) */
+ gm_phy_write(hw, port, PHY_MARV_CTRL, PHY_CT_PDOWN);
+ }
+
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+ reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
+ reg1 |= phy_power[port]; /* set PHY to PowerDown/COMA Mode */
+ sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
}
/* Force a renegotiation */
@@ -675,8 +798,11 @@
sky2->advertising &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full);
sky2->flow_mode = FC_NONE;
- sky2_phy_power(hw, port, 1);
- sky2_phy_reinit(sky2);
+
+ spin_lock_bh(&sky2->phy_lock);
+ sky2_phy_power_up(hw, port);
+ sky2_phy_init(hw, port);
+ spin_unlock_bh(&sky2->phy_lock);
sky2->flow_mode = save_mode;
sky2->advertising = ctrl;
@@ -781,6 +907,7 @@
sky2_write8(hw, SK_REG(port, GMAC_IRQ_MSK), GMAC_DEF_MSK);
spin_lock_bh(&sky2->phy_lock);
+ sky2_phy_power_up(hw, port);
sky2_phy_init(hw, port);
spin_unlock_bh(&sky2->phy_lock);
@@ -1385,8 +1512,6 @@
if (!sky2->rx_ring)
goto err_out;
- sky2_phy_power(hw, port, 1);
-
sky2_mac_init(hw, port);
/* Register is number of 4K blocks on internal RAM buffer. */
@@ -1767,7 +1892,7 @@
sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET);
- sky2_phy_power(hw, port, 0);
+ sky2_phy_power_down(hw, port);
netif_carrier_off(dev);
@@ -2741,6 +2866,10 @@
hw->flags = SKY2_HW_GIGABIT
| SKY2_HW_NEWER_PHY
| SKY2_HW_ADV_POWER_CTL;
+
+ /* check for Rev. A1 dev 4200 */
+ if (sky2_read16(hw, Q_ADDR(Q_XA1, Q_WM)) == 0)
+ hw->flags |= SKY2_HW_CLK_POWER;
break;
case CHIP_ID_YUKON_EX:
@@ -2791,6 +2920,11 @@
if (hw->pmd_type == 'L' || hw->pmd_type == 'S' || hw->pmd_type == 'P')
hw->flags |= SKY2_HW_FIBRE_PHY;
+ hw->pm_cap = pci_find_capability(hw->pdev, PCI_CAP_ID_PM);
+ if (hw->pm_cap == 0) {
+ dev_err(&hw->pdev->dev, "cannot find PowerManagement capability\n");
+ return -EIO;
+ }
hw->ports = 1;
t8 = sky2_read8(hw, B2_Y2_HW_RES);
@@ -3378,7 +3512,7 @@
gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
} else
- gm_phy_write(hw, port, PHY_MARV_LED_OVER,
+ gm_phy_write(hw, port, PHY_MARV_LED_OVER,
PHY_M_LED_MO_DUP(mode) |
PHY_M_LED_MO_10(mode) |
PHY_M_LED_MO_100(mode) |
@@ -4362,7 +4496,7 @@
pci_save_state(pdev);
pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ sky2_power_state(hw, pci_choose_state(pdev, state));
return 0;
}
@@ -4375,9 +4509,7 @@
if (!hw)
return 0;
- err = pci_set_power_state(pdev, PCI_D0);
- if (err)
- goto out;
+ sky2_power_state(hw, PCI_D0);
err = pci_restore_state(pdev);
if (err)
@@ -4447,8 +4579,7 @@
pci_enable_wake(pdev, PCI_D3cold, wol);
pci_disable_device(pdev);
- pci_set_power_state(pdev, PCI_D3hot);
-
+ sky2_power_state(hw, PCI_D3hot);
}
static struct pci_driver sky2_driver = {
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index c0a5eea..1fa82bf 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -28,6 +28,11 @@
PCI_Y2_PHY2_POWD = 1<<27, /* Set PHY 2 to Power Down (YUKON-2) */
PCI_Y2_PHY1_POWD = 1<<26, /* Set PHY 1 to Power Down (YUKON-2) */
PCI_Y2_PME_LEGACY= 1<<15, /* PCI Express legacy power management mode */
+
+ PCI_PHY_LNK_TIM_MSK= 3L<<8,/* Bit 9.. 8: GPHY Link Trigger Timer */
+ PCI_ENA_L1_EVENT = 1<<7, /* Enable PEX L1 Event */
+ PCI_ENA_GPHY_LNK = 1<<6, /* Enable PEX L1 on GPHY Link down */
+ PCI_FORCE_PEX_L1 = 1<<5, /* Force to PEX L1 */
};
enum pci_dev_reg_2 {
@@ -45,7 +50,11 @@
/* PCI_OUR_REG_4 32 bit Our Register 4 (Yukon-ECU only) */
enum pci_dev_reg_4 {
- /* (Link Training & Status State Machine) */
+ /* (Link Training & Status State Machine) */
+ P_PEX_LTSSM_STAT_MSK = 0x7fL<<25, /* Bit 31..25: PEX LTSSM Mask */
+#define P_PEX_LTSSM_STAT(x) ((x << 25) & P_PEX_LTSSM_STAT_MSK)
+ P_PEX_LTSSM_L1_STAT = 0x34,
+ P_PEX_LTSSM_DET_STAT = 0x01,
P_TIMER_VALUE_MSK = 0xffL<<16, /* Bit 23..16: Timer Value Mask */
/* (Active State Power Management) */
P_FORCE_ASPM_REQUEST = 1<<15, /* Force ASPM Request (A1 only) */
@@ -454,6 +463,9 @@
CHIP_REV_YU_EX_A0 = 1,
CHIP_REV_YU_EX_B0 = 2,
};
+enum yukon_supr_rev {
+ CHIP_REV_YU_SU_A0 = 0,
+};
/* B2_Y2_CLK_GATE 8 bit Clock Gating (Yukon-2 only) */
@@ -1143,6 +1155,12 @@
PHY_M_PC_ENA_AUTO = 3, /* 11 = Enable Automatic Crossover */
};
+/* for Yukon-EC Ultra Gigabit Ethernet PHY (88E1149 only) */
+enum {
+ PHY_M_PC_COP_TX_DIS = 1<<3, /* Copper Transmitter Disable */
+ PHY_M_PC_POW_D_ENA = 1<<2, /* Power Down Enable */
+};
+
/* for 10/100 Fast Ethernet PHY (88E3082 only) */
enum {
PHY_M_PC_ENA_DTE_DT = 1<<15, /* Enable Data Terminal Equ. (DTE) Detect */
@@ -1411,6 +1429,7 @@
/***** PHY_MARV_PHY_CTRL (page 2) 16 bit r/w MAC Specific Ctrl *****/
enum {
PHY_M_MAC_MD_MSK = 7<<7, /* Bit 9.. 7: Mode Select Mask */
+ PHY_M_MAC_GMIF_PUP = 1<<3, /* GMII Power Up (88E1149 only) */
PHY_M_MAC_MD_AUTO = 3,/* Auto Copper/1000Base-X */
PHY_M_MAC_MD_COPPER = 5,/* Copper only */
PHY_M_MAC_MD_1000BX = 7,/* 1000Base-X only */
@@ -2052,7 +2071,9 @@
#define SKY2_HW_NEW_LE 0x00000020 /* new LSOv2 format */
#define SKY2_HW_AUTO_TX_SUM 0x00000040 /* new IP decode for Tx */
#define SKY2_HW_ADV_POWER_CTL 0x00000080 /* additional PHY power regs */
+#define SKY2_HW_CLK_POWER 0x00000100 /* clock power management */
+ int pm_cap;
u8 chip_id;
u8 chip_rev;
u8 pmd_type;
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index e2ee91a..c587162 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -106,55 +106,6 @@
*/
#define POWER_DOWN 1
-
-/* store this information for the driver.. */
-struct smc911x_local {
- /*
- * If I have to wait until the DMA is finished and ready to reload a
- * packet, I will store the skbuff here. Then, the DMA will send it
- * out and free it.
- */
- struct sk_buff *pending_tx_skb;
-
- /* version/revision of the SMC911x chip */
- u16 version;
- u16 revision;
-
- /* FIFO sizes */
- int tx_fifo_kb;
- int tx_fifo_size;
- int rx_fifo_size;
- int afc_cfg;
-
- /* Contains the current active receive/phy mode */
- int ctl_rfduplx;
- int ctl_rspeed;
-
- u32 msg_enable;
- u32 phy_type;
- struct mii_if_info mii;
-
- /* work queue */
- struct work_struct phy_configure;
-
- int tx_throttle;
- spinlock_t lock;
-
- struct net_device *netdev;
-
-#ifdef SMC_USE_DMA
- /* DMA needs the physical address of the chip */
- u_long physaddr;
- int rxdma;
- int txdma;
- int rxdma_active;
- int txdma_active;
- struct sk_buff *current_rx_skb;
- struct sk_buff *current_tx_skb;
- struct device *dev;
-#endif
-};
-
#if SMC_DEBUG > 0
#define DBG(n, args...) \
do { \
@@ -202,24 +153,24 @@
/* this enables an interrupt in the interrupt mask register */
-#define SMC_ENABLE_INT(x) do { \
+#define SMC_ENABLE_INT(lp, x) do { \
unsigned int __mask; \
unsigned long __flags; \
spin_lock_irqsave(&lp->lock, __flags); \
- __mask = SMC_GET_INT_EN(); \
+ __mask = SMC_GET_INT_EN((lp)); \
__mask |= (x); \
- SMC_SET_INT_EN(__mask); \
+ SMC_SET_INT_EN((lp), __mask); \
spin_unlock_irqrestore(&lp->lock, __flags); \
} while (0)
/* this disables an interrupt from the interrupt mask register */
-#define SMC_DISABLE_INT(x) do { \
+#define SMC_DISABLE_INT(lp, x) do { \
unsigned int __mask; \
unsigned long __flags; \
spin_lock_irqsave(&lp->lock, __flags); \
- __mask = SMC_GET_INT_EN(); \
+ __mask = SMC_GET_INT_EN((lp)); \
__mask &= ~(x); \
- SMC_SET_INT_EN(__mask); \
+ SMC_SET_INT_EN((lp), __mask); \
spin_unlock_irqrestore(&lp->lock, __flags); \
} while (0)
@@ -228,7 +179,6 @@
*/
static void smc911x_reset(struct net_device *dev)
{
- unsigned long ioaddr = dev->base_addr;
struct smc911x_local *lp = netdev_priv(dev);
unsigned int reg, timeout=0, resets=1;
unsigned long flags;
@@ -236,13 +186,13 @@
DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
/* Take out of PM setting first */
- if ((SMC_GET_PMT_CTRL() & PMT_CTRL_READY_) == 0) {
+ if ((SMC_GET_PMT_CTRL(lp) & PMT_CTRL_READY_) == 0) {
/* Write to the bytetest will take out of powerdown */
- SMC_SET_BYTE_TEST(0);
+ SMC_SET_BYTE_TEST(lp, 0);
timeout=10;
do {
udelay(10);
- reg = SMC_GET_PMT_CTRL() & PMT_CTRL_READY_;
+ reg = SMC_GET_PMT_CTRL(lp) & PMT_CTRL_READY_;
} while (--timeout && !reg);
if (timeout == 0) {
PRINTK("%s: smc911x_reset timeout waiting for PM restore\n", dev->name);
@@ -252,15 +202,15 @@
/* Disable all interrupts */
spin_lock_irqsave(&lp->lock, flags);
- SMC_SET_INT_EN(0);
+ SMC_SET_INT_EN(lp, 0);
spin_unlock_irqrestore(&lp->lock, flags);
while (resets--) {
- SMC_SET_HW_CFG(HW_CFG_SRST_);
+ SMC_SET_HW_CFG(lp, HW_CFG_SRST_);
timeout=10;
do {
udelay(10);
- reg = SMC_GET_HW_CFG();
+ reg = SMC_GET_HW_CFG(lp);
/* If chip indicates reset timeout then try again */
if (reg & HW_CFG_SRST_TO_) {
PRINTK("%s: chip reset timeout, retrying...\n", dev->name);
@@ -276,7 +226,7 @@
/* make sure EEPROM has finished loading before setting GPIO_CFG */
timeout=1000;
- while ( timeout-- && (SMC_GET_E2P_CMD() & E2P_CMD_EPC_BUSY_)) {
+ while ( timeout-- && (SMC_GET_E2P_CMD(lp) & E2P_CMD_EPC_BUSY_)) {
udelay(10);
}
if (timeout == 0){
@@ -285,24 +235,24 @@
}
/* Initialize interrupts */
- SMC_SET_INT_EN(0);
- SMC_ACK_INT(-1);
+ SMC_SET_INT_EN(lp, 0);
+ SMC_ACK_INT(lp, -1);
/* Reset the FIFO level and flow control settings */
- SMC_SET_HW_CFG((lp->tx_fifo_kb & 0xF) << 16);
+ SMC_SET_HW_CFG(lp, (lp->tx_fifo_kb & 0xF) << 16);
//TODO: Figure out what appropriate pause time is
- SMC_SET_FLOW(FLOW_FCPT_ | FLOW_FCEN_);
- SMC_SET_AFC_CFG(lp->afc_cfg);
+ SMC_SET_FLOW(lp, FLOW_FCPT_ | FLOW_FCEN_);
+ SMC_SET_AFC_CFG(lp, lp->afc_cfg);
/* Set to LED outputs */
- SMC_SET_GPIO_CFG(0x70070000);
+ SMC_SET_GPIO_CFG(lp, 0x70070000);
/*
* Deassert IRQ for 1*10us for edge type interrupts
* and drive IRQ pin push-pull
*/
- SMC_SET_IRQ_CFG( (1 << 24) | INT_CFG_IRQ_EN_ | INT_CFG_IRQ_TYPE_ );
+ SMC_SET_IRQ_CFG(lp, (1 << 24) | INT_CFG_IRQ_EN_ | INT_CFG_IRQ_TYPE_);
/* clear anything saved */
if (lp->pending_tx_skb != NULL) {
@@ -318,46 +268,45 @@
*/
static void smc911x_enable(struct net_device *dev)
{
- unsigned long ioaddr = dev->base_addr;
struct smc911x_local *lp = netdev_priv(dev);
unsigned mask, cfg, cr;
unsigned long flags;
DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
- SMC_SET_MAC_ADDR(dev->dev_addr);
+ SMC_SET_MAC_ADDR(lp, dev->dev_addr);
/* Enable TX */
- cfg = SMC_GET_HW_CFG();
+ cfg = SMC_GET_HW_CFG(lp);
cfg &= HW_CFG_TX_FIF_SZ_ | 0xFFF;
cfg |= HW_CFG_SF_;
- SMC_SET_HW_CFG(cfg);
- SMC_SET_FIFO_TDA(0xFF);
+ SMC_SET_HW_CFG(lp, cfg);
+ SMC_SET_FIFO_TDA(lp, 0xFF);
/* Update TX stats on every 64 packets received or every 1 sec */
- SMC_SET_FIFO_TSL(64);
- SMC_SET_GPT_CFG(GPT_CFG_TIMER_EN_ | 10000);
+ SMC_SET_FIFO_TSL(lp, 64);
+ SMC_SET_GPT_CFG(lp, GPT_CFG_TIMER_EN_ | 10000);
spin_lock_irqsave(&lp->lock, flags);
- SMC_GET_MAC_CR(cr);
+ SMC_GET_MAC_CR(lp, cr);
cr |= MAC_CR_TXEN_ | MAC_CR_HBDIS_;
- SMC_SET_MAC_CR(cr);
- SMC_SET_TX_CFG(TX_CFG_TX_ON_);
+ SMC_SET_MAC_CR(lp, cr);
+ SMC_SET_TX_CFG(lp, TX_CFG_TX_ON_);
spin_unlock_irqrestore(&lp->lock, flags);
/* Add 2 byte padding to start of packets */
- SMC_SET_RX_CFG((2<<8) & RX_CFG_RXDOFF_);
+ SMC_SET_RX_CFG(lp, (2<<8) & RX_CFG_RXDOFF_);
/* Turn on receiver and enable RX */
if (cr & MAC_CR_RXEN_)
DBG(SMC_DEBUG_RX, "%s: Receiver already enabled\n", dev->name);
spin_lock_irqsave(&lp->lock, flags);
- SMC_SET_MAC_CR( cr | MAC_CR_RXEN_ );
+ SMC_SET_MAC_CR(lp, cr | MAC_CR_RXEN_);
spin_unlock_irqrestore(&lp->lock, flags);
/* Interrupt on every received packet */
- SMC_SET_FIFO_RSA(0x01);
- SMC_SET_FIFO_RSL(0x00);
+ SMC_SET_FIFO_RSA(lp, 0x01);
+ SMC_SET_FIFO_RSL(lp, 0x00);
/* now, enable interrupts */
mask = INT_EN_TDFA_EN_ | INT_EN_TSFL_EN_ | INT_EN_RSFL_EN_ |
@@ -368,7 +317,7 @@
else {
mask|=INT_EN_RDFO_EN_;
}
- SMC_ENABLE_INT(mask);
+ SMC_ENABLE_INT(lp, mask);
}
/*
@@ -376,7 +325,6 @@
*/
static void smc911x_shutdown(struct net_device *dev)
{
- unsigned long ioaddr = dev->base_addr;
struct smc911x_local *lp = netdev_priv(dev);
unsigned cr;
unsigned long flags;
@@ -384,35 +332,35 @@
DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", CARDNAME, __FUNCTION__);
/* Disable IRQ's */
- SMC_SET_INT_EN(0);
+ SMC_SET_INT_EN(lp, 0);
/* Turn of Rx and TX */
spin_lock_irqsave(&lp->lock, flags);
- SMC_GET_MAC_CR(cr);
+ SMC_GET_MAC_CR(lp, cr);
cr &= ~(MAC_CR_TXEN_ | MAC_CR_RXEN_ | MAC_CR_HBDIS_);
- SMC_SET_MAC_CR(cr);
- SMC_SET_TX_CFG(TX_CFG_STOP_TX_);
+ SMC_SET_MAC_CR(lp, cr);
+ SMC_SET_TX_CFG(lp, TX_CFG_STOP_TX_);
spin_unlock_irqrestore(&lp->lock, flags);
}
static inline void smc911x_drop_pkt(struct net_device *dev)
{
- unsigned long ioaddr = dev->base_addr;
+ struct smc911x_local *lp = netdev_priv(dev);
unsigned int fifo_count, timeout, reg;
DBG(SMC_DEBUG_FUNC | SMC_DEBUG_RX, "%s: --> %s\n", CARDNAME, __FUNCTION__);
- fifo_count = SMC_GET_RX_FIFO_INF() & 0xFFFF;
+ fifo_count = SMC_GET_RX_FIFO_INF(lp) & 0xFFFF;
if (fifo_count <= 4) {
/* Manually dump the packet data */
while (fifo_count--)
- SMC_GET_RX_FIFO();
+ SMC_GET_RX_FIFO(lp);
} else {
/* Fast forward through the bad packet */
- SMC_SET_RX_DP_CTRL(RX_DP_CTRL_FFWD_BUSY_);
+ SMC_SET_RX_DP_CTRL(lp, RX_DP_CTRL_FFWD_BUSY_);
timeout=50;
do {
udelay(10);
- reg = SMC_GET_RX_DP_CTRL() & RX_DP_CTRL_FFWD_BUSY_;
+ reg = SMC_GET_RX_DP_CTRL(lp) & RX_DP_CTRL_FFWD_BUSY_;
} while (--timeout && reg);
if (timeout == 0) {
PRINTK("%s: timeout waiting for RX fast forward\n", dev->name);
@@ -428,14 +376,14 @@
*/
static inline void smc911x_rcv(struct net_device *dev)
{
- unsigned long ioaddr = dev->base_addr;
+ struct smc911x_local *lp = netdev_priv(dev);
unsigned int pkt_len, status;
struct sk_buff *skb;
unsigned char *data;
DBG(SMC_DEBUG_FUNC | SMC_DEBUG_RX, "%s: --> %s\n",
dev->name, __FUNCTION__);
- status = SMC_GET_RX_STS_FIFO();
+ status = SMC_GET_RX_STS_FIFO(lp);
DBG(SMC_DEBUG_RX, "%s: Rx pkt len %d status 0x%08x \n",
dev->name, (status & 0x3fff0000) >> 16, status & 0xc000ffff);
pkt_len = (status & RX_STS_PKT_LEN_) >> 16;
@@ -472,24 +420,23 @@
skb_put(skb,pkt_len-4);
#ifdef SMC_USE_DMA
{
- struct smc911x_local *lp = netdev_priv(dev);
unsigned int fifo;
/* Lower the FIFO threshold if possible */
- fifo = SMC_GET_FIFO_INT();
+ fifo = SMC_GET_FIFO_INT(lp);
if (fifo & 0xFF) fifo--;
DBG(SMC_DEBUG_RX, "%s: Setting RX stat FIFO threshold to %d\n",
dev->name, fifo & 0xff);
- SMC_SET_FIFO_INT(fifo);
+ SMC_SET_FIFO_INT(lp, fifo);
/* Setup RX DMA */
- SMC_SET_RX_CFG(RX_CFG_RX_END_ALGN16_ | ((2<<8) & RX_CFG_RXDOFF_));
+ SMC_SET_RX_CFG(lp, RX_CFG_RX_END_ALGN16_ | ((2<<8) & RX_CFG_RXDOFF_));
lp->rxdma_active = 1;
lp->current_rx_skb = skb;
- SMC_PULL_DATA(data, (pkt_len+2+15) & ~15);
+ SMC_PULL_DATA(lp, data, (pkt_len+2+15) & ~15);
/* Packet processing deferred to DMA RX interrupt */
}
#else
- SMC_SET_RX_CFG(RX_CFG_RX_END_ALGN4_ | ((2<<8) & RX_CFG_RXDOFF_));
- SMC_PULL_DATA(data, pkt_len+2+3);
+ SMC_SET_RX_CFG(lp, RX_CFG_RX_END_ALGN4_ | ((2<<8) & RX_CFG_RXDOFF_));
+ SMC_PULL_DATA(lp, data, pkt_len+2+3);
DBG(SMC_DEBUG_PKTS, "%s: Received packet\n", dev->name);
PRINT_PKT(data, ((pkt_len - 4) <= 64) ? pkt_len - 4 : 64);
@@ -508,7 +455,6 @@
static void smc911x_hardware_send_pkt(struct net_device *dev)
{
struct smc911x_local *lp = netdev_priv(dev);
- unsigned long ioaddr = dev->base_addr;
struct sk_buff *skb;
unsigned int cmdA, cmdB, len;
unsigned char *buf;
@@ -541,8 +487,8 @@
DBG(SMC_DEBUG_TX, "%s: TX PKT LENGTH 0x%04x (%d) BUF 0x%p CMDA 0x%08x CMDB 0x%08x\n",
dev->name, len, len, buf, cmdA, cmdB);
- SMC_SET_TX_FIFO(cmdA);
- SMC_SET_TX_FIFO(cmdB);
+ SMC_SET_TX_FIFO(lp, cmdA);
+ SMC_SET_TX_FIFO(lp, cmdB);
DBG(SMC_DEBUG_PKTS, "%s: Transmitted packet\n", dev->name);
PRINT_PKT(buf, len <= 64 ? len : 64);
@@ -550,10 +496,10 @@
/* Send pkt via PIO or DMA */
#ifdef SMC_USE_DMA
lp->current_tx_skb = skb;
- SMC_PUSH_DATA(buf, len);
+ SMC_PUSH_DATA(lp, buf, len);
/* DMA complete IRQ will free buffer and set jiffies */
#else
- SMC_PUSH_DATA(buf, len);
+ SMC_PUSH_DATA(lp, buf, len);
dev->trans_start = jiffies;
dev_kfree_skb(skb);
#endif
@@ -562,7 +508,7 @@
netif_wake_queue(dev);
}
spin_unlock_irqrestore(&lp->lock, flags);
- SMC_ENABLE_INT(INT_EN_TDFA_EN_ | INT_EN_TSFL_EN_);
+ SMC_ENABLE_INT(lp, INT_EN_TDFA_EN_ | INT_EN_TSFL_EN_);
}
/*
@@ -574,7 +520,6 @@
static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct smc911x_local *lp = netdev_priv(dev);
- unsigned long ioaddr = dev->base_addr;
unsigned int free;
unsigned long flags;
@@ -583,7 +528,7 @@
BUG_ON(lp->pending_tx_skb != NULL);
- free = SMC_GET_TX_FIFO_INF() & TX_FIFO_INF_TDFREE_;
+ free = SMC_GET_TX_FIFO_INF(lp) & TX_FIFO_INF_TDFREE_;
DBG(SMC_DEBUG_TX, "%s: TX free space %d\n", dev->name, free);
/* Turn off the flow when running out of space in FIFO */
@@ -592,7 +537,7 @@
dev->name, free);
spin_lock_irqsave(&lp->lock, flags);
/* Reenable when at least 1 packet of size MTU present */
- SMC_SET_FIFO_TDA((SMC911X_TX_FIFO_LOW_THRESHOLD)/64);
+ SMC_SET_FIFO_TDA(lp, (SMC911X_TX_FIFO_LOW_THRESHOLD)/64);
lp->tx_throttle = 1;
netif_stop_queue(dev);
spin_unlock_irqrestore(&lp->lock, flags);
@@ -647,7 +592,6 @@
*/
static void smc911x_tx(struct net_device *dev)
{
- unsigned long ioaddr = dev->base_addr;
struct smc911x_local *lp = netdev_priv(dev);
unsigned int tx_status;
@@ -655,11 +599,11 @@
dev->name, __FUNCTION__);
/* Collect the TX status */
- while (((SMC_GET_TX_FIFO_INF() & TX_FIFO_INF_TSUSED_) >> 16) != 0) {
+ while (((SMC_GET_TX_FIFO_INF(lp) & TX_FIFO_INF_TSUSED_) >> 16) != 0) {
DBG(SMC_DEBUG_TX, "%s: Tx stat FIFO used 0x%04x\n",
dev->name,
- (SMC_GET_TX_FIFO_INF() & TX_FIFO_INF_TSUSED_) >> 16);
- tx_status = SMC_GET_TX_STS_FIFO();
+ (SMC_GET_TX_FIFO_INF(lp) & TX_FIFO_INF_TSUSED_) >> 16);
+ tx_status = SMC_GET_TX_STS_FIFO(lp);
dev->stats.tx_packets++;
dev->stats.tx_bytes+=tx_status>>16;
DBG(SMC_DEBUG_TX, "%s: Tx FIFO tag 0x%04x status 0x%04x\n",
@@ -697,10 +641,10 @@
static int smc911x_phy_read(struct net_device *dev, int phyaddr, int phyreg)
{
- unsigned long ioaddr = dev->base_addr;
+ struct smc911x_local *lp = netdev_priv(dev);
unsigned int phydata;
- SMC_GET_MII(phyreg, phyaddr, phydata);
+ SMC_GET_MII(lp, phyreg, phyaddr, phydata);
DBG(SMC_DEBUG_MISC, "%s: phyaddr=0x%x, phyreg=0x%02x, phydata=0x%04x\n",
__FUNCTION__, phyaddr, phyreg, phydata);
@@ -714,12 +658,12 @@
static void smc911x_phy_write(struct net_device *dev, int phyaddr, int phyreg,
int phydata)
{
- unsigned long ioaddr = dev->base_addr;
+ struct smc911x_local *lp = netdev_priv(dev);
DBG(SMC_DEBUG_MISC, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n",
__FUNCTION__, phyaddr, phyreg, phydata);
- SMC_SET_MII(phyreg, phyaddr, phydata);
+ SMC_SET_MII(lp, phyreg, phyaddr, phydata);
}
/*
@@ -728,7 +672,6 @@
*/
static void smc911x_phy_detect(struct net_device *dev)
{
- unsigned long ioaddr = dev->base_addr;
struct smc911x_local *lp = netdev_priv(dev);
int phyaddr;
unsigned int cfg, id1, id2;
@@ -744,30 +687,30 @@
switch(lp->version) {
case 0x115:
case 0x117:
- cfg = SMC_GET_HW_CFG();
+ cfg = SMC_GET_HW_CFG(lp);
if (cfg & HW_CFG_EXT_PHY_DET_) {
cfg &= ~HW_CFG_PHY_CLK_SEL_;
cfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_;
- SMC_SET_HW_CFG(cfg);
+ SMC_SET_HW_CFG(lp, cfg);
udelay(10); /* Wait for clocks to stop */
cfg |= HW_CFG_EXT_PHY_EN_;
- SMC_SET_HW_CFG(cfg);
+ SMC_SET_HW_CFG(lp, cfg);
udelay(10); /* Wait for clocks to stop */
cfg &= ~HW_CFG_PHY_CLK_SEL_;
cfg |= HW_CFG_PHY_CLK_SEL_EXT_PHY_;
- SMC_SET_HW_CFG(cfg);
+ SMC_SET_HW_CFG(lp, cfg);
udelay(10); /* Wait for clocks to stop */
cfg |= HW_CFG_SMI_SEL_;
- SMC_SET_HW_CFG(cfg);
+ SMC_SET_HW_CFG(lp, cfg);
for (phyaddr = 1; phyaddr < 32; ++phyaddr) {
/* Read the PHY identifiers */
- SMC_GET_PHY_ID1(phyaddr & 31, id1);
- SMC_GET_PHY_ID2(phyaddr & 31, id2);
+ SMC_GET_PHY_ID1(lp, phyaddr & 31, id1);
+ SMC_GET_PHY_ID2(lp, phyaddr & 31, id2);
/* Make sure it is a valid identifier */
if (id1 != 0x0000 && id1 != 0xffff &&
@@ -782,8 +725,8 @@
}
default:
/* Internal media only */
- SMC_GET_PHY_ID1(1, id1);
- SMC_GET_PHY_ID2(1, id2);
+ SMC_GET_PHY_ID1(lp, 1, id1);
+ SMC_GET_PHY_ID2(lp, 1, id2);
/* Save the PHY's address */
lp->mii.phy_id = 1;
lp->phy_type = id1 << 16 | id2;
@@ -800,16 +743,15 @@
static int smc911x_phy_fixed(struct net_device *dev)
{
struct smc911x_local *lp = netdev_priv(dev);
- unsigned long ioaddr = dev->base_addr;
int phyaddr = lp->mii.phy_id;
int bmcr;
DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
/* Enter Link Disable state */
- SMC_GET_PHY_BMCR(phyaddr, bmcr);
+ SMC_GET_PHY_BMCR(lp, phyaddr, bmcr);
bmcr |= BMCR_PDOWN;
- SMC_SET_PHY_BMCR(phyaddr, bmcr);
+ SMC_SET_PHY_BMCR(lp, phyaddr, bmcr);
/*
* Set our fixed capabilities
@@ -823,11 +765,11 @@
bmcr |= BMCR_SPEED100;
/* Write our capabilities to the phy control register */
- SMC_SET_PHY_BMCR(phyaddr, bmcr);
+ SMC_SET_PHY_BMCR(lp, phyaddr, bmcr);
/* Re-Configure the Receive/Phy Control register */
bmcr &= ~BMCR_PDOWN;
- SMC_SET_PHY_BMCR(phyaddr, bmcr);
+ SMC_SET_PHY_BMCR(lp, phyaddr, bmcr);
return 1;
}
@@ -847,7 +789,6 @@
static int smc911x_phy_reset(struct net_device *dev, int phy)
{
struct smc911x_local *lp = netdev_priv(dev);
- unsigned long ioaddr = dev->base_addr;
int timeout;
unsigned long flags;
unsigned int reg;
@@ -855,15 +796,15 @@
DBG(SMC_DEBUG_FUNC, "%s: --> %s()\n", dev->name, __FUNCTION__);
spin_lock_irqsave(&lp->lock, flags);
- reg = SMC_GET_PMT_CTRL();
+ reg = SMC_GET_PMT_CTRL(lp);
reg &= ~0xfffff030;
reg |= PMT_CTRL_PHY_RST_;
- SMC_SET_PMT_CTRL(reg);
+ SMC_SET_PMT_CTRL(lp, reg);
spin_unlock_irqrestore(&lp->lock, flags);
for (timeout = 2; timeout; timeout--) {
msleep(50);
spin_lock_irqsave(&lp->lock, flags);
- reg = SMC_GET_PMT_CTRL();
+ reg = SMC_GET_PMT_CTRL(lp);
spin_unlock_irqrestore(&lp->lock, flags);
if (!(reg & PMT_CTRL_PHY_RST_)) {
/* extra delay required because the phy may
@@ -888,13 +829,13 @@
*/
static void smc911x_phy_powerdown(struct net_device *dev, int phy)
{
- unsigned long ioaddr = dev->base_addr;
+ struct smc911x_local *lp = netdev_priv(dev);
unsigned int bmcr;
/* Enter Link Disable state */
- SMC_GET_PHY_BMCR(phy, bmcr);
+ SMC_GET_PHY_BMCR(lp, phy, bmcr);
bmcr |= BMCR_PDOWN;
- SMC_SET_PHY_BMCR(phy, bmcr);
+ SMC_SET_PHY_BMCR(lp, phy, bmcr);
}
/*
@@ -908,7 +849,6 @@
static void smc911x_phy_check_media(struct net_device *dev, int init)
{
struct smc911x_local *lp = netdev_priv(dev);
- unsigned long ioaddr = dev->base_addr;
int phyaddr = lp->mii.phy_id;
unsigned int bmcr, cr;
@@ -916,8 +856,8 @@
if (mii_check_media(&lp->mii, netif_msg_link(lp), init)) {
/* duplex state has changed */
- SMC_GET_PHY_BMCR(phyaddr, bmcr);
- SMC_GET_MAC_CR(cr);
+ SMC_GET_PHY_BMCR(lp, phyaddr, bmcr);
+ SMC_GET_MAC_CR(lp, cr);
if (lp->mii.full_duplex) {
DBG(SMC_DEBUG_MISC, "%s: Configuring for full-duplex mode\n", dev->name);
bmcr |= BMCR_FULLDPLX;
@@ -927,8 +867,8 @@
bmcr &= ~BMCR_FULLDPLX;
cr &= ~MAC_CR_RCVOWN_;
}
- SMC_SET_PHY_BMCR(phyaddr, bmcr);
- SMC_SET_MAC_CR(cr);
+ SMC_SET_PHY_BMCR(lp, phyaddr, bmcr);
+ SMC_SET_MAC_CR(lp, cr);
}
}
@@ -946,7 +886,6 @@
struct smc911x_local *lp = container_of(work, struct smc911x_local,
phy_configure);
struct net_device *dev = lp->netdev;
- unsigned long ioaddr = dev->base_addr;
int phyaddr = lp->mii.phy_id;
int my_phy_caps; /* My PHY capabilities */
int my_ad_caps; /* My Advertised capabilities */
@@ -971,7 +910,7 @@
* Enable PHY Interrupts (for register 18)
* Interrupts listed here are enabled
*/
- SMC_SET_PHY_INT_MASK(phyaddr, PHY_INT_MASK_ENERGY_ON_ |
+ SMC_SET_PHY_INT_MASK(lp, phyaddr, PHY_INT_MASK_ENERGY_ON_ |
PHY_INT_MASK_ANEG_COMP_ | PHY_INT_MASK_REMOTE_FAULT_ |
PHY_INT_MASK_LINK_DOWN_);
@@ -982,7 +921,7 @@
}
/* Copy our capabilities from MII_BMSR to MII_ADVERTISE */
- SMC_GET_PHY_BMSR(phyaddr, my_phy_caps);
+ SMC_GET_PHY_BMSR(lp, phyaddr, my_phy_caps);
if (!(my_phy_caps & BMSR_ANEGCAPABLE)) {
printk(KERN_INFO "Auto negotiation NOT supported\n");
smc911x_phy_fixed(dev);
@@ -1011,7 +950,7 @@
my_ad_caps &= ~(ADVERTISE_100FULL|ADVERTISE_10FULL);
/* Update our Auto-Neg Advertisement Register */
- SMC_SET_PHY_MII_ADV(phyaddr, my_ad_caps);
+ SMC_SET_PHY_MII_ADV(lp, phyaddr, my_ad_caps);
lp->mii.advertising = my_ad_caps;
/*
@@ -1020,13 +959,13 @@
* the link does not come up.
*/
udelay(10);
- SMC_GET_PHY_MII_ADV(phyaddr, status);
+ SMC_GET_PHY_MII_ADV(lp, phyaddr, status);
DBG(SMC_DEBUG_MISC, "%s: phy caps=0x%04x\n", dev->name, my_phy_caps);
DBG(SMC_DEBUG_MISC, "%s: phy advertised caps=0x%04x\n", dev->name, my_ad_caps);
/* Restart auto-negotiation process in order to advertise my caps */
- SMC_SET_PHY_BMCR(phyaddr, BMCR_ANENABLE | BMCR_ANRESTART);
+ SMC_SET_PHY_BMCR(lp, phyaddr, BMCR_ANENABLE | BMCR_ANRESTART);
smc911x_phy_check_media(dev, 1);
@@ -1043,7 +982,6 @@
static void smc911x_phy_interrupt(struct net_device *dev)
{
struct smc911x_local *lp = netdev_priv(dev);
- unsigned long ioaddr = dev->base_addr;
int phyaddr = lp->mii.phy_id;
int status;
@@ -1054,11 +992,11 @@
smc911x_phy_check_media(dev, 0);
/* read to clear status bits */
- SMC_GET_PHY_INT_SRC(phyaddr,status);
+ SMC_GET_PHY_INT_SRC(lp, phyaddr,status);
DBG(SMC_DEBUG_MISC, "%s: PHY interrupt status 0x%04x\n",
dev->name, status & 0xffff);
DBG(SMC_DEBUG_MISC, "%s: AFC_CFG 0x%08x\n",
- dev->name, SMC_GET_AFC_CFG());
+ dev->name, SMC_GET_AFC_CFG(lp));
}
/*--- END PHY CONTROL AND CONFIGURATION-------------------------------------*/
@@ -1070,7 +1008,6 @@
static irqreturn_t smc911x_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
- unsigned long ioaddr = dev->base_addr;
struct smc911x_local *lp = netdev_priv(dev);
unsigned int status, mask, timeout;
unsigned int rx_overrun=0, cr, pkts;
@@ -1081,21 +1018,21 @@
spin_lock_irqsave(&lp->lock, flags);
/* Spurious interrupt check */
- if ((SMC_GET_IRQ_CFG() & (INT_CFG_IRQ_INT_ | INT_CFG_IRQ_EN_)) !=
+ if ((SMC_GET_IRQ_CFG(lp) & (INT_CFG_IRQ_INT_ | INT_CFG_IRQ_EN_)) !=
(INT_CFG_IRQ_INT_ | INT_CFG_IRQ_EN_)) {
spin_unlock_irqrestore(&lp->lock, flags);
return IRQ_NONE;
}
- mask = SMC_GET_INT_EN();
- SMC_SET_INT_EN(0);
+ mask = SMC_GET_INT_EN(lp);
+ SMC_SET_INT_EN(lp, 0);
/* set a timeout value, so I don't stay here forever */
timeout = 8;
do {
- status = SMC_GET_INT();
+ status = SMC_GET_INT(lp);
DBG(SMC_DEBUG_MISC, "%s: INT 0x%08x MASK 0x%08x OUTSIDE MASK 0x%08x\n",
dev->name, status, mask, status & ~mask);
@@ -1106,53 +1043,53 @@
/* Handle SW interrupt condition */
if (status & INT_STS_SW_INT_) {
- SMC_ACK_INT(INT_STS_SW_INT_);
+ SMC_ACK_INT(lp, INT_STS_SW_INT_);
mask &= ~INT_EN_SW_INT_EN_;
}
/* Handle various error conditions */
if (status & INT_STS_RXE_) {
- SMC_ACK_INT(INT_STS_RXE_);
+ SMC_ACK_INT(lp, INT_STS_RXE_);
dev->stats.rx_errors++;
}
if (status & INT_STS_RXDFH_INT_) {
- SMC_ACK_INT(INT_STS_RXDFH_INT_);
- dev->stats.rx_dropped+=SMC_GET_RX_DROP();
+ SMC_ACK_INT(lp, INT_STS_RXDFH_INT_);
+ dev->stats.rx_dropped+=SMC_GET_RX_DROP(lp);
}
/* Undocumented interrupt-what is the right thing to do here? */
if (status & INT_STS_RXDF_INT_) {
- SMC_ACK_INT(INT_STS_RXDF_INT_);
+ SMC_ACK_INT(lp, INT_STS_RXDF_INT_);
}
/* Rx Data FIFO exceeds set level */
if (status & INT_STS_RDFL_) {
if (IS_REV_A(lp->revision)) {
rx_overrun=1;
- SMC_GET_MAC_CR(cr);
+ SMC_GET_MAC_CR(lp, cr);
cr &= ~MAC_CR_RXEN_;
- SMC_SET_MAC_CR(cr);
+ SMC_SET_MAC_CR(lp, cr);
DBG(SMC_DEBUG_RX, "%s: RX overrun\n", dev->name);
dev->stats.rx_errors++;
dev->stats.rx_fifo_errors++;
}
- SMC_ACK_INT(INT_STS_RDFL_);
+ SMC_ACK_INT(lp, INT_STS_RDFL_);
}
if (status & INT_STS_RDFO_) {
if (!IS_REV_A(lp->revision)) {
- SMC_GET_MAC_CR(cr);
+ SMC_GET_MAC_CR(lp, cr);
cr &= ~MAC_CR_RXEN_;
- SMC_SET_MAC_CR(cr);
+ SMC_SET_MAC_CR(lp, cr);
rx_overrun=1;
DBG(SMC_DEBUG_RX, "%s: RX overrun\n", dev->name);
dev->stats.rx_errors++;
dev->stats.rx_fifo_errors++;
}
- SMC_ACK_INT(INT_STS_RDFO_);
+ SMC_ACK_INT(lp, INT_STS_RDFO_);
}
/* Handle receive condition */
if ((status & INT_STS_RSFL_) || rx_overrun) {
unsigned int fifo;
DBG(SMC_DEBUG_RX, "%s: RX irq\n", dev->name);
- fifo = SMC_GET_RX_FIFO_INF();
+ fifo = SMC_GET_RX_FIFO_INF(lp);
pkts = (fifo & RX_FIFO_INF_RXSUSED_) >> 16;
DBG(SMC_DEBUG_RX, "%s: Rx FIFO pkts %d, bytes %d\n",
dev->name, pkts, fifo & 0xFFFF );
@@ -1163,61 +1100,61 @@
DBG(SMC_DEBUG_RX | SMC_DEBUG_DMA,
"%s: RX DMA active\n", dev->name);
/* The DMA is already running so up the IRQ threshold */
- fifo = SMC_GET_FIFO_INT() & ~0xFF;
+ fifo = SMC_GET_FIFO_INT(lp) & ~0xFF;
fifo |= pkts & 0xFF;
DBG(SMC_DEBUG_RX,
"%s: Setting RX stat FIFO threshold to %d\n",
dev->name, fifo & 0xff);
- SMC_SET_FIFO_INT(fifo);
+ SMC_SET_FIFO_INT(lp, fifo);
} else
#endif
smc911x_rcv(dev);
}
- SMC_ACK_INT(INT_STS_RSFL_);
+ SMC_ACK_INT(lp, INT_STS_RSFL_);
}
/* Handle transmit FIFO available */
if (status & INT_STS_TDFA_) {
DBG(SMC_DEBUG_TX, "%s: TX data FIFO space available irq\n", dev->name);
- SMC_SET_FIFO_TDA(0xFF);
+ SMC_SET_FIFO_TDA(lp, 0xFF);
lp->tx_throttle = 0;
#ifdef SMC_USE_DMA
if (!lp->txdma_active)
#endif
netif_wake_queue(dev);
- SMC_ACK_INT(INT_STS_TDFA_);
+ SMC_ACK_INT(lp, INT_STS_TDFA_);
}
/* Handle transmit done condition */
#if 1
if (status & (INT_STS_TSFL_ | INT_STS_GPT_INT_)) {
DBG(SMC_DEBUG_TX | SMC_DEBUG_MISC,
"%s: Tx stat FIFO limit (%d) /GPT irq\n",
- dev->name, (SMC_GET_FIFO_INT() & 0x00ff0000) >> 16);
+ dev->name, (SMC_GET_FIFO_INT(lp) & 0x00ff0000) >> 16);
smc911x_tx(dev);
- SMC_SET_GPT_CFG(GPT_CFG_TIMER_EN_ | 10000);
- SMC_ACK_INT(INT_STS_TSFL_);
- SMC_ACK_INT(INT_STS_TSFL_ | INT_STS_GPT_INT_);
+ SMC_SET_GPT_CFG(lp, GPT_CFG_TIMER_EN_ | 10000);
+ SMC_ACK_INT(lp, INT_STS_TSFL_);
+ SMC_ACK_INT(lp, INT_STS_TSFL_ | INT_STS_GPT_INT_);
}
#else
if (status & INT_STS_TSFL_) {
DBG(SMC_DEBUG_TX, "%s: TX status FIFO limit (%d) irq \n", dev->name, );
smc911x_tx(dev);
- SMC_ACK_INT(INT_STS_TSFL_);
+ SMC_ACK_INT(lp, INT_STS_TSFL_);
}
if (status & INT_STS_GPT_INT_) {
DBG(SMC_DEBUG_RX, "%s: IRQ_CFG 0x%08x FIFO_INT 0x%08x RX_CFG 0x%08x\n",
dev->name,
- SMC_GET_IRQ_CFG(),
- SMC_GET_FIFO_INT(),
- SMC_GET_RX_CFG());
+ SMC_GET_IRQ_CFG(lp),
+ SMC_GET_FIFO_INT(lp),
+ SMC_GET_RX_CFG(lp));
DBG(SMC_DEBUG_RX, "%s: Rx Stat FIFO Used 0x%02x "
"Data FIFO Used 0x%04x Stat FIFO 0x%08x\n",
dev->name,
- (SMC_GET_RX_FIFO_INF() & 0x00ff0000) >> 16,
- SMC_GET_RX_FIFO_INF() & 0xffff,
- SMC_GET_RX_STS_FIFO_PEEK());
- SMC_SET_GPT_CFG(GPT_CFG_TIMER_EN_ | 10000);
- SMC_ACK_INT(INT_STS_GPT_INT_);
+ (SMC_GET_RX_FIFO_INF(lp) & 0x00ff0000) >> 16,
+ SMC_GET_RX_FIFO_INF(lp) & 0xffff,
+ SMC_GET_RX_STS_FIFO_PEEK(lp));
+ SMC_SET_GPT_CFG(lp, GPT_CFG_TIMER_EN_ | 10000);
+ SMC_ACK_INT(lp, INT_STS_GPT_INT_);
}
#endif
@@ -1225,12 +1162,12 @@
if (status & INT_STS_PHY_INT_) {
DBG(SMC_DEBUG_MISC, "%s: PHY irq\n", dev->name);
smc911x_phy_interrupt(dev);
- SMC_ACK_INT(INT_STS_PHY_INT_);
+ SMC_ACK_INT(lp, INT_STS_PHY_INT_);
}
} while (--timeout);
/* restore mask state */
- SMC_SET_INT_EN(mask);
+ SMC_SET_INT_EN(lp, mask);
DBG(SMC_DEBUG_MISC, "%s: Interrupt done (%d loops)\n",
dev->name, 8-timeout);
@@ -1332,22 +1269,21 @@
static void smc911x_timeout(struct net_device *dev)
{
struct smc911x_local *lp = netdev_priv(dev);
- unsigned long ioaddr = dev->base_addr;
int status, mask;
unsigned long flags;
DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
spin_lock_irqsave(&lp->lock, flags);
- status = SMC_GET_INT();
- mask = SMC_GET_INT_EN();
+ status = SMC_GET_INT(lp);
+ mask = SMC_GET_INT_EN(lp);
spin_unlock_irqrestore(&lp->lock, flags);
DBG(SMC_DEBUG_MISC, "%s: INT 0x%02x MASK 0x%02x \n",
dev->name, status, mask);
/* Dump the current TX FIFO contents and restart */
- mask = SMC_GET_TX_CFG();
- SMC_SET_TX_CFG(mask | TX_CFG_TXS_DUMP_ | TX_CFG_TXD_DUMP_);
+ mask = SMC_GET_TX_CFG(lp);
+ SMC_SET_TX_CFG(lp, mask | TX_CFG_TXS_DUMP_ | TX_CFG_TXD_DUMP_);
/*
* Reconfiguring the PHY doesn't seem like a bad idea here, but
* smc911x_phy_configure() calls msleep() which calls schedule_timeout()
@@ -1370,7 +1306,6 @@
static void smc911x_set_multicast_list(struct net_device *dev)
{
struct smc911x_local *lp = netdev_priv(dev);
- unsigned long ioaddr = dev->base_addr;
unsigned int multicast_table[2];
unsigned int mcr, update_multicast = 0;
unsigned long flags;
@@ -1378,7 +1313,7 @@
DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
spin_lock_irqsave(&lp->lock, flags);
- SMC_GET_MAC_CR(mcr);
+ SMC_GET_MAC_CR(lp, mcr);
spin_unlock_irqrestore(&lp->lock, flags);
if (dev->flags & IFF_PROMISC) {
@@ -1455,13 +1390,13 @@
}
spin_lock_irqsave(&lp->lock, flags);
- SMC_SET_MAC_CR(mcr);
+ SMC_SET_MAC_CR(lp, mcr);
if (update_multicast) {
DBG(SMC_DEBUG_MISC,
"%s: update mcast hash table 0x%08x 0x%08x\n",
dev->name, multicast_table[0], multicast_table[1]);
- SMC_SET_HASHL(multicast_table[0]);
- SMC_SET_HASHH(multicast_table[1]);
+ SMC_SET_HASHL(lp, multicast_table[0]);
+ SMC_SET_HASHH(lp, multicast_table[1]);
}
spin_unlock_irqrestore(&lp->lock, flags);
}
@@ -1545,7 +1480,6 @@
smc911x_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct smc911x_local *lp = netdev_priv(dev);
- unsigned long ioaddr = dev->base_addr;
int ret, status;
unsigned long flags;
@@ -1573,7 +1507,7 @@
else
cmd->transceiver = XCVR_EXTERNAL;
cmd->port = 0;
- SMC_GET_PHY_SPECIAL(lp->mii.phy_id, status);
+ SMC_GET_PHY_SPECIAL(lp, lp->mii.phy_id, status);
cmd->duplex =
(status & (PHY_SPECIAL_SPD_10FULL_ | PHY_SPECIAL_SPD_100FULL_)) ?
DUPLEX_FULL : DUPLEX_HALF;
@@ -1654,7 +1588,6 @@
static void smc911x_ethtool_getregs(struct net_device *dev,
struct ethtool_regs* regs, void *buf)
{
- unsigned long ioaddr = dev->base_addr;
struct smc911x_local *lp = netdev_priv(dev);
unsigned long flags;
u32 reg,i,j=0;
@@ -1662,17 +1595,17 @@
regs->version = lp->version;
for(i=ID_REV;i<=E2P_CMD;i+=4) {
- data[j++] = SMC_inl(ioaddr,i);
+ data[j++] = SMC_inl(lp, i);
}
for(i=MAC_CR;i<=WUCSR;i++) {
spin_lock_irqsave(&lp->lock, flags);
- SMC_GET_MAC_CSR(i, reg);
+ SMC_GET_MAC_CSR(lp, i, reg);
spin_unlock_irqrestore(&lp->lock, flags);
data[j++] = reg;
}
for(i=0;i<=31;i++) {
spin_lock_irqsave(&lp->lock, flags);
- SMC_GET_MII(i, lp->mii.phy_id, reg);
+ SMC_GET_MII(lp, i, lp->mii.phy_id, reg);
spin_unlock_irqrestore(&lp->lock, flags);
data[j++] = reg & 0xFFFF;
}
@@ -1680,11 +1613,11 @@
static int smc911x_ethtool_wait_eeprom_ready(struct net_device *dev)
{
- unsigned long ioaddr = dev->base_addr;
+ struct smc911x_local *lp = netdev_priv(dev);
unsigned int timeout;
int e2p_cmd;
- e2p_cmd = SMC_GET_E2P_CMD();
+ e2p_cmd = SMC_GET_E2P_CMD(lp);
for(timeout=10;(e2p_cmd & E2P_CMD_EPC_BUSY_) && timeout; timeout--) {
if (e2p_cmd & E2P_CMD_EPC_TIMEOUT_) {
PRINTK("%s: %s timeout waiting for EEPROM to respond\n",
@@ -1692,7 +1625,7 @@
return -EFAULT;
}
mdelay(1);
- e2p_cmd = SMC_GET_E2P_CMD();
+ e2p_cmd = SMC_GET_E2P_CMD(lp);
}
if (timeout == 0) {
PRINTK("%s: %s timeout waiting for EEPROM CMD not busy\n",
@@ -1705,12 +1638,12 @@
static inline int smc911x_ethtool_write_eeprom_cmd(struct net_device *dev,
int cmd, int addr)
{
- unsigned long ioaddr = dev->base_addr;
+ struct smc911x_local *lp = netdev_priv(dev);
int ret;
if ((ret = smc911x_ethtool_wait_eeprom_ready(dev))!=0)
return ret;
- SMC_SET_E2P_CMD(E2P_CMD_EPC_BUSY_ |
+ SMC_SET_E2P_CMD(lp, E2P_CMD_EPC_BUSY_ |
((cmd) & (0x7<<28)) |
((addr) & 0xFF));
return 0;
@@ -1719,24 +1652,24 @@
static inline int smc911x_ethtool_read_eeprom_byte(struct net_device *dev,
u8 *data)
{
- unsigned long ioaddr = dev->base_addr;
+ struct smc911x_local *lp = netdev_priv(dev);
int ret;
if ((ret = smc911x_ethtool_wait_eeprom_ready(dev))!=0)
return ret;
- *data = SMC_GET_E2P_DATA();
+ *data = SMC_GET_E2P_DATA(lp);
return 0;
}
static inline int smc911x_ethtool_write_eeprom_byte(struct net_device *dev,
u8 data)
{
- unsigned long ioaddr = dev->base_addr;
+ struct smc911x_local *lp = netdev_priv(dev);
int ret;
if ((ret = smc911x_ethtool_wait_eeprom_ready(dev))!=0)
return ret;
- SMC_SET_E2P_DATA(data);
+ SMC_SET_E2P_DATA(lp, data);
return 0;
}
@@ -1803,8 +1736,9 @@
* This routine has a simple purpose -- make the SMC chip generate an
* interrupt, so an auto-detect routine can detect it, and find the IRQ,
*/
-static int __init smc911x_findirq(unsigned long ioaddr)
+static int __init smc911x_findirq(struct net_device *dev)
{
+ struct smc911x_local *lp = netdev_priv(dev);
int timeout = 20;
unsigned long cookie;
@@ -1816,7 +1750,7 @@
* Force a SW interrupt
*/
- SMC_SET_INT_EN(INT_EN_SW_INT_EN_);
+ SMC_SET_INT_EN(lp, INT_EN_SW_INT_EN_);
/*
* Wait until positive that the interrupt has been generated
@@ -1824,7 +1758,7 @@
do {
int int_status;
udelay(10);
- int_status = SMC_GET_INT_EN();
+ int_status = SMC_GET_INT_EN(lp);
if (int_status & INT_EN_SW_INT_EN_)
break; /* got the interrupt */
} while (--timeout);
@@ -1837,7 +1771,7 @@
*/
/* and disable all interrupts again */
- SMC_SET_INT_EN(0);
+ SMC_SET_INT_EN(lp, 0);
/* and return what I found */
return probe_irq_off(cookie);
@@ -1866,17 +1800,18 @@
* o actually GRAB the irq.
* o GRAB the region
*/
-static int __init smc911x_probe(struct net_device *dev, unsigned long ioaddr)
+static int __init smc911x_probe(struct net_device *dev)
{
struct smc911x_local *lp = netdev_priv(dev);
int i, retval;
unsigned int val, chip_id, revision;
const char *version_string;
+ unsigned long irq_flags;
DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
/* First, see if the endian word is recognized */
- val = SMC_GET_BYTE_TEST();
+ val = SMC_GET_BYTE_TEST(lp);
DBG(SMC_DEBUG_MISC, "%s: endian probe returned 0x%04x\n", CARDNAME, val);
if (val != 0x87654321) {
printk(KERN_ERR "Invalid chip endian 0x08%x\n",val);
@@ -1889,7 +1824,7 @@
* recognize. These might need to be added to later,
* as future revisions could be added.
*/
- chip_id = SMC_GET_PN();
+ chip_id = SMC_GET_PN(lp);
DBG(SMC_DEBUG_MISC, "%s: id probe returned 0x%04x\n", CARDNAME, chip_id);
for(i=0;chip_ids[i].id != 0; i++) {
if (chip_ids[i].id == chip_id) break;
@@ -1901,7 +1836,7 @@
}
version_string = chip_ids[i].name;
- revision = SMC_GET_REV();
+ revision = SMC_GET_REV(lp);
DBG(SMC_DEBUG_MISC, "%s: revision = 0x%04x\n", CARDNAME, revision);
/* At this point I'll assume that the chip is an SMC911x. */
@@ -1915,7 +1850,6 @@
}
/* fill in some of the fields */
- dev->base_addr = ioaddr;
lp->version = chip_ids[i].id;
lp->revision = revision;
lp->tx_fifo_kb = tx_fifo_kb;
@@ -1974,7 +1908,7 @@
spin_lock_init(&lp->lock);
/* Get the MAC address */
- SMC_GET_MAC_ADDR(dev->dev_addr);
+ SMC_GET_MAC_ADDR(lp, dev->dev_addr);
/* now, reset the chip, and put it into a known state */
smc911x_reset(dev);
@@ -1991,7 +1925,7 @@
trials = 3;
while (trials--) {
- dev->irq = smc911x_findirq(ioaddr);
+ dev->irq = smc911x_findirq(dev);
if (dev->irq)
break;
/* kick the card and try again */
@@ -2039,9 +1973,15 @@
lp->ctl_rfduplx = 1;
lp->ctl_rspeed = 100;
+#ifdef SMC_DYNAMIC_BUS_CONFIG
+ irq_flags = lp->cfg.irq_flags;
+#else
+ irq_flags = IRQF_SHARED | SMC_IRQ_SENSE;
+#endif
+
/* Grab the IRQ */
retval = request_irq(dev->irq, &smc911x_interrupt,
- IRQF_SHARED | SMC_IRQ_SENSE, dev->name, dev);
+ irq_flags, dev->name, dev);
if (retval)
goto err_out;
@@ -2111,6 +2051,7 @@
*/
static int smc911x_drv_probe(struct platform_device *pdev)
{
+ struct smc91x_platdata *pd = pdev->dev.platform_data;
struct net_device *ndev;
struct resource *res;
struct smc911x_local *lp;
@@ -2144,6 +2085,13 @@
ndev->irq = platform_get_irq(pdev, 0);
lp = netdev_priv(ndev);
lp->netdev = ndev;
+#ifdef SMC_DYNAMIC_BUS_CONFIG
+ if (!pd) {
+ ret = -EINVAL;
+ goto release_both;
+ }
+ memcpy(&lp->cfg, pd, sizeof(lp->cfg));
+#endif
addr = ioremap(res->start, SMC911X_IO_EXTENT);
if (!addr) {
@@ -2152,7 +2100,9 @@
}
platform_set_drvdata(pdev, ndev);
- ret = smc911x_probe(ndev, (unsigned long)addr);
+ lp->base = addr;
+ ndev->base_addr = res->start;
+ ret = smc911x_probe(ndev);
if (ret != 0) {
platform_set_drvdata(pdev, NULL);
iounmap(addr);
@@ -2176,6 +2126,7 @@
static int smc911x_drv_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
+ struct smc911x_local *lp = netdev_priv(ndev);
struct resource *res;
DBG(SMC_DEBUG_FUNC, "--> %s\n", __FUNCTION__);
@@ -2187,7 +2138,6 @@
#ifdef SMC_USE_DMA
{
- struct smc911x_local *lp = netdev_priv(ndev);
if (lp->rxdma != -1) {
SMC_DMA_FREE(dev, lp->rxdma);
}
@@ -2196,7 +2146,7 @@
}
}
#endif
- iounmap((void *)ndev->base_addr);
+ iounmap(lp->base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, SMC911X_IO_EXTENT);
@@ -2207,7 +2157,7 @@
static int smc911x_drv_suspend(struct platform_device *dev, pm_message_t state)
{
struct net_device *ndev = platform_get_drvdata(dev);
- unsigned long ioaddr = ndev->base_addr;
+ struct smc911x_local *lp = netdev_priv(ndev);
DBG(SMC_DEBUG_FUNC, "--> %s\n", __FUNCTION__);
if (ndev) {
@@ -2216,7 +2166,7 @@
smc911x_shutdown(ndev);
#if POWER_DOWN
/* Set D2 - Energy detect only setting */
- SMC_SET_PMT_CTRL(2<<12);
+ SMC_SET_PMT_CTRL(lp, 2<<12);
#endif
}
}
diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h
index 7defa63..76c17c2 100644
--- a/drivers/net/smc911x.h
+++ b/drivers/net/smc911x.h
@@ -29,6 +29,7 @@
#ifndef _SMC911X_H_
#define _SMC911X_H_
+#include <linux/smc911x.h>
/*
* Use the DMA feature on PXA chips
*/
@@ -38,42 +39,160 @@
#define SMC_USE_32BIT 1
#define SMC_IRQ_SENSE IRQF_TRIGGER_FALLING
#elif defined(CONFIG_SH_MAGIC_PANEL_R2)
- #define SMC_USE_SH_DMA 0
#define SMC_USE_16BIT 0
#define SMC_USE_32BIT 1
#define SMC_IRQ_SENSE IRQF_TRIGGER_LOW
+#else
+/*
+ * Default configuration
+ */
+
+#define SMC_DYNAMIC_BUS_CONFIG
#endif
+/* store this information for the driver.. */
+struct smc911x_local {
+ /*
+ * If I have to wait until the DMA is finished and ready to reload a
+ * packet, I will store the skbuff here. Then, the DMA will send it
+ * out and free it.
+ */
+ struct sk_buff *pending_tx_skb;
+
+ /* version/revision of the SMC911x chip */
+ u16 version;
+ u16 revision;
+
+ /* FIFO sizes */
+ int tx_fifo_kb;
+ int tx_fifo_size;
+ int rx_fifo_size;
+ int afc_cfg;
+
+ /* Contains the current active receive/phy mode */
+ int ctl_rfduplx;
+ int ctl_rspeed;
+
+ u32 msg_enable;
+ u32 phy_type;
+ struct mii_if_info mii;
+
+ /* work queue */
+ struct work_struct phy_configure;
+
+ int tx_throttle;
+ spinlock_t lock;
+
+ struct net_device *netdev;
+
+#ifdef SMC_USE_DMA
+ /* DMA needs the physical address of the chip */
+ u_long physaddr;
+ int rxdma;
+ int txdma;
+ int rxdma_active;
+ int txdma_active;
+ struct sk_buff *current_rx_skb;
+ struct sk_buff *current_tx_skb;
+ struct device *dev;
+#endif
+ void __iomem *base;
+#ifdef SMC_DYNAMIC_BUS_CONFIG
+ struct smc911x_platdata cfg;
+#endif
+};
/*
* Define the bus width specific IO macros
*/
+#ifdef SMC_DYNAMIC_BUS_CONFIG
+static inline unsigned int SMC_inl(struct smc911x_local *lp, int reg)
+{
+ void __iomem *ioaddr = lp->base + reg;
+
+ if (lp->cfg.flags & SMC911X_USE_32BIT)
+ return readl(ioaddr);
+
+ if (lp->cfg.flags & SMC911X_USE_16BIT)
+ return readw(ioaddr) | (readw(ioaddr + 2) << 16);
+
+ BUG();
+}
+
+static inline void SMC_outl(unsigned int value, struct smc911x_local *lp,
+ int reg)
+{
+ void __iomem *ioaddr = lp->base + reg;
+
+ if (lp->cfg.flags & SMC911X_USE_32BIT) {
+ writel(value, ioaddr);
+ return;
+ }
+
+ if (lp->cfg.flags & SMC911X_USE_16BIT) {
+ writew(value & 0xffff, ioaddr);
+ writew(value >> 16, ioaddr + 2);
+ return;
+ }
+
+ BUG();
+}
+
+static inline void SMC_insl(struct smc911x_local *lp, int reg,
+ void *addr, unsigned int count)
+{
+ void __iomem *ioaddr = lp->base + reg;
+
+ if (lp->cfg.flags & SMC911X_USE_32BIT) {
+ readsl(ioaddr, addr, count);
+ return;
+ }
+
+ if (lp->cfg.flags & SMC911X_USE_16BIT) {
+ readsw(ioaddr, addr, count * 2);
+ return;
+ }
+
+ BUG();
+}
+
+static inline void SMC_outsl(struct smc911x_local *lp, int reg,
+ void *addr, unsigned int count)
+{
+ void __iomem *ioaddr = lp->base + reg;
+
+ if (lp->cfg.flags & SMC911X_USE_32BIT) {
+ writesl(ioaddr, addr, count);
+ return;
+ }
+
+ if (lp->cfg.flags & SMC911X_USE_16BIT) {
+ writesw(ioaddr, addr, count * 2);
+ return;
+ }
+
+ BUG();
+}
+#else
#if SMC_USE_16BIT
-#define SMC_inb(a, r) readb((a) + (r))
-#define SMC_inw(a, r) readw((a) + (r))
-#define SMC_inl(a, r) ((SMC_inw(a, r) & 0xFFFF)+(SMC_inw(a+2, r)<<16))
-#define SMC_outb(v, a, r) writeb(v, (a) + (r))
-#define SMC_outw(v, a, r) writew(v, (a) + (r))
-#define SMC_outl(v, a, r) \
+#define SMC_inl(lp, r) ((readw((lp)->base + (r)) & 0xFFFF) + (readw((lp)->base + (r) + 2) << 16))
+#define SMC_outl(v, lp, r) \
do{ \
- writel(v & 0xFFFF, (a) + (r)); \
- writel(v >> 16, (a) + (r) + 2); \
+ writew(v & 0xFFFF, (lp)->base + (r)); \
+ writew(v >> 16, (lp)->base + (r) + 2); \
} while (0)
-#define SMC_insl(a, r, p, l) readsw((short*)((a) + (r)), p, l*2)
-#define SMC_outsl(a, r, p, l) writesw((short*)((a) + (r)), p, l*2)
+#define SMC_insl(lp, r, p, l) readsw((short*)((lp)->base + (r)), p, l*2)
+#define SMC_outsl(lp, r, p, l) writesw((short*)((lp)->base + (r)), p, l*2)
#elif SMC_USE_32BIT
-#define SMC_inb(a, r) readb((a) + (r))
-#define SMC_inw(a, r) readw((a) + (r))
-#define SMC_inl(a, r) readl((a) + (r))
-#define SMC_outb(v, a, r) writeb(v, (a) + (r))
-#define SMC_outl(v, a, r) writel(v, (a) + (r))
-#define SMC_insl(a, r, p, l) readsl((int*)((a) + (r)), p, l)
-#define SMC_outsl(a, r, p, l) writesl((int*)((a) + (r)), p, l)
+#define SMC_inl(lp, r) readl((lp)->base + (r))
+#define SMC_outl(v, lp, r) writel(v, (lp)->base + (r))
+#define SMC_insl(lp, r, p, l) readsl((int*)((lp)->base + (r)), p, l)
+#define SMC_outsl(lp, r, p, l) writesl((int*)((lp)->base + (r)), p, l)
#endif /* SMC_USE_16BIT */
-
+#endif /* SMC_DYNAMIC_BUS_CONFIG */
#ifdef SMC_USE_PXA_DMA
@@ -110,22 +229,22 @@
#ifdef SMC_insl
#undef SMC_insl
-#define SMC_insl(a, r, p, l) \
- smc_pxa_dma_insl(lp->dev, a, lp->physaddr, r, lp->rxdma, p, l)
+#define SMC_insl(lp, r, p, l) \
+ smc_pxa_dma_insl(lp, lp->physaddr, r, lp->rxdma, p, l)
static inline void
-smc_pxa_dma_insl(struct device *dev, u_long ioaddr, u_long physaddr,
+smc_pxa_dma_insl(struct smc911x_local *lp, u_long physaddr,
int reg, int dma, u_char *buf, int len)
{
/* 64 bit alignment is required for memory to memory DMA */
if ((long)buf & 4) {
- *((u32 *)buf) = SMC_inl(ioaddr, reg);
+ *((u32 *)buf) = SMC_inl(lp, reg);
buf += 4;
len--;
}
len *= 4;
- rx_dmabuf = dma_map_single(dev, buf, len, DMA_FROM_DEVICE);
+ rx_dmabuf = dma_map_single(lp->dev, buf, len, DMA_FROM_DEVICE);
rx_dmalen = len;
DCSR(dma) = DCSR_NODESC;
DTADR(dma) = rx_dmabuf;
@@ -136,52 +255,24 @@
}
#endif
-#ifdef SMC_insw
-#undef SMC_insw
-#define SMC_insw(a, r, p, l) \
- smc_pxa_dma_insw(lp->dev, a, lp->physaddr, r, lp->rxdma, p, l)
-
-static inline void
-smc_pxa_dma_insw(struct device *dev, u_long ioaddr, u_long physaddr,
- int reg, int dma, u_char *buf, int len)
-{
- /* 64 bit alignment is required for memory to memory DMA */
- while ((long)buf & 6) {
- *((u16 *)buf) = SMC_inw(ioaddr, reg);
- buf += 2;
- len--;
- }
-
- len *= 2;
- rx_dmabuf = dma_map_single(dev, buf, len, DMA_FROM_DEVICE);
- rx_dmalen = len;
- DCSR(dma) = DCSR_NODESC;
- DTADR(dma) = rx_dmabuf;
- DSADR(dma) = physaddr + reg;
- DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 |
- DCMD_WIDTH2 | DCMD_ENDIRQEN | (DCMD_LENGTH & rx_dmalen));
- DCSR(dma) = DCSR_NODESC | DCSR_RUN;
-}
-#endif
-
#ifdef SMC_outsl
#undef SMC_outsl
-#define SMC_outsl(a, r, p, l) \
- smc_pxa_dma_outsl(lp->dev, a, lp->physaddr, r, lp->txdma, p, l)
+#define SMC_outsl(lp, r, p, l) \
+ smc_pxa_dma_outsl(lp, lp->physaddr, r, lp->txdma, p, l)
static inline void
-smc_pxa_dma_outsl(struct device *dev, u_long ioaddr, u_long physaddr,
+smc_pxa_dma_outsl(struct smc911x_local *lp, u_long physaddr,
int reg, int dma, u_char *buf, int len)
{
/* 64 bit alignment is required for memory to memory DMA */
if ((long)buf & 4) {
- SMC_outl(*((u32 *)buf), ioaddr, reg);
+ SMC_outl(*((u32 *)buf), lp, reg);
buf += 4;
len--;
}
len *= 4;
- tx_dmabuf = dma_map_single(dev, buf, len, DMA_TO_DEVICE);
+ tx_dmabuf = dma_map_single(lp->dev, buf, len, DMA_TO_DEVICE);
tx_dmalen = len;
DCSR(dma) = DCSR_NODESC;
DSADR(dma) = tx_dmabuf;
@@ -191,35 +282,6 @@
DCSR(dma) = DCSR_NODESC | DCSR_RUN;
}
#endif
-
-#ifdef SMC_outsw
-#undef SMC_outsw
-#define SMC_outsw(a, r, p, l) \
- smc_pxa_dma_outsw(lp->dev, a, lp->physaddr, r, lp->txdma, p, l)
-
-static inline void
-smc_pxa_dma_outsw(struct device *dev, u_long ioaddr, u_long physaddr,
- int reg, int dma, u_char *buf, int len)
-{
- /* 64 bit alignment is required for memory to memory DMA */
- while ((long)buf & 6) {
- SMC_outw(*((u16 *)buf), ioaddr, reg);
- buf += 2;
- len--;
- }
-
- len *= 2;
- tx_dmabuf = dma_map_single(dev, buf, len, DMA_TO_DEVICE);
- tx_dmalen = len;
- DCSR(dma) = DCSR_NODESC;
- DSADR(dma) = tx_dmabuf;
- DTADR(dma) = physaddr + reg;
- DCMD(dma) = (DCMD_INCSRCADDR | DCMD_BURST32 |
- DCMD_WIDTH2 | DCMD_ENDIRQEN | (DCMD_LENGTH & tx_dmalen));
- DCSR(dma) = DCSR_NODESC | DCSR_RUN;
-}
-#endif
-
#endif /* SMC_USE_PXA_DMA */
@@ -629,213 +691,213 @@
* capabilities. Please use those and not the in/out primitives.
*/
/* FIFO read/write macros */
-#define SMC_PUSH_DATA(p, l) SMC_outsl( ioaddr, TX_DATA_FIFO, p, (l) >> 2 )
-#define SMC_PULL_DATA(p, l) SMC_insl ( ioaddr, RX_DATA_FIFO, p, (l) >> 2 )
-#define SMC_SET_TX_FIFO(x) SMC_outl( x, ioaddr, TX_DATA_FIFO )
-#define SMC_GET_RX_FIFO() SMC_inl( ioaddr, RX_DATA_FIFO )
+#define SMC_PUSH_DATA(lp, p, l) SMC_outsl( lp, TX_DATA_FIFO, p, (l) >> 2 )
+#define SMC_PULL_DATA(lp, p, l) SMC_insl ( lp, RX_DATA_FIFO, p, (l) >> 2 )
+#define SMC_SET_TX_FIFO(lp, x) SMC_outl( x, lp, TX_DATA_FIFO )
+#define SMC_GET_RX_FIFO(lp) SMC_inl( lp, RX_DATA_FIFO )
/* I/O mapped register read/write macros */
-#define SMC_GET_TX_STS_FIFO() SMC_inl( ioaddr, TX_STATUS_FIFO )
-#define SMC_GET_RX_STS_FIFO() SMC_inl( ioaddr, RX_STATUS_FIFO )
-#define SMC_GET_RX_STS_FIFO_PEEK() SMC_inl( ioaddr, RX_STATUS_FIFO_PEEK )
-#define SMC_GET_PN() (SMC_inl( ioaddr, ID_REV ) >> 16)
-#define SMC_GET_REV() (SMC_inl( ioaddr, ID_REV ) & 0xFFFF)
-#define SMC_GET_IRQ_CFG() SMC_inl( ioaddr, INT_CFG )
-#define SMC_SET_IRQ_CFG(x) SMC_outl( x, ioaddr, INT_CFG )
-#define SMC_GET_INT() SMC_inl( ioaddr, INT_STS )
-#define SMC_ACK_INT(x) SMC_outl( x, ioaddr, INT_STS )
-#define SMC_GET_INT_EN() SMC_inl( ioaddr, INT_EN )
-#define SMC_SET_INT_EN(x) SMC_outl( x, ioaddr, INT_EN )
-#define SMC_GET_BYTE_TEST() SMC_inl( ioaddr, BYTE_TEST )
-#define SMC_SET_BYTE_TEST(x) SMC_outl( x, ioaddr, BYTE_TEST )
-#define SMC_GET_FIFO_INT() SMC_inl( ioaddr, FIFO_INT )
-#define SMC_SET_FIFO_INT(x) SMC_outl( x, ioaddr, FIFO_INT )
-#define SMC_SET_FIFO_TDA(x) \
+#define SMC_GET_TX_STS_FIFO(lp) SMC_inl( lp, TX_STATUS_FIFO )
+#define SMC_GET_RX_STS_FIFO(lp) SMC_inl( lp, RX_STATUS_FIFO )
+#define SMC_GET_RX_STS_FIFO_PEEK(lp) SMC_inl( lp, RX_STATUS_FIFO_PEEK )
+#define SMC_GET_PN(lp) (SMC_inl( lp, ID_REV ) >> 16)
+#define SMC_GET_REV(lp) (SMC_inl( lp, ID_REV ) & 0xFFFF)
+#define SMC_GET_IRQ_CFG(lp) SMC_inl( lp, INT_CFG )
+#define SMC_SET_IRQ_CFG(lp, x) SMC_outl( x, lp, INT_CFG )
+#define SMC_GET_INT(lp) SMC_inl( lp, INT_STS )
+#define SMC_ACK_INT(lp, x) SMC_outl( x, lp, INT_STS )
+#define SMC_GET_INT_EN(lp) SMC_inl( lp, INT_EN )
+#define SMC_SET_INT_EN(lp, x) SMC_outl( x, lp, INT_EN )
+#define SMC_GET_BYTE_TEST(lp) SMC_inl( lp, BYTE_TEST )
+#define SMC_SET_BYTE_TEST(lp, x) SMC_outl( x, lp, BYTE_TEST )
+#define SMC_GET_FIFO_INT(lp) SMC_inl( lp, FIFO_INT )
+#define SMC_SET_FIFO_INT(lp, x) SMC_outl( x, lp, FIFO_INT )
+#define SMC_SET_FIFO_TDA(lp, x) \
do { \
unsigned long __flags; \
int __mask; \
local_irq_save(__flags); \
- __mask = SMC_GET_FIFO_INT() & ~(0xFF<<24); \
- SMC_SET_FIFO_INT( __mask | (x)<<24 ); \
+ __mask = SMC_GET_FIFO_INT((lp)) & ~(0xFF<<24); \
+ SMC_SET_FIFO_INT( (lp), __mask | (x)<<24 ); \
local_irq_restore(__flags); \
} while (0)
-#define SMC_SET_FIFO_TSL(x) \
+#define SMC_SET_FIFO_TSL(lp, x) \
do { \
unsigned long __flags; \
int __mask; \
local_irq_save(__flags); \
- __mask = SMC_GET_FIFO_INT() & ~(0xFF<<16); \
- SMC_SET_FIFO_INT( __mask | (((x) & 0xFF)<<16)); \
+ __mask = SMC_GET_FIFO_INT((lp)) & ~(0xFF<<16); \
+ SMC_SET_FIFO_INT( (lp), __mask | (((x) & 0xFF)<<16)); \
local_irq_restore(__flags); \
} while (0)
-#define SMC_SET_FIFO_RSA(x) \
+#define SMC_SET_FIFO_RSA(lp, x) \
do { \
unsigned long __flags; \
int __mask; \
local_irq_save(__flags); \
- __mask = SMC_GET_FIFO_INT() & ~(0xFF<<8); \
- SMC_SET_FIFO_INT( __mask | (((x) & 0xFF)<<8)); \
+ __mask = SMC_GET_FIFO_INT((lp)) & ~(0xFF<<8); \
+ SMC_SET_FIFO_INT( (lp), __mask | (((x) & 0xFF)<<8)); \
local_irq_restore(__flags); \
} while (0)
-#define SMC_SET_FIFO_RSL(x) \
+#define SMC_SET_FIFO_RSL(lp, x) \
do { \
unsigned long __flags; \
int __mask; \
local_irq_save(__flags); \
- __mask = SMC_GET_FIFO_INT() & ~0xFF; \
- SMC_SET_FIFO_INT( __mask | ((x) & 0xFF)); \
+ __mask = SMC_GET_FIFO_INT((lp)) & ~0xFF; \
+ SMC_SET_FIFO_INT( (lp),__mask | ((x) & 0xFF)); \
local_irq_restore(__flags); \
} while (0)
-#define SMC_GET_RX_CFG() SMC_inl( ioaddr, RX_CFG )
-#define SMC_SET_RX_CFG(x) SMC_outl( x, ioaddr, RX_CFG )
-#define SMC_GET_TX_CFG() SMC_inl( ioaddr, TX_CFG )
-#define SMC_SET_TX_CFG(x) SMC_outl( x, ioaddr, TX_CFG )
-#define SMC_GET_HW_CFG() SMC_inl( ioaddr, HW_CFG )
-#define SMC_SET_HW_CFG(x) SMC_outl( x, ioaddr, HW_CFG )
-#define SMC_GET_RX_DP_CTRL() SMC_inl( ioaddr, RX_DP_CTRL )
-#define SMC_SET_RX_DP_CTRL(x) SMC_outl( x, ioaddr, RX_DP_CTRL )
-#define SMC_GET_PMT_CTRL() SMC_inl( ioaddr, PMT_CTRL )
-#define SMC_SET_PMT_CTRL(x) SMC_outl( x, ioaddr, PMT_CTRL )
-#define SMC_GET_GPIO_CFG() SMC_inl( ioaddr, GPIO_CFG )
-#define SMC_SET_GPIO_CFG(x) SMC_outl( x, ioaddr, GPIO_CFG )
-#define SMC_GET_RX_FIFO_INF() SMC_inl( ioaddr, RX_FIFO_INF )
-#define SMC_SET_RX_FIFO_INF(x) SMC_outl( x, ioaddr, RX_FIFO_INF )
-#define SMC_GET_TX_FIFO_INF() SMC_inl( ioaddr, TX_FIFO_INF )
-#define SMC_SET_TX_FIFO_INF(x) SMC_outl( x, ioaddr, TX_FIFO_INF )
-#define SMC_GET_GPT_CFG() SMC_inl( ioaddr, GPT_CFG )
-#define SMC_SET_GPT_CFG(x) SMC_outl( x, ioaddr, GPT_CFG )
-#define SMC_GET_RX_DROP() SMC_inl( ioaddr, RX_DROP )
-#define SMC_SET_RX_DROP(x) SMC_outl( x, ioaddr, RX_DROP )
-#define SMC_GET_MAC_CMD() SMC_inl( ioaddr, MAC_CSR_CMD )
-#define SMC_SET_MAC_CMD(x) SMC_outl( x, ioaddr, MAC_CSR_CMD )
-#define SMC_GET_MAC_DATA() SMC_inl( ioaddr, MAC_CSR_DATA )
-#define SMC_SET_MAC_DATA(x) SMC_outl( x, ioaddr, MAC_CSR_DATA )
-#define SMC_GET_AFC_CFG() SMC_inl( ioaddr, AFC_CFG )
-#define SMC_SET_AFC_CFG(x) SMC_outl( x, ioaddr, AFC_CFG )
-#define SMC_GET_E2P_CMD() SMC_inl( ioaddr, E2P_CMD )
-#define SMC_SET_E2P_CMD(x) SMC_outl( x, ioaddr, E2P_CMD )
-#define SMC_GET_E2P_DATA() SMC_inl( ioaddr, E2P_DATA )
-#define SMC_SET_E2P_DATA(x) SMC_outl( x, ioaddr, E2P_DATA )
+#define SMC_GET_RX_CFG(lp) SMC_inl( lp, RX_CFG )
+#define SMC_SET_RX_CFG(lp, x) SMC_outl( x, lp, RX_CFG )
+#define SMC_GET_TX_CFG(lp) SMC_inl( lp, TX_CFG )
+#define SMC_SET_TX_CFG(lp, x) SMC_outl( x, lp, TX_CFG )
+#define SMC_GET_HW_CFG(lp) SMC_inl( lp, HW_CFG )
+#define SMC_SET_HW_CFG(lp, x) SMC_outl( x, lp, HW_CFG )
+#define SMC_GET_RX_DP_CTRL(lp) SMC_inl( lp, RX_DP_CTRL )
+#define SMC_SET_RX_DP_CTRL(lp, x) SMC_outl( x, lp, RX_DP_CTRL )
+#define SMC_GET_PMT_CTRL(lp) SMC_inl( lp, PMT_CTRL )
+#define SMC_SET_PMT_CTRL(lp, x) SMC_outl( x, lp, PMT_CTRL )
+#define SMC_GET_GPIO_CFG(lp) SMC_inl( lp, GPIO_CFG )
+#define SMC_SET_GPIO_CFG(lp, x) SMC_outl( x, lp, GPIO_CFG )
+#define SMC_GET_RX_FIFO_INF(lp) SMC_inl( lp, RX_FIFO_INF )
+#define SMC_SET_RX_FIFO_INF(lp, x) SMC_outl( x, lp, RX_FIFO_INF )
+#define SMC_GET_TX_FIFO_INF(lp) SMC_inl( lp, TX_FIFO_INF )
+#define SMC_SET_TX_FIFO_INF(lp, x) SMC_outl( x, lp, TX_FIFO_INF )
+#define SMC_GET_GPT_CFG(lp) SMC_inl( lp, GPT_CFG )
+#define SMC_SET_GPT_CFG(lp, x) SMC_outl( x, lp, GPT_CFG )
+#define SMC_GET_RX_DROP(lp) SMC_inl( lp, RX_DROP )
+#define SMC_SET_RX_DROP(lp, x) SMC_outl( x, lp, RX_DROP )
+#define SMC_GET_MAC_CMD(lp) SMC_inl( lp, MAC_CSR_CMD )
+#define SMC_SET_MAC_CMD(lp, x) SMC_outl( x, lp, MAC_CSR_CMD )
+#define SMC_GET_MAC_DATA(lp) SMC_inl( lp, MAC_CSR_DATA )
+#define SMC_SET_MAC_DATA(lp, x) SMC_outl( x, lp, MAC_CSR_DATA )
+#define SMC_GET_AFC_CFG(lp) SMC_inl( lp, AFC_CFG )
+#define SMC_SET_AFC_CFG(lp, x) SMC_outl( x, lp, AFC_CFG )
+#define SMC_GET_E2P_CMD(lp) SMC_inl( lp, E2P_CMD )
+#define SMC_SET_E2P_CMD(lp, x) SMC_outl( x, lp, E2P_CMD )
+#define SMC_GET_E2P_DATA(lp) SMC_inl( lp, E2P_DATA )
+#define SMC_SET_E2P_DATA(lp, x) SMC_outl( x, lp, E2P_DATA )
/* MAC register read/write macros */
-#define SMC_GET_MAC_CSR(a,v) \
+#define SMC_GET_MAC_CSR(lp,a,v) \
do { \
- while (SMC_GET_MAC_CMD() & MAC_CSR_CMD_CSR_BUSY_); \
- SMC_SET_MAC_CMD(MAC_CSR_CMD_CSR_BUSY_ | \
+ while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \
+ SMC_SET_MAC_CMD((lp),MAC_CSR_CMD_CSR_BUSY_ | \
MAC_CSR_CMD_R_NOT_W_ | (a) ); \
- while (SMC_GET_MAC_CMD() & MAC_CSR_CMD_CSR_BUSY_); \
- v = SMC_GET_MAC_DATA(); \
+ while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \
+ v = SMC_GET_MAC_DATA((lp)); \
} while (0)
-#define SMC_SET_MAC_CSR(a,v) \
+#define SMC_SET_MAC_CSR(lp,a,v) \
do { \
- while (SMC_GET_MAC_CMD() & MAC_CSR_CMD_CSR_BUSY_); \
- SMC_SET_MAC_DATA(v); \
- SMC_SET_MAC_CMD(MAC_CSR_CMD_CSR_BUSY_ | (a) ); \
- while (SMC_GET_MAC_CMD() & MAC_CSR_CMD_CSR_BUSY_); \
+ while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \
+ SMC_SET_MAC_DATA((lp), v); \
+ SMC_SET_MAC_CMD((lp), MAC_CSR_CMD_CSR_BUSY_ | (a) ); \
+ while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \
} while (0)
-#define SMC_GET_MAC_CR(x) SMC_GET_MAC_CSR( MAC_CR, x )
-#define SMC_SET_MAC_CR(x) SMC_SET_MAC_CSR( MAC_CR, x )
-#define SMC_GET_ADDRH(x) SMC_GET_MAC_CSR( ADDRH, x )
-#define SMC_SET_ADDRH(x) SMC_SET_MAC_CSR( ADDRH, x )
-#define SMC_GET_ADDRL(x) SMC_GET_MAC_CSR( ADDRL, x )
-#define SMC_SET_ADDRL(x) SMC_SET_MAC_CSR( ADDRL, x )
-#define SMC_GET_HASHH(x) SMC_GET_MAC_CSR( HASHH, x )
-#define SMC_SET_HASHH(x) SMC_SET_MAC_CSR( HASHH, x )
-#define SMC_GET_HASHL(x) SMC_GET_MAC_CSR( HASHL, x )
-#define SMC_SET_HASHL(x) SMC_SET_MAC_CSR( HASHL, x )
-#define SMC_GET_MII_ACC(x) SMC_GET_MAC_CSR( MII_ACC, x )
-#define SMC_SET_MII_ACC(x) SMC_SET_MAC_CSR( MII_ACC, x )
-#define SMC_GET_MII_DATA(x) SMC_GET_MAC_CSR( MII_DATA, x )
-#define SMC_SET_MII_DATA(x) SMC_SET_MAC_CSR( MII_DATA, x )
-#define SMC_GET_FLOW(x) SMC_GET_MAC_CSR( FLOW, x )
-#define SMC_SET_FLOW(x) SMC_SET_MAC_CSR( FLOW, x )
-#define SMC_GET_VLAN1(x) SMC_GET_MAC_CSR( VLAN1, x )
-#define SMC_SET_VLAN1(x) SMC_SET_MAC_CSR( VLAN1, x )
-#define SMC_GET_VLAN2(x) SMC_GET_MAC_CSR( VLAN2, x )
-#define SMC_SET_VLAN2(x) SMC_SET_MAC_CSR( VLAN2, x )
-#define SMC_SET_WUFF(x) SMC_SET_MAC_CSR( WUFF, x )
-#define SMC_GET_WUCSR(x) SMC_GET_MAC_CSR( WUCSR, x )
-#define SMC_SET_WUCSR(x) SMC_SET_MAC_CSR( WUCSR, x )
+#define SMC_GET_MAC_CR(lp, x) SMC_GET_MAC_CSR( (lp), MAC_CR, x )
+#define SMC_SET_MAC_CR(lp, x) SMC_SET_MAC_CSR( (lp), MAC_CR, x )
+#define SMC_GET_ADDRH(lp, x) SMC_GET_MAC_CSR( (lp), ADDRH, x )
+#define SMC_SET_ADDRH(lp, x) SMC_SET_MAC_CSR( (lp), ADDRH, x )
+#define SMC_GET_ADDRL(lp, x) SMC_GET_MAC_CSR( (lp), ADDRL, x )
+#define SMC_SET_ADDRL(lp, x) SMC_SET_MAC_CSR( (lp), ADDRL, x )
+#define SMC_GET_HASHH(lp, x) SMC_GET_MAC_CSR( (lp), HASHH, x )
+#define SMC_SET_HASHH(lp, x) SMC_SET_MAC_CSR( (lp), HASHH, x )
+#define SMC_GET_HASHL(lp, x) SMC_GET_MAC_CSR( (lp), HASHL, x )
+#define SMC_SET_HASHL(lp, x) SMC_SET_MAC_CSR( (lp), HASHL, x )
+#define SMC_GET_MII_ACC(lp, x) SMC_GET_MAC_CSR( (lp), MII_ACC, x )
+#define SMC_SET_MII_ACC(lp, x) SMC_SET_MAC_CSR( (lp), MII_ACC, x )
+#define SMC_GET_MII_DATA(lp, x) SMC_GET_MAC_CSR( (lp), MII_DATA, x )
+#define SMC_SET_MII_DATA(lp, x) SMC_SET_MAC_CSR( (lp), MII_DATA, x )
+#define SMC_GET_FLOW(lp, x) SMC_GET_MAC_CSR( (lp), FLOW, x )
+#define SMC_SET_FLOW(lp, x) SMC_SET_MAC_CSR( (lp), FLOW, x )
+#define SMC_GET_VLAN1(lp, x) SMC_GET_MAC_CSR( (lp), VLAN1, x )
+#define SMC_SET_VLAN1(lp, x) SMC_SET_MAC_CSR( (lp), VLAN1, x )
+#define SMC_GET_VLAN2(lp, x) SMC_GET_MAC_CSR( (lp), VLAN2, x )
+#define SMC_SET_VLAN2(lp, x) SMC_SET_MAC_CSR( (lp), VLAN2, x )
+#define SMC_SET_WUFF(lp, x) SMC_SET_MAC_CSR( (lp), WUFF, x )
+#define SMC_GET_WUCSR(lp, x) SMC_GET_MAC_CSR( (lp), WUCSR, x )
+#define SMC_SET_WUCSR(lp, x) SMC_SET_MAC_CSR( (lp), WUCSR, x )
/* PHY register read/write macros */
-#define SMC_GET_MII(a,phy,v) \
+#define SMC_GET_MII(lp,a,phy,v) \
do { \
u32 __v; \
do { \
- SMC_GET_MII_ACC(__v); \
+ SMC_GET_MII_ACC((lp), __v); \
} while ( __v & MII_ACC_MII_BUSY_ ); \
- SMC_SET_MII_ACC( ((phy)<<11) | ((a)<<6) | \
+ SMC_SET_MII_ACC( (lp), ((phy)<<11) | ((a)<<6) | \
MII_ACC_MII_BUSY_); \
do { \
- SMC_GET_MII_ACC(__v); \
+ SMC_GET_MII_ACC( (lp), __v); \
} while ( __v & MII_ACC_MII_BUSY_ ); \
- SMC_GET_MII_DATA(v); \
+ SMC_GET_MII_DATA((lp), v); \
} while (0)
-#define SMC_SET_MII(a,phy,v) \
+#define SMC_SET_MII(lp,a,phy,v) \
do { \
u32 __v; \
do { \
- SMC_GET_MII_ACC(__v); \
+ SMC_GET_MII_ACC((lp), __v); \
} while ( __v & MII_ACC_MII_BUSY_ ); \
- SMC_SET_MII_DATA(v); \
- SMC_SET_MII_ACC( ((phy)<<11) | ((a)<<6) | \
+ SMC_SET_MII_DATA((lp), v); \
+ SMC_SET_MII_ACC( (lp), ((phy)<<11) | ((a)<<6) | \
MII_ACC_MII_BUSY_ | \
MII_ACC_MII_WRITE_ ); \
do { \
- SMC_GET_MII_ACC(__v); \
+ SMC_GET_MII_ACC((lp), __v); \
} while ( __v & MII_ACC_MII_BUSY_ ); \
} while (0)
-#define SMC_GET_PHY_BMCR(phy,x) SMC_GET_MII( MII_BMCR, phy, x )
-#define SMC_SET_PHY_BMCR(phy,x) SMC_SET_MII( MII_BMCR, phy, x )
-#define SMC_GET_PHY_BMSR(phy,x) SMC_GET_MII( MII_BMSR, phy, x )
-#define SMC_GET_PHY_ID1(phy,x) SMC_GET_MII( MII_PHYSID1, phy, x )
-#define SMC_GET_PHY_ID2(phy,x) SMC_GET_MII( MII_PHYSID2, phy, x )
-#define SMC_GET_PHY_MII_ADV(phy,x) SMC_GET_MII( MII_ADVERTISE, phy, x )
-#define SMC_SET_PHY_MII_ADV(phy,x) SMC_SET_MII( MII_ADVERTISE, phy, x )
-#define SMC_GET_PHY_MII_LPA(phy,x) SMC_GET_MII( MII_LPA, phy, x )
-#define SMC_SET_PHY_MII_LPA(phy,x) SMC_SET_MII( MII_LPA, phy, x )
-#define SMC_GET_PHY_CTRL_STS(phy,x) SMC_GET_MII( PHY_MODE_CTRL_STS, phy, x )
-#define SMC_SET_PHY_CTRL_STS(phy,x) SMC_SET_MII( PHY_MODE_CTRL_STS, phy, x )
-#define SMC_GET_PHY_INT_SRC(phy,x) SMC_GET_MII( PHY_INT_SRC, phy, x )
-#define SMC_SET_PHY_INT_SRC(phy,x) SMC_SET_MII( PHY_INT_SRC, phy, x )
-#define SMC_GET_PHY_INT_MASK(phy,x) SMC_GET_MII( PHY_INT_MASK, phy, x )
-#define SMC_SET_PHY_INT_MASK(phy,x) SMC_SET_MII( PHY_INT_MASK, phy, x )
-#define SMC_GET_PHY_SPECIAL(phy,x) SMC_GET_MII( PHY_SPECIAL, phy, x )
+#define SMC_GET_PHY_BMCR(lp,phy,x) SMC_GET_MII( (lp), MII_BMCR, phy, x )
+#define SMC_SET_PHY_BMCR(lp,phy,x) SMC_SET_MII( (lp), MII_BMCR, phy, x )
+#define SMC_GET_PHY_BMSR(lp,phy,x) SMC_GET_MII( (lp), MII_BMSR, phy, x )
+#define SMC_GET_PHY_ID1(lp,phy,x) SMC_GET_MII( (lp), MII_PHYSID1, phy, x )
+#define SMC_GET_PHY_ID2(lp,phy,x) SMC_GET_MII( (lp), MII_PHYSID2, phy, x )
+#define SMC_GET_PHY_MII_ADV(lp,phy,x) SMC_GET_MII( (lp), MII_ADVERTISE, phy, x )
+#define SMC_SET_PHY_MII_ADV(lp,phy,x) SMC_SET_MII( (lp), MII_ADVERTISE, phy, x )
+#define SMC_GET_PHY_MII_LPA(lp,phy,x) SMC_GET_MII( (lp), MII_LPA, phy, x )
+#define SMC_SET_PHY_MII_LPA(lp,phy,x) SMC_SET_MII( (lp), MII_LPA, phy, x )
+#define SMC_GET_PHY_CTRL_STS(lp,phy,x) SMC_GET_MII( (lp), PHY_MODE_CTRL_STS, phy, x )
+#define SMC_SET_PHY_CTRL_STS(lp,phy,x) SMC_SET_MII( (lp), PHY_MODE_CTRL_STS, phy, x )
+#define SMC_GET_PHY_INT_SRC(lp,phy,x) SMC_GET_MII( (lp), PHY_INT_SRC, phy, x )
+#define SMC_SET_PHY_INT_SRC(lp,phy,x) SMC_SET_MII( (lp), PHY_INT_SRC, phy, x )
+#define SMC_GET_PHY_INT_MASK(lp,phy,x) SMC_GET_MII( (lp), PHY_INT_MASK, phy, x )
+#define SMC_SET_PHY_INT_MASK(lp,phy,x) SMC_SET_MII( (lp), PHY_INT_MASK, phy, x )
+#define SMC_GET_PHY_SPECIAL(lp,phy,x) SMC_GET_MII( (lp), PHY_SPECIAL, phy, x )
/* Misc read/write macros */
#ifndef SMC_GET_MAC_ADDR
-#define SMC_GET_MAC_ADDR(addr) \
+#define SMC_GET_MAC_ADDR(lp, addr) \
do { \
unsigned int __v; \
\
- SMC_GET_MAC_CSR(ADDRL, __v); \
+ SMC_GET_MAC_CSR((lp), ADDRL, __v); \
addr[0] = __v; addr[1] = __v >> 8; \
addr[2] = __v >> 16; addr[3] = __v >> 24; \
- SMC_GET_MAC_CSR(ADDRH, __v); \
+ SMC_GET_MAC_CSR((lp), ADDRH, __v); \
addr[4] = __v; addr[5] = __v >> 8; \
} while (0)
#endif
-#define SMC_SET_MAC_ADDR(addr) \
+#define SMC_SET_MAC_ADDR(lp, addr) \
do { \
- SMC_SET_MAC_CSR(ADDRL, \
+ SMC_SET_MAC_CSR((lp), ADDRL, \
addr[0] | \
(addr[1] << 8) | \
(addr[2] << 16) | \
(addr[3] << 24)); \
- SMC_SET_MAC_CSR(ADDRH, addr[4]|(addr[5] << 8));\
+ SMC_SET_MAC_CSR((lp), ADDRH, addr[4]|(addr[5] << 8));\
} while (0)
-#define SMC_WRITE_EEPROM_CMD(cmd, addr) \
+#define SMC_WRITE_EEPROM_CMD(lp, cmd, addr) \
do { \
- while (SMC_GET_E2P_CMD() & MAC_CSR_CMD_CSR_BUSY_); \
- SMC_SET_MAC_CMD(MAC_CSR_CMD_R_NOT_W_ | a ); \
- while (SMC_GET_MAC_CMD() & MAC_CSR_CMD_CSR_BUSY_); \
+ while (SMC_GET_E2P_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \
+ SMC_SET_MAC_CMD((lp), MAC_CSR_CMD_R_NOT_W_ | a ); \
+ while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_); \
} while (0)
#endif /* _SMC911X_H_ */
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/sunlance.c b/drivers/net/sunlance.c
index 26ade68..4e994f8 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -915,15 +915,11 @@
lp->tx_new = TX_NEXT(entry);
}
-struct net_device *last_dev;
-
static int lance_open(struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
int status = 0;
- last_dev = dev;
-
STOP_LANCE(lp);
if (request_irq(dev->irq, &lance_interrupt, IRQF_SHARED,
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index cc4bde8..633c128 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -32,6 +32,8 @@
#include <linux/skbuff.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/brcmphy.h>
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/tcp.h>
@@ -64,8 +66,8 @@
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "3.92.1"
-#define DRV_MODULE_RELDATE "June 9, 2008"
+#define DRV_MODULE_VERSION "3.93"
+#define DRV_MODULE_RELDATE "May 22, 2008"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -203,6 +205,7 @@
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5723)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761E)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5785)},
{PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)},
{PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)},
{PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)},
@@ -804,6 +807,569 @@
return ret;
}
+static int tg3_bmcr_reset(struct tg3 *tp)
+{
+ u32 phy_control;
+ int limit, err;
+
+ /* OK, reset it, and poll the BMCR_RESET bit until it
+ * clears or we time out.
+ */
+ phy_control = BMCR_RESET;
+ err = tg3_writephy(tp, MII_BMCR, phy_control);
+ if (err != 0)
+ return -EBUSY;
+
+ limit = 5000;
+ while (limit--) {
+ err = tg3_readphy(tp, MII_BMCR, &phy_control);
+ if (err != 0)
+ return -EBUSY;
+
+ if ((phy_control & BMCR_RESET) == 0) {
+ udelay(40);
+ break;
+ }
+ udelay(10);
+ }
+ if (limit <= 0)
+ return -EBUSY;
+
+ return 0;
+}
+
+static int tg3_mdio_read(struct mii_bus *bp, int mii_id, int reg)
+{
+ struct tg3 *tp = (struct tg3 *)bp->priv;
+ u32 val;
+
+ if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_PAUSED)
+ return -EAGAIN;
+
+ if (tg3_readphy(tp, reg, &val))
+ return -EIO;
+
+ return val;
+}
+
+static int tg3_mdio_write(struct mii_bus *bp, int mii_id, int reg, u16 val)
+{
+ struct tg3 *tp = (struct tg3 *)bp->priv;
+
+ if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_PAUSED)
+ return -EAGAIN;
+
+ if (tg3_writephy(tp, reg, val))
+ return -EIO;
+
+ return 0;
+}
+
+static int tg3_mdio_reset(struct mii_bus *bp)
+{
+ return 0;
+}
+
+static void tg3_mdio_config(struct tg3 *tp)
+{
+ u32 val;
+
+ if (tp->mdio_bus.phy_map[PHY_ADDR]->interface !=
+ PHY_INTERFACE_MODE_RGMII)
+ return;
+
+ val = tr32(MAC_PHYCFG1) & ~(MAC_PHYCFG1_RGMII_EXT_RX_DEC |
+ MAC_PHYCFG1_RGMII_SND_STAT_EN);
+ if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE) {
+ if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN)
+ val |= MAC_PHYCFG1_RGMII_EXT_RX_DEC;
+ if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN)
+ val |= MAC_PHYCFG1_RGMII_SND_STAT_EN;
+ }
+ tw32(MAC_PHYCFG1, val | MAC_PHYCFG1_RGMII_INT | MAC_PHYCFG1_TXC_DRV);
+
+ val = tr32(MAC_PHYCFG2) & ~(MAC_PHYCFG2_INBAND_ENABLE);
+ if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE))
+ val |= MAC_PHYCFG2_INBAND_ENABLE;
+ tw32(MAC_PHYCFG2, val);
+
+ val = tr32(MAC_EXT_RGMII_MODE);
+ val &= ~(MAC_RGMII_MODE_RX_INT_B |
+ MAC_RGMII_MODE_RX_QUALITY |
+ MAC_RGMII_MODE_RX_ACTIVITY |
+ MAC_RGMII_MODE_RX_ENG_DET |
+ MAC_RGMII_MODE_TX_ENABLE |
+ MAC_RGMII_MODE_TX_LOWPWR |
+ MAC_RGMII_MODE_TX_RESET);
+ if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE) {
+ if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN)
+ val |= MAC_RGMII_MODE_RX_INT_B |
+ MAC_RGMII_MODE_RX_QUALITY |
+ MAC_RGMII_MODE_RX_ACTIVITY |
+ MAC_RGMII_MODE_RX_ENG_DET;
+ if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN)
+ val |= MAC_RGMII_MODE_TX_ENABLE |
+ MAC_RGMII_MODE_TX_LOWPWR |
+ MAC_RGMII_MODE_TX_RESET;
+ }
+ tw32(MAC_EXT_RGMII_MODE, val);
+}
+
+static void tg3_mdio_start(struct tg3 *tp)
+{
+ if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) {
+ mutex_lock(&tp->mdio_bus.mdio_lock);
+ tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_PAUSED;
+ mutex_unlock(&tp->mdio_bus.mdio_lock);
+ }
+
+ tp->mi_mode &= ~MAC_MI_MODE_AUTO_POLL;
+ tw32_f(MAC_MI_MODE, tp->mi_mode);
+ udelay(80);
+
+ if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED)
+ tg3_mdio_config(tp);
+}
+
+static void tg3_mdio_stop(struct tg3 *tp)
+{
+ if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) {
+ mutex_lock(&tp->mdio_bus.mdio_lock);
+ tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_PAUSED;
+ mutex_unlock(&tp->mdio_bus.mdio_lock);
+ }
+}
+
+static int tg3_mdio_init(struct tg3 *tp)
+{
+ int i;
+ u32 reg;
+ struct phy_device *phydev;
+ struct mii_bus *mdio_bus = &tp->mdio_bus;
+
+ tg3_mdio_start(tp);
+
+ if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) ||
+ (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED))
+ return 0;
+
+ memset(mdio_bus, 0, sizeof(*mdio_bus));
+
+ mdio_bus->name = "tg3 mdio bus";
+ snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%x",
+ (tp->pdev->bus->number << 8) | tp->pdev->devfn);
+ mdio_bus->priv = tp;
+ mdio_bus->dev = &tp->pdev->dev;
+ mdio_bus->read = &tg3_mdio_read;
+ mdio_bus->write = &tg3_mdio_write;
+ mdio_bus->reset = &tg3_mdio_reset;
+ mdio_bus->phy_mask = ~(1 << PHY_ADDR);
+ mdio_bus->irq = &tp->mdio_irq[0];
+
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ mdio_bus->irq[i] = PHY_POLL;
+
+ /* The bus registration will look for all the PHYs on the mdio bus.
+ * Unfortunately, it does not ensure the PHY is powered up before
+ * accessing the PHY ID registers. A chip reset is the
+ * quickest way to bring the device back to an operational state..
+ */
+ if (tg3_readphy(tp, MII_BMCR, ®) || (reg & BMCR_PDOWN))
+ tg3_bmcr_reset(tp);
+
+ i = mdiobus_register(mdio_bus);
+ if (i) {
+ printk(KERN_WARNING "%s: mdiobus_reg failed (0x%x)\n",
+ tp->dev->name, i);
+ return i;
+ }
+
+ tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_INITED;
+
+ phydev = tp->mdio_bus.phy_map[PHY_ADDR];
+
+ switch (phydev->phy_id) {
+ case TG3_PHY_ID_BCM50610:
+ phydev->interface = PHY_INTERFACE_MODE_RGMII;
+ if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE)
+ phydev->dev_flags |= PHY_BRCM_STD_IBND_DISABLE;
+ if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN)
+ phydev->dev_flags |= PHY_BRCM_EXT_IBND_RX_ENABLE;
+ if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN)
+ phydev->dev_flags |= PHY_BRCM_EXT_IBND_TX_ENABLE;
+ break;
+ case TG3_PHY_ID_BCMAC131:
+ phydev->interface = PHY_INTERFACE_MODE_MII;
+ break;
+ }
+
+ tg3_mdio_config(tp);
+
+ return 0;
+}
+
+static void tg3_mdio_fini(struct tg3 *tp)
+{
+ if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) {
+ tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_INITED;
+ mdiobus_unregister(&tp->mdio_bus);
+ tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_PAUSED;
+ }
+}
+
+/* tp->lock is held. */
+static void tg3_wait_for_event_ack(struct tg3 *tp)
+{
+ int i;
+
+ /* Wait for up to 2.5 milliseconds */
+ for (i = 0; i < 250000; i++) {
+ if (!(tr32(GRC_RX_CPU_EVENT) & GRC_RX_CPU_DRIVER_EVENT))
+ break;
+ udelay(10);
+ }
+}
+
+/* tp->lock is held. */
+static void tg3_ump_link_report(struct tg3 *tp)
+{
+ u32 reg;
+ u32 val;
+
+ if (!(tp->tg3_flags2 & TG3_FLG2_5780_CLASS) ||
+ !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
+ return;
+
+ tg3_wait_for_event_ack(tp);
+
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_LINK_UPDATE);
+
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 14);
+
+ val = 0;
+ if (!tg3_readphy(tp, MII_BMCR, ®))
+ val = reg << 16;
+ if (!tg3_readphy(tp, MII_BMSR, ®))
+ val |= (reg & 0xffff);
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, val);
+
+ val = 0;
+ if (!tg3_readphy(tp, MII_ADVERTISE, ®))
+ val = reg << 16;
+ if (!tg3_readphy(tp, MII_LPA, ®))
+ val |= (reg & 0xffff);
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 4, val);
+
+ val = 0;
+ if (!(tp->tg3_flags2 & TG3_FLG2_MII_SERDES)) {
+ if (!tg3_readphy(tp, MII_CTRL1000, ®))
+ val = reg << 16;
+ if (!tg3_readphy(tp, MII_STAT1000, ®))
+ val |= (reg & 0xffff);
+ }
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 8, val);
+
+ if (!tg3_readphy(tp, MII_PHYADDR, ®))
+ val = reg << 16;
+ else
+ val = 0;
+ tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 12, val);
+
+ val = tr32(GRC_RX_CPU_EVENT);
+ val |= GRC_RX_CPU_DRIVER_EVENT;
+ tw32_f(GRC_RX_CPU_EVENT, val);
+}
+
+static void tg3_link_report(struct tg3 *tp)
+{
+ if (!netif_carrier_ok(tp->dev)) {
+ if (netif_msg_link(tp))
+ printk(KERN_INFO PFX "%s: Link is down.\n",
+ tp->dev->name);
+ tg3_ump_link_report(tp);
+ } else if (netif_msg_link(tp)) {
+ printk(KERN_INFO PFX "%s: Link is up at %d Mbps, %s duplex.\n",
+ tp->dev->name,
+ (tp->link_config.active_speed == SPEED_1000 ?
+ 1000 :
+ (tp->link_config.active_speed == SPEED_100 ?
+ 100 : 10)),
+ (tp->link_config.active_duplex == DUPLEX_FULL ?
+ "full" : "half"));
+
+ printk(KERN_INFO PFX
+ "%s: Flow control is %s for TX and %s for RX.\n",
+ tp->dev->name,
+ (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_TX) ?
+ "on" : "off",
+ (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX) ?
+ "on" : "off");
+ tg3_ump_link_report(tp);
+ }
+}
+
+static u16 tg3_advert_flowctrl_1000T(u8 flow_ctrl)
+{
+ u16 miireg;
+
+ if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX))
+ miireg = ADVERTISE_PAUSE_CAP;
+ else if (flow_ctrl & TG3_FLOW_CTRL_TX)
+ miireg = ADVERTISE_PAUSE_ASYM;
+ else if (flow_ctrl & TG3_FLOW_CTRL_RX)
+ miireg = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+ else
+ miireg = 0;
+
+ return miireg;
+}
+
+static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl)
+{
+ u16 miireg;
+
+ if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX))
+ miireg = ADVERTISE_1000XPAUSE;
+ else if (flow_ctrl & TG3_FLOW_CTRL_TX)
+ miireg = ADVERTISE_1000XPSE_ASYM;
+ else if (flow_ctrl & TG3_FLOW_CTRL_RX)
+ miireg = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
+ else
+ miireg = 0;
+
+ return miireg;
+}
+
+static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv)
+{
+ u8 cap = 0;
+
+ if (lcladv & ADVERTISE_PAUSE_CAP) {
+ if (lcladv & ADVERTISE_PAUSE_ASYM) {
+ if (rmtadv & LPA_PAUSE_CAP)
+ cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+ else if (rmtadv & LPA_PAUSE_ASYM)
+ cap = TG3_FLOW_CTRL_RX;
+ } else {
+ if (rmtadv & LPA_PAUSE_CAP)
+ cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+ }
+ } else if (lcladv & ADVERTISE_PAUSE_ASYM) {
+ if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM))
+ cap = TG3_FLOW_CTRL_TX;
+ }
+
+ return cap;
+}
+
+static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv)
+{
+ u8 cap = 0;
+
+ if (lcladv & ADVERTISE_1000XPAUSE) {
+ if (lcladv & ADVERTISE_1000XPSE_ASYM) {
+ if (rmtadv & LPA_1000XPAUSE)
+ cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+ else if (rmtadv & LPA_1000XPAUSE_ASYM)
+ cap = TG3_FLOW_CTRL_RX;
+ } else {
+ if (rmtadv & LPA_1000XPAUSE)
+ cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+ }
+ } else if (lcladv & ADVERTISE_1000XPSE_ASYM) {
+ if ((rmtadv & LPA_1000XPAUSE) && (rmtadv & LPA_1000XPAUSE_ASYM))
+ cap = TG3_FLOW_CTRL_TX;
+ }
+
+ return cap;
+}
+
+static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv)
+{
+ u8 autoneg;
+ u8 flowctrl = 0;
+ u32 old_rx_mode = tp->rx_mode;
+ u32 old_tx_mode = tp->tx_mode;
+
+ if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)
+ autoneg = tp->mdio_bus.phy_map[PHY_ADDR]->autoneg;
+ else
+ autoneg = tp->link_config.autoneg;
+
+ if (autoneg == AUTONEG_ENABLE &&
+ (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) {
+ if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)
+ flowctrl = tg3_resolve_flowctrl_1000X(lcladv, rmtadv);
+ else
+ flowctrl = tg3_resolve_flowctrl_1000T(lcladv, rmtadv);
+ } else
+ flowctrl = tp->link_config.flowctrl;
+
+ tp->link_config.active_flowctrl = flowctrl;
+
+ if (flowctrl & TG3_FLOW_CTRL_RX)
+ tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE;
+ else
+ tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE;
+
+ if (old_rx_mode != tp->rx_mode)
+ tw32_f(MAC_RX_MODE, tp->rx_mode);
+
+ if (flowctrl & TG3_FLOW_CTRL_TX)
+ tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE;
+ else
+ tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE;
+
+ if (old_tx_mode != tp->tx_mode)
+ tw32_f(MAC_TX_MODE, tp->tx_mode);
+}
+
+static void tg3_adjust_link(struct net_device *dev)
+{
+ u8 oldflowctrl, linkmesg = 0;
+ u32 mac_mode, lcl_adv, rmt_adv;
+ struct tg3 *tp = netdev_priv(dev);
+ struct phy_device *phydev = tp->mdio_bus.phy_map[PHY_ADDR];
+
+ spin_lock(&tp->lock);
+
+ mac_mode = tp->mac_mode & ~(MAC_MODE_PORT_MODE_MASK |
+ MAC_MODE_HALF_DUPLEX);
+
+ oldflowctrl = tp->link_config.active_flowctrl;
+
+ if (phydev->link) {
+ lcl_adv = 0;
+ rmt_adv = 0;
+
+ if (phydev->speed == SPEED_100 || phydev->speed == SPEED_10)
+ mac_mode |= MAC_MODE_PORT_MODE_MII;
+ else
+ mac_mode |= MAC_MODE_PORT_MODE_GMII;
+
+ if (phydev->duplex == DUPLEX_HALF)
+ mac_mode |= MAC_MODE_HALF_DUPLEX;
+ else {
+ lcl_adv = tg3_advert_flowctrl_1000T(
+ tp->link_config.flowctrl);
+
+ if (phydev->pause)
+ rmt_adv = LPA_PAUSE_CAP;
+ if (phydev->asym_pause)
+ rmt_adv |= LPA_PAUSE_ASYM;
+ }
+
+ tg3_setup_flow_control(tp, lcl_adv, rmt_adv);
+ } else
+ mac_mode |= MAC_MODE_PORT_MODE_GMII;
+
+ if (mac_mode != tp->mac_mode) {
+ tp->mac_mode = mac_mode;
+ tw32_f(MAC_MODE, tp->mac_mode);
+ udelay(40);
+ }
+
+ if (phydev->speed == SPEED_1000 && phydev->duplex == DUPLEX_HALF)
+ tw32(MAC_TX_LENGTHS,
+ ((2 << TX_LENGTHS_IPG_CRS_SHIFT) |
+ (6 << TX_LENGTHS_IPG_SHIFT) |
+ (0xff << TX_LENGTHS_SLOT_TIME_SHIFT)));
+ else
+ tw32(MAC_TX_LENGTHS,
+ ((2 << TX_LENGTHS_IPG_CRS_SHIFT) |
+ (6 << TX_LENGTHS_IPG_SHIFT) |
+ (32 << TX_LENGTHS_SLOT_TIME_SHIFT)));
+
+ if ((phydev->link && tp->link_config.active_speed == SPEED_INVALID) ||
+ (!phydev->link && tp->link_config.active_speed != SPEED_INVALID) ||
+ phydev->speed != tp->link_config.active_speed ||
+ phydev->duplex != tp->link_config.active_duplex ||
+ oldflowctrl != tp->link_config.active_flowctrl)
+ linkmesg = 1;
+
+ tp->link_config.active_speed = phydev->speed;
+ tp->link_config.active_duplex = phydev->duplex;
+
+ spin_unlock(&tp->lock);
+
+ if (linkmesg)
+ tg3_link_report(tp);
+}
+
+static int tg3_phy_init(struct tg3 *tp)
+{
+ struct phy_device *phydev;
+
+ if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED)
+ return 0;
+
+ /* Bring the PHY back to a known state. */
+ tg3_bmcr_reset(tp);
+
+ phydev = tp->mdio_bus.phy_map[PHY_ADDR];
+
+ /* Attach the MAC to the PHY. */
+ phydev = phy_connect(tp->dev, phydev->dev.bus_id, tg3_adjust_link,
+ phydev->dev_flags, phydev->interface);
+ if (IS_ERR(phydev)) {
+ printk(KERN_ERR "%s: Could not attach to PHY\n", tp->dev->name);
+ return PTR_ERR(phydev);
+ }
+
+ tp->tg3_flags3 |= TG3_FLG3_PHY_CONNECTED;
+
+ /* Mask with MAC supported features. */
+ phydev->supported &= (PHY_GBIT_FEATURES |
+ SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause);
+
+ phydev->advertising = phydev->supported;
+
+ printk(KERN_INFO
+ "%s: attached PHY driver [%s] (mii_bus:phy_addr=%s)\n",
+ tp->dev->name, phydev->drv->name, phydev->dev.bus_id);
+
+ return 0;
+}
+
+static void tg3_phy_start(struct tg3 *tp)
+{
+ struct phy_device *phydev;
+
+ if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+ return;
+
+ phydev = tp->mdio_bus.phy_map[PHY_ADDR];
+
+ if (tp->link_config.phy_is_low_power) {
+ tp->link_config.phy_is_low_power = 0;
+ phydev->speed = tp->link_config.orig_speed;
+ phydev->duplex = tp->link_config.orig_duplex;
+ phydev->autoneg = tp->link_config.orig_autoneg;
+ phydev->advertising = tp->link_config.orig_advertising;
+ }
+
+ phy_start(phydev);
+
+ phy_start_aneg(phydev);
+}
+
+static void tg3_phy_stop(struct tg3 *tp)
+{
+ if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+ return;
+
+ phy_stop(tp->mdio_bus.phy_map[PHY_ADDR]);
+}
+
+static void tg3_phy_fini(struct tg3 *tp)
+{
+ if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) {
+ phy_disconnect(tp->mdio_bus.phy_map[PHY_ADDR]);
+ tp->tg3_flags3 &= ~TG3_FLG3_PHY_CONNECTED;
+ }
+}
+
static void tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val)
{
tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg);
@@ -861,37 +1427,6 @@
(val | (1 << 15) | (1 << 4)));
}
-static int tg3_bmcr_reset(struct tg3 *tp)
-{
- u32 phy_control;
- int limit, err;
-
- /* OK, reset it, and poll the BMCR_RESET bit until it
- * clears or we time out.
- */
- phy_control = BMCR_RESET;
- err = tg3_writephy(tp, MII_BMCR, phy_control);
- if (err != 0)
- return -EBUSY;
-
- limit = 5000;
- while (limit--) {
- err = tg3_readphy(tp, MII_BMCR, &phy_control);
- if (err != 0)
- return -EBUSY;
-
- if ((phy_control & BMCR_RESET) == 0) {
- udelay(40);
- break;
- }
- udelay(10);
- }
- if (limit <= 0)
- return -EBUSY;
-
- return 0;
-}
-
static void tg3_phy_apply_otp(struct tg3 *tp)
{
u32 otp, phy;
@@ -1115,8 +1650,6 @@
return err;
}
-static void tg3_link_report(struct tg3 *);
-
/* This will reset the tigon3 PHY if there is no valid
* link unless the FORCE argument is non-zero.
*/
@@ -1421,7 +1954,7 @@
tw32_f(GRC_MISC_CFG, val | GRC_MISC_CFG_EPHY_IDDQ);
udelay(40);
return;
- } else {
+ } else if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) {
tg3_writephy(tp, MII_TG3_EXT_CTRL,
MII_TG3_EXT_CTRL_FORCE_LED_OFF);
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x01b2);
@@ -1495,7 +2028,7 @@
"requested.\n",
tp->dev->name, state);
return -EINVAL;
- };
+ }
power_control |= PCI_PM_CTRL_PME_ENABLE;
@@ -1503,18 +2036,55 @@
tw32(TG3PCI_MISC_HOST_CTRL,
misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT);
- if (tp->link_config.phy_is_low_power == 0) {
- tp->link_config.phy_is_low_power = 1;
- tp->link_config.orig_speed = tp->link_config.speed;
- tp->link_config.orig_duplex = tp->link_config.duplex;
- tp->link_config.orig_autoneg = tp->link_config.autoneg;
- }
+ if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+ if ((tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) &&
+ !tp->link_config.phy_is_low_power) {
+ struct phy_device *phydev;
+ u32 advertising;
- if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) {
- tp->link_config.speed = SPEED_10;
- tp->link_config.duplex = DUPLEX_HALF;
- tp->link_config.autoneg = AUTONEG_ENABLE;
- tg3_setup_phy(tp, 0);
+ phydev = tp->mdio_bus.phy_map[PHY_ADDR];
+
+ tp->link_config.phy_is_low_power = 1;
+
+ tp->link_config.orig_speed = phydev->speed;
+ tp->link_config.orig_duplex = phydev->duplex;
+ tp->link_config.orig_autoneg = phydev->autoneg;
+ tp->link_config.orig_advertising = phydev->advertising;
+
+ advertising = ADVERTISED_TP |
+ ADVERTISED_Pause |
+ ADVERTISED_Autoneg |
+ ADVERTISED_10baseT_Half;
+
+ if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
+ (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)) {
+ if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB)
+ advertising |=
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_10baseT_Full;
+ else
+ advertising |= ADVERTISED_10baseT_Full;
+ }
+
+ phydev->advertising = advertising;
+
+ phy_start_aneg(phydev);
+ }
+ } else {
+ if (tp->link_config.phy_is_low_power == 0) {
+ tp->link_config.phy_is_low_power = 1;
+ tp->link_config.orig_speed = tp->link_config.speed;
+ tp->link_config.orig_duplex = tp->link_config.duplex;
+ tp->link_config.orig_autoneg = tp->link_config.autoneg;
+ }
+
+ if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)) {
+ tp->link_config.speed = SPEED_10;
+ tp->link_config.duplex = DUPLEX_HALF;
+ tp->link_config.autoneg = AUTONEG_ENABLE;
+ tg3_setup_phy(tp, 0);
+ }
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
@@ -1545,8 +2115,10 @@
u32 mac_mode;
if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
- tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a);
- udelay(40);
+ if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) {
+ tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a);
+ udelay(40);
+ }
if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
mac_mode = MAC_MODE_PORT_MODE_GMII;
@@ -1671,212 +2243,6 @@
return 0;
}
-/* tp->lock is held. */
-static void tg3_wait_for_event_ack(struct tg3 *tp)
-{
- int i;
-
- /* Wait for up to 2.5 milliseconds */
- for (i = 0; i < 250000; i++) {
- if (!(tr32(GRC_RX_CPU_EVENT) & GRC_RX_CPU_DRIVER_EVENT))
- break;
- udelay(10);
- }
-}
-
-/* tp->lock is held. */
-static void tg3_ump_link_report(struct tg3 *tp)
-{
- u32 reg;
- u32 val;
-
- if (!(tp->tg3_flags2 & TG3_FLG2_5780_CLASS) ||
- !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
- return;
-
- tg3_wait_for_event_ack(tp);
-
- tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_LINK_UPDATE);
-
- tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 14);
-
- val = 0;
- if (!tg3_readphy(tp, MII_BMCR, ®))
- val = reg << 16;
- if (!tg3_readphy(tp, MII_BMSR, ®))
- val |= (reg & 0xffff);
- tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, val);
-
- val = 0;
- if (!tg3_readphy(tp, MII_ADVERTISE, ®))
- val = reg << 16;
- if (!tg3_readphy(tp, MII_LPA, ®))
- val |= (reg & 0xffff);
- tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 4, val);
-
- val = 0;
- if (!(tp->tg3_flags2 & TG3_FLG2_MII_SERDES)) {
- if (!tg3_readphy(tp, MII_CTRL1000, ®))
- val = reg << 16;
- if (!tg3_readphy(tp, MII_STAT1000, ®))
- val |= (reg & 0xffff);
- }
- tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 8, val);
-
- if (!tg3_readphy(tp, MII_PHYADDR, ®))
- val = reg << 16;
- else
- val = 0;
- tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 12, val);
-
- val = tr32(GRC_RX_CPU_EVENT);
- val |= GRC_RX_CPU_DRIVER_EVENT;
- tw32_f(GRC_RX_CPU_EVENT, val);
-}
-
-static void tg3_link_report(struct tg3 *tp)
-{
- if (!netif_carrier_ok(tp->dev)) {
- if (netif_msg_link(tp))
- printk(KERN_INFO PFX "%s: Link is down.\n",
- tp->dev->name);
- tg3_ump_link_report(tp);
- } else if (netif_msg_link(tp)) {
- printk(KERN_INFO PFX "%s: Link is up at %d Mbps, %s duplex.\n",
- tp->dev->name,
- (tp->link_config.active_speed == SPEED_1000 ?
- 1000 :
- (tp->link_config.active_speed == SPEED_100 ?
- 100 : 10)),
- (tp->link_config.active_duplex == DUPLEX_FULL ?
- "full" : "half"));
-
- printk(KERN_INFO PFX
- "%s: Flow control is %s for TX and %s for RX.\n",
- tp->dev->name,
- (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_TX) ?
- "on" : "off",
- (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX) ?
- "on" : "off");
- tg3_ump_link_report(tp);
- }
-}
-
-static u16 tg3_advert_flowctrl_1000T(u8 flow_ctrl)
-{
- u16 miireg;
-
- if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX))
- miireg = ADVERTISE_PAUSE_CAP;
- else if (flow_ctrl & TG3_FLOW_CTRL_TX)
- miireg = ADVERTISE_PAUSE_ASYM;
- else if (flow_ctrl & TG3_FLOW_CTRL_RX)
- miireg = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
- else
- miireg = 0;
-
- return miireg;
-}
-
-static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl)
-{
- u16 miireg;
-
- if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX))
- miireg = ADVERTISE_1000XPAUSE;
- else if (flow_ctrl & TG3_FLOW_CTRL_TX)
- miireg = ADVERTISE_1000XPSE_ASYM;
- else if (flow_ctrl & TG3_FLOW_CTRL_RX)
- miireg = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
- else
- miireg = 0;
-
- return miireg;
-}
-
-static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv)
-{
- u8 cap = 0;
-
- if (lcladv & ADVERTISE_PAUSE_CAP) {
- if (lcladv & ADVERTISE_PAUSE_ASYM) {
- if (rmtadv & LPA_PAUSE_CAP)
- cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
- else if (rmtadv & LPA_PAUSE_ASYM)
- cap = TG3_FLOW_CTRL_RX;
- } else {
- if (rmtadv & LPA_PAUSE_CAP)
- cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
- }
- } else if (lcladv & ADVERTISE_PAUSE_ASYM) {
- if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM))
- cap = TG3_FLOW_CTRL_TX;
- }
-
- return cap;
-}
-
-static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv)
-{
- u8 cap = 0;
-
- if (lcladv & ADVERTISE_1000XPAUSE) {
- if (lcladv & ADVERTISE_1000XPSE_ASYM) {
- if (rmtadv & LPA_1000XPAUSE)
- cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
- else if (rmtadv & LPA_1000XPAUSE_ASYM)
- cap = TG3_FLOW_CTRL_RX;
- } else {
- if (rmtadv & LPA_1000XPAUSE)
- cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
- }
- } else if (lcladv & ADVERTISE_1000XPSE_ASYM) {
- if ((rmtadv & LPA_1000XPAUSE) && (rmtadv & LPA_1000XPAUSE_ASYM))
- cap = TG3_FLOW_CTRL_TX;
- }
-
- return cap;
-}
-
-static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv)
-{
- u8 new_tg3_flags = 0;
- u32 old_rx_mode = tp->rx_mode;
- u32 old_tx_mode = tp->tx_mode;
-
- if (tp->link_config.autoneg == AUTONEG_ENABLE &&
- (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) {
- if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)
- new_tg3_flags = tg3_resolve_flowctrl_1000X(local_adv,
- remote_adv);
- else
- new_tg3_flags = tg3_resolve_flowctrl_1000T(local_adv,
- remote_adv);
- } else {
- new_tg3_flags = tp->link_config.flowctrl;
- }
-
- tp->link_config.active_flowctrl = new_tg3_flags;
-
- if (new_tg3_flags & TG3_FLOW_CTRL_RX)
- tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE;
- else
- tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE;
-
- if (old_rx_mode != tp->rx_mode) {
- tw32_f(MAC_RX_MODE, tp->rx_mode);
- }
-
- if (new_tg3_flags & TG3_FLOW_CTRL_TX)
- tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE;
- else
- tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE;
-
- if (old_tx_mode != tp->tx_mode) {
- tw32_f(MAC_TX_MODE, tp->tx_mode);
- }
-}
-
static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8 *duplex)
{
switch (val & MII_TG3_AUX_STAT_SPDMASK) {
@@ -1921,7 +2287,7 @@
*speed = SPEED_INVALID;
*duplex = DUPLEX_INVALID;
break;
- };
+ }
}
static void tg3_phy_copper_begin(struct tg3 *tp)
@@ -2033,7 +2399,7 @@
case SPEED_1000:
bmcr |= TG3_BMCR_SPEED1000;
break;
- };
+ }
if (tp->link_config.duplex == DUPLEX_FULL)
bmcr |= BMCR_FULLDPLX;
@@ -2731,7 +3097,7 @@
default:
ret = ANEG_FAILED;
break;
- };
+ }
return ret;
}
@@ -3572,7 +3938,7 @@
default:
return -EINVAL;
- };
+ }
/* Do not overwrite any of the map or rp information
* until we are sure we can commit to a new buffer.
@@ -3632,7 +3998,7 @@
default:
return;
- };
+ }
dest_map->skb = src_map->skb;
pci_unmap_addr_set(dest_map, mapping,
@@ -3842,7 +4208,15 @@
sblk->status = SD_STATUS_UPDATED |
(sblk->status & ~SD_STATUS_LINK_CHG);
spin_lock(&tp->lock);
- tg3_setup_phy(tp, 0);
+ if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+ tw32_f(MAC_STATUS,
+ (MAC_STATUS_SYNC_CHANGED |
+ MAC_STATUS_CFG_CHANGED |
+ MAC_STATUS_MI_COMPLETION |
+ MAC_STATUS_LNKSTATE_CHANGED));
+ udelay(40);
+ } else
+ tg3_setup_phy(tp, 0);
spin_unlock(&tp->lock);
}
}
@@ -4130,6 +4504,7 @@
static void tg3_reset_task(struct work_struct *work)
{
struct tg3 *tp = container_of(work, struct tg3, reset_task);
+ int err;
unsigned int restart_timer;
tg3_full_lock(tp, 0);
@@ -4141,6 +4516,8 @@
tg3_full_unlock(tp);
+ tg3_phy_stop(tp);
+
tg3_netif_stop(tp);
tg3_full_lock(tp, 1);
@@ -4156,7 +4533,8 @@
}
tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
- if (tg3_init_hw(tp, 1))
+ err = tg3_init_hw(tp, 1);
+ if (err)
goto out;
tg3_netif_start(tp);
@@ -4166,6 +4544,9 @@
out:
tg3_full_unlock(tp);
+
+ if (!err)
+ tg3_phy_start(tp);
}
static void tg3_dump_short_state(struct tg3 *tp)
@@ -4669,6 +5050,8 @@
return 0;
}
+ tg3_phy_stop(tp);
+
tg3_netif_stop(tp);
tg3_full_lock(tp, 1);
@@ -4684,6 +5067,9 @@
tg3_full_unlock(tp);
+ if (!err)
+ tg3_phy_start(tp);
+
return err;
}
@@ -4975,7 +5361,7 @@
default:
break;
- };
+ }
}
val = tr32(ofs);
@@ -5217,7 +5603,7 @@
default:
break;
- };
+ }
}
if (kind == RESET_KIND_INIT ||
@@ -5242,7 +5628,7 @@
default:
break;
- };
+ }
}
if (kind == RESET_KIND_SHUTDOWN)
@@ -5271,7 +5657,7 @@
default:
break;
- };
+ }
}
}
@@ -5393,6 +5779,8 @@
tg3_nvram_lock(tp);
+ tg3_mdio_stop(tp);
+
/* No matching tg3_nvram_unlock() after this because
* chip reset below will undo the nvram lock.
*/
@@ -5408,7 +5796,8 @@
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
tw32(GRC_FASTBOOT_PC, 0);
/*
@@ -5544,6 +5933,8 @@
tw32_f(MAC_MODE, 0);
udelay(40);
+ tg3_mdio_start(tp);
+
err = tg3_poll_fw(tp);
if (err)
return err;
@@ -6623,7 +7014,8 @@
tg3_abort_hw(tp, 1);
}
- if (reset_phy)
+ if (reset_phy &&
+ !(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB))
tg3_phy_reset(tp);
err = tg3_chip_reset(tp);
@@ -6699,7 +7091,8 @@
return err;
if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) {
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) {
/* This value is determined during the probe time DMA
* engine test, tg3_test_dma.
*/
@@ -6938,7 +7331,8 @@
RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
RDMAC_MODE_LNGREAD_ENAB);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784)
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
rdmac_mode |= RDMAC_MODE_BD_SBD_CRPT_ENAB |
RDMAC_MODE_MBUF_RBD_CRPT_ENAB |
RDMAC_MODE_MBUF_SBD_CRPT_ENAB;
@@ -7106,8 +7500,9 @@
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) ||
(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) ||
(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) ||
- (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761))
- val |= (1 << 29);
+ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) ||
+ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785))
+ val |= WDMAC_MODE_STATUS_TAG_FIX;
tw32_f(WDMAC_MODE, val);
udelay(40);
@@ -7168,23 +7563,14 @@
tp->rx_mode = RX_MODE_ENABLE;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
tp->rx_mode |= RX_MODE_IPV6_CSUM_ENABLE;
tw32_f(MAC_RX_MODE, tp->rx_mode);
udelay(10);
- if (tp->link_config.phy_is_low_power) {
- tp->link_config.phy_is_low_power = 0;
- tp->link_config.speed = tp->link_config.orig_speed;
- tp->link_config.duplex = tp->link_config.orig_duplex;
- tp->link_config.autoneg = tp->link_config.orig_autoneg;
- }
-
- tp->mi_mode &= ~MAC_MI_MODE_AUTO_POLL;
- tw32_f(MAC_MI_MODE, tp->mi_mode);
- udelay(80);
-
tw32(MAC_LED_CTRL, tp->led_ctrl);
tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB);
@@ -7231,19 +7617,28 @@
tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
}
- err = tg3_setup_phy(tp, 0);
- if (err)
- return err;
+ if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) {
+ if (tp->link_config.phy_is_low_power) {
+ tp->link_config.phy_is_low_power = 0;
+ tp->link_config.speed = tp->link_config.orig_speed;
+ tp->link_config.duplex = tp->link_config.orig_duplex;
+ tp->link_config.autoneg = tp->link_config.orig_autoneg;
+ }
- if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) {
- u32 tmp;
+ err = tg3_setup_phy(tp, 0);
+ if (err)
+ return err;
- /* Clear CRC stats. */
- if (!tg3_readphy(tp, MII_TG3_TEST1, &tmp)) {
- tg3_writephy(tp, MII_TG3_TEST1,
- tmp | MII_TG3_TEST1_CRC_EN);
- tg3_readphy(tp, 0x14, &tmp);
+ if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) {
+ u32 tmp;
+
+ /* Clear CRC stats. */
+ if (!tg3_readphy(tp, MII_TG3_TEST1, &tmp)) {
+ tg3_writephy(tp, MII_TG3_TEST1,
+ tmp | MII_TG3_TEST1_CRC_EN);
+ tg3_readphy(tp, 0x14, &tmp);
+ }
}
}
@@ -7296,7 +7691,7 @@
default:
break;
- };
+ }
if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
/* Write our heartbeat update interval to APE. */
@@ -7758,6 +8153,8 @@
}
}
+ tg3_phy_start(tp);
+
tg3_full_lock(tp, 0);
add_timer(&tp->timer);
@@ -8559,7 +8956,13 @@
static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
- struct tg3 *tp = netdev_priv(dev);
+ struct tg3 *tp = netdev_priv(dev);
+
+ if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+ if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+ return -EAGAIN;
+ return phy_ethtool_gset(tp->mdio_bus.phy_map[PHY_ADDR], cmd);
+ }
cmd->supported = (SUPPORTED_Autoneg);
@@ -8596,6 +8999,12 @@
{
struct tg3 *tp = netdev_priv(dev);
+ if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+ if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+ return -EAGAIN;
+ return phy_ethtool_sset(tp->mdio_bus.phy_map[PHY_ADDR], cmd);
+ }
+
if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) {
/* These are the only valid advertisement bits allowed. */
if (cmd->autoneg == AUTONEG_ENABLE &&
@@ -8628,7 +9037,7 @@
tp->link_config.advertising = 0;
tp->link_config.speed = cmd->speed;
tp->link_config.duplex = cmd->duplex;
- }
+ }
tp->link_config.orig_speed = tp->link_config.speed;
tp->link_config.orig_duplex = tp->link_config.duplex;
@@ -8711,7 +9120,10 @@
(GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) {
if (value) {
dev->features |= NETIF_F_TSO6;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
+ GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
dev->features |= NETIF_F_TSO_ECN;
} else
dev->features &= ~(NETIF_F_TSO6 | NETIF_F_TSO_ECN);
@@ -8722,7 +9134,6 @@
static int tg3_nway_reset(struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
- u32 bmcr;
int r;
if (!netif_running(dev))
@@ -8731,17 +9142,25 @@
if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
return -EINVAL;
- spin_lock_bh(&tp->lock);
- r = -EINVAL;
- tg3_readphy(tp, MII_BMCR, &bmcr);
- if (!tg3_readphy(tp, MII_BMCR, &bmcr) &&
- ((bmcr & BMCR_ANENABLE) ||
- (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT))) {
- tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART |
- BMCR_ANENABLE);
- r = 0;
+ if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+ if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+ return -EAGAIN;
+ r = phy_start_aneg(tp->mdio_bus.phy_map[PHY_ADDR]);
+ } else {
+ u32 bmcr;
+
+ spin_lock_bh(&tp->lock);
+ r = -EINVAL;
+ tg3_readphy(tp, MII_BMCR, &bmcr);
+ if (!tg3_readphy(tp, MII_BMCR, &bmcr) &&
+ ((bmcr & BMCR_ANENABLE) ||
+ (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT))) {
+ tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART |
+ BMCR_ANENABLE);
+ r = 0;
+ }
+ spin_unlock_bh(&tp->lock);
}
- spin_unlock_bh(&tp->lock);
return r;
}
@@ -8783,6 +9202,7 @@
return -EINVAL;
if (netif_running(dev)) {
+ tg3_phy_stop(tp);
tg3_netif_stop(tp);
irq_sync = 1;
}
@@ -8806,6 +9226,9 @@
tg3_full_unlock(tp);
+ if (irq_sync && !err)
+ tg3_phy_start(tp);
+
return err;
}
@@ -8829,37 +9252,93 @@
static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
{
struct tg3 *tp = netdev_priv(dev);
- int irq_sync = 0, err = 0;
+ int err = 0;
- if (netif_running(dev)) {
- tg3_netif_stop(tp);
- irq_sync = 1;
+ if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+ if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+ return -EAGAIN;
+
+ if (epause->autoneg) {
+ u32 newadv;
+ struct phy_device *phydev;
+
+ phydev = tp->mdio_bus.phy_map[PHY_ADDR];
+
+ if (epause->rx_pause) {
+ if (epause->tx_pause)
+ newadv = ADVERTISED_Pause;
+ else
+ newadv = ADVERTISED_Pause |
+ ADVERTISED_Asym_Pause;
+ } else if (epause->tx_pause) {
+ newadv = ADVERTISED_Asym_Pause;
+ } else
+ newadv = 0;
+
+ if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) {
+ u32 oldadv = phydev->advertising &
+ (ADVERTISED_Pause |
+ ADVERTISED_Asym_Pause);
+ if (oldadv != newadv) {
+ phydev->advertising &=
+ ~(ADVERTISED_Pause |
+ ADVERTISED_Asym_Pause);
+ phydev->advertising |= newadv;
+ err = phy_start_aneg(phydev);
+ }
+ } else {
+ tp->link_config.advertising &=
+ ~(ADVERTISED_Pause |
+ ADVERTISED_Asym_Pause);
+ tp->link_config.advertising |= newadv;
+ }
+ } else {
+ if (epause->rx_pause)
+ tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX;
+ else
+ tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX;
+
+ if (epause->tx_pause)
+ tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX;
+ else
+ tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX;
+
+ if (netif_running(dev))
+ tg3_setup_flow_control(tp, 0, 0);
+ }
+ } else {
+ int irq_sync = 0;
+
+ if (netif_running(dev)) {
+ tg3_netif_stop(tp);
+ irq_sync = 1;
+ }
+
+ tg3_full_lock(tp, irq_sync);
+
+ if (epause->autoneg)
+ tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
+ else
+ tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG;
+ if (epause->rx_pause)
+ tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX;
+ else
+ tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX;
+ if (epause->tx_pause)
+ tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX;
+ else
+ tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX;
+
+ if (netif_running(dev)) {
+ tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
+ err = tg3_restart_hw(tp, 1);
+ if (!err)
+ tg3_netif_start(tp);
+ }
+
+ tg3_full_unlock(tp);
}
- tg3_full_lock(tp, irq_sync);
-
- if (epause->autoneg)
- tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
- else
- tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG;
- if (epause->rx_pause)
- tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX;
- else
- tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX;
- if (epause->tx_pause)
- tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX;
- else
- tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX;
-
- if (netif_running(dev)) {
- tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
- err = tg3_restart_hw(tp, 1);
- if (!err)
- tg3_netif_start(tp);
- }
-
- tg3_full_unlock(tp);
-
return err;
}
@@ -8902,7 +9381,8 @@
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
ethtool_op_set_tx_ipv6_csum(dev, data);
else
ethtool_op_set_tx_csum(dev, data);
@@ -9423,7 +9903,8 @@
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
mem_tbl = mem_tbl_5755;
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
mem_tbl = mem_tbl_5906;
@@ -9630,7 +10111,8 @@
return TG3_LOOPBACK_FAILED;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) {
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
int i;
u32 status;
@@ -9658,14 +10140,16 @@
err |= TG3_MAC_LOOPBACK_FAILED;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) {
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
tw32(TG3_CPMU_CTRL, cpmuctrl);
/* Release the mutex */
tw32(TG3_CPMU_MUTEX_GNT, CPMU_MUTEX_GNT_DRIVER);
}
- if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
+ if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
+ !(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) {
if (tg3_run_loopback(tp, TG3_PHY_LOOPBACK))
err |= TG3_PHY_LOOPBACK_FAILED;
}
@@ -9692,9 +10176,10 @@
data[1] = 1;
}
if (etest->flags & ETH_TEST_FL_OFFLINE) {
- int err, irq_sync = 0;
+ int err, err2 = 0, irq_sync = 0;
if (netif_running(dev)) {
+ tg3_phy_stop(tp);
tg3_netif_stop(tp);
irq_sync = 1;
}
@@ -9735,11 +10220,15 @@
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
if (netif_running(dev)) {
tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
- if (!tg3_restart_hw(tp, 1))
+ err2 = tg3_restart_hw(tp, 1);
+ if (!err2)
tg3_netif_start(tp);
}
tg3_full_unlock(tp);
+
+ if (irq_sync && !err2)
+ tg3_phy_start(tp);
}
if (tp->link_config.phy_is_low_power)
tg3_set_power_state(tp, PCI_D3hot);
@@ -9752,6 +10241,12 @@
struct tg3 *tp = netdev_priv(dev);
int err;
+ if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+ if (!(tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED))
+ return -EAGAIN;
+ return phy_mii_ioctl(tp->mdio_bus.phy_map[PHY_ADDR], data, cmd);
+ }
+
switch(cmd) {
case SIOCGMIIPHY:
data->phy_id = PHY_ADDR;
@@ -10294,7 +10789,8 @@
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
tg3_get_5755_nvram_info(tp);
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784)
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
tg3_get_5787_nvram_info(tp);
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
tg3_get_5761_nvram_info(tp);
@@ -10625,6 +11121,7 @@
(GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) &&
(GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784) &&
(GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) &&
+ (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) &&
(tp->nvram_jedecnum == JEDEC_ST) &&
(nvram_cmd & NVRAM_CMD_FIRST)) {
@@ -10807,7 +11304,7 @@
tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val);
if (val == NIC_SRAM_DATA_SIG_MAGIC) {
u32 nic_cfg, led_cfg;
- u32 nic_phy_id, ver, cfg2 = 0, eeprom_phy_id;
+ u32 nic_phy_id, ver, cfg2 = 0, cfg4 = 0, eeprom_phy_id;
int eeprom_phy_serdes = 0;
tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg);
@@ -10821,6 +11318,9 @@
(ver > 0) && (ver < 0x100))
tg3_read_mem(tp, NIC_SRAM_DATA_CFG_2, &cfg2);
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+ tg3_read_mem(tp, NIC_SRAM_DATA_CFG_4, &cfg4);
+
if ((nic_cfg & NIC_SRAM_DATA_CFG_PHY_TYPE_MASK) ==
NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER)
eeprom_phy_serdes = 1;
@@ -10893,7 +11393,7 @@
LED_CTRL_MODE_PHY_2);
break;
- };
+ }
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) &&
@@ -10945,6 +11445,13 @@
if (cfg3 & NIC_SRAM_ASPM_DEBOUNCE)
tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND;
}
+
+ if (cfg4 & NIC_SRAM_RGMII_STD_IBND_DISABLE)
+ tp->tg3_flags3 |= TG3_FLG3_RGMII_STD_IBND_DISABLE;
+ if (cfg4 & NIC_SRAM_RGMII_EXT_IBND_RX_EN)
+ tp->tg3_flags3 |= TG3_FLG3_RGMII_EXT_IBND_RX_EN;
+ if (cfg4 & NIC_SRAM_RGMII_EXT_IBND_TX_EN)
+ tp->tg3_flags3 |= TG3_FLG3_RGMII_EXT_IBND_TX_EN;
}
}
@@ -11003,6 +11510,9 @@
u32 hw_phy_id, hw_phy_id_masked;
int err;
+ if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)
+ return tg3_phy_init(tp);
+
/* Reading the PHY ID register can conflict with ASF
* firwmare access to the PHY hardware.
*/
@@ -11525,6 +12035,7 @@
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 ||
(tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
tp->tg3_flags2 |= TG3_FLG2_5750_PLUS;
@@ -11546,6 +12057,7 @@
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2;
tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI;
@@ -11558,14 +12070,8 @@
}
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755 &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787 &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761 &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
+ if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
+ (tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE;
pcie_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_EXP);
@@ -11754,7 +12260,8 @@
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) {
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT;
if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 ||
@@ -11847,7 +12354,8 @@
tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG;
if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5755M)
tp->tg3_flags2 |= TG3_FLG2_PHY_ADJUST_TRIM;
- } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
+ } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785)
tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG;
}
@@ -11858,8 +12366,7 @@
tp->phy_otp = TG3_OTP_DEFAULT;
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT)
tp->mi_mode = MAC_MI_MODE_500KHZ_CONST;
else
tp->mi_mode = MAC_MI_MODE_BASE;
@@ -11869,9 +12376,12 @@
GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX)
tp->coalesce_mode |= HOSTCC_MODE_32BYTE;
- /* Initialize MAC MI mode, polling disabled. */
- tw32_f(MAC_MI_MODE, tp->mi_mode);
- udelay(80);
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
+ tp->tg3_flags3 |= TG3_FLG3_USE_PHYLIB;
+
+ err = tg3_mdio_init(tp);
+ if (err)
+ return err;
/* Initialize data/descriptor byte/word swapping. */
val = tr32(GRC_MODE);
@@ -11952,6 +12462,7 @@
printk(KERN_ERR PFX "(%s) phy probe failed, err %d\n",
pci_name(tp->pdev), err);
/* ... but do not return immediately ... */
+ tg3_mdio_fini(tp);
}
tg3_read_partno(tp);
@@ -11999,6 +12510,7 @@
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
tp->dev->hard_start_xmit = tg3_start_xmit;
else
@@ -12201,7 +12713,7 @@
val |= (DMA_RWCTRL_READ_BNDRY_384_PCIX |
DMA_RWCTRL_WRITE_BNDRY_384_PCIX);
break;
- };
+ }
} else if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
switch (cacheline_size) {
case 16:
@@ -12218,7 +12730,7 @@
val &= ~DMA_RWCTRL_WRITE_BNDRY_DISAB_PCIE;
val |= DMA_RWCTRL_WRITE_BNDRY_128_PCIE;
break;
- };
+ }
} else {
switch (cacheline_size) {
case 16:
@@ -12262,7 +12774,7 @@
val |= (DMA_RWCTRL_READ_BNDRY_1024 |
DMA_RWCTRL_WRITE_BNDRY_1024);
break;
- };
+ }
}
out:
@@ -12622,7 +13134,7 @@
case PHY_ID_BCM8002: return "8002/serdes";
case 0: return "serdes";
default: return "unknown";
- };
+ }
}
static char * __devinit tg3_bus_string(struct tg3 *tp, char *str)
@@ -12923,7 +13435,10 @@
if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) &&
(GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906))
dev->features |= NETIF_F_TSO6;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
+ GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
dev->features |= NETIF_F_TSO_ECN;
}
@@ -12989,7 +13504,8 @@
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
dev->features |= NETIF_F_IPV6_CSUM;
tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
@@ -13071,6 +13587,12 @@
struct tg3 *tp = netdev_priv(dev);
flush_scheduled_work();
+
+ if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+ tg3_phy_fini(tp);
+ tg3_mdio_fini(tp);
+ }
+
unregister_netdev(dev);
if (tp->aperegs) {
iounmap(tp->aperegs);
@@ -13103,6 +13625,7 @@
return 0;
flush_scheduled_work();
+ tg3_phy_stop(tp);
tg3_netif_stop(tp);
del_timer_sync(&tp->timer);
@@ -13120,10 +13643,13 @@
err = tg3_set_power_state(tp, pci_choose_state(pdev, state));
if (err) {
+ int err2;
+
tg3_full_lock(tp, 0);
tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
- if (tg3_restart_hw(tp, 1))
+ err2 = tg3_restart_hw(tp, 1);
+ if (err2)
goto out;
tp->timer.expires = jiffies + tp->timer_offset;
@@ -13134,6 +13660,9 @@
out:
tg3_full_unlock(tp);
+
+ if (!err2)
+ tg3_phy_start(tp);
}
return err;
@@ -13171,6 +13700,9 @@
out:
tg3_full_unlock(tp);
+ if (!err)
+ tg3_phy_start(tp);
+
return err;
}
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 0404f93..df07842 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -128,6 +128,7 @@
#define ASIC_REV_USE_PROD_ID_REG 0x0f
#define ASIC_REV_5784 0x5784
#define ASIC_REV_5761 0x5761
+#define ASIC_REV_5785 0x5785
#define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8)
#define CHIPREV_5700_AX 0x70
#define CHIPREV_5700_BX 0x71
@@ -528,7 +529,23 @@
#define MAC_SERDES_CFG 0x00000590
#define MAC_SERDES_CFG_EDGE_SELECT 0x00001000
#define MAC_SERDES_STAT 0x00000594
-/* 0x598 --> 0x5b0 unused */
+/* 0x598 --> 0x5a0 unused */
+#define MAC_PHYCFG1 0x000005a0
+#define MAC_PHYCFG1_RGMII_INT 0x00000001
+#define MAC_PHYCFG1_RGMII_EXT_RX_DEC 0x02000000
+#define MAC_PHYCFG1_RGMII_SND_STAT_EN 0x04000000
+#define MAC_PHYCFG1_TXC_DRV 0x20000000
+#define MAC_PHYCFG2 0x000005a4
+#define MAC_PHYCFG2_INBAND_ENABLE 0x00000001
+#define MAC_EXT_RGMII_MODE 0x000005a8
+#define MAC_RGMII_MODE_TX_ENABLE 0x00000001
+#define MAC_RGMII_MODE_TX_LOWPWR 0x00000002
+#define MAC_RGMII_MODE_TX_RESET 0x00000004
+#define MAC_RGMII_MODE_RX_INT_B 0x00000100
+#define MAC_RGMII_MODE_RX_QUALITY 0x00000200
+#define MAC_RGMII_MODE_RX_ACTIVITY 0x00000400
+#define MAC_RGMII_MODE_RX_ENG_DET 0x00000800
+/* 0x5ac --> 0x5b0 unused */
#define SERDES_RX_CTRL 0x000005b0 /* 5780/5714 only */
#define SERDES_RX_SIG_DETECT 0x00000400
#define SG_DIG_CTRL 0x000005b0
@@ -1109,6 +1126,7 @@
#define WDMAC_MODE_FIFOOREAD_ENAB 0x00000100
#define WDMAC_MODE_LNGREAD_ENAB 0x00000200
#define WDMAC_MODE_RX_ACCEL 0x00000400
+#define WDMAC_MODE_STATUS_TAG_FIX 0x20000000
#define WDMAC_STATUS 0x00004c04
#define WDMAC_STATUS_TGTABORT 0x00000004
#define WDMAC_STATUS_MSTABORT 0x00000008
@@ -1713,6 +1731,12 @@
#define NIC_SRAM_DATA_CFG_3 0x00000d3c
#define NIC_SRAM_ASPM_DEBOUNCE 0x00000002
+#define NIC_SRAM_DATA_CFG_4 0x00000d60
+#define NIC_SRAM_GMII_MODE 0x00000002
+#define NIC_SRAM_RGMII_STD_IBND_DISABLE 0x00000004
+#define NIC_SRAM_RGMII_EXT_IBND_RX_EN 0x00000008
+#define NIC_SRAM_RGMII_EXT_IBND_TX_EN 0x00000010
+
#define NIC_SRAM_RX_MINI_BUFFER_DESC 0x00001000
#define NIC_SRAM_DMA_DESC_POOL_BASE 0x00002000
@@ -2204,6 +2228,7 @@
u16 orig_speed;
u8 orig_duplex;
u8 orig_autoneg;
+ u32 orig_advertising;
};
struct tg3_bufmgr_config {
@@ -2479,6 +2504,13 @@
#define TG3_FLG3_ENABLE_APE 0x00000002
#define TG3_FLG3_5761_5784_AX_FIXES 0x00000004
#define TG3_FLG3_5701_DMA_BUG 0x00000008
+#define TG3_FLG3_USE_PHYLIB 0x00000010
+#define TG3_FLG3_MDIOBUS_INITED 0x00000020
+#define TG3_FLG3_MDIOBUS_PAUSED 0x00000040
+#define TG3_FLG3_PHY_CONNECTED 0x00000080
+#define TG3_FLG3_RGMII_STD_IBND_DISABLE 0x00000100
+#define TG3_FLG3_RGMII_EXT_IBND_RX_EN 0x00000200
+#define TG3_FLG3_RGMII_EXT_IBND_TX_EN 0x00000400
struct timer_list timer;
u16 timer_counter;
@@ -2519,6 +2551,9 @@
int msi_cap;
int pcix_cap;
+ struct mii_bus mdio_bus;
+ int mdio_irq[PHY_MAX_ADDR];
+
/* PHY info */
u32 phy_id;
#define PHY_ID_MASK 0xfffffff0
@@ -2546,6 +2581,9 @@
#define PHY_REV_BCM5401_B2 0x3
#define PHY_REV_BCM5401_C0 0x6
#define PHY_REV_BCM5411_X0 0x1 /* Found on Netgear GA302T */
+#define TG3_PHY_ID_BCM50610 0x143bd60
+#define TG3_PHY_ID_BCMAC131 0x143bc70
+
u32 led_ctrl;
u32 phy_otp;
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index 0166407..85246ed 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -13,8 +13,6 @@
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
- ** This file is best viewed/edited with columns>=132.
- *
** Useful (if not required) reading:
*
* Texas Instruments, ThunderLAN Programmer's Guide,
@@ -218,9 +216,7 @@
module_param(bbuf, int, 0);
MODULE_PARM_DESC(bbuf, "ThunderLAN use big buffer (0-1)");
-static u8 *TLanPadBuffer;
-static dma_addr_t TLanPadBufferDMA;
-static char TLanSignature[] = "TLAN";
+static const char TLanSignature[] = "TLAN";
static const char tlan_banner[] = "ThunderLAN driver v1.15\n";
static int tlan_have_pci;
static int tlan_have_eisa;
@@ -238,9 +234,11 @@
{ "Compaq Netelligent 10 T PCI UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 },
{ "Compaq Netelligent 10/100 TX PCI UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 },
{ "Compaq Integrated NetFlex-3/P", TLAN_ADAPTER_NONE, 0x83 },
- { "Compaq NetFlex-3/P", TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 },
+ { "Compaq NetFlex-3/P",
+ TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 },
{ "Compaq NetFlex-3/P", TLAN_ADAPTER_NONE, 0x83 },
- { "Compaq Netelligent Integrated 10/100 TX UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 },
+ { "Compaq Netelligent Integrated 10/100 TX UTP",
+ TLAN_ADAPTER_ACTIVITY_LED, 0x83 },
{ "Compaq Netelligent Dual 10/100 TX PCI UTP", TLAN_ADAPTER_NONE, 0x83 },
{ "Compaq Netelligent 10/100 TX Embedded UTP", TLAN_ADAPTER_NONE, 0x83 },
{ "Olicom OC-2183/2185", TLAN_ADAPTER_USE_INTERN_10, 0x83 },
@@ -248,8 +246,9 @@
{ "Olicom OC-2326", TLAN_ADAPTER_USE_INTERN_10, 0xF8 },
{ "Compaq Netelligent 10/100 TX UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 },
{ "Compaq Netelligent 10 T/2 PCI UTP/Coax", TLAN_ADAPTER_NONE, 0x83 },
- { "Compaq NetFlex-3/E", TLAN_ADAPTER_ACTIVITY_LED | /* EISA card */
- TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 },
+ { "Compaq NetFlex-3/E",
+ TLAN_ADAPTER_ACTIVITY_LED | /* EISA card */
+ TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 },
{ "Compaq NetFlex-3/E", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, /* EISA card */
};
@@ -294,12 +293,12 @@
static struct net_device_stats *TLan_GetStats( struct net_device *);
static void TLan_SetMulticastList( struct net_device *);
static int TLan_ioctl( struct net_device *dev, struct ifreq *rq, int cmd);
-static int TLan_probe1( struct pci_dev *pdev, long ioaddr, int irq, int rev, const struct pci_device_id *ent);
+static int TLan_probe1( struct pci_dev *pdev, long ioaddr,
+ int irq, int rev, const struct pci_device_id *ent);
static void TLan_tx_timeout( struct net_device *dev);
static void TLan_tx_timeout_work(struct work_struct *work);
static int tlan_init_one( struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 TLan_HandleInvalid( struct net_device *, u16 );
static u32 TLan_HandleTxEOF( struct net_device *, u16 );
static u32 TLan_HandleStatOverflow( struct net_device *, u16 );
static u32 TLan_HandleRxEOF( struct net_device *, u16 );
@@ -348,29 +347,27 @@
static int TLan_EeReadByte( struct net_device *, u8, u8 * );
-static void
+static inline void
TLan_StoreSKB( struct tlan_list_tag *tag, struct sk_buff *skb)
{
unsigned long addr = (unsigned long)skb;
- tag->buffer[9].address = (u32)addr;
- addr >>= 31; /* >>= 32 is undefined for 32bit arch, stupid C */
- addr >>= 1;
- tag->buffer[8].address = (u32)addr;
+ tag->buffer[9].address = addr;
+ tag->buffer[8].address = upper_32_bits(addr);
}
-static struct sk_buff *
-TLan_GetSKB( struct tlan_list_tag *tag)
+static inline struct sk_buff *
+TLan_GetSKB( const struct tlan_list_tag *tag)
{
- unsigned long addr = tag->buffer[8].address;
- addr <<= 31;
- addr <<= 1;
- addr |= tag->buffer[9].address;
+ unsigned long addr;
+
+ addr = tag->buffer[8].address;
+ addr |= (tag->buffer[9].address << 16) << 16;
return (struct sk_buff *) addr;
}
static TLanIntVectorFunc *TLanIntVector[TLAN_INT_NUMBER_OF_INTS] = {
- TLan_HandleInvalid,
+ NULL,
TLan_HandleTxEOF,
TLan_HandleStatOverflow,
TLan_HandleRxEOF,
@@ -444,7 +441,9 @@
unregister_netdev( dev );
if ( priv->dmaStorage ) {
- pci_free_consistent(priv->pciDev, priv->dmaSize, priv->dmaStorage, priv->dmaStorageDMA );
+ pci_free_consistent(priv->pciDev,
+ priv->dmaSize, priv->dmaStorage,
+ priv->dmaStorageDMA );
}
#ifdef CONFIG_PCI
@@ -469,16 +468,6 @@
printk(KERN_INFO "%s", tlan_banner);
- TLanPadBuffer = (u8 *) pci_alloc_consistent(NULL, TLAN_MIN_FRAME_SIZE, &TLanPadBufferDMA);
-
- if (TLanPadBuffer == NULL) {
- printk(KERN_ERR "TLAN: Could not allocate memory for pad buffer.\n");
- rc = -ENOMEM;
- goto err_out;
- }
-
- memset(TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE);
-
TLAN_DBG(TLAN_DEBUG_PROBE, "Starting PCI Probe....\n");
/* Use new style PCI probing. Now the kernel will
@@ -506,8 +495,6 @@
err_out_pci_unreg:
pci_unregister_driver(&tlan_driver);
err_out_pci_free:
- pci_free_consistent(NULL, TLAN_MIN_FRAME_SIZE, TLanPadBuffer, TLanPadBufferDMA);
-err_out:
return rc;
}
@@ -539,7 +526,8 @@
**************************************************************/
static int __devinit TLan_probe1(struct pci_dev *pdev,
- long ioaddr, int irq, int rev, const struct pci_device_id *ent )
+ long ioaddr, int irq, int rev,
+ const struct pci_device_id *ent )
{
struct net_device *dev;
@@ -625,8 +613,10 @@
/* Kernel parameters */
if (dev->mem_start) {
priv->aui = dev->mem_start & 0x01;
- priv->duplex = ((dev->mem_start & 0x06) == 0x06) ? 0 : (dev->mem_start & 0x06) >> 1;
- priv->speed = ((dev->mem_start & 0x18) == 0x18) ? 0 : (dev->mem_start & 0x18) >> 3;
+ priv->duplex = ((dev->mem_start & 0x06) == 0x06) ? 0
+ : (dev->mem_start & 0x06) >> 1;
+ priv->speed = ((dev->mem_start & 0x18) == 0x18) ? 0
+ : (dev->mem_start & 0x18) >> 3;
if (priv->speed == 0x1) {
priv->speed = TLAN_SPEED_10;
@@ -706,7 +696,8 @@
dev = TLan_Eisa_Devices;
priv = netdev_priv(dev);
if (priv->dmaStorage) {
- pci_free_consistent(priv->pciDev, priv->dmaSize, priv->dmaStorage, priv->dmaStorageDMA );
+ pci_free_consistent(priv->pciDev, priv->dmaSize,
+ priv->dmaStorage, priv->dmaStorageDMA );
}
release_region( dev->base_addr, 0x10);
unregister_netdev( dev );
@@ -724,8 +715,6 @@
if (tlan_have_eisa)
TLan_Eisa_Cleanup();
- pci_free_consistent(NULL, TLAN_MIN_FRAME_SIZE, TLanPadBuffer, TLanPadBufferDMA);
-
}
@@ -763,8 +752,10 @@
/* Loop through all slots of the EISA bus */
for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
- TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n", (int) ioaddr + 0xC80, inw(ioaddr + EISA_ID));
- TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n", (int) ioaddr + 0xC82, inw(ioaddr + EISA_ID2));
+ TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n",
+ (int) ioaddr + 0xC80, inw(ioaddr + EISA_ID));
+ TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n",
+ (int) ioaddr + 0xC82, inw(ioaddr + EISA_ID2));
TLAN_DBG(TLAN_DEBUG_PROBE, "Probing for EISA adapter at IO: 0x%4x : ",
@@ -874,7 +865,8 @@
dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS )
* ( sizeof(TLanList) );
}
- priv->dmaStorage = pci_alloc_consistent(priv->pciDev, dma_size, &priv->dmaStorageDMA);
+ priv->dmaStorage = pci_alloc_consistent(priv->pciDev,
+ dma_size, &priv->dmaStorageDMA);
priv->dmaSize = dma_size;
if ( priv->dmaStorage == NULL ) {
@@ -883,16 +875,19 @@
return -ENOMEM;
}
memset( priv->dmaStorage, 0, dma_size );
- priv->rxList = (TLanList *)
- ( ( ( (u32) priv->dmaStorage ) + 7 ) & 0xFFFFFFF8 );
- priv->rxListDMA = ( ( ( (u32) priv->dmaStorageDMA ) + 7 ) & 0xFFFFFFF8 );
+ priv->rxList = (TLanList *) ALIGN((unsigned long)priv->dmaStorage, 8);
+ priv->rxListDMA = ALIGN(priv->dmaStorageDMA, 8);
priv->txList = priv->rxList + TLAN_NUM_RX_LISTS;
priv->txListDMA = priv->rxListDMA + sizeof(TLanList) * TLAN_NUM_RX_LISTS;
+
if ( bbuf ) {
priv->rxBuffer = (u8 *) ( priv->txList + TLAN_NUM_TX_LISTS );
- priv->rxBufferDMA =priv->txListDMA + sizeof(TLanList) * TLAN_NUM_TX_LISTS;
- priv->txBuffer = priv->rxBuffer + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE );
- priv->txBufferDMA = priv->rxBufferDMA + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE );
+ priv->rxBufferDMA =priv->txListDMA
+ + sizeof(TLanList) * TLAN_NUM_TX_LISTS;
+ priv->txBuffer = priv->rxBuffer
+ + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE );
+ priv->txBufferDMA = priv->rxBufferDMA
+ + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE );
}
err = 0;
@@ -952,10 +947,12 @@
int err;
priv->tlanRev = TLan_DioRead8( dev->base_addr, TLAN_DEF_REVISION );
- err = request_irq( dev->irq, TLan_HandleInterrupt, IRQF_SHARED, TLanSignature, dev );
+ err = request_irq( dev->irq, TLan_HandleInterrupt, IRQF_SHARED,
+ dev->name, dev );
if ( err ) {
- printk(KERN_ERR "TLAN: Cannot open %s because IRQ %d is already in use.\n", dev->name, dev->irq );
+ pr_err("TLAN: Cannot open %s because IRQ %d is already in use.\n",
+ dev->name, dev->irq );
return err;
}
@@ -969,7 +966,8 @@
TLan_ReadAndClearStats( dev, TLAN_IGNORE );
TLan_ResetAdapter( dev );
- TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Opened. TLAN Chip Rev: %x\n", dev->name, priv->tlanRev );
+ TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Opened. TLAN Chip Rev: %x\n",
+ dev->name, priv->tlanRev );
return 0;
@@ -1007,14 +1005,16 @@
case SIOCGMIIREG: /* Read MII PHY register. */
- TLan_MiiReadReg(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, &data->val_out);
+ TLan_MiiReadReg(dev, data->phy_id & 0x1f,
+ data->reg_num & 0x1f, &data->val_out);
return 0;
case SIOCSMIIREG: /* Write MII PHY register. */
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- TLan_MiiWriteReg(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
+ TLan_MiiWriteReg(dev, data->phy_id & 0x1f,
+ data->reg_num & 0x1f, data->val_in);
return 0;
default:
return -EOPNOTSUPP;
@@ -1096,20 +1096,25 @@
TLanList *tail_list;
dma_addr_t tail_list_phys;
u8 *tail_buffer;
- int pad;
unsigned long flags;
if ( ! priv->phyOnline ) {
- TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s PHY is not ready\n", dev->name );
+ TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s PHY is not ready\n",
+ dev->name );
dev_kfree_skb_any(skb);
return 0;
}
+ if (skb_padto(skb, TLAN_MIN_FRAME_SIZE))
+ return 0;
+
tail_list = priv->txList + priv->txTail;
tail_list_phys = priv->txListDMA + sizeof(TLanList) * priv->txTail;
if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) {
- TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s is busy (Head=%d Tail=%d)\n", dev->name, priv->txHead, priv->txTail );
+ TLAN_DBG( TLAN_DEBUG_TX,
+ "TRANSMIT: %s is busy (Head=%d Tail=%d)\n",
+ dev->name, priv->txHead, priv->txTail );
netif_stop_queue(dev);
priv->txBusyCount++;
return 1;
@@ -1121,37 +1126,34 @@
tail_buffer = priv->txBuffer + ( priv->txTail * TLAN_MAX_FRAME_SIZE );
skb_copy_from_linear_data(skb, tail_buffer, skb->len);
} else {
- tail_list->buffer[0].address = pci_map_single(priv->pciDev, skb->data, skb->len, PCI_DMA_TODEVICE);
+ tail_list->buffer[0].address = pci_map_single(priv->pciDev,
+ skb->data, skb->len,
+ PCI_DMA_TODEVICE);
TLan_StoreSKB(tail_list, skb);
}
- pad = TLAN_MIN_FRAME_SIZE - skb->len;
-
- if ( pad > 0 ) {
- tail_list->frameSize = (u16) skb->len + pad;
- tail_list->buffer[0].count = (u32) skb->len;
- tail_list->buffer[1].count = TLAN_LAST_BUFFER | (u32) pad;
- tail_list->buffer[1].address = TLanPadBufferDMA;
- } else {
- tail_list->frameSize = (u16) skb->len;
- tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) skb->len;
- tail_list->buffer[1].count = 0;
- tail_list->buffer[1].address = 0;
- }
+ tail_list->frameSize = (u16) skb->len;
+ tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) skb->len;
+ tail_list->buffer[1].count = 0;
+ tail_list->buffer[1].address = 0;
spin_lock_irqsave(&priv->lock, flags);
tail_list->cStat = TLAN_CSTAT_READY;
if ( ! priv->txInProgress ) {
priv->txInProgress = 1;
- TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Starting TX on buffer %d\n", priv->txTail );
+ TLAN_DBG( TLAN_DEBUG_TX,
+ "TRANSMIT: Starting TX on buffer %d\n", priv->txTail );
outl( tail_list_phys, dev->base_addr + TLAN_CH_PARM );
outl( TLAN_HC_GO, dev->base_addr + TLAN_HOST_CMD );
} else {
- TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Adding buffer %d to TX channel\n", priv->txTail );
+ TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Adding buffer %d to TX channel\n",
+ priv->txTail );
if ( priv->txTail == 0 ) {
- ( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward = tail_list_phys;
+ ( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward
+ = tail_list_phys;
} else {
- ( priv->txList + ( priv->txTail - 1 ) )->forward = tail_list_phys;
+ ( priv->txList + ( priv->txTail - 1 ) )->forward
+ = tail_list_phys;
}
}
spin_unlock_irqrestore(&priv->lock, flags);
@@ -1191,33 +1193,31 @@
static irqreturn_t TLan_HandleInterrupt(int irq, void *dev_id)
{
- u32 ack;
- struct net_device *dev;
- u32 host_cmd;
+ struct net_device *dev = dev_id;
+ TLanPrivateInfo *priv = netdev_priv(dev);
u16 host_int;
- int type;
- TLanPrivateInfo *priv;
-
- dev = dev_id;
- priv = netdev_priv(dev);
+ u16 type;
spin_lock(&priv->lock);
host_int = inw( dev->base_addr + TLAN_HOST_INT );
- outw( host_int, dev->base_addr + TLAN_HOST_INT );
-
type = ( host_int & TLAN_HI_IT_MASK ) >> 2;
+ if ( type ) {
+ u32 ack;
+ u32 host_cmd;
- ack = TLanIntVector[type]( dev, host_int );
+ outw( host_int, dev->base_addr + TLAN_HOST_INT );
+ ack = TLanIntVector[type]( dev, host_int );
- if ( ack ) {
- host_cmd = TLAN_HC_ACK | ack | ( type << 18 );
- outl( host_cmd, dev->base_addr + TLAN_HOST_CMD );
+ if ( ack ) {
+ host_cmd = TLAN_HC_ACK | ack | ( type << 18 );
+ outl( host_cmd, dev->base_addr + TLAN_HOST_CMD );
+ }
}
spin_unlock(&priv->lock);
- return IRQ_HANDLED;
+ return IRQ_RETVAL(type);
} /* TLan_HandleInterrupts */
@@ -1286,8 +1286,10 @@
/* Should only read stats if open ? */
TLan_ReadAndClearStats( dev, TLAN_RECORD );
- TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: %s EOC count = %d\n", dev->name, priv->rxEocCount );
- TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s Busy count = %d\n", dev->name, priv->txBusyCount );
+ TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: %s EOC count = %d\n", dev->name,
+ priv->rxEocCount );
+ TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s Busy count = %d\n", dev->name,
+ priv->txBusyCount );
if ( debug & TLAN_DEBUG_GNRL ) {
TLan_PrintDio( dev->base_addr );
TLan_PhyPrint( dev );
@@ -1299,7 +1301,7 @@
TLan_PrintList( priv->txList + i, "TX", i );
}
- return ( &( (TLanPrivateInfo *) netdev_priv(dev) )->stats );
+ return &dev->stats;
} /* TLan_GetStats */
@@ -1337,10 +1339,12 @@
if ( dev->flags & IFF_PROMISC ) {
tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD );
- TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp | TLAN_NET_CMD_CAF );
+ TLan_DioWrite8( dev->base_addr,
+ TLAN_NET_CMD, tmp | TLAN_NET_CMD_CAF );
} else {
tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD );
- TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp & ~TLAN_NET_CMD_CAF );
+ TLan_DioWrite8( dev->base_addr,
+ TLAN_NET_CMD, tmp & ~TLAN_NET_CMD_CAF );
if ( dev->flags & IFF_ALLMULTI ) {
for ( i = 0; i < 3; i++ )
TLan_SetMac( dev, i + 1, NULL );
@@ -1349,7 +1353,8 @@
} else {
for ( i = 0; i < dev->mc_count; i++ ) {
if ( i < 3 ) {
- TLan_SetMac( dev, i + 1, (char *) &dmi->dmi_addr );
+ TLan_SetMac( dev, i + 1,
+ (char *) &dmi->dmi_addr );
} else {
offset = TLan_HashFunc( (u8 *) &dmi->dmi_addr );
if ( offset < 32 )
@@ -1383,31 +1388,6 @@
*****************************************************************************/
- /***************************************************************
- * TLan_HandleInvalid
- *
- * Returns:
- * 0
- * Parms:
- * dev Device assigned the IRQ that was
- * raised.
- * host_int The contents of the HOST_INT
- * port.
- *
- * This function handles invalid interrupts. This should
- * never happen unless some other adapter is trying to use
- * the IRQ line assigned to the device.
- *
- **************************************************************/
-
-static u32 TLan_HandleInvalid( struct net_device *dev, u16 host_int )
-{
- /* printk( "TLAN: Invalid interrupt on %s.\n", dev->name ); */
- return 0;
-
-} /* TLan_HandleInvalid */
-
-
/***************************************************************
@@ -1441,14 +1421,16 @@
u32 ack = 0;
u16 tmpCStat;
- TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOF (Head=%d Tail=%d)\n", priv->txHead, priv->txTail );
+ TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOF (Head=%d Tail=%d)\n",
+ priv->txHead, priv->txTail );
head_list = priv->txList + priv->txHead;
while (((tmpCStat = head_list->cStat ) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) {
ack++;
if ( ! bbuf ) {
struct sk_buff *skb = TLan_GetSKB(head_list);
- pci_unmap_single(priv->pciDev, head_list->buffer[0].address, skb->len, PCI_DMA_TODEVICE);
+ pci_unmap_single(priv->pciDev, head_list->buffer[0].address,
+ skb->len, PCI_DMA_TODEVICE);
dev_kfree_skb_any(skb);
head_list->buffer[8].address = 0;
head_list->buffer[9].address = 0;
@@ -1457,7 +1439,7 @@
if ( tmpCStat & TLAN_CSTAT_EOC )
eoc = 1;
- priv->stats.tx_bytes += head_list->frameSize;
+ dev->stats.tx_bytes += head_list->frameSize;
head_list->cStat = TLAN_CSTAT_UNUSED;
netif_start_queue(dev);
@@ -1469,7 +1451,9 @@
printk(KERN_INFO "TLAN: Received interrupt for uncompleted TX frame.\n");
if ( eoc ) {
- TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOC (Head=%d Tail=%d)\n", priv->txHead, priv->txTail );
+ TLAN_DBG( TLAN_DEBUG_TX,
+ "TRANSMIT: Handling TX EOC (Head=%d Tail=%d)\n",
+ priv->txHead, priv->txTail );
head_list = priv->txList + priv->txHead;
head_list_phys = priv->txListDMA + sizeof(TLanList) * priv->txHead;
if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) {
@@ -1481,7 +1465,8 @@
}
if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) {
- TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
+ TLan_DioWrite8( dev->base_addr,
+ TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
if ( priv->timer.function == NULL ) {
priv->timer.function = &TLan_Timer;
priv->timer.data = (unsigned long) dev;
@@ -1563,66 +1548,65 @@
TLanList *head_list;
struct sk_buff *skb;
TLanList *tail_list;
- void *t;
- u32 frameSize;
u16 tmpCStat;
dma_addr_t head_list_phys;
- TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOF (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail );
+ TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOF (Head=%d Tail=%d)\n",
+ priv->rxHead, priv->rxTail );
head_list = priv->rxList + priv->rxHead;
head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead;
while (((tmpCStat = head_list->cStat) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) {
- frameSize = head_list->frameSize;
+ dma_addr_t frameDma = head_list->buffer[0].address;
+ u32 frameSize = head_list->frameSize;
ack++;
if (tmpCStat & TLAN_CSTAT_EOC)
eoc = 1;
if (bbuf) {
- skb = dev_alloc_skb(frameSize + 7);
- if (skb == NULL)
- printk(KERN_INFO "TLAN: Couldn't allocate memory for received data.\n");
- else {
- head_buffer = priv->rxBuffer + (priv->rxHead * TLAN_MAX_FRAME_SIZE);
- skb_reserve(skb, 2);
- t = (void *) skb_put(skb, frameSize);
+ skb = netdev_alloc_skb(dev, frameSize + 7);
+ if ( !skb )
+ goto drop_and_reuse;
- priv->stats.rx_bytes += head_list->frameSize;
+ head_buffer = priv->rxBuffer
+ + (priv->rxHead * TLAN_MAX_FRAME_SIZE);
+ skb_reserve(skb, 2);
+ pci_dma_sync_single_for_cpu(priv->pciDev,
+ frameDma, frameSize,
+ PCI_DMA_FROMDEVICE);
+ skb_copy_from_linear_data(skb, head_buffer, frameSize);
+ skb_put(skb, frameSize);
+ dev->stats.rx_bytes += frameSize;
- memcpy( t, head_buffer, frameSize );
- skb->protocol = eth_type_trans( skb, dev );
- netif_rx( skb );
- }
+ skb->protocol = eth_type_trans( skb, dev );
+ netif_rx( skb );
} else {
struct sk_buff *new_skb;
- /*
- * I changed the algorithm here. What we now do
- * is allocate the new frame. If this fails we
- * simply recycle the frame.
- */
+ new_skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 );
+ if ( !new_skb )
+ goto drop_and_reuse;
- new_skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 );
+ skb = TLan_GetSKB(head_list);
+ pci_unmap_single(priv->pciDev, frameDma,
+ TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE);
+ skb_put( skb, frameSize );
- if ( new_skb != NULL ) {
- skb = TLan_GetSKB(head_list);
- pci_unmap_single(priv->pciDev, head_list->buffer[0].address, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE);
- skb_trim( skb, frameSize );
+ dev->stats.rx_bytes += frameSize;
- priv->stats.rx_bytes += frameSize;
+ skb->protocol = eth_type_trans( skb, dev );
+ netif_rx( skb );
- skb->protocol = eth_type_trans( skb, dev );
- netif_rx( skb );
+ skb_reserve( new_skb, NET_IP_ALIGN );
+ head_list->buffer[0].address = pci_map_single(priv->pciDev,
+ new_skb->data,
+ TLAN_MAX_FRAME_SIZE,
+ PCI_DMA_FROMDEVICE);
- skb_reserve( new_skb, 2 );
- t = (void *) skb_put( new_skb, TLAN_MAX_FRAME_SIZE );
- head_list->buffer[0].address = pci_map_single(priv->pciDev, new_skb->data, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE);
- head_list->buffer[8].address = (u32) t;
- TLan_StoreSKB(head_list, new_skb);
- } else
- printk(KERN_WARNING "TLAN: Couldn't allocate memory for received data.\n" );
+ TLan_StoreSKB(head_list, new_skb);
+
}
-
+drop_and_reuse:
head_list->forward = 0;
head_list->cStat = 0;
tail_list = priv->rxList + priv->rxTail;
@@ -1638,10 +1622,10 @@
printk(KERN_INFO "TLAN: Received interrupt for uncompleted RX frame.\n");
-
-
if ( eoc ) {
- TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOC (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail );
+ TLAN_DBG( TLAN_DEBUG_RX,
+ "RECEIVE: Handling RX EOC (Head=%d Tail=%d)\n",
+ priv->rxHead, priv->rxTail );
head_list = priv->rxList + priv->rxHead;
head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead;
outl(head_list_phys, dev->base_addr + TLAN_CH_PARM );
@@ -1650,7 +1634,8 @@
}
if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) {
- TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
+ TLan_DioWrite8( dev->base_addr,
+ TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
if ( priv->timer.function == NULL ) {
priv->timer.function = &TLan_Timer;
priv->timer.data = (unsigned long) dev;
@@ -1728,7 +1713,9 @@
host_int = 0;
if ( priv->tlanRev < 0x30 ) {
- TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOC (Head=%d Tail=%d) -- IRQ\n", priv->txHead, priv->txTail );
+ TLAN_DBG( TLAN_DEBUG_TX,
+ "TRANSMIT: Handling TX EOC (Head=%d Tail=%d) -- IRQ\n",
+ priv->txHead, priv->txTail );
head_list = priv->txList + priv->txHead;
head_list_phys = priv->txListDMA + sizeof(TLanList) * priv->txHead;
if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) {
@@ -1796,15 +1783,18 @@
net_sts = TLan_DioRead8( dev->base_addr, TLAN_NET_STS );
if ( net_sts ) {
TLan_DioWrite8( dev->base_addr, TLAN_NET_STS, net_sts );
- TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Net_Sts = %x\n", dev->name, (unsigned) net_sts );
+ TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Net_Sts = %x\n",
+ dev->name, (unsigned) net_sts );
}
if ( ( net_sts & TLAN_NET_STS_MIRQ ) && ( priv->phyNum == 0 ) ) {
TLan_MiiReadReg( dev, phy, TLAN_TLPHY_STS, &tlphy_sts );
TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tlphy_ctl );
- if ( ! ( tlphy_sts & TLAN_TS_POLOK ) && ! ( tlphy_ctl & TLAN_TC_SWAPOL ) ) {
+ if ( ! ( tlphy_sts & TLAN_TS_POLOK ) &&
+ ! ( tlphy_ctl & TLAN_TC_SWAPOL ) ) {
tlphy_ctl |= TLAN_TC_SWAPOL;
TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl);
- } else if ( ( tlphy_sts & TLAN_TS_POLOK ) && ( tlphy_ctl & TLAN_TC_SWAPOL ) ) {
+ } else if ( ( tlphy_sts & TLAN_TS_POLOK )
+ && ( tlphy_ctl & TLAN_TC_SWAPOL ) ) {
tlphy_ctl &= ~TLAN_TC_SWAPOL;
TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl);
}
@@ -1849,7 +1839,9 @@
u32 ack = 1;
if ( priv->tlanRev < 0x30 ) {
- TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOC (Head=%d Tail=%d) -- IRQ\n", priv->rxHead, priv->rxTail );
+ TLAN_DBG( TLAN_DEBUG_RX,
+ "RECEIVE: Handling RX EOC (Head=%d Tail=%d) -- IRQ\n",
+ priv->rxHead, priv->rxTail );
head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead;
outl( head_list_phys, dev->base_addr + TLAN_CH_PARM );
ack |= TLAN_HC_GO | TLAN_HC_RT;
@@ -1940,10 +1932,12 @@
if ( priv->timer.function == NULL ) {
elapsed = jiffies - priv->timerSetAt;
if ( elapsed >= TLAN_TIMER_ACT_DELAY ) {
- TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK );
+ TLan_DioWrite8( dev->base_addr,
+ TLAN_LED_REG, TLAN_LED_LINK );
} else {
priv->timer.function = &TLan_Timer;
- priv->timer.expires = priv->timerSetAt + TLAN_TIMER_ACT_DELAY;
+ priv->timer.expires = priv->timerSetAt
+ + TLAN_TIMER_ACT_DELAY;
spin_unlock_irqrestore(&priv->lock, flags);
add_timer( &priv->timer );
break;
@@ -1998,7 +1992,8 @@
list = priv->txList + i;
list->cStat = TLAN_CSTAT_UNUSED;
if ( bbuf ) {
- list->buffer[0].address = priv->txBufferDMA + ( i * TLAN_MAX_FRAME_SIZE );
+ list->buffer[0].address = priv->txBufferDMA
+ + ( i * TLAN_MAX_FRAME_SIZE );
} else {
list->buffer[0].address = 0;
}
@@ -2017,29 +2012,33 @@
list->frameSize = TLAN_MAX_FRAME_SIZE;
list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER;
if ( bbuf ) {
- list->buffer[0].address = priv->rxBufferDMA + ( i * TLAN_MAX_FRAME_SIZE );
+ list->buffer[0].address = priv->rxBufferDMA
+ + ( i * TLAN_MAX_FRAME_SIZE );
} else {
- skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 );
- if ( skb == NULL ) {
- printk( "TLAN: Couldn't allocate memory for received data.\n" );
- /* If this ever happened it would be a problem */
- } else {
- skb->dev = dev;
- skb_reserve( skb, 2 );
- t = (void *) skb_put( skb, TLAN_MAX_FRAME_SIZE );
+ skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 );
+ if ( !skb ) {
+ pr_err("TLAN: out of memory for received data.\n" );
+ break;
}
- list->buffer[0].address = pci_map_single(priv->pciDev, t, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE);
- list->buffer[8].address = (u32) t;
+
+ skb_reserve( skb, NET_IP_ALIGN );
+ list->buffer[0].address = pci_map_single(priv->pciDev, t,
+ TLAN_MAX_FRAME_SIZE,
+ PCI_DMA_FROMDEVICE);
TLan_StoreSKB(list, skb);
}
list->buffer[1].count = 0;
list->buffer[1].address = 0;
- if ( i < TLAN_NUM_RX_LISTS - 1 )
- list->forward = list_phys + sizeof(TLanList);
- else
- list->forward = 0;
+ list->forward = list_phys + sizeof(TLanList);
}
+ /* in case ran out of memory early, clear bits */
+ while (i < TLAN_NUM_RX_LISTS) {
+ TLan_StoreSKB(priv->rxList + i, NULL);
+ ++i;
+ }
+ list->forward = 0;
+
} /* TLan_ResetLists */
@@ -2055,7 +2054,9 @@
list = priv->txList + i;
skb = TLan_GetSKB(list);
if ( skb ) {
- pci_unmap_single(priv->pciDev, list->buffer[0].address, skb->len, PCI_DMA_TODEVICE);
+ pci_unmap_single(priv->pciDev,
+ list->buffer[0].address, skb->len,
+ PCI_DMA_TODEVICE);
dev_kfree_skb_any( skb );
list->buffer[8].address = 0;
list->buffer[9].address = 0;
@@ -2066,7 +2067,10 @@
list = priv->rxList + i;
skb = TLan_GetSKB(list);
if ( skb ) {
- pci_unmap_single(priv->pciDev, list->buffer[0].address, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE);
+ pci_unmap_single(priv->pciDev,
+ list->buffer[0].address,
+ TLAN_MAX_FRAME_SIZE,
+ PCI_DMA_FROMDEVICE);
dev_kfree_skb_any( skb );
list->buffer[8].address = 0;
list->buffer[9].address = 0;
@@ -2097,7 +2101,8 @@
u32 data0, data1;
int i;
- printk( "TLAN: Contents of internal registers for io base 0x%04hx.\n", io_base );
+ printk( "TLAN: Contents of internal registers for io base 0x%04hx.\n",
+ io_base );
printk( "TLAN: Off. +0 +4\n" );
for ( i = 0; i < 0x4C; i+= 8 ) {
data0 = TLan_DioRead32( io_base, i );
@@ -2131,13 +2136,14 @@
{
int i;
- printk( "TLAN: %s List %d at 0x%08x\n", type, num, (u32) list );
+ printk( "TLAN: %s List %d at %p\n", type, num, list );
printk( "TLAN: Forward = 0x%08x\n", list->forward );
printk( "TLAN: CSTAT = 0x%04hx\n", list->cStat );
printk( "TLAN: Frame Size = 0x%04hx\n", list->frameSize );
/* for ( i = 0; i < 10; i++ ) { */
for ( i = 0; i < 2; i++ ) {
- printk( "TLAN: Buffer[%d].count, addr = 0x%08x, 0x%08x\n", i, list->buffer[i].count, list->buffer[i].address );
+ printk( "TLAN: Buffer[%d].count, addr = 0x%08x, 0x%08x\n",
+ i, list->buffer[i].count, list->buffer[i].address );
}
} /* TLan_PrintList */
@@ -2165,7 +2171,6 @@
static void TLan_ReadAndClearStats( struct net_device *dev, int record )
{
- TLanPrivateInfo *priv = netdev_priv(dev);
u32 tx_good, tx_under;
u32 rx_good, rx_over;
u32 def_tx, crc, code;
@@ -2202,18 +2207,18 @@
loss = inb( dev->base_addr + TLAN_DIO_DATA + 2 );
if ( record ) {
- priv->stats.rx_packets += rx_good;
- priv->stats.rx_errors += rx_over + crc + code;
- priv->stats.tx_packets += tx_good;
- priv->stats.tx_errors += tx_under + loss;
- priv->stats.collisions += multi_col + single_col + excess_col + late_col;
+ dev->stats.rx_packets += rx_good;
+ dev->stats.rx_errors += rx_over + crc + code;
+ dev->stats.tx_packets += tx_good;
+ dev->stats.tx_errors += tx_under + loss;
+ dev->stats.collisions += multi_col + single_col + excess_col + late_col;
- priv->stats.rx_over_errors += rx_over;
- priv->stats.rx_crc_errors += crc;
- priv->stats.rx_frame_errors += code;
+ dev->stats.rx_over_errors += rx_over;
+ dev->stats.rx_crc_errors += crc;
+ dev->stats.rx_frame_errors += code;
- priv->stats.tx_aborted_errors += tx_under;
- priv->stats.tx_carrier_errors += loss;
+ dev->stats.tx_aborted_errors += tx_under;
+ dev->stats.tx_carrier_errors += loss;
}
} /* TLan_ReadAndClearStats */
@@ -2354,14 +2359,16 @@
TLan_MiiReadReg( dev, phy, MII_GEN_ID_HI, &tlphy_id1 );
TLan_MiiReadReg( dev, phy, MII_GEN_ID_LO, &tlphy_id2 );
- if ( ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) || ( priv->aui ) ) {
+ if ( ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) ||
+ ( priv->aui ) ) {
status = MII_GS_LINK;
printk( "TLAN: %s: Link forced.\n", dev->name );
} else {
TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
udelay( 1000 );
TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
- if ( (status & MII_GS_LINK) && /* We only support link info on Nat.Sem. PHY's */
+ if ( (status & MII_GS_LINK) &&
+ /* We only support link info on Nat.Sem. PHY's */
(tlphy_id1 == NAT_SEM_ID1) &&
(tlphy_id2 == NAT_SEM_ID2) ) {
TLan_MiiReadReg( dev, phy, MII_AN_LPA, &partner );
@@ -2370,12 +2377,12 @@
printk( "TLAN: %s: Link active with ", dev->name );
if (!(tlphy_par & TLAN_PHY_AN_EN_STAT)) {
printk( "forced 10%sMbps %s-Duplex\n",
- tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0",
- tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half");
+ tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0",
+ tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half");
} else {
printk( "AutoNegotiation enabled, at 10%sMbps %s-Duplex\n",
- tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0",
- tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half");
+ tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0",
+ tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half");
printk("TLAN: Partner capability: ");
for (i = 5; i <= 10; i++)
if (partner & (1<<i))
@@ -2416,7 +2423,8 @@
outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD );
netif_carrier_on(dev);
} else {
- printk( "TLAN: %s: Link inactive, will retry in 10 secs...\n", dev->name );
+ printk( "TLAN: %s: Link inactive, will retry in 10 secs...\n",
+ dev->name );
TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_FINISH_RESET );
return;
}
@@ -2456,10 +2464,12 @@
if ( mac != NULL ) {
for ( i = 0; i < 6; i++ )
- TLan_DioWrite8( dev->base_addr, TLAN_AREG_0 + areg + i, mac[i] );
+ TLan_DioWrite8( dev->base_addr,
+ TLAN_AREG_0 + areg + i, mac[i] );
} else {
for ( i = 0; i < 6; i++ )
- TLan_DioWrite8( dev->base_addr, TLAN_AREG_0 + areg + i, 0 );
+ TLan_DioWrite8( dev->base_addr,
+ TLAN_AREG_0 + areg + i, 0 );
}
} /* TLan_SetMac */
@@ -2565,9 +2575,13 @@
TLan_MiiReadReg( dev, phy, MII_GEN_CTL, &control );
TLan_MiiReadReg( dev, phy, MII_GEN_ID_HI, &hi );
TLan_MiiReadReg( dev, phy, MII_GEN_ID_LO, &lo );
- if ( ( control != 0xFFFF ) || ( hi != 0xFFFF ) || ( lo != 0xFFFF ) ) {
- TLAN_DBG( TLAN_DEBUG_GNRL, "PHY found at %02x %04x %04x %04x\n", phy, control, hi, lo );
- if ( ( priv->phy[1] == TLAN_PHY_NONE ) && ( phy != TLAN_PHY_MAX_ADDR ) ) {
+ if ( ( control != 0xFFFF ) ||
+ ( hi != 0xFFFF ) || ( lo != 0xFFFF ) ) {
+ TLAN_DBG( TLAN_DEBUG_GNRL,
+ "PHY found at %02x %04x %04x %04x\n",
+ phy, control, hi, lo );
+ if ( ( priv->phy[1] == TLAN_PHY_NONE ) &&
+ ( phy != TLAN_PHY_MAX_ADDR ) ) {
priv->phy[1] = phy;
}
}
@@ -2595,7 +2609,9 @@
value = MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE;
TLan_MiiSync( dev->base_addr );
TLan_MiiWriteReg( dev, priv->phy[priv->phyNum], MII_GEN_CTL, value );
- if ( ( priv->phyNum == 0 ) && ( priv->phy[1] != TLAN_PHY_NONE ) && ( ! ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) ) ) {
+ if ( ( priv->phyNum == 0 ) &&
+ ( priv->phy[1] != TLAN_PHY_NONE ) &&
+ ( ! ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) ) ) {
TLan_MiiSync( dev->base_addr );
TLan_MiiWriteReg( dev, priv->phy[1], MII_GEN_CTL, value );
}
@@ -2768,10 +2784,10 @@
* more time. Perhaps we should fail after a while.
*/
if (!priv->neg_be_verbose++) {
- printk(KERN_INFO "TLAN: Giving autonegotiation more time.\n");
- printk(KERN_INFO "TLAN: Please check that your adapter has\n");
- printk(KERN_INFO "TLAN: been properly connected to a HUB or Switch.\n");
- printk(KERN_INFO "TLAN: Trying to establish link in the background...\n");
+ pr_info("TLAN: Giving autonegotiation more time.\n");
+ pr_info("TLAN: Please check that your adapter has\n");
+ pr_info("TLAN: been properly connected to a HUB or Switch.\n");
+ pr_info("TLAN: Trying to establish link in the background...\n");
}
TLan_SetTimer( dev, (8*HZ), TLAN_TIMER_PHY_FINISH_AN );
return;
@@ -2787,7 +2803,9 @@
priv->tlanFullDuplex = TRUE;
}
- if ( ( ! ( mode & 0x0180 ) ) && ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) && ( priv->phyNum != 0 ) ) {
+ if ( ( ! ( mode & 0x0180 ) ) &&
+ ( priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10 ) &&
+ ( priv->phyNum != 0 ) ) {
priv->phyNum = 0;
data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN;
TLan_DioWrite16( dev->base_addr, TLAN_NET_CONFIG, data );
@@ -2796,12 +2814,14 @@
}
if ( priv->phyNum == 0 ) {
- if ( ( priv->duplex == TLAN_DUPLEX_FULL ) || ( an_adv & an_lpa & 0x0040 ) ) {
- TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, MII_GC_AUTOENB | MII_GC_DUPLEX );
- printk( "TLAN: Starting internal PHY with FULL-DUPLEX\n" );
+ if ( ( priv->duplex == TLAN_DUPLEX_FULL ) ||
+ ( an_adv & an_lpa & 0x0040 ) ) {
+ TLan_MiiWriteReg( dev, phy, MII_GEN_CTL,
+ MII_GC_AUTOENB | MII_GC_DUPLEX );
+ pr_info("TLAN: Starting internal PHY with FULL-DUPLEX\n" );
} else {
TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, MII_GC_AUTOENB );
- printk( "TLAN: Starting internal PHY with HALF-DUPLEX\n" );
+ pr_info( "TLAN: Starting internal PHY with HALF-DUPLEX\n" );
}
}
@@ -3209,7 +3229,8 @@
TLan_SetBit( TLAN_NET_SIO_ETXEN, sio );
if ( ( ! err ) && stop ) {
- TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); /* STOP, raise data while clock is high */
+ /* STOP, raise data while clock is high */
+ TLan_ClearBit( TLAN_NET_SIO_EDATA, sio );
TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
TLan_SetBit( TLAN_NET_SIO_EDATA, sio );
}
@@ -3272,7 +3293,8 @@
TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); /* No ack = 1 (?) */
TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio );
- TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); /* STOP, raise data while clock is high */
+ /* STOP, raise data while clock is high */
+ TLan_ClearBit( TLAN_NET_SIO_EDATA, sio );
TLan_SetBit( TLAN_NET_SIO_ECLOK, sio );
TLan_SetBit( TLAN_NET_SIO_EDATA, sio );
}
diff --git a/drivers/net/tlan.h b/drivers/net/tlan.h
index 41ce0b6..4b82f28 100644
--- a/drivers/net/tlan.h
+++ b/drivers/net/tlan.h
@@ -13,8 +13,6 @@
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
- ** This file is best viewed/edited with tabstop=4, colums>=132
- *
*
* Dec 10, 1999 Torben Mathiasen <torben.mathiasen@compaq.com>
* New Maintainer
@@ -45,7 +43,9 @@
#define TLAN_IGNORE 0
#define TLAN_RECORD 1
-#define TLAN_DBG(lvl, format, args...) if (debug&lvl) printk(KERN_DEBUG "TLAN: " format, ##args );
+#define TLAN_DBG(lvl, format, args...) \
+ do { if (debug&lvl) printk(KERN_DEBUG "TLAN: " format, ##args ); } while(0)
+
#define TLAN_DEBUG_GNRL 0x0001
#define TLAN_DEBUG_TX 0x0002
#define TLAN_DEBUG_RX 0x0004
@@ -194,7 +194,6 @@
u32 timerSetAt;
u32 timerType;
struct timer_list timer;
- struct net_device_stats stats;
struct board *adapter;
u32 adapterRev;
u32 aui;
@@ -205,7 +204,6 @@
u32 speed;
u8 tlanRev;
u8 tlanFullDuplex;
- char devName[8];
spinlock_t lock;
u8 link;
u8 is_eisa;
@@ -517,12 +515,18 @@
* xor( a, xor( b, xor( c, xor( d, xor( e, xor( f, xor( g, h ) ) ) ) ) ) )
* #define DA( a, bit ) ( ( (u8) a[bit/8] ) & ( (u8) ( 1 << bit%8 ) ) )
*
- * hash = XOR8( DA(a,0), DA(a, 6), DA(a,12), DA(a,18), DA(a,24), DA(a,30), DA(a,36), DA(a,42) );
- * hash |= XOR8( DA(a,1), DA(a, 7), DA(a,13), DA(a,19), DA(a,25), DA(a,31), DA(a,37), DA(a,43) ) << 1;
- * hash |= XOR8( DA(a,2), DA(a, 8), DA(a,14), DA(a,20), DA(a,26), DA(a,32), DA(a,38), DA(a,44) ) << 2;
- * hash |= XOR8( DA(a,3), DA(a, 9), DA(a,15), DA(a,21), DA(a,27), DA(a,33), DA(a,39), DA(a,45) ) << 3;
- * hash |= XOR8( DA(a,4), DA(a,10), DA(a,16), DA(a,22), DA(a,28), DA(a,34), DA(a,40), DA(a,46) ) << 4;
- * hash |= XOR8( DA(a,5), DA(a,11), DA(a,17), DA(a,23), DA(a,29), DA(a,35), DA(a,41), DA(a,47) ) << 5;
+ * hash = XOR8( DA(a,0), DA(a, 6), DA(a,12), DA(a,18), DA(a,24),
+ * DA(a,30), DA(a,36), DA(a,42) );
+ * hash |= XOR8( DA(a,1), DA(a, 7), DA(a,13), DA(a,19), DA(a,25),
+ * DA(a,31), DA(a,37), DA(a,43) ) << 1;
+ * hash |= XOR8( DA(a,2), DA(a, 8), DA(a,14), DA(a,20), DA(a,26),
+ * DA(a,32), DA(a,38), DA(a,44) ) << 2;
+ * hash |= XOR8( DA(a,3), DA(a, 9), DA(a,15), DA(a,21), DA(a,27),
+ * DA(a,33), DA(a,39), DA(a,45) ) << 3;
+ * hash |= XOR8( DA(a,4), DA(a,10), DA(a,16), DA(a,22), DA(a,28),
+ * DA(a,34), DA(a,40), DA(a,46) ) << 4;
+ * hash |= XOR8( DA(a,5), DA(a,11), DA(a,17), DA(a,23), DA(a,29),
+ * DA(a,35), DA(a,41), DA(a,47) ) << 5;
*
*/
static inline u32 TLan_HashFunc( const u8 *a )
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 74cf8e1..66b1ff6 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..febfaee 100644
--- a/drivers/net/tsi108_eth.c
+++ b/drivers/net/tsi108_eth.c
@@ -803,7 +803,8 @@
int rx = data->rxhead;
struct sk_buff *skb;
- data->rxskbs[rx] = skb = dev_alloc_skb(TSI108_RXBUF_SIZE + 2);
+ data->rxskbs[rx] = skb = netdev_alloc_skb(dev,
+ TSI108_RXBUF_SIZE + 2);
if (!skb)
break;
@@ -1352,8 +1353,9 @@
data->rxhead = 0;
for (i = 0; i < TSI108_RXRING_LEN; i++) {
- struct sk_buff *skb = dev_alloc_skb(TSI108_RXBUF_SIZE + NET_IP_ALIGN);
+ struct sk_buff *skb;
+ skb = netdev_alloc_skb(dev, TSI108_RXBUF_SIZE + NET_IP_ALIGN);
if (!skb) {
/* Bah. No memory for now, but maybe we'll get
* some more later.
@@ -1526,7 +1528,7 @@
struct tsi108_prv_data *data = netdev_priv(dev);
unsigned long flags;
int rc;
-
+
spin_lock_irqsave(&data->txlock, flags);
rc = mii_ethtool_gset(&data->mii_if, cmd);
spin_unlock_irqrestore(&data->txlock, flags);
@@ -1543,7 +1545,7 @@
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 f5839c4..cfbbfee 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.
*
@@ -160,7 +160,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/usb/Kconfig b/drivers/net/usb/Kconfig
index 0604f3f..68e198b 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -154,6 +154,16 @@
This driver creates an interface named "ethX", where X depends on
what other networking devices you have in use.
+config USB_HSO
+ tristate "Option USB High Speed Mobile Devices"
+ depends on USB && RFKILL
+ default n
+ help
+ Choose this option if you have an Option HSDPA/HSUPA card.
+ These cards support downlink speeds of 7.2Mbps or greater.
+
+ To compile this driver as a module, choose M here: the
+ module will be called hso.
config USB_NET_CDCETHER
tristate "CDC Ethernet support (smart devices such as cable modems)"
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index 595a539..24800c1 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -6,6 +6,7 @@
obj-$(CONFIG_USB_KAWETH) += kaweth.o
obj-$(CONFIG_USB_PEGASUS) += pegasus.o
obj-$(CONFIG_USB_RTL8150) += rtl8150.o
+obj-$(CONFIG_USB_HSO) += hso.o
obj-$(CONFIG_USB_NET_AX8817X) += asix.o
obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o
obj-$(CONFIG_USB_NET_DM9601) += dm9601.o
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
new file mode 100644
index 0000000..031d07b
--- /dev/null
+++ b/drivers/net/usb/hso.c
@@ -0,0 +1,2836 @@
+/******************************************************************************
+ *
+ * Driver for Option High Speed Mobile Devices.
+ *
+ * Copyright (C) 2008 Option International
+ * Copyright (C) 2007 Andrew Bird (Sphere Systems Ltd)
+ * <ajb@spheresystems.co.uk>
+ * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de>
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ *
+ *****************************************************************************/
+
+/******************************************************************************
+ *
+ * Description of the device:
+ *
+ * Interface 0: Contains the IP network interface on the bulk end points.
+ * The multiplexed serial ports are using the interrupt and
+ * control endpoints.
+ * Interrupt contains a bitmap telling which multiplexed
+ * serialport needs servicing.
+ *
+ * Interface 1: Diagnostics port, uses bulk only, do not submit urbs until the
+ * port is opened, as this have a huge impact on the network port
+ * throughput.
+ *
+ * Interface 2: Standard modem interface - circuit switched interface, should
+ * not be used.
+ *
+ *****************************************************************************/
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/module.h>
+#include <linux/ethtool.h>
+#include <linux/usb.h>
+#include <linux/timer.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/kmod.h>
+#include <linux/rfkill.h>
+#include <linux/ip.h>
+#include <linux/uaccess.h>
+#include <linux/usb/cdc.h>
+#include <net/arp.h>
+#include <asm/byteorder.h>
+
+
+#define DRIVER_VERSION "1.2"
+#define MOD_AUTHOR "Option Wireless"
+#define MOD_DESCRIPTION "USB High Speed Option driver"
+#define MOD_LICENSE "GPL"
+
+#define HSO_MAX_NET_DEVICES 10
+#define HSO__MAX_MTU 2048
+#define DEFAULT_MTU 1500
+#define DEFAULT_MRU 1500
+
+#define CTRL_URB_RX_SIZE 1024
+#define CTRL_URB_TX_SIZE 64
+
+#define BULK_URB_RX_SIZE 4096
+#define BULK_URB_TX_SIZE 8192
+
+#define MUX_BULK_RX_BUF_SIZE HSO__MAX_MTU
+#define MUX_BULK_TX_BUF_SIZE HSO__MAX_MTU
+#define MUX_BULK_RX_BUF_COUNT 4
+#define USB_TYPE_OPTION_VENDOR 0x20
+
+/* These definitions are used with the struct hso_net flags element */
+/* - use *_bit operations on it. (bit indices not values.) */
+#define HSO_NET_RUNNING 0
+
+#define HSO_NET_TX_TIMEOUT (HZ*10)
+
+/* Serial port defines and structs. */
+#define HSO_SERIAL_FLAG_RX_SENT 0
+
+#define HSO_SERIAL_MAGIC 0x48534f31
+
+/* Number of ttys to handle */
+#define HSO_SERIAL_TTY_MINORS 256
+
+#define MAX_RX_URBS 2
+
+#define get_serial_by_tty(x) \
+ (x ? (struct hso_serial *)x->driver_data : NULL)
+
+/*****************************************************************************/
+/* Debugging functions */
+/*****************************************************************************/
+#define D__(lvl_, fmt, arg...) \
+ do { \
+ printk(lvl_ "[%d:%s]: " fmt "\n", \
+ __LINE__, __func__, ## arg); \
+ } while (0)
+
+#define D_(lvl, args...) \
+ do { \
+ if (lvl & debug) \
+ D__(KERN_INFO, args); \
+ } while (0)
+
+#define D1(args...) D_(0x01, ##args)
+#define D2(args...) D_(0x02, ##args)
+#define D3(args...) D_(0x04, ##args)
+#define D4(args...) D_(0x08, ##args)
+#define D5(args...) D_(0x10, ##args)
+
+/*****************************************************************************/
+/* Enumerators */
+/*****************************************************************************/
+enum pkt_parse_state {
+ WAIT_IP,
+ WAIT_DATA,
+ WAIT_SYNC
+};
+
+/*****************************************************************************/
+/* Structs */
+/*****************************************************************************/
+
+struct hso_shared_int {
+ struct usb_endpoint_descriptor *intr_endp;
+ void *shared_intr_buf;
+ struct urb *shared_intr_urb;
+ struct usb_device *usb;
+ int use_count;
+ int ref_count;
+ struct mutex shared_int_lock;
+};
+
+struct hso_net {
+ struct hso_device *parent;
+ struct net_device *net;
+ struct rfkill *rfkill;
+
+ struct usb_endpoint_descriptor *in_endp;
+ struct usb_endpoint_descriptor *out_endp;
+
+ struct urb *mux_bulk_rx_urb_pool[MUX_BULK_RX_BUF_COUNT];
+ struct urb *mux_bulk_tx_urb;
+ void *mux_bulk_rx_buf_pool[MUX_BULK_RX_BUF_COUNT];
+ void *mux_bulk_tx_buf;
+
+ struct sk_buff *skb_rx_buf;
+ struct sk_buff *skb_tx_buf;
+
+ enum pkt_parse_state rx_parse_state;
+ spinlock_t net_lock;
+
+ unsigned short rx_buf_size;
+ unsigned short rx_buf_missing;
+ struct iphdr rx_ip_hdr;
+
+ unsigned long flags;
+};
+
+struct hso_serial {
+ struct hso_device *parent;
+ int magic;
+ u8 minor;
+
+ struct hso_shared_int *shared_int;
+
+ /* rx/tx urb could be either a bulk urb or a control urb depending
+ on which serial port it is used on. */
+ struct urb *rx_urb[MAX_RX_URBS];
+ u8 num_rx_urbs;
+ u8 *rx_data[MAX_RX_URBS];
+ u16 rx_data_length; /* should contain allocated length */
+
+ struct urb *tx_urb;
+ u8 *tx_data;
+ u8 *tx_buffer;
+ u16 tx_data_length; /* should contain allocated length */
+ u16 tx_data_count;
+ u16 tx_buffer_count;
+ struct usb_ctrlrequest ctrl_req_tx;
+ struct usb_ctrlrequest ctrl_req_rx;
+
+ struct usb_endpoint_descriptor *in_endp;
+ struct usb_endpoint_descriptor *out_endp;
+
+ unsigned long flags;
+ u8 rts_state;
+ u8 dtr_state;
+ unsigned tx_urb_used:1;
+
+ /* from usb_serial_port */
+ struct tty_struct *tty;
+ int open_count;
+ spinlock_t serial_lock;
+
+ int (*write_data) (struct hso_serial *serial);
+};
+
+struct hso_device {
+ union {
+ struct hso_serial *dev_serial;
+ struct hso_net *dev_net;
+ } port_data;
+
+ u32 port_spec;
+
+ u8 is_active;
+ u8 usb_gone;
+ struct work_struct async_get_intf;
+ struct work_struct async_put_intf;
+
+ struct usb_device *usb;
+ struct usb_interface *interface;
+
+ struct device *dev;
+ struct kref ref;
+ struct mutex mutex;
+};
+
+/* Type of interface */
+#define HSO_INTF_MASK 0xFF00
+#define HSO_INTF_MUX 0x0100
+#define HSO_INTF_BULK 0x0200
+
+/* Type of port */
+#define HSO_PORT_MASK 0xFF
+#define HSO_PORT_NO_PORT 0x0
+#define HSO_PORT_CONTROL 0x1
+#define HSO_PORT_APP 0x2
+#define HSO_PORT_GPS 0x3
+#define HSO_PORT_PCSC 0x4
+#define HSO_PORT_APP2 0x5
+#define HSO_PORT_GPS_CONTROL 0x6
+#define HSO_PORT_MSD 0x7
+#define HSO_PORT_VOICE 0x8
+#define HSO_PORT_DIAG2 0x9
+#define HSO_PORT_DIAG 0x10
+#define HSO_PORT_MODEM 0x11
+#define HSO_PORT_NETWORK 0x12
+
+/* Additional device info */
+#define HSO_INFO_MASK 0xFF000000
+#define HSO_INFO_CRC_BUG 0x01000000
+
+/*****************************************************************************/
+/* Prototypes */
+/*****************************************************************************/
+/* Serial driver functions */
+static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file,
+ unsigned int set, unsigned int clear);
+static void ctrl_callback(struct urb *urb);
+static void put_rxbuf_data(struct urb *urb, struct hso_serial *serial);
+static void hso_kick_transmit(struct hso_serial *serial);
+/* Helper functions */
+static int hso_mux_submit_intr_urb(struct hso_shared_int *mux_int,
+ struct usb_device *usb, gfp_t gfp);
+static void log_usb_status(int status, const char *function);
+static struct usb_endpoint_descriptor *hso_get_ep(struct usb_interface *intf,
+ int type, int dir);
+static int hso_get_mux_ports(struct usb_interface *intf, unsigned char *ports);
+static void hso_free_interface(struct usb_interface *intf);
+static int hso_start_serial_device(struct hso_device *hso_dev, gfp_t flags);
+static int hso_stop_serial_device(struct hso_device *hso_dev);
+static int hso_start_net_device(struct hso_device *hso_dev);
+static void hso_free_shared_int(struct hso_shared_int *shared_int);
+static int hso_stop_net_device(struct hso_device *hso_dev);
+static void hso_serial_ref_free(struct kref *ref);
+static void async_get_intf(struct work_struct *data);
+static void async_put_intf(struct work_struct *data);
+static int hso_put_activity(struct hso_device *hso_dev);
+static int hso_get_activity(struct hso_device *hso_dev);
+
+/*****************************************************************************/
+/* Helping functions */
+/*****************************************************************************/
+
+/* #define DEBUG */
+
+#define dev2net(x) (x->port_data.dev_net)
+#define dev2ser(x) (x->port_data.dev_serial)
+
+/* Debugging functions */
+#ifdef DEBUG
+static void dbg_dump(int line_count, const char *func_name, unsigned char *buf,
+ unsigned int len)
+{
+ u8 i = 0;
+
+ printk(KERN_DEBUG "[%d:%s]: len %d", line_count, func_name, len);
+
+ for (i = 0; i < len; i++) {
+ if (!(i % 16))
+ printk("\n 0x%03x: ", i);
+ printk("%02x ", (unsigned char)buf[i]);
+ }
+ printk("\n");
+}
+
+#define DUMP(buf_, len_) \
+ dbg_dump(__LINE__, __func__, buf_, len_)
+
+#define DUMP1(buf_, len_) \
+ do { \
+ if (0x01 & debug) \
+ DUMP(buf_, len_); \
+ } while (0)
+#else
+#define DUMP(buf_, len_)
+#define DUMP1(buf_, len_)
+#endif
+
+/* module parameters */
+static int debug;
+static int tty_major;
+static int disable_net;
+
+/* driver info */
+static const char driver_name[] = "hso";
+static const char tty_filename[] = "ttyHS";
+static const char *version = __FILE__ ": " DRIVER_VERSION " " MOD_AUTHOR;
+/* the usb driver itself (registered in hso_init) */
+static struct usb_driver hso_driver;
+/* serial structures */
+static struct tty_driver *tty_drv;
+static struct hso_device *serial_table[HSO_SERIAL_TTY_MINORS];
+static struct hso_device *network_table[HSO_MAX_NET_DEVICES];
+static spinlock_t serial_table_lock;
+static struct ktermios *hso_serial_termios[HSO_SERIAL_TTY_MINORS];
+static struct ktermios *hso_serial_termios_locked[HSO_SERIAL_TTY_MINORS];
+
+static const s32 default_port_spec[] = {
+ HSO_INTF_MUX | HSO_PORT_NETWORK,
+ HSO_INTF_BULK | HSO_PORT_DIAG,
+ HSO_INTF_BULK | HSO_PORT_MODEM,
+ 0
+};
+
+static const s32 icon321_port_spec[] = {
+ HSO_INTF_MUX | HSO_PORT_NETWORK,
+ HSO_INTF_BULK | HSO_PORT_DIAG2,
+ HSO_INTF_BULK | HSO_PORT_MODEM,
+ HSO_INTF_BULK | HSO_PORT_DIAG,
+ 0
+};
+
+#define default_port_device(vendor, product) \
+ USB_DEVICE(vendor, product), \
+ .driver_info = (kernel_ulong_t)default_port_spec
+
+#define icon321_port_device(vendor, product) \
+ USB_DEVICE(vendor, product), \
+ .driver_info = (kernel_ulong_t)icon321_port_spec
+
+/* list of devices we support */
+static const struct usb_device_id hso_ids[] = {
+ {default_port_device(0x0af0, 0x6711)},
+ {default_port_device(0x0af0, 0x6731)},
+ {default_port_device(0x0af0, 0x6751)},
+ {default_port_device(0x0af0, 0x6771)},
+ {default_port_device(0x0af0, 0x6791)},
+ {default_port_device(0x0af0, 0x6811)},
+ {default_port_device(0x0af0, 0x6911)},
+ {default_port_device(0x0af0, 0x6951)},
+ {default_port_device(0x0af0, 0x6971)},
+ {default_port_device(0x0af0, 0x7011)},
+ {default_port_device(0x0af0, 0x7031)},
+ {default_port_device(0x0af0, 0x7051)},
+ {default_port_device(0x0af0, 0x7071)},
+ {default_port_device(0x0af0, 0x7111)},
+ {default_port_device(0x0af0, 0x7211)},
+ {default_port_device(0x0af0, 0x7251)},
+ {default_port_device(0x0af0, 0x7271)},
+ {default_port_device(0x0af0, 0x7311)},
+ {default_port_device(0x0af0, 0xc031)}, /* Icon-Edge */
+ {icon321_port_device(0x0af0, 0xd013)}, /* Module HSxPA */
+ {icon321_port_device(0x0af0, 0xd031)}, /* Icon-321 */
+ {default_port_device(0x0af0, 0xd033)}, /* Icon-322 */
+ {USB_DEVICE(0x0af0, 0x7301)}, /* GE40x */
+ {USB_DEVICE(0x0af0, 0x7361)}, /* GE40x */
+ {USB_DEVICE(0x0af0, 0x7401)}, /* GI 0401 */
+ {USB_DEVICE(0x0af0, 0x7501)}, /* GTM 382 */
+ {USB_DEVICE(0x0af0, 0x7601)}, /* GE40x */
+ {}
+};
+MODULE_DEVICE_TABLE(usb, hso_ids);
+
+/* Sysfs attribute */
+static ssize_t hso_sysfs_show_porttype(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct hso_device *hso_dev = dev->driver_data;
+ char *port_name;
+
+ if (!hso_dev)
+ return 0;
+
+ switch (hso_dev->port_spec & HSO_PORT_MASK) {
+ case HSO_PORT_CONTROL:
+ port_name = "Control";
+ break;
+ case HSO_PORT_APP:
+ port_name = "Application";
+ break;
+ case HSO_PORT_APP2:
+ port_name = "Application2";
+ break;
+ case HSO_PORT_GPS:
+ port_name = "GPS";
+ break;
+ case HSO_PORT_GPS_CONTROL:
+ port_name = "GPS Control";
+ break;
+ case HSO_PORT_PCSC:
+ port_name = "PCSC";
+ break;
+ case HSO_PORT_DIAG:
+ port_name = "Diagnostic";
+ break;
+ case HSO_PORT_DIAG2:
+ port_name = "Diagnostic2";
+ break;
+ case HSO_PORT_MODEM:
+ port_name = "Modem";
+ break;
+ case HSO_PORT_NETWORK:
+ port_name = "Network";
+ break;
+ default:
+ port_name = "Unknown";
+ break;
+ }
+
+ return sprintf(buf, "%s\n", port_name);
+}
+static DEVICE_ATTR(hsotype, S_IRUGO, hso_sysfs_show_porttype, NULL);
+
+/* converts mux value to a port spec value */
+static u32 hso_mux_to_port(int mux)
+{
+ u32 result;
+
+ switch (mux) {
+ case 0x1:
+ result = HSO_PORT_CONTROL;
+ break;
+ case 0x2:
+ result = HSO_PORT_APP;
+ break;
+ case 0x4:
+ result = HSO_PORT_PCSC;
+ break;
+ case 0x8:
+ result = HSO_PORT_GPS;
+ break;
+ case 0x10:
+ result = HSO_PORT_APP2;
+ break;
+ default:
+ result = HSO_PORT_NO_PORT;
+ }
+ return result;
+}
+
+/* converts port spec value to a mux value */
+static u32 hso_port_to_mux(int port)
+{
+ u32 result;
+
+ switch (port & HSO_PORT_MASK) {
+ case HSO_PORT_CONTROL:
+ result = 0x0;
+ break;
+ case HSO_PORT_APP:
+ result = 0x1;
+ break;
+ case HSO_PORT_PCSC:
+ result = 0x2;
+ break;
+ case HSO_PORT_GPS:
+ result = 0x3;
+ break;
+ case HSO_PORT_APP2:
+ result = 0x4;
+ break;
+ default:
+ result = 0x0;
+ }
+ return result;
+}
+
+static struct hso_serial *get_serial_by_shared_int_and_type(
+ struct hso_shared_int *shared_int,
+ int mux)
+{
+ int i, port;
+
+ port = hso_mux_to_port(mux);
+
+ for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
+ if (serial_table[i]
+ && (dev2ser(serial_table[i])->shared_int == shared_int)
+ && ((serial_table[i]->port_spec & HSO_PORT_MASK) == port)) {
+ return dev2ser(serial_table[i]);
+ }
+ }
+
+ return NULL;
+}
+
+static struct hso_serial *get_serial_by_index(unsigned index)
+{
+ struct hso_serial *serial;
+ unsigned long flags;
+
+ if (!serial_table[index])
+ return NULL;
+ spin_lock_irqsave(&serial_table_lock, flags);
+ serial = dev2ser(serial_table[index]);
+ spin_unlock_irqrestore(&serial_table_lock, flags);
+
+ return serial;
+}
+
+static int get_free_serial_index(void)
+{
+ int index;
+ unsigned long flags;
+
+ spin_lock_irqsave(&serial_table_lock, flags);
+ for (index = 0; index < HSO_SERIAL_TTY_MINORS; index++) {
+ if (serial_table[index] == NULL) {
+ spin_unlock_irqrestore(&serial_table_lock, flags);
+ return index;
+ }
+ }
+ spin_unlock_irqrestore(&serial_table_lock, flags);
+
+ printk(KERN_ERR "%s: no free serial devices in table\n", __func__);
+ return -1;
+}
+
+static void set_serial_by_index(unsigned index, struct hso_serial *serial)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&serial_table_lock, flags);
+ if (serial)
+ serial_table[index] = serial->parent;
+ else
+ serial_table[index] = NULL;
+ spin_unlock_irqrestore(&serial_table_lock, flags);
+}
+
+/* log a meaningfull explanation of an USB status */
+static void log_usb_status(int status, const char *function)
+{
+ char *explanation;
+
+ switch (status) {
+ case -ENODEV:
+ explanation = "no device";
+ break;
+ case -ENOENT:
+ explanation = "endpoint not enabled";
+ break;
+ case -EPIPE:
+ explanation = "endpoint stalled";
+ break;
+ case -ENOSPC:
+ explanation = "not enough bandwidth";
+ break;
+ case -ESHUTDOWN:
+ explanation = "device disabled";
+ break;
+ case -EHOSTUNREACH:
+ explanation = "device suspended";
+ break;
+ case -EINVAL:
+ case -EAGAIN:
+ case -EFBIG:
+ case -EMSGSIZE:
+ explanation = "internal error";
+ break;
+ default:
+ explanation = "unknown status";
+ break;
+ }
+ D1("%s: received USB status - %s (%d)", function, explanation, status);
+}
+
+/* Network interface functions */
+
+/* called when net interface is brought up by ifconfig */
+static int hso_net_open(struct net_device *net)
+{
+ struct hso_net *odev = netdev_priv(net);
+ unsigned long flags = 0;
+
+ if (!odev) {
+ dev_err(&net->dev, "No net device !\n");
+ return -ENODEV;
+ }
+
+ odev->skb_tx_buf = NULL;
+
+ /* setup environment */
+ spin_lock_irqsave(&odev->net_lock, flags);
+ odev->rx_parse_state = WAIT_IP;
+ odev->rx_buf_size = 0;
+ odev->rx_buf_missing = sizeof(struct iphdr);
+ spin_unlock_irqrestore(&odev->net_lock, flags);
+
+ hso_start_net_device(odev->parent);
+
+ /* We are up and running. */
+ set_bit(HSO_NET_RUNNING, &odev->flags);
+
+ /* Tell the kernel we are ready to start receiving from it */
+ netif_start_queue(net);
+
+ return 0;
+}
+
+/* called when interface is brought down by ifconfig */
+static int hso_net_close(struct net_device *net)
+{
+ struct hso_net *odev = netdev_priv(net);
+
+ /* we don't need the queue anymore */
+ netif_stop_queue(net);
+ /* no longer running */
+ clear_bit(HSO_NET_RUNNING, &odev->flags);
+
+ hso_stop_net_device(odev->parent);
+
+ /* done */
+ return 0;
+}
+
+/* USB tells is xmit done, we should start the netqueue again */
+static void write_bulk_callback(struct urb *urb)
+{
+ struct hso_net *odev = urb->context;
+ int status = urb->status;
+
+ /* Sanity check */
+ if (!odev || !test_bit(HSO_NET_RUNNING, &odev->flags)) {
+ dev_err(&urb->dev->dev, "%s: device not running\n", __func__);
+ return;
+ }
+
+ /* Do we still have a valid kernel network device? */
+ if (!netif_device_present(odev->net)) {
+ dev_err(&urb->dev->dev, "%s: net device not present\n",
+ __func__);
+ return;
+ }
+
+ /* log status, but don't act on it, we don't need to resubmit anything
+ * anyhow */
+ if (status)
+ log_usb_status(status, __func__);
+
+ hso_put_activity(odev->parent);
+
+ /* Tell the network interface we are ready for another frame */
+ netif_wake_queue(odev->net);
+}
+
+/* called by kernel when we need to transmit a packet */
+static int hso_net_start_xmit(struct sk_buff *skb, struct net_device *net)
+{
+ struct hso_net *odev = netdev_priv(net);
+ int result;
+
+ /* Tell the kernel, "No more frames 'til we are done with this one." */
+ netif_stop_queue(net);
+ if (hso_get_activity(odev->parent) == -EAGAIN) {
+ odev->skb_tx_buf = skb;
+ return 0;
+ }
+
+ /* log if asked */
+ DUMP1(skb->data, skb->len);
+ /* Copy it from kernel memory to OUR memory */
+ memcpy(odev->mux_bulk_tx_buf, skb->data, skb->len);
+ D1("len: %d/%d", skb->len, MUX_BULK_TX_BUF_SIZE);
+
+ /* Fill in the URB for shipping it out. */
+ usb_fill_bulk_urb(odev->mux_bulk_tx_urb,
+ odev->parent->usb,
+ usb_sndbulkpipe(odev->parent->usb,
+ odev->out_endp->
+ bEndpointAddress & 0x7F),
+ odev->mux_bulk_tx_buf, skb->len, write_bulk_callback,
+ odev);
+
+ /* Deal with the Zero Length packet problem, I hope */
+ odev->mux_bulk_tx_urb->transfer_flags |= URB_ZERO_PACKET;
+
+ /* Send the URB on its merry way. */
+ result = usb_submit_urb(odev->mux_bulk_tx_urb, GFP_ATOMIC);
+ if (result) {
+ dev_warn(&odev->parent->interface->dev,
+ "failed mux_bulk_tx_urb %d", result);
+ net->stats.tx_errors++;
+ netif_start_queue(net);
+ } else {
+ net->stats.tx_packets++;
+ net->stats.tx_bytes += skb->len;
+ /* And tell the kernel when the last transmit started. */
+ net->trans_start = jiffies;
+ }
+ dev_kfree_skb(skb);
+ /* we're done */
+ return result;
+}
+
+static void hso_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
+{
+ struct hso_net *odev = netdev_priv(net);
+
+ strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN);
+ strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
+ usb_make_path(odev->parent->usb, info->bus_info, sizeof info->bus_info);
+}
+
+static struct ethtool_ops ops = {
+ .get_drvinfo = hso_get_drvinfo,
+ .get_link = ethtool_op_get_link
+};
+
+/* called when a packet did not ack after watchdogtimeout */
+static void hso_net_tx_timeout(struct net_device *net)
+{
+ struct hso_net *odev = netdev_priv(net);
+
+ if (!odev)
+ return;
+
+ /* Tell syslog we are hosed. */
+ dev_warn(&net->dev, "Tx timed out.\n");
+
+ /* Tear the waiting frame off the list */
+ if (odev->mux_bulk_tx_urb
+ && (odev->mux_bulk_tx_urb->status == -EINPROGRESS))
+ usb_unlink_urb(odev->mux_bulk_tx_urb);
+
+ /* Update statistics */
+ net->stats.tx_errors++;
+}
+
+/* make a real packet from the received USB buffer */
+static void packetizeRx(struct hso_net *odev, unsigned char *ip_pkt,
+ unsigned int count, unsigned char is_eop)
+{
+ unsigned short temp_bytes;
+ unsigned short buffer_offset = 0;
+ unsigned short frame_len;
+ unsigned char *tmp_rx_buf;
+
+ /* log if needed */
+ D1("Rx %d bytes", count);
+ DUMP(ip_pkt, min(128, (int)count));
+
+ while (count) {
+ switch (odev->rx_parse_state) {
+ case WAIT_IP:
+ /* waiting for IP header. */
+ /* wanted bytes - size of ip header */
+ temp_bytes =
+ (count <
+ odev->rx_buf_missing) ? count : odev->
+ rx_buf_missing;
+
+ memcpy(((unsigned char *)(&odev->rx_ip_hdr)) +
+ odev->rx_buf_size, ip_pkt + buffer_offset,
+ temp_bytes);
+
+ odev->rx_buf_size += temp_bytes;
+ buffer_offset += temp_bytes;
+ odev->rx_buf_missing -= temp_bytes;
+ count -= temp_bytes;
+
+ if (!odev->rx_buf_missing) {
+ /* header is complete allocate an sk_buffer and
+ * continue to WAIT_DATA */
+ frame_len = ntohs(odev->rx_ip_hdr.tot_len);
+
+ if ((frame_len > DEFAULT_MRU) ||
+ (frame_len < sizeof(struct iphdr))) {
+ dev_err(&odev->net->dev,
+ "Invalid frame (%d) length\n",
+ frame_len);
+ odev->rx_parse_state = WAIT_SYNC;
+ continue;
+ }
+ /* Allocate an sk_buff */
+ odev->skb_rx_buf = dev_alloc_skb(frame_len);
+ if (!odev->skb_rx_buf) {
+ /* We got no receive buffer. */
+ D1("could not allocate memory");
+ odev->rx_parse_state = WAIT_SYNC;
+ return;
+ }
+ /* Here's where it came from */
+ odev->skb_rx_buf->dev = odev->net;
+
+ /* Copy what we got so far. make room for iphdr
+ * after tail. */
+ tmp_rx_buf =
+ skb_put(odev->skb_rx_buf,
+ sizeof(struct iphdr));
+ memcpy(tmp_rx_buf, (char *)&(odev->rx_ip_hdr),
+ sizeof(struct iphdr));
+
+ /* ETH_HLEN */
+ odev->rx_buf_size = sizeof(struct iphdr);
+
+ /* Filip actually use .tot_len */
+ odev->rx_buf_missing =
+ frame_len - sizeof(struct iphdr);
+ odev->rx_parse_state = WAIT_DATA;
+ }
+ break;
+
+ case WAIT_DATA:
+ temp_bytes = (count < odev->rx_buf_missing)
+ ? count : odev->rx_buf_missing;
+
+ /* Copy the rest of the bytes that are left in the
+ * buffer into the waiting sk_buf. */
+ /* Make room for temp_bytes after tail. */
+ tmp_rx_buf = skb_put(odev->skb_rx_buf, temp_bytes);
+ memcpy(tmp_rx_buf, ip_pkt + buffer_offset, temp_bytes);
+
+ odev->rx_buf_missing -= temp_bytes;
+ count -= temp_bytes;
+ buffer_offset += temp_bytes;
+ odev->rx_buf_size += temp_bytes;
+ if (!odev->rx_buf_missing) {
+ /* Packet is complete. Inject into stack. */
+ /* We have IP packet here */
+ odev->skb_rx_buf->protocol =
+ __constant_htons(ETH_P_IP);
+ /* don't check it */
+ odev->skb_rx_buf->ip_summed =
+ CHECKSUM_UNNECESSARY;
+
+ skb_reset_mac_header(odev->skb_rx_buf);
+
+ /* Ship it off to the kernel */
+ netif_rx(odev->skb_rx_buf);
+ /* No longer our buffer. */
+ odev->skb_rx_buf = NULL;
+
+ /* update out statistics */
+ odev->net->stats.rx_packets++;
+
+ odev->net->stats.rx_bytes += odev->rx_buf_size;
+
+ odev->rx_buf_size = 0;
+ odev->rx_buf_missing = sizeof(struct iphdr);
+ odev->rx_parse_state = WAIT_IP;
+ }
+ break;
+
+ case WAIT_SYNC:
+ D1(" W_S");
+ count = 0;
+ break;
+ default:
+ D1(" ");
+ count--;
+ break;
+ }
+ }
+
+ /* Recovery mechanism for WAIT_SYNC state. */
+ if (is_eop) {
+ if (odev->rx_parse_state == WAIT_SYNC) {
+ odev->rx_parse_state = WAIT_IP;
+ odev->rx_buf_size = 0;
+ odev->rx_buf_missing = sizeof(struct iphdr);
+ }
+ }
+}
+
+/* Moving data from usb to kernel (in interrupt state) */
+static void read_bulk_callback(struct urb *urb)
+{
+ struct hso_net *odev = urb->context;
+ struct net_device *net;
+ int result;
+ int status = urb->status;
+
+ /* is al ok? (Filip: Who's Al ?) */
+ if (status) {
+ log_usb_status(status, __func__);
+ return;
+ }
+
+ /* Sanity check */
+ if (!odev || !test_bit(HSO_NET_RUNNING, &odev->flags)) {
+ D1("BULK IN callback but driver is not active!");
+ return;
+ }
+ usb_mark_last_busy(urb->dev);
+
+ net = odev->net;
+
+ if (!netif_device_present(net)) {
+ /* Somebody killed our network interface... */
+ return;
+ }
+
+ if (odev->parent->port_spec & HSO_INFO_CRC_BUG) {
+ u32 rest;
+ u8 crc_check[4] = { 0xDE, 0xAD, 0xBE, 0xEF };
+ rest = urb->actual_length % odev->in_endp->wMaxPacketSize;
+ if (((rest == 5) || (rest == 6))
+ && !memcmp(((u8 *) urb->transfer_buffer) +
+ urb->actual_length - 4, crc_check, 4)) {
+ urb->actual_length -= 4;
+ }
+ }
+
+ /* do we even have a packet? */
+ if (urb->actual_length) {
+ /* Handle the IP stream, add header and push it onto network
+ * stack if the packet is complete. */
+ spin_lock(&odev->net_lock);
+ packetizeRx(odev, urb->transfer_buffer, urb->actual_length,
+ (urb->transfer_buffer_length >
+ urb->actual_length) ? 1 : 0);
+ spin_unlock(&odev->net_lock);
+ }
+
+ /* We are done with this URB, resubmit it. Prep the USB to wait for
+ * another frame. Reuse same as received. */
+ usb_fill_bulk_urb(urb,
+ odev->parent->usb,
+ usb_rcvbulkpipe(odev->parent->usb,
+ odev->in_endp->
+ bEndpointAddress & 0x7F),
+ urb->transfer_buffer, MUX_BULK_RX_BUF_SIZE,
+ read_bulk_callback, odev);
+
+ /* Give this to the USB subsystem so it can tell us when more data
+ * arrives. */
+ result = usb_submit_urb(urb, GFP_ATOMIC);
+ if (result)
+ dev_warn(&odev->parent->interface->dev,
+ "%s failed submit mux_bulk_rx_urb %d", __func__,
+ result);
+}
+
+/* Serial driver functions */
+
+static void _hso_serial_set_termios(struct tty_struct *tty,
+ struct ktermios *old)
+{
+ struct hso_serial *serial = get_serial_by_tty(tty);
+ struct ktermios *termios;
+
+ if ((!tty) || (!tty->termios) || (!serial)) {
+ printk(KERN_ERR "%s: no tty structures", __func__);
+ return;
+ }
+
+ D4("port %d", serial->minor);
+
+ /*
+ * The default requirements for this device are:
+ */
+ termios = tty->termios;
+ termios->c_iflag &=
+ ~(IGNBRK /* disable ignore break */
+ | BRKINT /* disable break causes interrupt */
+ | PARMRK /* disable mark parity errors */
+ | ISTRIP /* disable clear high bit of input characters */
+ | INLCR /* disable translate NL to CR */
+ | IGNCR /* disable ignore CR */
+ | ICRNL /* disable translate CR to NL */
+ | IXON); /* disable enable XON/XOFF flow control */
+
+ /* disable postprocess output characters */
+ termios->c_oflag &= ~OPOST;
+
+ termios->c_lflag &=
+ ~(ECHO /* disable echo input characters */
+ | ECHONL /* disable echo new line */
+ | ICANON /* disable erase, kill, werase, and rprnt
+ special characters */
+ | ISIG /* disable interrupt, quit, and suspend special
+ characters */
+ | IEXTEN); /* disable non-POSIX special characters */
+
+ termios->c_cflag &=
+ ~(CSIZE /* no size */
+ | PARENB /* disable parity bit */
+ | CBAUD /* clear current baud rate */
+ | CBAUDEX); /* clear current buad rate */
+
+ termios->c_cflag |= CS8; /* character size 8 bits */
+
+ /* baud rate 115200 */
+ tty_encode_baud_rate(serial->tty, 115200, 115200);
+
+ /*
+ * Force low_latency on; otherwise the pushes are scheduled;
+ * this is bad as it opens up the possibility of dropping bytes
+ * on the floor. We don't want to drop bytes on the floor. :)
+ */
+ serial->tty->low_latency = 1;
+ return;
+}
+
+/* open the requested serial port */
+static int hso_serial_open(struct tty_struct *tty, struct file *filp)
+{
+ struct hso_serial *serial = get_serial_by_index(tty->index);
+ int result;
+
+ /* sanity check */
+ if (serial == NULL || serial->magic != HSO_SERIAL_MAGIC) {
+ tty->driver_data = NULL;
+ D1("Failed to open port");
+ return -ENODEV;
+ }
+
+ mutex_lock(&serial->parent->mutex);
+ result = usb_autopm_get_interface(serial->parent->interface);
+ if (result < 0)
+ goto err_out;
+
+ D1("Opening %d", serial->minor);
+ kref_get(&serial->parent->ref);
+
+ /* setup */
+ tty->driver_data = serial;
+ serial->tty = tty;
+
+ /* check for port allready opened, if not set the termios */
+ serial->open_count++;
+ if (serial->open_count == 1) {
+ tty->low_latency = 1;
+ serial->flags = 0;
+ /* Force default termio settings */
+ _hso_serial_set_termios(tty, NULL);
+ result = hso_start_serial_device(serial->parent, GFP_KERNEL);
+ if (result) {
+ hso_stop_serial_device(serial->parent);
+ serial->open_count--;
+ kref_put(&serial->parent->ref, hso_serial_ref_free);
+ }
+ } else {
+ D1("Port was already open");
+ }
+
+ usb_autopm_put_interface(serial->parent->interface);
+
+ /* done */
+ if (result)
+ hso_serial_tiocmset(tty, NULL, TIOCM_RTS | TIOCM_DTR, 0);
+err_out:
+ mutex_unlock(&serial->parent->mutex);
+ return result;
+}
+
+/* close the requested serial port */
+static void hso_serial_close(struct tty_struct *tty, struct file *filp)
+{
+ struct hso_serial *serial = tty->driver_data;
+ u8 usb_gone;
+
+ D1("Closing serial port");
+
+ mutex_lock(&serial->parent->mutex);
+ usb_gone = serial->parent->usb_gone;
+
+ if (!usb_gone)
+ usb_autopm_get_interface(serial->parent->interface);
+
+ /* reset the rts and dtr */
+ /* do the actual close */
+ serial->open_count--;
+ if (serial->open_count <= 0) {
+ kref_put(&serial->parent->ref, hso_serial_ref_free);
+ serial->open_count = 0;
+ if (serial->tty) {
+ serial->tty->driver_data = NULL;
+ serial->tty = NULL;
+ }
+ if (!usb_gone)
+ hso_stop_serial_device(serial->parent);
+ }
+ if (!usb_gone)
+ usb_autopm_put_interface(serial->parent->interface);
+ mutex_unlock(&serial->parent->mutex);
+}
+
+/* close the requested serial port */
+static int hso_serial_write(struct tty_struct *tty, const unsigned char *buf,
+ int count)
+{
+ struct hso_serial *serial = get_serial_by_tty(tty);
+ int space, tx_bytes;
+ unsigned long flags;
+
+ /* sanity check */
+ if (serial == NULL) {
+ printk(KERN_ERR "%s: serial is NULL\n", __func__);
+ return -ENODEV;
+ }
+
+ spin_lock_irqsave(&serial->serial_lock, flags);
+
+ space = serial->tx_data_length - serial->tx_buffer_count;
+ tx_bytes = (count < space) ? count : space;
+
+ if (!tx_bytes)
+ goto out;
+
+ memcpy(serial->tx_buffer + serial->tx_buffer_count, buf, tx_bytes);
+ serial->tx_buffer_count += tx_bytes;
+
+out:
+ spin_unlock_irqrestore(&serial->serial_lock, flags);
+
+ hso_kick_transmit(serial);
+ /* done */
+ return tx_bytes;
+}
+
+/* how much room is there for writing */
+static int hso_serial_write_room(struct tty_struct *tty)
+{
+ struct hso_serial *serial = get_serial_by_tty(tty);
+ int room;
+ unsigned long flags;
+
+ spin_lock_irqsave(&serial->serial_lock, flags);
+ room = serial->tx_data_length - serial->tx_buffer_count;
+ spin_unlock_irqrestore(&serial->serial_lock, flags);
+
+ /* return free room */
+ return room;
+}
+
+/* setup the term */
+static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
+{
+ struct hso_serial *serial = get_serial_by_tty(tty);
+ unsigned long flags;
+
+ if (old)
+ D5("Termios called with: cflags new[%d] - old[%d]",
+ tty->termios->c_cflag, old->c_cflag);
+
+ /* the actual setup */
+ spin_lock_irqsave(&serial->serial_lock, flags);
+ if (serial->open_count)
+ _hso_serial_set_termios(tty, old);
+ else
+ tty->termios = old;
+ spin_unlock_irqrestore(&serial->serial_lock, flags);
+
+ /* done */
+ return;
+}
+
+/* how many characters in the buffer */
+static int hso_serial_chars_in_buffer(struct tty_struct *tty)
+{
+ struct hso_serial *serial = get_serial_by_tty(tty);
+ int chars;
+ unsigned long flags;
+
+ /* sanity check */
+ if (serial == NULL)
+ return 0;
+
+ spin_lock_irqsave(&serial->serial_lock, flags);
+ chars = serial->tx_buffer_count;
+ spin_unlock_irqrestore(&serial->serial_lock, flags);
+
+ return chars;
+}
+
+static int hso_serial_tiocmget(struct tty_struct *tty, struct file *file)
+{
+ unsigned int value;
+ struct hso_serial *serial = get_serial_by_tty(tty);
+ unsigned long flags;
+
+ /* sanity check */
+ if (!serial) {
+ D1("no tty structures");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&serial->serial_lock, flags);
+ value = ((serial->rts_state) ? TIOCM_RTS : 0) |
+ ((serial->dtr_state) ? TIOCM_DTR : 0);
+ spin_unlock_irqrestore(&serial->serial_lock, flags);
+
+ return value;
+}
+
+static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file,
+ unsigned int set, unsigned int clear)
+{
+ int val = 0;
+ unsigned long flags;
+ int if_num;
+ struct hso_serial *serial = get_serial_by_tty(tty);
+
+ /* sanity check */
+ if (!serial) {
+ D1("no tty structures");
+ return -EINVAL;
+ }
+ if_num = serial->parent->interface->altsetting->desc.bInterfaceNumber;
+
+ spin_lock_irqsave(&serial->serial_lock, flags);
+ if (set & TIOCM_RTS)
+ serial->rts_state = 1;
+ if (set & TIOCM_DTR)
+ serial->dtr_state = 1;
+
+ if (clear & TIOCM_RTS)
+ serial->rts_state = 0;
+ if (clear & TIOCM_DTR)
+ serial->dtr_state = 0;
+
+ if (serial->dtr_state)
+ val |= 0x01;
+ if (serial->rts_state)
+ val |= 0x02;
+
+ spin_unlock_irqrestore(&serial->serial_lock, flags);
+
+ return usb_control_msg(serial->parent->usb,
+ usb_rcvctrlpipe(serial->parent->usb, 0), 0x22,
+ 0x21, val, if_num, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+}
+
+/* starts a transmit */
+static void hso_kick_transmit(struct hso_serial *serial)
+{
+ u8 *temp;
+ unsigned long flags;
+ int res;
+
+ spin_lock_irqsave(&serial->serial_lock, flags);
+ if (!serial->tx_buffer_count)
+ goto out;
+
+ if (serial->tx_urb_used)
+ goto out;
+
+ /* Wakeup USB interface if necessary */
+ if (hso_get_activity(serial->parent) == -EAGAIN)
+ goto out;
+
+ /* Switch pointers around to avoid memcpy */
+ temp = serial->tx_buffer;
+ serial->tx_buffer = serial->tx_data;
+ serial->tx_data = temp;
+ serial->tx_data_count = serial->tx_buffer_count;
+ serial->tx_buffer_count = 0;
+
+ /* If temp is set, it means we switched buffers */
+ if (temp && serial->write_data) {
+ res = serial->write_data(serial);
+ if (res >= 0)
+ serial->tx_urb_used = 1;
+ }
+out:
+ spin_unlock_irqrestore(&serial->serial_lock, flags);
+}
+
+/* make a request (for reading and writing data to muxed serial port) */
+static int mux_device_request(struct hso_serial *serial, u8 type, u16 port,
+ struct urb *ctrl_urb,
+ struct usb_ctrlrequest *ctrl_req,
+ u8 *ctrl_urb_data, u32 size)
+{
+ int result;
+ int pipe;
+
+ /* Sanity check */
+ if (!serial || !ctrl_urb || !ctrl_req) {
+ printk(KERN_ERR "%s: Wrong arguments\n", __func__);
+ return -EINVAL;
+ }
+
+ /* initialize */
+ ctrl_req->wValue = 0;
+ ctrl_req->wIndex = hso_port_to_mux(port);
+ ctrl_req->wLength = size;
+
+ if (type == USB_CDC_GET_ENCAPSULATED_RESPONSE) {
+ /* Reading command */
+ ctrl_req->bRequestType = USB_DIR_IN |
+ USB_TYPE_OPTION_VENDOR |
+ USB_RECIP_INTERFACE;
+ ctrl_req->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
+ pipe = usb_rcvctrlpipe(serial->parent->usb, 0);
+ } else {
+ /* Writing command */
+ ctrl_req->bRequestType = USB_DIR_OUT |
+ USB_TYPE_OPTION_VENDOR |
+ USB_RECIP_INTERFACE;
+ ctrl_req->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND;
+ pipe = usb_sndctrlpipe(serial->parent->usb, 0);
+ }
+ /* syslog */
+ D2("%s command (%02x) len: %d, port: %d",
+ type == USB_CDC_GET_ENCAPSULATED_RESPONSE ? "Read" : "Write",
+ ctrl_req->bRequestType, ctrl_req->wLength, port);
+
+ /* Load ctrl urb */
+ ctrl_urb->transfer_flags = 0;
+ usb_fill_control_urb(ctrl_urb,
+ serial->parent->usb,
+ pipe,
+ (u8 *) ctrl_req,
+ ctrl_urb_data, size, ctrl_callback, serial);
+ /* Send it on merry way */
+ result = usb_submit_urb(ctrl_urb, GFP_ATOMIC);
+ if (result) {
+ dev_err(&ctrl_urb->dev->dev,
+ "%s failed submit ctrl_urb %d type %d", __func__,
+ result, type);
+ return result;
+ }
+
+ /* done */
+ return size;
+}
+
+/* called by intr_callback when read occurs */
+static int hso_mux_serial_read(struct hso_serial *serial)
+{
+ if (!serial)
+ return -EINVAL;
+
+ /* clean data */
+ memset(serial->rx_data[0], 0, CTRL_URB_RX_SIZE);
+ /* make the request */
+
+ if (serial->num_rx_urbs != 1) {
+ dev_err(&serial->parent->interface->dev,
+ "ERROR: mux'd reads with multiple buffers "
+ "not possible\n");
+ return 0;
+ }
+ return mux_device_request(serial,
+ USB_CDC_GET_ENCAPSULATED_RESPONSE,
+ serial->parent->port_spec & HSO_PORT_MASK,
+ serial->rx_urb[0],
+ &serial->ctrl_req_rx,
+ serial->rx_data[0], serial->rx_data_length);
+}
+
+/* used for muxed serial port callback (muxed serial read) */
+static void intr_callback(struct urb *urb)
+{
+ struct hso_shared_int *shared_int = urb->context;
+ struct hso_serial *serial;
+ unsigned char *port_req;
+ int status = urb->status;
+ int i;
+
+ usb_mark_last_busy(urb->dev);
+
+ /* sanity check */
+ if (!shared_int)
+ return;
+
+ /* status check */
+ if (status) {
+ log_usb_status(status, __func__);
+ return;
+ }
+ D4("\n--- Got intr callback 0x%02X ---", status);
+
+ /* what request? */
+ port_req = urb->transfer_buffer;
+ D4(" port_req = 0x%.2X\n", *port_req);
+ /* loop over all muxed ports to find the one sending this */
+ for (i = 0; i < 8; i++) {
+ /* max 8 channels on MUX */
+ if (*port_req & (1 << i)) {
+ serial = get_serial_by_shared_int_and_type(shared_int,
+ (1 << i));
+ if (serial != NULL) {
+ D1("Pending read interrupt on port %d\n", i);
+ if (!test_and_set_bit(HSO_SERIAL_FLAG_RX_SENT,
+ &serial->flags)) {
+ /* Setup and send a ctrl req read on
+ * port i */
+ hso_mux_serial_read(serial);
+ } else {
+ D1("Already pending a read on "
+ "port %d\n", i);
+ }
+ }
+ }
+ }
+ /* Resubmit interrupt urb */
+ hso_mux_submit_intr_urb(shared_int, urb->dev, GFP_ATOMIC);
+}
+
+/* called for writing to muxed serial port */
+static int hso_mux_serial_write_data(struct hso_serial *serial)
+{
+ if (NULL == serial)
+ return -EINVAL;
+
+ return mux_device_request(serial,
+ USB_CDC_SEND_ENCAPSULATED_COMMAND,
+ serial->parent->port_spec & HSO_PORT_MASK,
+ serial->tx_urb,
+ &serial->ctrl_req_tx,
+ serial->tx_data, serial->tx_data_count);
+}
+
+/* write callback for Diag and CS port */
+static void hso_std_serial_write_bulk_callback(struct urb *urb)
+{
+ struct hso_serial *serial = urb->context;
+ int status = urb->status;
+
+ /* sanity check */
+ if (!serial) {
+ D1("serial == NULL");
+ return;
+ }
+
+ spin_lock(&serial->serial_lock);
+ serial->tx_urb_used = 0;
+ spin_unlock(&serial->serial_lock);
+ if (status) {
+ log_usb_status(status, __func__);
+ return;
+ }
+ hso_put_activity(serial->parent);
+ tty_wakeup(serial->tty);
+ hso_kick_transmit(serial);
+
+ D1(" ");
+ return;
+}
+
+/* called for writing diag or CS serial port */
+static int hso_std_serial_write_data(struct hso_serial *serial)
+{
+ int count = serial->tx_data_count;
+ int result;
+
+ usb_fill_bulk_urb(serial->tx_urb,
+ serial->parent->usb,
+ usb_sndbulkpipe(serial->parent->usb,
+ serial->out_endp->
+ bEndpointAddress & 0x7F),
+ serial->tx_data, serial->tx_data_count,
+ hso_std_serial_write_bulk_callback, serial);
+
+ result = usb_submit_urb(serial->tx_urb, GFP_ATOMIC);
+ if (result) {
+ dev_warn(&serial->parent->usb->dev,
+ "Failed to submit urb - res %d\n", result);
+ return result;
+ }
+
+ return count;
+}
+
+/* callback after read or write on muxed serial port */
+static void ctrl_callback(struct urb *urb)
+{
+ struct hso_serial *serial = urb->context;
+ struct usb_ctrlrequest *req;
+ int status = urb->status;
+
+ /* sanity check */
+ if (!serial)
+ return;
+
+ spin_lock(&serial->serial_lock);
+ serial->tx_urb_used = 0;
+ spin_unlock(&serial->serial_lock);
+ if (status) {
+ log_usb_status(status, __func__);
+ return;
+ }
+
+ /* what request? */
+ req = (struct usb_ctrlrequest *)(urb->setup_packet);
+ D4("\n--- Got muxed ctrl callback 0x%02X ---", status);
+ D4("Actual length of urb = %d\n", urb->actual_length);
+ DUMP1(urb->transfer_buffer, urb->actual_length);
+
+ if (req->bRequestType ==
+ (USB_DIR_IN | USB_TYPE_OPTION_VENDOR | USB_RECIP_INTERFACE)) {
+ /* response to a read command */
+ if (serial->open_count > 0) {
+ /* handle RX data the normal way */
+ put_rxbuf_data(urb, serial);
+ }
+
+ /* Re issue a read as long as we receive data. */
+ if (urb->actual_length != 0)
+ hso_mux_serial_read(serial);
+ else
+ clear_bit(HSO_SERIAL_FLAG_RX_SENT, &serial->flags);
+ } else {
+ hso_put_activity(serial->parent);
+ tty_wakeup(serial->tty);
+ /* response to a write command */
+ hso_kick_transmit(serial);
+ }
+}
+
+/* handle RX data for serial port */
+static void put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
+{
+ struct tty_struct *tty = serial->tty;
+
+ /* Sanity check */
+ if (urb == NULL || serial == NULL) {
+ D1("serial = NULL");
+ return;
+ }
+
+ /* Push data to tty */
+ if (tty && urb->actual_length) {
+ D1("data to push to tty");
+ tty_insert_flip_string(tty, urb->transfer_buffer,
+ urb->actual_length);
+ tty_flip_buffer_push(tty);
+ }
+}
+
+/* read callback for Diag and CS port */
+static void hso_std_serial_read_bulk_callback(struct urb *urb)
+{
+ struct hso_serial *serial = urb->context;
+ int result;
+ int status = urb->status;
+
+ /* sanity check */
+ if (!serial) {
+ D1("serial == NULL");
+ return;
+ } else if (status) {
+ log_usb_status(status, __func__);
+ return;
+ }
+
+ D4("\n--- Got serial_read_bulk callback %02x ---", status);
+ D1("Actual length = %d\n", urb->actual_length);
+ DUMP1(urb->transfer_buffer, urb->actual_length);
+
+ /* Anyone listening? */
+ if (serial->open_count == 0)
+ return;
+
+ if (status == 0) {
+ if (serial->parent->port_spec & HSO_INFO_CRC_BUG) {
+ u32 rest;
+ u8 crc_check[4] = { 0xDE, 0xAD, 0xBE, 0xEF };
+ rest =
+ urb->actual_length %
+ serial->in_endp->wMaxPacketSize;
+ if (((rest == 5) || (rest == 6))
+ && !memcmp(((u8 *) urb->transfer_buffer) +
+ urb->actual_length - 4, crc_check, 4)) {
+ urb->actual_length -= 4;
+ }
+ }
+ /* Valid data, handle RX data */
+ put_rxbuf_data(urb, serial);
+ } else if (status == -ENOENT || status == -ECONNRESET) {
+ /* Unlinked - check for throttled port. */
+ D2("Port %d, successfully unlinked urb", serial->minor);
+ } else {
+ D2("Port %d, status = %d for read urb", serial->minor, status);
+ return;
+ }
+
+ usb_mark_last_busy(urb->dev);
+
+ /* We are done with this URB, resubmit it. Prep the USB to wait for
+ * another frame */
+ usb_fill_bulk_urb(urb, serial->parent->usb,
+ usb_rcvbulkpipe(serial->parent->usb,
+ serial->in_endp->
+ bEndpointAddress & 0x7F),
+ urb->transfer_buffer, serial->rx_data_length,
+ hso_std_serial_read_bulk_callback, serial);
+ /* Give this to the USB subsystem so it can tell us when more data
+ * arrives. */
+ result = usb_submit_urb(urb, GFP_ATOMIC);
+ if (result) {
+ dev_err(&urb->dev->dev, "%s failed submit serial rx_urb %d",
+ __func__, result);
+ }
+}
+
+/* Base driver functions */
+
+static void hso_log_port(struct hso_device *hso_dev)
+{
+ char *port_type;
+ char port_dev[20];
+
+ switch (hso_dev->port_spec & HSO_PORT_MASK) {
+ case HSO_PORT_CONTROL:
+ port_type = "Control";
+ break;
+ case HSO_PORT_APP:
+ port_type = "Application";
+ break;
+ case HSO_PORT_GPS:
+ port_type = "GPS";
+ break;
+ case HSO_PORT_GPS_CONTROL:
+ port_type = "GPS control";
+ break;
+ case HSO_PORT_APP2:
+ port_type = "Application2";
+ break;
+ case HSO_PORT_PCSC:
+ port_type = "PCSC";
+ break;
+ case HSO_PORT_DIAG:
+ port_type = "Diagnostic";
+ break;
+ case HSO_PORT_DIAG2:
+ port_type = "Diagnostic2";
+ break;
+ case HSO_PORT_MODEM:
+ port_type = "Modem";
+ break;
+ case HSO_PORT_NETWORK:
+ port_type = "Network";
+ break;
+ default:
+ port_type = "Unknown";
+ break;
+ }
+ if ((hso_dev->port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) {
+ sprintf(port_dev, "%s", dev2net(hso_dev)->net->name);
+ } else
+ sprintf(port_dev, "/dev/%s%d", tty_filename,
+ dev2ser(hso_dev)->minor);
+
+ dev_dbg(&hso_dev->interface->dev, "HSO: Found %s port %s\n",
+ port_type, port_dev);
+}
+
+static int hso_start_net_device(struct hso_device *hso_dev)
+{
+ int i, result = 0;
+ struct hso_net *hso_net = dev2net(hso_dev);
+
+ if (!hso_net)
+ return -ENODEV;
+
+ /* send URBs for all read buffers */
+ for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) {
+
+ /* Prep a receive URB */
+ usb_fill_bulk_urb(hso_net->mux_bulk_rx_urb_pool[i],
+ hso_dev->usb,
+ usb_rcvbulkpipe(hso_dev->usb,
+ hso_net->in_endp->
+ bEndpointAddress & 0x7F),
+ hso_net->mux_bulk_rx_buf_pool[i],
+ MUX_BULK_RX_BUF_SIZE, read_bulk_callback,
+ hso_net);
+
+ /* Put it out there so the device can send us stuff */
+ result = usb_submit_urb(hso_net->mux_bulk_rx_urb_pool[i],
+ GFP_NOIO);
+ if (result)
+ dev_warn(&hso_dev->usb->dev,
+ "%s failed mux_bulk_rx_urb[%d] %d\n", __func__,
+ i, result);
+ }
+
+ return result;
+}
+
+static int hso_stop_net_device(struct hso_device *hso_dev)
+{
+ int i;
+ struct hso_net *hso_net = dev2net(hso_dev);
+
+ if (!hso_net)
+ return -ENODEV;
+
+ for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) {
+ if (hso_net->mux_bulk_rx_urb_pool[i])
+ usb_kill_urb(hso_net->mux_bulk_rx_urb_pool[i]);
+
+ }
+ if (hso_net->mux_bulk_tx_urb)
+ usb_kill_urb(hso_net->mux_bulk_tx_urb);
+
+ return 0;
+}
+
+static int hso_start_serial_device(struct hso_device *hso_dev, gfp_t flags)
+{
+ int i, result = 0;
+ struct hso_serial *serial = dev2ser(hso_dev);
+
+ if (!serial)
+ return -ENODEV;
+
+ /* If it is not the MUX port fill in and submit a bulk urb (already
+ * allocated in hso_serial_start) */
+ if (!(serial->parent->port_spec & HSO_INTF_MUX)) {
+ for (i = 0; i < serial->num_rx_urbs; i++) {
+ usb_fill_bulk_urb(serial->rx_urb[i],
+ serial->parent->usb,
+ usb_rcvbulkpipe(serial->parent->usb,
+ serial->in_endp->
+ bEndpointAddress &
+ 0x7F),
+ serial->rx_data[i],
+ serial->rx_data_length,
+ hso_std_serial_read_bulk_callback,
+ serial);
+ result = usb_submit_urb(serial->rx_urb[i], flags);
+ if (result) {
+ dev_warn(&serial->parent->usb->dev,
+ "Failed to submit urb - res %d\n",
+ result);
+ break;
+ }
+ }
+ } else {
+ mutex_lock(&serial->shared_int->shared_int_lock);
+ if (!serial->shared_int->use_count) {
+ result =
+ hso_mux_submit_intr_urb(serial->shared_int,
+ hso_dev->usb, flags);
+ }
+ serial->shared_int->use_count++;
+ mutex_unlock(&serial->shared_int->shared_int_lock);
+ }
+
+ return result;
+}
+
+static int hso_stop_serial_device(struct hso_device *hso_dev)
+{
+ int i;
+ struct hso_serial *serial = dev2ser(hso_dev);
+
+ if (!serial)
+ return -ENODEV;
+
+ for (i = 0; i < serial->num_rx_urbs; i++) {
+ if (serial->rx_urb[i])
+ usb_kill_urb(serial->rx_urb[i]);
+ }
+
+ if (serial->tx_urb)
+ usb_kill_urb(serial->tx_urb);
+
+ if (serial->shared_int) {
+ mutex_lock(&serial->shared_int->shared_int_lock);
+ if (serial->shared_int->use_count &&
+ (--serial->shared_int->use_count == 0)) {
+ struct urb *urb;
+
+ urb = serial->shared_int->shared_intr_urb;
+ if (urb)
+ usb_kill_urb(urb);
+ }
+ mutex_unlock(&serial->shared_int->shared_int_lock);
+ }
+
+ return 0;
+}
+
+static void hso_serial_common_free(struct hso_serial *serial)
+{
+ int i;
+
+ if (serial->parent->dev)
+ device_remove_file(serial->parent->dev, &dev_attr_hsotype);
+
+ tty_unregister_device(tty_drv, serial->minor);
+
+ for (i = 0; i < serial->num_rx_urbs; i++) {
+ /* unlink and free RX URB */
+ usb_free_urb(serial->rx_urb[i]);
+ /* free the RX buffer */
+ kfree(serial->rx_data[i]);
+ }
+
+ /* unlink and free TX URB */
+ usb_free_urb(serial->tx_urb);
+ kfree(serial->tx_data);
+}
+
+static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
+ int rx_size, int tx_size)
+{
+ struct device *dev;
+ int minor;
+ int i;
+
+ minor = get_free_serial_index();
+ if (minor < 0)
+ goto exit;
+
+ /* register our minor number */
+ serial->parent->dev = tty_register_device(tty_drv, minor,
+ &serial->parent->interface->dev);
+ dev = serial->parent->dev;
+ dev->driver_data = serial->parent;
+ i = device_create_file(dev, &dev_attr_hsotype);
+
+ /* fill in specific data for later use */
+ serial->minor = minor;
+ serial->magic = HSO_SERIAL_MAGIC;
+ spin_lock_init(&serial->serial_lock);
+ serial->num_rx_urbs = num_urbs;
+
+ /* RX, allocate urb and initialize */
+
+ /* prepare our RX buffer */
+ serial->rx_data_length = rx_size;
+ for (i = 0; i < serial->num_rx_urbs; i++) {
+ serial->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
+ if (!serial->rx_urb[i]) {
+ dev_err(dev, "Could not allocate urb?\n");
+ goto exit;
+ }
+ serial->rx_urb[i]->transfer_buffer = NULL;
+ serial->rx_urb[i]->transfer_buffer_length = 0;
+ serial->rx_data[i] = kzalloc(serial->rx_data_length,
+ GFP_KERNEL);
+ if (!serial->rx_data[i]) {
+ dev_err(dev, "%s - Out of memory\n", __func__);
+ goto exit;
+ }
+ }
+
+ /* TX, allocate urb and initialize */
+ serial->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!serial->tx_urb) {
+ dev_err(dev, "Could not allocate urb?\n");
+ goto exit;
+ }
+ serial->tx_urb->transfer_buffer = NULL;
+ serial->tx_urb->transfer_buffer_length = 0;
+ /* prepare our TX buffer */
+ serial->tx_data_count = 0;
+ serial->tx_buffer_count = 0;
+ serial->tx_data_length = tx_size;
+ serial->tx_data = kzalloc(serial->tx_data_length, GFP_KERNEL);
+ if (!serial->tx_data) {
+ dev_err(dev, "%s - Out of memory", __func__);
+ goto exit;
+ }
+ serial->tx_buffer = kzalloc(serial->tx_data_length, GFP_KERNEL);
+ if (!serial->tx_buffer) {
+ dev_err(dev, "%s - Out of memory", __func__);
+ goto exit;
+ }
+
+ return 0;
+exit:
+ hso_serial_common_free(serial);
+ return -1;
+}
+
+/* Frees a general hso device */
+static void hso_free_device(struct hso_device *hso_dev)
+{
+ kfree(hso_dev);
+}
+
+/* Creates a general hso device */
+static struct hso_device *hso_create_device(struct usb_interface *intf,
+ int port_spec)
+{
+ struct hso_device *hso_dev;
+
+ hso_dev = kzalloc(sizeof(*hso_dev), GFP_ATOMIC);
+ if (!hso_dev)
+ return NULL;
+
+ hso_dev->port_spec = port_spec;
+ hso_dev->usb = interface_to_usbdev(intf);
+ hso_dev->interface = intf;
+ kref_init(&hso_dev->ref);
+ mutex_init(&hso_dev->mutex);
+
+ INIT_WORK(&hso_dev->async_get_intf, async_get_intf);
+ INIT_WORK(&hso_dev->async_put_intf, async_put_intf);
+
+ return hso_dev;
+}
+
+/* Removes a network device in the network device table */
+static int remove_net_device(struct hso_device *hso_dev)
+{
+ int i;
+
+ for (i = 0; i < HSO_MAX_NET_DEVICES; i++) {
+ if (network_table[i] == hso_dev) {
+ network_table[i] = NULL;
+ break;
+ }
+ }
+ if (i == HSO_MAX_NET_DEVICES)
+ return -1;
+ return 0;
+}
+
+/* Frees our network device */
+static void hso_free_net_device(struct hso_device *hso_dev)
+{
+ int i;
+ struct hso_net *hso_net = dev2net(hso_dev);
+
+ if (!hso_net)
+ return;
+
+ /* start freeing */
+ for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) {
+ usb_free_urb(hso_net->mux_bulk_rx_urb_pool[i]);
+ kfree(hso_net->mux_bulk_rx_buf_pool[i]);
+ }
+ usb_free_urb(hso_net->mux_bulk_tx_urb);
+ kfree(hso_net->mux_bulk_tx_buf);
+
+ remove_net_device(hso_net->parent);
+
+ if (hso_net->net) {
+ unregister_netdev(hso_net->net);
+ free_netdev(hso_net->net);
+ }
+
+ hso_free_device(hso_dev);
+}
+
+/* initialize the network interface */
+static void hso_net_init(struct net_device *net)
+{
+ struct hso_net *hso_net = netdev_priv(net);
+
+ D1("sizeof hso_net is %d", (int)sizeof(*hso_net));
+
+ /* fill in the other fields */
+ net->open = hso_net_open;
+ net->stop = hso_net_close;
+ net->hard_start_xmit = hso_net_start_xmit;
+ net->tx_timeout = hso_net_tx_timeout;
+ net->watchdog_timeo = HSO_NET_TX_TIMEOUT;
+ net->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
+ net->type = ARPHRD_NONE;
+ net->mtu = DEFAULT_MTU - 14;
+ net->tx_queue_len = 10;
+ SET_ETHTOOL_OPS(net, &ops);
+
+ /* and initialize the semaphore */
+ spin_lock_init(&hso_net->net_lock);
+}
+
+/* Adds a network device in the network device table */
+static int add_net_device(struct hso_device *hso_dev)
+{
+ int i;
+
+ for (i = 0; i < HSO_MAX_NET_DEVICES; i++) {
+ if (network_table[i] == NULL) {
+ network_table[i] = hso_dev;
+ break;
+ }
+ }
+ if (i == HSO_MAX_NET_DEVICES)
+ return -1;
+ return 0;
+}
+
+static int hso_radio_toggle(void *data, enum rfkill_state state)
+{
+ struct hso_device *hso_dev = data;
+ int enabled = (state == RFKILL_STATE_ON);
+ int rv;
+
+ mutex_lock(&hso_dev->mutex);
+ if (hso_dev->usb_gone)
+ rv = 0;
+ else
+ rv = usb_control_msg(hso_dev->usb, usb_rcvctrlpipe(hso_dev->usb, 0),
+ enabled ? 0x82 : 0x81, 0x40, 0, 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ mutex_unlock(&hso_dev->mutex);
+ return rv;
+}
+
+/* Creates and sets up everything for rfkill */
+static void hso_create_rfkill(struct hso_device *hso_dev,
+ struct usb_interface *interface)
+{
+ struct hso_net *hso_net = dev2net(hso_dev);
+ struct device *dev = hso_dev->dev;
+ char *rfkn;
+
+ hso_net->rfkill = rfkill_allocate(&interface_to_usbdev(interface)->dev,
+ RFKILL_TYPE_WLAN);
+ if (!hso_net->rfkill) {
+ dev_err(dev, "%s - Out of memory", __func__);
+ return;
+ }
+ rfkn = kzalloc(20, GFP_KERNEL);
+ if (!rfkn) {
+ rfkill_free(hso_net->rfkill);
+ dev_err(dev, "%s - Out of memory", __func__);
+ return;
+ }
+ snprintf(rfkn, 20, "hso-%d",
+ interface->altsetting->desc.bInterfaceNumber);
+ hso_net->rfkill->name = rfkn;
+ hso_net->rfkill->state = RFKILL_STATE_ON;
+ hso_net->rfkill->data = hso_dev;
+ hso_net->rfkill->toggle_radio = hso_radio_toggle;
+ if (rfkill_register(hso_net->rfkill) < 0) {
+ kfree(rfkn);
+ hso_net->rfkill->name = NULL;
+ rfkill_free(hso_net->rfkill);
+ dev_err(dev, "%s - Failed to register rfkill", __func__);
+ return;
+ }
+}
+
+/* Creates our network device */
+static struct hso_device *hso_create_net_device(struct usb_interface *interface)
+{
+ int result, i;
+ struct net_device *net;
+ struct hso_net *hso_net;
+ struct hso_device *hso_dev;
+
+ hso_dev = hso_create_device(interface, HSO_INTF_MUX | HSO_PORT_NETWORK);
+ if (!hso_dev)
+ return NULL;
+
+ /* allocate our network device, then we can put in our private data */
+ /* call hso_net_init to do the basic initialization */
+ net = alloc_netdev(sizeof(struct hso_net), "hso%d", hso_net_init);
+ if (!net) {
+ dev_err(&interface->dev, "Unable to create ethernet device\n");
+ goto exit;
+ }
+
+ hso_net = netdev_priv(net);
+
+ hso_dev->port_data.dev_net = hso_net;
+ hso_net->net = net;
+ hso_net->parent = hso_dev;
+
+ hso_net->in_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_BULK,
+ USB_DIR_IN);
+ if (!hso_net->in_endp) {
+ dev_err(&interface->dev, "Can't find BULK IN endpoint\n");
+ goto exit;
+ }
+ hso_net->out_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_BULK,
+ USB_DIR_OUT);
+ if (!hso_net->out_endp) {
+ dev_err(&interface->dev, "Can't find BULK OUT endpoint\n");
+ goto exit;
+ }
+ SET_NETDEV_DEV(net, &interface->dev);
+
+ /* registering our net device */
+ result = register_netdev(net);
+ if (result) {
+ dev_err(&interface->dev, "Failed to register device\n");
+ goto exit;
+ }
+
+ /* start allocating */
+ for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) {
+ hso_net->mux_bulk_rx_urb_pool[i] = usb_alloc_urb(0, GFP_KERNEL);
+ if (!hso_net->mux_bulk_rx_urb_pool[i]) {
+ dev_err(&interface->dev, "Could not allocate rx urb\n");
+ goto exit;
+ }
+ hso_net->mux_bulk_rx_buf_pool[i] = kzalloc(MUX_BULK_RX_BUF_SIZE,
+ GFP_KERNEL);
+ if (!hso_net->mux_bulk_rx_buf_pool[i]) {
+ dev_err(&interface->dev, "Could not allocate rx buf\n");
+ goto exit;
+ }
+ }
+ hso_net->mux_bulk_tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!hso_net->mux_bulk_tx_urb) {
+ dev_err(&interface->dev, "Could not allocate tx urb\n");
+ goto exit;
+ }
+ hso_net->mux_bulk_tx_buf = kzalloc(MUX_BULK_TX_BUF_SIZE, GFP_KERNEL);
+ if (!hso_net->mux_bulk_tx_buf) {
+ dev_err(&interface->dev, "Could not allocate tx buf\n");
+ goto exit;
+ }
+
+ add_net_device(hso_dev);
+
+ hso_log_port(hso_dev);
+
+ hso_create_rfkill(hso_dev, interface);
+
+ return hso_dev;
+exit:
+ hso_free_net_device(hso_dev);
+ return NULL;
+}
+
+/* Frees an AT channel ( goes for both mux and non-mux ) */
+static void hso_free_serial_device(struct hso_device *hso_dev)
+{
+ struct hso_serial *serial = dev2ser(hso_dev);
+
+ if (!serial)
+ return;
+ set_serial_by_index(serial->minor, NULL);
+
+ hso_serial_common_free(serial);
+
+ if (serial->shared_int) {
+ mutex_lock(&serial->shared_int->shared_int_lock);
+ if (--serial->shared_int->ref_count == 0)
+ hso_free_shared_int(serial->shared_int);
+ else
+ mutex_unlock(&serial->shared_int->shared_int_lock);
+ }
+ kfree(serial);
+ hso_free_device(hso_dev);
+}
+
+/* Creates a bulk AT channel */
+static struct hso_device *hso_create_bulk_serial_device(
+ struct usb_interface *interface, int port)
+{
+ struct hso_device *hso_dev;
+ struct hso_serial *serial;
+ int num_urbs;
+
+ hso_dev = hso_create_device(interface, port);
+ if (!hso_dev)
+ return NULL;
+
+ serial = kzalloc(sizeof(*serial), GFP_KERNEL);
+ if (!serial)
+ goto exit;
+
+ serial->parent = hso_dev;
+ hso_dev->port_data.dev_serial = serial;
+
+ if (port & HSO_PORT_MODEM)
+ num_urbs = 2;
+ else
+ num_urbs = 1;
+
+ if (hso_serial_common_create(serial, num_urbs, BULK_URB_RX_SIZE,
+ BULK_URB_TX_SIZE))
+ goto exit;
+
+ serial->in_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_BULK,
+ USB_DIR_IN);
+ if (!serial->in_endp) {
+ dev_err(&interface->dev, "Failed to find BULK IN ep\n");
+ goto exit;
+ }
+
+ if (!
+ (serial->out_endp =
+ hso_get_ep(interface, USB_ENDPOINT_XFER_BULK, USB_DIR_OUT))) {
+ dev_err(&interface->dev, "Failed to find BULK IN ep\n");
+ goto exit;
+ }
+
+ serial->write_data = hso_std_serial_write_data;
+
+ /* and record this serial */
+ set_serial_by_index(serial->minor, serial);
+
+ /* setup the proc dirs and files if needed */
+ hso_log_port(hso_dev);
+
+ /* done, return it */
+ return hso_dev;
+exit:
+ if (hso_dev && serial)
+ hso_serial_common_free(serial);
+ kfree(serial);
+ hso_free_device(hso_dev);
+ return NULL;
+}
+
+/* Creates a multiplexed AT channel */
+static
+struct hso_device *hso_create_mux_serial_device(struct usb_interface *interface,
+ int port,
+ struct hso_shared_int *mux)
+{
+ struct hso_device *hso_dev;
+ struct hso_serial *serial;
+ int port_spec;
+
+ port_spec = HSO_INTF_MUX;
+ port_spec &= ~HSO_PORT_MASK;
+
+ port_spec |= hso_mux_to_port(port);
+ if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NO_PORT)
+ return NULL;
+
+ hso_dev = hso_create_device(interface, port_spec);
+ if (!hso_dev)
+ return NULL;
+
+ serial = kzalloc(sizeof(*serial), GFP_KERNEL);
+ if (!serial)
+ goto exit;
+
+ hso_dev->port_data.dev_serial = serial;
+ serial->parent = hso_dev;
+
+ if (hso_serial_common_create
+ (serial, 1, CTRL_URB_RX_SIZE, CTRL_URB_TX_SIZE))
+ goto exit;
+
+ serial->tx_data_length--;
+ serial->write_data = hso_mux_serial_write_data;
+
+ serial->shared_int = mux;
+ mutex_lock(&serial->shared_int->shared_int_lock);
+ serial->shared_int->ref_count++;
+ mutex_unlock(&serial->shared_int->shared_int_lock);
+
+ /* and record this serial */
+ set_serial_by_index(serial->minor, serial);
+
+ /* setup the proc dirs and files if needed */
+ hso_log_port(hso_dev);
+
+ /* done, return it */
+ return hso_dev;
+
+exit:
+ if (serial) {
+ tty_unregister_device(tty_drv, serial->minor);
+ kfree(serial);
+ }
+ if (hso_dev)
+ hso_free_device(hso_dev);
+ return NULL;
+
+}
+
+static void hso_free_shared_int(struct hso_shared_int *mux)
+{
+ usb_free_urb(mux->shared_intr_urb);
+ kfree(mux->shared_intr_buf);
+ mutex_unlock(&mux->shared_int_lock);
+ kfree(mux);
+}
+
+static
+struct hso_shared_int *hso_create_shared_int(struct usb_interface *interface)
+{
+ struct hso_shared_int *mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+
+ if (!mux)
+ return NULL;
+
+ mux->intr_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_INT,
+ USB_DIR_IN);
+ if (!mux->intr_endp) {
+ dev_err(&interface->dev, "Can't find INT IN endpoint\n");
+ goto exit;
+ }
+
+ mux->shared_intr_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!mux->shared_intr_urb) {
+ dev_err(&interface->dev, "Could not allocate intr urb?");
+ goto exit;
+ }
+ mux->shared_intr_buf = kzalloc(mux->intr_endp->wMaxPacketSize,
+ GFP_KERNEL);
+ if (!mux->shared_intr_buf) {
+ dev_err(&interface->dev, "Could not allocate intr buf?");
+ goto exit;
+ }
+
+ mutex_init(&mux->shared_int_lock);
+
+ return mux;
+
+exit:
+ kfree(mux->shared_intr_buf);
+ usb_free_urb(mux->shared_intr_urb);
+ kfree(mux);
+ return NULL;
+}
+
+/* Gets the port spec for a certain interface */
+static int hso_get_config_data(struct usb_interface *interface)
+{
+ struct usb_device *usbdev = interface_to_usbdev(interface);
+ u8 config_data[17];
+ u32 if_num = interface->altsetting->desc.bInterfaceNumber;
+ s32 result;
+
+ if (usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
+ 0x86, 0xC0, 0, 0, config_data, 17,
+ USB_CTRL_SET_TIMEOUT) != 0x11) {
+ return -EIO;
+ }
+
+ switch (config_data[if_num]) {
+ case 0x0:
+ result = 0;
+ break;
+ case 0x1:
+ result = HSO_PORT_DIAG;
+ break;
+ case 0x2:
+ result = HSO_PORT_GPS;
+ break;
+ case 0x3:
+ result = HSO_PORT_GPS_CONTROL;
+ break;
+ case 0x4:
+ result = HSO_PORT_APP;
+ break;
+ case 0x5:
+ result = HSO_PORT_APP2;
+ break;
+ case 0x6:
+ result = HSO_PORT_CONTROL;
+ break;
+ case 0x7:
+ result = HSO_PORT_NETWORK;
+ break;
+ case 0x8:
+ result = HSO_PORT_MODEM;
+ break;
+ case 0x9:
+ result = HSO_PORT_MSD;
+ break;
+ case 0xa:
+ result = HSO_PORT_PCSC;
+ break;
+ case 0xb:
+ result = HSO_PORT_VOICE;
+ break;
+ default:
+ result = 0;
+ }
+
+ if (result)
+ result |= HSO_INTF_BULK;
+
+ if (config_data[16] & 0x1)
+ result |= HSO_INFO_CRC_BUG;
+
+ return result;
+}
+
+/* called once for each interface upon device insertion */
+static int hso_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ int mux, i, if_num, port_spec;
+ unsigned char port_mask;
+ struct hso_device *hso_dev = NULL;
+ struct hso_shared_int *shared_int;
+ struct hso_device *tmp_dev = NULL;
+
+ if_num = interface->altsetting->desc.bInterfaceNumber;
+
+ /* Get the interface/port specification from either driver_info or from
+ * the device itself */
+ if (id->driver_info)
+ port_spec = ((u32 *)(id->driver_info))[if_num];
+ else
+ port_spec = hso_get_config_data(interface);
+
+ if (interface->cur_altsetting->desc.bInterfaceClass != 0xFF) {
+ dev_err(&interface->dev, "Not our interface\n");
+ return -ENODEV;
+ }
+ /* Check if we need to switch to alt interfaces prior to port
+ * configuration */
+ if (interface->num_altsetting > 1)
+ usb_set_interface(interface_to_usbdev(interface), if_num, 1);
+ interface->needs_remote_wakeup = 1;
+
+ /* Allocate new hso device(s) */
+ switch (port_spec & HSO_INTF_MASK) {
+ case HSO_INTF_MUX:
+ if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) {
+ /* Create the network device */
+ if (!disable_net) {
+ hso_dev = hso_create_net_device(interface);
+ if (!hso_dev)
+ goto exit;
+ tmp_dev = hso_dev;
+ }
+ }
+
+ if (hso_get_mux_ports(interface, &port_mask))
+ /* TODO: de-allocate everything */
+ goto exit;
+
+ shared_int = hso_create_shared_int(interface);
+ if (!shared_int)
+ goto exit;
+
+ for (i = 1, mux = 0; i < 0x100; i = i << 1, mux++) {
+ if (port_mask & i) {
+ hso_dev = hso_create_mux_serial_device(
+ interface, i, shared_int);
+ if (!hso_dev)
+ goto exit;
+ }
+ }
+
+ if (tmp_dev)
+ hso_dev = tmp_dev;
+ break;
+
+ case HSO_INTF_BULK:
+ /* It's a regular bulk interface */
+ if (((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK)
+ && !disable_net)
+ hso_dev = hso_create_net_device(interface);
+ else
+ hso_dev =
+ hso_create_bulk_serial_device(interface, port_spec);
+ if (!hso_dev)
+ goto exit;
+ break;
+ default:
+ goto exit;
+ }
+
+ usb_driver_claim_interface(&hso_driver, interface, hso_dev);
+
+ /* save our data pointer in this device */
+ usb_set_intfdata(interface, hso_dev);
+
+ /* done */
+ return 0;
+exit:
+ hso_free_interface(interface);
+ return -ENODEV;
+}
+
+/* device removed, cleaning up */
+static void hso_disconnect(struct usb_interface *interface)
+{
+ hso_free_interface(interface);
+
+ /* remove reference of our private data */
+ usb_set_intfdata(interface, NULL);
+
+ usb_driver_release_interface(&hso_driver, interface);
+}
+
+static void async_get_intf(struct work_struct *data)
+{
+ struct hso_device *hso_dev =
+ container_of(data, struct hso_device, async_get_intf);
+ usb_autopm_get_interface(hso_dev->interface);
+}
+
+static void async_put_intf(struct work_struct *data)
+{
+ struct hso_device *hso_dev =
+ container_of(data, struct hso_device, async_put_intf);
+ usb_autopm_put_interface(hso_dev->interface);
+}
+
+static int hso_get_activity(struct hso_device *hso_dev)
+{
+ if (hso_dev->usb->state == USB_STATE_SUSPENDED) {
+ if (!hso_dev->is_active) {
+ hso_dev->is_active = 1;
+ schedule_work(&hso_dev->async_get_intf);
+ }
+ }
+
+ if (hso_dev->usb->state != USB_STATE_CONFIGURED)
+ return -EAGAIN;
+
+ usb_mark_last_busy(hso_dev->usb);
+
+ return 0;
+}
+
+static int hso_put_activity(struct hso_device *hso_dev)
+{
+ if (hso_dev->usb->state != USB_STATE_SUSPENDED) {
+ if (hso_dev->is_active) {
+ hso_dev->is_active = 0;
+ schedule_work(&hso_dev->async_put_intf);
+ return -EAGAIN;
+ }
+ }
+ hso_dev->is_active = 0;
+ return 0;
+}
+
+/* called by kernel when we need to suspend device */
+static int hso_suspend(struct usb_interface *iface, pm_message_t message)
+{
+ int i, result;
+
+ /* Stop all serial ports */
+ for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
+ if (serial_table[i] && (serial_table[i]->interface == iface)) {
+ result = hso_stop_serial_device(serial_table[i]);
+ if (result)
+ goto out;
+ }
+ }
+
+ /* Stop all network ports */
+ for (i = 0; i < HSO_MAX_NET_DEVICES; i++) {
+ if (network_table[i] &&
+ (network_table[i]->interface == iface)) {
+ result = hso_stop_net_device(network_table[i]);
+ if (result)
+ goto out;
+ }
+ }
+
+out:
+ return 0;
+}
+
+/* called by kernel when we need to resume device */
+static int hso_resume(struct usb_interface *iface)
+{
+ int i, result = 0;
+ struct hso_net *hso_net;
+
+ /* Start all serial ports */
+ for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
+ if (serial_table[i] && (serial_table[i]->interface == iface)) {
+ if (dev2ser(serial_table[i])->open_count) {
+ result =
+ hso_start_serial_device(serial_table[i], GFP_NOIO);
+ hso_kick_transmit(dev2ser(serial_table[i]));
+ if (result)
+ goto out;
+ }
+ }
+ }
+
+ /* Start all network ports */
+ for (i = 0; i < HSO_MAX_NET_DEVICES; i++) {
+ if (network_table[i] &&
+ (network_table[i]->interface == iface)) {
+ hso_net = dev2net(network_table[i]);
+ /* First transmit any lingering data, then restart the
+ * device. */
+ if (hso_net->skb_tx_buf) {
+ dev_dbg(&iface->dev,
+ "Transmitting lingering data\n");
+ hso_net_start_xmit(hso_net->skb_tx_buf,
+ hso_net->net);
+ }
+ result = hso_start_net_device(network_table[i]);
+ if (result)
+ goto out;
+ }
+ }
+
+out:
+ return result;
+}
+
+static void hso_serial_ref_free(struct kref *ref)
+{
+ struct hso_device *hso_dev = container_of(ref, struct hso_device, ref);
+
+ hso_free_serial_device(hso_dev);
+}
+
+static void hso_free_interface(struct usb_interface *interface)
+{
+ struct hso_serial *hso_dev;
+ int i;
+
+ for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
+ if (serial_table[i]
+ && (serial_table[i]->interface == interface)) {
+ hso_dev = dev2ser(serial_table[i]);
+ if (hso_dev->tty)
+ tty_hangup(hso_dev->tty);
+ mutex_lock(&hso_dev->parent->mutex);
+ hso_dev->parent->usb_gone = 1;
+ mutex_unlock(&hso_dev->parent->mutex);
+ kref_put(&serial_table[i]->ref, hso_serial_ref_free);
+ }
+ }
+
+ for (i = 0; i < HSO_MAX_NET_DEVICES; i++) {
+ if (network_table[i]
+ && (network_table[i]->interface == interface)) {
+ struct rfkill *rfk = dev2net(network_table[i])->rfkill;
+ /* hso_stop_net_device doesn't stop the net queue since
+ * traffic needs to start it again when suspended */
+ netif_stop_queue(dev2net(network_table[i])->net);
+ hso_stop_net_device(network_table[i]);
+ cancel_work_sync(&network_table[i]->async_put_intf);
+ cancel_work_sync(&network_table[i]->async_get_intf);
+ if(rfk)
+ rfkill_unregister(rfk);
+ hso_free_net_device(network_table[i]);
+ }
+ }
+}
+
+/* Helper functions */
+
+/* Get the endpoint ! */
+static struct usb_endpoint_descriptor *hso_get_ep(struct usb_interface *intf,
+ int type, int dir)
+{
+ int i;
+ struct usb_host_interface *iface = intf->cur_altsetting;
+ struct usb_endpoint_descriptor *endp;
+
+ for (i = 0; i < iface->desc.bNumEndpoints; i++) {
+ endp = &iface->endpoint[i].desc;
+ if (((endp->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == dir) &&
+ ((endp->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == type))
+ return endp;
+ }
+
+ return NULL;
+}
+
+/* Get the byte that describes which ports are enabled */
+static int hso_get_mux_ports(struct usb_interface *intf, unsigned char *ports)
+{
+ int i;
+ struct usb_host_interface *iface = intf->cur_altsetting;
+
+ if (iface->extralen == 3) {
+ *ports = iface->extra[2];
+ return 0;
+ }
+
+ for (i = 0; i < iface->desc.bNumEndpoints; i++) {
+ if (iface->endpoint[i].extralen == 3) {
+ *ports = iface->endpoint[i].extra[2];
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+/* interrupt urb needs to be submitted, used for serial read of muxed port */
+static int hso_mux_submit_intr_urb(struct hso_shared_int *shared_int,
+ struct usb_device *usb, gfp_t gfp)
+{
+ int result;
+
+ usb_fill_int_urb(shared_int->shared_intr_urb, usb,
+ usb_rcvintpipe(usb,
+ shared_int->intr_endp->bEndpointAddress & 0x7F),
+ shared_int->shared_intr_buf,
+ shared_int->intr_endp->wMaxPacketSize,
+ intr_callback, shared_int,
+ shared_int->intr_endp->bInterval);
+
+ result = usb_submit_urb(shared_int->shared_intr_urb, gfp);
+ if (result)
+ dev_warn(&usb->dev, "%s failed mux_intr_urb %d", __func__,
+ result);
+
+ return result;
+}
+
+/* operations setup of the serial interface */
+static struct tty_operations hso_serial_ops = {
+ .open = hso_serial_open,
+ .close = hso_serial_close,
+ .write = hso_serial_write,
+ .write_room = hso_serial_write_room,
+ .set_termios = hso_serial_set_termios,
+ .chars_in_buffer = hso_serial_chars_in_buffer,
+ .tiocmget = hso_serial_tiocmget,
+ .tiocmset = hso_serial_tiocmset,
+};
+
+static struct usb_driver hso_driver = {
+ .name = driver_name,
+ .probe = hso_probe,
+ .disconnect = hso_disconnect,
+ .id_table = hso_ids,
+ .suspend = hso_suspend,
+ .resume = hso_resume,
+ .supports_autosuspend = 1,
+};
+
+static int __init hso_init(void)
+{
+ int i;
+ int result;
+
+ /* put it in the log */
+ printk(KERN_INFO "hso: %s\n", version);
+
+ /* Initialise the serial table semaphore and table */
+ spin_lock_init(&serial_table_lock);
+ for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++)
+ serial_table[i] = NULL;
+
+ /* allocate our driver using the proper amount of supported minors */
+ tty_drv = alloc_tty_driver(HSO_SERIAL_TTY_MINORS);
+ if (!tty_drv)
+ return -ENOMEM;
+
+ /* fill in all needed values */
+ tty_drv->magic = TTY_DRIVER_MAGIC;
+ tty_drv->owner = THIS_MODULE;
+ tty_drv->driver_name = driver_name;
+ tty_drv->name = tty_filename;
+
+ /* if major number is provided as parameter, use that one */
+ if (tty_major)
+ tty_drv->major = tty_major;
+
+ tty_drv->minor_start = 0;
+ tty_drv->num = HSO_SERIAL_TTY_MINORS;
+ tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
+ tty_drv->subtype = SERIAL_TYPE_NORMAL;
+ tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ tty_drv->init_termios = tty_std_termios;
+ tty_drv->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ tty_drv->termios = hso_serial_termios;
+ tty_drv->termios_locked = hso_serial_termios_locked;
+ tty_set_operations(tty_drv, &hso_serial_ops);
+
+ /* register the tty driver */
+ result = tty_register_driver(tty_drv);
+ if (result) {
+ printk(KERN_ERR "%s - tty_register_driver failed(%d)\n",
+ __func__, result);
+ return result;
+ }
+
+ /* register this module as an usb driver */
+ result = usb_register(&hso_driver);
+ if (result) {
+ printk(KERN_ERR "Could not register hso driver? error: %d\n",
+ result);
+ /* cleanup serial interface */
+ tty_unregister_driver(tty_drv);
+ return result;
+ }
+
+ /* done */
+ return 0;
+}
+
+static void __exit hso_exit(void)
+{
+ printk(KERN_INFO "hso: unloaded\n");
+
+ tty_unregister_driver(tty_drv);
+ /* deregister the usb driver */
+ usb_deregister(&hso_driver);
+}
+
+/* Module definitions */
+module_init(hso_init);
+module_exit(hso_exit);
+
+MODULE_AUTHOR(MOD_AUTHOR);
+MODULE_DESCRIPTION(MOD_DESCRIPTION);
+MODULE_LICENSE(MOD_LICENSE);
+MODULE_INFO(Version, DRIVER_VERSION);
+
+/* change the debug level (eg: insmod hso.ko debug=0x04) */
+MODULE_PARM_DESC(debug, "Level of debug [0x01 | 0x02 | 0x04 | 0x08 | 0x10]");
+module_param(debug, int, S_IRUGO | S_IWUSR);
+
+/* set the major tty number (eg: insmod hso.ko tty_major=245) */
+MODULE_PARM_DESC(tty_major, "Set the major tty number");
+module_param(tty_major, int, S_IRUGO | S_IWUSR);
+
+/* disable network interface (eg: insmod hso.ko disable_net=1) */
+MODULE_PARM_DESC(disable_net, "Disable the network interface");
+module_param(disable_net, int, S_IRUGO | S_IWUSR);
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 6b8d882..bcbf2fa 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -1495,24 +1495,18 @@
* enough. This function returns a negative value if the received
* packet is too big or if memory is exhausted.
*/
-static inline int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size,
- struct velocity_info *vptr)
+static int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size,
+ struct velocity_info *vptr)
{
int ret = -1;
-
if (pkt_size < rx_copybreak) {
struct sk_buff *new_skb;
- new_skb = dev_alloc_skb(pkt_size + 2);
+ new_skb = netdev_alloc_skb(vptr->dev, pkt_size + 2);
if (new_skb) {
- new_skb->dev = vptr->dev;
new_skb->ip_summed = rx_skb[0]->ip_summed;
-
- if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN)
- skb_reserve(new_skb, 2);
-
- skb_copy_from_linear_data(rx_skb[0], new_skb->data,
- pkt_size);
+ skb_reserve(new_skb, 2);
+ skb_copy_from_linear_data(*rx_skb, new_skb->data, pkt_size);
*rx_skb = new_skb;
ret = 0;
}
@@ -1533,12 +1527,8 @@
static inline void velocity_iph_realign(struct velocity_info *vptr,
struct sk_buff *skb, int pkt_size)
{
- /* FIXME - memmove ? */
if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) {
- int i;
-
- for (i = pkt_size; i >= 0; i--)
- *(skb->data + i + 2) = *(skb->data + i);
+ memmove(skb->data + 2, skb->data, pkt_size);
skb_reserve(skb, 2);
}
}
@@ -1629,7 +1619,7 @@
struct rx_desc *rd = &(vptr->rd_ring[idx]);
struct velocity_rd_info *rd_info = &(vptr->rd_info[idx]);
- rd_info->skb = dev_alloc_skb(vptr->rx_buf_sz + 64);
+ rd_info->skb = netdev_alloc_skb(vptr->dev, vptr->rx_buf_sz + 64);
if (rd_info->skb == NULL)
return -ENOMEM;
@@ -1638,7 +1628,6 @@
* 64byte alignment.
*/
skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->data & 63);
- rd_info->skb->dev = vptr->dev;
rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->data, vptr->rx_buf_sz, PCI_DMA_FROMDEVICE);
/*
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index 5c0d2b0..0ba55ba 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;
}
@@ -325,7 +324,7 @@
for (dirty_tx = priv->dirty_tx; priv->cur_tx - dirty_tx; dirty_tx++) {
unsigned int entry = dirty_tx % priv->tx_ring_size;
u32 status = le32_to_cpu(priv->tx_ring[entry].status);
- struct ieee80211_tx_status tx_status;
+ struct ieee80211_tx_info *txi;
struct adm8211_tx_ring_info *info;
struct sk_buff *skb;
@@ -335,24 +334,23 @@
info = &priv->tx_buffers[entry];
skb = info->skb;
+ txi = IEEE80211_SKB_CB(skb);
/* TODO: check TDES0_STATUS_TUF and TDES0_STATUS_TRO */
pci_unmap_single(priv->pdev, info->mapping,
info->skb->len, PCI_DMA_TODEVICE);
- memset(&tx_status, 0, sizeof(tx_status));
+ memset(&txi->status, 0, sizeof(txi->status));
skb_pull(skb, sizeof(struct adm8211_tx_hdr));
memcpy(skb_push(skb, info->hdrlen), skb->cb, info->hdrlen);
- memcpy(&tx_status.control, &info->tx_control,
- sizeof(tx_status.control));
- if (!(tx_status.control.flags & IEEE80211_TXCTL_NO_ACK)) {
+ if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) {
if (status & TDES0_STATUS_ES)
- tx_status.excessive_retries = 1;
+ txi->status.excessive_retries = 1;
else
- tx_status.flags |= IEEE80211_TX_STATUS_ACK;
+ txi->flags |= IEEE80211_TX_STAT_ACK;
}
- ieee80211_tx_status_irqsafe(dev, skb, &tx_status);
+ ieee80211_tx_status_irqsafe(dev, skb);
info->skb = NULL;
}
@@ -446,9 +444,9 @@
struct ieee80211_rx_status rx_status = {0};
if (priv->pdev->revision < ADM8211_REV_CA)
- rx_status.ssi = rssi;
+ rx_status.signal = rssi;
else
- rx_status.ssi = 100 - rssi;
+ rx_status.signal = 100 - rssi;
rx_status.rate_idx = rate;
@@ -1639,7 +1637,6 @@
/* Transmit skb w/adm8211_tx_hdr (802.11 header created by hardware) */
static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb,
u16 plcp_signal,
- struct ieee80211_tx_control *control,
size_t hdrlen)
{
struct adm8211_priv *priv = dev->priv;
@@ -1665,7 +1662,6 @@
priv->tx_buffers[entry].skb = skb;
priv->tx_buffers[entry].mapping = mapping;
- memcpy(&priv->tx_buffers[entry].tx_control, control, sizeof(*control));
priv->tx_buffers[entry].hdrlen = hdrlen;
priv->tx_ring[entry].buffer1 = cpu_to_le32(mapping);
@@ -1686,18 +1682,18 @@
}
/* Put adm8211_tx_hdr on skb and transmit */
-static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
{
struct adm8211_tx_hdr *txhdr;
u16 fc;
size_t payload_len, hdrlen;
int plcp, dur, len, plcp_signal, short_preamble;
struct ieee80211_hdr *hdr;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, info);
- short_preamble = !!(control->tx_rate->flags &
- IEEE80211_TXCTL_SHORT_PREAMBLE);
- plcp_signal = control->tx_rate->bitrate;
+ short_preamble = !!(txrate->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE);
+ plcp_signal = txrate->bitrate;
hdr = (struct ieee80211_hdr *)skb->data;
fc = le16_to_cpu(hdr->frame_control) & ~IEEE80211_FCTL_PROTECTED;
@@ -1731,15 +1727,15 @@
if (short_preamble)
txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE);
- if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
+ if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS);
if (fc & IEEE80211_FCTL_PROTECTED)
txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE);
- txhdr->retry_limit = control->retry_limit;
+ txhdr->retry_limit = info->control.retry_limit;
- adm8211_tx_raw(dev, skb, plcp_signal, control, hdrlen);
+ adm8211_tx_raw(dev, skb, plcp_signal, hdrlen);
return NETDEV_TX_OK;
}
@@ -1894,9 +1890,10 @@
dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr);
/* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */
+ dev->flags = IEEE80211_HW_SIGNAL_UNSPEC;
dev->channel_change_time = 1000;
- dev->max_rssi = 100; /* FIXME: find better value */
+ dev->max_signal = 100; /* FIXME: find better value */
dev->queues = 1; /* ADM8211C supports more, maybe ADM8211B too */
@@ -2015,7 +2012,7 @@
if (priv->mode != IEEE80211_IF_TYPE_INVALID) {
adm8211_start(dev);
- ieee80211_start_queues(dev);
+ ieee80211_wake_queues(dev);
}
return 0;
diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h
index 8d7c564..9b190ee 100644
--- a/drivers/net/wireless/adm8211.h
+++ b/drivers/net/wireless/adm8211.h
@@ -443,7 +443,6 @@
struct adm8211_tx_ring_info {
struct sk_buff *skb;
dma_addr_t mapping;
- struct ieee80211_tx_control tx_control;
size_t hdrlen;
};
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 32019fb..1e1446b 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -1148,7 +1148,6 @@
static void airo_networks_free(struct airo_info *ai);
struct airo_info {
- struct net_device_stats stats;
struct net_device *dev;
struct list_head dev_list;
/* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we
@@ -1924,7 +1923,7 @@
if (npacks >= MAXTXQ - 1) {
netif_stop_queue (dev);
if (npacks > MAXTXQ) {
- ai->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
return 1;
}
skb_queue_tail (&ai->txq, skb);
@@ -2044,13 +2043,13 @@
bap_read(ai, &status, 2, BAP0);
}
if (le16_to_cpu(status) & 2) /* Too many retries */
- ai->stats.tx_aborted_errors++;
+ ai->dev->stats.tx_aborted_errors++;
if (le16_to_cpu(status) & 4) /* Transmit lifetime exceeded */
- ai->stats.tx_heartbeat_errors++;
+ ai->dev->stats.tx_heartbeat_errors++;
if (le16_to_cpu(status) & 8) /* Aid fail */
{ }
if (le16_to_cpu(status) & 0x10) /* MAC disabled */
- ai->stats.tx_carrier_errors++;
+ ai->dev->stats.tx_carrier_errors++;
if (le16_to_cpu(status) & 0x20) /* Association lost */
{ }
/* We produce a TXDROP event only for retry or lifetime
@@ -2102,7 +2101,7 @@
for (; i < MAX_FIDS / 2 && (priv->fids[i] & 0xffff0000); i++);
} else {
priv->fids[fid] &= 0xffff;
- priv->stats.tx_window_errors++;
+ dev->stats.tx_window_errors++;
}
if (i < MAX_FIDS / 2)
netif_wake_queue(dev);
@@ -2128,7 +2127,7 @@
netif_stop_queue(dev);
if (i == MAX_FIDS / 2) {
- priv->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
return 1;
}
}
@@ -2167,7 +2166,7 @@
for (; i < MAX_FIDS && (priv->fids[i] & 0xffff0000); i++);
} else {
priv->fids[fid] &= 0xffff;
- priv->stats.tx_window_errors++;
+ dev->stats.tx_window_errors++;
}
if (i < MAX_FIDS)
netif_wake_queue(dev);
@@ -2199,7 +2198,7 @@
netif_stop_queue(dev);
if (i == MAX_FIDS) {
- priv->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
return 1;
}
}
@@ -2219,8 +2218,9 @@
return 0;
}
-static void airo_read_stats(struct airo_info *ai)
+static void airo_read_stats(struct net_device *dev)
{
+ struct airo_info *ai = dev->priv;
StatsRid stats_rid;
__le32 *vals = stats_rid.vals;
@@ -2232,23 +2232,24 @@
readStatsRid(ai, &stats_rid, RID_STATS, 0);
up(&ai->sem);
- ai->stats.rx_packets = le32_to_cpu(vals[43]) + le32_to_cpu(vals[44]) +
+ dev->stats.rx_packets = le32_to_cpu(vals[43]) + le32_to_cpu(vals[44]) +
le32_to_cpu(vals[45]);
- ai->stats.tx_packets = le32_to_cpu(vals[39]) + le32_to_cpu(vals[40]) +
+ dev->stats.tx_packets = le32_to_cpu(vals[39]) + le32_to_cpu(vals[40]) +
le32_to_cpu(vals[41]);
- ai->stats.rx_bytes = le32_to_cpu(vals[92]);
- ai->stats.tx_bytes = le32_to_cpu(vals[91]);
- ai->stats.rx_errors = le32_to_cpu(vals[0]) + le32_to_cpu(vals[2]) +
+ dev->stats.rx_bytes = le32_to_cpu(vals[92]);
+ dev->stats.tx_bytes = le32_to_cpu(vals[91]);
+ dev->stats.rx_errors = le32_to_cpu(vals[0]) + le32_to_cpu(vals[2]) +
le32_to_cpu(vals[3]) + le32_to_cpu(vals[4]);
- ai->stats.tx_errors = le32_to_cpu(vals[42]) + ai->stats.tx_fifo_errors;
- ai->stats.multicast = le32_to_cpu(vals[43]);
- ai->stats.collisions = le32_to_cpu(vals[89]);
+ dev->stats.tx_errors = le32_to_cpu(vals[42]) +
+ dev->stats.tx_fifo_errors;
+ dev->stats.multicast = le32_to_cpu(vals[43]);
+ dev->stats.collisions = le32_to_cpu(vals[89]);
/* detailed rx_errors: */
- ai->stats.rx_length_errors = le32_to_cpu(vals[3]);
- ai->stats.rx_crc_errors = le32_to_cpu(vals[4]);
- ai->stats.rx_frame_errors = le32_to_cpu(vals[2]);
- ai->stats.rx_fifo_errors = le32_to_cpu(vals[0]);
+ dev->stats.rx_length_errors = le32_to_cpu(vals[3]);
+ dev->stats.rx_crc_errors = le32_to_cpu(vals[4]);
+ dev->stats.rx_frame_errors = le32_to_cpu(vals[2]);
+ dev->stats.rx_fifo_errors = le32_to_cpu(vals[0]);
}
static struct net_device_stats *airo_get_stats(struct net_device *dev)
@@ -2261,10 +2262,10 @@
set_bit(JOB_STATS, &local->jobs);
wake_up_interruptible(&local->thr_wait);
} else
- airo_read_stats(local);
+ airo_read_stats(dev);
}
- return &local->stats;
+ return &dev->stats;
}
static void airo_set_promisc(struct airo_info *ai) {
@@ -3093,7 +3094,7 @@
else if (test_bit(JOB_XMIT11, &ai->jobs))
airo_end_xmit11(dev);
else if (test_bit(JOB_STATS, &ai->jobs))
- airo_read_stats(ai);
+ airo_read_stats(dev);
else if (test_bit(JOB_WSTATS, &ai->jobs))
airo_read_wireless_stats(ai);
else if (test_bit(JOB_PROMISC, &ai->jobs))
@@ -3289,7 +3290,7 @@
skb = dev_alloc_skb( len + hdrlen + 2 + 2 );
if ( !skb ) {
- apriv->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
goto badrx;
}
skb_reserve(skb, 2); /* This way the IP header is aligned */
@@ -3557,7 +3558,7 @@
skb = dev_alloc_skb(len);
if (!skb) {
- ai->stats.rx_dropped++;
+ ai->dev->stats.rx_dropped++;
goto badrx;
}
buffer = skb_put(skb,len);
@@ -3650,7 +3651,7 @@
skb = dev_alloc_skb( len + hdrlen + 2 );
if ( !skb ) {
- ai->stats.rx_dropped++;
+ ai->dev->stats.rx_dropped++;
goto badrx;
}
buffer = (u16*)skb_put (skb, len + hdrlen);
diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c
index dbdfc9e..dec5e87 100644
--- a/drivers/net/wireless/arlan-main.c
+++ b/drivers/net/wireless/arlan-main.c
@@ -125,7 +125,7 @@
{
struct arlan_private *priv = netdev_priv(dev);
- priv->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (priv->Conf->tx_delay_ms)
{
priv->tx_done_delayed = jiffies + priv->Conf->tx_delay_ms * HZ / 1000 + 1;
@@ -1269,7 +1269,7 @@
{
IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
printk("arlan intr: transmit OK\n");
- priv->stats.tx_packets++;
+ dev->stats.tx_packets++;
priv->bad = 0;
priv->reset = 0;
priv->retransmissions = 0;
@@ -1496,7 +1496,7 @@
if (skb == NULL)
{
printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name);
- priv->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
break;
}
skb_reserve(skb, 2);
@@ -1536,14 +1536,14 @@
}
netif_rx(skb);
dev->last_rx = jiffies;
- priv->stats.rx_packets++;
- priv->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
break;
default:
printk(KERN_ERR "arlan intr: received unknown status\n");
- priv->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
break;
}
ARLAN_DEBUG_EXIT("arlan_rx_interrupt");
@@ -1719,23 +1719,23 @@
/* Update the statistics from the device registers. */
- READSHM(priv->stats.collisions, arlan->numReTransmissions, u_int);
- READSHM(priv->stats.rx_crc_errors, arlan->numCRCErrors, u_int);
- READSHM(priv->stats.rx_dropped, arlan->numFramesDiscarded, u_int);
- READSHM(priv->stats.rx_fifo_errors, arlan->numRXBufferOverflows, u_int);
- READSHM(priv->stats.rx_frame_errors, arlan->numReceiveFramesLost, u_int);
- READSHM(priv->stats.rx_over_errors, arlan->numRXOverruns, u_int);
- READSHM(priv->stats.rx_packets, arlan->numDatagramsReceived, u_int);
- READSHM(priv->stats.tx_aborted_errors, arlan->numAbortErrors, u_int);
- READSHM(priv->stats.tx_carrier_errors, arlan->numStatusTimeouts, u_int);
- READSHM(priv->stats.tx_dropped, arlan->numDatagramsDiscarded, u_int);
- READSHM(priv->stats.tx_fifo_errors, arlan->numTXUnderruns, u_int);
- READSHM(priv->stats.tx_packets, arlan->numDatagramsTransmitted, u_int);
- READSHM(priv->stats.tx_window_errors, arlan->numHoldOffs, u_int);
+ READSHM(dev->stats.collisions, arlan->numReTransmissions, u_int);
+ READSHM(dev->stats.rx_crc_errors, arlan->numCRCErrors, u_int);
+ READSHM(dev->stats.rx_dropped, arlan->numFramesDiscarded, u_int);
+ READSHM(dev->stats.rx_fifo_errors, arlan->numRXBufferOverflows, u_int);
+ READSHM(dev->stats.rx_frame_errors, arlan->numReceiveFramesLost, u_int);
+ READSHM(dev->stats.rx_over_errors, arlan->numRXOverruns, u_int);
+ READSHM(dev->stats.rx_packets, arlan->numDatagramsReceived, u_int);
+ READSHM(dev->stats.tx_aborted_errors, arlan->numAbortErrors, u_int);
+ READSHM(dev->stats.tx_carrier_errors, arlan->numStatusTimeouts, u_int);
+ READSHM(dev->stats.tx_dropped, arlan->numDatagramsDiscarded, u_int);
+ READSHM(dev->stats.tx_fifo_errors, arlan->numTXUnderruns, u_int);
+ READSHM(dev->stats.tx_packets, arlan->numDatagramsTransmitted, u_int);
+ READSHM(dev->stats.tx_window_errors, arlan->numHoldOffs, u_int);
ARLAN_DEBUG_EXIT("arlan_statistics");
- return &priv->stats;
+ return &dev->stats;
}
diff --git a/drivers/net/wireless/arlan.h b/drivers/net/wireless/arlan.h
index 3ed1df7..fb3ad51 100644
--- a/drivers/net/wireless/arlan.h
+++ b/drivers/net/wireless/arlan.h
@@ -330,7 +330,6 @@
#define TX_RING_SIZE 2
/* Information that need to be kept for each board. */
struct arlan_private {
- struct net_device_stats stats;
struct arlan_shmem __iomem * card;
struct arlan_shmem * conf;
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index 635b9ac..85045af 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -167,8 +167,7 @@
/*
* Prototypes - MAC 802.11 stack related functions
*/
-static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_control *ctl);
+static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
static int ath5k_reset(struct ieee80211_hw *hw);
static int ath5k_start(struct ieee80211_hw *hw);
static void ath5k_stop(struct ieee80211_hw *hw);
@@ -196,8 +195,7 @@
static u64 ath5k_get_tsf(struct ieee80211_hw *hw);
static void ath5k_reset_tsf(struct ieee80211_hw *hw);
static int ath5k_beacon_update(struct ieee80211_hw *hw,
- struct sk_buff *skb,
- struct ieee80211_tx_control *ctl);
+ struct sk_buff *skb);
static struct ieee80211_ops ath5k_hw_ops = {
.tx = ath5k_tx,
@@ -251,9 +249,7 @@
static int ath5k_rxbuf_setup(struct ath5k_softc *sc,
struct ath5k_buf *bf);
static int ath5k_txbuf_setup(struct ath5k_softc *sc,
- struct ath5k_buf *bf,
- struct ieee80211_tx_control *ctl);
-
+ struct ath5k_buf *bf);
static inline void ath5k_txbuf_free(struct ath5k_softc *sc,
struct ath5k_buf *bf)
{
@@ -289,8 +285,7 @@
static void ath5k_tasklet_tx(unsigned long data);
/* Beacon handling */
static int ath5k_beacon_setup(struct ath5k_softc *sc,
- struct ath5k_buf *bf,
- struct ieee80211_tx_control *ctl);
+ struct ath5k_buf *bf);
static void ath5k_beacon_send(struct ath5k_softc *sc);
static void ath5k_beacon_config(struct ath5k_softc *sc);
static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf);
@@ -458,13 +453,11 @@
/* Initialize driver private data */
SET_IEEE80211_DEV(hw, &pdev->dev);
- hw->flags = IEEE80211_HW_RX_INCLUDES_FCS;
+ hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_NOISE_DBM;
hw->extra_tx_headroom = 2;
hw->channel_change_time = 5000;
- /* these names are misleading */
- hw->max_rssi = -110; /* signal in dBm */
- hw->max_noise = -110; /* noise in dBm */
- hw->max_signal = 100; /* we will provide a percentage based on rssi */
sc = hw->priv;
sc->hw = hw;
sc->pdev = pdev;
@@ -1297,36 +1290,36 @@
}
static int
-ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
- struct ieee80211_tx_control *ctl)
+ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
{
struct ath5k_hw *ah = sc->ah;
struct ath5k_txq *txq = sc->txq;
struct ath5k_desc *ds = bf->desc;
struct sk_buff *skb = bf->skb;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID;
int ret;
flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK;
- bf->ctl = *ctl;
+
/* XXX endianness */
bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len,
PCI_DMA_TODEVICE);
- if (ctl->flags & IEEE80211_TXCTL_NO_ACK)
+ if (info->flags & IEEE80211_TX_CTL_NO_ACK)
flags |= AR5K_TXDESC_NOACK;
pktlen = skb->len;
- if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) {
- keyidx = ctl->key_idx;
- pktlen += ctl->icv_len;
+ if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) {
+ keyidx = info->control.hw_key->hw_key_idx;
+ pktlen += info->control.icv_len;
}
-
ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL,
- (sc->power_level * 2), ctl->tx_rate->hw_value,
- ctl->retry_limit, keyidx, 0, flags, 0, 0);
+ (sc->power_level * 2),
+ ieee80211_get_tx_rate(sc->hw, info)->hw_value,
+ info->control.retry_limit, keyidx, 0, flags, 0, 0);
if (ret)
goto err_unmap;
@@ -1335,7 +1328,7 @@
spin_lock_bh(&txq->lock);
list_add_tail(&bf->list, &txq->q);
- sc->tx_stats.data[txq->qnum].len++;
+ sc->tx_stats[txq->qnum].len++;
if (txq->link == NULL) /* is this first packet? */
ath5k_hw_put_tx_buf(ah, txq->qnum, bf->daddr);
else /* no, so only link it */
@@ -1566,7 +1559,7 @@
ath5k_txbuf_free(sc, bf);
spin_lock_bh(&sc->txbuflock);
- sc->tx_stats.data[txq->qnum].len--;
+ sc->tx_stats[txq->qnum].len--;
list_move_tail(&bf->list, &sc->txbuf);
sc->txbuf_len++;
spin_unlock_bh(&sc->txbuflock);
@@ -1601,7 +1594,7 @@
sc->txqs[i].link);
}
}
- ieee80211_start_queues(sc->hw); /* XXX move to callers */
+ ieee80211_wake_queues(sc->hw); /* XXX move to callers */
for (i = 0; i < ARRAY_SIZE(sc->txqs); i++)
if (sc->txqs[i].setup)
@@ -1895,20 +1888,9 @@
rxs.freq = sc->curchan->center_freq;
rxs.band = sc->curband->band;
- /*
- * signal quality:
- * the names here are misleading and the usage of these
- * values by iwconfig makes it even worse
- */
- /* noise floor in dBm, from the last noise calibration */
rxs.noise = sc->ah->ah_noise_floor;
- /* signal level in dBm */
- rxs.ssi = rxs.noise + rs.rs_rssi;
- /*
- * "signal" is actually displayed as Link Quality by iwconfig
- * we provide a percentage based on rssi (assuming max rssi 64)
- */
- rxs.signal = rs.rs_rssi * 100 / 64;
+ rxs.signal = rxs.noise + rs.rs_rssi;
+ rxs.qual = rs.rs_rssi * 100 / 64;
rxs.antenna = rs.rs_antenna;
rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);
@@ -1939,11 +1921,11 @@
static void
ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
{
- struct ieee80211_tx_status txs = {};
struct ath5k_tx_status ts = {};
struct ath5k_buf *bf, *bf0;
struct ath5k_desc *ds;
struct sk_buff *skb;
+ struct ieee80211_tx_info *info;
int ret;
spin_lock(&txq->lock);
@@ -1963,28 +1945,29 @@
}
skb = bf->skb;
+ info = IEEE80211_SKB_CB(skb);
bf->skb = NULL;
+
pci_unmap_single(sc->pdev, bf->skbaddr, skb->len,
PCI_DMA_TODEVICE);
- txs.control = bf->ctl;
- txs.retry_count = ts.ts_shortretry + ts.ts_longretry / 6;
+ info->status.retry_count = ts.ts_shortretry + ts.ts_longretry / 6;
if (unlikely(ts.ts_status)) {
sc->ll_stats.dot11ACKFailureCount++;
if (ts.ts_status & AR5K_TXERR_XRETRY)
- txs.excessive_retries = 1;
+ info->status.excessive_retries = 1;
else if (ts.ts_status & AR5K_TXERR_FILT)
- txs.flags |= IEEE80211_TX_STATUS_TX_FILTERED;
+ info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
} else {
- txs.flags |= IEEE80211_TX_STATUS_ACK;
- txs.ack_signal = ts.ts_rssi;
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ info->status.ack_signal = ts.ts_rssi;
}
- ieee80211_tx_status(sc->hw, skb, &txs);
- sc->tx_stats.data[txq->qnum].count++;
+ ieee80211_tx_status(sc->hw, skb);
+ sc->tx_stats[txq->qnum].count++;
spin_lock(&sc->txbuflock);
- sc->tx_stats.data[txq->qnum].len--;
+ sc->tx_stats[txq->qnum].len--;
list_move_tail(&bf->list, &sc->txbuf);
sc->txbuf_len++;
spin_unlock(&sc->txbuflock);
@@ -2017,10 +2000,10 @@
* Setup the beacon frame for transmit.
*/
static int
-ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
- struct ieee80211_tx_control *ctl)
+ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
{
struct sk_buff *skb = bf->skb;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ath5k_hw *ah = sc->ah;
struct ath5k_desc *ds;
int ret, antenna = 0;
@@ -2059,7 +2042,8 @@
ret = ah->ah_setup_tx_desc(ah, ds, skb->len,
ieee80211_get_hdrlen_from_skb(skb),
AR5K_PKT_TYPE_BEACON, (sc->power_level * 2),
- ctl->tx_rate->hw_value, 1, AR5K_TXKEYIX_INVALID,
+ ieee80211_get_tx_rate(sc->hw, info)->hw_value,
+ 1, AR5K_TXKEYIX_INVALID,
antenna, flags, 0, 0);
if (ret)
goto err_unmap;
@@ -2637,11 +2621,11 @@
\********************/
static int
-ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_control *ctl)
+ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_buf *bf;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
unsigned long flags;
int hdrlen;
int pad;
@@ -2667,13 +2651,13 @@
memmove(skb->data, skb->data+pad, hdrlen);
}
- sc->led_txrate = ctl->tx_rate->hw_value;
+ sc->led_txrate = ieee80211_get_tx_rate(hw, info)->hw_value;
spin_lock_irqsave(&sc->txbuflock, flags);
if (list_empty(&sc->txbuf)) {
ATH5K_ERR(sc, "no further txbuf available, dropping packet\n");
spin_unlock_irqrestore(&sc->txbuflock, flags);
- ieee80211_stop_queue(hw, ctl->queue);
+ ieee80211_stop_queue(hw, skb_get_queue_mapping(skb));
return -1;
}
bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list);
@@ -2685,7 +2669,7 @@
bf->skb = skb;
- if (ath5k_txbuf_setup(sc, bf, ctl)) {
+ if (ath5k_txbuf_setup(sc, bf)) {
bf->skb = NULL;
spin_lock_irqsave(&sc->txbuflock, flags);
list_add_tail(&bf->list, &sc->txbuf);
@@ -3063,8 +3047,7 @@
}
static int
-ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_control *ctl)
+ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ath5k_softc *sc = hw->priv;
int ret;
@@ -3080,7 +3063,7 @@
ath5k_txbuf_free(sc, sc->bbuf);
sc->bbuf->skb = skb;
- ret = ath5k_beacon_setup(sc, sc->bbuf, ctl);
+ ret = ath5k_beacon_setup(sc, sc->bbuf);
if (ret)
sc->bbuf->skb = NULL;
else
diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h
index 3a97558..bb4b26d 100644
--- a/drivers/net/wireless/ath5k/base.h
+++ b/drivers/net/wireless/ath5k/base.h
@@ -60,7 +60,6 @@
dma_addr_t daddr; /* physical addr of desc */
struct sk_buff *skb; /* skbuff for buf */
dma_addr_t skbaddr;/* physical addr of skb data */
- struct ieee80211_tx_control ctl;
};
/*
@@ -92,7 +91,8 @@
struct 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/atmel.c b/drivers/net/wireless/atmel.c
index 438e63e..7bb2646 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -433,7 +433,6 @@
struct net_device *dev;
struct device *sys_dev;
struct iw_statistics wstats;
- struct net_device_stats stats; // device stats
spinlock_t irqlock, timerlock; // spinlocks
enum { BUS_TYPE_PCCARD, BUS_TYPE_PCI } bus_type;
enum {
@@ -694,9 +693,9 @@
if (type == TX_PACKET_TYPE_DATA) {
if (status == TX_STATUS_SUCCESS)
- priv->stats.tx_packets++;
+ priv->dev->stats.tx_packets++;
else
- priv->stats.tx_errors++;
+ priv->dev->stats.tx_errors++;
netif_wake_queue(priv->dev);
}
}
@@ -792,13 +791,13 @@
if (priv->card && priv->present_callback &&
!(*priv->present_callback)(priv->card)) {
- priv->stats.tx_errors++;
+ dev->stats.tx_errors++;
dev_kfree_skb(skb);
return 0;
}
if (priv->station_state != STATION_STATE_READY) {
- priv->stats.tx_errors++;
+ dev->stats.tx_errors++;
dev_kfree_skb(skb);
return 0;
}
@@ -815,7 +814,7 @@
initial + 18 (+30-12) */
if (!(buff = find_tx_buff(priv, len + 18))) {
- priv->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
spin_unlock_irqrestore(&priv->irqlock, flags);
spin_unlock_bh(&priv->timerlock);
netif_stop_queue(dev);
@@ -851,7 +850,7 @@
/* low bit of first byte of destination tells us if broadcast */
tx_update_descriptor(priv, *(skb->data) & 0x01, len + 18, buff, TX_PACKET_TYPE_DATA);
dev->trans_start = jiffies;
- priv->stats.tx_bytes += len;
+ dev->stats.tx_bytes += len;
spin_unlock_irqrestore(&priv->irqlock, flags);
spin_unlock_bh(&priv->timerlock);
@@ -895,7 +894,7 @@
}
if (!(skb = dev_alloc_skb(msdu_size + 14))) {
- priv->stats.rx_dropped++;
+ priv->dev->stats.rx_dropped++;
return;
}
@@ -908,7 +907,7 @@
crc = crc32_le(crc, skbp + 12, msdu_size);
atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + 30 + msdu_size, 4);
if ((crc ^ 0xffffffff) != netcrc) {
- priv->stats.rx_crc_errors++;
+ priv->dev->stats.rx_crc_errors++;
dev_kfree_skb(skb);
return;
}
@@ -924,8 +923,8 @@
skb->protocol = eth_type_trans(skb, priv->dev);
skb->ip_summed = CHECKSUM_NONE;
netif_rx(skb);
- priv->stats.rx_bytes += 12 + msdu_size;
- priv->stats.rx_packets++;
+ priv->dev->stats.rx_bytes += 12 + msdu_size;
+ priv->dev->stats.rx_packets++;
}
/* Test to see if the packet in card memory at packet_loc has a valid CRC
@@ -991,7 +990,7 @@
crc = crc32_le(crc, &priv->rx_buf[12], msdu_size);
atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4);
if ((crc ^ 0xffffffff) != netcrc) {
- priv->stats.rx_crc_errors++;
+ priv->dev->stats.rx_crc_errors++;
memset(priv->frag_source, 0xff, 6);
}
}
@@ -1009,7 +1008,7 @@
msdu_size);
atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4);
if ((crc ^ 0xffffffff) != netcrc) {
- priv->stats.rx_crc_errors++;
+ priv->dev->stats.rx_crc_errors++;
memset(priv->frag_source, 0xff, 6);
more_frags = 1; /* don't send broken assembly */
}
@@ -1021,7 +1020,7 @@
if (!more_frags) { /* last one */
memset(priv->frag_source, 0xff, 6);
if (!(skb = dev_alloc_skb(priv->frag_len + 14))) {
- priv->stats.rx_dropped++;
+ priv->dev->stats.rx_dropped++;
} else {
skb_reserve(skb, 2);
memcpy(skb_put(skb, priv->frag_len + 12),
@@ -1031,8 +1030,8 @@
skb->protocol = eth_type_trans(skb, priv->dev);
skb->ip_summed = CHECKSUM_NONE;
netif_rx(skb);
- priv->stats.rx_bytes += priv->frag_len + 12;
- priv->stats.rx_packets++;
+ priv->dev->stats.rx_bytes += priv->frag_len + 12;
+ priv->dev->stats.rx_packets++;
}
}
} else
@@ -1057,7 +1056,7 @@
if (status == 0xc1) /* determined by experiment */
priv->wstats.discard.nwid++;
else
- priv->stats.rx_errors++;
+ priv->dev->stats.rx_errors++;
goto next;
}
@@ -1065,7 +1064,7 @@
rx_packet_loc = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_POS_OFFSET, priv->rx_desc_head));
if (msdu_size < 30) {
- priv->stats.rx_errors++;
+ priv->dev->stats.rx_errors++;
goto next;
}
@@ -1123,7 +1122,7 @@
msdu_size -= 4;
crc = crc32_le(crc, (unsigned char *)&priv->rx_buf, msdu_size);
if ((crc ^ 0xffffffff) != (*((u32 *)&priv->rx_buf[msdu_size]))) {
- priv->stats.rx_crc_errors++;
+ priv->dev->stats.rx_crc_errors++;
goto next;
}
}
@@ -1250,12 +1249,6 @@
}
}
-static struct net_device_stats *atmel_get_stats(struct net_device *dev)
-{
- struct atmel_private *priv = netdev_priv(dev);
- return &priv->stats;
-}
-
static struct iw_statistics *atmel_get_wireless_stats(struct net_device *dev)
{
struct atmel_private *priv = netdev_priv(dev);
@@ -1518,8 +1511,6 @@
priv->crc_ok_cnt = priv->crc_ko_cnt = 0;
} else
priv->probe_crc = 0;
- memset(&priv->stats, 0, sizeof(priv->stats));
- memset(&priv->wstats, 0, sizeof(priv->wstats));
priv->last_qual = jiffies;
priv->last_beacon_timestamp = 0;
memset(priv->frag_source, 0xff, sizeof(priv->frag_source));
@@ -1568,7 +1559,6 @@
dev->change_mtu = atmel_change_mtu;
dev->set_mac_address = atmel_set_mac_address;
dev->hard_start_xmit = start_tx;
- dev->get_stats = atmel_get_stats;
dev->wireless_handlers = (struct iw_handler_def *)&atmel_handler_def;
dev->do_ioctl = atmel_ioctl;
dev->irq = irq;
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index dfa4bdd..239e71c 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 | \
@@ -423,6 +422,26 @@
B43_IRQ_RFKILL | \
B43_IRQ_TX_OK)
+/* The firmware register to fetch the debug-IRQ reason from. */
+#define B43_DEBUGIRQ_REASON_REG 63
+/* Debug-IRQ reasons. */
+#define B43_DEBUGIRQ_PANIC 0 /* The firmware panic'ed */
+#define B43_DEBUGIRQ_DUMP_SHM 1 /* Dump shared SHM */
+#define B43_DEBUGIRQ_DUMP_REGS 2 /* Dump the microcode registers */
+#define B43_DEBUGIRQ_MARKER 3 /* A "marker" was thrown by the firmware. */
+#define B43_DEBUGIRQ_ACK 0xFFFF /* The host writes that to ACK the IRQ */
+
+/* The firmware register that contains the "marker" line. */
+#define B43_MARKER_ID_REG 2
+#define B43_MARKER_LINE_REG 3
+
+/* The firmware register to fetch the panic reason from. */
+#define B43_FWPANIC_REASON_REG 3
+/* Firmware panic reason codes */
+#define B43_FWPANIC_DIE 0 /* Firmware died. Don't auto-restart it. */
+#define B43_FWPANIC_RESTART 1 /* Firmware died. Schedule a controller reset. */
+
+
/* Device specific rate values.
* The actual values defined here are (rate_in_mbps * 2).
* Some code depends on this. Don't change it. */
@@ -734,7 +753,6 @@
/* The beacon we are currently using (AP or IBSS mode).
* This beacon stuff is protected by the irq_lock. */
struct sk_buff *current_beacon;
- struct ieee80211_tx_control beacon_txctl;
bool beacon0_uploaded;
bool beacon1_uploaded;
bool beacon_templates_virgin; /* Never wrote the templates? */
@@ -768,6 +786,13 @@
u16 rev;
/* Firmware patchlevel */
u16 patch;
+
+ /* Set to true, if we are using an opensource firmware. */
+ bool opensource;
+ /* Set to true, if the core needs a PCM firmware, but
+ * we failed to load one. This is always false for
+ * core rev > 10, as these don't need PCM firmware. */
+ bool pcm_request_failed;
};
/* Device (802.11 core) initialization status. */
@@ -941,22 +966,6 @@
# define B43_WARN_ON(x) __b43_warn_on_dummy(unlikely(!!(x)))
#endif
-/** Limit a value between two limits */
-#ifdef limit_value
-# undef limit_value
-#endif
-#define limit_value(value, min, max) \
- ({ \
- typeof(value) __value = (value); \
- typeof(value) __min = (min); \
- typeof(value) __max = (max); \
- if (__value < __min) \
- __value = __min; \
- else if (__value > __max) \
- __value = __max; \
- __value; \
- })
-
/* Convert an integer to a Q5.2 value */
#define INT_TO_Q52(i) ((i) << 2)
/* Convert a Q5.2 value to an integer (precision loss!) */
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..b4eadd9 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -1131,10 +1131,10 @@
}
static int dma_tx_fragment(struct b43_dmaring *ring,
- struct sk_buff *skb,
- struct ieee80211_tx_control *ctl)
+ struct sk_buff *skb)
{
const struct b43_dma_ops *ops = ring->ops;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
u8 *header;
int slot, old_top_slot, old_used_slots;
int err;
@@ -1158,7 +1158,7 @@
header = &(ring->txhdr_cache[slot * hdrsize]);
cookie = generate_cookie(ring, slot);
err = b43_generate_txhdr(ring->dev, header,
- skb->data, skb->len, ctl, cookie);
+ skb->data, skb->len, info, cookie);
if (unlikely(err)) {
ring->current_slot = old_top_slot;
ring->used_slots = old_used_slots;
@@ -1180,7 +1180,6 @@
desc = ops->idx2desc(ring, slot, &meta);
memset(meta, 0, sizeof(*meta));
- memcpy(&meta->txstat.control, ctl, sizeof(*ctl));
meta->skb = skb;
meta->is_last_fragment = 1;
@@ -1210,7 +1209,7 @@
ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1);
- if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) {
+ if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
/* Tell the firmware about the cookie of the last
* mcast frame, so it can clear the more-data bit in it. */
b43_shm_write16(ring->dev, B43_SHM_SHARED,
@@ -1281,16 +1280,16 @@
return ring;
}
-int b43_dma_tx(struct b43_wldev *dev,
- struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb)
{
struct b43_dmaring *ring;
struct ieee80211_hdr *hdr;
int err = 0;
unsigned long flags;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
hdr = (struct ieee80211_hdr *)skb->data;
- if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) {
+ if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
/* The multicast ring will be sent after the DTIM */
ring = dev->dma.tx_ring_mcast;
/* Set the more-data bit. Ucode will clear it on
@@ -1298,7 +1297,8 @@
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
} else {
/* Decide by priority where to put this frame. */
- ring = select_ring_by_priority(dev, ctl->queue);
+ ring = select_ring_by_priority(
+ dev, skb_get_queue_mapping(skb));
}
spin_lock_irqsave(&ring->lock, flags);
@@ -1316,9 +1316,9 @@
/* Assign the queue number to the ring (if not already done before)
* so TX status handling can use it. The queue to ring mapping is
* static, so we don't need to store it per frame. */
- ring->queue_prio = ctl->queue;
+ ring->queue_prio = skb_get_queue_mapping(skb);
- err = dma_tx_fragment(ring, skb, ctl);
+ err = dma_tx_fragment(ring, skb);
if (unlikely(err == -ENOKEY)) {
/* Drop this packet, as we don't have the encryption key
* anymore and must not transmit it unencrypted. */
@@ -1334,7 +1334,7 @@
if ((free_slots(ring) < SLOTS_PER_PACKET) ||
should_inject_overflow(ring)) {
/* This TX ring is full. */
- ieee80211_stop_queue(dev->wl->hw, ctl->queue);
+ ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb));
ring->stopped = 1;
if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {
b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index);
@@ -1377,13 +1377,19 @@
b43_txhdr_size(dev), 1);
if (meta->is_last_fragment) {
- B43_WARN_ON(!meta->skb);
- /* Call back to inform the ieee80211 subsystem about the
- * status of the transmission.
- * Some fields of txstat are already filled in dma_tx().
+ struct ieee80211_tx_info *info;
+
+ BUG_ON(!meta->skb);
+
+ info = IEEE80211_SKB_CB(meta->skb);
+
+ memset(&info->status, 0, sizeof(info->status));
+
+ /*
+ * Call back to inform the ieee80211 subsystem about
+ * the status of the transmission.
*/
- frame_succeed = b43_fill_txstatus_report(
- &(meta->txstat), status);
+ frame_succeed = b43_fill_txstatus_report(info, status);
#ifdef CONFIG_B43_DEBUG
if (frame_succeed)
ring->nr_succeed_tx_packets++;
@@ -1391,8 +1397,8 @@
ring->nr_failed_tx_packets++;
ring->nr_total_packet_tries += status->frame_count;
#endif /* DEBUG */
- ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb,
- &(meta->txstat));
+ ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb);
+
/* skb is freed by ieee80211_tx_status_irqsafe() */
meta->skb = NULL;
} else {
@@ -1427,18 +1433,16 @@
{
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/dma.h b/drivers/net/wireless/b43/dma.h
index 20acf88..d1eb5c0 100644
--- a/drivers/net/wireless/b43/dma.h
+++ b/drivers/net/wireless/b43/dma.h
@@ -181,7 +181,6 @@
dma_addr_t dmaaddr;
/* ieee80211 TX status. Only used once per 802.11 frag. */
bool is_last_fragment;
- struct ieee80211_tx_status txstat;
};
struct b43_dmaring;
@@ -285,7 +284,7 @@
struct ieee80211_tx_queue_stats *stats);
int b43_dma_tx(struct b43_wldev *dev,
- struct sk_buff *skb, struct ieee80211_tx_control *ctl);
+ struct sk_buff *skb);
void b43_dma_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status);
diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c
index d890f36..9c854d6 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,
@@ -366,7 +199,7 @@
if (lb_gain > 10) {
radio_pctl_reg = 0;
pga = abs(10 - lb_gain) / 6;
- pga = limit_value(pga, 0, 15);
+ pga = clamp_val(pga, 0, 15);
} else {
int cmp_val;
int tmp;
@@ -438,48 +271,26 @@
b43_radio_write16(dev, 0x52, b43_radio_read16(dev, 0x52)
& 0xFFF0); /* TX bias == 0 */
}
+ lo->txctl_measured_time = jiffies;
}
static void lo_read_power_vector(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
struct b43_txpower_lo_control *lo = phy->lo_control;
- u16 i;
+ int i;
u64 tmp;
u64 power_vector = 0;
- int rf_offset, bb_offset;
- struct b43_loctl *loctl;
for (i = 0; i < 8; i += 2) {
tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x310 + i);
- /* Clear the top byte. We get holes in the bitmap... */
- tmp &= 0xFF;
power_vector |= (tmp << (i * 8));
/* Clear the vector on the device. */
b43_shm_write16(dev, B43_SHM_SHARED, 0x310 + i, 0);
}
-
if (power_vector)
lo->power_vector = power_vector;
- power_vector = lo->power_vector;
-
- for (i = 0; i < 64; i++) {
- if (power_vector & ((u64) 1ULL << i)) {
- /* Now figure out which b43_loctl corresponds
- * to this bit.
- */
- rf_offset = i / lo->rfatt_list.len;
- bb_offset = i % lo->rfatt_list.len; //FIXME?
- loctl =
- b43_get_lo_g_ctl(dev,
- &lo->rfatt_list.list[rf_offset],
- &lo->bbatt_list.list[bb_offset]);
- /* And mark it as "used", as the device told us
- * through the bitmap it is using it.
- */
- loctl->used = 1;
- }
- }
+ lo->pwr_vec_read_time = jiffies;
}
/* 802.11/LO/GPHY/MeasuringGains */
@@ -510,7 +321,7 @@
phy->lna_lod_gain = 1;
trsw_rx_gain -= 8;
}
- trsw_rx_gain = limit_value(trsw_rx_gain, 0, 0x2D);
+ trsw_rx_gain = clamp_val(trsw_rx_gain, 0, 0x2D);
phy->pga_gain = trsw_rx_gain / 3;
if (phy->pga_gain >= 5) {
phy->pga_gain -= 5;
@@ -609,8 +420,6 @@
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 6c3d9ea..1e31e0b 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -1182,10 +1182,10 @@
/* Get the noise samples. */
B43_WARN_ON(dev->noisecalc.nr_samples >= 8);
i = dev->noisecalc.nr_samples;
- noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
- noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
- noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
- noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+ noise[0] = clamp_val(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+ noise[1] = clamp_val(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+ noise[2] = clamp_val(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+ noise[3] = clamp_val(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]];
dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]];
dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]];
@@ -1368,18 +1368,18 @@
unsigned int rate;
u16 ctl;
int antenna;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon);
bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);
len = min((size_t) dev->wl->current_beacon->len,
0x200 - sizeof(struct b43_plcp_hdr6));
- rate = dev->wl->beacon_txctl.tx_rate->hw_value;
+ rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value;
b43_write_template_common(dev, (const u8 *)bcn,
len, ram_offset, shm_size_offset, rate);
/* Write the PHY TX control parameters. */
- antenna = b43_antenna_from_ieee80211(dev,
- dev->wl->beacon_txctl.antenna_sel_tx);
+ antenna = b43_antenna_from_ieee80211(dev, info->antenna_sel_tx);
antenna = b43_antenna_to_phyctl(antenna);
ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
/* We can't send beacons with short preamble. Would get PHY errors. */
@@ -1430,11 +1430,17 @@
i += ie_len + 2;
}
if (!tim_found) {
- b43warn(dev->wl, "Did not find a valid TIM IE in "
- "the beacon template packet. AP or IBSS operation "
- "may be broken.\n");
- } else
- b43dbg(dev->wl, "Updated beacon template\n");
+ /*
+ * If ucode wants to modify TIM do it behind the beacon, this
+ * will happen, for example, when doing mesh networking.
+ */
+ b43_shm_write16(dev, B43_SHM_SHARED,
+ B43_SHM_SH_TIMBPOS,
+ len + sizeof(struct b43_plcp_hdr6));
+ b43_shm_write16(dev, B43_SHM_SHARED,
+ B43_SHM_SH_DTIMPER, 0);
+ }
+ b43dbg(dev->wl, "Updated beacon template at 0x%x\n", ram_offset);
}
static void b43_write_probe_resp_plcp(struct b43_wldev *dev,
@@ -1573,7 +1579,8 @@
struct b43_wl *wl = dev->wl;
u32 cmd, beacon0_valid, beacon1_valid;
- if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP))
+ if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP) &&
+ !b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT))
return;
/* This is the bottom half of the asynchronous beacon update. */
@@ -1640,8 +1647,7 @@
/* Asynchronously update the packet templates in template RAM.
* Locking: Requires wl->irq_lock to be locked. */
-static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon,
- const struct ieee80211_tx_control *txctl)
+static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon)
{
/* This is the top half of the ansynchronous beacon update.
* The bottom half is the beacon IRQ.
@@ -1652,7 +1658,6 @@
if (wl->current_beacon)
dev_kfree_skb_any(wl->current_beacon);
wl->current_beacon = beacon;
- memcpy(&wl->beacon_txctl, txctl, sizeof(wl->beacon_txctl));
wl->beacon0_uploaded = 0;
wl->beacon1_uploaded = 0;
queue_work(wl->hw->workqueue, &wl->beacon_update_trigger);
@@ -1691,9 +1696,100 @@
b43dbg(dev->wl, "Set beacon interval to %u\n", beacon_int);
}
+static void b43_handle_firmware_panic(struct b43_wldev *dev)
+{
+ u16 reason;
+
+ /* Read the register that contains the reason code for the panic. */
+ reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_FWPANIC_REASON_REG);
+ b43err(dev->wl, "Whoopsy, firmware panic! Reason: %u\n", reason);
+
+ switch (reason) {
+ default:
+ b43dbg(dev->wl, "The panic reason is unknown.\n");
+ /* fallthrough */
+ case B43_FWPANIC_DIE:
+ /* Do not restart the controller or firmware.
+ * The device is nonfunctional from now on.
+ * Restarting would result in this panic to trigger again,
+ * so we avoid that recursion. */
+ break;
+ case B43_FWPANIC_RESTART:
+ b43_controller_restart(dev, "Microcode panic");
+ break;
+ }
+}
+
static void handle_irq_ucode_debug(struct b43_wldev *dev)
{
- //TODO
+ unsigned int i, cnt;
+ u16 reason, marker_id, marker_line;
+ __le16 *buf;
+
+ /* The proprietary firmware doesn't have this IRQ. */
+ if (!dev->fw.opensource)
+ return;
+
+ /* Read the register that contains the reason code for this IRQ. */
+ reason = b43_shm_read16(dev, B43_SHM_SCRATCH, B43_DEBUGIRQ_REASON_REG);
+
+ switch (reason) {
+ case B43_DEBUGIRQ_PANIC:
+ b43_handle_firmware_panic(dev);
+ break;
+ case B43_DEBUGIRQ_DUMP_SHM:
+ if (!B43_DEBUG)
+ break; /* Only with driver debugging enabled. */
+ buf = kmalloc(4096, GFP_ATOMIC);
+ if (!buf) {
+ b43dbg(dev->wl, "SHM-dump: Failed to allocate memory\n");
+ goto out;
+ }
+ for (i = 0; i < 4096; i += 2) {
+ u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, i);
+ buf[i / 2] = cpu_to_le16(tmp);
+ }
+ b43info(dev->wl, "Shared memory dump:\n");
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET,
+ 16, 2, buf, 4096, 1);
+ kfree(buf);
+ break;
+ case B43_DEBUGIRQ_DUMP_REGS:
+ if (!B43_DEBUG)
+ break; /* Only with driver debugging enabled. */
+ b43info(dev->wl, "Microcode register dump:\n");
+ for (i = 0, cnt = 0; i < 64; i++) {
+ u16 tmp = b43_shm_read16(dev, B43_SHM_SCRATCH, i);
+ if (cnt == 0)
+ printk(KERN_INFO);
+ printk("r%02u: 0x%04X ", i, tmp);
+ cnt++;
+ if (cnt == 6) {
+ printk("\n");
+ cnt = 0;
+ }
+ }
+ printk("\n");
+ break;
+ case B43_DEBUGIRQ_MARKER:
+ if (!B43_DEBUG)
+ break; /* Only with driver debugging enabled. */
+ marker_id = b43_shm_read16(dev, B43_SHM_SCRATCH,
+ B43_MARKER_ID_REG);
+ marker_line = b43_shm_read16(dev, B43_SHM_SCRATCH,
+ B43_MARKER_LINE_REG);
+ b43info(dev->wl, "The firmware just executed the MARKER(%u) "
+ "at line number %u\n",
+ marker_id, marker_line);
+ break;
+ default:
+ b43dbg(dev->wl, "Debug-IRQ triggered for unknown reason: %u\n",
+ reason);
+ }
+out:
+ /* Acknowledge the debug-IRQ, so the firmware can continue. */
+ b43_shm_write16(dev, B43_SHM_SCRATCH,
+ B43_DEBUGIRQ_REASON_REG, B43_DEBUGIRQ_ACK);
}
/* Interrupt handler bottom-half */
@@ -1880,7 +1976,8 @@
static int do_request_fw(struct b43_wldev *dev,
const char *name,
- struct b43_firmware_file *fw)
+ struct b43_firmware_file *fw,
+ bool silent)
{
char path[sizeof(modparam_fwpostfix) + 32];
const struct firmware *blob;
@@ -1904,9 +2001,15 @@
"b43%s/%s.fw",
modparam_fwpostfix, name);
err = request_firmware(&blob, path, dev->dev->dev);
- if (err) {
- b43err(dev->wl, "Firmware file \"%s\" not found "
- "or load failed.\n", path);
+ if (err == -ENOENT) {
+ if (!silent) {
+ b43err(dev->wl, "Firmware file \"%s\" not found\n",
+ path);
+ }
+ return err;
+ } else if (err) {
+ b43err(dev->wl, "Firmware file \"%s\" request failed (err=%d)\n",
+ path, err);
return err;
}
if (blob->size < sizeof(struct b43_fw_header))
@@ -1957,7 +2060,7 @@
filename = "ucode13";
else
goto err_no_ucode;
- err = do_request_fw(dev, filename, &fw->ucode);
+ err = do_request_fw(dev, filename, &fw->ucode, 0);
if (err)
goto err_load;
@@ -1968,8 +2071,13 @@
filename = NULL;
else
goto err_no_pcm;
- err = do_request_fw(dev, filename, &fw->pcm);
- if (err)
+ fw->pcm_request_failed = 0;
+ err = do_request_fw(dev, filename, &fw->pcm, 1);
+ if (err == -ENOENT) {
+ /* We did not find a PCM file? Not fatal, but
+ * core rev <= 10 must do without hwcrypto then. */
+ fw->pcm_request_failed = 1;
+ } else if (err)
goto err_load;
/* Get initvals */
@@ -1987,7 +2095,7 @@
if ((rev >= 5) && (rev <= 10))
filename = "b0g0initvals5";
else if (rev >= 13)
- filename = "lp0initvals13";
+ filename = "b0g0initvals13";
else
goto err_no_initvals;
break;
@@ -2000,7 +2108,7 @@
default:
goto err_no_initvals;
}
- err = do_request_fw(dev, filename, &fw->initvals);
+ err = do_request_fw(dev, filename, &fw->initvals, 0);
if (err)
goto err_load;
@@ -2034,7 +2142,7 @@
default:
goto err_no_initvals;
}
- err = do_request_fw(dev, filename, &fw->initvals_band);
+ err = do_request_fw(dev, filename, &fw->initvals_band, 0);
if (err)
goto err_load;
@@ -2151,14 +2259,28 @@
err = -EOPNOTSUPP;
goto error;
}
- b43info(dev->wl, "Loading firmware version %u.%u "
- "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
- fwrev, fwpatch,
- (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
- (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F);
-
dev->fw.rev = fwrev;
dev->fw.patch = fwpatch;
+ dev->fw.opensource = (fwdate == 0xFFFF);
+
+ if (dev->fw.opensource) {
+ /* Patchlevel info is encoded in the "time" field. */
+ dev->fw.patch = fwtime;
+ b43info(dev->wl, "Loading OpenSource firmware version %u.%u%s\n",
+ dev->fw.rev, dev->fw.patch,
+ dev->fw.pcm_request_failed ? " (Hardware crypto not supported)" : "");
+ } else {
+ b43info(dev->wl, "Loading firmware version %u.%u "
+ "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
+ fwrev, fwpatch,
+ (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
+ (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F);
+ if (dev->fw.pcm_request_failed) {
+ b43warn(dev->wl, "No \"pcm5.fw\" firmware file found. "
+ "Hardware accelerated cryptography is disabled.\n");
+ b43_print_fw_helptext(dev->wl, 0);
+ }
+ }
if (b43_is_old_txhdr_format(dev)) {
b43warn(dev->wl, "You are using an old firmware image. "
@@ -2335,7 +2457,7 @@
}
/* http://bcm-specs.sipsolutions.net/EnableMac */
-static void b43_mac_enable(struct b43_wldev *dev)
+void b43_mac_enable(struct b43_wldev *dev)
{
dev->mac_suspended--;
B43_WARN_ON(dev->mac_suspended < 0);
@@ -2349,16 +2471,11 @@
b43_read32(dev, B43_MMIO_MACCTL);
b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
b43_power_saving_ctl_bits(dev, 0);
-
- /* Re-enable IRQs. */
- spin_lock_irq(&dev->wl->irq_lock);
- b43_interrupt_enable(dev, dev->irq_savedstate);
- spin_unlock_irq(&dev->wl->irq_lock);
}
}
/* http://bcm-specs.sipsolutions.net/SuspendMAC */
-static void b43_mac_suspend(struct b43_wldev *dev)
+void b43_mac_suspend(struct b43_wldev *dev)
{
int i;
u32 tmp;
@@ -2367,14 +2484,6 @@
B43_WARN_ON(dev->mac_suspended < 0);
if (dev->mac_suspended == 0) {
- /* Mask IRQs before suspending MAC. Otherwise
- * the MAC stays busy and won't suspend. */
- spin_lock_irq(&dev->wl->irq_lock);
- tmp = b43_interrupt_disable(dev, B43_IRQ_ALL);
- spin_unlock_irq(&dev->wl->irq_lock);
- b43_synchronize_irq(dev);
- dev->irq_savedstate = tmp;
-
b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
b43_write32(dev, B43_MMIO_MACCTL,
b43_read32(dev, B43_MMIO_MACCTL)
@@ -2416,7 +2525,8 @@
ctl &= ~B43_MACCTL_BEACPROMISC;
ctl |= B43_MACCTL_INFRA;
- if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP))
+ if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
+ b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT))
ctl |= B43_MACCTL_AP;
else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS))
ctl &= ~B43_MACCTL_INFRA;
@@ -2530,6 +2640,7 @@
{
b43_radio_turn_off(dev, 1);
b43_gpio_cleanup(dev);
+ b43_lo_g_cleanup(dev);
/* firmware is released later */
}
@@ -2636,28 +2747,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);
@@ -2709,6 +2804,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);
@@ -2720,8 +2816,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)
@@ -2869,8 +2963,7 @@
}
static int b43_op_tx(struct ieee80211_hw *hw,
- struct sk_buff *skb,
- struct ieee80211_tx_control *ctl)
+ struct sk_buff *skb)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
struct b43_wldev *dev = wl->current_dev;
@@ -2892,9 +2985,9 @@
err = -ENODEV;
if (likely(b43_status(dev) >= B43_STAT_STARTED)) {
if (b43_using_pio_transfers(dev))
- err = b43_pio_tx(dev, skb, ctl);
+ err = b43_pio_tx(dev, skb);
else
- err = b43_dma_tx(dev, skb, ctl);
+ err = b43_dma_tx(dev, skb);
}
read_unlock_irqrestore(&wl->tx_lock, flags);
@@ -3052,8 +3145,7 @@
mutex_unlock(&wl->mutex);
}
-static int b43_op_conf_tx(struct ieee80211_hw *hw,
- int _queue,
+static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue,
const struct ieee80211_tx_queue_params *params)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
@@ -3301,8 +3393,9 @@
antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx);
b43_set_rx_antenna(dev, antenna);
- /* Update templates for AP mode. */
- if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP))
+ /* Update templates for AP/mesh mode. */
+ if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
+ b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT))
b43_set_beacon_int(dev, conf->beacon_int);
if (!!conf->radio_enabled != phy->radio_on) {
@@ -3353,6 +3446,13 @@
if (!dev || b43_status(dev) < B43_STAT_INITIALIZED)
goto out_unlock;
+ if (dev->fw.pcm_request_failed) {
+ /* We don't have firmware for the crypto engine.
+ * Must use software-crypto. */
+ err = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+
err = -EINVAL;
switch (key->alg) {
case ALG_WEP:
@@ -3483,13 +3583,12 @@
else
memset(wl->bssid, 0, ETH_ALEN);
if (b43_status(dev) >= B43_STAT_INITIALIZED) {
- if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) {
- B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP);
+ if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
+ b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) {
+ B43_WARN_ON(conf->type != wl->if_type);
b43_set_ssid(dev, conf->ssid, conf->ssid_len);
- if (conf->beacon) {
- b43_update_templates(wl, conf->beacon,
- conf->beacon_control);
- }
+ if (conf->beacon)
+ b43_update_templates(wl, conf->beacon);
}
b43_write_mac_bssid_templates(dev);
}
@@ -3554,7 +3653,6 @@
/* Start data flow (TX/RX). */
b43_mac_enable(dev);
b43_interrupt_enable(dev, dev->irq_savedstate);
- ieee80211_start_queues(dev->wl->hw);
/* Start maintainance work */
b43_periodic_tasks_setup(dev);
@@ -3695,8 +3793,8 @@
lo = phy->lo_control;
if (lo) {
memset(lo, 0, sizeof(*(phy->lo_control)));
- lo->rebuild = 1;
lo->tx_bias = 0xFF;
+ INIT_LIST_HEAD(&lo->calib_list);
}
phy->max_lb_gain = 0;
phy->trsw_rx_gain = 0;
@@ -4027,6 +4125,7 @@
/* TODO: allow WDS/AP devices to coexist */
if (conf->type != IEEE80211_IF_TYPE_AP &&
+ conf->type != IEEE80211_IF_TYPE_MESH_POINT &&
conf->type != IEEE80211_IF_TYPE_STA &&
conf->type != IEEE80211_IF_TYPE_WDS &&
conf->type != IEEE80211_IF_TYPE_IBSS)
@@ -4179,31 +4278,29 @@
struct b43_wl *wl = hw_to_b43_wl(hw);
struct sk_buff *beacon;
unsigned long flags;
- struct ieee80211_tx_control txctl;
/* We could modify the existing beacon and set the aid bit in
* the TIM field, but that would probably require resizing and
* moving of data within the beacon template.
* Simply request a new beacon and let mac80211 do the hard work. */
- beacon = ieee80211_beacon_get(hw, wl->vif, &txctl);
+ beacon = ieee80211_beacon_get(hw, wl->vif);
if (unlikely(!beacon))
return -ENOMEM;
spin_lock_irqsave(&wl->irq_lock, flags);
- b43_update_templates(wl, beacon, &txctl);
+ b43_update_templates(wl, beacon);
spin_unlock_irqrestore(&wl->irq_lock, flags);
return 0;
}
static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw,
- struct sk_buff *beacon,
- struct ieee80211_tx_control *ctl)
+ struct sk_buff *beacon)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
unsigned long flags;
spin_lock_irqsave(&wl->irq_lock, flags);
- b43_update_templates(wl, beacon, ctl);
+ b43_update_templates(wl, beacon);
spin_unlock_irqrestore(&wl->irq_lock, flags);
return 0;
@@ -4530,10 +4627,10 @@
/* fill hw info */
hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
- IEEE80211_HW_RX_INCLUDES_FCS;
- hw->max_signal = 100;
- hw->max_rssi = -110;
- hw->max_noise = -110;
+ IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_NOISE_DBM;
+
hw->queues = b43_modparam_qos ? 4 : 1;
SET_IEEE80211_DEV(hw, dev->dev);
if (is_valid_ether_addr(sprom->et1mac))
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/nphy.c b/drivers/net/wireless/b43/nphy.c
index 8695eb2..644eed9 100644
--- a/drivers/net/wireless/b43/nphy.c
+++ b/drivers/net/wireless/b43/nphy.c
@@ -29,8 +29,6 @@
#include "nphy.h"
#include "tables_nphy.h"
-#include <linux/delay.h>
-
void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
{//TODO
diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c
index de024dc..305d4cd 100644
--- a/drivers/net/wireless/b43/phy.c
+++ b/drivers/net/wireless/b43/phy.c
@@ -28,6 +28,7 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/types.h>
+#include <linux/bitrev.h>
#include "b43.h"
#include "phy.h"
@@ -83,25 +84,9 @@
72, 84,
};
+#define bitrev4(tmp) (bitrev8(tmp) >> 4)
static void b43_phy_initg(struct b43_wldev *dev);
-/* Reverse the bits of a 4bit value.
- * Example: 1101 is flipped 1011
- */
-static u16 flip_4bit(u16 value)
-{
- u16 flipped = 0x0000;
-
- B43_WARN_ON(value & ~0x000F);
-
- flipped |= (value & 0x0001) << 3;
- flipped |= (value & 0x0002) << 1;
- flipped |= (value & 0x0004) >> 1;
- flipped |= (value & 0x0008) >> 3;
-
- return flipped;
-}
-
static void generate_rfatt_list(struct b43_wldev *dev,
struct b43_rfatt_list *list)
{
@@ -145,8 +130,7 @@
{.att = 9,.with_padmix = 1,},
};
- if ((phy->type == B43_PHYTYPE_A && phy->rev < 5) ||
- (phy->type == B43_PHYTYPE_G && phy->rev < 6)) {
+ if (!b43_has_hardware_pctl(phy)) {
/* Software pctl */
list->list = rfatt_0;
list->len = ARRAY_SIZE(rfatt_0);
@@ -158,7 +142,7 @@
/* Hardware pctl */
list->list = rfatt_1;
list->len = ARRAY_SIZE(rfatt_1);
- list->min_val = 2;
+ list->min_val = 0;
list->max_val = 14;
return;
}
@@ -346,6 +330,7 @@
/* Save the values for later */
phy->tx_control = tx_control;
memcpy(&phy->rfatt, rfatt, sizeof(*rfatt));
+ phy->rfatt.with_padmix = !!(tx_control & B43_TXCTL_TXMIX);
memcpy(&phy->bbatt, bbatt, sizeof(*bbatt));
if (b43_debug(dev, B43_DBG_XMITPOWER)) {
@@ -559,11 +544,6 @@
u16 tmp;
u8 rf, bb;
- if (!lo->lo_measured) {
- b43_phy_write(dev, 0x3FF, 0);
- return;
- }
-
for (rf = 0; rf < lo->rfatt_list.len; rf++) {
for (bb = 0; bb < lo->bbatt_list.len; bb++) {
if (nr_written >= 0x40)
@@ -581,42 +561,6 @@
}
}
-/* GPHY_DC_Lookup_Table */
-void b43_gphy_dc_lt_init(struct b43_wldev *dev)
-{
- struct b43_phy *phy = &dev->phy;
- struct b43_txpower_lo_control *lo = phy->lo_control;
- struct b43_loctl *loctl0;
- struct b43_loctl *loctl1;
- int i;
- int rf_offset, bb_offset;
- u16 tmp;
-
- for (i = 0; i < lo->rfatt_list.len + lo->bbatt_list.len; i += 2) {
- rf_offset = i / lo->rfatt_list.len;
- bb_offset = i % lo->rfatt_list.len;
-
- loctl0 = b43_get_lo_g_ctl(dev, &lo->rfatt_list.list[rf_offset],
- &lo->bbatt_list.list[bb_offset]);
- if (i + 1 < lo->rfatt_list.len * lo->bbatt_list.len) {
- rf_offset = (i + 1) / lo->rfatt_list.len;
- bb_offset = (i + 1) % lo->rfatt_list.len;
-
- loctl1 =
- b43_get_lo_g_ctl(dev,
- &lo->rfatt_list.list[rf_offset],
- &lo->bbatt_list.list[bb_offset]);
- } else
- loctl1 = loctl0;
-
- tmp = ((u16) loctl0->q & 0xF);
- tmp |= ((u16) loctl0->i & 0xF) << 4;
- tmp |= ((u16) loctl1->q & 0xF) << 8;
- tmp |= ((u16) loctl1->i & 0xF) << 12; //FIXME?
- b43_phy_write(dev, 0x3A0 + (i / 2), tmp);
- }
-}
-
static void hardware_pctl_init_aphy(struct b43_wldev *dev)
{
//TODO
@@ -643,7 +587,7 @@
b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801)
& 0xFFBF);
- b43_gphy_dc_lt_init(dev);
+ b43_gphy_dc_lt_init(dev, 1);
}
/* HardwarePowerControl init for A and G PHY */
@@ -931,109 +875,6 @@
}
}
-static void b43_phy_initb2(struct b43_wldev *dev)
-{
- struct b43_phy *phy = &dev->phy;
- u16 offset, val;
-
- b43_write16(dev, 0x03EC, 0x3F22);
- b43_phy_write(dev, 0x0020, 0x301C);
- b43_phy_write(dev, 0x0026, 0x0000);
- b43_phy_write(dev, 0x0030, 0x00C6);
- b43_phy_write(dev, 0x0088, 0x3E00);
- val = 0x3C3D;
- for (offset = 0x0089; offset < 0x00A7; offset++) {
- b43_phy_write(dev, offset, val);
- val -= 0x0202;
- }
- b43_phy_write(dev, 0x03E4, 0x3000);
- b43_radio_selectchannel(dev, phy->channel, 0);
- if (phy->radio_ver != 0x2050) {
- b43_radio_write16(dev, 0x0075, 0x0080);
- b43_radio_write16(dev, 0x0079, 0x0081);
- }
- b43_radio_write16(dev, 0x0050, 0x0020);
- b43_radio_write16(dev, 0x0050, 0x0023);
- if (phy->radio_ver == 0x2050) {
- b43_radio_write16(dev, 0x0050, 0x0020);
- b43_radio_write16(dev, 0x005A, 0x0070);
- b43_radio_write16(dev, 0x005B, 0x007B);
- b43_radio_write16(dev, 0x005C, 0x00B0);
- b43_radio_write16(dev, 0x007A, 0x000F);
- b43_phy_write(dev, 0x0038, 0x0677);
- b43_radio_init2050(dev);
- }
- b43_phy_write(dev, 0x0014, 0x0080);
- b43_phy_write(dev, 0x0032, 0x00CA);
- b43_phy_write(dev, 0x0032, 0x00CC);
- b43_phy_write(dev, 0x0035, 0x07C2);
- b43_lo_b_measure(dev);
- b43_phy_write(dev, 0x0026, 0xCC00);
- if (phy->radio_ver != 0x2050)
- b43_phy_write(dev, 0x0026, 0xCE00);
- b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1000);
- b43_phy_write(dev, 0x002A, 0x88A3);
- if (phy->radio_ver != 0x2050)
- b43_phy_write(dev, 0x002A, 0x88C2);
- b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
- b43_phy_init_pctl(dev);
-}
-
-static void b43_phy_initb4(struct b43_wldev *dev)
-{
- struct b43_phy *phy = &dev->phy;
- u16 offset, val;
-
- b43_write16(dev, 0x03EC, 0x3F22);
- b43_phy_write(dev, 0x0020, 0x301C);
- b43_phy_write(dev, 0x0026, 0x0000);
- b43_phy_write(dev, 0x0030, 0x00C6);
- b43_phy_write(dev, 0x0088, 0x3E00);
- val = 0x3C3D;
- for (offset = 0x0089; offset < 0x00A7; offset++) {
- b43_phy_write(dev, offset, val);
- val -= 0x0202;
- }
- b43_phy_write(dev, 0x03E4, 0x3000);
- b43_radio_selectchannel(dev, phy->channel, 0);
- if (phy->radio_ver != 0x2050) {
- b43_radio_write16(dev, 0x0075, 0x0080);
- b43_radio_write16(dev, 0x0079, 0x0081);
- }
- b43_radio_write16(dev, 0x0050, 0x0020);
- b43_radio_write16(dev, 0x0050, 0x0023);
- if (phy->radio_ver == 0x2050) {
- b43_radio_write16(dev, 0x0050, 0x0020);
- b43_radio_write16(dev, 0x005A, 0x0070);
- b43_radio_write16(dev, 0x005B, 0x007B);
- b43_radio_write16(dev, 0x005C, 0x00B0);
- b43_radio_write16(dev, 0x007A, 0x000F);
- b43_phy_write(dev, 0x0038, 0x0677);
- b43_radio_init2050(dev);
- }
- b43_phy_write(dev, 0x0014, 0x0080);
- b43_phy_write(dev, 0x0032, 0x00CA);
- if (phy->radio_ver == 0x2050)
- b43_phy_write(dev, 0x0032, 0x00E0);
- b43_phy_write(dev, 0x0035, 0x07C2);
-
- b43_lo_b_measure(dev);
-
- b43_phy_write(dev, 0x0026, 0xCC00);
- if (phy->radio_ver == 0x2050)
- b43_phy_write(dev, 0x0026, 0xCE00);
- b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1100);
- b43_phy_write(dev, 0x002A, 0x88A3);
- if (phy->radio_ver == 0x2050)
- b43_phy_write(dev, 0x002A, 0x88C2);
- b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
- if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
- b43_calc_nrssi_slope(dev);
- b43_calc_nrssi_threshold(dev);
- }
- b43_phy_init_pctl(dev);
-}
-
static void b43_phy_initb5(struct b43_wldev *dev)
{
struct ssb_bus *bus = dev->dev->bus;
@@ -1259,19 +1100,9 @@
b43_phy_write(dev, 0x0002, (b43_phy_read(dev, 0x0002) & 0xFFC0)
| 0x0004);
}
- if (phy->type == B43_PHYTYPE_B) {
- b43_write16(dev, 0x03E6, 0x8140);
- b43_phy_write(dev, 0x0016, 0x0410);
- b43_phy_write(dev, 0x0017, 0x0820);
- b43_phy_write(dev, 0x0062, 0x0007);
- b43_radio_init2050(dev);
- b43_lo_g_measure(dev);
- if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
- b43_calc_nrssi_slope(dev);
- b43_calc_nrssi_threshold(dev);
- }
- b43_phy_init_pctl(dev);
- } else if (phy->type == B43_PHYTYPE_G)
+ if (phy->type == B43_PHYTYPE_B)
+ B43_WARN_ON(1);
+ else if (phy->type == B43_PHYTYPE_G)
b43_write16(dev, 0x03E6, 0x0);
}
@@ -1534,34 +1365,31 @@
else
b43_radio_write16(dev, 0x0078, phy->initval);
}
- if (phy->lo_control->tx_bias == 0xFF) {
- b43_lo_g_measure(dev);
+ b43_lo_g_init(dev);
+ if (has_tx_magnification(phy)) {
+ b43_radio_write16(dev, 0x52,
+ (b43_radio_read16(dev, 0x52) & 0xFF00)
+ | phy->lo_control->tx_bias | phy->
+ lo_control->tx_magn);
} else {
- if (has_tx_magnification(phy)) {
- b43_radio_write16(dev, 0x52,
- (b43_radio_read16(dev, 0x52) & 0xFF00)
- | phy->lo_control->tx_bias | phy->
- lo_control->tx_magn);
- } else {
- b43_radio_write16(dev, 0x52,
- (b43_radio_read16(dev, 0x52) & 0xFFF0)
- | phy->lo_control->tx_bias);
- }
- if (phy->rev >= 6) {
- b43_phy_write(dev, B43_PHY_CCK(0x36),
- (b43_phy_read(dev, B43_PHY_CCK(0x36))
- & 0x0FFF) | (phy->lo_control->
- tx_bias << 12));
- }
- if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
- b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075);
- else
- b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F);
- if (phy->rev < 2)
- b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101);
- else
- b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202);
+ b43_radio_write16(dev, 0x52,
+ (b43_radio_read16(dev, 0x52) & 0xFFF0)
+ | phy->lo_control->tx_bias);
}
+ if (phy->rev >= 6) {
+ b43_phy_write(dev, B43_PHY_CCK(0x36),
+ (b43_phy_read(dev, B43_PHY_CCK(0x36))
+ & 0x0FFF) | (phy->lo_control->
+ tx_bias << 12));
+ }
+ if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
+ b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075);
+ else
+ b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F);
+ if (phy->rev < 2)
+ b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101);
+ else
+ b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202);
if (phy->gmode || phy->rev >= 2) {
b43_lo_g_adjust(dev);
b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
@@ -1572,7 +1400,7 @@
* the value 0x7FFFFFFF here. I think that is some weird
* compiler optimization in the original driver.
* Essentially, what we do here is resetting all NRSSI LT
- * entries to -32 (see the limit_value() in nrssi_hw_update())
+ * entries to -32 (see the clamp_val() in nrssi_hw_update())
*/
b43_nrssi_hw_update(dev, 0xFFFF); //FIXME?
b43_calc_nrssi_threshold(dev);
@@ -1634,13 +1462,13 @@
switch (phy->type) {
case B43_PHYTYPE_A:
tmp += 0x80;
- tmp = limit_value(tmp, 0x00, 0xFF);
+ tmp = clamp_val(tmp, 0x00, 0xFF);
dbm = phy->tssi2dbm[tmp];
//TODO: There's a FIXME on the specs
break;
case B43_PHYTYPE_B:
case B43_PHYTYPE_G:
- tmp = limit_value(tmp, 0x00, 0x3F);
+ tmp = clamp_val(tmp, 0x00, 0x3F);
dbm = phy->tssi2dbm[tmp];
break;
default:
@@ -1699,8 +1527,8 @@
break;
}
- *_rfatt = limit_value(rfatt, rf_min, rf_max);
- *_bbatt = limit_value(bbatt, bb_min, bb_max);
+ *_rfatt = clamp_val(rfatt, rf_min, rf_max);
+ *_bbatt = clamp_val(bbatt, bb_min, bb_max);
}
/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */
@@ -1795,7 +1623,7 @@
/* Get desired power (in Q5.2) */
desired_pwr = INT_TO_Q52(phy->power_level);
/* And limit it. max_pwr already is Q5.2 */
- desired_pwr = limit_value(desired_pwr, 0, max_pwr);
+ desired_pwr = clamp_val(desired_pwr, 0, max_pwr);
if (b43_debug(dev, B43_DBG_XMITPOWER)) {
b43dbg(dev->wl,
"Current TX power output: " Q52_FMT
@@ -1821,10 +1649,8 @@
bbatt_delta -= 4 * rfatt_delta;
/* So do we finally need to adjust something? */
- if ((rfatt_delta == 0) && (bbatt_delta == 0)) {
- b43_lo_g_ctl_mark_cur_used(dev);
+ if ((rfatt_delta == 0) && (bbatt_delta == 0))
return;
- }
/* Calculate the new attenuation values. */
bbatt = phy->bbatt.att;
@@ -1870,7 +1696,6 @@
b43_radio_lock(dev);
b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt,
phy->tx_control);
- b43_lo_g_ctl_mark_cur_used(dev);
b43_radio_unlock(dev);
b43_phy_unlock(dev);
break;
@@ -1908,7 +1733,7 @@
f = q;
i++;
} while (delta >= 2);
- entry[index] = limit_value(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128);
+ entry[index] = clamp_val(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128);
return 0;
}
@@ -2007,24 +1832,6 @@
else
unsupported = 1;
break;
- case B43_PHYTYPE_B:
- switch (phy->rev) {
- case 2:
- b43_phy_initb2(dev);
- break;
- case 4:
- b43_phy_initb4(dev);
- break;
- case 5:
- b43_phy_initb5(dev);
- break;
- case 6:
- b43_phy_initb6(dev);
- break;
- default:
- unsupported = 1;
- }
- break;
case B43_PHYTYPE_G:
b43_phy_initg(dev);
break;
@@ -2452,7 +2259,7 @@
for (i = 0; i < 64; i++) {
tmp = b43_nrssi_hw_read(dev, i);
tmp -= val;
- tmp = limit_value(tmp, -32, 31);
+ tmp = clamp_val(tmp, -32, 31);
b43_nrssi_hw_write(dev, i, tmp);
}
}
@@ -2469,7 +2276,7 @@
tmp = (i - delta) * phy->nrssislope;
tmp /= 0x10000;
tmp += 0x3A;
- tmp = limit_value(tmp, 0, 0x3F);
+ tmp = clamp_val(tmp, 0, 0x3F);
phy->nrssi_lt[i] = tmp;
}
}
@@ -2906,7 +2713,7 @@
} else
threshold = phy->nrssi[1] - 5;
- threshold = limit_value(threshold, 0, 0x3E);
+ threshold = clamp_val(threshold, 0, 0x3E);
b43_phy_read(dev, 0x0020); /* dummy read */
b43_phy_write(dev, 0x0020,
(((u16) threshold) << 8) | 0x001C);
@@ -2957,7 +2764,7 @@
else
a += 32;
a = a >> 6;
- a = limit_value(a, -31, 31);
+ a = clamp_val(a, -31, 31);
b = b * (phy->nrssi[1] - phy->nrssi[0]);
b += (phy->nrssi[0] << 6);
@@ -2966,7 +2773,7 @@
else
b += 32;
b = b >> 6;
- b = limit_value(b, -31, 31);
+ b = clamp_val(b, -31, 31);
tmp_u16 = b43_phy_read(dev, 0x048A) & 0xF000;
tmp_u16 |= ((u32) b & 0x0000003F);
@@ -3069,13 +2876,13 @@
}
radio_stacksave(0x0078);
tmp = (b43_radio_read16(dev, 0x0078) & 0x001E);
- flipped = flip_4bit(tmp);
+ B43_WARN_ON(tmp > 15);
+ flipped = bitrev4(tmp);
if (flipped < 10 && flipped >= 8)
flipped = 7;
else if (flipped >= 10)
flipped -= 3;
- flipped = flip_4bit(flipped);
- flipped = (flipped << 1) | 0x0020;
+ flipped = (bitrev4(flipped) << 1) | 0x0020;
b43_radio_write16(dev, 0x0078, flipped);
b43_calc_nrssi_threshold(dev);
@@ -3708,7 +3515,7 @@
tmp1 >>= 9;
for (i = 0; i < 16; i++) {
- radio78 = ((flip_4bit(i) << 1) | 0x20);
+ radio78 = (bitrev4(i) << 1) | 0x0020;
b43_radio_write16(dev, 0x78, radio78);
udelay(10);
for (j = 0; j < 16; j++) {
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..8b1555d 100644
--- a/drivers/net/wireless/b43/pio.c
+++ b/drivers/net/wireless/b43/pio.c
@@ -446,29 +446,27 @@
}
static int pio_tx_frame(struct b43_pio_txqueue *q,
- struct sk_buff *skb,
- struct ieee80211_tx_control *ctl)
+ struct sk_buff *skb)
{
struct b43_pio_txpacket *pack;
struct b43_txhdr txhdr;
u16 cookie;
int err;
unsigned int hdrlen;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
B43_WARN_ON(list_empty(&q->packets_list));
pack = list_entry(q->packets_list.next,
struct b43_pio_txpacket, list);
- memset(&pack->txstat, 0, sizeof(pack->txstat));
- memcpy(&pack->txstat.control, ctl, sizeof(*ctl));
cookie = generate_cookie(q, pack);
hdrlen = b43_txhdr_size(q->dev);
err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb->data,
- skb->len, ctl, cookie);
+ skb->len, info, cookie);
if (err)
return err;
- if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) {
+ if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
/* Tell the firmware about the cookie of the last
* mcast frame, so it can clear the more-data bit in it. */
b43_shm_write16(q->dev, B43_SHM_SHARED,
@@ -492,17 +490,18 @@
return 0;
}
-int b43_pio_tx(struct b43_wldev *dev,
- struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb)
{
struct b43_pio_txqueue *q;
struct ieee80211_hdr *hdr;
unsigned long flags;
unsigned int hdrlen, total_len;
int err = 0;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
hdr = (struct ieee80211_hdr *)skb->data;
- if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) {
+
+ if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
/* The multicast queue will be sent after the DTIM. */
q = dev->pio.tx_queue_mcast;
/* Set the frame More-Data bit. Ucode will clear it
@@ -510,7 +509,7 @@
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
} else {
/* Decide by priority where to put this frame. */
- q = select_queue_by_priority(dev, ctl->queue);
+ q = select_queue_by_priority(dev, skb_get_queue_mapping(skb));
}
spin_lock_irqsave(&q->lock, flags);
@@ -533,7 +532,7 @@
if (total_len > (q->buffer_size - q->buffer_used)) {
/* Not enough memory on the queue. */
err = -EBUSY;
- ieee80211_stop_queue(dev->wl->hw, ctl->queue);
+ ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb));
q->stopped = 1;
goto out_unlock;
}
@@ -541,9 +540,9 @@
/* Assign the queue number to the ring (if not already done before)
* so TX status handling can use it. The mac80211-queue to b43-queue
* mapping is static, so we don't need to store it per frame. */
- q->queue_prio = ctl->queue;
+ q->queue_prio = skb_get_queue_mapping(skb);
- err = pio_tx_frame(q, skb, ctl);
+ err = pio_tx_frame(q, skb);
if (unlikely(err == -ENOKEY)) {
/* Drop this packet, as we don't have the encryption key
* anymore and must not transmit it unencrypted. */
@@ -561,7 +560,7 @@
if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) ||
(q->free_packet_slots == 0)) {
/* The queue is full. */
- ieee80211_stop_queue(dev->wl->hw, ctl->queue);
+ ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb));
q->stopped = 1;
}
@@ -578,6 +577,7 @@
struct b43_pio_txqueue *q;
struct b43_pio_txpacket *pack = NULL;
unsigned int total_len;
+ struct ieee80211_tx_info *info;
q = parse_cookie(dev, status->cookie, &pack);
if (unlikely(!q))
@@ -586,15 +586,17 @@
spin_lock(&q->lock); /* IRQs are already disabled. */
- b43_fill_txstatus_report(&(pack->txstat), status);
+ info = (void *)pack->skb;
+ memset(&info->status, 0, sizeof(info->status));
+
+ b43_fill_txstatus_report(info, status);
total_len = pack->skb->len + b43_txhdr_size(dev);
total_len = roundup(total_len, 4);
q->buffer_used -= total_len;
q->free_packet_slots += 1;
- ieee80211_tx_status_irqsafe(dev->wl->hw, pack->skb,
- &(pack->txstat));
+ ieee80211_tx_status_irqsafe(dev->wl->hw, pack->skb);
pack->skb = NULL;
list_add(&pack->list, &q->packets_list);
@@ -611,18 +613,16 @@
{
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/pio.h b/drivers/net/wireless/b43/pio.h
index e2ec676..6c174c9 100644
--- a/drivers/net/wireless/b43/pio.h
+++ b/drivers/net/wireless/b43/pio.h
@@ -62,8 +62,6 @@
struct b43_pio_txqueue *queue;
/* The TX data packet. */
struct sk_buff *skb;
- /* The status meta data. */
- struct ieee80211_tx_status txstat;
/* Index in the (struct b43_pio_txqueue)->packets array. */
u8 index;
@@ -167,8 +165,7 @@
void b43_pio_stop(struct b43_wldev *dev);
void b43_pio_free(struct b43_wldev *dev);
-int b43_pio_tx(struct b43_wldev *dev,
- struct sk_buff *skb, struct ieee80211_tx_control *ctl);
+int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb);
void b43_pio_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status);
void b43_pio_get_tx_stats(struct b43_wldev *dev,
@@ -193,8 +190,7 @@
{
}
static inline int b43_pio_tx(struct b43_wldev *dev,
- struct sk_buff *skb,
- struct ieee80211_tx_control *ctl)
+ struct sk_buff *skb)
{
return 0;
}
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
index 19aefbf..f9e1cff 100644
--- a/drivers/net/wireless/b43/xmit.c
+++ b/drivers/net/wireless/b43/xmit.c
@@ -185,14 +185,14 @@
u8 *_txhdr,
const unsigned char *fragment_data,
unsigned int fragment_len,
- const struct ieee80211_tx_control *txctl,
+ const struct ieee80211_tx_info *info,
u16 cookie)
{
struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr;
const struct b43_phy *phy = &dev->phy;
const struct ieee80211_hdr *wlhdr =
(const struct ieee80211_hdr *)fragment_data;
- int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT));
+ int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT));
u16 fctl = le16_to_cpu(wlhdr->frame_control);
struct ieee80211_rate *fbrate;
u8 rate, rate_fb;
@@ -201,13 +201,14 @@
u32 mac_ctl = 0;
u16 phy_ctl = 0;
u8 extra_ft = 0;
+ struct ieee80211_rate *txrate;
memset(txhdr, 0, sizeof(*txhdr));
- WARN_ON(!txctl->tx_rate);
- rate = txctl->tx_rate ? txctl->tx_rate->hw_value : B43_CCK_RATE_1MB;
+ txrate = ieee80211_get_tx_rate(dev->wl->hw, info);
+ rate = txrate ? txrate->hw_value : B43_CCK_RATE_1MB;
rate_ofdm = b43_is_ofdm_rate(rate);
- fbrate = txctl->alt_retry_rate ? : txctl->tx_rate;
+ fbrate = ieee80211_get_alt_retry_rate(dev->wl->hw, info) ? : txrate;
rate_fb = fbrate->hw_value;
rate_fb_ofdm = b43_is_ofdm_rate(rate_fb);
@@ -227,15 +228,13 @@
* use the original dur_id field. */
txhdr->dur_fb = wlhdr->duration_id;
} else {
- txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
- txctl->vif,
- fragment_len,
- fbrate);
+ txhdr->dur_fb = ieee80211_generic_frame_duration(
+ dev->wl->hw, info->control.vif, fragment_len, fbrate);
}
plcp_fragment_len = fragment_len + FCS_LEN;
if (use_encryption) {
- u8 key_idx = (u16) (txctl->key_idx);
+ u8 key_idx = info->control.hw_key->hw_key_idx;
struct b43_key *key;
int wlhdr_len;
size_t iv_len;
@@ -253,7 +252,7 @@
}
/* Hardware appends ICV. */
- plcp_fragment_len += txctl->icv_len;
+ plcp_fragment_len += info->control.icv_len;
key_idx = b43_kidx_to_fw(dev, key_idx);
mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) &
@@ -261,7 +260,7 @@
mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) &
B43_TXH_MAC_KEYALG;
wlhdr_len = ieee80211_get_hdrlen(fctl);
- iv_len = min((size_t) txctl->iv_len,
+ iv_len = min((size_t) info->control.iv_len,
ARRAY_SIZE(txhdr->iv));
memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
}
@@ -292,10 +291,10 @@
phy_ctl |= B43_TXH_PHY_ENC_OFDM;
else
phy_ctl |= B43_TXH_PHY_ENC_CCK;
- if (txctl->flags & IEEE80211_TXCTL_SHORT_PREAMBLE)
+ if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE)
phy_ctl |= B43_TXH_PHY_SHORTPRMBL;
- switch (b43_ieee80211_antenna_sanitize(dev, txctl->antenna_sel_tx)) {
+ switch (b43_ieee80211_antenna_sanitize(dev, info->antenna_sel_tx)) {
case 0: /* Default */
phy_ctl |= B43_TXH_PHY_ANT01AUTO;
break;
@@ -316,34 +315,36 @@
}
/* MAC control */
- if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK))
+ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
mac_ctl |= B43_TXH_MAC_ACK;
if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
mac_ctl |= B43_TXH_MAC_HWSEQ;
- if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)
+ if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
mac_ctl |= B43_TXH_MAC_STMSDU;
if (phy->type == B43_PHYTYPE_A)
mac_ctl |= B43_TXH_MAC_5GHZ;
- if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT)
+ if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
mac_ctl |= B43_TXH_MAC_LONGFRAME;
/* Generate the RTS or CTS-to-self frame */
- if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
- (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
+ if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
+ (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
unsigned int len;
struct ieee80211_hdr *hdr;
int rts_rate, rts_rate_fb;
int rts_rate_ofdm, rts_rate_fb_ofdm;
struct b43_plcp_hdr6 *plcp;
+ struct ieee80211_rate *rts_cts_rate;
- WARN_ON(!txctl->rts_cts_rate);
- rts_rate = txctl->rts_cts_rate ? txctl->rts_cts_rate->hw_value : B43_CCK_RATE_1MB;
+ rts_cts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info);
+
+ rts_rate = rts_cts_rate ? rts_cts_rate->hw_value : B43_CCK_RATE_1MB;
rts_rate_ofdm = b43_is_ofdm_rate(rts_rate);
rts_rate_fb = b43_calc_fallback_rate(rts_rate);
rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
- if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
+ if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
struct ieee80211_cts *cts;
if (b43_is_old_txhdr_format(dev)) {
@@ -353,9 +354,9 @@
cts = (struct ieee80211_cts *)
(txhdr->new_format.rts_frame);
}
- ieee80211_ctstoself_get(dev->wl->hw, txctl->vif,
+ ieee80211_ctstoself_get(dev->wl->hw, info->control.vif,
fragment_data, fragment_len,
- txctl, cts);
+ info, cts);
mac_ctl |= B43_TXH_MAC_SENDCTS;
len = sizeof(struct ieee80211_cts);
} else {
@@ -368,9 +369,9 @@
rts = (struct ieee80211_rts *)
(txhdr->new_format.rts_frame);
}
- ieee80211_rts_get(dev->wl->hw, txctl->vif,
+ ieee80211_rts_get(dev->wl->hw, info->control.vif,
fragment_data, fragment_len,
- txctl, rts);
+ info, rts);
mac_ctl |= B43_TXH_MAC_SENDRTS;
len = sizeof(struct ieee80211_rts);
}
@@ -581,12 +582,11 @@
// and also find out what the maximum possible value is.
// Fill status.ssi and status.signal fields.
} else {
- status.ssi = b43_rssi_postprocess(dev, rxhdr->jssi,
+ status.signal = b43_rssi_postprocess(dev, rxhdr->jssi,
(phystat0 & B43_RX_PHYST0_OFDM),
(phystat0 & B43_RX_PHYST0_GAINCTL),
(phystat3 & B43_RX_PHYST3_TRSTATE));
- /* the next line looks wrong, but is what mac80211 wants */
- status.signal = (rxhdr->jssi * 100) / B43_RX_MAX_SSI;
+ status.qual = (rxhdr->jssi * 100) / B43_RX_MAX_SSI;
}
if (phystat0 & B43_RX_PHYST0_OFDM)
@@ -685,27 +685,27 @@
/* Fill out the mac80211 TXstatus report based on the b43-specific
* txstatus report data. This returns a boolean whether the frame was
* successfully transmitted. */
-bool b43_fill_txstatus_report(struct ieee80211_tx_status *report,
+bool b43_fill_txstatus_report(struct ieee80211_tx_info *report,
const struct b43_txstatus *status)
{
bool frame_success = 1;
if (status->acked) {
/* The frame was ACKed. */
- report->flags |= IEEE80211_TX_STATUS_ACK;
+ report->flags |= IEEE80211_TX_STAT_ACK;
} else {
/* The frame was not ACKed... */
- if (!(report->control.flags & IEEE80211_TXCTL_NO_ACK)) {
+ if (!(report->flags & IEEE80211_TX_CTL_NO_ACK)) {
/* ...but we expected an ACK. */
frame_success = 0;
- report->excessive_retries = 1;
+ report->status.excessive_retries = 1;
}
}
if (status->frame_count == 0) {
/* The frame was not transmitted at all. */
- report->retry_count = 0;
+ report->status.retry_count = 0;
} else
- report->retry_count = status->frame_count - 1;
+ report->status.retry_count = status->frame_count - 1;
return frame_success;
}
diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h
index b05f44e..0215faf 100644
--- a/drivers/net/wireless/b43/xmit.h
+++ b/drivers/net/wireless/b43/xmit.h
@@ -178,7 +178,7 @@
u8 * txhdr,
const unsigned char *fragment_data,
unsigned int fragment_len,
- const struct ieee80211_tx_control *txctl, u16 cookie);
+ const struct ieee80211_tx_info *txctl, u16 cookie);
/* Transmit Status */
struct b43_txstatus {
@@ -294,7 +294,7 @@
void b43_handle_txstatus(struct b43_wldev *dev,
const struct b43_txstatus *status);
-bool b43_fill_txstatus_report(struct ieee80211_tx_status *report,
+bool b43_fill_txstatus_report(struct ieee80211_tx_info *report,
const struct b43_txstatus *status);
void b43_tx_suspend(struct b43_wldev *dev);
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h
index ded3cd3..c40078e 100644
--- a/drivers/net/wireless/b43legacy/b43legacy.h
+++ b/drivers/net/wireless/b43legacy/b43legacy.h
@@ -823,23 +823,6 @@
# define b43legacydbg(wl, fmt...) do { /* nothing */ } while (0)
#endif /* DEBUG */
-
-/** Limit a value between two limits */
-#ifdef limit_value
-# undef limit_value
-#endif
-#define limit_value(value, min, max) \
- ({ \
- typeof(value) __value = (value); \
- typeof(value) __min = (min); \
- typeof(value) __max = (max); \
- if (__value < __min) \
- __value = __min; \
- else if (__value > __max) \
- __value = __max; \
- __value; \
- })
-
/* Macros for printing a value in Q5.2 format */
#define Q52_FMT "%u.%u"
#define Q52_ARG(q52) ((q52) / 4), (((q52) & 3) * 100 / 4)
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
index c990f87..33cc256 100644
--- a/drivers/net/wireless/b43legacy/dma.c
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -1205,10 +1205,10 @@
}
static int dma_tx_fragment(struct b43legacy_dmaring *ring,
- struct sk_buff *skb,
- struct ieee80211_tx_control *ctl)
+ struct sk_buff *skb)
{
const struct b43legacy_dma_ops *ops = ring->ops;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
u8 *header;
int slot, old_top_slot, old_used_slots;
int err;
@@ -1231,7 +1231,7 @@
header = &(ring->txhdr_cache[slot * sizeof(
struct b43legacy_txhdr_fw3)]);
err = b43legacy_generate_txhdr(ring->dev, header,
- skb->data, skb->len, ctl,
+ skb->data, skb->len, info,
generate_cookie(ring, slot));
if (unlikely(err)) {
ring->current_slot = old_top_slot;
@@ -1255,7 +1255,6 @@
desc = ops->idx2desc(ring, slot, &meta);
memset(meta, 0, sizeof(*meta));
- memcpy(&meta->txstat.control, ctl, sizeof(*ctl));
meta->skb = skb;
meta->is_last_fragment = 1;
@@ -1323,14 +1322,13 @@
}
int b43legacy_dma_tx(struct b43legacy_wldev *dev,
- struct sk_buff *skb,
- struct ieee80211_tx_control *ctl)
+ struct sk_buff *skb)
{
struct b43legacy_dmaring *ring;
int err = 0;
unsigned long flags;
- ring = priority_to_txring(dev, ctl->queue);
+ ring = priority_to_txring(dev, skb_get_queue_mapping(skb));
spin_lock_irqsave(&ring->lock, flags);
B43legacy_WARN_ON(!ring->tx);
if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) {
@@ -1343,7 +1341,7 @@
* That would be a mac80211 bug. */
B43legacy_BUG_ON(ring->stopped);
- err = dma_tx_fragment(ring, skb, ctl);
+ err = dma_tx_fragment(ring, skb);
if (unlikely(err == -ENOKEY)) {
/* Drop this packet, as we don't have the encryption key
* anymore and must not transmit it unencrypted. */
@@ -1401,26 +1399,29 @@
1);
if (meta->is_last_fragment) {
- B43legacy_WARN_ON(!meta->skb);
+ struct ieee80211_tx_info *info;
+ BUG_ON(!meta->skb);
+ info = IEEE80211_SKB_CB(meta->skb);
/* Call back to inform the ieee80211 subsystem about the
* status of the transmission.
* Some fields of txstat are already filled in dma_tx().
*/
+
+ memset(&info->status, 0, sizeof(info->status));
+
if (status->acked) {
- meta->txstat.flags |= IEEE80211_TX_STATUS_ACK;
+ info->flags |= IEEE80211_TX_STAT_ACK;
} else {
- if (!(meta->txstat.control.flags
- & IEEE80211_TXCTL_NO_ACK))
- meta->txstat.excessive_retries = 1;
+ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
+ info->status.excessive_retries = 1;
}
if (status->frame_count == 0) {
/* The frame was not transmitted at all. */
- meta->txstat.retry_count = 0;
+ info->status.retry_count = 0;
} else
- meta->txstat.retry_count = status->frame_count
+ info->status.retry_count = status->frame_count
- 1;
- ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb,
- &(meta->txstat));
+ ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb);
/* skb is freed by ieee80211_tx_status_irqsafe() */
meta->skb = NULL;
} else {
@@ -1455,18 +1456,16 @@
{
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/dma.h b/drivers/net/wireless/b43legacy/dma.h
index 2dd488c..2f18600 100644
--- a/drivers/net/wireless/b43legacy/dma.h
+++ b/drivers/net/wireless/b43legacy/dma.h
@@ -195,7 +195,6 @@
dma_addr_t dmaaddr;
/* ieee80211 TX status. Only used once per 802.11 frag. */
bool is_last_fragment;
- struct ieee80211_tx_status txstat;
};
struct b43legacy_dmaring;
@@ -297,8 +296,7 @@
struct ieee80211_tx_queue_stats *stats);
int b43legacy_dma_tx(struct b43legacy_wldev *dev,
- struct sk_buff *skb,
- struct ieee80211_tx_control *ctl);
+ struct sk_buff *skb);
void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
const struct b43legacy_txstatus *status);
@@ -323,8 +321,7 @@
}
static inline
int b43legacy_dma_tx(struct b43legacy_wldev *dev,
- struct sk_buff *skb,
- struct ieee80211_tx_control *ctl)
+ struct sk_buff *skb)
{
return 0;
}
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 204077c..5f533b9 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -846,10 +846,10 @@
/* Get the noise samples. */
B43legacy_WARN_ON(dev->noisecalc.nr_samples >= 8);
i = dev->noisecalc.nr_samples;
- noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
- noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
- noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
- noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+ noise[0] = clamp_val(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+ noise[1] = clamp_val(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+ noise[2] = clamp_val(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+ noise[3] = clamp_val(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]];
dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]];
dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]];
@@ -2358,8 +2358,7 @@
}
static int b43legacy_op_tx(struct ieee80211_hw *hw,
- struct sk_buff *skb,
- struct ieee80211_tx_control *ctl)
+ struct sk_buff *skb)
{
struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
struct b43legacy_wldev *dev = wl->current_dev;
@@ -2373,18 +2372,17 @@
/* DMA-TX is done without a global lock. */
if (b43legacy_using_pio(dev)) {
spin_lock_irqsave(&wl->irq_lock, flags);
- err = b43legacy_pio_tx(dev, skb, ctl);
+ err = b43legacy_pio_tx(dev, skb);
spin_unlock_irqrestore(&wl->irq_lock, flags);
} else
- err = b43legacy_dma_tx(dev, skb, ctl);
+ err = b43legacy_dma_tx(dev, skb);
out:
if (unlikely(err))
return NETDEV_TX_BUSY;
return NETDEV_TX_OK;
}
-static int b43legacy_op_conf_tx(struct ieee80211_hw *hw,
- int queue,
+static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
return 0;
@@ -2795,7 +2793,6 @@
/* Start data flow (TX/RX) */
b43legacy_mac_enable(dev);
b43legacy_interrupt_enable(dev, dev->irq_savedstate);
- ieee80211_start_queues(dev->wl->hw);
/* Start maintenance work */
b43legacy_periodic_tasks_setup(dev);
@@ -3404,7 +3401,7 @@
* field, but that would probably require resizing and moving of data
* within the beacon template. Simply request a new beacon and let
* mac80211 do the hard work. */
- beacon = ieee80211_beacon_get(hw, wl->vif, NULL);
+ beacon = ieee80211_beacon_get(hw, wl->vif);
if (unlikely(!beacon))
return -ENOMEM;
spin_lock_irqsave(&wl->irq_lock, flags);
@@ -3415,8 +3412,7 @@
}
static int b43legacy_op_ibss_beacon_update(struct ieee80211_hw *hw,
- struct sk_buff *beacon,
- struct ieee80211_tx_control *ctl)
+ struct sk_buff *beacon)
{
struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
unsigned long flags;
@@ -3716,10 +3712,9 @@
/* fill hw info */
hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
- IEEE80211_HW_RX_INCLUDES_FCS;
- hw->max_signal = 100;
- hw->max_rssi = -110;
- hw->max_noise = -110;
+ IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_NOISE_DBM;
hw->queues = 1; /* FIXME: hardware has more queues */
SET_IEEE80211_DEV(hw, dev->dev);
if (is_valid_ether_addr(sprom->et1mac))
diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c
index 8e5c09b..768cccb 100644
--- a/drivers/net/wireless/b43legacy/phy.c
+++ b/drivers/net/wireless/b43legacy/phy.c
@@ -1088,7 +1088,7 @@
* the value 0x7FFFFFFF here. I think that is some weird
* compiler optimization in the original driver.
* Essentially, what we do here is resetting all NRSSI LT
- * entries to -32 (see the limit_value() in nrssi_hw_update())
+ * entries to -32 (see the clamp_val() in nrssi_hw_update())
*/
b43legacy_nrssi_hw_update(dev, 0xFFFF);
b43legacy_calc_nrssi_threshold(dev);
@@ -1756,7 +1756,7 @@
switch (phy->type) {
case B43legacy_PHYTYPE_B:
case B43legacy_PHYTYPE_G:
- tmp = limit_value(tmp, 0x00, 0x3F);
+ tmp = clamp_val(tmp, 0x00, 0x3F);
dbm = phy->tssi2dbm[tmp];
break;
default:
@@ -1859,7 +1859,7 @@
/* find the desired power in Q5.2 - power_level is in dBm
* and limit it - max_pwr is already in Q5.2 */
- desired_pwr = limit_value(phy->power_level << 2, 0, max_pwr);
+ desired_pwr = clamp_val(phy->power_level << 2, 0, max_pwr);
if (b43legacy_debug(dev, B43legacy_DBG_XMITPOWER))
b43legacydbg(dev->wl, "Current TX power output: " Q52_FMT
" dBm, Desired TX power output: " Q52_FMT
@@ -1905,7 +1905,7 @@
radio_attenuation++;
}
}
- baseband_attenuation = limit_value(baseband_attenuation, 0, 11);
+ baseband_attenuation = clamp_val(baseband_attenuation, 0, 11);
txpower = phy->txctl1;
if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) {
@@ -1933,8 +1933,8 @@
}
/* Save the control values */
phy->txctl1 = txpower;
- baseband_attenuation = limit_value(baseband_attenuation, 0, 11);
- radio_attenuation = limit_value(radio_attenuation, 0, 9);
+ baseband_attenuation = clamp_val(baseband_attenuation, 0, 11);
+ radio_attenuation = clamp_val(radio_attenuation, 0, 9);
phy->rfatt = radio_attenuation;
phy->bbatt = baseband_attenuation;
@@ -1979,7 +1979,7 @@
f = q;
i++;
} while (delta >= 2);
- entry[index] = limit_value(b43legacy_tssi2dbm_ad(m1 * f, 8192),
+ entry[index] = clamp_val(b43legacy_tssi2dbm_ad(m1 * f, 8192),
-127, 128);
return 0;
}
diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c
index bcdd54e..a86c764 100644
--- a/drivers/net/wireless/b43legacy/pio.c
+++ b/drivers/net/wireless/b43legacy/pio.c
@@ -196,7 +196,7 @@
B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0);
err = b43legacy_generate_txhdr(queue->dev,
txhdr, skb->data, skb->len,
- &packet->txstat.control,
+ IEEE80211_SKB_CB(skb),
generate_cookie(queue, packet));
if (err)
return err;
@@ -463,8 +463,7 @@
}
int b43legacy_pio_tx(struct b43legacy_wldev *dev,
- struct sk_buff *skb,
- struct ieee80211_tx_control *ctl)
+ struct sk_buff *skb)
{
struct b43legacy_pioqueue *queue = dev->pio.queue1;
struct b43legacy_pio_txpacket *packet;
@@ -476,9 +475,6 @@
list);
packet->skb = skb;
- memset(&packet->txstat, 0, sizeof(packet->txstat));
- memcpy(&packet->txstat.control, ctl, sizeof(*ctl));
-
list_move_tail(&packet->list, &queue->txqueue);
queue->nr_txfree--;
queue->nr_tx_packets++;
@@ -494,6 +490,7 @@
{
struct b43legacy_pioqueue *queue;
struct b43legacy_pio_txpacket *packet;
+ struct ieee80211_tx_info *info;
queue = parse_cookie(dev, status->cookie, &packet);
B43legacy_WARN_ON(!queue);
@@ -505,11 +502,13 @@
queue->tx_devq_used -= (packet->skb->len +
sizeof(struct b43legacy_txhdr_fw3));
+ info = IEEE80211_SKB_CB(packet->skb);
+ memset(&info->status, 0, sizeof(info->status));
+
if (status->acked)
- packet->txstat.flags |= IEEE80211_TX_STATUS_ACK;
- packet->txstat.retry_count = status->frame_count - 1;
- ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb,
- &(packet->txstat));
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ info->status.retry_count = status->frame_count - 1;
+ ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb);
packet->skb = NULL;
free_txpacket(packet, 1);
@@ -525,13 +524,11 @@
{
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/pio.h b/drivers/net/wireless/b43legacy/pio.h
index 5bfed0c..464fec0 100644
--- a/drivers/net/wireless/b43legacy/pio.h
+++ b/drivers/net/wireless/b43legacy/pio.h
@@ -41,7 +41,6 @@
struct b43legacy_pio_txpacket {
struct b43legacy_pioqueue *queue;
struct sk_buff *skb;
- struct ieee80211_tx_status txstat;
struct list_head list;
};
@@ -104,8 +103,7 @@
void b43legacy_pio_free(struct b43legacy_wldev *dev);
int b43legacy_pio_tx(struct b43legacy_wldev *dev,
- struct sk_buff *skb,
- struct ieee80211_tx_control *ctl);
+ struct sk_buff *skb);
void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
const struct b43legacy_txstatus *status);
void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev,
@@ -132,8 +130,7 @@
}
static inline
int b43legacy_pio_tx(struct b43legacy_wldev *dev,
- struct sk_buff *skb,
- struct ieee80211_tx_control *ctl)
+ struct sk_buff *skb)
{
return 0;
}
diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c
index 955832e..2df545c 100644
--- a/drivers/net/wireless/b43legacy/radio.c
+++ b/drivers/net/wireless/b43legacy/radio.c
@@ -357,7 +357,7 @@
for (i = 0; i < 64; i++) {
tmp = b43legacy_nrssi_hw_read(dev, i);
tmp -= val;
- tmp = limit_value(tmp, -32, 31);
+ tmp = clamp_val(tmp, -32, 31);
b43legacy_nrssi_hw_write(dev, i, tmp);
}
}
@@ -375,7 +375,7 @@
tmp = (i - delta) * phy->nrssislope;
tmp /= 0x10000;
tmp += 0x3A;
- tmp = limit_value(tmp, 0, 0x3F);
+ tmp = clamp_val(tmp, 0, 0x3F);
phy->nrssi_lt[i] = tmp;
}
}
@@ -839,7 +839,7 @@
} else
threshold = phy->nrssi[1] - 5;
- threshold = limit_value(threshold, 0, 0x3E);
+ threshold = clamp_val(threshold, 0, 0x3E);
b43legacy_phy_read(dev, 0x0020); /* dummy read */
b43legacy_phy_write(dev, 0x0020, (((u16)threshold) << 8)
| 0x001C);
@@ -892,7 +892,7 @@
else
a += 32;
a = a >> 6;
- a = limit_value(a, -31, 31);
+ a = clamp_val(a, -31, 31);
b = b * (phy->nrssi[1] - phy->nrssi[0]);
b += (phy->nrssi[0] << 6);
@@ -901,7 +901,7 @@
else
b += 32;
b = b >> 6;
- b = limit_value(b, -31, 31);
+ b = clamp_val(b, -31, 31);
tmp_u16 = b43legacy_phy_read(dev, 0x048A) & 0xF000;
tmp_u16 |= ((u32)b & 0x0000003F);
@@ -1905,7 +1905,7 @@
u16 dac;
u16 ilt;
- txpower = limit_value(txpower, 0, 63);
+ txpower = clamp_val(txpower, 0, 63);
pamp = b43legacy_get_txgain_freq_power_amp(txpower);
pamp <<= 5;
diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c
index dcad249..82dc04d 100644
--- a/drivers/net/wireless/b43legacy/xmit.c
+++ b/drivers/net/wireless/b43legacy/xmit.c
@@ -188,11 +188,11 @@
struct b43legacy_txhdr_fw3 *txhdr,
const unsigned char *fragment_data,
unsigned int fragment_len,
- const struct ieee80211_tx_control *txctl,
+ const struct ieee80211_tx_info *info,
u16 cookie)
{
const struct ieee80211_hdr *wlhdr;
- int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT));
+ int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT));
u16 fctl;
u8 rate;
struct ieee80211_rate *rate_fb;
@@ -201,15 +201,18 @@
unsigned int plcp_fragment_len;
u32 mac_ctl = 0;
u16 phy_ctl = 0;
+ struct ieee80211_rate *tx_rate;
wlhdr = (const struct ieee80211_hdr *)fragment_data;
fctl = le16_to_cpu(wlhdr->frame_control);
memset(txhdr, 0, sizeof(*txhdr));
- rate = txctl->tx_rate->hw_value;
+ tx_rate = ieee80211_get_tx_rate(dev->wl->hw, info);
+
+ rate = tx_rate->hw_value;
rate_ofdm = b43legacy_is_ofdm_rate(rate);
- rate_fb = txctl->alt_retry_rate ? : txctl->tx_rate;
+ rate_fb = ieee80211_get_alt_retry_rate(dev->wl->hw, info) ? : tx_rate;
rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb->hw_value);
txhdr->mac_frame_ctl = wlhdr->frame_control;
@@ -225,14 +228,14 @@
txhdr->dur_fb = wlhdr->duration_id;
} else {
txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
- txctl->vif,
+ info->control.vif,
fragment_len,
rate_fb);
}
plcp_fragment_len = fragment_len + FCS_LEN;
if (use_encryption) {
- u8 key_idx = (u16)(txctl->key_idx);
+ u8 key_idx = info->control.hw_key->hw_key_idx;
struct b43legacy_key *key;
int wlhdr_len;
size_t iv_len;
@@ -242,7 +245,7 @@
if (key->enabled) {
/* Hardware appends ICV. */
- plcp_fragment_len += txctl->icv_len;
+ plcp_fragment_len += info->control.icv_len;
key_idx = b43legacy_kidx_to_fw(dev, key_idx);
mac_ctl |= (key_idx << B43legacy_TX4_MAC_KEYIDX_SHIFT) &
@@ -251,7 +254,7 @@
B43legacy_TX4_MAC_KEYALG_SHIFT) &
B43legacy_TX4_MAC_KEYALG;
wlhdr_len = ieee80211_get_hdrlen(fctl);
- iv_len = min((size_t)txctl->iv_len,
+ iv_len = min((size_t)info->control.iv_len,
ARRAY_SIZE(txhdr->iv));
memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len);
} else {
@@ -275,7 +278,7 @@
phy_ctl |= B43legacy_TX4_PHY_OFDM;
if (dev->short_preamble)
phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL;
- switch (txctl->antenna_sel_tx) {
+ switch (info->antenna_sel_tx) {
case 0:
phy_ctl |= B43legacy_TX4_PHY_ANTLAST;
break;
@@ -290,21 +293,21 @@
}
/* MAC control */
- if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK))
+ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
mac_ctl |= B43legacy_TX4_MAC_ACK;
if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
mac_ctl |= B43legacy_TX4_MAC_HWSEQ;
- if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)
+ if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
mac_ctl |= B43legacy_TX4_MAC_STMSDU;
if (rate_fb_ofdm)
mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM;
- if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT)
+ if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
mac_ctl |= B43legacy_TX4_MAC_LONGFRAME;
/* Generate the RTS or CTS-to-self frame */
- if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
- (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
+ if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
+ (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
unsigned int len;
struct ieee80211_hdr *hdr;
int rts_rate;
@@ -312,26 +315,26 @@
int rts_rate_ofdm;
int rts_rate_fb_ofdm;
- rts_rate = txctl->rts_cts_rate->hw_value;
+ rts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info)->hw_value;
rts_rate_ofdm = b43legacy_is_ofdm_rate(rts_rate);
rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate);
rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb);
if (rts_rate_fb_ofdm)
mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM;
- if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
+ if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
ieee80211_ctstoself_get(dev->wl->hw,
- txctl->vif,
+ info->control.vif,
fragment_data,
- fragment_len, txctl,
+ fragment_len, info,
(struct ieee80211_cts *)
(txhdr->rts_frame));
mac_ctl |= B43legacy_TX4_MAC_SENDCTS;
len = sizeof(struct ieee80211_cts);
} else {
ieee80211_rts_get(dev->wl->hw,
- txctl->vif,
- fragment_data, fragment_len, txctl,
+ info->control.vif,
+ fragment_data, fragment_len, info,
(struct ieee80211_rts *)
(txhdr->rts_frame));
mac_ctl |= B43legacy_TX4_MAC_SENDRTS;
@@ -362,12 +365,12 @@
u8 *txhdr,
const unsigned char *fragment_data,
unsigned int fragment_len,
- const struct ieee80211_tx_control *txctl,
+ const struct ieee80211_tx_info *info,
u16 cookie)
{
return generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr,
fragment_data, fragment_len,
- txctl, cookie);
+ info, cookie);
}
static s8 b43legacy_rssi_postprocess(struct b43legacy_wldev *dev,
@@ -532,12 +535,12 @@
}
}
- status.ssi = b43legacy_rssi_postprocess(dev, jssi,
+ status.signal = b43legacy_rssi_postprocess(dev, jssi,
(phystat0 & B43legacy_RX_PHYST0_OFDM),
(phystat0 & B43legacy_RX_PHYST0_GAINCTL),
(phystat3 & B43legacy_RX_PHYST3_TRSTATE));
status.noise = dev->stats.link_noise;
- status.signal = (jssi * 100) / B43legacy_RX_MAX_SSI;
+ status.qual = (jssi * 100) / B43legacy_RX_MAX_SSI;
/* change to support A PHY */
if (phystat0 & B43legacy_RX_PHYST0_OFDM)
status.rate_idx = b43legacy_plcp_get_bitrate_idx_ofdm(plcp, false);
diff --git a/drivers/net/wireless/b43legacy/xmit.h b/drivers/net/wireless/b43legacy/xmit.h
index bab4792..e56777e0f 100644
--- a/drivers/net/wireless/b43legacy/xmit.h
+++ b/drivers/net/wireless/b43legacy/xmit.h
@@ -80,7 +80,7 @@
u8 *txhdr,
const unsigned char *fragment_data,
unsigned int fragment_len,
- const struct ieee80211_tx_control *txctl,
+ const struct ieee80211_tx_info *info,
u16 cookie);
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index 62fb89d..5f3e849 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"
@@ -85,13 +96,13 @@
control which debug output is sent to the kernel log by setting the
value in
- /sys/bus/pci/drivers/${DRIVER}/debug_level
+ /sys/class/net/wlan0/device/debug_level
This entry will only exist if this option is enabled.
To set a value, simply echo an 8-byte hex value to the same file:
- % echo 0x43fff > /sys/bus/pci/drivers/${DRIVER}/debug_level
+ % echo 0x43fff > /sys/class/net/wlan0/device/debug_level
You can find the list of debug mask values in:
drivers/net/wireless/iwlwifi/iwl-4965-debug.h
@@ -100,6 +111,23 @@
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..5c73eed 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -1,13 +1,20 @@
obj-$(CONFIG_IWLCORE) += iwlcore.o
-iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o
+iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o
+iwlcore-objs += iwl-rx.o iwl-tx.o iwl-sta.o
iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o
iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o
+iwlcore-$(CONFIG_IWLWIFI_RUN_TIME_CALIB) += iwl-calib.o
obj-$(CONFIG_IWL3945) += iwl3945.o
iwl3945-objs := iwl3945-base.o iwl-3945.o iwl-3945-rs.o
iwl3945-$(CONFIG_IWL3945_LEDS) += iwl-3945-led.o
obj-$(CONFIG_IWL4965) += iwl4965.o
-iwl4965-objs := iwl4965-base.o iwl-4965.o iwl-4965-rs.o iwl-sta.o
+iwl4965-objs := iwl4965-base.o iwl-4965.o iwl-4965-rs.o
+
+ifeq ($(CONFIG_IWL5000),y)
+ iwl4965-objs += iwl-5000.o
+endif
+
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..10c64bd 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>
@@ -446,8 +445,7 @@
*/
static void rs_tx_status(void *priv_rate,
struct net_device *dev,
- struct sk_buff *skb,
- struct ieee80211_tx_status *tx_resp)
+ struct sk_buff *skb)
{
u8 retries, current_count;
int scale_rate_index, first_index, last_index;
@@ -458,14 +456,15 @@
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct iwl3945_rs_sta *rs_sta;
struct ieee80211_supported_band *sband;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
IWL_DEBUG_RATE("enter\n");
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- retries = tx_resp->retry_count;
- first_index = tx_resp->control.tx_rate->hw_value;
+ retries = info->status.retry_count;
+ first_index = sband->bitrates[info->tx_rate_idx].hw_value;
if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) {
IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index);
return;
@@ -526,11 +525,11 @@
/* Update the last index window with success/failure based on ACK */
IWL_DEBUG_RATE("Update rate %d with %s.\n",
last_index,
- (tx_resp->flags & IEEE80211_TX_STATUS_ACK) ?
+ (info->flags & IEEE80211_TX_STAT_ACK) ?
"success" : "failure");
iwl3945_collect_tx_data(rs_sta,
&rs_sta->win[last_index],
- tx_resp->flags & IEEE80211_TX_STATUS_ACK, 1);
+ info->flags & IEEE80211_TX_STAT_ACK, 1);
/* We updated the rate scale window -- if its been more than
* flush_time since the last run, schedule the flush
@@ -670,7 +669,7 @@
is_multicast_ether_addr(hdr->addr1) ||
!sta || !sta->rate_ctrl_priv) {
IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
- sel->rate = rate_lowest(local, sband, sta);
+ sel->rate_idx = rate_lowest_index(local, sband, sta);
rcu_read_unlock();
return;
}
@@ -814,7 +813,7 @@
IWL_DEBUG_RATE("leave: %d\n", index);
- sel->rate = &sband->bitrates[sta->txrate_idx];
+ sel->rate_idx = sta->txrate_idx;
}
static struct rate_control_ops rs_ops = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 62a3d8f..0ba6889 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -283,8 +283,7 @@
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
tx_info = &txq->txb[txq->q.read_ptr];
- ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0],
- &tx_info->status);
+ ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]);
tx_info->skb[0] = NULL;
iwl3945_hw_txq_free_tfd(priv, txq);
}
@@ -306,7 +305,7 @@
int txq_id = SEQ_TO_QUEUE(sequence);
int index = SEQ_TO_INDEX(sequence);
struct iwl3945_tx_queue *txq = &priv->txq[txq_id];
- struct ieee80211_tx_status *tx_status;
+ struct ieee80211_tx_info *info;
struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
u32 status = le32_to_cpu(tx_resp->status);
int rate_idx;
@@ -319,19 +318,22 @@
return;
}
- tx_status = &(txq->txb[txq->q.read_ptr].status);
+ info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
+ memset(&info->status, 0, sizeof(info->status));
- tx_status->retry_count = tx_resp->failure_frame;
+ info->status.retry_count = tx_resp->failure_frame;
/* tx_status->rts_retry_count = tx_resp->failure_rts; */
- tx_status->flags = ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ?
- IEEE80211_TX_STATUS_ACK : 0;
+ info->flags |= ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ?
+ IEEE80211_TX_STAT_ACK : 0;
IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n",
txq_id, iwl3945_get_tx_fail_reason(status), status,
tx_resp->rate, tx_resp->failure_frame);
rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate);
- tx_status->control.tx_rate = &priv->ieee_rates[rate_idx];
+ if (info->band == IEEE80211_BAND_5GHZ)
+ rate_idx -= IWL_FIRST_OFDM_RATE;
+ info->tx_rate_idx = rate_idx;
IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
iwl3945_tx_queue_reclaim(priv, txq_id, index);
@@ -520,7 +522,7 @@
{
/* First cache any information we need before we overwrite
* the information provided in the skb from the hardware */
- s8 signal = stats->ssi;
+ s8 signal = stats->signal;
s8 noise = 0;
int rate = stats->rate_idx;
u64 tsf = stats->mactime;
@@ -693,7 +695,7 @@
}
/* Convert 3945's rssi indicator to dBm */
- rx_status.ssi = rx_stats->rssi - IWL_RSSI_OFFSET;
+ rx_status.signal = rx_stats->rssi - IWL_RSSI_OFFSET;
/* Set default noise value to -127 */
if (priv->last_rx_noise == 0)
@@ -712,21 +714,21 @@
* Calculate rx_status.signal (quality indicator in %) based on SNR. */
if (rx_stats_noise_diff) {
snr = rx_stats_sig_avg / rx_stats_noise_diff;
- rx_status.noise = rx_status.ssi -
+ rx_status.noise = rx_status.signal -
iwl3945_calc_db_from_ratio(snr);
- rx_status.signal = iwl3945_calc_sig_qual(rx_status.ssi,
+ rx_status.qual = iwl3945_calc_sig_qual(rx_status.signal,
rx_status.noise);
/* If noise info not available, calculate signal quality indicator (%)
* using just the dBm signal level. */
} else {
rx_status.noise = priv->last_rx_noise;
- rx_status.signal = iwl3945_calc_sig_qual(rx_status.ssi, 0);
+ rx_status.qual = iwl3945_calc_sig_qual(rx_status.signal, 0);
}
IWL_DEBUG_STATS("Rssi %d noise %d qual %d sig_avg %d noise_diff %d\n",
- rx_status.ssi, rx_status.noise, rx_status.signal,
+ rx_status.signal, rx_status.noise, rx_status.qual,
rx_stats_sig_avg, rx_stats_noise_diff);
header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
@@ -736,8 +738,8 @@
IWL_DEBUG_STATS_LIMIT("[%c] %d RSSI:%d Signal:%u, Noise:%u, Rate:%u\n",
network_packet ? '*' : ' ',
le16_to_cpu(rx_hdr->channel),
- rx_status.ssi, rx_status.ssi,
- rx_status.ssi, rx_status.rate_idx);
+ rx_status.signal, rx_status.signal,
+ rx_status.noise, rx_status.rate_idx);
#ifdef CONFIG_IWL3945_DEBUG
if (iwl3945_debug_level & (IWL_DL_RX))
@@ -748,7 +750,7 @@
if (network_packet) {
priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp);
priv->last_tsf = le64_to_cpu(rx_end->timestamp);
- priv->last_rx_rssi = rx_status.ssi;
+ priv->last_rx_rssi = rx_status.signal;
priv->last_rx_noise = rx_status.noise;
}
@@ -958,11 +960,12 @@
*/
void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv,
struct iwl3945_cmd *cmd,
- struct ieee80211_tx_control *ctrl,
+ struct ieee80211_tx_info *info,
struct ieee80211_hdr *hdr, int sta_id, int tx_id)
{
unsigned long flags;
- u16 rate_index = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1);
+ u16 hw_value = ieee80211_get_tx_rate(priv->hw, info)->hw_value;
+ u16 rate_index = min(hw_value & 0xffff, IWL_RATE_COUNT - 1);
u16 rate_mask;
int rate;
u8 rts_retry_limit;
@@ -974,7 +977,7 @@
tx_flags = cmd->cmd.tx.tx_flags;
/* We need to figure out how to get the sta->supp_rates while
- * in this running context; perhaps encoding into ctrl->tx_rate? */
+ * in this running context */
rate_mask = IWL_RATES_MASK;
spin_lock_irqsave(&priv->sta_lock, flags);
@@ -1229,7 +1232,7 @@
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..a9b3eda 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -124,7 +124,6 @@
/* One for each TFD */
struct iwl3945_tx_info {
- struct ieee80211_tx_status status;
struct sk_buff *skb[MAX_NUM_OF_TBS];
};
@@ -645,7 +644,7 @@
extern int iwl3945_hw_get_rx_read(struct iwl3945_priv *priv);
extern void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv,
struct iwl3945_cmd *cmd,
- struct ieee80211_tx_control *ctrl,
+ struct ieee80211_tx_info *info,
struct ieee80211_hdr *hdr,
int sta_id, int tx_id);
extern int iwl3945_hw_reg_send_txpower(struct iwl3945_priv *priv);
@@ -836,8 +835,6 @@
u8 mac80211_registered;
- u32 notif_missed_beacons;
-
/* Rx'd packet timing information */
u32 last_beacon_time;
u64 last_tsf;
@@ -886,6 +883,7 @@
struct work_struct report_work;
struct work_struct request_scan;
struct work_struct beacon_update;
+ struct work_struct set_monitor;
struct tasklet_struct irq_tasklet;
@@ -924,11 +922,6 @@
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..fc11833 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,11 +98,16 @@
#define IWL_RSSI_OFFSET 44
-#include "iwl-4965-commands.h"
+#include "iwl-commands.h"
-#define PCI_LINK_CTRL 0x0F0
+/* PCI registers */
+#define PCI_LINK_CTRL 0x0F0 /* 1 byte */
#define PCI_POWER_SOURCE 0x0C8
#define PCI_REG_WUM8 0x0E8
+
+/* PCI register values */
+#define PCI_LINK_VAL_L0S_EN 0x01
+#define PCI_LINK_VAL_L1_EN 0x02
#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000)
#define TFD_QUEUE_SIZE_MAX (256)
@@ -131,10 +141,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 +793,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,14 +827,14 @@
* up to 7 DMA channels (FIFOs). Each Tx queue is supported by a circular array
* in DRAM containing 256 Transmit Frame Descriptors (TFDs).
*/
-#define IWL4965_MAX_WIN_SIZE 64
-#define IWL4965_QUEUE_SIZE 256
-#define IWL4965_NUM_FIFOS 7
-#define IWL4965_MAX_NUM_QUEUES 16
-
+#define IWL49_MAX_WIN_SIZE 64
+#define IWL49_QUEUE_SIZE 256
+#define IWL49_NUM_FIFOS 7
+#define IWL49_CMD_FIFO_NUM 4
+#define IWL49_NUM_QUEUES 16
/**
- * struct iwl4965_tfd_frame_data
+ * struct iwl_tfd_frame_data
*
* Describes up to 2 buffers containing (contiguous) portions of a Tx frame.
* Each buffer must be on dword boundary.
@@ -1411,7 +853,7 @@
* 31-20: Tx buffer 2 length (bytes)
* 19- 0: Tx buffer 2 address bits [35:16]
*/
-struct iwl4965_tfd_frame_data {
+struct iwl_tfd_frame_data {
__le32 tb1_addr;
__le32 val1;
@@ -1441,7 +883,7 @@
/**
- * struct iwl4965_tfd_frame
+ * struct iwl_tfd_frame
*
* Transmit Frame Descriptor (TFD)
*
@@ -1468,7 +910,7 @@
*
* A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx.
*/
-struct iwl4965_tfd_frame {
+struct iwl_tfd_frame {
__le32 val0;
/* __le32 rsvd1:24; */
/* __le32 num_tbs:5; */
@@ -1477,7 +919,7 @@
#define IWL_num_tbs_SYM val0
/* __le32 rsvd2:1; */
/* __le32 padding:2; */
- struct iwl4965_tfd_frame_data pa[10];
+ struct iwl_tfd_frame_data pa[10];
__le32 reserved;
} __attribute__ ((packed));
@@ -1520,10 +962,10 @@
* 4965 assumes tables are separated by 1024 bytes.
*/
struct iwl4965_sched_queue_byte_cnt_tbl {
- struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL4965_QUEUE_SIZE +
- IWL4965_MAX_WIN_SIZE];
+ struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL49_QUEUE_SIZE +
+ IWL49_MAX_WIN_SIZE];
u8 dont_care[1024 -
- (IWL4965_QUEUE_SIZE + IWL4965_MAX_WIN_SIZE) *
+ (IWL49_QUEUE_SIZE + IWL49_MAX_WIN_SIZE) *
sizeof(__le16)];
} __attribute__ ((packed));
@@ -1553,7 +995,7 @@
*/
struct iwl4965_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 3a7f0cb..d8f2b4d 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
@@ -271,14 +282,20 @@
* increment traffic load value for tid and also remove
* any old values if passed the certain time period
*/
-static void rs_tl_add_packet(struct iwl4965_lq_sta *lq_data, u8 tid)
+static void rs_tl_add_packet(struct iwl4965_lq_sta *lq_data,
+ struct ieee80211_hdr *hdr)
{
u32 curr_time = jiffies_to_msecs(jiffies);
u32 time_diff;
s32 index;
struct iwl4965_traffic_load *tl = NULL;
+ u16 fc = le16_to_cpu(hdr->frame_control);
+ u8 tid;
- if (tid >= TID_MAX_LOAD_COUNT)
+ if (ieee80211_is_qos_data(fc)) {
+ u8 *qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc));
+ tid = qc[0] & 0xf;
+ } else
return;
tl = &lq_data->load[tid];
@@ -349,9 +366,9 @@
unsigned long state;
DECLARE_MAC_BUF(mac);
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_lock_bh(&sta->lock);
state = sta->ampdu_mlme.tid_state_tx[tid];
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
if (state == HT_AGG_STATE_IDLE &&
rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) {
@@ -374,6 +391,13 @@
#endif /* CONFIG_IWLWIFI_HT */
+static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
+{
+ return (!!(rate_n_flags & RATE_MCS_ANT_A_MSK) +
+ !!(rate_n_flags & RATE_MCS_ANT_B_MSK) +
+ !!(rate_n_flags & RATE_MCS_ANT_C_MSK));
+}
+
/**
* rs_collect_tx_data - Update the success/failure sliding window
*
@@ -386,8 +410,7 @@
int successes)
{
struct iwl4965_rate_scale_data *window = NULL;
- u64 mask;
- u8 win_size = IWL_RATE_MAX_WINDOW;
+ static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1));
s32 fail_count;
if (scale_index < 0 || scale_index >= IWL_RATE_COUNT)
@@ -405,14 +428,14 @@
* we keep these bitmaps!).
*/
while (retries > 0) {
- if (window->counter >= win_size) {
- window->counter = win_size - 1;
- mask = 1;
- mask = (mask << (win_size - 1));
+ if (window->counter >= IWL_RATE_MAX_WINDOW) {
+
+ /* remove earliest */
+ window->counter = IWL_RATE_MAX_WINDOW - 1;
+
if (window->data & mask) {
window->data &= ~mask;
- window->success_counter =
- window->success_counter - 1;
+ window->success_counter--;
}
}
@@ -422,10 +445,9 @@
/* Shift bitmap by one frame (throw away oldest history),
* OR in "1", and increment "success" if this
* frame was successful. */
- mask = window->data;
- window->data = (mask << 1);
+ window->data <<= 1;;
if (successes > 0) {
- window->success_counter = window->success_counter + 1;
+ window->success_counter++;
window->data |= 0x1;
successes--;
}
@@ -458,170 +480,166 @@
/*
* Fill uCode API rate_n_flags field, based on "search" or "active" table.
*/
-static void rs_mcs_from_tbl(struct iwl4965_rate *mcs_rate,
- struct iwl4965_scale_tbl_info *tbl,
- int index, u8 use_green)
+/* FIXME:RS:remove this function and put the flags statically in the table */
+static u32 rate_n_flags_from_tbl(struct iwl4965_scale_tbl_info *tbl,
+ int index, u8 use_green)
{
+ u32 rate_n_flags = 0;
+
if (is_legacy(tbl->lq_type)) {
- mcs_rate->rate_n_flags = iwl4965_rates[index].plcp;
+ rate_n_flags = iwl_rates[index].plcp;
if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE)
- mcs_rate->rate_n_flags |= RATE_MCS_CCK_MSK;
+ rate_n_flags |= RATE_MCS_CCK_MSK;
- } else if (is_siso(tbl->lq_type)) {
- if (index > IWL_LAST_OFDM_RATE)
+ } else if (is_Ht(tbl->lq_type)) {
+ if (index > IWL_LAST_OFDM_RATE) {
+ IWL_ERROR("invalid HT rate index %d\n", index);
index = IWL_LAST_OFDM_RATE;
- mcs_rate->rate_n_flags = iwl4965_rates[index].plcp_siso |
- RATE_MCS_HT_MSK;
- } else {
- if (index > IWL_LAST_OFDM_RATE)
- index = IWL_LAST_OFDM_RATE;
- mcs_rate->rate_n_flags = iwl4965_rates[index].plcp_mimo |
- RATE_MCS_HT_MSK;
- }
+ }
+ 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 |= iwl_rates[index].plcp_siso;
+ else if (is_mimo2(tbl->lq_type))
+ rate_n_flags |= iwl_rates[index].plcp_mimo2;
+ else
+ rate_n_flags |= iwl_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,27 +648,28 @@
* 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;
}
}
-static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type)
+static u16 rs_get_adjacent_rate(struct iwl_priv *priv, u8 index, u16 rate_mask,
+ int rate_type)
{
u8 high = IWL_RATE_INVALID;
u8 low = IWL_RATE_INVALID;
@@ -684,7 +703,7 @@
low = index;
while (low != IWL_RATE_INVALID) {
- low = iwl4965_rates[low].prev_rs;
+ low = iwl_rates[low].prev_rs;
if (low == IWL_RATE_INVALID)
break;
if (rate_mask & (1 << low))
@@ -694,7 +713,7 @@
high = index;
while (high != IWL_RATE_INVALID) {
- high = iwl4965_rates[high].next_rs;
+ high = iwl_rates[high].next_rs;
if (high == IWL_RATE_INVALID)
break;
if (rate_mask & (1 << high))
@@ -705,9 +724,9 @@
return (high << 8) | low;
}
-static void rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta,
+static u32 rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta,
struct iwl4965_scale_tbl_info *tbl, u8 scale_index,
- u8 ht_possible, struct iwl4965_rate *mcs_rate)
+ u8 ht_possible)
{
s32 low;
u16 rate_mask;
@@ -726,15 +745,14 @@
else
tbl->lq_type = LQ_G;
- if ((tbl->antenna_type == ANT_BOTH) ||
- (tbl->antenna_type == ANT_NONE))
- tbl->antenna_type = ANT_MAIN;
+ if (num_of_ant(tbl->ant_type) > 1)
+ tbl->ant_type = ANT_A;/*FIXME:RS*/
tbl->is_fat = 0;
tbl->is_SGI = 0;
}
- rs_get_supported_rates(lq_sta, NULL, tbl->lq_type, &rate_mask);
+ rate_mask = rs_get_supported_rates(lq_sta, NULL, tbl->lq_type);
/* Mask with station rate restriction */
if (is_legacy(tbl->lq_type)) {
@@ -748,25 +766,26 @@
/* If we switched from HT to legacy, check current rate */
if (switch_to_legacy && (rate_mask & (1 << scale_index))) {
- rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green);
- return;
+ low = scale_index;
+ goto out;
}
- high_low = rs_get_adjacent_rate(scale_index, rate_mask, tbl->lq_type);
+ high_low = rs_get_adjacent_rate(lq_sta->drv, scale_index, rate_mask,
+ tbl->lq_type);
low = high_low & 0xff;
- if (low != IWL_RATE_INVALID)
- rs_mcs_from_tbl(mcs_rate, tbl, low, is_green);
- else
- rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green);
+ if (low == IWL_RATE_INVALID)
+ low = scale_index;
+
+out:
+ return rate_n_flags_from_tbl(tbl, low, is_green);
}
/*
* mac80211 sends us Tx status
*/
static void rs_tx_status(void *priv_rate, struct net_device *dev,
- struct sk_buff *skb,
- struct ieee80211_tx_status *tx_resp)
+ struct sk_buff *skb)
{
int status;
u8 retries;
@@ -778,9 +797,10 @@
struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_hw *hw = local_to_hw(local);
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl4965_rate_scale_data *window = NULL;
struct iwl4965_rate_scale_data *search_win = NULL;
- struct iwl4965_rate tx_mcs;
+ u32 tx_rate;
struct iwl4965_scale_tbl_info tbl_type;
struct iwl4965_scale_tbl_info *curr_tbl, *search_tbl;
u8 active_index = 0;
@@ -793,11 +813,11 @@
return;
/* This packet was aggregated but doesn't carry rate scale info */
- if ((tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) &&
- !(tx_resp->flags & IEEE80211_TX_STATUS_AMPDU))
+ if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
+ !(info->flags & IEEE80211_TX_STAT_AMPDU))
return;
- retries = tx_resp->retry_count;
+ retries = info->status.retry_count;
if (retries > 15)
retries = 15;
@@ -822,15 +842,6 @@
table = &lq_sta->lq;
active_index = lq_sta->active_tbl;
- /* Get mac80211 antenna info */
- lq_sta->antenna =
- (lq_sta->valid_antenna & local->hw.conf.antenna_sel_tx);
- if (!lq_sta->antenna)
- lq_sta->antenna = lq_sta->valid_antenna;
-
- /* Ignore mac80211 antenna info for now */
- lq_sta->antenna = lq_sta->valid_antenna;
-
curr_tbl = &(lq_sta->lq_info[active_index]);
search_tbl = &(lq_sta->lq_info[(1 - active_index)]);
window = (struct iwl4965_rate_scale_data *)
@@ -846,28 +857,26 @@
* to check "search" mode, or a prior "search" mode after we've moved
* to a new "search" mode (which might become the new "active" mode).
*/
- tx_mcs.rate_n_flags = le32_to_cpu(table->rs_table[0].rate_n_flags);
- rs_get_tbl_info_from_mcs(&tx_mcs, priv->band, &tbl_type, &rs_index);
+ tx_rate = le32_to_cpu(table->rs_table[0].rate_n_flags);
+ rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index);
if (priv->band == IEEE80211_BAND_5GHZ)
rs_index -= IWL_FIRST_OFDM_RATE;
- if ((tx_resp->control.tx_rate == NULL) ||
+ if ((info->tx_rate_idx < 0) ||
(tbl_type.is_SGI ^
- !!(tx_resp->control.flags & IEEE80211_TXCTL_SHORT_GI)) ||
+ !!(info->flags & IEEE80211_TX_CTL_SHORT_GI)) ||
(tbl_type.is_fat ^
- !!(tx_resp->control.flags & IEEE80211_TXCTL_40_MHZ_WIDTH)) ||
+ !!(info->flags & IEEE80211_TX_CTL_40_MHZ_WIDTH)) ||
(tbl_type.is_dup ^
- !!(tx_resp->control.flags & IEEE80211_TXCTL_DUP_DATA)) ||
- (tbl_type.antenna_type ^
- tx_resp->control.antenna_sel_tx) ||
- (!!(tx_mcs.rate_n_flags & RATE_MCS_HT_MSK) ^
- !!(tx_resp->control.flags & IEEE80211_TXCTL_OFDM_HT)) ||
- (!!(tx_mcs.rate_n_flags & RATE_MCS_GF_MSK) ^
- !!(tx_resp->control.flags & IEEE80211_TXCTL_GREEN_FIELD)) ||
+ !!(info->flags & IEEE80211_TX_CTL_DUP_DATA)) ||
+ (tbl_type.ant_type ^ info->antenna_sel_tx) ||
+ (!!(tx_rate & RATE_MCS_HT_MSK) ^
+ !!(info->flags & IEEE80211_TX_CTL_OFDM_HT)) ||
+ (!!(tx_rate & RATE_MCS_GF_MSK) ^
+ !!(info->flags & IEEE80211_TX_CTL_GREEN_FIELD)) ||
(hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate !=
- tx_resp->control.tx_rate->bitrate)) {
- IWL_DEBUG_RATE("initial rate does not match 0x%x\n",
- tx_mcs.rate_n_flags);
+ hw->wiphy->bands[info->band]->bitrates[info->tx_rate_idx].bitrate)) {
+ IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate);
goto out;
}
@@ -875,15 +884,14 @@
while (retries) {
/* Look up the rate and other info used for each tx attempt.
* Each tx attempt steps one entry deeper in the rate table. */
- tx_mcs.rate_n_flags =
- le32_to_cpu(table->rs_table[index].rate_n_flags);
- rs_get_tbl_info_from_mcs(&tx_mcs, priv->band,
+ tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags);
+ rs_get_tbl_info_from_mcs(tx_rate, priv->band,
&tbl_type, &rs_index);
/* If type matches "search" table,
* add failure to "search" history */
if ((tbl_type.lq_type == search_tbl->lq_type) &&
- (tbl_type.antenna_type == search_tbl->antenna_type) &&
+ (tbl_type.ant_type == search_tbl->ant_type) &&
(tbl_type.is_SGI == search_tbl->is_SGI)) {
if (search_tbl->expected_tpt)
tpt = search_tbl->expected_tpt[rs_index];
@@ -894,7 +902,7 @@
/* Else if type matches "current/active" table,
* add failure to "current/active" history */
} else if ((tbl_type.lq_type == curr_tbl->lq_type) &&
- (tbl_type.antenna_type == curr_tbl->antenna_type) &&
+ (tbl_type.ant_type == curr_tbl->ant_type) &&
(tbl_type.is_SGI == curr_tbl->is_SGI)) {
if (curr_tbl->expected_tpt)
tpt = curr_tbl->expected_tpt[rs_index];
@@ -917,44 +925,41 @@
* if Tx was successful first try, use original rate,
* else look up the rate that was, finally, successful.
*/
- tx_mcs.rate_n_flags = le32_to_cpu(table->rs_table[index].rate_n_flags);
- rs_get_tbl_info_from_mcs(&tx_mcs, priv->band, &tbl_type, &rs_index);
+ tx_rate = le32_to_cpu(table->rs_table[index].rate_n_flags);
+ rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type, &rs_index);
/* Update frame history window with "success" if Tx got ACKed ... */
- if (tx_resp->flags & IEEE80211_TX_STATUS_ACK)
- status = 1;
- else
- status = 0;
+ status = !!(info->flags & IEEE80211_TX_STAT_ACK);
/* If type matches "search" table,
* add final tx status to "search" history */
if ((tbl_type.lq_type == search_tbl->lq_type) &&
- (tbl_type.antenna_type == search_tbl->antenna_type) &&
+ (tbl_type.ant_type == search_tbl->ant_type) &&
(tbl_type.is_SGI == search_tbl->is_SGI)) {
if (search_tbl->expected_tpt)
tpt = search_tbl->expected_tpt[rs_index];
else
tpt = 0;
- if (tx_resp->control.flags & IEEE80211_TXCTL_AMPDU)
+ if (info->flags & IEEE80211_TX_CTL_AMPDU)
rs_collect_tx_data(search_win, rs_index, tpt,
- tx_resp->ampdu_ack_len,
- tx_resp->ampdu_ack_map);
+ info->status.ampdu_ack_len,
+ info->status.ampdu_ack_map);
else
rs_collect_tx_data(search_win, rs_index, tpt,
1, status);
/* Else if type matches "current/active" table,
* add final tx status to "current/active" history */
} else if ((tbl_type.lq_type == curr_tbl->lq_type) &&
- (tbl_type.antenna_type == curr_tbl->antenna_type) &&
+ (tbl_type.ant_type == curr_tbl->ant_type) &&
(tbl_type.is_SGI == curr_tbl->is_SGI)) {
if (curr_tbl->expected_tpt)
tpt = curr_tbl->expected_tpt[rs_index];
else
tpt = 0;
- if (tx_resp->control.flags & IEEE80211_TXCTL_AMPDU)
+ if (info->flags & IEEE80211_TX_CTL_AMPDU)
rs_collect_tx_data(window, rs_index, tpt,
- tx_resp->ampdu_ack_len,
- tx_resp->ampdu_ack_map);
+ info->status.ampdu_ack_len,
+ info->status.ampdu_ack_map);
else
rs_collect_tx_data(window, rs_index, tpt,
1, status);
@@ -963,10 +968,10 @@
/* If not searching for new mode, increment success/failed counter
* ... these help determine when to start searching again */
if (lq_sta->stay_in_tbl) {
- if (tx_resp->control.flags & IEEE80211_TXCTL_AMPDU) {
- lq_sta->total_success += tx_resp->ampdu_ack_map;
+ if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+ lq_sta->total_success += info->status.ampdu_ack_map;
lq_sta->total_failed +=
- (tx_resp->ampdu_ack_len - tx_resp->ampdu_ack_map);
+ (info->status.ampdu_ack_len - info->status.ampdu_ack_map);
} else {
if (status)
lq_sta->total_success++;
@@ -982,30 +987,6 @@
return;
}
-static u8 rs_is_ant_connected(u8 valid_antenna,
- enum iwl4965_antenna_type antenna_type)
-{
- if (antenna_type == ANT_AUX)
- return ((valid_antenna & 0x2) ? 1:0);
- else if (antenna_type == ANT_MAIN)
- return ((valid_antenna & 0x1) ? 1:0);
- else if (antenna_type == ANT_BOTH)
- return ((valid_antenna & 0x3) == 0x3);
-
- return 1;
-}
-
-static u8 rs_is_other_ant_connected(u8 valid_antenna,
- enum iwl4965_antenna_type antenna_type)
-{
- if (antenna_type == ANT_AUX)
- return rs_is_ant_connected(valid_antenna, ANT_MAIN);
- else
- return rs_is_ant_connected(valid_antenna, ANT_AUX);
-
- return 0;
-}
-
/*
* Begin a period of staying with a selected modulation mode.
* Set "stay_in_tbl" flag to prevent any mode switches.
@@ -1014,10 +995,10 @@
* These control how long we stay using same modulation mode before
* searching for a new mode.
*/
-static void rs_set_stay_in_table(u8 is_legacy,
+static void rs_set_stay_in_table(struct iwl_priv *priv, u8 is_legacy,
struct iwl4965_lq_sta *lq_sta)
{
- IWL_DEBUG_HT("we are staying in the same table\n");
+ IWL_DEBUG_RATE("we are staying in the same table\n");
lq_sta->stay_in_tbl = 1; /* only place this gets set */
if (is_legacy) {
lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT;
@@ -1036,7 +1017,7 @@
/*
* Find correct throughput table for given mode of modulation
*/
-static void rs_get_expected_tpt_table(struct iwl4965_lq_sta *lq_sta,
+static void rs_set_expected_tpt_table(struct iwl4965_lq_sta *lq_sta,
struct iwl4965_scale_tbl_info *tbl)
{
if (is_legacy(tbl->lq_type)) {
@@ -1055,7 +1036,7 @@
else
tbl->expected_tpt = expected_tpt_siso20MHz;
- } else if (is_mimo(tbl->lq_type)) {
+ } else if (is_mimo(tbl->lq_type)) { /* FIXME:need to separate mimo2/3 */
if (tbl->is_fat && !lq_sta->is_dup)
if (tbl->is_SGI)
tbl->expected_tpt = expected_tpt_mimo40MHzSGI;
@@ -1085,7 +1066,7 @@
static s32 rs_get_best_rate(struct iwl_priv *priv,
struct iwl4965_lq_sta *lq_sta,
struct iwl4965_scale_tbl_info *tbl, /* "search" */
- u16 rate_mask, s8 index, s8 rate)
+ u16 rate_mask, s8 index)
{
/* "active" values */
struct iwl4965_scale_tbl_info *active_tbl =
@@ -1098,11 +1079,13 @@
s32 new_rate, high, low, start_hi;
u16 high_low;
+ s8 rate = index;
new_rate = high = low = start_hi = IWL_RATE_INVALID;
for (; ;) {
- high_low = rs_get_adjacent_rate(rate, rate_mask, tbl->lq_type);
+ high_low = rs_get_adjacent_rate(priv, rate, rate_mask,
+ tbl->lq_type);
low = high_low & 0xff;
high = (high_low >> 8) & 0xff;
@@ -1171,21 +1154,16 @@
}
#endif /* CONFIG_IWL4965_HT */
-static inline u8 rs_is_both_ant_supp(u8 valid_antenna)
-{
- return (rs_is_ant_connected(valid_antenna, ANT_BOTH));
-}
-
/*
* Set up search table for MIMO
*/
-static int rs_switch_to_mimo(struct iwl_priv *priv,
+#ifdef CONFIG_IWL4965_HT
+static int rs_switch_to_mimo2(struct iwl_priv *priv,
struct iwl4965_lq_sta *lq_sta,
struct ieee80211_conf *conf,
struct sta_info *sta,
struct iwl4965_scale_tbl_info *tbl, int index)
{
-#ifdef CONFIG_IWL4965_HT
u16 rate_mask;
s32 rate;
s8 is_green = lq_sta->is_green;
@@ -1194,26 +1172,27 @@
!sta->ht_info.ht_supported)
return -1;
- IWL_DEBUG_HT("LQ: try to switch to MIMO\n");
- tbl->lq_type = LQ_MIMO;
- rs_get_supported_rates(lq_sta, NULL, tbl->lq_type,
- &rate_mask);
-
if (priv->current_ht_config.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC)
return -1;
/* Need both Tx chains/antennas to support MIMO */
- if (!rs_is_both_ant_supp(lq_sta->antenna))
+ if (priv->hw_params.tx_chains_num < 2)
return -1;
+ IWL_DEBUG_RATE("LQ: try to switch to MIMO2\n");
+
+ tbl->lq_type = LQ_MIMO2;
tbl->is_dup = lq_sta->is_dup;
tbl->action = 0;
+ rate_mask = lq_sta->active_mimo2_rate;
+
if (priv->current_ht_config.supported_chan_width
- == IWL_CHANNEL_WIDTH_40MHZ)
+ == IWL_CHANNEL_WIDTH_40MHZ)
tbl->is_fat = 1;
else
tbl->is_fat = 0;
+ /* FIXME: - don't toggle SGI here
if (tbl->is_fat) {
if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY)
tbl->is_SGI = 1;
@@ -1223,23 +1202,35 @@
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
@@ -1255,16 +1246,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)
@@ -1272,6 +1263,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;
@@ -1281,26 +1273,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 */
}
@@ -1313,7 +1305,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 =
@@ -1322,41 +1313,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;
+ }
+ break;
case IWL_LEGACY_SWITCH_SISO:
- IWL_DEBUG_HT("LQ: Legacy switch to SISO\n");
+ IWL_DEBUG_RATE("LQ: Legacy switch to SISO\n");
/* Set up search table to try SISO */
memcpy(search_tbl, tbl, sz);
- search_tbl->lq_type = LQ_SISO;
search_tbl->is_SGI = 0;
- search_tbl->is_fat = 0;
ret = rs_switch_to_siso(priv, lq_sta, conf, sta,
search_tbl, index);
if (!ret) {
@@ -1366,16 +1351,15 @@
}
break;
- case IWL_LEGACY_SWITCH_MIMO:
- IWL_DEBUG_HT("LQ: Legacy switch MIMO\n");
+ case IWL_LEGACY_SWITCH_MIMO2:
+ IWL_DEBUG_RATE("LQ: Legacy switch to MIMO2\n");
/* Set up search table to try MIMO */
memcpy(search_tbl, tbl, sz);
- search_tbl->lq_type = LQ_MIMO;
search_tbl->is_SGI = 0;
- search_tbl->is_fat = 0;
- search_tbl->antenna_type = ANT_BOTH;
- ret = rs_switch_to_mimo(priv, lq_sta, conf, sta,
+ search_tbl->ant_type = ANT_AB;/*FIXME:RS*/
+ /*FIXME:RS:need to check ant validity*/
+ ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta,
search_tbl, index);
if (!ret) {
lq_sta->search_better_tbl = 1;
@@ -1385,7 +1369,7 @@
break;
}
tbl->action++;
- if (tbl->action > IWL_LEGACY_SWITCH_MIMO)
+ if (tbl->action > IWL_LEGACY_SWITCH_MIMO2)
tbl->action = IWL_LEGACY_SWITCH_ANTENNA;
if (tbl->action == start_action)
@@ -1396,7 +1380,7 @@
out:
tbl->action++;
- if (tbl->action > IWL_LEGACY_SWITCH_MIMO)
+ if (tbl->action > IWL_LEGACY_SWITCH_MIMO2)
tbl->action = IWL_LEGACY_SWITCH_ANTENNA;
return 0;
@@ -1411,7 +1395,6 @@
struct sta_info *sta,
int index)
{
- int ret;
u8 is_green = lq_sta->is_green;
struct iwl4965_scale_tbl_info *tbl =
&(lq_sta->lq_info[lq_sta->active_tbl]);
@@ -1421,35 +1404,30 @@
u32 sz = (sizeof(struct iwl4965_scale_tbl_info) -
(sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT));
u8 start_action = tbl->action;
+ u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
+ int ret;
for (;;) {
lq_sta->action_counter++;
switch (tbl->action) {
case IWL_SISO_SWITCH_ANTENNA:
- IWL_DEBUG_HT("LQ: SISO SWITCH ANTENNA SISO\n");
- search_tbl->lq_type = LQ_NONE;
+ IWL_DEBUG_RATE("LQ: SISO toggle Antenna\n");
if (window->success_ratio >= IWL_RS_GOOD_RATIO)
break;
- if (!rs_is_other_ant_connected(lq_sta->antenna,
- tbl->antenna_type))
- break;
memcpy(search_tbl, tbl, sz);
- search_tbl->action = IWL_SISO_SWITCH_MIMO;
- rs_toggle_antenna(&(search_tbl->current_rate),
- search_tbl);
- lq_sta->search_better_tbl = 1;
-
- goto out;
-
- case IWL_SISO_SWITCH_MIMO:
- IWL_DEBUG_HT("LQ: SISO SWITCH TO MIMO FROM SISO\n");
+ if (rs_toggle_antenna(valid_tx_ant,
+ &search_tbl->current_rate, search_tbl)) {
+ lq_sta->search_better_tbl = 1;
+ goto out;
+ }
+ break;
+ case IWL_SISO_SWITCH_MIMO2:
+ IWL_DEBUG_RATE("LQ: SISO switch to MIMO2\n");
memcpy(search_tbl, tbl, sz);
- search_tbl->lq_type = LQ_MIMO;
search_tbl->is_SGI = 0;
- search_tbl->is_fat = 0;
- search_tbl->antenna_type = ANT_BOTH;
- ret = rs_switch_to_mimo(priv, lq_sta, conf, sta,
+ search_tbl->ant_type = ANT_AB; /*FIXME:RS*/
+ ret = rs_switch_to_mimo2(priv, lq_sta, conf, sta,
search_tbl, index);
if (!ret) {
lq_sta->search_better_tbl = 1;
@@ -1457,29 +1435,34 @@
}
break;
case IWL_SISO_SWITCH_GI:
- IWL_DEBUG_HT("LQ: SISO SWITCH TO GI\n");
+ if (!tbl->is_fat &&
+ !(priv->current_ht_config.sgf &
+ HT_SHORT_GI_20MHZ))
+ break;
+ if (tbl->is_fat &&
+ !(priv->current_ht_config.sgf &
+ HT_SHORT_GI_40MHZ))
+ break;
+
+ IWL_DEBUG_RATE("LQ: SISO toggle SGI/NGI\n");
memcpy(search_tbl, tbl, sz);
- search_tbl->action = 0;
- if (search_tbl->is_SGI)
- search_tbl->is_SGI = 0;
- else if (!is_green)
- search_tbl->is_SGI = 1;
- else
- break;
- lq_sta->search_better_tbl = 1;
- if ((tbl->lq_type == LQ_SISO) &&
- (tbl->is_SGI)) {
- 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++;
@@ -1507,7 +1490,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]);
@@ -1516,24 +1498,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);
@@ -1544,37 +1526,35 @@
break;
case IWL_MIMO_SWITCH_GI:
- IWL_DEBUG_HT("LQ: MIMO SWITCH TO GI\n");
+ if (!tbl->is_fat &&
+ !(priv->current_ht_config.sgf &
+ HT_SHORT_GI_20MHZ))
+ break;
+ if (tbl->is_fat &&
+ !(priv->current_ht_config.sgf &
+ HT_SHORT_GI_40MHZ))
+ break;
+
+ IWL_DEBUG_RATE("LQ: MIMO toggle SGI/NGI\n");
/* Set up new search table for MIMO */
memcpy(search_tbl, tbl, sz);
- search_tbl->lq_type = LQ_MIMO;
- search_tbl->antenna_type = ANT_BOTH;
- search_tbl->action = 0;
- if (search_tbl->is_SGI)
- search_tbl->is_SGI = 0;
- else
- search_tbl->is_SGI = 1;
- lq_sta->search_better_tbl = 1;
-
+ search_tbl->is_SGI = !tbl->is_SGI;
+ rs_set_expected_tpt_table(lq_sta, search_tbl);
/*
* If active table already uses the fastest possible
* modulation (dual stream with short guard interval),
* and it's working well, there's no need to look
* for a better type of modulation!
*/
- if ((tbl->lq_type == LQ_MIMO) &&
- (tbl->is_SGI)) {
+ if (tbl->is_SGI) {
s32 tpt = lq_sta->last_tpt / 100;
- if (((!tbl->is_fat) &&
- (tpt >= expected_tpt_mimo20MHz[index])) ||
- ((tbl->is_fat) &&
- (tpt >= expected_tpt_mimo40MHz[index])))
- lq_sta->search_better_tbl = 0;
+ if (tpt >= search_tbl->expected_tpt[index])
+ break;
}
- rs_get_expected_tpt_table(lq_sta, search_tbl);
- rs_mcs_from_tbl(&search_tbl->current_rate,
- search_tbl, index, is_green);
+ search_tbl->current_rate = rate_n_flags_from_tbl(
+ search_tbl, index, is_green);
+ lq_sta->search_better_tbl = 1;
goto out;
}
@@ -1608,7 +1588,9 @@
int i;
int active_tbl;
int flush_interval_passed = 0;
+ struct iwl_priv *priv;
+ priv = lq_sta->drv;
active_tbl = lq_sta->active_tbl;
tbl = &(lq_sta->lq_info[active_tbl]);
@@ -1623,9 +1605,6 @@
(unsigned long)(lq_sta->flush_timer +
IWL_RATE_SCALE_FLUSH_INTVL));
- /* For now, disable the elapsed time criterion */
- flush_interval_passed = 0;
-
/*
* Check if we should allow search for new modulation mode.
* If many frames have failed or succeeded, or we've used
@@ -1638,7 +1617,7 @@
(lq_sta->total_success > lq_sta->max_success_limit) ||
((!lq_sta->search_better_tbl) && (lq_sta->flush_timer)
&& (flush_interval_passed))) {
- IWL_DEBUG_HT("LQ: stay is expired %d %d %d\n:",
+ IWL_DEBUG_RATE("LQ: stay is expired %d %d %d\n:",
lq_sta->total_failed,
lq_sta->total_success,
flush_interval_passed);
@@ -1661,7 +1640,7 @@
lq_sta->table_count_limit) {
lq_sta->table_count = 0;
- IWL_DEBUG_HT("LQ: stay in table clear win\n");
+ IWL_DEBUG_RATE("LQ: stay in table clear win\n");
for (i = 0; i < IWL_RATE_COUNT; i++)
rs_rate_scale_clear_window(
&(tbl->win[i]));
@@ -1704,14 +1683,14 @@
struct iwl4965_lq_sta *lq_sta;
struct iwl4965_scale_tbl_info *tbl, *tbl1;
u16 rate_scale_index_msk = 0;
- struct iwl4965_rate mcs_rate;
+ u32 rate;
u8 is_green = 0;
u8 active_tbl = 0;
u8 done_search = 0;
u16 high_low;
+ s32 sr;
#ifdef CONFIG_IWL4965_HT
u8 tid = MAX_TID_COUNT;
- __le16 *qc;
#endif
IWL_DEBUG_RATE("rate scale calculate new rate for skb\n");
@@ -1734,11 +1713,7 @@
lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv;
#ifdef CONFIG_IWL4965_HT
- qc = ieee80211_get_qos_ctrl(hdr);
- if (qc) {
- tid = (u8)(le16_to_cpu(*qc) & 0xf);
- rs_tl_add_packet(lq_sta, tid);
- }
+ rs_tl_add_packet(lq_sta, hdr);
#endif
/*
* Select rate-scale / modulation-mode table to work with in
@@ -1760,8 +1735,7 @@
tbl->lq_type);
/* rates available for this association, and for modulation mode */
- rs_get_supported_rates(lq_sta, hdr, tbl->lq_type,
- &rate_mask);
+ rate_mask = rs_get_supported_rates(lq_sta, hdr, tbl->lq_type);
IWL_DEBUG_RATE("mask 0x%04X \n", rate_mask);
@@ -1781,27 +1755,16 @@
if (!rate_scale_index_msk)
rate_scale_index_msk = rate_mask;
- /* If current rate is no longer supported on current association,
- * or user changed preferences for rates, find a new supported rate. */
- if (index < 0 || !((1 << index) & rate_scale_index_msk)) {
- index = IWL_INVALID_VALUE;
- update_lq = 1;
-
- /* get the highest available rate */
- for (i = 0; i <= IWL_RATE_COUNT; i++) {
- if ((1 << i) & rate_scale_index_msk)
- index = i;
- }
-
- if (index == IWL_INVALID_VALUE) {
- IWL_WARNING("Can not find a suitable rate\n");
- return;
- }
+ if (!((1 << index) & rate_scale_index_msk)) {
+ IWL_ERROR("Current Rate is not valid\n");
+ return;
}
/* Get expected throughput table and history window for current rate */
- if (!tbl->expected_tpt)
- rs_get_expected_tpt_table(lq_sta, tbl);
+ if (!tbl->expected_tpt) {
+ IWL_ERROR("tbl->expected_tpt is NULL\n");
+ return;
+ }
window = &(tbl->win[index]);
@@ -1813,10 +1776,9 @@
* in current association (use new rate found above).
*/
fail_count = window->counter - window->success_counter;
- if (((fail_count < IWL_RATE_MIN_FAILURE_TH) &&
- (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))
- || (tbl->expected_tpt == NULL)) {
- IWL_DEBUG_RATE("LQ: still below TH succ %d total %d "
+ if ((fail_count < IWL_RATE_MIN_FAILURE_TH) &&
+ (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) {
+ IWL_DEBUG_RATE("LQ: still below TH. succ=%d total=%d "
"for index %d\n",
window->success_counter, window->counter, index);
@@ -1827,44 +1789,51 @@
* or search for a new one? */
rs_stay_in_table(lq_sta);
- /* Set up new rate table in uCode, if needed */
- if (update_lq) {
- rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green);
- rs_fill_link_cmd(lq_sta, &mcs_rate, &lq_sta->lq);
- iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
- }
goto out;
/* Else we have enough samples; calculate estimate of
* actual average throughput */
- } else
- window->average_tpt = ((window->success_ratio *
+ } else {
+ /*FIXME:RS remove this else if we don't get this error*/
+ if (window->average_tpt != ((window->success_ratio *
+ tbl->expected_tpt[index] + 64) / 128)) {
+ IWL_ERROR("expected_tpt should have been calculated"
+ " by now\n");
+ window->average_tpt = ((window->success_ratio *
tbl->expected_tpt[index] + 64) / 128);
+ }
+ }
/* If we are searching for better modulation mode, check success. */
if (lq_sta->search_better_tbl) {
- int success_limit = IWL_RATE_SCALE_SWITCH;
/* If good success, continue using the "search" mode;
* no need to send new link quality command, since we're
* continuing to use the setup that we've been trying. */
- if ((window->success_ratio > success_limit) ||
- (window->average_tpt > lq_sta->last_tpt)) {
- if (!is_legacy(tbl->lq_type)) {
- IWL_DEBUG_HT("LQ: we are switching to HT"
- " rate suc %d current tpt %d"
- " old tpt %d\n",
- window->success_ratio,
- window->average_tpt,
- lq_sta->last_tpt);
+ if (window->average_tpt > lq_sta->last_tpt) {
+
+ IWL_DEBUG_RATE("LQ: SWITCHING TO CURRENT TABLE "
+ "suc=%d cur-tpt=%d old-tpt=%d\n",
+ window->success_ratio,
+ window->average_tpt,
+ lq_sta->last_tpt);
+
+ if (!is_legacy(tbl->lq_type))
lq_sta->enable_counter = 1;
- }
+
/* Swap tables; "search" becomes "active" */
lq_sta->active_tbl = active_tbl;
current_tpt = window->average_tpt;
/* Else poor success; go back to mode in "active" table */
} else {
+
+ IWL_DEBUG_RATE("LQ: GOING BACK TO THE OLD TABLE "
+ "suc=%d cur-tpt=%d old-tpt=%d\n",
+ window->success_ratio,
+ window->average_tpt,
+ lq_sta->last_tpt);
+
/* Nullify "search" table */
tbl->lq_type = LQ_NONE;
@@ -1874,12 +1843,11 @@
/* Revert to "active" rate and throughput info */
index = iwl4965_hwrate_to_plcp_idx(
- tbl->current_rate.rate_n_flags);
+ tbl->current_rate);
current_tpt = lq_sta->last_tpt;
/* Need to set up a new rate table in uCode */
update_lq = 1;
- IWL_DEBUG_HT("XXY GO BACK TO OLD TABLE\n");
}
/* Either way, we've made a decision; modulation mode
@@ -1891,11 +1859,13 @@
/* (Else) not in search of better modulation mode, try for better
* starting rate, while staying in this mode. */
- high_low = rs_get_adjacent_rate(index, rate_scale_index_msk,
+ high_low = rs_get_adjacent_rate(priv, index, rate_scale_index_msk,
tbl->lq_type);
low = high_low & 0xff;
high = (high_low >> 8) & 0xff;
+ sr = window->success_ratio;
+
/* Collect measured throughputs for current and adjacent rates */
current_tpt = window->average_tpt;
if (low != IWL_RATE_INVALID)
@@ -1903,19 +1873,22 @@
if (high != IWL_RATE_INVALID)
high_tpt = tbl->win[high].average_tpt;
- /* Assume rate increase */
- scale_action = 1;
+ scale_action = 0;
/* Too many failures, decrease rate */
- if ((window->success_ratio <= IWL_RATE_DECREASE_TH) ||
- (current_tpt == 0)) {
+ if ((sr <= IWL_RATE_DECREASE_TH) || (current_tpt == 0)) {
IWL_DEBUG_RATE("decrease rate because of low success_ratio\n");
scale_action = -1;
/* No throughput measured yet for adjacent rates; try increase. */
} else if ((low_tpt == IWL_INVALID_VALUE) &&
- (high_tpt == IWL_INVALID_VALUE))
- scale_action = 1;
+ (high_tpt == IWL_INVALID_VALUE)) {
+
+ if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH)
+ scale_action = 1;
+ else if (low != IWL_RATE_INVALID)
+ scale_action = -1;
+ }
/* Both adjacent throughputs are measured, but neither one has better
* throughput; we're using the best rate, don't change it! */
@@ -1931,9 +1904,10 @@
/* Higher adjacent rate's throughput is measured */
if (high_tpt != IWL_INVALID_VALUE) {
/* Higher rate has better throughput */
- if (high_tpt > current_tpt)
+ if (high_tpt > current_tpt &&
+ sr >= IWL_RATE_INCREASE_TH) {
scale_action = 1;
- else {
+ } else {
IWL_DEBUG_RATE
("decrease rate because of high tpt\n");
scale_action = -1;
@@ -1946,23 +1920,17 @@
IWL_DEBUG_RATE
("decrease rate because of low tpt\n");
scale_action = -1;
- } else
+ } else if (sr >= IWL_RATE_INCREASE_TH) {
scale_action = 1;
+ }
}
}
/* Sanity check; asked for decrease, but success rate or throughput
* has been good at old rate. Don't change it. */
- if (scale_action == -1) {
- if ((low != IWL_RATE_INVALID) &&
- ((window->success_ratio > IWL_RATE_HIGH_TH) ||
+ if ((scale_action == -1) && (low != IWL_RATE_INVALID) &&
+ ((sr > IWL_RATE_HIGH_TH) ||
(current_tpt > (100 * tbl->expected_tpt[low]))))
- scale_action = 0;
-
- /* Sanity check; asked for increase, but success rate has not been great
- * even at old rate, higher rate will be worse. Don't change it. */
- } else if ((scale_action == 1) &&
- (window->success_ratio < IWL_RATE_INCREASE_TH))
scale_action = 0;
switch (scale_action) {
@@ -1987,15 +1955,15 @@
break;
}
- IWL_DEBUG_HT("choose rate scale index %d action %d low %d "
+ IWL_DEBUG_RATE("choose rate scale index %d action %d low %d "
"high %d type %d\n",
index, scale_action, low, high, tbl->lq_type);
- lq_update:
+lq_update:
/* Replace uCode's rate table for the destination station. */
if (update_lq) {
- rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green);
- rs_fill_link_cmd(lq_sta, &mcs_rate, &lq_sta->lq);
+ rate = rate_n_flags_from_tbl(tbl, index, is_green);
+ rs_fill_link_cmd(priv, lq_sta, rate);
iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
}
@@ -2030,12 +1998,11 @@
/* Use new "search" start rate */
index = iwl4965_hwrate_to_plcp_idx(
- tbl->current_rate.rate_n_flags);
+ tbl->current_rate);
- IWL_DEBUG_HT("Switch current mcs: %X index: %d\n",
- tbl->current_rate.rate_n_flags, index);
- rs_fill_link_cmd(lq_sta, &tbl->current_rate,
- &lq_sta->lq);
+ IWL_DEBUG_RATE("Switch current mcs: %X index: %d\n",
+ tbl->current_rate, index);
+ rs_fill_link_cmd(priv, lq_sta, tbl->current_rate);
iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
}
@@ -2051,8 +2018,8 @@
#endif
(lq_sta->action_counter >= 1)) {
lq_sta->action_counter = 0;
- IWL_DEBUG_HT("LQ: STAY in legacy table\n");
- rs_set_stay_in_table(1, lq_sta);
+ IWL_DEBUG_RATE("LQ: STAY in legacy table\n");
+ rs_set_stay_in_table(priv, 1, lq_sta);
}
/* If we're in an HT mode, and all 3 mode switch actions
@@ -2064,12 +2031,12 @@
if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) &&
(lq_sta->tx_agg_tid_en & (1 << tid)) &&
(tid != MAX_TID_COUNT)) {
- IWL_DEBUG_HT("try to aggregate tid %d\n", tid);
+ IWL_DEBUG_RATE("try to aggregate tid %d\n", tid);
rs_tl_turn_on_agg(priv, tid, lq_sta, sta);
}
#endif /*CONFIG_IWL4965_HT */
lq_sta->action_counter = 0;
- rs_set_stay_in_table(0, lq_sta);
+ rs_set_stay_in_table(priv, 0, lq_sta);
}
/*
@@ -2085,7 +2052,7 @@
}
out:
- rs_mcs_from_tbl(&tbl->current_rate, tbl, index, is_green);
+ tbl->current_rate = rate_n_flags_from_tbl(tbl, index, is_green);
i = index;
sta->last_txrate_idx = i;
@@ -2105,13 +2072,14 @@
struct ieee80211_conf *conf,
struct sta_info *sta)
{
- int i;
struct iwl4965_lq_sta *lq_sta;
struct iwl4965_scale_tbl_info *tbl;
- u8 active_tbl = 0;
int rate_idx;
+ int i;
+ u32 rate;
u8 use_green = rs_use_green(priv, conf);
- struct iwl4965_rate mcs_rate;
+ u8 active_tbl = 0;
+ u8 valid_tx_ant;
if (!sta || !sta->rate_ctrl_priv)
goto out;
@@ -2123,6 +2091,8 @@
(priv->iw_mode == IEEE80211_IF_TYPE_IBSS))
goto out;
+ valid_tx_ant = priv->hw_params.valid_tx_ant;
+
if (!lq_sta->search_better_tbl)
active_tbl = lq_sta->active_tbl;
else
@@ -2133,22 +2103,23 @@
if ((i < 0) || (i >= IWL_RATE_COUNT))
i = 0;
- mcs_rate.rate_n_flags = iwl4965_rates[i].plcp ;
- mcs_rate.rate_n_flags |= RATE_MCS_ANT_B_MSK;
- mcs_rate.rate_n_flags &= ~RATE_MCS_ANT_A_MSK;
+ /* FIXME:RS: This is also wrong in 4965 */
+ rate = iwl_rates[i].plcp;
+ rate |= RATE_MCS_ANT_B_MSK;
+ rate &= ~RATE_MCS_ANT_A_MSK;
if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE)
- mcs_rate.rate_n_flags |= RATE_MCS_CCK_MSK;
+ rate |= RATE_MCS_CCK_MSK;
- tbl->antenna_type = ANT_AUX;
- rs_get_tbl_info_from_mcs(&mcs_rate, priv->band, tbl, &rate_idx);
- if (!rs_is_ant_connected(priv->valid_antenna, tbl->antenna_type))
- rs_toggle_antenna(&mcs_rate, tbl);
+ tbl->ant_type = ANT_B;
+ rs_get_tbl_info_from_mcs(rate, priv->band, tbl, &rate_idx);
+ if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type))
+ rs_toggle_antenna(valid_tx_ant, &rate, tbl);
- rs_mcs_from_tbl(&mcs_rate, tbl, rate_idx, use_green);
- tbl->current_rate.rate_n_flags = mcs_rate.rate_n_flags;
- rs_get_expected_tpt_table(lq_sta, tbl);
- rs_fill_link_cmd(lq_sta, &mcs_rate, &lq_sta->lq);
+ rate = rate_n_flags_from_tbl(tbl, rate_idx, use_green);
+ tbl->current_rate = rate;
+ rs_set_expected_tpt_table(lq_sta, tbl);
+ rs_fill_link_cmd(NULL, lq_sta, rate);
iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
out:
return;
@@ -2180,7 +2151,7 @@
fc = le16_to_cpu(hdr->frame_control);
if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) ||
!sta || !sta->rate_ctrl_priv) {
- sel->rate = rate_lowest(local, sband, sta);
+ sel->rate_idx = rate_lowest_index(local, sband, sta);
goto out;
}
@@ -2189,13 +2160,13 @@
if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
!lq_sta->ibss_sta_added) {
- u8 sta_id = iwl4965_hw_find_station(priv, hdr->addr1);
+ u8 sta_id = iwl_find_station(priv, hdr->addr1);
DECLARE_MAC_BUF(mac);
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_RATE("LQ: ADD station %s\n",
print_mac(mac, hdr->addr1));
- sta_id = iwl4965_add_station_flags(priv, hdr->addr1,
+ sta_id = iwl_add_station_flags(priv, hdr->addr1,
0, CMD_ASYNC, NULL);
}
if ((sta_id != IWL_INVALID_STATION)) {
@@ -2210,20 +2181,24 @@
done:
if ((i < 0) || (i > IWL_RATE_COUNT)) {
- sel->rate = rate_lowest(local, sband, sta);
+ sel->rate_idx = rate_lowest_index(local, sband, sta);
goto out;
}
- sel->rate = &priv->ieee_rates[i];
+ if (sband->band == IEEE80211_BAND_5GHZ)
+ i -= IWL_FIRST_OFDM_RATE;
+ sel->rate_idx = i;
out:
rcu_read_unlock();
}
-static void *rs_alloc_sta(void *priv, gfp_t gfp)
+static void *rs_alloc_sta(void *priv_rate, gfp_t gfp)
{
struct iwl4965_lq_sta *lq_sta;
+ struct iwl_priv *priv;
int i, j;
+ priv = (struct iwl_priv *)priv_rate;
IWL_DEBUG_RATE("create station rate scale window\n");
lq_sta = kzalloc(sizeof(struct iwl4965_lq_sta), gfp);
@@ -2259,7 +2234,7 @@
for (i = 0; i < IWL_RATE_COUNT; i++)
rs_rate_scale_clear_window(&(lq_sta->lq_info[j].win[i]));
- IWL_DEBUG_RATE("rate scale global init\n");
+ IWL_DEBUG_RATE("LQ: *** rate scale global init ***\n");
/* TODO: what is a good starting rate for STA? About middle? Maybe not
* the lowest or the highest rate.. Could consider using RSSI from
* previous packets? Need to have IEEE 802.1X auth succeed immediately
@@ -2267,17 +2242,17 @@
lq_sta->ibss_sta_added = 0;
if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
- u8 sta_id = iwl4965_hw_find_station(priv, sta->addr);
+ u8 sta_id = iwl_find_station(priv, sta->addr);
DECLARE_MAC_BUF(mac);
/* for IBSS the call are from tasklet */
- IWL_DEBUG_HT("LQ: ADD station %s\n",
+ IWL_DEBUG_RATE("LQ: ADD station %s\n",
print_mac(mac, sta->addr));
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_RATE("LQ: ADD station %s\n",
print_mac(mac, sta->addr));
- sta_id = iwl4965_add_station_flags(priv, sta->addr,
+ sta_id = iwl_add_station_flags(priv, sta->addr,
0, CMD_ASYNC, NULL);
}
if ((sta_id != IWL_INVALID_STATION)) {
@@ -2300,11 +2275,8 @@
sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
lq_sta->is_dup = 0;
- lq_sta->valid_antenna = priv->valid_antenna;
- lq_sta->antenna = priv->antenna;
lq_sta->is_green = rs_use_green(priv, conf);
- lq_sta->active_rate = priv->active_rate;
- lq_sta->active_rate &= ~(0x1000);
+ lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000);
lq_sta->active_rate_basic = priv->active_rate_basic;
lq_sta->band = priv->band;
#ifdef CONFIG_IWL4965_HT
@@ -2312,23 +2284,37 @@
* 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*/
@@ -2342,50 +2328,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.
@@ -2393,26 +2384,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.
@@ -2422,20 +2412,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. */
@@ -2445,14 +2437,13 @@
rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
/* Fill next table entry */
- lq_cmd->rs_table[index].rate_n_flags =
- cpu_to_le32(new_rate.rate_n_flags);
+ lq_cmd->rs_table[index].rate_n_flags = cpu_to_le32(new_rate);
index++;
repeat_rate--;
}
- lq_cmd->general_params.dual_stream_ant_msk = 3;
+ lq_cmd->agg_params.agg_frame_cnt_limit = 64;
lq_cmd->agg_params.agg_dis_start_th = 3;
lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000);
}
@@ -2478,10 +2469,12 @@
IWL_DEBUG_RATE("leave\n");
}
-static void rs_free_sta(void *priv, void *priv_sta)
+static void rs_free_sta(void *priv_rate, void *priv_sta)
{
struct iwl4965_lq_sta *lq_sta = priv_sta;
+ struct iwl_priv *priv;
+ priv = (struct iwl_priv *)priv_rate;
IWL_DEBUG_RATE("enter\n");
kfree(lq_sta);
IWL_DEBUG_RATE("leave\n");
@@ -2495,54 +2488,56 @@
return 0;
}
static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta,
- struct iwl4965_rate *mcs, int index)
+ u32 *rate_n_flags, int index)
{
- u32 base_rate;
+ struct iwl_priv *priv;
- if (lq_sta->band == IEEE80211_BAND_5GHZ)
- base_rate = 0x800D;
- else
- base_rate = 0x820A;
-
- if (lq_sta->dbg_fixed.rate_n_flags) {
- if (index < 12)
- mcs->rate_n_flags = lq_sta->dbg_fixed.rate_n_flags;
- else
- mcs->rate_n_flags = base_rate;
+ priv = lq_sta->drv;
+ if (lq_sta->dbg_fixed_rate) {
+ if (index < 12) {
+ *rate_n_flags = lq_sta->dbg_fixed_rate;
+ } else {
+ if (lq_sta->band == IEEE80211_BAND_5GHZ)
+ *rate_n_flags = 0x800D;
+ else
+ *rate_n_flags = 0x820A;
+ }
IWL_DEBUG_RATE("Fixed rate ON\n");
- return;
+ } else {
+ IWL_DEBUG_RATE("Fixed rate OFF\n");
}
-
- IWL_DEBUG_RATE("Fixed rate OFF\n");
}
static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
const char __user *user_buf, size_t count, loff_t *ppos)
{
struct iwl4965_lq_sta *lq_sta = file->private_data;
+ struct iwl_priv *priv;
char buf[64];
int buf_size;
u32 parsed_rate;
+ priv = lq_sta->drv;
memset(buf, 0, sizeof(buf));
buf_size = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT;
if (sscanf(buf, "%x", &parsed_rate) == 1)
- lq_sta->dbg_fixed.rate_n_flags = parsed_rate;
+ lq_sta->dbg_fixed_rate = parsed_rate;
else
- lq_sta->dbg_fixed.rate_n_flags = 0;
+ lq_sta->dbg_fixed_rate = 0;
- lq_sta->active_rate = 0x0FFF; /* 1 - 54 MBits, includes CCK */
- lq_sta->active_siso_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */
- lq_sta->active_mimo_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */
+ lq_sta->active_legacy_rate = 0x0FFF; /* 1 - 54 MBits, includes CCK */
+ lq_sta->active_siso_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */
+ lq_sta->active_mimo2_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */
+ lq_sta->active_mimo3_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */
IWL_DEBUG_RATE("sta_id %d rate 0x%X\n",
- lq_sta->lq.sta_id, lq_sta->dbg_fixed.rate_n_flags);
+ lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate);
- if (lq_sta->dbg_fixed.rate_n_flags) {
- rs_fill_link_cmd(lq_sta, &lq_sta->dbg_fixed, &lq_sta->lq);
+ if (lq_sta->dbg_fixed_rate) {
+ rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate);
iwl_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC);
}
@@ -2561,9 +2556,9 @@
desc += sprintf(buff+desc, "sta_id %d\n", lq_sta->lq.sta_id);
desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n",
lq_sta->total_failed, lq_sta->total_success,
- lq_sta->active_rate);
+ lq_sta->active_legacy_rate);
desc += sprintf(buff+desc, "fixed rate 0x%X\n",
- lq_sta->dbg_fixed.rate_n_flags);
+ lq_sta->dbg_fixed_rate);
desc += sprintf(buff+desc, "general:"
"flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n",
lq_sta->lq.general_params.flags,
@@ -2613,7 +2608,7 @@
lq_sta->lq_info[i].is_SGI,
lq_sta->lq_info[i].is_fat,
lq_sta->lq_info[i].is_dup,
- lq_sta->lq_info[i].current_rate.rate_n_flags);
+ lq_sta->lq_info[i].current_rate);
for (j = 0; j < IWL_RATE_COUNT; j++) {
desc += sprintf(buff+desc,
"counter=%d success=%d %%=%d\n",
@@ -2703,7 +2698,7 @@
lq_sta = (void *)sta->rate_ctrl_priv;
lq_type = lq_sta->lq_info[lq_sta->active_tbl].lq_type;
- antenna = lq_sta->lq_info[lq_sta->active_tbl].antenna_type;
+ antenna = lq_sta->lq_info[lq_sta->active_tbl].ant_type;
if (is_legacy(lq_type))
i = IWL_RATE_54M_INDEX;
@@ -2715,7 +2710,7 @@
int active = lq_sta->active_tbl;
cnt +=
- sprintf(&buf[cnt], " %2dMbs: ", iwl4965_rates[i].ieee / 2);
+ sprintf(&buf[cnt], " %2dMbs: ", iwl_rates[i].ieee / 2);
mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1));
for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1)
@@ -2726,7 +2721,7 @@
samples += lq_sta->lq_info[active].win[i].counter;
good += lq_sta->lq_info[active].win[i].success_counter;
success += lq_sta->lq_info[active].win[i].success_counter *
- iwl4965_rates[i].ieee;
+ iwl_rates[i].ieee;
if (lq_sta->lq_info[active].win[i].stamp) {
int delta =
@@ -2746,10 +2741,11 @@
i = j;
}
- /* Display the average rate of all samples taken.
- *
- * NOTE: We multiply # of samples by 2 since the IEEE measurement
- * added from iwl4965_rates is actually 2X the rate */
+ /*
+ * Display the average rate of all samples taken.
+ * NOTE: We multiply # of samples by 2 since the IEEE measurement
+ * added from iwl_rates is actually 2X the rate.
+ */
if (samples)
cnt += sprintf(&buf[cnt],
"\nAverage rate is %3d.%02dMbs over last %4dms\n"
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h
index 866e378..1dd4124 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 {
+struct iwl_rate_info {
u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */
u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */
- u8 plcp_mimo; /* uCode API: IWL_RATE_MIMO_6M_PLCP, etc. */
+ u8 plcp_mimo2; /* uCode API: IWL_RATE_MIMO2_6M_PLCP, etc. */
+ u8 plcp_mimo3; /* uCode API: IWL_RATE_MIMO3_6M_PLCP, etc. */
u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */
u8 prev_ieee; /* previous rate in IEEE speeds */
u8 next_ieee; /* next rate in IEEE speeds */
@@ -44,7 +45,7 @@
/*
* These serve as indexes into
- * struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT];
+ * struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
*/
enum {
IWL_RATE_1M_INDEX = 0,
@@ -60,9 +61,9 @@
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" */
@@ -224,35 +240,46 @@
#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING)
#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y))
-extern const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT];
+extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
-enum iwl4965_table_type {
+enum iwl_table_type {
LQ_NONE,
LQ_G, /* legacy types */
LQ_A,
LQ_SISO, /* high-throughput types */
- LQ_MIMO,
+ LQ_MIMO2,
+ LQ_MIMO3,
LQ_MAX,
};
#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A))
-#define is_siso(tbl) (((tbl) == LQ_SISO))
-#define is_mimo(tbl) (((tbl) == LQ_MIMO))
+#define is_siso(tbl) ((tbl) == LQ_SISO)
+#define is_mimo2(tbl) ((tbl) == LQ_MIMO2)
+#define is_mimo3(tbl) ((tbl) == LQ_MIMO3)
+#define is_mimo(tbl) (is_mimo2(tbl) || is_mimo3(tbl))
#define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl))
-#define is_a_band(tbl) (((tbl) == LQ_A))
-#define is_g_and(tbl) (((tbl) == LQ_G))
+#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)
{
- u8 rate = iwl4965_rates[rate_index].prev_ieee;
+ u8 rate = iwl_rates[rate_index].prev_ieee;
if (rate == IWL_RATE_INVALID)
rate = rate_index;
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index bf19eb8..aee7014 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -39,81 +39,22 @@
#include <asm/unaligned.h>
#include "iwl-eeprom.h"
-#include "iwl-4965.h"
+#include "iwl-dev.h"
#include "iwl-core.h"
#include "iwl-io.h"
#include "iwl-helpers.h"
+#include "iwl-calib.h"
+#include "iwl-sta.h"
/* module parameters */
static struct iwl_mod_params iwl4965_mod_params = {
- .num_of_queues = IWL4965_MAX_NUM_QUEUES,
+ .num_of_queues = IWL49_NUM_QUEUES,
.enable_qos = 1,
.amsdu_size_8K = 1,
+ .restart_fw = 1,
/* the rest are 0 by default */
};
-static void iwl4965_hw_card_show_info(struct iwl_priv *priv);
-
-#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \
- [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \
- IWL_RATE_SISO_##s##M_PLCP, \
- IWL_RATE_MIMO_##s##M_PLCP, \
- IWL_RATE_##r##M_IEEE, \
- IWL_RATE_##ip##M_INDEX, \
- IWL_RATE_##in##M_INDEX, \
- IWL_RATE_##rp##M_INDEX, \
- IWL_RATE_##rn##M_INDEX, \
- IWL_RATE_##pp##M_INDEX, \
- IWL_RATE_##np##M_INDEX }
-
-/*
- * Parameter order:
- * rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate
- *
- * If there isn't a valid next or previous rate then INV is used which
- * maps to IWL_RATE_INVALID
- *
- */
-const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT] = {
- IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2), /* 1mbps */
- IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5), /* 2mbps */
- IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11), /*5.5mbps */
- IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18), /* 11mbps */
- IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11), /* 6mbps */
- IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11), /* 9mbps */
- IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18), /* 12mbps */
- IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24), /* 18mbps */
- IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36), /* 24mbps */
- IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48), /* 36mbps */
- IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54), /* 48mbps */
- IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */
- IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */
-};
-
-#ifdef CONFIG_IWL4965_HT
-
-static const u16 default_tid_to_tx_fifo[] = {
- IWL_TX_FIFO_AC1,
- IWL_TX_FIFO_AC0,
- IWL_TX_FIFO_AC0,
- IWL_TX_FIFO_AC1,
- IWL_TX_FIFO_AC2,
- IWL_TX_FIFO_AC2,
- IWL_TX_FIFO_AC3,
- IWL_TX_FIFO_AC3,
- IWL_TX_FIFO_NONE,
- IWL_TX_FIFO_NONE,
- IWL_TX_FIFO_NONE,
- IWL_TX_FIFO_NONE,
- IWL_TX_FIFO_NONE,
- IWL_TX_FIFO_NONE,
- IWL_TX_FIFO_NONE,
- IWL_TX_FIFO_NONE,
- IWL_TX_FIFO_AC3
-};
-
-#endif /*CONFIG_IWL4965_HT */
-
/* check contents of special bootstrap uCode SRAM */
static int iwl4965_verify_bsm(struct iwl_priv *priv)
{
@@ -192,15 +133,18 @@
IWL_DEBUG_INFO("Begin load bsm\n");
+ priv->ucode_type = UCODE_RT;
+
/* make sure bootstrap program is no larger than BSM's SRAM size */
if (len > IWL_MAX_BSM_SIZE)
return -EINVAL;
/* Tell bootstrap uCode where to find the "Initialize" uCode
* in host DRAM ... host DRAM physical address bits 35:4 for 4965.
- * NOTE: iwl4965_initialize_alive_start() will replace these values,
+ * NOTE: iwl_init_alive_start() will replace these values,
* after the "initialize" uCode has run, to point to
- * runtime/protocol instructions and backup data cache. */
+ * runtime/protocol instructions and backup data cache.
+ */
pinst = priv->ucode_init.p_addr >> 4;
pdata = priv->ucode_init_data.p_addr >> 4;
inst_len = priv->ucode_init.len;
@@ -259,120 +203,108 @@
return 0;
}
-static int iwl4965_init_drv(struct iwl_priv *priv)
+/**
+ * iwl4965_set_ucode_ptrs - Set uCode address location
+ *
+ * Tell initialization uCode where to find runtime uCode.
+ *
+ * BSM registers initially contain pointers to initialization uCode.
+ * We need to replace them to load runtime uCode inst and data,
+ * and to save runtime data when powering down.
+ */
+static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv)
{
- int ret;
- int i;
+ dma_addr_t pinst;
+ dma_addr_t pdata;
+ unsigned long flags;
+ int ret = 0;
- priv->antenna = (enum iwl4965_antenna)priv->cfg->mod_params->antenna;
- priv->retry_rate = 1;
- priv->ibss_beacon = NULL;
+ /* bits 35:4 for 4965 */
+ pinst = priv->ucode_code.p_addr >> 4;
+ pdata = priv->ucode_data_backup.p_addr >> 4;
- 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);
+ spin_lock_irqsave(&priv->lock, flags);
+ ret = iwl_grab_nic_access(priv);
if (ret) {
- IWL_ERROR("initializing regulatory failed: %d\n", ret);
- goto err;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return ret;
}
- ret = iwl4965_init_geos(priv);
- if (ret) {
- IWL_ERROR("initializing geos failed: %d\n", ret);
- goto err_free_channel_map;
- }
+ /* Tell bootstrap uCode where to find image to load */
+ iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
+ iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
+ iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG,
+ priv->ucode_data.len);
- ret = ieee80211_register_hw(priv->hw);
- if (ret) {
- IWL_ERROR("Failed to register network device (error %d)\n",
- ret);
- goto err_free_geos;
- }
+ /* Inst bytecount must be last to set up, bit 31 signals uCode
+ * that all new ptr/size info is in place */
+ iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG,
+ priv->ucode_code.len | BSM_DRAM_INST_LOAD);
+ iwl_release_nic_access(priv);
- priv->hw->conf.beacon_int = 100;
- priv->mac80211_registered = 1;
+ spin_unlock_irqrestore(&priv->lock, flags);
- return 0;
+ IWL_DEBUG_INFO("Runtime uCode pointers are set.\n");
-err_free_geos:
- iwl4965_free_geos(priv);
-err_free_channel_map:
- iwl_free_channel_map(priv);
-err:
return ret;
}
+/**
+ * iwl4965_init_alive_start - Called after REPLY_ALIVE notification received
+ *
+ * Called after REPLY_ALIVE notification received from "initialize" uCode.
+ *
+ * The 4965 "initialize" ALIVE reply contains calibration data for:
+ * Voltage, temperature, and MIMO tx gain correction, now stored in priv
+ * (3945 does not contain this data).
+ *
+ * Tell "initialize" uCode to go ahead and load the runtime uCode.
+*/
+static void iwl4965_init_alive_start(struct iwl_priv *priv)
+{
+ /* Check alive response for "valid" sign from uCode */
+ if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
+ /* We had an error bringing up the hardware, so take it
+ * all the way back down so we can try again */
+ IWL_DEBUG_INFO("Initialize Alive failed.\n");
+ goto restart;
+ }
+
+ /* Bootstrap uCode has loaded initialize uCode ... verify inst image.
+ * This is a paranoid check, because we would not have gotten the
+ * "initialize" alive if code weren't properly loaded. */
+ if (iwl_verify_ucode(priv)) {
+ /* Runtime instruction load was bad;
+ * take it all the way back down so we can try again */
+ IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n");
+ goto restart;
+ }
+
+ /* Calculate temperature */
+ priv->temperature = iwl4965_get_temperature(priv);
+
+ /* Send pointers to protocol/runtime uCode image ... init code will
+ * load and launch runtime uCode, which will send us another "Alive"
+ * notification. */
+ IWL_DEBUG_INFO("Initialization Alive received.\n");
+ if (iwl4965_set_ucode_ptrs(priv)) {
+ /* Runtime instruction load won't happen;
+ * take it all the way back down so we can try again */
+ IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n");
+ goto restart;
+ }
+ return;
+
+restart:
+ queue_work(priv->workqueue, &priv->restart);
+}
+
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 +313,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*/
@@ -393,8 +325,8 @@
/* 4965 legacy rate format, search for match in table */
} else {
- for (idx = 0; idx < ARRAY_SIZE(iwl4965_rates); idx++)
- if (iwl4965_rates[idx].plcp == (rate_n_flags & 0xFF))
+ for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++)
+ if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF))
return idx;
}
@@ -405,125 +337,54 @@
* translate ucode response to mac80211 tx status control values
*/
void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
- struct ieee80211_tx_control *control)
+ struct ieee80211_tx_info *control)
{
int rate_index;
control->antenna_sel_tx =
- ((rate_n_flags & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS);
+ ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS);
if (rate_n_flags & RATE_MCS_HT_MSK)
- control->flags |= IEEE80211_TXCTL_OFDM_HT;
+ control->flags |= IEEE80211_TX_CTL_OFDM_HT;
if (rate_n_flags & RATE_MCS_GF_MSK)
- control->flags |= IEEE80211_TXCTL_GREEN_FIELD;
+ control->flags |= IEEE80211_TX_CTL_GREEN_FIELD;
if (rate_n_flags & RATE_MCS_FAT_MSK)
- control->flags |= IEEE80211_TXCTL_40_MHZ_WIDTH;
+ control->flags |= IEEE80211_TX_CTL_40_MHZ_WIDTH;
if (rate_n_flags & RATE_MCS_DUP_MSK)
- control->flags |= IEEE80211_TXCTL_DUP_DATA;
+ control->flags |= IEEE80211_TX_CTL_DUP_DATA;
if (rate_n_flags & RATE_MCS_SGI_MSK)
- control->flags |= IEEE80211_TXCTL_SHORT_GI;
- /* since iwl4965_hwrate_to_plcp_idx is band indifferent, we always use
- * IEEE80211_BAND_2GHZ band as it contains all the rates */
+ control->flags |= IEEE80211_TX_CTL_SHORT_GI;
rate_index = iwl4965_hwrate_to_plcp_idx(rate_n_flags);
- if (rate_index == -1)
- control->tx_rate = NULL;
- else
- control->tx_rate =
- &priv->bands[IEEE80211_BAND_2GHZ].bitrates[rate_index];
+ if (control->band == IEEE80211_BAND_5GHZ)
+ rate_index -= IWL_FIRST_OFDM_RATE;
+ control->tx_rate_idx = rate_index;
}
/*
- * Determine how many receiver/antenna chains to use.
- * More provides better reception via diversity. Fewer saves power.
- * MIMO (dual stream) requires at least 2, but works better with 3.
- * This does not determine *which* chains to use, just how many.
+ * EEPROM handlers
*/
-static int iwl4965_get_rx_chain_counter(struct iwl_priv *priv,
- u8 *idle_state, u8 *rx_state)
+
+static int iwl4965_eeprom_check_version(struct iwl_priv *priv)
{
- u8 is_single = is_single_stream(priv);
- u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1;
+ u16 eeprom_ver;
+ u16 calib_ver;
- /* # 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;
+ eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
- /* # 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;
- }
+ calib_ver = iwl_eeprom_query16(priv, EEPROM_4965_CALIB_VERSION_OFFSET);
+
+ if (eeprom_ver < EEPROM_4965_EEPROM_VERSION ||
+ calib_ver < EEPROM_4965_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_4965_EEPROM_VERSION,
+ calib_ver, EEPROM_4965_TX_POWER_VERSION);
+ return -EINVAL;
+
}
-
-int iwl4965_hw_rxq_stop(struct iwl_priv *priv)
-{
- int rc;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
- rc = iwl_grab_nic_access(priv);
- if (rc) {
- spin_unlock_irqrestore(&priv->lock, flags);
- return rc;
- }
-
- /* stop Rx DMA */
- iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
- rc = iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
- (1 << 24), 1000);
- if (rc < 0)
- IWL_ERROR("Can't stop Rx DMA.\n");
-
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
-}
-
-u8 iwl4965_hw_find_station(struct iwl_priv *priv, const u8 *addr)
-{
- int i;
- int start = 0;
- int ret = IWL_INVALID_STATION;
- unsigned long flags;
- DECLARE_MAC_BUF(mac);
-
- if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) ||
- (priv->iw_mode == IEEE80211_IF_TYPE_AP))
- start = IWL_STA_ID;
-
- if (is_broadcast_ether_addr(addr))
- return priv->hw_params.bcast_sta_id;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
- for (i = start; i < priv->hw_params.max_stations; i++)
- if ((priv->stations[i].used) &&
- (!compare_ether_addr
- (priv->stations[i].sta.sta.addr, addr))) {
- ret = i;
- goto out;
- }
-
- IWL_DEBUG_ASSOC_LIMIT("can not find STA %s total %d\n",
- print_mac(mac, addr), priv->num_stations);
-
- 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 +396,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);
@@ -556,319 +418,108 @@
return ret;
}
-static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq)
-{
- int ret;
- unsigned long flags;
- unsigned int rb_size;
-
- spin_lock_irqsave(&priv->lock, flags);
- ret = iwl_grab_nic_access(priv);
- if (ret) {
- spin_unlock_irqrestore(&priv->lock, flags);
- return ret;
- }
-
- if (priv->cfg->mod_params->amsdu_size_8K)
- rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
- else
- rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
-
- /* Stop Rx DMA */
- iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
-
- /* Reset driver's Rx queue write index */
- iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
-
- /* Tell device where to find RBD circular buffer in DRAM */
- iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
- rxq->dma_addr >> 8);
-
- /* Tell device where in DRAM to update its Rx status */
- iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
- (priv->shared_phys +
- offsetof(struct iwl4965_shared, rb_closed)) >> 4);
-
- /* Enable Rx DMA, enable host interrupt, Rx buffer size 4k, 256 RBDs */
- iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG,
- FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
- FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
- rb_size |
- /* 0x10 << 4 | */
- (RX_QUEUE_SIZE_LOG <<
- FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));
-
- /*
- * iwl_write32(priv,CSR_INT_COAL_REG,0);
- */
-
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
-}
-
-/* Tell 4965 where to find the "keep warm" buffer */
-static int iwl4965_kw_init(struct iwl_priv *priv)
-{
- unsigned long flags;
- int rc;
-
- spin_lock_irqsave(&priv->lock, flags);
- rc = iwl_grab_nic_access(priv);
- if (rc)
- goto out;
-
- iwl_write_direct32(priv, IWL_FH_KW_MEM_ADDR_REG,
- priv->kw.dma_addr >> 4);
- iwl_release_nic_access(priv);
-out:
- spin_unlock_irqrestore(&priv->lock, flags);
- return rc;
-}
-
-static int iwl4965_kw_alloc(struct iwl_priv *priv)
-{
- struct pci_dev *dev = priv->pci_dev;
- struct iwl4965_kw *kw = &priv->kw;
-
- kw->size = IWL4965_KW_SIZE; /* TBW need set somewhere else */
- kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr);
- if (!kw->v_addr)
- return -ENOMEM;
-
- return 0;
-}
-
-/**
- * iwl4965_kw_free - Free the "keep warm" buffer
+/*
+ * Activate/Deactivat Tx DMA/FIFO channels according tx fifos mask
+ * must be called under priv->lock and mac access
*/
-static void iwl4965_kw_free(struct iwl_priv *priv)
+static void iwl4965_txq_set_sched(struct iwl_priv *priv, u32 mask)
{
- struct pci_dev *dev = priv->pci_dev;
- struct iwl4965_kw *kw = &priv->kw;
-
- if (kw->v_addr) {
- pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr);
- memset(kw, 0, sizeof(*kw));
- }
+ iwl_write_prph(priv, IWL49_SCD_TXFACT, mask);
}
-/**
- * iwl4965_txq_ctx_reset - Reset TX queue context
- * Destroys all DMA structures and initialise them again
- *
- * @param priv
- * @return error code
- */
-static int iwl4965_txq_ctx_reset(struct iwl_priv *priv)
+static int iwl4965_apm_init(struct iwl_priv *priv)
{
- int rc = 0;
- int txq_id, slots_num;
- unsigned long flags;
-
- iwl4965_kw_free(priv);
-
- /* Free all tx/cmd queues and keep-warm buffer */
- iwl4965_hw_txq_ctx_free(priv);
-
- /* Alloc keep-warm buffer */
- rc = iwl4965_kw_alloc(priv);
- if (rc) {
- IWL_ERROR("Keep Warm allocation failed");
- goto error_kw;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
-
- rc = iwl_grab_nic_access(priv);
- if (unlikely(rc)) {
- IWL_ERROR("TX reset failed");
- spin_unlock_irqrestore(&priv->lock, flags);
- goto error_reset;
- }
-
- /* Turn off all Tx DMA channels */
- iwl_write_prph(priv, IWL49_SCD_TXFACT, 0);
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- /* Tell 4965 where to find the keep-warm buffer */
- rc = iwl4965_kw_init(priv);
- if (rc) {
- IWL_ERROR("kw_init failed\n");
- goto error_reset;
- }
-
- /* Alloc and init all (default 16) Tx queues,
- * including the command queue (#4) */
- for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
- slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
- TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
- rc = iwl4965_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
- txq_id);
- if (rc) {
- IWL_ERROR("Tx %d queue init failed\n", txq_id);
- goto error;
- }
- }
-
- return rc;
-
- error:
- iwl4965_hw_txq_ctx_free(priv);
- error_reset:
- iwl4965_kw_free(priv);
- error_kw:
- return rc;
-}
-
-int iwl4965_hw_nic_init(struct iwl_priv *priv)
-{
- int rc;
- unsigned long flags;
- struct iwl4965_rx_queue *rxq = &priv->rxq;
- u8 rev_id;
- u32 val;
- u8 val_link;
-
- iwl4965_power_init_handle(priv);
-
- /* nic_init */
- spin_lock_irqsave(&priv->lock, flags);
+ int ret = 0;
iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
- CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+ CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+ /* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */
+ iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+ CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
+
+ /* 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);
-
- iwl_write_prph(priv, APMG_CLK_CTRL_REG,
- APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT);
- iwl_read_prph(priv, APMG_CLK_CTRL_REG);
+ /* enable DMA */
+ iwl_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT |
+ APMG_CLK_VAL_BSM_CLK_RQT);
udelay(20);
+ /* disable L1-Active */
iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
- APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+ APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
iwl_release_nic_access(priv);
- iwl_write32(priv, CSR_INT_COALESCING, 512 / 32);
- spin_unlock_irqrestore(&priv->lock, flags);
+out:
+ return ret;
+}
- /* Determine HW type */
- rc = pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id);
- if (rc)
- return rc;
- IWL_DEBUG_INFO("HW Revision ID = 0x%X\n", rev_id);
+static void iwl4965_nic_config(struct iwl_priv *priv)
+{
+ unsigned long flags;
+ u32 val;
+ u16 radio_cfg;
+ u8 val_link;
- iwl4965_nic_set_pwr_src(priv, 1);
spin_lock_irqsave(&priv->lock, flags);
- if ((rev_id & 0x80) == 0x80 && (rev_id & 0x7f) < 8) {
+ if ((priv->rev_id & 0x80) == 0x80 && (priv->rev_id & 0x7f) < 8) {
pci_read_config_dword(priv->pci_dev, PCI_REG_WUM8, &val);
/* Enable No Snoop field */
pci_write_config_dword(priv->pci_dev, PCI_REG_WUM8,
val & ~(1 << 11));
}
- spin_unlock_irqrestore(&priv->lock, flags);
-
- if (priv->eeprom.calib_version < EEPROM_TX_POWER_VERSION_NEW) {
- IWL_ERROR("Older EEPROM detected! Aborting.\n");
- return -EINVAL;
- }
-
pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link);
- /* disable L1 entry -- workaround for pre-B1 */
- pci_write_config_byte(priv->pci_dev, PCI_LINK_CTRL, val_link & ~0x02);
+ /* L1 is enabled by BIOS */
+ if ((val_link & PCI_LINK_VAL_L1_EN) == PCI_LINK_VAL_L1_EN)
+ /* diable L0S disabled L1A enabled */
+ iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
+ else
+ /* L0S enabled L1A disabled */
+ iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
- spin_lock_irqsave(&priv->lock, flags);
+ radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
+
+ /* 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;
- }
-
- iwl_read_prph(priv, APMG_PS_CTRL_REG);
- iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ);
- udelay(5);
- iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ);
-
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- iwl4965_hw_card_show_info(priv);
-
- /* end nic_init */
-
- /* Allocate the RX queue, or reset if it is already allocated */
- if (!rxq->bd) {
- rc = iwl4965_rx_queue_alloc(priv);
- if (rc) {
- IWL_ERROR("Unable to initialize Rx queue\n");
- return -ENOMEM;
- }
- } else
- iwl4965_rx_queue_reset(priv, rxq);
-
- iwl4965_rx_replenish(priv);
-
- iwl4965_rx_init(priv, rxq);
-
- spin_lock_irqsave(&priv->lock, flags);
-
- rxq->need_update = 1;
- iwl4965_rx_queue_update_write_ptr(priv, rxq);
+ priv->calib_info = (struct iwl_eeprom_calib_info *)
+ iwl_eeprom_query_addr(priv, EEPROM_4965_CALIB_TXPOWER_OFFSET);
spin_unlock_irqrestore(&priv->lock, flags);
-
- /* Allocate and init all Tx and Command queues */
- rc = iwl4965_txq_ctx_reset(priv);
- if (rc)
- return rc;
-
- if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_SW_RF_KILL_ENABLE)
- IWL_DEBUG_RF_KILL("SW RF KILL supported in EEPROM.\n");
-
- if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE)
- IWL_DEBUG_RF_KILL("HW RF KILL supported in EEPROM.\n");
-
- set_bit(STATUS_INIT, &priv->status);
-
- return 0;
}
-int iwl4965_hw_nic_stop_master(struct iwl_priv *priv)
+static int iwl4965_apm_stop_master(struct iwl_priv *priv)
{
- int rc = 0;
- u32 reg_val;
+ int ret = 0;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
@@ -876,64 +527,24 @@
/* set stop master bit */
iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
- reg_val = iwl_read32(priv, CSR_GP_CNTRL);
-
- if (CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE ==
- (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE))
- IWL_DEBUG_INFO("Card in power save, master is already "
- "stopped\n");
- else {
- rc = iwl_poll_bit(priv, CSR_RESET,
+ ret = iwl_poll_bit(priv, CSR_RESET,
CSR_RESET_REG_FLAG_MASTER_DISABLED,
CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
- if (rc < 0) {
- spin_unlock_irqrestore(&priv->lock, flags);
- return rc;
- }
- }
+ if (ret < 0)
+ goto out;
+out:
spin_unlock_irqrestore(&priv->lock, flags);
IWL_DEBUG_INFO("stop master\n");
- return rc;
+ return ret;
}
-/**
- * iwl4965_hw_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory
- */
-void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv)
+static void iwl4965_apm_stop(struct iwl_priv *priv)
{
-
- int txq_id;
unsigned long flags;
- /* Stop each Tx DMA channel, and wait for it to be idle */
- for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
- spin_lock_irqsave(&priv->lock, flags);
- if (iwl_grab_nic_access(priv)) {
- spin_unlock_irqrestore(&priv->lock, flags);
- continue;
- }
-
- iwl_write_direct32(priv,
- IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), 0x0);
- iwl_poll_direct_bit(priv, IWL_FH_TSSR_TX_STATUS_REG,
- IWL_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE
- (txq_id), 200);
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->lock, flags);
- }
-
- /* Deallocate memory for all Tx queues */
- iwl4965_hw_txq_ctx_free(priv);
-}
-
-int iwl4965_hw_nic_reset(struct iwl_priv *priv)
-{
- int rc = 0;
- unsigned long flags;
-
- iwl4965_hw_nic_stop_master(priv);
+ iwl4965_apm_stop_master(priv);
spin_lock_irqsave(&priv->lock, flags);
@@ -942,33 +553,57 @@
udelay(10);
iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
- rc = iwl_poll_bit(priv, CSR_RESET,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25);
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int iwl4965_apm_reset(struct iwl_priv *priv)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ iwl4965_apm_stop_master(priv);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
udelay(10);
- rc = iwl_grab_nic_access(priv);
- if (!rc) {
- iwl_write_prph(priv, APMG_CLK_EN_REG,
- APMG_CLK_VAL_DMA_CLK_RQT |
- APMG_CLK_VAL_BSM_CLK_RQT);
+ /* FIXME: put here L1A -L0S w/a */
- udelay(10);
+ iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
- iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
- APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+ ret = iwl_poll_bit(priv, CSR_RESET,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25);
- iwl_release_nic_access(priv);
- }
+ if (ret)
+ goto out;
+
+ udelay(10);
+
+ ret = iwl_grab_nic_access(priv);
+ if (ret)
+ goto out;
+ /* Enable DMA and BSM Clock */
+ iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT |
+ APMG_CLK_VAL_BSM_CLK_RQT);
+
+ udelay(10);
+
+ /* disable L1A */
+ iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
+ APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+
+ iwl_release_nic_access(priv);
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
wake_up_interruptible(&priv->wait_command_queue);
+out:
spin_unlock_irqrestore(&priv->lock, flags);
- return rc;
-
+ return ret;
}
#define REG_RECALIB_PERIOD (60)
@@ -993,15 +628,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 +639,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 +669,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 +755,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)
{
@@ -1880,7 +810,7 @@
* NOTE: Acquire priv->lock before calling this function !
*/
static void iwl4965_tx_queue_set_status(struct iwl_priv *priv,
- struct iwl4965_tx_queue *txq,
+ struct iwl_tx_queue *txq,
int tx_fifo_id, int scd_retry)
{
int txq_id = txq->q.id;
@@ -1890,11 +820,11 @@
/* Set up and activate */
iwl_write_prph(priv, IWL49_SCD_QUEUE_STATUS_BITS(txq_id),
- (active << SCD_QUEUE_STTS_REG_POS_ACTIVE) |
- (tx_fifo_id << SCD_QUEUE_STTS_REG_POS_TXF) |
- (scd_retry << SCD_QUEUE_STTS_REG_POS_WSL) |
- (scd_retry << SCD_QUEUE_STTS_REG_POS_SCD_ACK) |
- SCD_QUEUE_STTS_REG_MSK);
+ (active << IWL49_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
+ (tx_fifo_id << IWL49_SCD_QUEUE_STTS_REG_POS_TXF) |
+ (scd_retry << IWL49_SCD_QUEUE_STTS_REG_POS_WSL) |
+ (scd_retry << IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACK) |
+ IWL49_SCD_QUEUE_STTS_REG_MSK);
txq->sched_retry = scd_retry;
@@ -1908,21 +838,11 @@
IWL_TX_FIFO_AC2,
IWL_TX_FIFO_AC1,
IWL_TX_FIFO_AC0,
- IWL_CMD_FIFO_NUM,
+ IWL49_CMD_FIFO_NUM,
IWL_TX_FIFO_HCCA_1,
IWL_TX_FIFO_HCCA_2
};
-static inline void iwl4965_txq_ctx_activate(struct iwl_priv *priv, int txq_id)
-{
- set_bit(txq_id, &priv->txq_ctx_active_msk);
-}
-
-static inline void iwl4965_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id)
-{
- clear_bit(txq_id, &priv->txq_ctx_active_msk);
-}
-
int iwl4965_alive_notify(struct iwl_priv *priv)
{
u32 a;
@@ -1932,15 +852,6 @@
spin_lock_irqsave(&priv->lock, flags);
-#ifdef CONFIG_IWL4965_SENSITIVITY
- memset(&(priv->sensitivity_data), 0,
- sizeof(struct iwl4965_sensitivity_data));
- memset(&(priv->chain_noise_data), 0,
- sizeof(struct iwl4965_chain_noise_data));
- for (i = 0; i < NUM_RX_CHAINS; i++)
- priv->chain_noise_data.delta_gain_code[i] =
- CHAIN_NOISE_DELTA_GAIN_INIT_VAL;
-#endif /* CONFIG_IWL4965_SENSITIVITY*/
ret = iwl_grab_nic_access(priv);
if (ret) {
spin_unlock_irqrestore(&priv->lock, flags);
@@ -1949,10 +860,10 @@
/* Clear 4965's internal Tx Scheduler data base */
priv->scd_base_addr = iwl_read_prph(priv, IWL49_SCD_SRAM_BASE_ADDR);
- a = priv->scd_base_addr + SCD_CONTEXT_DATA_OFFSET;
- for (; a < priv->scd_base_addr + SCD_TX_STTS_BITMAP_OFFSET; a += 4)
+ a = priv->scd_base_addr + IWL49_SCD_CONTEXT_DATA_OFFSET;
+ for (; a < priv->scd_base_addr + IWL49_SCD_TX_STTS_BITMAP_OFFSET; a += 4)
iwl_write_targ_mem(priv, a, 0);
- for (; a < priv->scd_base_addr + SCD_TRANSLATE_TBL_OFFSET; a += 4)
+ for (; a < priv->scd_base_addr + IWL49_SCD_TRANSLATE_TBL_OFFSET; a += 4)
iwl_write_targ_mem(priv, a, 0);
for (; a < sizeof(u16) * priv->hw_params.max_txq_num; a += 4)
iwl_write_targ_mem(priv, a, 0);
@@ -1974,45 +885,66 @@
/* Max Tx Window size for Scheduler-ACK mode */
iwl_write_targ_mem(priv, priv->scd_base_addr +
- SCD_CONTEXT_QUEUE_OFFSET(i),
- (SCD_WIN_SIZE <<
- SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) &
- SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK);
+ IWL49_SCD_CONTEXT_QUEUE_OFFSET(i),
+ (SCD_WIN_SIZE <<
+ IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) &
+ IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK);
/* Frame limit */
iwl_write_targ_mem(priv, priv->scd_base_addr +
- SCD_CONTEXT_QUEUE_OFFSET(i) +
- sizeof(u32),
- (SCD_FRAME_LIMIT <<
- SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
- SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK);
+ IWL49_SCD_CONTEXT_QUEUE_OFFSET(i) +
+ sizeof(u32),
+ (SCD_FRAME_LIMIT <<
+ IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
+ IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK);
}
iwl_write_prph(priv, IWL49_SCD_INTERRUPT_MASK,
(1 << priv->hw_params.max_txq_num) - 1);
/* Activate all Tx DMA/FIFO channels */
- iwl_write_prph(priv, IWL49_SCD_TXFACT,
- SCD_TXFACT_REG_TXFIFO_MASK(0, 7));
+ priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7));
iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
/* Map each Tx/cmd queue to its corresponding fifo */
for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) {
int ac = default_queue_to_tx_fifo[i];
- iwl4965_txq_ctx_activate(priv, i);
+ iwl_txq_ctx_activate(priv, i);
iwl4965_tx_queue_set_status(priv, &priv->txq[i], ac, 0);
}
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
- /* Ask for statistics now, the uCode will send statistics notification
- * periodically after association */
- iwl_send_statistics_request(priv, CMD_ASYNC);
return ret;
}
+#ifdef CONFIG_IWL4965_RUN_TIME_CALIB
+static struct iwl_sensitivity_ranges iwl4965_sensitivity = {
+ .min_nrg_cck = 97,
+ .max_nrg_cck = 0,
+
+ .auto_corr_min_ofdm = 85,
+ .auto_corr_min_ofdm_mrc = 170,
+ .auto_corr_min_ofdm_x1 = 105,
+ .auto_corr_min_ofdm_mrc_x1 = 220,
+
+ .auto_corr_max_ofdm = 120,
+ .auto_corr_max_ofdm_mrc = 210,
+ .auto_corr_max_ofdm_x1 = 140,
+ .auto_corr_max_ofdm_mrc_x1 = 270,
+
+ .auto_corr_min_cck = 125,
+ .auto_corr_max_cck = 200,
+ .auto_corr_min_cck_mrc = 200,
+ .auto_corr_max_cck_mrc = 400,
+
+ .nrg_th_cck = 100,
+ .nrg_th_ofdm = 100,
+};
+#endif
+
/**
* iwl4965_hw_set_hw_params
*
@@ -2021,15 +953,15 @@
int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
{
- if ((priv->cfg->mod_params->num_of_queues > IWL4965_MAX_NUM_QUEUES) ||
+ if ((priv->cfg->mod_params->num_of_queues > IWL49_NUM_QUEUES) ||
(priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) {
IWL_ERROR("invalid queues_num, should be between %d and %d\n",
- IWL_MIN_NUM_QUEUES, IWL4965_MAX_NUM_QUEUES);
+ IWL_MIN_NUM_QUEUES, IWL49_NUM_QUEUES);
return -EINVAL;
}
priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues;
- priv->hw_params.tx_cmd_len = sizeof(struct iwl4965_tx_cmd);
+ priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto;
priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
if (priv->cfg->mod_params->amsdu_size_8K)
@@ -2040,90 +972,35 @@
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;
}
-/**
- * iwl4965_hw_txq_ctx_free - Free TXQ Context
- *
- * Destroy all TX DMA queues and structures
- */
-void iwl4965_hw_txq_ctx_free(struct iwl_priv *priv)
+/* set card power command */
+static int iwl4965_set_power(struct iwl_priv *priv,
+ void *cmd)
{
- int txq_id;
+ int ret = 0;
- /* Tx queues */
- for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
- iwl4965_tx_queue_free(priv, &priv->txq[txq_id]);
-
- /* Keep-warm buffer */
- iwl4965_kw_free(priv);
+ ret = iwl_send_cmd_pdu_async(priv, POWER_TABLE_CMD,
+ sizeof(struct iwl4965_powertable_cmd),
+ cmd, NULL);
+ return ret;
}
-
-/**
- * iwl4965_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
- *
- * Does NOT advance any TFD circular buffer read/write indexes
- * Does NOT free the TFD itself (which is within circular buffer)
- */
-int iwl4965_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl4965_tx_queue *txq)
-{
- struct iwl4965_tfd_frame *bd_tmp = (struct iwl4965_tfd_frame *)&txq->bd[0];
- struct iwl4965_tfd_frame *bd = &bd_tmp[txq->q.read_ptr];
- struct pci_dev *dev = priv->pci_dev;
- int i;
- int counter = 0;
- int index, is_odd;
-
- /* Host command buffers stay mapped in memory, nothing to clean */
- if (txq->q.id == IWL_CMD_QUEUE_NUM)
- return 0;
-
- /* Sanity check on number of chunks */
- counter = IWL_GET_BITS(*bd, num_tbs);
- if (counter > MAX_NUM_OF_TBS) {
- IWL_ERROR("Too many chunks: %i\n", counter);
- /* @todo issue fatal error, it is quite serious situation */
- return 0;
- }
-
- /* Unmap chunks, if any.
- * TFD info for odd chunks is different format than for even chunks. */
- for (i = 0; i < counter; i++) {
- index = i / 2;
- is_odd = i & 0x1;
-
- if (is_odd)
- pci_unmap_single(
- dev,
- IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) |
- (IWL_GET_BITS(bd->pa[index],
- tb2_addr_hi20) << 16),
- IWL_GET_BITS(bd->pa[index], tb2_len),
- PCI_DMA_TODEVICE);
-
- else if (i > 0)
- pci_unmap_single(dev,
- le32_to_cpu(bd->pa[index].tb1_addr),
- IWL_GET_BITS(bd->pa[index], tb1_len),
- PCI_DMA_TODEVICE);
-
- /* Free SKB, if any, for this chunk */
- if (txq->txb[txq->q.read_ptr].skb[i]) {
- struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[i];
-
- dev_kfree_skb(skb);
- txq->txb[txq->q.read_ptr].skb[i] = NULL;
- }
- }
- return 0;
-}
-
int iwl4965_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
{
IWL_ERROR("TODO: Implement iwl4965_hw_reg_set_txpower!\n");
@@ -2224,11 +1101,11 @@
s32 b = -1;
for (b = 0; b < EEPROM_TX_POWER_BANDS; b++) {
- if (priv->eeprom.calib_info.band_info[b].ch_from == 0)
+ if (priv->calib_info->band_info[b].ch_from == 0)
continue;
- if ((channel >= priv->eeprom.calib_info.band_info[b].ch_from)
- && (channel <= priv->eeprom.calib_info.band_info[b].ch_to))
+ if ((channel >= priv->calib_info->band_info[b].ch_from)
+ && (channel <= priv->calib_info->band_info[b].ch_to))
break;
}
@@ -2256,14 +1133,14 @@
* in channel number.
*/
static int iwl4965_interpolate_chan(struct iwl_priv *priv, u32 channel,
- struct iwl4965_eeprom_calib_ch_info *chan_info)
+ struct iwl_eeprom_calib_ch_info *chan_info)
{
s32 s = -1;
u32 c;
u32 m;
- const struct iwl4965_eeprom_calib_measure *m1;
- const struct iwl4965_eeprom_calib_measure *m2;
- struct iwl4965_eeprom_calib_measure *omeas;
+ const struct iwl_eeprom_calib_measure *m1;
+ const struct iwl_eeprom_calib_measure *m2;
+ struct iwl_eeprom_calib_measure *omeas;
u32 ch_i1;
u32 ch_i2;
@@ -2273,8 +1150,8 @@
return -1;
}
- ch_i1 = priv->eeprom.calib_info.band_info[s].ch1.ch_num;
- ch_i2 = priv->eeprom.calib_info.band_info[s].ch2.ch_num;
+ ch_i1 = priv->calib_info->band_info[s].ch1.ch_num;
+ ch_i2 = priv->calib_info->band_info[s].ch2.ch_num;
chan_info->ch_num = (u8) channel;
IWL_DEBUG_TXPOWER("channel %d subband %d factory cal ch %d & %d\n",
@@ -2282,9 +1159,9 @@
for (c = 0; c < EEPROM_TX_POWER_TX_CHAINS; c++) {
for (m = 0; m < EEPROM_TX_POWER_MEASUREMENTS; m++) {
- m1 = &(priv->eeprom.calib_info.band_info[s].ch1.
+ m1 = &(priv->calib_info->band_info[s].ch1.
measurements[c][m]);
- m2 = &(priv->eeprom.calib_info.band_info[s].ch2.
+ m2 = &(priv->calib_info->band_info[s].ch2.
measurements[c][m]);
omeas = &(chan_info->measurements[c][m]);
@@ -2603,8 +1480,8 @@
int i;
int c;
const struct iwl_channel_info *ch_info = NULL;
- struct iwl4965_eeprom_calib_ch_info ch_eeprom_info;
- const struct iwl4965_eeprom_calib_measure *measurement;
+ struct iwl_eeprom_calib_ch_info ch_eeprom_info;
+ const struct iwl_eeprom_calib_measure *measurement;
s16 voltage;
s32 init_voltage;
s32 voltage_compensation;
@@ -2661,9 +1538,9 @@
/* hardware txpower limits ...
* saturation (clipping distortion) txpowers are in half-dBm */
if (band)
- saturation_power = priv->eeprom.calib_info.saturation_power24;
+ saturation_power = priv->calib_info->saturation_power24;
else
- saturation_power = priv->eeprom.calib_info.saturation_power52;
+ saturation_power = priv->calib_info->saturation_power52;
if (saturation_power < IWL_TX_POWER_SATURATION_MIN ||
saturation_power > IWL_TX_POWER_SATURATION_MAX) {
@@ -2693,7 +1570,7 @@
iwl4965_interpolate_chan(priv, channel, &ch_eeprom_info);
/* calculate tx gain adjustment based on power supply voltage */
- voltage = priv->eeprom.calib_info.voltage;
+ voltage = priv->calib_info->voltage;
init_voltage = (s32)le32_to_cpu(priv->card_alive_init.voltage);
voltage_compensation =
iwl4965_get_voltage_compensation(voltage, init_voltage);
@@ -2888,8 +1765,8 @@
{
int ret = 0;
struct iwl4965_rxon_assoc_cmd rxon_assoc;
- const struct iwl4965_rxon_cmd *rxon1 = &priv->staging_rxon;
- const struct iwl4965_rxon_cmd *rxon2 = &priv->active_rxon;
+ const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
+ const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
if ((rxon1->flags == rxon2->flags) &&
(rxon1->filter_flags == rxon2->filter_flags) &&
@@ -2965,77 +1842,7 @@
return rc;
}
-#define RTS_HCCA_RETRY_LIMIT 3
-#define RTS_DFAULT_RETRY_LIMIT 60
-
-void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv,
- struct iwl_cmd *cmd,
- struct ieee80211_tx_control *ctrl,
- struct ieee80211_hdr *hdr, int sta_id,
- int is_hcca)
-{
- struct iwl4965_tx_cmd *tx = &cmd->cmd.tx;
- u8 rts_retry_limit = 0;
- u8 data_retry_limit = 0;
- u16 fc = le16_to_cpu(hdr->frame_control);
- u8 rate_plcp;
- u16 rate_flags = 0;
- int rate_idx = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1);
-
- rate_plcp = iwl4965_rates[rate_idx].plcp;
-
- rts_retry_limit = (is_hcca) ?
- RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT;
-
- if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
- rate_flags |= RATE_MCS_CCK_MSK;
-
-
- if (ieee80211_is_probe_response(fc)) {
- data_retry_limit = 3;
- if (data_retry_limit < rts_retry_limit)
- rts_retry_limit = data_retry_limit;
- } else
- data_retry_limit = IWL_DEFAULT_TX_RETRY;
-
- if (priv->data_retry_limit != -1)
- data_retry_limit = priv->data_retry_limit;
-
-
- if (ieee80211_is_data(fc)) {
- tx->initial_rate_index = 0;
- tx->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
- } else {
- switch (fc & IEEE80211_FCTL_STYPE) {
- case IEEE80211_STYPE_AUTH:
- case IEEE80211_STYPE_DEAUTH:
- case IEEE80211_STYPE_ASSOC_REQ:
- case IEEE80211_STYPE_REASSOC_REQ:
- if (tx->tx_flags & TX_CMD_FLG_RTS_MSK) {
- tx->tx_flags &= ~TX_CMD_FLG_RTS_MSK;
- tx->tx_flags |= TX_CMD_FLG_CTS_MSK;
- }
- break;
- default:
- break;
- }
-
- /* Alternate between antenna A and B for successive frames */
- if (priv->use_ant_b_for_management_frame) {
- priv->use_ant_b_for_management_frame = 0;
- rate_flags |= RATE_MCS_ANT_B_MSK;
- } else {
- priv->use_ant_b_for_management_frame = 1;
- rate_flags |= RATE_MCS_ANT_A_MSK;
- }
- }
-
- tx->rts_retry_limit = rts_retry_limit;
- tx->data_retry_limit = data_retry_limit;
- tx->rate_n_flags = iwl4965_hw_set_rate_n_flags(rate_plcp, rate_flags);
-}
-
-int iwl4965_hw_get_rx_read(struct iwl_priv *priv)
+static int iwl4965_shared_mem_rx_idx(struct iwl_priv *priv)
{
struct iwl4965_shared *s = priv->shared_virt;
return le32_to_cpu(s->rb_closed) & 0xFFF;
@@ -3047,7 +1854,7 @@
}
unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
- struct iwl4965_frame *frame, u8 rate)
+ struct iwl_frame *frame, u8 rate)
{
struct iwl4965_tx_beacon_cmd *tx_beacon_cmd;
unsigned int frame_size;
@@ -3060,7 +1867,7 @@
frame_size = iwl4965_fill_beacon_frame(priv,
tx_beacon_cmd->frame,
- iwl4965_broadcast_addr,
+ iwl_bcast_addr,
sizeof(frame->u) - sizeof(*tx_beacon_cmd));
BUG_ON(frame_size > MAX_MPDU_SIZE);
@@ -3078,95 +1885,35 @@
return (sizeof(*tx_beacon_cmd) + frame_size);
}
-/*
- * Tell 4965 where to find circular buffer of Tx Frame Descriptors for
- * given Tx queue, and enable the DMA channel used for that queue.
- *
- * 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA
- * channels supported in hardware.
- */
-int iwl4965_hw_tx_queue_init(struct iwl_priv *priv, struct iwl4965_tx_queue *txq)
+static int iwl4965_alloc_shared_mem(struct iwl_priv *priv)
{
- int rc;
- unsigned long flags;
- int txq_id = txq->q.id;
+ priv->shared_virt = pci_alloc_consistent(priv->pci_dev,
+ sizeof(struct iwl4965_shared),
+ &priv->shared_phys);
+ if (!priv->shared_virt)
+ return -ENOMEM;
- spin_lock_irqsave(&priv->lock, flags);
- rc = iwl_grab_nic_access(priv);
- if (rc) {
- spin_unlock_irqrestore(&priv->lock, flags);
- return rc;
- }
+ memset(priv->shared_virt, 0, sizeof(struct iwl4965_shared));
- /* Circular buffer (TFD queue in DRAM) physical base address */
- iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
- txq->q.dma_addr >> 8);
-
- /* Enable DMA channel, using same id as for TFD queue */
- iwl_write_direct32(
- priv, IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id),
- IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
- IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL);
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->lock, flags);
+ priv->rb_closed_offset = offsetof(struct iwl4965_shared, rb_closed);
return 0;
}
-int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,
- dma_addr_t addr, u16 len)
+static void iwl4965_free_shared_mem(struct iwl_priv *priv)
{
- int index, is_odd;
- struct iwl4965_tfd_frame *tfd = ptr;
- u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs);
-
- /* Each TFD can point to a maximum 20 Tx buffers */
- if ((num_tbs >= MAX_NUM_OF_TBS) || (num_tbs < 0)) {
- IWL_ERROR("Error can not send more than %d chunks\n",
- MAX_NUM_OF_TBS);
- return -EINVAL;
- }
-
- index = num_tbs / 2;
- is_odd = num_tbs & 0x1;
-
- if (!is_odd) {
- tfd->pa[index].tb1_addr = cpu_to_le32(addr);
- IWL_SET_BITS(tfd->pa[index], tb1_addr_hi,
- iwl_get_dma_hi_address(addr));
- IWL_SET_BITS(tfd->pa[index], tb1_len, len);
- } else {
- IWL_SET_BITS(tfd->pa[index], tb2_addr_lo16,
- (u32) (addr & 0xffff));
- IWL_SET_BITS(tfd->pa[index], tb2_addr_hi20, addr >> 16);
- IWL_SET_BITS(tfd->pa[index], tb2_len, len);
- }
-
- IWL_SET_BITS(*tfd, num_tbs, num_tbs + 1);
-
- return 0;
+ if (priv->shared_virt)
+ pci_free_consistent(priv->pci_dev,
+ sizeof(struct iwl4965_shared),
+ priv->shared_virt,
+ priv->shared_phys);
}
-static void iwl4965_hw_card_show_info(struct iwl_priv *priv)
-{
- u16 hw_version = priv->eeprom.board_revision_4965;
-
- IWL_DEBUG_INFO("4965ABGN HW Version %u.%u.%u\n",
- ((hw_version >> 8) & 0x0F),
- ((hw_version >> 8) >> 4), (hw_version & 0x00FF));
-
- IWL_DEBUG_INFO("4965ABGN PBA Number %.16s\n",
- priv->eeprom.board_pba_number_4965);
-}
-
-#define IWL_TX_CRC_SIZE 4
-#define IWL_TX_DELIMITER_SIZE 4
-
/**
* iwl4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
*/
static void iwl4965_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
- struct iwl4965_tx_queue *txq,
+ struct iwl_tx_queue *txq,
u16 byte_cnt)
{
int len;
@@ -3180,50 +1927,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
@@ -3383,9 +2093,10 @@
priv->last_rx_noise);
}
-void iwl4965_hw_rx_statistics(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb)
+void iwl4965_hw_rx_statistics(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
{
- struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
int change;
s32 temp;
@@ -3412,7 +2123,7 @@
if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&
(pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {
iwl4965_rx_calc_noise(priv);
-#ifdef CONFIG_IWL4965_SENSITIVITY
+#ifdef CONFIG_IWL4965_RUN_TIME_CALIB
queue_work(priv->workqueue, &priv->sensitivity_work);
#endif
}
@@ -3455,7 +2166,7 @@
struct ieee80211_rx_status *stats,
u32 ampdu_status)
{
- s8 signal = stats->ssi;
+ s8 signal = stats->signal;
s8 noise = 0;
int rate = stats->rate_idx;
u64 tsf = stats->mactime;
@@ -3529,7 +2240,7 @@
if (rate == -1)
iwl4965_rt->rt_rate = 0;
else
- iwl4965_rt->rt_rate = iwl4965_rates[rate].ieee;
+ iwl4965_rt->rt_rate = iwl_rates[rate].ieee;
/*
* "antenna number"
@@ -3562,7 +2273,54 @@
priv->rx_stats[idx].bytes += len;
}
-static u32 iwl4965_translate_rx_status(u32 decrypt_in)
+/*
+ * returns non-zero if packet should be dropped
+ */
+static int iwl4965_set_decrypted_flag(struct iwl_priv *priv,
+ struct ieee80211_hdr *hdr,
+ u32 decrypt_res,
+ struct ieee80211_rx_status *stats)
+{
+ u16 fc = le16_to_cpu(hdr->frame_control);
+
+ if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK)
+ return 0;
+
+ if (!(fc & IEEE80211_FCTL_PROTECTED))
+ return 0;
+
+ IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res);
+ switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) {
+ case RX_RES_STATUS_SEC_TYPE_TKIP:
+ /* The uCode has got a bad phase 1 Key, pushes the packet.
+ * Decryption will be done in SW. */
+ if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+ RX_RES_STATUS_BAD_KEY_TTAK)
+ break;
+
+ case RX_RES_STATUS_SEC_TYPE_WEP:
+ if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+ RX_RES_STATUS_BAD_ICV_MIC) {
+ /* bad ICV, the packet is destroyed since the
+ * decryption is inplace, drop it */
+ IWL_DEBUG_RX("Packet destroyed\n");
+ return -1;
+ }
+ case RX_RES_STATUS_SEC_TYPE_CCMP:
+ if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+ RX_RES_STATUS_DECRYPT_OK) {
+ IWL_DEBUG_RX("hw decrypt successfully!!!\n");
+ stats->flag |= RX_FLAG_DECRYPTED;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+static u32 iwl4965_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
{
u32 decrypt_out = 0;
@@ -3623,10 +2381,10 @@
static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
int include_phy,
- struct iwl4965_rx_mem_buffer *rxb,
+ struct iwl_rx_mem_buffer *rxb,
struct ieee80211_rx_status *stats)
{
- struct iwl4965_rx_packet *pkt = (struct iwl4965_rx_packet *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
struct iwl4965_rx_phy_res *rx_start = (include_phy) ?
(struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : NULL;
struct ieee80211_hdr *hdr;
@@ -3663,7 +2421,9 @@
rx_start->byte_count = amsdu->byte_count;
rx_end = (__le32 *) (((u8 *) hdr) + len);
}
- if (len > priv->hw_params.max_pkt_size || len < 16) {
+ /* In monitor mode allow 802.11 ACk frames (10 bytes) */
+ if (len > priv->hw_params.max_pkt_size ||
+ len < ((priv->iw_mode == IEEE80211_IF_TYPE_MNTR) ? 10 : 16)) {
IWL_WARNING("byte count out of range [16,4K] : %d\n", len);
return;
}
@@ -3674,7 +2434,7 @@
if (!include_phy) {
/* New status scheme, need to translate */
ampdu_status_legacy = ampdu_status;
- ampdu_status = iwl4965_translate_rx_status(ampdu_status);
+ ampdu_status = iwl4965_translate_rx_status(priv, ampdu_status);
}
/* start from MAC */
@@ -3691,8 +2451,10 @@
stats->flag = 0;
hdr = (struct ieee80211_hdr *)rxb->skb->data;
- if (!priv->cfg->mod_params->sw_crypto)
- iwl4965_set_decrypted_flag(priv, rxb->skb, ampdu_status, stats);
+ /* in case of HW accelerated crypto and bad decryption, drop */
+ if (!priv->hw_params.sw_crypto &&
+ iwl4965_set_decrypted_flag(priv, hdr, ampdu_status, stats))
+ return;
if (priv->add_radiotap)
iwl4965_add_radiotap(priv, rxb->skb, rx_start, stats, ampdu_status);
@@ -3704,7 +2466,8 @@
}
/* Calc max signal level (dBm) among 3 possible receivers */
-static int iwl4965_calc_rssi(struct iwl4965_rx_phy_res *rx_resp)
+static int iwl4965_calc_rssi(struct iwl_priv *priv,
+ struct iwl4965_rx_phy_res *rx_resp)
{
/* data from PHY/DSP regarding signal strength, etc.,
* contents are always there, not configurable by host. */
@@ -3737,38 +2500,6 @@
return (max_rssi - agc - IWL_RSSI_OFFSET);
}
-#ifdef CONFIG_IWL4965_HT
-
-void iwl4965_init_ht_hw_capab(struct iwl_priv *priv,
- struct ieee80211_ht_info *ht_info,
- enum ieee80211_band band)
-{
- ht_info->cap = 0;
- memset(ht_info->supp_mcs_set, 0, 16);
-
- ht_info->ht_supported = 1;
-
- if (band == IEEE80211_BAND_5GHZ) {
- ht_info->cap |= (u16)IEEE80211_HT_CAP_SUP_WIDTH;
- ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_40;
- ht_info->supp_mcs_set[4] = 0x01;
- }
- ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD;
- ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20;
- ht_info->cap |= (u16)(IEEE80211_HT_CAP_MIMO_PS &
- (IWL_MIMO_PS_NONE << 2));
-
- if (priv->cfg->mod_params->amsdu_size_8K)
- ht_info->cap |= (u16)IEEE80211_HT_CAP_MAX_AMSDU;
-
- ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
- ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF;
-
- ht_info->supp_mcs_set[0] = 0xFF;
- ht_info->supp_mcs_set[1] = 0xFF;
-}
-#endif /* CONFIG_IWL4965_HT */
-
static void iwl4965_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
{
unsigned long flags;
@@ -3780,13 +2511,13 @@
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
spin_unlock_irqrestore(&priv->sta_lock, flags);
- iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+ iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
}
static void iwl4965_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
{
/* FIXME: need locking over ps_status ??? */
- u8 sta_id = iwl4965_hw_find_station(priv, addr);
+ u8 sta_id = iwl_find_station(priv, addr);
if (sta_id != IWL_INVALID_STATION) {
u8 sta_awake = priv->stations[sta_id].
@@ -3813,7 +2544,7 @@
* proper operation with 4965.
*/
static void iwl4965_dbg_report_frame(struct iwl_priv *priv,
- struct iwl4965_rx_packet *pkt,
+ struct iwl_rx_packet *pkt,
struct ieee80211_hdr *header, int group100)
{
u32 to_us;
@@ -3840,7 +2571,7 @@
struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt);
u8 *data = IWL_RX_DATA(pkt);
- if (likely(!(iwl_debug_level & IWL_DL_RX)))
+ if (likely(!(priv->debug_level & IWL_DL_RX)))
return;
/* MAC header */
@@ -3921,7 +2652,7 @@
if (unlikely(rate_idx == -1))
bitrate = 0;
else
- bitrate = iwl4965_rates[rate_idx].ieee / 2;
+ bitrate = iwl_rates[rate_idx].ieee / 2;
/* print frame summary.
* MAC addresses show just the last byte (for brevity),
@@ -3943,11 +2674,11 @@
}
}
if (print_dump)
- iwl_print_hex_dump(IWL_DL_RX, data, length);
+ iwl_print_hex_dump(priv, IWL_DL_RX, data, length);
}
#else
static inline void iwl4965_dbg_report_frame(struct iwl_priv *priv,
- struct iwl4965_rx_packet *pkt,
+ struct iwl_rx_packet *pkt,
struct ieee80211_hdr *header,
int group100)
{
@@ -3958,12 +2689,12 @@
/* Called for REPLY_RX (legacy ABG frames), or
* REPLY_RX_MPDU_CMD (HT high-throughput N frames). */
-static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
- struct iwl4965_rx_mem_buffer *rxb)
+void iwl4965_rx_reply_rx(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
{
struct ieee80211_hdr *header;
struct ieee80211_rx_status rx_status;
- struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
/* Use phy data (Rx signal strength, etc.) contained within
* this rx packet for legacy frames,
* or phy data cached from REPLY_RX_PHY_CMD for HT frames. */
@@ -4036,7 +2767,7 @@
priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp);
/* Find max signal strength (dBm) among 3 antenna/receiver chains */
- rx_status.ssi = iwl4965_calc_rssi(rx_start);
+ rx_status.signal = iwl4965_calc_rssi(priv, rx_start);
/* Meaningful noise values are available only from beacon statistics,
* which are gathered only when associated, and indicate noise
@@ -4045,11 +2776,11 @@
if (iwl_is_associated(priv) &&
!test_bit(STATUS_SCANNING, &priv->status)) {
rx_status.noise = priv->last_rx_noise;
- rx_status.signal = iwl4965_calc_sig_qual(rx_status.ssi,
+ rx_status.qual = iwl4965_calc_sig_qual(rx_status.signal,
rx_status.noise);
} else {
rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
- rx_status.signal = iwl4965_calc_sig_qual(rx_status.ssi, 0);
+ rx_status.qual = iwl4965_calc_sig_qual(rx_status.signal, 0);
}
/* Reset beacon noise level if not associated. */
@@ -4061,12 +2792,19 @@
iwl4965_dbg_report_frame(priv, pkt, header, 1);
IWL_DEBUG_STATS_LIMIT("Rssi %d, noise %d, qual %d, TSF %llu\n",
- rx_status.ssi, rx_status.noise, rx_status.signal,
+ rx_status.signal, rx_status.noise, rx_status.signal,
(unsigned long long)rx_status.mactime);
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
+ iwl4965_handle_data_packet(priv, 1, include_phy,
+ rxb, &rx_status);
+ return;
+ }
+
network_packet = iwl4965_is_network_packet(priv, header);
if (network_packet) {
- priv->last_rx_rssi = rx_status.ssi;
+ priv->last_rx_rssi = rx_status.signal;
priv->last_beacon_time = priv->ucode_beacon_time;
priv->last_tsf = le64_to_cpu(rx_start->timestamp);
}
@@ -4125,65 +2863,16 @@
}
}
-/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD).
- * This will be used later in iwl4965_rx_reply_rx() for REPLY_RX_MPDU_CMD. */
-static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv,
- struct iwl4965_rx_mem_buffer *rxb)
-{
- struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
- priv->last_phy_res[0] = 1;
- memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]),
- sizeof(struct iwl4965_rx_phy_res));
-}
-static void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv,
- struct iwl4965_rx_mem_buffer *rxb)
-
-{
-#ifdef CONFIG_IWL4965_SENSITIVITY
- struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
- struct iwl4965_missed_beacon_notif *missed_beacon;
-
- missed_beacon = &pkt->u.missed_beacon;
- if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) {
- IWL_DEBUG_CALIB("missed bcn cnsq %d totl %d rcd %d expctd %d\n",
- le32_to_cpu(missed_beacon->consequtive_missed_beacons),
- le32_to_cpu(missed_beacon->total_missed_becons),
- le32_to_cpu(missed_beacon->num_recvd_beacons),
- le32_to_cpu(missed_beacon->num_expected_beacons));
- priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT;
- if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)))
- queue_work(priv->workqueue, &priv->sensitivity_work);
- }
-#endif /*CONFIG_IWL4965_SENSITIVITY*/
-}
#ifdef CONFIG_IWL4965_HT
/**
- * iwl4965_sta_modify_enable_tid_tx - Enable Tx for this TID in station table
- */
-static void iwl4965_sta_modify_enable_tid_tx(struct iwl_priv *priv,
- int sta_id, int tid)
-{
- unsigned long flags;
-
- /* Remove "disable" flag, to enable Tx for this TID */
- spin_lock_irqsave(&priv->sta_lock, flags);
- priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX;
- priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid));
- priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-
- iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
-}
-
-/**
* iwl4965_tx_status_reply_compressed_ba - Update tx status from block-ack
*
* Go through block-ack's bitmap of ACK'd frames, update driver's record of
* ACK vs. not. This gets sent to mac80211, then to rate scaling algo.
*/
static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv,
- struct iwl4965_ht_agg *agg,
+ struct iwl_ht_agg *agg,
struct iwl4965_compressed_ba_resp*
ba_resp)
@@ -4193,7 +2882,7 @@
u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
u64 bitmap;
int successes = 0;
- struct ieee80211_tx_status *tx_status;
+ struct ieee80211_tx_info *info;
if (unlikely(!agg->wait_for_ba)) {
IWL_ERROR("Received BA when not expected\n");
@@ -4231,13 +2920,13 @@
agg->start_idx + i);
}
- tx_status = &priv->txq[scd_flow].txb[agg->start_idx].status;
- tx_status->flags = IEEE80211_TX_STATUS_ACK;
- tx_status->flags |= IEEE80211_TX_STATUS_AMPDU;
- tx_status->ampdu_ack_map = successes;
- tx_status->ampdu_ack_len = agg->frame_count;
- iwl4965_hwrate_to_tx_control(priv, agg->rate_n_flags,
- &tx_status->control);
+ info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]);
+ memset(&info->status, 0, sizeof(info->status));
+ info->flags = IEEE80211_TX_STAT_ACK;
+ info->flags |= IEEE80211_TX_STAT_AMPDU;
+ info->status.ampdu_ack_map = successes;
+ info->status.ampdu_ack_len = agg->frame_count;
+ iwl4965_hwrate_to_tx_control(priv, agg->rate_n_flags, info);
IWL_DEBUG_TX_REPLY("Bitmap %llx\n", (unsigned long long)bitmap);
@@ -4254,16 +2943,16 @@
* the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */
iwl_write_prph(priv,
IWL49_SCD_QUEUE_STATUS_BITS(txq_id),
- (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
- (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
+ (0 << IWL49_SCD_QUEUE_STTS_REG_POS_ACTIVE)|
+ (1 << IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
}
/**
* txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID
* priv->lock must be held by the caller
*/
-static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id,
- u16 ssn_idx, u8 tx_fifo)
+static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
+ u16 ssn_idx, u8 tx_fifo)
{
int ret = 0;
@@ -4287,7 +2976,7 @@
iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx);
iwl_clear_bits_prph(priv, IWL49_SCD_INTERRUPT_MASK, (1 << txq_id));
- iwl4965_txq_ctx_deactivate(priv, txq_id);
+ iwl_txq_ctx_deactivate(priv, txq_id);
iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0);
iwl_release_nic_access(priv);
@@ -4295,49 +2984,6 @@
return 0;
}
-int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id,
- u8 tid, int txq_id)
-{
- struct iwl4965_queue *q = &priv->txq[txq_id].q;
- u8 *addr = priv->stations[sta_id].sta.sta.addr;
- struct iwl4965_tid_data *tid_data = &priv->stations[sta_id].tid[tid];
-
- switch (priv->stations[sta_id].tid[tid].agg.state) {
- case IWL_EMPTYING_HW_QUEUE_DELBA:
- /* We are reclaiming the last packet of the */
- /* aggregated HW queue */
- if (txq_id == tid_data->agg.txq_id &&
- q->read_ptr == q->write_ptr) {
- u16 ssn = SEQ_TO_SN(tid_data->seq_number);
- int tx_fifo = default_tid_to_tx_fifo[tid];
- IWL_DEBUG_HT("HW queue empty: continue DELBA flow\n");
- iwl4965_tx_queue_agg_disable(priv, txq_id,
- ssn, tx_fifo);
- tid_data->agg.state = IWL_AGG_OFF;
- ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, addr, tid);
- }
- break;
- case IWL_EMPTYING_HW_QUEUE_ADDBA:
- /* We are reclaiming the last packet of the queue */
- if (tid_data->tfds_in_queue == 0) {
- IWL_DEBUG_HT("HW queue empty: continue ADDBA flow\n");
- tid_data->agg.state = IWL_AGG_ON;
- ieee80211_start_tx_ba_cb_irqsafe(priv->hw, addr, tid);
- }
- break;
- }
- return 0;
-}
-
-/**
- * iwl4965_queue_dec_wrap - Decrement queue index, wrap back to end if needed
- * @index -- current index
- * @n_bd -- total number of entries in queue (s/b power of 2)
- */
-static inline int iwl4965_queue_dec_wrap(int index, int n_bd)
-{
- return (index == 0) ? n_bd - 1 : index - 1;
-}
/**
* iwl4965_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA
@@ -4346,13 +2992,13 @@
* of frames sent via aggregation.
*/
static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv,
- struct iwl4965_rx_mem_buffer *rxb)
+ struct iwl_rx_mem_buffer *rxb)
{
- struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
struct iwl4965_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba;
int index;
- struct iwl4965_tx_queue *txq = NULL;
- struct iwl4965_ht_agg *agg;
+ struct iwl_tx_queue *txq = NULL;
+ struct iwl_ht_agg *agg;
DECLARE_MAC_BUF(mac);
/* "flow" corresponds to Tx queue */
@@ -4371,7 +3017,7 @@
agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg;
/* Find index just before block-ack window */
- index = iwl4965_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd);
+ index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd);
/* TODO: Need to get this copy more safely - now good for debug */
@@ -4398,15 +3044,19 @@
* block-ack window (we assume that they've been successfully
* transmitted ... if not, it's too late anyway). */
if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) {
- int freed = iwl4965_tx_queue_reclaim(priv, scd_flow, index);
+ /* calculate mac80211 ampdu sw queue to wake */
+ int ampdu_q =
+ scd_flow - IWL_BACK_QUEUE_FIRST_ID + priv->hw->queues;
+ int freed = iwl_tx_queue_reclaim(priv, scd_flow, index);
priv->stations[ba_resp->sta_id].
tid[ba_resp->tid].tfds_in_queue -= freed;
- if (iwl4965_queue_space(&txq->q) > txq->q.low_mark &&
+ if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
priv->mac80211_registered &&
agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)
- ieee80211_wake_queue(priv->hw, scd_flow);
- iwl4965_check_empty_hw_queue(priv, ba_resp->sta_id,
- ba_resp->tid, scd_flow);
+ ieee80211_wake_queue(priv->hw, ampdu_q);
+
+ iwl_txq_check_empty(priv, ba_resp->sta_id,
+ ba_resp->tid, scd_flow);
}
}
@@ -4420,10 +3070,10 @@
u32 tbl_dw;
u16 scd_q2ratid;
- scd_q2ratid = ra_tid & SCD_QUEUE_RA_TID_MAP_RATID_MSK;
+ scd_q2ratid = ra_tid & IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK;
tbl_dw_addr = priv->scd_base_addr +
- SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id);
+ IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id);
tbl_dw = iwl_read_targ_mem(priv, tbl_dw_addr);
@@ -4444,12 +3094,11 @@
* NOTE: txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID,
* i.e. it must be one of the higher queues used for aggregation
*/
-static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id,
- int tx_fifo, int sta_id, int tid,
- u16 ssn_idx)
+static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id,
+ int tx_fifo, int sta_id, int tid, u16 ssn_idx)
{
unsigned long flags;
- int rc;
+ int ret;
u16 ra_tid;
if (IWL_BACK_QUEUE_FIRST_ID > txq_id)
@@ -4459,13 +3108,13 @@
ra_tid = BUILD_RAxTID(sta_id, tid);
/* Modify device's station table to Tx this TID */
- iwl4965_sta_modify_enable_tid_tx(priv, sta_id, tid);
+ iwl_sta_modify_enable_tid_tx(priv, sta_id, tid);
spin_lock_irqsave(&priv->lock, flags);
- rc = iwl_grab_nic_access(priv);
- if (rc) {
+ ret = iwl_grab_nic_access(priv);
+ if (ret) {
spin_unlock_irqrestore(&priv->lock, flags);
- return rc;
+ return ret;
}
/* Stop this Tx queue before configuring it */
@@ -4485,14 +3134,14 @@
/* Set up Tx window size and frame limit for this queue */
iwl_write_targ_mem(priv,
- priv->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(txq_id),
- (SCD_WIN_SIZE << SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) &
- SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK);
+ priv->scd_base_addr + IWL49_SCD_CONTEXT_QUEUE_OFFSET(txq_id),
+ (SCD_WIN_SIZE << IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) &
+ IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK);
iwl_write_targ_mem(priv, priv->scd_base_addr +
- SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32),
- (SCD_FRAME_LIMIT << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS)
- & SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK);
+ IWL49_SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32),
+ (SCD_FRAME_LIMIT << IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS)
+ & IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK);
iwl_set_bits_prph(priv, IWL49_SCD_INTERRUPT_MASK, (1 << txq_id));
@@ -4507,209 +3156,17 @@
#endif /* CONFIG_IWL4965_HT */
-/**
- * iwl4965_add_station - Initialize a station's hardware rate table
- *
- * The uCode's station table contains a table of fallback rates
- * for automatic fallback during transmission.
- *
- * NOTE: This sets up a default set of values. These will be replaced later
- * if the driver's iwl-4965-rs rate scaling algorithm is used, instead of
- * rc80211_simple.
- *
- * NOTE: Run REPLY_ADD_STA command to set up station table entry, before
- * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD,
- * which requires station table entry to exist).
- */
-void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
-{
- int i, r;
- struct iwl_link_quality_cmd link_cmd = {
- .reserved1 = 0,
- };
- u16 rate_flags;
-
- /* Set up the rate scaling to start at selected rate, fall back
- * all the way down to 1M in IEEE order, and then spin on 1M */
- if (is_ap)
- r = IWL_RATE_54M_INDEX;
- else if (priv->band == IEEE80211_BAND_5GHZ)
- r = IWL_RATE_6M_INDEX;
- else
- r = IWL_RATE_1M_INDEX;
-
- for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
- rate_flags = 0;
- if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
- rate_flags |= RATE_MCS_CCK_MSK;
-
- /* Use Tx antenna B only */
- rate_flags |= RATE_MCS_ANT_B_MSK;
- rate_flags &= ~RATE_MCS_ANT_A_MSK;
-
- link_cmd.rs_table[i].rate_n_flags =
- iwl4965_hw_set_rate_n_flags(iwl4965_rates[r].plcp, rate_flags);
- r = iwl4965_get_prev_ieee_rate(r);
- }
-
- link_cmd.general_params.single_stream_ant_msk = 2;
- link_cmd.general_params.dual_stream_ant_msk = 3;
- link_cmd.agg_params.agg_dis_start_th = 3;
- link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000);
-
- /* Update the rate scaling for control frame Tx to AP */
- link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id;
-
- iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD,
- sizeof(link_cmd), &link_cmd, NULL);
-}
#ifdef CONFIG_IWL4965_HT
-
-static u8 iwl4965_is_channel_extension(struct iwl_priv *priv,
- enum ieee80211_band band,
- u16 channel, u8 extension_chan_offset)
-{
- const struct iwl_channel_info *ch_info;
-
- ch_info = iwl_get_channel_info(priv, band, channel);
- if (!is_channel_valid(ch_info))
- return 0;
-
- if (extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_NONE)
- return 0;
-
- if ((ch_info->fat_extension_channel == extension_chan_offset) ||
- (ch_info->fat_extension_channel == HT_IE_EXT_CHANNEL_MAX))
- return 1;
-
- return 0;
-}
-
-static u8 iwl4965_is_fat_tx_allowed(struct iwl_priv *priv,
- struct ieee80211_ht_info *sta_ht_inf)
-{
- struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config;
-
- if ((!iwl_ht_conf->is_ht) ||
- (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) ||
- (iwl_ht_conf->extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_NONE))
- return 0;
-
- if (sta_ht_inf) {
- if ((!sta_ht_inf->ht_supported) ||
- (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH)))
- return 0;
- }
-
- return (iwl4965_is_channel_extension(priv, priv->band,
- iwl_ht_conf->control_channel,
- iwl_ht_conf->extension_chan_offset));
-}
-
-void iwl4965_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
-{
- struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon;
- u32 val;
-
- if (!ht_info->is_ht)
- return;
-
- /* Set up channel bandwidth: 20 MHz only, or 20/40 mixed if fat ok */
- if (iwl4965_is_fat_tx_allowed(priv, NULL))
- rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK;
- else
- rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
- RXON_FLG_CHANNEL_MODE_PURE_40_MSK);
-
- if (le16_to_cpu(rxon->channel) != ht_info->control_channel) {
- IWL_DEBUG_ASSOC("control diff than current %d %d\n",
- le16_to_cpu(rxon->channel),
- ht_info->control_channel);
- rxon->channel = cpu_to_le16(ht_info->control_channel);
- return;
- }
-
- /* Note: control channel is opposite of extension channel */
- switch (ht_info->extension_chan_offset) {
- case IWL_EXT_CHANNEL_OFFSET_ABOVE:
- rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
- break;
- case IWL_EXT_CHANNEL_OFFSET_BELOW:
- rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
- break;
- case IWL_EXT_CHANNEL_OFFSET_NONE:
- default:
- rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK;
- break;
- }
-
- val = ht_info->ht_protection;
-
- rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS);
-
- iwl4965_set_rxon_chain(priv);
-
- IWL_DEBUG_ASSOC("supported HT rate 0x%X %X "
- "rxon flags 0x%X operation mode :0x%X "
- "extension channel offset 0x%x "
- "control chan %d\n",
- ht_info->supp_mcs_set[0], ht_info->supp_mcs_set[1],
- le32_to_cpu(rxon->flags), ht_info->ht_protection,
- ht_info->extension_chan_offset,
- ht_info->control_channel);
- return;
-}
-
-void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index,
- struct ieee80211_ht_info *sta_ht_inf)
-{
- __le32 sta_flags;
- u8 mimo_ps_mode;
-
- if (!sta_ht_inf || !sta_ht_inf->ht_supported)
- goto done;
-
- mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2;
-
- sta_flags = priv->stations[index].sta.station_flags;
-
- sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK);
-
- switch (mimo_ps_mode) {
- case WLAN_HT_CAP_MIMO_PS_STATIC:
- sta_flags |= STA_FLG_MIMO_DIS_MSK;
- break;
- case WLAN_HT_CAP_MIMO_PS_DYNAMIC:
- sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK;
- break;
- case WLAN_HT_CAP_MIMO_PS_DISABLED:
- break;
- default:
- IWL_WARNING("Invalid MIMO PS mode %d", mimo_ps_mode);
- break;
- }
-
- sta_flags |= cpu_to_le32(
- (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS);
-
- sta_flags |= cpu_to_le32(
- (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
-
- if (iwl4965_is_fat_tx_allowed(priv, sta_ht_inf))
- sta_flags |= STA_FLG_FAT_EN_MSK;
- else
- sta_flags &= ~STA_FLG_FAT_EN_MSK;
-
- priv->stations[index].sta.station_flags = sta_flags;
- done:
- return;
-}
-
-static void iwl4965_sta_modify_add_ba_tid(struct iwl_priv *priv,
- int sta_id, int tid, u16 ssn)
+static int iwl4965_rx_agg_start(struct iwl_priv *priv,
+ const u8 *addr, int tid, u16 ssn)
{
unsigned long flags;
+ int sta_id;
+
+ sta_id = iwl_find_station(priv, addr);
+ if (sta_id == IWL_INVALID_STATION)
+ return -ENXIO;
spin_lock_irqsave(&priv->sta_lock, flags);
priv->stations[sta_id].sta.station_flags_msk = 0;
@@ -4719,13 +3176,19 @@
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
spin_unlock_irqrestore(&priv->sta_lock, flags);
- iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+ return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
+ CMD_ASYNC);
}
-static void iwl4965_sta_modify_del_ba_tid(struct iwl_priv *priv,
- int sta_id, int tid)
+static int iwl4965_rx_agg_stop(struct iwl_priv *priv,
+ const u8 *addr, int tid)
{
unsigned long flags;
+ int sta_id;
+
+ sta_id = iwl_find_station(priv, addr);
+ if (sta_id == IWL_INVALID_STATION)
+ return -ENXIO;
spin_lock_irqsave(&priv->sta_lock, flags);
priv->stations[sta_id].sta.station_flags_msk = 0;
@@ -4734,143 +3197,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);
-}
-
-/*
- * Find first available (lowest unused) Tx Queue, mark it "active".
- * Called only when finding queue for aggregation.
- * Should never return anything < 7, because they should already
- * be in use as EDCA AC (0-3), Command (4), HCCA (5, 6).
- */
-static int iwl4965_txq_ctx_activate_free(struct iwl_priv *priv)
-{
- int txq_id;
-
- for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
- if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk))
- return txq_id;
- return -1;
-}
-
-static int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, const u8 *da,
- u16 tid, u16 *start_seq_num)
-{
- struct iwl_priv *priv = hw->priv;
- int sta_id;
- int tx_fifo;
- int txq_id;
- int ssn = -1;
- int ret = 0;
- unsigned long flags;
- struct iwl4965_tid_data *tid_data;
- DECLARE_MAC_BUF(mac);
-
- if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
- tx_fifo = default_tid_to_tx_fifo[tid];
- else
- return -EINVAL;
-
- IWL_WARNING("%s on da = %s tid = %d\n",
- __func__, print_mac(mac, da), tid);
-
- sta_id = iwl4965_hw_find_station(priv, da);
- if (sta_id == IWL_INVALID_STATION)
- return -ENXIO;
-
- if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) {
- IWL_ERROR("Start AGG when state is not IWL_AGG_OFF !\n");
- return -ENXIO;
- }
-
- txq_id = iwl4965_txq_ctx_activate_free(priv);
- if (txq_id == -1)
- return -ENXIO;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
- tid_data = &priv->stations[sta_id].tid[tid];
- ssn = SEQ_TO_SN(tid_data->seq_number);
- tid_data->agg.txq_id = txq_id;
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-
- *start_seq_num = ssn;
- ret = iwl4965_tx_queue_agg_enable(priv, txq_id, tx_fifo,
- sta_id, tid, ssn);
- if (ret)
- return ret;
-
- ret = 0;
- if (tid_data->tfds_in_queue == 0) {
- printk(KERN_ERR "HW queue is empty\n");
- tid_data->agg.state = IWL_AGG_ON;
- ieee80211_start_tx_ba_cb_irqsafe(hw, da, tid);
- } else {
- IWL_DEBUG_HT("HW queue is NOT empty: %d packets in HW queue\n",
- tid_data->tfds_in_queue);
- tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
- }
- return ret;
-}
-
-static int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, const u8 *da,
- u16 tid)
-{
-
- struct iwl_priv *priv = hw->priv;
- int tx_fifo_id, txq_id, sta_id, ssn = -1;
- struct iwl4965_tid_data *tid_data;
- int ret, write_ptr, read_ptr;
- unsigned long flags;
- DECLARE_MAC_BUF(mac);
-
- if (!da) {
- IWL_ERROR("da = NULL\n");
- return -EINVAL;
- }
-
- if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
- tx_fifo_id = default_tid_to_tx_fifo[tid];
- else
- return -EINVAL;
-
- sta_id = iwl4965_hw_find_station(priv, da);
-
- if (sta_id == IWL_INVALID_STATION)
- return -ENXIO;
-
- if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON)
- IWL_WARNING("Stopping AGG while state not IWL_AGG_ON\n");
-
- tid_data = &priv->stations[sta_id].tid[tid];
- ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4;
- txq_id = tid_data->agg.txq_id;
- write_ptr = priv->txq[txq_id].q.write_ptr;
- read_ptr = priv->txq[txq_id].q.read_ptr;
-
- /* The queue is not empty */
- if (write_ptr != read_ptr) {
- IWL_DEBUG_HT("Stopping a non empty AGG HW QUEUE\n");
- priv->stations[sta_id].tid[tid].agg.state =
- IWL_EMPTYING_HW_QUEUE_DELBA;
- return 0;
- }
-
- IWL_DEBUG_HT("HW queue empty\n");;
- priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
-
- spin_lock_irqsave(&priv->lock, flags);
- ret = iwl4965_tx_queue_agg_disable(priv, txq_id, ssn, tx_fifo_id);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- if (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);
-
- return 0;
+ return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
+ CMD_ASYNC);
}
int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
@@ -4878,27 +3206,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 iwl_tx_agg_start(priv, 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 iwl_tx_agg_stop(priv, addr, tid);
default:
IWL_DEBUG_HT("unknown\n");
return -EINVAL;
@@ -4906,21 +3231,288 @@
}
return 0;
}
-
#endif /* CONFIG_IWL4965_HT */
+
+static u16 iwl4965_get_hcmd_size(u8 cmd_id, u16 len)
+{
+ switch (cmd_id) {
+ case REPLY_RXON:
+ return (u16) sizeof(struct iwl4965_rxon_cmd);
+ default:
+ return len;
+ }
+}
+
+static u16 iwl4965_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
+{
+ struct iwl4965_addsta_cmd *addsta = (struct iwl4965_addsta_cmd *)data;
+ addsta->mode = cmd->mode;
+ memcpy(&addsta->sta, &cmd->sta, sizeof(struct sta_id_modify));
+ memcpy(&addsta->key, &cmd->key, sizeof(struct iwl4965_keyinfo));
+ addsta->station_flags = cmd->station_flags;
+ addsta->station_flags_msk = cmd->station_flags_msk;
+ addsta->tid_disable_tx = cmd->tid_disable_tx;
+ addsta->add_immediate_ba_tid = cmd->add_immediate_ba_tid;
+ addsta->remove_immediate_ba_tid = cmd->remove_immediate_ba_tid;
+ addsta->add_immediate_ba_ssn = cmd->add_immediate_ba_ssn;
+ addsta->reserved1 = __constant_cpu_to_le16(0);
+ addsta->reserved2 = __constant_cpu_to_le32(0);
+
+ return (u16)sizeof(struct iwl4965_addsta_cmd);
+}
+
+#ifdef CONFIG_IWL4965_HT
+static inline u32 iwl4965_get_scd_ssn(struct iwl4965_tx_resp *tx_resp)
+{
+ __le32 *scd_ssn = (__le32 *)((u32 *)&tx_resp->status +
+ tx_resp->frame_count);
+ return le32_to_cpu(*scd_ssn) & MAX_SN;
+
+}
+
+/**
+ * iwl4965_tx_status_reply_tx - Handle Tx rspnse for frames in aggregation queue
+ */
+static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
+ struct iwl_ht_agg *agg,
+ struct iwl4965_tx_resp_agg *tx_resp,
+ u16 start_idx)
+{
+ u16 status;
+ struct agg_tx_status *frame_status = &tx_resp->status;
+ struct ieee80211_tx_info *info = NULL;
+ struct ieee80211_hdr *hdr = NULL;
+ int i, sh;
+ int txq_id, idx;
+ u16 seq;
+
+ if (agg->wait_for_ba)
+ IWL_DEBUG_TX_REPLY("got tx response w/o block-ack\n");
+
+ agg->frame_count = tx_resp->frame_count;
+ agg->start_idx = start_idx;
+ agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
+ agg->bitmap = 0;
+
+ /* # frames attempted by Tx command */
+ if (agg->frame_count == 1) {
+ /* Only one frame was attempted; no block-ack will arrive */
+ status = le16_to_cpu(frame_status[0].status);
+ seq = le16_to_cpu(frame_status[0].sequence);
+ idx = SEQ_TO_INDEX(seq);
+ txq_id = SEQ_TO_QUEUE(seq);
+
+ /* FIXME: code repetition */
+ IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n",
+ agg->frame_count, agg->start_idx, idx);
+
+ info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
+ info->status.retry_count = tx_resp->failure_frame;
+ info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+ info->flags |= iwl_is_tx_success(status)?
+ IEEE80211_TX_STAT_ACK : 0;
+ iwl4965_hwrate_to_tx_control(priv,
+ le32_to_cpu(tx_resp->rate_n_flags),
+ info);
+ /* FIXME: code repetition end */
+
+ IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n",
+ status & 0xff, tx_resp->failure_frame);
+ IWL_DEBUG_TX_REPLY("Rate Info rate_n_flags=%x\n",
+ iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags));
+
+ agg->wait_for_ba = 0;
+ } else {
+ /* Two or more frames were attempted; expect block-ack */
+ u64 bitmap = 0;
+ int start = agg->start_idx;
+
+ /* Construct bit-map of pending frames within Tx window */
+ for (i = 0; i < agg->frame_count; i++) {
+ u16 sc;
+ status = le16_to_cpu(frame_status[i].status);
+ seq = le16_to_cpu(frame_status[i].sequence);
+ idx = SEQ_TO_INDEX(seq);
+ txq_id = SEQ_TO_QUEUE(seq);
+
+ if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
+ AGG_TX_STATE_ABORT_MSK))
+ continue;
+
+ IWL_DEBUG_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n",
+ agg->frame_count, txq_id, idx);
+
+ hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx);
+
+ sc = le16_to_cpu(hdr->seq_ctrl);
+ if (idx != (SEQ_TO_SN(sc) & 0xff)) {
+ IWL_ERROR("BUG_ON idx doesn't match seq control"
+ " idx=%d, seq_idx=%d, seq=%d\n",
+ idx, SEQ_TO_SN(sc),
+ hdr->seq_ctrl);
+ return -1;
+ }
+
+ IWL_DEBUG_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n",
+ i, idx, SEQ_TO_SN(sc));
+
+ sh = idx - start;
+ if (sh > 64) {
+ sh = (start - idx) + 0xff;
+ bitmap = bitmap << sh;
+ sh = 0;
+ start = idx;
+ } else if (sh < -64)
+ sh = 0xff - (start - idx);
+ else if (sh < 0) {
+ sh = start - idx;
+ start = idx;
+ bitmap = bitmap << sh;
+ sh = 0;
+ }
+ bitmap |= (1 << sh);
+ IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%x\n",
+ start, (u32)(bitmap & 0xFFFFFFFF));
+ }
+
+ agg->bitmap = bitmap;
+ agg->start_idx = start;
+ agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
+ IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n",
+ agg->frame_count, agg->start_idx,
+ (unsigned long long)agg->bitmap);
+
+ if (bitmap)
+ agg->wait_for_ba = 1;
+ }
+ return 0;
+}
+#endif
+
+/**
+ * iwl4965_rx_reply_tx - Handle standard (non-aggregation) Tx response
+ */
+static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+ int txq_id = SEQ_TO_QUEUE(sequence);
+ int index = SEQ_TO_INDEX(sequence);
+ struct iwl_tx_queue *txq = &priv->txq[txq_id];
+ struct ieee80211_tx_info *info;
+ struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
+ u32 status = le32_to_cpu(tx_resp->status);
+#ifdef CONFIG_IWL4965_HT
+ int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION;
+ u16 fc;
+ struct ieee80211_hdr *hdr;
+ u8 *qc = NULL;
+#endif
+
+ if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
+ IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
+ "is out of range [0-%d] %d %d\n", txq_id,
+ index, txq->q.n_bd, txq->q.write_ptr,
+ txq->q.read_ptr);
+ return;
+ }
+
+ info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
+ memset(&info->status, 0, sizeof(info->status));
+
+#ifdef CONFIG_IWL4965_HT
+ hdr = iwl_tx_queue_get_hdr(priv, txq_id, index);
+ fc = le16_to_cpu(hdr->frame_control);
+ if (ieee80211_is_qos_data(fc)) {
+ qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc));
+ tid = qc[0] & 0xf;
+ }
+
+ sta_id = iwl_get_ra_sta_id(priv, hdr);
+ if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) {
+ IWL_ERROR("Station not known\n");
+ return;
+ }
+
+ if (txq->sched_retry) {
+ const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp);
+ struct iwl_ht_agg *agg = NULL;
+
+ if (!qc)
+ return;
+
+ agg = &priv->stations[sta_id].tid[tid].agg;
+
+ iwl4965_tx_status_reply_tx(priv, agg,
+ (struct iwl4965_tx_resp_agg *)tx_resp, index);
+
+ if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status)) {
+ /* TODO: send BAR */
+ }
+
+ if (txq->q.read_ptr != (scd_ssn & 0xff)) {
+ int freed, ampdu_q;
+ index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
+ IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn "
+ "%d index %d\n", scd_ssn , index);
+ freed = iwl_tx_queue_reclaim(priv, txq_id, index);
+ priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+
+ if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
+ txq_id >= 0 && priv->mac80211_registered &&
+ agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) {
+ /* calculate mac80211 ampdu sw queue to wake */
+ ampdu_q = txq_id - IWL_BACK_QUEUE_FIRST_ID +
+ priv->hw->queues;
+ if (agg->state == IWL_AGG_OFF)
+ ieee80211_wake_queue(priv->hw, txq_id);
+ else
+ ieee80211_wake_queue(priv->hw, ampdu_q);
+ }
+ iwl_txq_check_empty(priv, sta_id, tid, txq_id);
+ }
+ } else {
+#endif /* CONFIG_IWL4965_HT */
+
+ info->status.retry_count = tx_resp->failure_frame;
+ info->flags |= iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0;
+ iwl4965_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags),
+ info);
+
+ IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x "
+ "retries %d\n", txq_id, iwl_get_tx_fail_reason(status),
+ status, le32_to_cpu(tx_resp->rate_n_flags),
+ tx_resp->failure_frame);
+
+ IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
+#ifdef CONFIG_IWL4965_HT
+ if (index != -1) {
+ int freed = iwl_tx_queue_reclaim(priv, txq_id, index);
+ if (tid != MAX_TID_COUNT)
+ priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+ if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
+ (txq_id >= 0) && priv->mac80211_registered)
+ ieee80211_wake_queue(priv->hw, txq_id);
+ if (tid != MAX_TID_COUNT)
+ iwl_txq_check_empty(priv, sta_id, tid, txq_id);
+ }
+ }
+#endif /* CONFIG_IWL4965_HT */
+
+ if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
+ IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n");
+}
+
+
/* Set up 4965-specific Rx frame reply handlers */
-void iwl4965_hw_rx_handler_setup(struct iwl_priv *priv)
+static void iwl4965_rx_handler_setup(struct iwl_priv *priv)
{
/* Legacy Rx frames */
priv->rx_handlers[REPLY_RX] = iwl4965_rx_reply_rx;
-
- /* High-throughput (HT) Rx frames */
- priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl4965_rx_reply_rx_phy;
- priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl4965_rx_reply_rx;
-
- priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] =
- iwl4965_rx_missed_beacon_notif;
+ /* Tx response */
+ priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx;
#ifdef CONFIG_IWL4965_HT
priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl4965_rx_reply_compressed_ba;
@@ -4930,7 +3522,7 @@
void iwl4965_hw_setup_deferred_work(struct iwl_priv *priv)
{
INIT_WORK(&priv->txpower_work, iwl4965_bg_txpower_work);
-#ifdef CONFIG_IWL4965_SENSITIVITY
+#ifdef CONFIG_IWL4965_RUN_TIME_CALIB
INIT_WORK(&priv->sensitivity_work, iwl4965_bg_sensitivity_work);
#endif
init_timer(&priv->statistics_periodic);
@@ -4951,23 +3543,56 @@
};
static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
- .enqueue_hcmd = iwl4965_enqueue_hcmd,
+ .get_hcmd_size = iwl4965_get_hcmd_size,
+ .build_addsta_hcmd = iwl4965_build_addsta_hcmd,
+#ifdef CONFIG_IWL4965_RUN_TIME_CALIB
+ .chain_noise_reset = iwl4965_chain_noise_reset,
+ .gain_computation = iwl4965_gain_computation,
+#endif
};
static struct iwl_lib_ops iwl4965_lib = {
- .init_drv = iwl4965_init_drv,
.set_hw_params = iwl4965_hw_set_hw_params,
+ .alloc_shared_mem = iwl4965_alloc_shared_mem,
+ .free_shared_mem = iwl4965_free_shared_mem,
+ .shared_mem_rx_idx = iwl4965_shared_mem_rx_idx,
.txq_update_byte_cnt_tbl = iwl4965_txq_update_byte_cnt_tbl,
- .hw_nic_init = iwl4965_hw_nic_init,
+ .txq_set_sched = iwl4965_txq_set_sched,
+#ifdef CONFIG_IWL4965_HT
+ .txq_agg_enable = iwl4965_txq_agg_enable,
+ .txq_agg_disable = iwl4965_txq_agg_disable,
+#endif
+ .rx_handler_setup = iwl4965_rx_handler_setup,
.is_valid_rtc_data_addr = iwl4965_hw_valid_rtc_data_addr,
.alive_notify = iwl4965_alive_notify,
+ .init_alive_start = iwl4965_init_alive_start,
.load_ucode = iwl4965_load_bsm,
+ .apm_ops = {
+ .init = iwl4965_apm_init,
+ .reset = iwl4965_apm_reset,
+ .stop = iwl4965_apm_stop,
+ .config = iwl4965_nic_config,
+ .set_pwr_src = iwl4965_set_pwr_src,
+ },
.eeprom_ops = {
+ .regulatory_bands = {
+ EEPROM_REGULATORY_BAND_1_CHANNELS,
+ EEPROM_REGULATORY_BAND_2_CHANNELS,
+ EEPROM_REGULATORY_BAND_3_CHANNELS,
+ EEPROM_REGULATORY_BAND_4_CHANNELS,
+ EEPROM_REGULATORY_BAND_5_CHANNELS,
+ EEPROM_4965_REGULATORY_BAND_24_FAT_CHANNELS,
+ EEPROM_4965_REGULATORY_BAND_52_FAT_CHANNELS
+ },
.verify_signature = iwlcore_eeprom_verify_signature,
.acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
.release_semaphore = iwlcore_eeprom_release_semaphore,
+ .check_version = iwl4965_eeprom_check_version,
+ .query_addr = iwlcore_eeprom_query_addr,
},
.radio_kill_sw = iwl4965_radio_kill_sw,
+ .set_power = iwl4965_set_power,
+ .update_chain_flags = iwl4965_update_chain_flags,
};
static struct iwl_ops iwl4965_ops = {
@@ -4980,6 +3605,7 @@
.name = "4965AGN",
.fw_name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode",
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+ .eeprom_size = IWL4965_EEPROM_IMG_SIZE,
.ops = &iwl4965_ops,
.mod_params = &iwl4965_mod_params,
};
@@ -5004,4 +3630,5 @@
MODULE_PARM_DESC(qos_enable, "enable all QoS functionality");
module_param_named(amsdu_size_8K, iwl4965_mod_params.amsdu_size_8K, int, 0444);
MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size");
-
+module_param_named(fw_restart4965, iwl4965_mod_params.restart_fw, int, 0444);
+MODULE_PARM_DESC(fw_restart4965, "restart firmware in case of error");
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
new file mode 100644
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..7e525ad
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -0,0 +1,1417 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007-2008 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <net/mac80211.h>
+#include <linux/etherdevice.h>
+#include <asm/unaligned.h>
+
+#include "iwl-eeprom.h"
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-io.h"
+#include "iwl-helpers.h"
+#include "iwl-5000-hw.h"
+
+#define IWL5000_UCODE_API "-1"
+
+static const u16 iwl5000_default_queue_to_tx_fifo[] = {
+ IWL_TX_FIFO_AC3,
+ IWL_TX_FIFO_AC2,
+ IWL_TX_FIFO_AC1,
+ IWL_TX_FIFO_AC0,
+ IWL50_CMD_FIFO_NUM,
+ IWL_TX_FIFO_HCCA_1,
+ IWL_TX_FIFO_HCCA_2
+};
+
+/* FIXME: same implementation as 4965 */
+static int iwl5000_apm_stop_master(struct iwl_priv *priv)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* set stop master bit */
+ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
+
+ ret = iwl_poll_bit(priv, CSR_RESET,
+ CSR_RESET_REG_FLAG_MASTER_DISABLED,
+ CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
+ if (ret < 0)
+ goto out;
+
+out:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ IWL_DEBUG_INFO("stop master\n");
+
+ return ret;
+}
+
+
+static int iwl5000_apm_init(struct iwl_priv *priv)
+{
+ int ret = 0;
+
+ iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+ CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+
+ /* disable L0s without affecting L1 :don't wait for ICH L0s bug W/A) */
+ iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+ CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
+
+ iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL);
+
+ /* set "initialization complete" bit to move adapter
+ * D0U* --> D0A* state */
+ iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+
+ /* wait for clock stabilization */
+ ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+ if (ret < 0) {
+ IWL_DEBUG_INFO("Failed to init the card\n");
+ return ret;
+ }
+
+ ret = iwl_grab_nic_access(priv);
+ if (ret)
+ return ret;
+
+ /* enable DMA */
+ iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
+
+ udelay(20);
+
+ /* disable L1-Active */
+ iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
+ APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+
+ iwl_release_nic_access(priv);
+
+ return ret;
+}
+
+/* FIXME: this is indentical to 4965 */
+static void iwl5000_apm_stop(struct iwl_priv *priv)
+{
+ unsigned long flags;
+
+ iwl5000_apm_stop_master(priv);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+
+ udelay(10);
+
+ iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+
+static int iwl5000_apm_reset(struct iwl_priv *priv)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ iwl5000_apm_stop_master(priv);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+
+ udelay(10);
+
+
+ /* FIXME: put here L1A -L0S w/a */
+
+ iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL);
+
+ /* set "initialization complete" bit to move adapter
+ * D0U* --> D0A* state */
+ iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+
+ /* wait for clock stabilization */
+ ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+ if (ret < 0) {
+ IWL_DEBUG_INFO("Failed to init the card\n");
+ goto out;
+ }
+
+ ret = iwl_grab_nic_access(priv);
+ if (ret)
+ goto out;
+
+ /* enable DMA */
+ iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
+
+ udelay(20);
+
+ /* disable L1-Active */
+ iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
+ APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+
+ iwl_release_nic_access(priv);
+
+out:
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return ret;
+}
+
+
+static void iwl5000_nic_config(struct iwl_priv *priv)
+{
+ unsigned long flags;
+ u16 radio_cfg;
+ u8 val_link;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link);
+
+ /* L1 is enabled by BIOS */
+ if ((val_link & PCI_LINK_VAL_L1_EN) == PCI_LINK_VAL_L1_EN)
+ /* diable L0S disabled L1A enabled */
+ iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
+ else
+ /* L0S enabled L1A disabled */
+ iwl_clear_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
+
+ radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
+
+ /* write radio config values to register */
+ if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) < EEPROM_5000_RF_CFG_TYPE_MAX)
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ EEPROM_RF_CFG_TYPE_MSK(radio_cfg) |
+ EEPROM_RF_CFG_STEP_MSK(radio_cfg) |
+ EEPROM_RF_CFG_DASH_MSK(radio_cfg));
+
+ /* set CSR_HW_CONFIG_REG for uCode use */
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
+ CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+
+
+/*
+ * EEPROM
+ */
+static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address)
+{
+ u16 offset = 0;
+
+ if ((address & INDIRECT_ADDRESS) == 0)
+ return address;
+
+ switch (address & INDIRECT_TYPE_MSK) {
+ case INDIRECT_HOST:
+ offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_HOST);
+ break;
+ case INDIRECT_GENERAL:
+ offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_GENERAL);
+ break;
+ case INDIRECT_REGULATORY:
+ offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_REGULATORY);
+ break;
+ case INDIRECT_CALIBRATION:
+ offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_CALIBRATION);
+ break;
+ case INDIRECT_PROCESS_ADJST:
+ offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_PROCESS_ADJST);
+ break;
+ case INDIRECT_OTHERS:
+ offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_OTHERS);
+ break;
+ default:
+ IWL_ERROR("illegal indirect type: 0x%X\n",
+ address & INDIRECT_TYPE_MSK);
+ break;
+ }
+
+ /* translate the offset from words to byte */
+ return (address & ADDRESS_MSK) + (offset << 1);
+}
+
+static int iwl5000_eeprom_check_version(struct iwl_priv *priv)
+{
+ u16 eeprom_ver;
+ struct iwl_eeprom_calib_hdr {
+ u8 version;
+ u8 pa_type;
+ u16 voltage;
+ } *hdr;
+
+ eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
+
+ hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv,
+ EEPROM_5000_CALIB_ALL);
+
+ if (eeprom_ver < EEPROM_5000_EEPROM_VERSION ||
+ hdr->version < EEPROM_5000_TX_POWER_VERSION)
+ goto err;
+
+ return 0;
+err:
+ IWL_ERROR("Unsuported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n",
+ eeprom_ver, EEPROM_5000_EEPROM_VERSION,
+ hdr->version, EEPROM_5000_TX_POWER_VERSION);
+ return -EINVAL;
+
+}
+
+#ifdef CONFIG_IWL5000_RUN_TIME_CALIB
+
+static void iwl5000_gain_computation(struct iwl_priv *priv,
+ u32 average_noise[NUM_RX_CHAINS],
+ u16 min_average_noise_antenna_i,
+ u32 min_average_noise)
+{
+ int i;
+ s32 delta_g;
+ struct iwl_chain_noise_data *data = &priv->chain_noise_data;
+
+ /* Find Gain Code for the antennas B and C */
+ for (i = 1; i < NUM_RX_CHAINS; i++) {
+ if ((data->disconn_array[i])) {
+ data->delta_gain_code[i] = 0;
+ continue;
+ }
+ delta_g = (1000 * ((s32)average_noise[0] -
+ (s32)average_noise[i])) / 1500;
+ /* bound gain by 2 bits value max, 3rd bit is sign */
+ data->delta_gain_code[i] =
+ min(abs(delta_g), CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
+
+ if (delta_g < 0)
+ /* set negative sign */
+ data->delta_gain_code[i] |= (1 << 2);
+ }
+
+ IWL_DEBUG_CALIB("Delta gains: ANT_B = %d ANT_C = %d\n",
+ data->delta_gain_code[1], data->delta_gain_code[2]);
+
+ if (!data->radio_write) {
+ struct iwl5000_calibration_chain_noise_gain_cmd cmd;
+ memset(&cmd, 0, sizeof(cmd));
+
+ cmd.op_code = IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD;
+ cmd.delta_gain_1 = data->delta_gain_code[1];
+ cmd.delta_gain_2 = data->delta_gain_code[2];
+ iwl_send_cmd_pdu_async(priv, REPLY_PHY_CALIBRATION_CMD,
+ sizeof(cmd), &cmd, NULL);
+
+ data->radio_write = 1;
+ data->state = IWL_CHAIN_NOISE_CALIBRATED;
+ }
+
+ data->chain_noise_a = 0;
+ data->chain_noise_b = 0;
+ data->chain_noise_c = 0;
+ data->chain_signal_a = 0;
+ data->chain_signal_b = 0;
+ data->chain_signal_c = 0;
+ data->beacon_count = 0;
+}
+
+
+static void iwl5000_chain_noise_reset(struct iwl_priv *priv)
+{
+ struct iwl_chain_noise_data *data = &priv->chain_noise_data;
+
+ if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
+ struct iwl5000_calibration_chain_noise_reset_cmd cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_code = IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD;
+ if (iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
+ sizeof(cmd), &cmd))
+ IWL_ERROR("Could not send REPLY_PHY_CALIBRATION_CMD\n");
+ data->state = IWL_CHAIN_NOISE_ACCUMULATE;
+ IWL_DEBUG_CALIB("Run chain_noise_calibrate\n");
+ }
+}
+
+static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
+ .min_nrg_cck = 95,
+ .max_nrg_cck = 0,
+ .auto_corr_min_ofdm = 90,
+ .auto_corr_min_ofdm_mrc = 170,
+ .auto_corr_min_ofdm_x1 = 120,
+ .auto_corr_min_ofdm_mrc_x1 = 240,
+
+ .auto_corr_max_ofdm = 120,
+ .auto_corr_max_ofdm_mrc = 210,
+ .auto_corr_max_ofdm_x1 = 155,
+ .auto_corr_max_ofdm_mrc_x1 = 290,
+
+ .auto_corr_min_cck = 125,
+ .auto_corr_max_cck = 200,
+ .auto_corr_min_cck_mrc = 170,
+ .auto_corr_max_cck_mrc = 400,
+ .nrg_th_cck = 95,
+ .nrg_th_ofdm = 95,
+};
+
+#endif /* CONFIG_IWL5000_RUN_TIME_CALIB */
+
+
+
+static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
+ size_t offset)
+{
+ u32 address = eeprom_indirect_address(priv, offset);
+ BUG_ON(address >= priv->cfg->eeprom_size);
+ return &priv->eeprom[address];
+}
+
+/*
+ * Calibration
+ */
+static int iwl5000_send_Xtal_calib(struct iwl_priv *priv)
+{
+ u16 *xtal_calib = (u16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_XTAL);
+
+ struct iwl5000_calibration cal_cmd = {
+ .op_code = IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD,
+ .data = {
+ (u8)xtal_calib[0],
+ (u8)xtal_calib[1],
+ }
+ };
+
+ return iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
+ sizeof(cal_cmd), &cal_cmd);
+}
+
+static int iwl5000_send_calib_results(struct iwl_priv *priv)
+{
+ int ret = 0;
+
+ struct iwl_host_cmd hcmd = {
+ .id = REPLY_PHY_CALIBRATION_CMD,
+ .meta.flags = CMD_SIZE_HUGE,
+ };
+
+ if (priv->calib_results.lo_res) {
+ hcmd.len = priv->calib_results.lo_res_len;
+ hcmd.data = priv->calib_results.lo_res;
+ ret = iwl_send_cmd_sync(priv, &hcmd);
+
+ if (ret)
+ goto err;
+ }
+
+ if (priv->calib_results.tx_iq_res) {
+ hcmd.len = priv->calib_results.tx_iq_res_len;
+ hcmd.data = priv->calib_results.tx_iq_res;
+ ret = iwl_send_cmd_sync(priv, &hcmd);
+
+ if (ret)
+ goto err;
+ }
+
+ if (priv->calib_results.tx_iq_perd_res) {
+ hcmd.len = priv->calib_results.tx_iq_perd_res_len;
+ hcmd.data = priv->calib_results.tx_iq_perd_res;
+ ret = iwl_send_cmd_sync(priv, &hcmd);
+
+ if (ret)
+ goto err;
+ }
+
+ return 0;
+err:
+ IWL_ERROR("Error %d\n", ret);
+ return ret;
+}
+
+static int iwl5000_send_calib_cfg(struct iwl_priv *priv)
+{
+ struct iwl5000_calib_cfg_cmd calib_cfg_cmd;
+ struct iwl_host_cmd cmd = {
+ .id = CALIBRATION_CFG_CMD,
+ .len = sizeof(struct iwl5000_calib_cfg_cmd),
+ .data = &calib_cfg_cmd,
+ };
+
+ memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
+ calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_INIT_CFG_ALL;
+ calib_cfg_cmd.ucd_calib_cfg.once.start = IWL_CALIB_INIT_CFG_ALL;
+ calib_cfg_cmd.ucd_calib_cfg.once.send_res = IWL_CALIB_INIT_CFG_ALL;
+ calib_cfg_cmd.ucd_calib_cfg.flags = IWL_CALIB_INIT_CFG_ALL;
+
+ return iwl_send_cmd(priv, &cmd);
+}
+
+static void iwl5000_rx_calib_result(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl5000_calib_hdr *hdr = (struct iwl5000_calib_hdr *)pkt->u.raw;
+ int len = le32_to_cpu(pkt->len) & FH_RSCSR_FRAME_SIZE_MSK;
+
+ iwl_free_calib_results(priv);
+
+ /* reduce the size of the length field itself */
+ len -= 4;
+
+ switch (hdr->op_code) {
+ case IWL5000_PHY_CALIBRATE_LO_CMD:
+ priv->calib_results.lo_res = kzalloc(len, GFP_ATOMIC);
+ priv->calib_results.lo_res_len = len;
+ memcpy(priv->calib_results.lo_res, pkt->u.raw, len);
+ break;
+ case IWL5000_PHY_CALIBRATE_TX_IQ_CMD:
+ priv->calib_results.tx_iq_res = kzalloc(len, GFP_ATOMIC);
+ priv->calib_results.tx_iq_res_len = len;
+ memcpy(priv->calib_results.tx_iq_res, pkt->u.raw, len);
+ break;
+ case IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD:
+ priv->calib_results.tx_iq_perd_res = kzalloc(len, GFP_ATOMIC);
+ priv->calib_results.tx_iq_perd_res_len = len;
+ memcpy(priv->calib_results.tx_iq_perd_res, pkt->u.raw, len);
+ break;
+ default:
+ IWL_ERROR("Unknown calibration notification %d\n",
+ hdr->op_code);
+ return;
+ }
+}
+
+static void iwl5000_rx_calib_complete(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ IWL_DEBUG_INFO("Init. calibration is completed, restarting fw.\n");
+ queue_work(priv->workqueue, &priv->restart);
+}
+
+/*
+ * ucode
+ */
+static int iwl5000_load_section(struct iwl_priv *priv,
+ struct fw_desc *image,
+ u32 dst_addr)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ dma_addr_t phy_addr = image->p_addr;
+ u32 byte_cnt = image->len;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ ret = iwl_grab_nic_access(priv);
+ if (ret) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return ret;
+ }
+
+ iwl_write_direct32(priv,
+ FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
+ FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
+
+ iwl_write_direct32(priv,
+ FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr);
+
+ iwl_write_direct32(priv,
+ FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL),
+ phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
+
+ /* FIME: write the MSB of the phy_addr in CTRL1
+ * iwl_write_direct32(priv,
+ IWL_FH_TFDIB_CTRL1_REG(IWL_FH_SRVC_CHNL),
+ ((phy_addr & MSB_MSK)
+ << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_count);
+ */
+ iwl_write_direct32(priv,
+ FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), byte_cnt);
+ iwl_write_direct32(priv,
+ FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL),
+ 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM |
+ 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX |
+ FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
+
+ iwl_write_direct32(priv,
+ FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
+ FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+ FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL |
+ FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
+
+ iwl_release_nic_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return 0;
+}
+
+static int iwl5000_load_given_ucode(struct iwl_priv *priv,
+ struct fw_desc *inst_image,
+ struct fw_desc *data_image)
+{
+ int ret = 0;
+
+ ret = iwl5000_load_section(
+ priv, inst_image, RTC_INST_LOWER_BOUND);
+ if (ret)
+ return ret;
+
+ IWL_DEBUG_INFO("INST uCode section being loaded...\n");
+ ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+ priv->ucode_write_complete, 5 * HZ);
+ if (ret == -ERESTARTSYS) {
+ IWL_ERROR("Could not load the INST uCode section due "
+ "to interrupt\n");
+ return ret;
+ }
+ if (!ret) {
+ IWL_ERROR("Could not load the INST uCode section\n");
+ return -ETIMEDOUT;
+ }
+
+ priv->ucode_write_complete = 0;
+
+ ret = iwl5000_load_section(
+ priv, data_image, RTC_DATA_LOWER_BOUND);
+ if (ret)
+ return ret;
+
+ IWL_DEBUG_INFO("DATA uCode section being loaded...\n");
+
+ ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+ priv->ucode_write_complete, 5 * HZ);
+ if (ret == -ERESTARTSYS) {
+ IWL_ERROR("Could not load the INST uCode section due "
+ "to interrupt\n");
+ return ret;
+ } else if (!ret) {
+ IWL_ERROR("Could not load the DATA uCode section\n");
+ return -ETIMEDOUT;
+ } else
+ ret = 0;
+
+ priv->ucode_write_complete = 0;
+
+ return ret;
+}
+
+static int iwl5000_load_ucode(struct iwl_priv *priv)
+{
+ int ret = 0;
+
+ /* check whether init ucode should be loaded, or rather runtime ucode */
+ if (priv->ucode_init.len && (priv->ucode_type == UCODE_NONE)) {
+ IWL_DEBUG_INFO("Init ucode found. Loading init ucode...\n");
+ ret = iwl5000_load_given_ucode(priv,
+ &priv->ucode_init, &priv->ucode_init_data);
+ if (!ret) {
+ IWL_DEBUG_INFO("Init ucode load complete.\n");
+ priv->ucode_type = UCODE_INIT;
+ }
+ } else {
+ IWL_DEBUG_INFO("Init ucode not found, or already loaded. "
+ "Loading runtime ucode...\n");
+ ret = iwl5000_load_given_ucode(priv,
+ &priv->ucode_code, &priv->ucode_data);
+ if (!ret) {
+ IWL_DEBUG_INFO("Runtime ucode load complete.\n");
+ priv->ucode_type = UCODE_RT;
+ }
+ }
+
+ return ret;
+}
+
+static void iwl5000_init_alive_start(struct iwl_priv *priv)
+{
+ int ret = 0;
+
+ /* Check alive response for "valid" sign from uCode */
+ if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
+ /* We had an error bringing up the hardware, so take it
+ * all the way back down so we can try again */
+ IWL_DEBUG_INFO("Initialize Alive failed.\n");
+ goto restart;
+ }
+
+ /* initialize uCode was loaded... verify inst image.
+ * This is a paranoid check, because we would not have gotten the
+ * "initialize" alive if code weren't properly loaded. */
+ if (iwl_verify_ucode(priv)) {
+ /* Runtime instruction load was bad;
+ * take it all the way back down so we can try again */
+ IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n");
+ goto restart;
+ }
+
+ iwlcore_clear_stations_table(priv);
+ ret = priv->cfg->ops->lib->alive_notify(priv);
+ if (ret) {
+ IWL_WARNING("Could not complete ALIVE transition: %d\n", ret);
+ goto restart;
+ }
+
+ iwl5000_send_calib_cfg(priv);
+ return;
+
+restart:
+ /* real restart (first load init_ucode) */
+ queue_work(priv->workqueue, &priv->restart);
+}
+
+static void iwl5000_set_wr_ptrs(struct iwl_priv *priv,
+ int txq_id, u32 index)
+{
+ iwl_write_direct32(priv, HBUS_TARG_WRPTR,
+ (index & 0xff) | (txq_id << 8));
+ iwl_write_prph(priv, IWL50_SCD_QUEUE_RDPTR(txq_id), index);
+}
+
+static void iwl5000_tx_queue_set_status(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq,
+ int tx_fifo_id, int scd_retry)
+{
+ int txq_id = txq->q.id;
+ int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0;
+
+ iwl_write_prph(priv, IWL50_SCD_QUEUE_STATUS_BITS(txq_id),
+ (active << IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
+ (tx_fifo_id << IWL50_SCD_QUEUE_STTS_REG_POS_TXF) |
+ (1 << IWL50_SCD_QUEUE_STTS_REG_POS_WSL) |
+ IWL50_SCD_QUEUE_STTS_REG_MSK);
+
+ txq->sched_retry = scd_retry;
+
+ IWL_DEBUG_INFO("%s %s Queue %d on AC %d\n",
+ active ? "Activate" : "Deactivate",
+ scd_retry ? "BA" : "AC", txq_id, tx_fifo_id);
+}
+
+static int iwl5000_send_wimax_coex(struct iwl_priv *priv)
+{
+ struct iwl_wimax_coex_cmd coex_cmd;
+
+ memset(&coex_cmd, 0, sizeof(coex_cmd));
+
+ return iwl_send_cmd_pdu(priv, COEX_PRIORITY_TABLE_CMD,
+ sizeof(coex_cmd), &coex_cmd);
+}
+
+static int iwl5000_alive_notify(struct iwl_priv *priv)
+{
+ u32 a;
+ int i = 0;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ ret = iwl_grab_nic_access(priv);
+ if (ret) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return ret;
+ }
+
+ priv->scd_base_addr = iwl_read_prph(priv, IWL50_SCD_SRAM_BASE_ADDR);
+ a = priv->scd_base_addr + IWL50_SCD_CONTEXT_DATA_OFFSET;
+ for (; a < priv->scd_base_addr + IWL50_SCD_TX_STTS_BITMAP_OFFSET;
+ a += 4)
+ iwl_write_targ_mem(priv, a, 0);
+ for (; a < priv->scd_base_addr + IWL50_SCD_TRANSLATE_TBL_OFFSET;
+ a += 4)
+ iwl_write_targ_mem(priv, a, 0);
+ for (; a < sizeof(u16) * priv->hw_params.max_txq_num; a += 4)
+ iwl_write_targ_mem(priv, a, 0);
+
+ iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR,
+ (priv->shared_phys +
+ offsetof(struct iwl5000_shared, queues_byte_cnt_tbls)) >> 10);
+ iwl_write_prph(priv, IWL50_SCD_QUEUECHAIN_SEL,
+ IWL50_SCD_QUEUECHAIN_SEL_ALL(
+ priv->hw_params.max_txq_num));
+ iwl_write_prph(priv, IWL50_SCD_AGGR_SEL, 0);
+
+ /* initiate the queues */
+ for (i = 0; i < priv->hw_params.max_txq_num; i++) {
+ iwl_write_prph(priv, IWL50_SCD_QUEUE_RDPTR(i), 0);
+ iwl_write_direct32(priv, HBUS_TARG_WRPTR, 0 | (i << 8));
+ iwl_write_targ_mem(priv, priv->scd_base_addr +
+ IWL50_SCD_CONTEXT_QUEUE_OFFSET(i), 0);
+ iwl_write_targ_mem(priv, priv->scd_base_addr +
+ IWL50_SCD_CONTEXT_QUEUE_OFFSET(i) +
+ sizeof(u32),
+ ((SCD_WIN_SIZE <<
+ IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
+ IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
+ ((SCD_FRAME_LIMIT <<
+ IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
+ IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
+ }
+
+ iwl_write_prph(priv, IWL50_SCD_INTERRUPT_MASK,
+ IWL_MASK(0, priv->hw_params.max_txq_num));
+
+ /* Activate all Tx DMA/FIFO channels */
+ priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7));
+
+ iwl5000_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
+ /* map qos queues to fifos one-to-one */
+ for (i = 0; i < ARRAY_SIZE(iwl5000_default_queue_to_tx_fifo); i++) {
+ int ac = iwl5000_default_queue_to_tx_fifo[i];
+ iwl_txq_ctx_activate(priv, i);
+ iwl5000_tx_queue_set_status(priv, &priv->txq[i], ac, 0);
+ }
+ /* TODO - need to initialize those FIFOs inside the loop above,
+ * not only mark them as active */
+ iwl_txq_ctx_activate(priv, 4);
+ iwl_txq_ctx_activate(priv, 7);
+ iwl_txq_ctx_activate(priv, 8);
+ iwl_txq_ctx_activate(priv, 9);
+
+ iwl_release_nic_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+
+ iwl5000_send_wimax_coex(priv);
+
+ iwl5000_send_Xtal_calib(priv);
+
+ if (priv->ucode_type == UCODE_RT) {
+ iwl5000_send_calib_results(priv);
+ set_bit(STATUS_READY, &priv->status);
+ priv->is_open = 1;
+ }
+
+ return 0;
+}
+
+static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
+{
+ if ((priv->cfg->mod_params->num_of_queues > IWL50_NUM_QUEUES) ||
+ (priv->cfg->mod_params->num_of_queues < IWL_MIN_NUM_QUEUES)) {
+ IWL_ERROR("invalid queues_num, should be between %d and %d\n",
+ IWL_MIN_NUM_QUEUES, IWL50_NUM_QUEUES);
+ return -EINVAL;
+ }
+
+ priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues;
+ priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto;
+ priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
+ priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
+ if (priv->cfg->mod_params->amsdu_size_8K)
+ priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_8K;
+ else
+ priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K;
+ priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256;
+ priv->hw_params.max_stations = IWL5000_STATION_COUNT;
+ priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
+ priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE;
+ priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE;
+ priv->hw_params.max_bsm_size = BSM_SRAM_SIZE;
+ priv->hw_params.fat_channel = BIT(IEEE80211_BAND_2GHZ) |
+ BIT(IEEE80211_BAND_5GHZ);
+#ifdef CONFIG_IWL5000_RUN_TIME_CALIB
+ priv->hw_params.sens = &iwl5000_sensitivity;
+#endif
+
+ switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
+ case CSR_HW_REV_TYPE_5100:
+ case CSR_HW_REV_TYPE_5150:
+ priv->hw_params.tx_chains_num = 1;
+ priv->hw_params.rx_chains_num = 2;
+ /* FIXME: move to ANT_A, ANT_B, ANT_C enum */
+ priv->hw_params.valid_tx_ant = ANT_A;
+ priv->hw_params.valid_rx_ant = ANT_AB;
+ break;
+ case CSR_HW_REV_TYPE_5300:
+ case CSR_HW_REV_TYPE_5350:
+ priv->hw_params.tx_chains_num = 3;
+ priv->hw_params.rx_chains_num = 3;
+ priv->hw_params.valid_tx_ant = ANT_ABC;
+ priv->hw_params.valid_rx_ant = ANT_ABC;
+ break;
+ }
+
+ switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
+ case CSR_HW_REV_TYPE_5100:
+ case CSR_HW_REV_TYPE_5300:
+ /* 5X00 wants in Celsius */
+ priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD;
+ break;
+ case CSR_HW_REV_TYPE_5150:
+ case CSR_HW_REV_TYPE_5350:
+ /* 5X50 wants in Kelvin */
+ priv->hw_params.ct_kill_threshold =
+ CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD);
+ break;
+ }
+
+ return 0;
+}
+
+static int iwl5000_alloc_shared_mem(struct iwl_priv *priv)
+{
+ priv->shared_virt = pci_alloc_consistent(priv->pci_dev,
+ sizeof(struct iwl5000_shared),
+ &priv->shared_phys);
+ if (!priv->shared_virt)
+ return -ENOMEM;
+
+ memset(priv->shared_virt, 0, sizeof(struct iwl5000_shared));
+
+ priv->rb_closed_offset = offsetof(struct iwl5000_shared, rb_closed);
+
+ return 0;
+}
+
+static void iwl5000_free_shared_mem(struct iwl_priv *priv)
+{
+ if (priv->shared_virt)
+ pci_free_consistent(priv->pci_dev,
+ sizeof(struct iwl5000_shared),
+ priv->shared_virt,
+ priv->shared_phys);
+}
+
+static int iwl5000_shared_mem_rx_idx(struct iwl_priv *priv)
+{
+ struct iwl5000_shared *s = priv->shared_virt;
+ return le32_to_cpu(s->rb_closed) & 0xFFF;
+}
+
+/**
+ * iwl5000_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
+ */
+static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq,
+ u16 byte_cnt)
+{
+ struct iwl5000_shared *shared_data = priv->shared_virt;
+ int txq_id = txq->q.id;
+ u8 sec_ctl = 0;
+ u8 sta = 0;
+ int len;
+
+ len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
+
+ if (txq_id != IWL_CMD_QUEUE_NUM) {
+ sta = txq->cmd[txq->q.write_ptr].cmd.tx.sta_id;
+ sec_ctl = txq->cmd[txq->q.write_ptr].cmd.tx.sec_ctl;
+
+ switch (sec_ctl & TX_CMD_SEC_MSK) {
+ case TX_CMD_SEC_CCM:
+ len += CCMP_MIC_LEN;
+ break;
+ case TX_CMD_SEC_TKIP:
+ len += TKIP_ICV_LEN;
+ break;
+ case TX_CMD_SEC_WEP:
+ len += WEP_IV_LEN + WEP_ICV_LEN;
+ break;
+ }
+ }
+
+ IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
+ tfd_offset[txq->q.write_ptr], byte_cnt, len);
+
+ IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
+ tfd_offset[txq->q.write_ptr], sta_id, sta);
+
+ if (txq->q.write_ptr < IWL50_MAX_WIN_SIZE) {
+ IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
+ tfd_offset[IWL50_QUEUE_SIZE + txq->q.write_ptr],
+ byte_cnt, len);
+ IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
+ tfd_offset[IWL50_QUEUE_SIZE + txq->q.write_ptr],
+ sta_id, sta);
+ }
+}
+
+static void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq)
+{
+ int txq_id = txq->q.id;
+ struct iwl5000_shared *shared_data = priv->shared_virt;
+ u8 sta = 0;
+
+ if (txq_id != IWL_CMD_QUEUE_NUM)
+ sta = txq->cmd[txq->q.read_ptr].cmd.tx.sta_id;
+
+ shared_data->queues_byte_cnt_tbls[txq_id].tfd_offset[txq->q.read_ptr].
+ val = cpu_to_le16(1 | (sta << 12));
+
+ if (txq->q.write_ptr < IWL50_MAX_WIN_SIZE) {
+ shared_data->queues_byte_cnt_tbls[txq_id].
+ tfd_offset[IWL50_QUEUE_SIZE + txq->q.read_ptr].
+ val = cpu_to_le16(1 | (sta << 12));
+ }
+}
+
+static u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
+{
+ u16 size = (u16)sizeof(struct iwl_addsta_cmd);
+ memcpy(data, cmd, size);
+ return size;
+}
+
+
+/*
+ * Activate/Deactivat Tx DMA/FIFO channels according tx fifos mask
+ * must be called under priv->lock and mac access
+ */
+static void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask)
+{
+ iwl_write_prph(priv, IWL50_SCD_TXFACT, mask);
+}
+
+
+static inline u32 iwl5000_get_scd_ssn(struct iwl5000_tx_resp *tx_resp)
+{
+ __le32 *scd_ssn = (__le32 *)((u32 *)&tx_resp->status +
+ tx_resp->frame_count);
+ return le32_to_cpu(*scd_ssn) & MAX_SN;
+
+}
+
+static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv,
+ struct iwl_ht_agg *agg,
+ struct iwl5000_tx_resp *tx_resp,
+ u16 start_idx)
+{
+ u16 status;
+ struct agg_tx_status *frame_status = &tx_resp->status;
+ struct ieee80211_tx_info *info = NULL;
+ struct ieee80211_hdr *hdr = NULL;
+ int i, sh;
+ int txq_id, idx;
+ u16 seq;
+
+ if (agg->wait_for_ba)
+ IWL_DEBUG_TX_REPLY("got tx response w/o block-ack\n");
+
+ agg->frame_count = tx_resp->frame_count;
+ agg->start_idx = start_idx;
+ agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
+ agg->bitmap = 0;
+
+ /* # frames attempted by Tx command */
+ if (agg->frame_count == 1) {
+ /* Only one frame was attempted; no block-ack will arrive */
+ status = le16_to_cpu(frame_status[0].status);
+ seq = le16_to_cpu(frame_status[0].sequence);
+ idx = SEQ_TO_INDEX(seq);
+ txq_id = SEQ_TO_QUEUE(seq);
+
+ /* FIXME: code repetition */
+ IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n",
+ agg->frame_count, agg->start_idx, idx);
+
+ info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
+ info->status.retry_count = tx_resp->failure_frame;
+ info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+ info->flags |= iwl_is_tx_success(status)?
+ IEEE80211_TX_STAT_ACK : 0;
+ iwl4965_hwrate_to_tx_control(priv,
+ le32_to_cpu(tx_resp->rate_n_flags),
+ info);
+ /* FIXME: code repetition end */
+
+ IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n",
+ status & 0xff, tx_resp->failure_frame);
+ IWL_DEBUG_TX_REPLY("Rate Info rate_n_flags=%x\n",
+ iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags));
+
+ agg->wait_for_ba = 0;
+ } else {
+ /* Two or more frames were attempted; expect block-ack */
+ u64 bitmap = 0;
+ int start = agg->start_idx;
+
+ /* Construct bit-map of pending frames within Tx window */
+ for (i = 0; i < agg->frame_count; i++) {
+ u16 sc;
+ status = le16_to_cpu(frame_status[i].status);
+ seq = le16_to_cpu(frame_status[i].sequence);
+ idx = SEQ_TO_INDEX(seq);
+ txq_id = SEQ_TO_QUEUE(seq);
+
+ if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
+ AGG_TX_STATE_ABORT_MSK))
+ continue;
+
+ IWL_DEBUG_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n",
+ agg->frame_count, txq_id, idx);
+
+ hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx);
+
+ sc = le16_to_cpu(hdr->seq_ctrl);
+ if (idx != (SEQ_TO_SN(sc) & 0xff)) {
+ IWL_ERROR("BUG_ON idx doesn't match seq control"
+ " idx=%d, seq_idx=%d, seq=%d\n",
+ idx, SEQ_TO_SN(sc),
+ hdr->seq_ctrl);
+ return -1;
+ }
+
+ IWL_DEBUG_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n",
+ i, idx, SEQ_TO_SN(sc));
+
+ sh = idx - start;
+ if (sh > 64) {
+ sh = (start - idx) + 0xff;
+ bitmap = bitmap << sh;
+ sh = 0;
+ start = idx;
+ } else if (sh < -64)
+ sh = 0xff - (start - idx);
+ else if (sh < 0) {
+ sh = start - idx;
+ start = idx;
+ bitmap = bitmap << sh;
+ sh = 0;
+ }
+ bitmap |= (1 << sh);
+ IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%x\n",
+ start, (u32)(bitmap & 0xFFFFFFFF));
+ }
+
+ agg->bitmap = bitmap;
+ agg->start_idx = start;
+ agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
+ IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n",
+ agg->frame_count, agg->start_idx,
+ (unsigned long long)agg->bitmap);
+
+ if (bitmap)
+ agg->wait_for_ba = 1;
+ }
+ return 0;
+}
+
+static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+ int txq_id = SEQ_TO_QUEUE(sequence);
+ int index = SEQ_TO_INDEX(sequence);
+ struct iwl_tx_queue *txq = &priv->txq[txq_id];
+ struct ieee80211_tx_info *info;
+ struct iwl5000_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
+ u32 status = le16_to_cpu(tx_resp->status.status);
+#ifdef CONFIG_IWL4965_HT
+ int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION;
+ u16 fc;
+ struct ieee80211_hdr *hdr;
+ u8 *qc = NULL;
+#endif
+
+ if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
+ IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
+ "is out of range [0-%d] %d %d\n", txq_id,
+ index, txq->q.n_bd, txq->q.write_ptr,
+ txq->q.read_ptr);
+ return;
+ }
+
+ info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
+ memset(&info->status, 0, sizeof(info->status));
+
+#ifdef CONFIG_IWL4965_HT
+ hdr = iwl_tx_queue_get_hdr(priv, txq_id, index);
+ fc = le16_to_cpu(hdr->frame_control);
+ if (ieee80211_is_qos_data(fc)) {
+ qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc));
+ tid = qc[0] & 0xf;
+ }
+
+ sta_id = iwl_get_ra_sta_id(priv, hdr);
+ if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) {
+ IWL_ERROR("Station not known\n");
+ return;
+ }
+
+ if (txq->sched_retry) {
+ const u32 scd_ssn = iwl5000_get_scd_ssn(tx_resp);
+ struct iwl_ht_agg *agg = NULL;
+
+ if (!qc)
+ return;
+
+ agg = &priv->stations[sta_id].tid[tid].agg;
+
+ iwl5000_tx_status_reply_tx(priv, agg, tx_resp, index);
+
+ if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status)) {
+ /* TODO: send BAR */
+ }
+
+ if (txq->q.read_ptr != (scd_ssn & 0xff)) {
+ int freed, ampdu_q;
+ index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
+ IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn "
+ "%d index %d\n", scd_ssn , index);
+ freed = iwl_tx_queue_reclaim(priv, txq_id, index);
+ priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+
+ if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
+ txq_id >= 0 && priv->mac80211_registered &&
+ agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) {
+ /* calculate mac80211 ampdu sw queue to wake */
+ ampdu_q = txq_id - IWL_BACK_QUEUE_FIRST_ID +
+ priv->hw->queues;
+ if (agg->state == IWL_AGG_OFF)
+ ieee80211_wake_queue(priv->hw, txq_id);
+ else
+ ieee80211_wake_queue(priv->hw, ampdu_q);
+ }
+ iwl_txq_check_empty(priv, sta_id, tid, txq_id);
+ }
+ } else {
+#endif /* CONFIG_IWL4965_HT */
+
+ info->status.retry_count = tx_resp->failure_frame;
+ info->flags = iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0;
+ iwl4965_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags),
+ info);
+
+ IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x "
+ "retries %d\n", txq_id, iwl_get_tx_fail_reason(status),
+ status, le32_to_cpu(tx_resp->rate_n_flags),
+ tx_resp->failure_frame);
+
+ IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
+#ifdef CONFIG_IWL4965_HT
+ if (index != -1) {
+ int freed = iwl_tx_queue_reclaim(priv, txq_id, index);
+ if (tid != MAX_TID_COUNT)
+ priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+ if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
+ (txq_id >= 0) && priv->mac80211_registered)
+ ieee80211_wake_queue(priv->hw, txq_id);
+ if (tid != MAX_TID_COUNT)
+ iwl_txq_check_empty(priv, sta_id, tid, txq_id);
+ }
+ }
+#endif /* CONFIG_IWL4965_HT */
+
+ if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
+ IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n");
+}
+
+/* Currently 5000 is the supperset of everything */
+static u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len)
+{
+ return len;
+}
+
+static void iwl5000_rx_handler_setup(struct iwl_priv *priv)
+{
+ /* init calibration handlers */
+ priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] =
+ iwl5000_rx_calib_result;
+ priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] =
+ iwl5000_rx_calib_complete;
+ priv->rx_handlers[REPLY_TX] = iwl5000_rx_reply_tx;
+}
+
+
+static int iwl5000_hw_valid_rtc_data_addr(u32 addr)
+{
+ return (addr >= RTC_DATA_LOWER_BOUND) &&
+ (addr < IWL50_RTC_DATA_UPPER_BOUND);
+}
+
+static int iwl5000_send_rxon_assoc(struct iwl_priv *priv)
+{
+ int ret = 0;
+ struct iwl5000_rxon_assoc_cmd rxon_assoc;
+ const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
+ const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
+
+ if ((rxon1->flags == rxon2->flags) &&
+ (rxon1->filter_flags == rxon2->filter_flags) &&
+ (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
+ (rxon1->ofdm_ht_single_stream_basic_rates ==
+ rxon2->ofdm_ht_single_stream_basic_rates) &&
+ (rxon1->ofdm_ht_dual_stream_basic_rates ==
+ rxon2->ofdm_ht_dual_stream_basic_rates) &&
+ (rxon1->ofdm_ht_triple_stream_basic_rates ==
+ rxon2->ofdm_ht_triple_stream_basic_rates) &&
+ (rxon1->acquisition_data == rxon2->acquisition_data) &&
+ (rxon1->rx_chain == rxon2->rx_chain) &&
+ (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
+ IWL_DEBUG_INFO("Using current RXON_ASSOC. Not resending.\n");
+ return 0;
+ }
+
+ rxon_assoc.flags = priv->staging_rxon.flags;
+ rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
+ rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
+ rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
+ rxon_assoc.reserved1 = 0;
+ rxon_assoc.reserved2 = 0;
+ rxon_assoc.reserved3 = 0;
+ rxon_assoc.ofdm_ht_single_stream_basic_rates =
+ priv->staging_rxon.ofdm_ht_single_stream_basic_rates;
+ rxon_assoc.ofdm_ht_dual_stream_basic_rates =
+ priv->staging_rxon.ofdm_ht_dual_stream_basic_rates;
+ rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain;
+ rxon_assoc.ofdm_ht_triple_stream_basic_rates =
+ priv->staging_rxon.ofdm_ht_triple_stream_basic_rates;
+ rxon_assoc.acquisition_data = priv->staging_rxon.acquisition_data;
+
+ ret = iwl_send_cmd_pdu_async(priv, REPLY_RXON_ASSOC,
+ sizeof(rxon_assoc), &rxon_assoc, NULL);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
+static struct iwl_hcmd_ops iwl5000_hcmd = {
+ .rxon_assoc = iwl5000_send_rxon_assoc,
+};
+
+static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
+ .get_hcmd_size = iwl5000_get_hcmd_size,
+ .build_addsta_hcmd = iwl5000_build_addsta_hcmd,
+#ifdef CONFIG_IWL5000_RUN_TIME_CALIB
+ .gain_computation = iwl5000_gain_computation,
+ .chain_noise_reset = iwl5000_chain_noise_reset,
+#endif
+};
+
+static struct iwl_lib_ops iwl5000_lib = {
+ .set_hw_params = iwl5000_hw_set_hw_params,
+ .alloc_shared_mem = iwl5000_alloc_shared_mem,
+ .free_shared_mem = iwl5000_free_shared_mem,
+ .shared_mem_rx_idx = iwl5000_shared_mem_rx_idx,
+ .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
+ .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
+ .txq_set_sched = iwl5000_txq_set_sched,
+ .rx_handler_setup = iwl5000_rx_handler_setup,
+ .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
+ .load_ucode = iwl5000_load_ucode,
+ .init_alive_start = iwl5000_init_alive_start,
+ .alive_notify = iwl5000_alive_notify,
+ .apm_ops = {
+ .init = iwl5000_apm_init,
+ .reset = iwl5000_apm_reset,
+ .stop = iwl5000_apm_stop,
+ .config = iwl5000_nic_config,
+ .set_pwr_src = iwl4965_set_pwr_src,
+ },
+ .eeprom_ops = {
+ .regulatory_bands = {
+ EEPROM_5000_REG_BAND_1_CHANNELS,
+ EEPROM_5000_REG_BAND_2_CHANNELS,
+ EEPROM_5000_REG_BAND_3_CHANNELS,
+ EEPROM_5000_REG_BAND_4_CHANNELS,
+ EEPROM_5000_REG_BAND_5_CHANNELS,
+ EEPROM_5000_REG_BAND_24_FAT_CHANNELS,
+ EEPROM_5000_REG_BAND_52_FAT_CHANNELS
+ },
+ .verify_signature = iwlcore_eeprom_verify_signature,
+ .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
+ .release_semaphore = iwlcore_eeprom_release_semaphore,
+ .check_version = iwl5000_eeprom_check_version,
+ .query_addr = iwl5000_eeprom_query_addr,
+ },
+};
+
+static struct iwl_ops iwl5000_ops = {
+ .lib = &iwl5000_lib,
+ .hcmd = &iwl5000_hcmd,
+ .utils = &iwl5000_hcmd_utils,
+};
+
+static struct iwl_mod_params iwl50_mod_params = {
+ .num_of_queues = IWL50_NUM_QUEUES,
+ .enable_qos = 1,
+ .amsdu_size_8K = 1,
+ .restart_fw = 1,
+ /* the rest are 0 by default */
+};
+
+
+struct iwl_cfg iwl5300_agn_cfg = {
+ .name = "5300AGN",
+ .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
+ .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+ .ops = &iwl5000_ops,
+ .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .mod_params = &iwl50_mod_params,
+};
+
+struct iwl_cfg iwl5100_agn_cfg = {
+ .name = "5100AGN",
+ .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
+ .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+ .ops = &iwl5000_ops,
+ .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .mod_params = &iwl50_mod_params,
+};
+
+struct iwl_cfg iwl5350_agn_cfg = {
+ .name = "5350AGN",
+ .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
+ .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+ .ops = &iwl5000_ops,
+ .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .mod_params = &iwl50_mod_params,
+};
+
+module_param_named(disable50, iwl50_mod_params.disable, int, 0444);
+MODULE_PARM_DESC(disable50,
+ "manually disable the 50XX radio (default 0 [radio on])");
+module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444);
+MODULE_PARM_DESC(swcrypto50,
+ "using software crypto engine (default 0 [hardware])\n");
+module_param_named(debug50, iwl50_mod_params.debug, int, 0444);
+MODULE_PARM_DESC(debug50, "50XX debug output mask");
+module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444);
+MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series");
+module_param_named(qos_enable50, iwl50_mod_params.enable_qos, int, 0444);
+MODULE_PARM_DESC(qos_enable50, "enable all 50XX QoS functionality");
+module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K, int, 0444);
+MODULE_PARM_DESC(amsdu_size_8K50, "enable 8K amsdu size in 50XX series");
+module_param_named(fw_restart50, iwl50_mod_params.restart_fw, int, 0444);
+MODULE_PARM_DESC(fw_restart50, "restart firmware in case of error");
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c
new file mode 100644
index 0000000..a6c7f0d
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.c
@@ -0,0 +1,806 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * Tomas Winkler <tomas.winkler@intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <net/mac80211.h>
+
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-calib.h"
+#include "iwl-eeprom.h"
+
+/* "false alarms" are signals that our DSP tries to lock onto,
+ * but then determines that they are either noise, or transmissions
+ * from a distant wireless network (also "noise", really) that get
+ * "stepped on" by stronger transmissions within our own network.
+ * This algorithm attempts to set a sensitivity level that is high
+ * enough to receive all of our own network traffic, but not so
+ * high that our DSP gets too busy trying to lock onto non-network
+ * activity/noise. */
+static int iwl_sens_energy_cck(struct iwl_priv *priv,
+ u32 norm_fa,
+ u32 rx_enable_time,
+ struct statistics_general_data *rx_info)
+{
+ u32 max_nrg_cck = 0;
+ int i = 0;
+ u8 max_silence_rssi = 0;
+ u32 silence_ref = 0;
+ u8 silence_rssi_a = 0;
+ u8 silence_rssi_b = 0;
+ u8 silence_rssi_c = 0;
+ u32 val;
+
+ /* "false_alarms" values below are cross-multiplications to assess the
+ * numbers of false alarms within the measured period of actual Rx
+ * (Rx is off when we're txing), vs the min/max expected false alarms
+ * (some should be expected if rx is sensitive enough) in a
+ * hypothetical listening period of 200 time units (TU), 204.8 msec:
+ *
+ * MIN_FA/fixed-time < false_alarms/actual-rx-time < MAX_FA/beacon-time
+ *
+ * */
+ u32 false_alarms = norm_fa * 200 * 1024;
+ u32 max_false_alarms = MAX_FA_CCK * rx_enable_time;
+ u32 min_false_alarms = MIN_FA_CCK * rx_enable_time;
+ struct iwl_sensitivity_data *data = NULL;
+ const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
+
+ data = &(priv->sensitivity_data);
+
+ data->nrg_auto_corr_silence_diff = 0;
+
+ /* Find max silence rssi among all 3 receivers.
+ * This is background noise, which may include transmissions from other
+ * networks, measured during silence before our network's beacon */
+ silence_rssi_a = (u8)((rx_info->beacon_silence_rssi_a &
+ ALL_BAND_FILTER) >> 8);
+ silence_rssi_b = (u8)((rx_info->beacon_silence_rssi_b &
+ ALL_BAND_FILTER) >> 8);
+ silence_rssi_c = (u8)((rx_info->beacon_silence_rssi_c &
+ ALL_BAND_FILTER) >> 8);
+
+ val = max(silence_rssi_b, silence_rssi_c);
+ max_silence_rssi = max(silence_rssi_a, (u8) val);
+
+ /* Store silence rssi in 20-beacon history table */
+ data->nrg_silence_rssi[data->nrg_silence_idx] = max_silence_rssi;
+ data->nrg_silence_idx++;
+ if (data->nrg_silence_idx >= NRG_NUM_PREV_STAT_L)
+ data->nrg_silence_idx = 0;
+
+ /* Find max silence rssi across 20 beacon history */
+ for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) {
+ val = data->nrg_silence_rssi[i];
+ silence_ref = max(silence_ref, val);
+ }
+ IWL_DEBUG_CALIB("silence a %u, b %u, c %u, 20-bcn max %u\n",
+ silence_rssi_a, silence_rssi_b, silence_rssi_c,
+ silence_ref);
+
+ /* Find max rx energy (min value!) among all 3 receivers,
+ * measured during beacon frame.
+ * Save it in 10-beacon history table. */
+ i = data->nrg_energy_idx;
+ val = min(rx_info->beacon_energy_b, rx_info->beacon_energy_c);
+ data->nrg_value[i] = min(rx_info->beacon_energy_a, val);
+
+ data->nrg_energy_idx++;
+ if (data->nrg_energy_idx >= 10)
+ data->nrg_energy_idx = 0;
+
+ /* Find min rx energy (max value) across 10 beacon history.
+ * This is the minimum signal level that we want to receive well.
+ * Add backoff (margin so we don't miss slightly lower energy frames).
+ * This establishes an upper bound (min value) for energy threshold. */
+ max_nrg_cck = data->nrg_value[0];
+ for (i = 1; i < 10; i++)
+ max_nrg_cck = (u32) max(max_nrg_cck, (data->nrg_value[i]));
+ max_nrg_cck += 6;
+
+ IWL_DEBUG_CALIB("rx energy a %u, b %u, c %u, 10-bcn max/min %u\n",
+ rx_info->beacon_energy_a, rx_info->beacon_energy_b,
+ rx_info->beacon_energy_c, max_nrg_cck - 6);
+
+ /* Count number of consecutive beacons with fewer-than-desired
+ * false alarms. */
+ if (false_alarms < min_false_alarms)
+ data->num_in_cck_no_fa++;
+ else
+ data->num_in_cck_no_fa = 0;
+ IWL_DEBUG_CALIB("consecutive bcns with few false alarms = %u\n",
+ data->num_in_cck_no_fa);
+
+ /* If we got too many false alarms this time, reduce sensitivity */
+ if ((false_alarms > max_false_alarms) &&
+ (data->auto_corr_cck > AUTO_CORR_MAX_TH_CCK)) {
+ IWL_DEBUG_CALIB("norm FA %u > max FA %u\n",
+ false_alarms, max_false_alarms);
+ IWL_DEBUG_CALIB("... reducing sensitivity\n");
+ data->nrg_curr_state = IWL_FA_TOO_MANY;
+ /* Store for "fewer than desired" on later beacon */
+ data->nrg_silence_ref = silence_ref;
+
+ /* increase energy threshold (reduce nrg value)
+ * to decrease sensitivity */
+ if (data->nrg_th_cck >
+ (ranges->max_nrg_cck + NRG_STEP_CCK))
+ data->nrg_th_cck = data->nrg_th_cck
+ - NRG_STEP_CCK;
+ else
+ data->nrg_th_cck = ranges->max_nrg_cck;
+ /* Else if we got fewer than desired, increase sensitivity */
+ } else if (false_alarms < min_false_alarms) {
+ data->nrg_curr_state = IWL_FA_TOO_FEW;
+
+ /* Compare silence level with silence level for most recent
+ * healthy number or too many false alarms */
+ data->nrg_auto_corr_silence_diff = (s32)data->nrg_silence_ref -
+ (s32)silence_ref;
+
+ IWL_DEBUG_CALIB("norm FA %u < min FA %u, silence diff %d\n",
+ false_alarms, min_false_alarms,
+ data->nrg_auto_corr_silence_diff);
+
+ /* Increase value to increase sensitivity, but only if:
+ * 1a) previous beacon did *not* have *too many* false alarms
+ * 1b) AND there's a significant difference in Rx levels
+ * from a previous beacon with too many, or healthy # FAs
+ * OR 2) We've seen a lot of beacons (100) with too few
+ * false alarms */
+ if ((data->nrg_prev_state != IWL_FA_TOO_MANY) &&
+ ((data->nrg_auto_corr_silence_diff > NRG_DIFF) ||
+ (data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) {
+
+ IWL_DEBUG_CALIB("... increasing sensitivity\n");
+ /* Increase nrg value to increase sensitivity */
+ val = data->nrg_th_cck + NRG_STEP_CCK;
+ data->nrg_th_cck = min((u32)ranges->min_nrg_cck, val);
+ } else {
+ IWL_DEBUG_CALIB("... but not changing sensitivity\n");
+ }
+
+ /* Else we got a healthy number of false alarms, keep status quo */
+ } else {
+ IWL_DEBUG_CALIB(" FA in safe zone\n");
+ data->nrg_curr_state = IWL_FA_GOOD_RANGE;
+
+ /* Store for use in "fewer than desired" with later beacon */
+ data->nrg_silence_ref = silence_ref;
+
+ /* If previous beacon had too many false alarms,
+ * give it some extra margin by reducing sensitivity again
+ * (but don't go below measured energy of desired Rx) */
+ if (IWL_FA_TOO_MANY == data->nrg_prev_state) {
+ IWL_DEBUG_CALIB("... increasing margin\n");
+ if (data->nrg_th_cck > (max_nrg_cck + NRG_MARGIN))
+ data->nrg_th_cck -= NRG_MARGIN;
+ else
+ data->nrg_th_cck = max_nrg_cck;
+ }
+ }
+
+ /* Make sure the energy threshold does not go above the measured
+ * energy of the desired Rx signals (reduced by backoff margin),
+ * or else we might start missing Rx frames.
+ * Lower value is higher energy, so we use max()!
+ */
+ data->nrg_th_cck = max(max_nrg_cck, data->nrg_th_cck);
+ IWL_DEBUG_CALIB("new nrg_th_cck %u\n", data->nrg_th_cck);
+
+ data->nrg_prev_state = data->nrg_curr_state;
+
+ /* Auto-correlation CCK algorithm */
+ if (false_alarms > min_false_alarms) {
+
+ /* increase auto_corr values to decrease sensitivity
+ * so the DSP won't be disturbed by the noise
+ */
+ if (data->auto_corr_cck < AUTO_CORR_MAX_TH_CCK)
+ data->auto_corr_cck = AUTO_CORR_MAX_TH_CCK + 1;
+ else {
+ val = data->auto_corr_cck + AUTO_CORR_STEP_CCK;
+ data->auto_corr_cck =
+ min((u32)ranges->auto_corr_max_cck, val);
+ }
+ val = data->auto_corr_cck_mrc + AUTO_CORR_STEP_CCK;
+ data->auto_corr_cck_mrc =
+ min((u32)ranges->auto_corr_max_cck_mrc, val);
+ } else if ((false_alarms < min_false_alarms) &&
+ ((data->nrg_auto_corr_silence_diff > NRG_DIFF) ||
+ (data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) {
+
+ /* Decrease auto_corr values to increase sensitivity */
+ val = data->auto_corr_cck - AUTO_CORR_STEP_CCK;
+ data->auto_corr_cck =
+ max((u32)ranges->auto_corr_min_cck, val);
+ val = data->auto_corr_cck_mrc - AUTO_CORR_STEP_CCK;
+ data->auto_corr_cck_mrc =
+ max((u32)ranges->auto_corr_min_cck_mrc, val);
+ }
+
+ return 0;
+}
+
+
+static int iwl_sens_auto_corr_ofdm(struct iwl_priv *priv,
+ u32 norm_fa,
+ u32 rx_enable_time)
+{
+ u32 val;
+ u32 false_alarms = norm_fa * 200 * 1024;
+ u32 max_false_alarms = MAX_FA_OFDM * rx_enable_time;
+ u32 min_false_alarms = MIN_FA_OFDM * rx_enable_time;
+ struct iwl_sensitivity_data *data = NULL;
+ const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
+
+ data = &(priv->sensitivity_data);
+
+ /* If we got too many false alarms this time, reduce sensitivity */
+ if (false_alarms > max_false_alarms) {
+
+ IWL_DEBUG_CALIB("norm FA %u > max FA %u)\n",
+ false_alarms, max_false_alarms);
+
+ val = data->auto_corr_ofdm + AUTO_CORR_STEP_OFDM;
+ data->auto_corr_ofdm =
+ min((u32)ranges->auto_corr_max_ofdm, val);
+
+ val = data->auto_corr_ofdm_mrc + AUTO_CORR_STEP_OFDM;
+ data->auto_corr_ofdm_mrc =
+ min((u32)ranges->auto_corr_max_ofdm_mrc, val);
+
+ val = data->auto_corr_ofdm_x1 + AUTO_CORR_STEP_OFDM;
+ data->auto_corr_ofdm_x1 =
+ min((u32)ranges->auto_corr_max_ofdm_x1, val);
+
+ val = data->auto_corr_ofdm_mrc_x1 + AUTO_CORR_STEP_OFDM;
+ data->auto_corr_ofdm_mrc_x1 =
+ min((u32)ranges->auto_corr_max_ofdm_mrc_x1, val);
+ }
+
+ /* Else if we got fewer than desired, increase sensitivity */
+ else if (false_alarms < min_false_alarms) {
+
+ IWL_DEBUG_CALIB("norm FA %u < min FA %u\n",
+ false_alarms, min_false_alarms);
+
+ val = data->auto_corr_ofdm - AUTO_CORR_STEP_OFDM;
+ data->auto_corr_ofdm =
+ max((u32)ranges->auto_corr_min_ofdm, val);
+
+ val = data->auto_corr_ofdm_mrc - AUTO_CORR_STEP_OFDM;
+ data->auto_corr_ofdm_mrc =
+ max((u32)ranges->auto_corr_min_ofdm_mrc, val);
+
+ val = data->auto_corr_ofdm_x1 - AUTO_CORR_STEP_OFDM;
+ data->auto_corr_ofdm_x1 =
+ max((u32)ranges->auto_corr_min_ofdm_x1, val);
+
+ val = data->auto_corr_ofdm_mrc_x1 - AUTO_CORR_STEP_OFDM;
+ data->auto_corr_ofdm_mrc_x1 =
+ max((u32)ranges->auto_corr_min_ofdm_mrc_x1, val);
+ } else {
+ IWL_DEBUG_CALIB("min FA %u < norm FA %u < max FA %u OK\n",
+ min_false_alarms, false_alarms, max_false_alarms);
+ }
+ return 0;
+}
+
+/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
+static int iwl_sensitivity_write(struct iwl_priv *priv)
+{
+ int ret = 0;
+ struct iwl_sensitivity_cmd cmd ;
+ struct iwl_sensitivity_data *data = NULL;
+ struct iwl_host_cmd cmd_out = {
+ .id = SENSITIVITY_CMD,
+ .len = sizeof(struct iwl_sensitivity_cmd),
+ .meta.flags = CMD_ASYNC,
+ .data = &cmd,
+ };
+
+ data = &(priv->sensitivity_data);
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX] =
+ cpu_to_le16((u16)data->auto_corr_ofdm);
+ cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX] =
+ cpu_to_le16((u16)data->auto_corr_ofdm_mrc);
+ cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX] =
+ cpu_to_le16((u16)data->auto_corr_ofdm_x1);
+ cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX] =
+ cpu_to_le16((u16)data->auto_corr_ofdm_mrc_x1);
+
+ cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX] =
+ cpu_to_le16((u16)data->auto_corr_cck);
+ cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX] =
+ cpu_to_le16((u16)data->auto_corr_cck_mrc);
+
+ cmd.table[HD_MIN_ENERGY_CCK_DET_INDEX] =
+ cpu_to_le16((u16)data->nrg_th_cck);
+ cmd.table[HD_MIN_ENERGY_OFDM_DET_INDEX] =
+ cpu_to_le16((u16)data->nrg_th_ofdm);
+
+ cmd.table[HD_BARKER_CORR_TH_ADD_MIN_INDEX] =
+ __constant_cpu_to_le16(190);
+ cmd.table[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] =
+ __constant_cpu_to_le16(390);
+ cmd.table[HD_OFDM_ENERGY_TH_IN_INDEX] =
+ __constant_cpu_to_le16(62);
+
+ IWL_DEBUG_CALIB("ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n",
+ data->auto_corr_ofdm, data->auto_corr_ofdm_mrc,
+ data->auto_corr_ofdm_x1, data->auto_corr_ofdm_mrc_x1,
+ data->nrg_th_ofdm);
+
+ IWL_DEBUG_CALIB("cck: ac %u mrc %u thresh %u\n",
+ data->auto_corr_cck, data->auto_corr_cck_mrc,
+ data->nrg_th_cck);
+
+ /* Update uCode's "work" table, and copy it to DSP */
+ cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE;
+
+ /* Don't send command to uCode if nothing has changed */
+ if (!memcmp(&cmd.table[0], &(priv->sensitivity_tbl[0]),
+ sizeof(u16)*HD_TABLE_SIZE)) {
+ IWL_DEBUG_CALIB("No change in SENSITIVITY_CMD\n");
+ return 0;
+ }
+
+ /* Copy table for comparison next time */
+ memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]),
+ sizeof(u16)*HD_TABLE_SIZE);
+
+ ret = iwl_send_cmd(priv, &cmd_out);
+ if (ret)
+ IWL_ERROR("SENSITIVITY_CMD failed\n");
+
+ return ret;
+}
+
+void iwl_init_sensitivity(struct iwl_priv *priv)
+{
+ int ret = 0;
+ int i;
+ struct iwl_sensitivity_data *data = NULL;
+ const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens;
+
+ if (priv->disable_sens_cal)
+ return;
+
+ IWL_DEBUG_CALIB("Start iwl_init_sensitivity\n");
+
+ /* Clear driver's sensitivity algo data */
+ data = &(priv->sensitivity_data);
+
+ if (ranges == NULL)
+ /* can happen if IWLWIFI_RUN_TIME_CALIB is selected
+ * but no IWLXXXX_RUN_TIME_CALIB for specific is selected */
+ return;
+
+ memset(data, 0, sizeof(struct iwl_sensitivity_data));
+
+ data->num_in_cck_no_fa = 0;
+ data->nrg_curr_state = IWL_FA_TOO_MANY;
+ data->nrg_prev_state = IWL_FA_TOO_MANY;
+ data->nrg_silence_ref = 0;
+ data->nrg_silence_idx = 0;
+ data->nrg_energy_idx = 0;
+
+ for (i = 0; i < 10; i++)
+ data->nrg_value[i] = 0;
+
+ for (i = 0; i < NRG_NUM_PREV_STAT_L; i++)
+ data->nrg_silence_rssi[i] = 0;
+
+ data->auto_corr_ofdm = 90;
+ data->auto_corr_ofdm_mrc = ranges->auto_corr_min_ofdm_mrc;
+ data->auto_corr_ofdm_x1 = ranges->auto_corr_min_ofdm_x1;
+ data->auto_corr_ofdm_mrc_x1 = ranges->auto_corr_min_ofdm_mrc_x1;
+ data->auto_corr_cck = AUTO_CORR_CCK_MIN_VAL_DEF;
+ data->auto_corr_cck_mrc = ranges->auto_corr_min_cck_mrc;
+ data->nrg_th_cck = ranges->nrg_th_cck;
+ data->nrg_th_ofdm = ranges->nrg_th_ofdm;
+
+ data->last_bad_plcp_cnt_ofdm = 0;
+ data->last_fa_cnt_ofdm = 0;
+ data->last_bad_plcp_cnt_cck = 0;
+ data->last_fa_cnt_cck = 0;
+
+ ret |= iwl_sensitivity_write(priv);
+ IWL_DEBUG_CALIB("<<return 0x%X\n", ret);
+}
+EXPORT_SYMBOL(iwl_init_sensitivity);
+
+void iwl_sensitivity_calibration(struct iwl_priv *priv,
+ struct iwl4965_notif_statistics *resp)
+{
+ u32 rx_enable_time;
+ u32 fa_cck;
+ u32 fa_ofdm;
+ u32 bad_plcp_cck;
+ u32 bad_plcp_ofdm;
+ u32 norm_fa_ofdm;
+ u32 norm_fa_cck;
+ struct iwl_sensitivity_data *data = NULL;
+ struct statistics_rx_non_phy *rx_info = &(resp->rx.general);
+ struct statistics_rx *statistics = &(resp->rx);
+ unsigned long flags;
+ struct statistics_general_data statis;
+
+ if (priv->disable_sens_cal)
+ return;
+
+ data = &(priv->sensitivity_data);
+
+ if (!iwl_is_associated(priv)) {
+ IWL_DEBUG_CALIB("<< - not associated\n");
+ return;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
+ IWL_DEBUG_CALIB("<< invalid data.\n");
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return;
+ }
+
+ /* Extract Statistics: */
+ rx_enable_time = le32_to_cpu(rx_info->channel_load);
+ fa_cck = le32_to_cpu(statistics->cck.false_alarm_cnt);
+ fa_ofdm = le32_to_cpu(statistics->ofdm.false_alarm_cnt);
+ bad_plcp_cck = le32_to_cpu(statistics->cck.plcp_err);
+ bad_plcp_ofdm = le32_to_cpu(statistics->ofdm.plcp_err);
+
+ statis.beacon_silence_rssi_a =
+ le32_to_cpu(statistics->general.beacon_silence_rssi_a);
+ statis.beacon_silence_rssi_b =
+ le32_to_cpu(statistics->general.beacon_silence_rssi_b);
+ statis.beacon_silence_rssi_c =
+ le32_to_cpu(statistics->general.beacon_silence_rssi_c);
+ statis.beacon_energy_a =
+ le32_to_cpu(statistics->general.beacon_energy_a);
+ statis.beacon_energy_b =
+ le32_to_cpu(statistics->general.beacon_energy_b);
+ statis.beacon_energy_c =
+ le32_to_cpu(statistics->general.beacon_energy_c);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ IWL_DEBUG_CALIB("rx_enable_time = %u usecs\n", rx_enable_time);
+
+ if (!rx_enable_time) {
+ IWL_DEBUG_CALIB("<< RX Enable Time == 0! \n");
+ return;
+ }
+
+ /* These statistics increase monotonically, and do not reset
+ * at each beacon. Calculate difference from last value, or just
+ * use the new statistics value if it has reset or wrapped around. */
+ if (data->last_bad_plcp_cnt_cck > bad_plcp_cck)
+ data->last_bad_plcp_cnt_cck = bad_plcp_cck;
+ else {
+ bad_plcp_cck -= data->last_bad_plcp_cnt_cck;
+ data->last_bad_plcp_cnt_cck += bad_plcp_cck;
+ }
+
+ if (data->last_bad_plcp_cnt_ofdm > bad_plcp_ofdm)
+ data->last_bad_plcp_cnt_ofdm = bad_plcp_ofdm;
+ else {
+ bad_plcp_ofdm -= data->last_bad_plcp_cnt_ofdm;
+ data->last_bad_plcp_cnt_ofdm += bad_plcp_ofdm;
+ }
+
+ if (data->last_fa_cnt_ofdm > fa_ofdm)
+ data->last_fa_cnt_ofdm = fa_ofdm;
+ else {
+ fa_ofdm -= data->last_fa_cnt_ofdm;
+ data->last_fa_cnt_ofdm += fa_ofdm;
+ }
+
+ if (data->last_fa_cnt_cck > fa_cck)
+ data->last_fa_cnt_cck = fa_cck;
+ else {
+ fa_cck -= data->last_fa_cnt_cck;
+ data->last_fa_cnt_cck += fa_cck;
+ }
+
+ /* Total aborted signal locks */
+ norm_fa_ofdm = fa_ofdm + bad_plcp_ofdm;
+ norm_fa_cck = fa_cck + bad_plcp_cck;
+
+ IWL_DEBUG_CALIB("cck: fa %u badp %u ofdm: fa %u badp %u\n", fa_cck,
+ bad_plcp_cck, fa_ofdm, bad_plcp_ofdm);
+
+ iwl_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time);
+ iwl_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis);
+ iwl_sensitivity_write(priv);
+
+ return;
+}
+EXPORT_SYMBOL(iwl_sensitivity_calibration);
+
+/*
+ * Accumulate 20 beacons of signal and noise statistics for each of
+ * 3 receivers/antennas/rx-chains, then figure out:
+ * 1) Which antennas are connected.
+ * 2) Differential rx gain settings to balance the 3 receivers.
+ */
+void iwl_chain_noise_calibration(struct iwl_priv *priv,
+ struct iwl4965_notif_statistics *stat_resp)
+{
+ struct iwl_chain_noise_data *data = NULL;
+
+ u32 chain_noise_a;
+ u32 chain_noise_b;
+ u32 chain_noise_c;
+ u32 chain_sig_a;
+ u32 chain_sig_b;
+ u32 chain_sig_c;
+ u32 average_sig[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
+ u32 average_noise[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
+ u32 max_average_sig;
+ u16 max_average_sig_antenna_i;
+ u32 min_average_noise = MIN_AVERAGE_NOISE_MAX_VALUE;
+ u16 min_average_noise_antenna_i = INITIALIZATION_VALUE;
+ u16 i = 0;
+ u16 rxon_chnum = INITIALIZATION_VALUE;
+ u16 stat_chnum = INITIALIZATION_VALUE;
+ u8 rxon_band24;
+ u8 stat_band24;
+ u32 active_chains = 0;
+ u8 num_tx_chains;
+ unsigned long flags;
+ struct statistics_rx_non_phy *rx_info = &(stat_resp->rx.general);
+
+ if (priv->disable_chain_noise_cal)
+ return;
+
+ data = &(priv->chain_noise_data);
+
+ /* Accumulate just the first 20 beacons after the first association,
+ * then we're done forever. */
+ if (data->state != IWL_CHAIN_NOISE_ACCUMULATE) {
+ if (data->state == IWL_CHAIN_NOISE_ALIVE)
+ IWL_DEBUG_CALIB("Wait for noise calib reset\n");
+ return;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
+ IWL_DEBUG_CALIB(" << Interference data unavailable\n");
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return;
+ }
+
+ rxon_band24 = !!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK);
+ rxon_chnum = le16_to_cpu(priv->staging_rxon.channel);
+ stat_band24 = !!(stat_resp->flag & STATISTICS_REPLY_FLG_BAND_24G_MSK);
+ stat_chnum = le32_to_cpu(stat_resp->flag) >> 16;
+
+ /* Make sure we accumulate data for just the associated channel
+ * (even if scanning). */
+ if ((rxon_chnum != stat_chnum) || (rxon_band24 != stat_band24)) {
+ IWL_DEBUG_CALIB("Stats not from chan=%d, band24=%d\n",
+ rxon_chnum, rxon_band24);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return;
+ }
+
+ /* Accumulate beacon statistics values across 20 beacons */
+ chain_noise_a = le32_to_cpu(rx_info->beacon_silence_rssi_a) &
+ IN_BAND_FILTER;
+ chain_noise_b = le32_to_cpu(rx_info->beacon_silence_rssi_b) &
+ IN_BAND_FILTER;
+ chain_noise_c = le32_to_cpu(rx_info->beacon_silence_rssi_c) &
+ IN_BAND_FILTER;
+
+ chain_sig_a = le32_to_cpu(rx_info->beacon_rssi_a) & IN_BAND_FILTER;
+ chain_sig_b = le32_to_cpu(rx_info->beacon_rssi_b) & IN_BAND_FILTER;
+ chain_sig_c = le32_to_cpu(rx_info->beacon_rssi_c) & IN_BAND_FILTER;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ data->beacon_count++;
+
+ data->chain_noise_a = (chain_noise_a + data->chain_noise_a);
+ data->chain_noise_b = (chain_noise_b + data->chain_noise_b);
+ data->chain_noise_c = (chain_noise_c + data->chain_noise_c);
+
+ data->chain_signal_a = (chain_sig_a + data->chain_signal_a);
+ data->chain_signal_b = (chain_sig_b + data->chain_signal_b);
+ data->chain_signal_c = (chain_sig_c + data->chain_signal_c);
+
+ IWL_DEBUG_CALIB("chan=%d, band24=%d, beacon=%d\n",
+ rxon_chnum, rxon_band24, data->beacon_count);
+ IWL_DEBUG_CALIB("chain_sig: a %d b %d c %d\n",
+ chain_sig_a, chain_sig_b, chain_sig_c);
+ IWL_DEBUG_CALIB("chain_noise: a %d b %d c %d\n",
+ chain_noise_a, chain_noise_b, chain_noise_c);
+
+ /* If this is the 20th beacon, determine:
+ * 1) Disconnected antennas (using signal strengths)
+ * 2) Differential gain (using silence noise) to balance receivers */
+ if (data->beacon_count != CAL_NUM_OF_BEACONS)
+ return;
+
+ /* Analyze signal for disconnected antenna */
+ average_sig[0] = (data->chain_signal_a) / CAL_NUM_OF_BEACONS;
+ average_sig[1] = (data->chain_signal_b) / CAL_NUM_OF_BEACONS;
+ average_sig[2] = (data->chain_signal_c) / CAL_NUM_OF_BEACONS;
+
+ if (average_sig[0] >= average_sig[1]) {
+ max_average_sig = average_sig[0];
+ max_average_sig_antenna_i = 0;
+ active_chains = (1 << max_average_sig_antenna_i);
+ } else {
+ max_average_sig = average_sig[1];
+ max_average_sig_antenna_i = 1;
+ active_chains = (1 << max_average_sig_antenna_i);
+ }
+
+ if (average_sig[2] >= max_average_sig) {
+ max_average_sig = average_sig[2];
+ max_average_sig_antenna_i = 2;
+ active_chains = (1 << max_average_sig_antenna_i);
+ }
+
+ IWL_DEBUG_CALIB("average_sig: a %d b %d c %d\n",
+ average_sig[0], average_sig[1], average_sig[2]);
+ IWL_DEBUG_CALIB("max_average_sig = %d, antenna %d\n",
+ max_average_sig, max_average_sig_antenna_i);
+
+ /* Compare signal strengths for all 3 receivers. */
+ for (i = 0; i < NUM_RX_CHAINS; i++) {
+ if (i != max_average_sig_antenna_i) {
+ s32 rssi_delta = (max_average_sig - average_sig[i]);
+
+ /* If signal is very weak, compared with
+ * strongest, mark it as disconnected. */
+ if (rssi_delta > MAXIMUM_ALLOWED_PATHLOSS)
+ data->disconn_array[i] = 1;
+ else
+ active_chains |= (1 << i);
+ IWL_DEBUG_CALIB("i = %d rssiDelta = %d "
+ "disconn_array[i] = %d\n",
+ i, rssi_delta, data->disconn_array[i]);
+ }
+ }
+
+ num_tx_chains = 0;
+ for (i = 0; i < NUM_RX_CHAINS; i++) {
+ /* loops on all the bits of
+ * priv->hw_setting.valid_tx_ant */
+ u8 ant_msk = (1 << i);
+ if (!(priv->hw_params.valid_tx_ant & ant_msk))
+ continue;
+
+ num_tx_chains++;
+ if (data->disconn_array[i] == 0)
+ /* there is a Tx antenna connected */
+ break;
+ if (num_tx_chains == priv->hw_params.tx_chains_num &&
+ data->disconn_array[i]) {
+ /* This is the last TX antenna and is also
+ * disconnected connect it anyway */
+ data->disconn_array[i] = 0;
+ active_chains |= ant_msk;
+ IWL_DEBUG_CALIB("All Tx chains are disconnected W/A - "
+ "declare %d as connected\n", i);
+ break;
+ }
+ }
+
+ IWL_DEBUG_CALIB("active_chains (bitwise) = 0x%x\n",
+ active_chains);
+
+ /* Save for use within RXON, TX, SCAN commands, etc. */
+ /*priv->valid_antenna = active_chains;*/
+ /*FIXME: should be reflected in RX chains in RXON */
+
+ /* Analyze noise for rx balance */
+ average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS);
+ average_noise[1] = ((data->chain_noise_b)/CAL_NUM_OF_BEACONS);
+ average_noise[2] = ((data->chain_noise_c)/CAL_NUM_OF_BEACONS);
+
+ for (i = 0; i < NUM_RX_CHAINS; i++) {
+ if (!(data->disconn_array[i]) &&
+ (average_noise[i] <= min_average_noise)) {
+ /* This means that chain i is active and has
+ * lower noise values so far: */
+ min_average_noise = average_noise[i];
+ min_average_noise_antenna_i = i;
+ }
+ }
+
+ IWL_DEBUG_CALIB("average_noise: a %d b %d c %d\n",
+ average_noise[0], average_noise[1],
+ average_noise[2]);
+
+ IWL_DEBUG_CALIB("min_average_noise = %d, antenna %d\n",
+ min_average_noise, min_average_noise_antenna_i);
+
+ priv->cfg->ops->utils->gain_computation(priv, average_noise,
+ min_average_noise_antenna_i, min_average_noise);
+}
+EXPORT_SYMBOL(iwl_chain_noise_calibration);
+
+
+void iwl_reset_run_time_calib(struct iwl_priv *priv)
+{
+ int i;
+ memset(&(priv->sensitivity_data), 0,
+ sizeof(struct iwl_sensitivity_data));
+ memset(&(priv->chain_noise_data), 0,
+ sizeof(struct iwl_chain_noise_data));
+ for (i = 0; i < NUM_RX_CHAINS; i++)
+ priv->chain_noise_data.delta_gain_code[i] =
+ CHAIN_NOISE_DELTA_GAIN_INIT_VAL;
+
+ /* Ask for statistics now, the uCode will send notification
+ * periodically after association */
+ iwl_send_statistics_request(priv, CMD_ASYNC);
+}
+EXPORT_SYMBOL(iwl_reset_run_time_calib);
+
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.h b/drivers/net/wireless/iwlwifi/iwl-calib.h
new file mode 100644
index 0000000..b8e57c5
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.h
@@ -0,0 +1,109 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * Tomas Winkler <tomas.winkler@intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2008 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+#ifndef __iwl_calib_h__
+#define __iwl_calib_h__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <net/mac80211.h>
+#include "iwl-eeprom.h"
+#include "iwl-core.h"
+#include "iwl-dev.h"
+
+#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
+void iwl_chain_noise_calibration(struct iwl_priv *priv,
+ struct iwl4965_notif_statistics *stat_resp);
+void iwl_sensitivity_calibration(struct iwl_priv *priv,
+ struct iwl4965_notif_statistics *resp);
+
+void iwl_init_sensitivity(struct iwl_priv *priv);
+void iwl_reset_run_time_calib(struct iwl_priv *priv);
+static inline void iwl_chain_noise_reset(struct iwl_priv *priv)
+{
+
+ if (!priv->disable_chain_noise_cal &&
+ priv->cfg->ops->utils->chain_noise_reset)
+ priv->cfg->ops->utils->chain_noise_reset(priv);
+}
+#else
+static inline void iwl_chain_noise_calibration(struct iwl_priv *priv,
+ struct iwl4965_notif_statistics *stat_resp)
+{
+}
+static inline void iwl_sensitivity_calibration(struct iwl_priv *priv,
+ struct iwl4965_notif_statistics *resp)
+{
+}
+static inline void iwl_init_sensitivity(struct iwl_priv *priv)
+{
+}
+static inline void iwl_chain_noise_reset(struct iwl_priv *priv)
+{
+}
+static inline void iwl_reset_run_time_calib(struct iwl_priv *priv)
+{
+}
+#endif
+
+#endif /* __iwl_calib_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
similarity index 91%
rename from drivers/net/wireless/iwlwifi/iwl-4965-commands.h
rename to drivers/net/wireless/iwlwifi/iwl-commands.h
index 3bcd107..fb6f5ff 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__
@@ -93,6 +93,11 @@
REPLY_LEDS_CMD = 0x48,
REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */
+ /* WiMAX coexistence */
+ COEX_PRIORITY_TABLE_CMD = 0x5a, /*5000 only */
+ COEX_MEDIUM_NOTIFICATION = 0x5b,
+ COEX_EVENT_CMD = 0x5c,
+
/* 802.11h related */
RADAR_NOTIFICATION = 0x70, /* not used */
REPLY_QUIET_CMD = 0x71, /* not used */
@@ -269,10 +274,11 @@
* 10 B active, A inactive
* 11 Both active
*/
-#define RATE_MCS_ANT_POS 14
-#define RATE_MCS_ANT_A_MSK 0x04000
-#define RATE_MCS_ANT_B_MSK 0x08000
-#define RATE_MCS_ANT_AB_MSK 0x0C000
+#define RATE_MCS_ANT_POS 14
+#define RATE_MCS_ANT_A_MSK 0x04000
+#define RATE_MCS_ANT_B_MSK 0x08000
+#define RATE_MCS_ANT_C_MSK 0x10000
+#define RATE_MCS_ANT_ABC_MSK 0x1C000
/**
@@ -367,7 +373,7 @@
* 3) Tx gain compensation to balance 4965's 2 Tx chains for MIMO operation,
* for each of 5 frequency ranges.
*/
-struct iwl4965_init_alive_resp {
+struct iwl_init_alive_resp {
u8 ucode_minor;
u8 ucode_major;
__le16 reserved1;
@@ -443,7 +449,7 @@
* The Linux driver can print both logs to the system log when a uCode error
* occurs.
*/
-struct iwl4965_alive_resp {
+struct iwl_alive_resp {
u8 ucode_minor;
u8 ucode_major;
__le16 reserved1;
@@ -467,7 +473,7 @@
/*
* REPLY_ERROR = 0x2 (response only, not a command)
*/
-struct iwl4965_error_resp {
+struct iwl_error_resp {
__le32 error_type;
u8 cmd_id;
u8 reserved1;
@@ -599,6 +605,46 @@
u8 ofdm_ht_dual_stream_basic_rates;
} __attribute__ ((packed));
+/* 5000 HW just extend this cmmand */
+struct iwl_rxon_cmd {
+ u8 node_addr[6];
+ __le16 reserved1;
+ u8 bssid_addr[6];
+ __le16 reserved2;
+ u8 wlap_bssid_addr[6];
+ __le16 reserved3;
+ u8 dev_type;
+ u8 air_propagation;
+ __le16 rx_chain;
+ u8 ofdm_basic_rates;
+ u8 cck_basic_rates;
+ __le16 assoc_id;
+ __le32 flags;
+ __le32 filter_flags;
+ __le16 channel;
+ u8 ofdm_ht_single_stream_basic_rates;
+ u8 ofdm_ht_dual_stream_basic_rates;
+ u8 ofdm_ht_triple_stream_basic_rates;
+ u8 reserved5;
+ __le16 acquisition_data;
+ __le16 reserved6;
+} __attribute__ ((packed));
+
+struct iwl5000_rxon_assoc_cmd {
+ __le32 flags;
+ __le32 filter_flags;
+ u8 ofdm_basic_rates;
+ u8 cck_basic_rates;
+ __le16 reserved1;
+ u8 ofdm_ht_single_stream_basic_rates;
+ u8 ofdm_ht_dual_stream_basic_rates;
+ u8 ofdm_ht_triple_stream_basic_rates;
+ u8 reserved2;
+ __le16 rx_chain_select_flags;
+ __le16 acquisition_data;
+ __le32 reserved3;
+} __attribute__ ((packed));
+
/*
* REPLY_RXON_ASSOC = 0x11 (command, has simple generic response)
*/
@@ -613,6 +659,9 @@
__le16 reserved;
} __attribute__ ((packed));
+
+
+
/*
* REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
*/
@@ -711,6 +760,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
@@ -766,6 +817,20 @@
u8 key[16]; /* 16-byte unicast decryption key */
} __attribute__ ((packed));
+/* 5000 */
+struct iwl_keyinfo {
+ __le16 key_flags;
+ u8 tkip_rx_tsc_byte2; /* TSC[2] for key mix ph1 detection */
+ u8 reserved1;
+ __le16 tkip_rx_ttak[5]; /* 10-byte unicast TKIP TTAK */
+ u8 key_offset;
+ u8 reserved2;
+ u8 key[16]; /* 16-byte unicast decryption key */
+ __le64 tx_secur_seq_cnt;
+ __le64 hw_tkip_mic_rx_key;
+ __le64 hw_tkip_mic_tx_key;
+} __attribute__ ((packed));
+
/**
* struct sta_id_modify
* @addr[ETH_ALEN]: station's MAC address
@@ -841,6 +906,38 @@
__le32 reserved2;
} __attribute__ ((packed));
+/* 5000 */
+struct iwl_addsta_cmd {
+ u8 mode; /* 1: modify existing, 0: add new station */
+ u8 reserved[3];
+ struct sta_id_modify sta;
+ struct iwl_keyinfo key;
+ __le32 station_flags; /* STA_FLG_* */
+ __le32 station_flags_msk; /* STA_FLG_* */
+
+ /* bit field to disable (1) or enable (0) Tx for Traffic ID (TID)
+ * corresponding to bit (e.g. bit 5 controls TID 5).
+ * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */
+ __le16 tid_disable_tx;
+
+ __le16 reserved1;
+
+ /* TID for which to add block-ack support.
+ * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
+ u8 add_immediate_ba_tid;
+
+ /* TID for which to remove block-ack support.
+ * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */
+ u8 remove_immediate_ba_tid;
+
+ /* Starting Sequence Number for added block-ack support.
+ * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
+ __le16 add_immediate_ba_ssn;
+
+ __le32 reserved2;
+} __attribute__ ((packed));
+
+
#define ADD_STA_SUCCESS_MSK 0x1
#define ADD_STA_NO_ROOM_IN_TABLE 0x2
#define ADD_STA_NO_BLOCK_ACK_RESOURCE 0x4
@@ -848,10 +945,28 @@
/*
* REPLY_ADD_STA = 0x18 (response)
*/
-struct iwl4965_add_sta_resp {
+struct iwl_add_sta_resp {
u8 status; /* ADD_STA_* */
} __attribute__ ((packed));
+#define REM_STA_SUCCESS_MSK 0x1
+/*
+ * REPLY_REM_STA = 0x19 (response)
+ */
+struct iwl_rem_sta_resp {
+ u8 status;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_REM_STA = 0x19 (command)
+ */
+struct iwl_rem_sta_cmd {
+ u8 num_sta; /* number of removed stations */
+ u8 reserved[3];
+ u8 addr[ETH_ALEN]; /* MAC addr of the first station */
+ u8 reserved2[2];
+} __attribute__ ((packed));
+
/*
* REPLY_WEP_KEY = 0x20
*/
@@ -1100,6 +1215,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.
@@ -1113,7 +1236,7 @@
/*
* REPLY_TX = 0x1c (command)
*/
-struct iwl4965_tx_cmd {
+struct iwl_tx_cmd {
/*
* MPDU byte count:
* MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size,
@@ -1259,6 +1382,15 @@
TX_ABORT_REQUIRED_MSK = 0x80000000, /* bits 31:31 */
};
+static inline int iwl_is_tx_success(u32 status)
+{
+ status &= TX_STATUS_MSK;
+ return (status == TX_STATUS_SUCCESS)
+ || (status == TX_STATUS_DIRECT_DONE);
+}
+
+
+
/* *******************************
* TX aggregation status
******************************* */
@@ -1313,6 +1445,11 @@
* within the sending station (this 4965), rather than whether it was
* received successfully by the destination station.
*/
+struct agg_tx_status {
+ __le16 status;
+ __le16 sequence;
+} __attribute__ ((packed));
+
struct iwl4965_tx_resp {
u8 frame_count; /* 1 no aggregation, >1 aggregation */
u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */
@@ -1347,11 +1484,6 @@
__le32 status; /* TX status (for aggregation status of 1st frame) */
} __attribute__ ((packed));
-struct agg_tx_status {
- __le16 status;
- __le16 sequence;
-} __attribute__ ((packed));
-
struct iwl4965_tx_resp_agg {
u8 frame_count; /* 1 no aggregation, >1 aggregation */
u8 reserved1;
@@ -1366,6 +1498,44 @@
/* of 1st frame) */
} __attribute__ ((packed));
+struct iwl5000_tx_resp {
+ u8 frame_count; /* 1 no aggregation, >1 aggregation */
+ u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */
+ u8 failure_rts; /* # failures due to unsuccessful RTS */
+ u8 failure_frame; /* # failures due to no ACK (unused for agg) */
+
+ /* For non-agg: Rate at which frame was successful.
+ * For agg: Rate at which all frames were transmitted. */
+ __le32 rate_n_flags; /* RATE_MCS_* */
+
+ /* For non-agg: RTS + CTS + frame tx attempts time + ACK.
+ * For agg: RTS + CTS + aggregation tx time + block-ack time. */
+ __le16 wireless_media_time; /* uSecs */
+
+ __le16 reserved;
+ __le32 pa_power1; /* RF power amplifier measurement (not used) */
+ __le32 pa_power2;
+
+ __le32 tfd_info;
+ __le16 seq_ctl;
+ __le16 byte_cnt;
+ __le32 tlc_info;
+ /*
+ * For non-agg: frame status TX_STATUS_*
+ * For agg: status of 1st frame, AGG_TX_STATE_*; other frame status
+ * fields follow this one, up to frame_count.
+ * Bit fields:
+ * 11- 0: AGG_TX_STATE_* status code
+ * 15-12: Retry count for 1st frame in aggregation (retries
+ * occur if tx failed for this frame when it was a
+ * member of a previous aggregation block). If rate
+ * scaling is used, retry count indicates the rate
+ * table entry used for all frames in the new agg.
+ * 31-16: Sequence # for this frame's Tx cmd (not SSN!)
+ */
+ struct agg_tx_status status; /* TX status (in aggregation -
+ * status of 1st frame) */
+} __attribute__ ((packed));
/*
* REPLY_COMPRESSED_BA = 0xc5 (response only, not a command)
*
@@ -1853,6 +2023,7 @@
#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK __constant_cpu_to_le16(1 << 0)
#define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le16(1 << 2)
#define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le16(1 << 3)
+#define IWL_POWER_FAST_PD __constant_cpu_to_le16(1 << 4)
struct iwl4965_powertable_cmd {
__le16 flags;
@@ -2051,7 +2222,7 @@
/* For active scans (set to all-0s for passive scans).
* Does not include payload. Must specify Tx rate; no rate scaling. */
- struct iwl4965_tx_cmd tx_cmd;
+ struct iwl_tx_cmd tx_cmd;
/* For directed active scans (set to all-0s otherwise) */
struct iwl4965_ssid_ie direct_scan[PROBE_OPTION_MAX];
@@ -2148,7 +2319,7 @@
* REPLY_TX_BEACON = 0x91 (command, has simple generic response)
*/
struct iwl4965_tx_beacon_cmd {
- struct iwl4965_tx_cmd tx;
+ struct iwl_tx_cmd tx;
__le16 tim_idx;
u8 tim_size;
u8 reserved1;
@@ -2559,7 +2730,7 @@
*/
/*
- * Table entries in SENSITIVITY_CMD (struct iwl4965_sensitivity_cmd)
+ * Table entries in SENSITIVITY_CMD (struct iwl_sensitivity_cmd)
*/
#define HD_TABLE_SIZE (11) /* number of entries */
#define HD_MIN_ENERGY_CCK_DET_INDEX (0) /* table indexes */
@@ -2574,18 +2745,18 @@
#define HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX (9)
#define HD_OFDM_ENERGY_TH_IN_INDEX (10)
-/* Control field in struct iwl4965_sensitivity_cmd */
+/* Control field in struct iwl_sensitivity_cmd */
#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE __constant_cpu_to_le16(0)
#define SENSITIVITY_CMD_CONTROL_WORK_TABLE __constant_cpu_to_le16(1)
/**
- * struct iwl4965_sensitivity_cmd
+ * struct iwl_sensitivity_cmd
* @control: (1) updates working table, (0) updates default table
* @table: energy threshold values, use HD_* as index into table
*
* Always use "1" in "control" to update uCode's working table and DSP.
*/
-struct iwl4965_sensitivity_cmd {
+struct iwl_sensitivity_cmd {
__le16 control; /* always use "1" */
__le16 table[HD_TABLE_SIZE]; /* use HD_* as index */
} __attribute__ ((packed));
@@ -2659,6 +2830,86 @@
u8 reserved1;
} __attribute__ ((packed));
+/* Phy calibration command for 5000 series */
+
+enum {
+ IWL5000_PHY_CALIBRATE_DC_CMD = 8,
+ IWL5000_PHY_CALIBRATE_LO_CMD = 9,
+ IWL5000_PHY_CALIBRATE_RX_BB_CMD = 10,
+ IWL5000_PHY_CALIBRATE_TX_IQ_CMD = 11,
+ IWL5000_PHY_CALIBRATE_RX_IQ_CMD = 12,
+ IWL5000_PHY_CALIBRATION_NOISE_CMD = 13,
+ IWL5000_PHY_CALIBRATE_AGC_TABLE_CMD = 14,
+ IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15,
+ IWL5000_PHY_CALIBRATE_BASE_BAND_CMD = 16,
+ IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD = 17,
+ IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD = 18,
+ IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD = 19,
+};
+
+enum {
+ CALIBRATION_CFG_CMD = 0x65,
+ CALIBRATION_RES_NOTIFICATION = 0x66,
+ CALIBRATION_COMPLETE_NOTIFICATION = 0x67
+};
+
+struct iwl_cal_crystal_freq_cmd {
+ u8 cap_pin1;
+ u8 cap_pin2;
+} __attribute__ ((packed));
+
+struct iwl5000_calibration {
+ u8 op_code;
+ u8 first_group;
+ u8 num_groups;
+ u8 all_data_valid;
+ struct iwl_cal_crystal_freq_cmd data;
+} __attribute__ ((packed));
+
+#define IWL_CALIB_INIT_CFG_ALL __constant_cpu_to_le32(0xffffffff)
+
+struct iwl_calib_cfg_elmnt_s {
+ __le32 is_enable;
+ __le32 start;
+ __le32 send_res;
+ __le32 apply_res;
+ __le32 reserved;
+} __attribute__ ((packed));
+
+struct iwl_calib_cfg_status_s {
+ struct iwl_calib_cfg_elmnt_s once;
+ struct iwl_calib_cfg_elmnt_s perd;
+ __le32 flags;
+} __attribute__ ((packed));
+
+struct iwl5000_calib_cfg_cmd {
+ struct iwl_calib_cfg_status_s ucd_calib_cfg;
+ struct iwl_calib_cfg_status_s drv_calib_cfg;
+ __le32 reserved1;
+} __attribute__ ((packed));
+
+struct iwl5000_calib_hdr {
+ u8 op_code;
+ u8 first_group;
+ u8 groups_num;
+ u8 data_valid;
+} __attribute__ ((packed));
+
+struct iwl5000_calibration_chain_noise_reset_cmd {
+ u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */
+ u8 flags; /* not used */
+ __le16 reserved;
+} __attribute__ ((packed));
+
+struct iwl5000_calibration_chain_noise_gain_cmd {
+ u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */
+ u8 flags; /* not used */
+ __le16 reserved;
+ u8 delta_gain_1;
+ u8 delta_gain_2;
+ __le16 reserved1;
+} __attribute__ ((packed));
+
/******************************************************************************
* (12)
* Miscellaneous Commands:
@@ -2682,30 +2933,81 @@
u8 reserved;
} __attribute__ ((packed));
+/*
+ * Coexistence WIFI/WIMAX Command
+ * COEX_PRIORITY_TABLE_CMD = 0x5a
+ *
+ */
+enum {
+ COEX_UNASSOC_IDLE = 0,
+ COEX_UNASSOC_MANUAL_SCAN = 1,
+ COEX_UNASSOC_AUTO_SCAN = 2,
+ COEX_CALIBRATION = 3,
+ COEX_PERIODIC_CALIBRATION = 4,
+ COEX_CONNECTION_ESTAB = 5,
+ COEX_ASSOCIATED_IDLE = 6,
+ COEX_ASSOC_MANUAL_SCAN = 7,
+ COEX_ASSOC_AUTO_SCAN = 8,
+ COEX_ASSOC_ACTIVE_LEVEL = 9,
+ COEX_RF_ON = 10,
+ COEX_RF_OFF = 11,
+ COEX_STAND_ALONE_DEBUG = 12,
+ COEX_IPAN_ASSOC_LEVEL = 13,
+ COEX_RSRVD1 = 14,
+ COEX_RSRVD2 = 15,
+ COEX_NUM_OF_EVENTS = 16
+};
+
+struct iwl_wimax_coex_event_entry {
+ u8 request_prio;
+ u8 win_medium_prio;
+ u8 reserved;
+ u8 flags;
+} __attribute__ ((packed));
+
+/* COEX flag masks */
+
+/* Staion table is valid */
+#define COEX_FLAGS_STA_TABLE_VALID_MSK (0x1)
+/* UnMask wakeup src at unassociated sleep */
+#define COEX_FLAGS_UNASSOC_WA_UNMASK_MSK (0x4)
+/* UnMask wakeup src at associated sleep */
+#define COEX_FLAGS_ASSOC_WA_UNMASK_MSK (0x8)
+/* Enable CoEx feature. */
+#define COEX_FLAGS_COEX_ENABLE_MSK (0x80)
+
+struct iwl_wimax_coex_cmd {
+ u8 flags;
+ u8 reserved[3];
+ struct iwl_wimax_coex_event_entry sta_prio[COEX_NUM_OF_EVENTS];
+} __attribute__ ((packed));
+
/******************************************************************************
* (13)
* Union of all expected notifications/responses:
*
*****************************************************************************/
-struct iwl4965_rx_packet {
+struct iwl_rx_packet {
__le32 len;
struct iwl_cmd_header hdr;
union {
- struct iwl4965_alive_resp alive_frame;
+ struct iwl_alive_resp alive_frame;
struct iwl4965_rx_frame rx_frame;
struct iwl4965_tx_resp tx_resp;
struct iwl4965_spectrum_notification spectrum_notif;
struct iwl4965_csa_notification csa_notif;
- struct iwl4965_error_resp err_resp;
+ struct iwl_error_resp err_resp;
struct iwl4965_card_state_notif card_state_notif;
struct iwl4965_beacon_notif beacon_status;
- struct iwl4965_add_sta_resp add_sta;
+ struct iwl_add_sta_resp add_sta;
+ struct iwl_rem_sta_resp rem_sta;
struct iwl4965_sleep_notification sleep_notif;
struct iwl4965_spectrum_resp spectrum;
struct iwl4965_notif_statistics stats;
struct iwl4965_compressed_ba_resp compressed_ba;
struct iwl4965_missed_beacon_notif missed_beacon;
+ struct iwl5000_calibration calib;
__le32 status;
u8 raw[0];
} u;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 2dfd982..61716ba 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");
@@ -44,10 +46,49 @@
MODULE_AUTHOR(DRV_COPYRIGHT);
MODULE_LICENSE("GPL");
-#ifdef CONFIG_IWLWIFI_DEBUG
-u32 iwl_debug_level;
-EXPORT_SYMBOL(iwl_debug_level);
-#endif
+#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \
+ [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \
+ IWL_RATE_SISO_##s##M_PLCP, \
+ IWL_RATE_MIMO2_##s##M_PLCP,\
+ IWL_RATE_MIMO3_##s##M_PLCP,\
+ IWL_RATE_##r##M_IEEE, \
+ IWL_RATE_##ip##M_INDEX, \
+ IWL_RATE_##in##M_INDEX, \
+ IWL_RATE_##rp##M_INDEX, \
+ IWL_RATE_##rn##M_INDEX, \
+ IWL_RATE_##pp##M_INDEX, \
+ IWL_RATE_##np##M_INDEX }
+
+/*
+ * Parameter order:
+ * rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate
+ *
+ * If there isn't a valid next or previous rate then INV is used which
+ * maps to IWL_RATE_INVALID
+ *
+ */
+const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
+ IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2), /* 1mbps */
+ IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5), /* 2mbps */
+ IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11), /*5.5mbps */
+ IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18), /* 11mbps */
+ IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11), /* 6mbps */
+ IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11), /* 9mbps */
+ IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18), /* 12mbps */
+ IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24), /* 18mbps */
+ IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36), /* 24mbps */
+ IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48), /* 36mbps */
+ IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54), /* 48mbps */
+ IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */
+ IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */
+ /* FIXME:RS: ^^ should be INV (legacy) */
+};
+EXPORT_SYMBOL(iwl_rates);
+
+
+const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+EXPORT_SYMBOL(iwl_bcast_addr);
+
/* This function both allocates and initializes hw and priv. */
struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
@@ -72,6 +113,108 @@
}
EXPORT_SYMBOL(iwl_alloc_all);
+void iwl_hw_detect(struct iwl_priv *priv)
+{
+ priv->hw_rev = _iwl_read32(priv, CSR_HW_REV);
+ priv->hw_wa_rev = _iwl_read32(priv, CSR_HW_REV_WA_REG);
+ pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &priv->rev_id);
+}
+EXPORT_SYMBOL(iwl_hw_detect);
+
+/* Tell nic where to find the "keep warm" buffer */
+int iwl_kw_init(struct iwl_priv *priv)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ ret = iwl_grab_nic_access(priv);
+ if (ret)
+ goto out;
+
+ iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG,
+ priv->kw.dma_addr >> 4);
+ iwl_release_nic_access(priv);
+out:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return ret;
+}
+
+int iwl_kw_alloc(struct iwl_priv *priv)
+{
+ struct pci_dev *dev = priv->pci_dev;
+ struct iwl_kw *kw = &priv->kw;
+
+ kw->size = IWL_KW_SIZE;
+ kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr);
+ if (!kw->v_addr)
+ return -ENOMEM;
+
+ return 0;
+}
+
+/**
+ * iwl_kw_free - Free the "keep warm" buffer
+ */
+void iwl_kw_free(struct iwl_priv *priv)
+{
+ struct pci_dev *dev = priv->pci_dev;
+ struct iwl_kw *kw = &priv->kw;
+
+ if (kw->v_addr) {
+ pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr);
+ memset(kw, 0, sizeof(*kw));
+ }
+}
+
+int iwl_hw_nic_init(struct iwl_priv *priv)
+{
+ unsigned long flags;
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ int ret;
+
+ /* nic_init */
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->cfg->ops->lib->apm_ops.init(priv);
+ iwl_write32(priv, CSR_INT_COALESCING, 512 / 32);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN);
+
+ priv->cfg->ops->lib->apm_ops.config(priv);
+
+ /* Allocate the RX queue, or reset if it is already allocated */
+ if (!rxq->bd) {
+ ret = iwl_rx_queue_alloc(priv);
+ if (ret) {
+ IWL_ERROR("Unable to initialize Rx queue\n");
+ return -ENOMEM;
+ }
+ } else
+ iwl_rx_queue_reset(priv, rxq);
+
+ iwl_rx_replenish(priv);
+
+ iwl_rx_init(priv, rxq);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ rxq->need_update = 1;
+ iwl_rx_queue_update_write_ptr(priv, rxq);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* Allocate and init all Tx and Command queues */
+ ret = iwl_txq_ctx_reset(priv);
+ if (ret)
+ return ret;
+
+ set_bit(STATUS_INIT, &priv->status);
+
+ return 0;
+}
+EXPORT_SYMBOL(iwl_hw_nic_init);
+
/**
* iwlcore_clear_stations_table - Clear the driver's station table
*
@@ -90,7 +233,7 @@
}
EXPORT_SYMBOL(iwlcore_clear_stations_table);
-void iwlcore_reset_qos(struct iwl_priv *priv)
+void iwl_reset_qos(struct iwl_priv *priv)
{
u16 cw_min = 15;
u16 cw_max = 1023;
@@ -176,7 +319,427 @@
spin_unlock_irqrestore(&priv->lock, flags);
}
-EXPORT_SYMBOL(iwlcore_reset_qos);
+EXPORT_SYMBOL(iwl_reset_qos);
+
+#ifdef CONFIG_IWL4965_HT
+#define MAX_BIT_RATE_40_MHZ 0x96; /* 150 Mbps */
+#define MAX_BIT_RATE_20_MHZ 0x48; /* 72 Mbps */
+static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
+ struct ieee80211_ht_info *ht_info,
+ enum ieee80211_band band)
+{
+ u16 max_bit_rate = 0;
+ u8 rx_chains_num = priv->hw_params.rx_chains_num;
+ u8 tx_chains_num = priv->hw_params.tx_chains_num;
+
+ ht_info->cap = 0;
+ memset(ht_info->supp_mcs_set, 0, 16);
+
+ ht_info->ht_supported = 1;
+
+ ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD;
+ ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20;
+ ht_info->cap |= (u16)(IEEE80211_HT_CAP_MIMO_PS &
+ (IWL_MIMO_PS_NONE << 2));
+
+ max_bit_rate = MAX_BIT_RATE_20_MHZ;
+ if (priv->hw_params.fat_channel & BIT(band)) {
+ ht_info->cap |= (u16)IEEE80211_HT_CAP_SUP_WIDTH;
+ ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_40;
+ ht_info->supp_mcs_set[4] = 0x01;
+ max_bit_rate = MAX_BIT_RATE_40_MHZ;
+ }
+
+ if (priv->cfg->mod_params->amsdu_size_8K)
+ ht_info->cap |= (u16)IEEE80211_HT_CAP_MAX_AMSDU;
+
+ ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
+ ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF;
+
+ ht_info->supp_mcs_set[0] = 0xFF;
+ if (rx_chains_num >= 2)
+ ht_info->supp_mcs_set[1] = 0xFF;
+ if (rx_chains_num >= 3)
+ ht_info->supp_mcs_set[2] = 0xFF;
+
+ /* Highest supported Rx data rate */
+ max_bit_rate *= rx_chains_num;
+ ht_info->supp_mcs_set[10] = (u8)(max_bit_rate & 0x00FF);
+ ht_info->supp_mcs_set[11] = (u8)((max_bit_rate & 0xFF00) >> 8);
+
+ /* Tx MCS capabilities */
+ ht_info->supp_mcs_set[12] = IEEE80211_HT_CAP_MCS_TX_DEFINED;
+ if (tx_chains_num != rx_chains_num) {
+ ht_info->supp_mcs_set[12] |= IEEE80211_HT_CAP_MCS_TX_RX_DIFF;
+ ht_info->supp_mcs_set[12] |= ((tx_chains_num - 1) << 2);
+ }
+}
+#else
+static inline void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
+ struct ieee80211_ht_info *ht_info,
+ enum ieee80211_band band)
+{
+}
+#endif /* CONFIG_IWL4965_HT */
+
+static void iwlcore_init_hw_rates(struct iwl_priv *priv,
+ struct ieee80211_rate *rates)
+{
+ int i;
+
+ for (i = 0; i < IWL_RATE_COUNT; i++) {
+ rates[i].bitrate = iwl_rates[i].ieee * 5;
+ rates[i].hw_value = i; /* Rate scaling will work on indexes */
+ rates[i].hw_value_short = i;
+ rates[i].flags = 0;
+ if ((i > IWL_LAST_OFDM_RATE) || (i < IWL_FIRST_OFDM_RATE)) {
+ /*
+ * If CCK != 1M then set short preamble rate flag.
+ */
+ rates[i].flags |=
+ (iwl_rates[i].plcp == IWL_RATE_1M_PLCP) ?
+ 0 : IEEE80211_RATE_SHORT_PREAMBLE;
+ }
+ }
+}
+
+/**
+ * iwlcore_init_geos - Initialize mac80211's geo/channel info based from eeprom
+ */
+static int iwlcore_init_geos(struct iwl_priv *priv)
+{
+ struct iwl_channel_info *ch;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *channels;
+ struct ieee80211_channel *geo_ch;
+ struct ieee80211_rate *rates;
+ int i = 0;
+
+ if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates ||
+ priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) {
+ IWL_DEBUG_INFO("Geography modes already initialized.\n");
+ set_bit(STATUS_GEO_CONFIGURED, &priv->status);
+ return 0;
+ }
+
+ channels = kzalloc(sizeof(struct ieee80211_channel) *
+ priv->channel_count, GFP_KERNEL);
+ if (!channels)
+ return -ENOMEM;
+
+ rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_RATE_COUNT + 1)),
+ GFP_KERNEL);
+ if (!rates) {
+ kfree(channels);
+ return -ENOMEM;
+ }
+
+ /* 5.2GHz channels start after the 2.4GHz channels */
+ sband = &priv->bands[IEEE80211_BAND_5GHZ];
+ sband->channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
+ /* just OFDM */
+ sband->bitrates = &rates[IWL_FIRST_OFDM_RATE];
+ sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE;
+
+ iwlcore_init_ht_hw_capab(priv, &sband->ht_info, IEEE80211_BAND_5GHZ);
+
+ sband = &priv->bands[IEEE80211_BAND_2GHZ];
+ sband->channels = channels;
+ /* OFDM & CCK */
+ sband->bitrates = rates;
+ sband->n_bitrates = IWL_RATE_COUNT;
+
+ iwlcore_init_ht_hw_capab(priv, &sband->ht_info, IEEE80211_BAND_2GHZ);
+
+ priv->ieee_channels = channels;
+ priv->ieee_rates = rates;
+
+ iwlcore_init_hw_rates(priv, rates);
+
+ for (i = 0; i < priv->channel_count; i++) {
+ ch = &priv->channel_info[i];
+
+ /* FIXME: might be removed if scan is OK */
+ if (!is_channel_valid(ch))
+ continue;
+
+ if (is_channel_a_band(ch))
+ sband = &priv->bands[IEEE80211_BAND_5GHZ];
+ else
+ sband = &priv->bands[IEEE80211_BAND_2GHZ];
+
+ geo_ch = &sband->channels[sband->n_channels++];
+
+ geo_ch->center_freq =
+ ieee80211_channel_to_frequency(ch->channel);
+ geo_ch->max_power = ch->max_power_avg;
+ geo_ch->max_antenna_gain = 0xff;
+ geo_ch->hw_value = ch->channel;
+
+ if (is_channel_valid(ch)) {
+ if (!(ch->flags & EEPROM_CHANNEL_IBSS))
+ geo_ch->flags |= IEEE80211_CHAN_NO_IBSS;
+
+ if (!(ch->flags & EEPROM_CHANNEL_ACTIVE))
+ geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+
+ if (ch->flags & EEPROM_CHANNEL_RADAR)
+ geo_ch->flags |= IEEE80211_CHAN_RADAR;
+
+ switch (ch->fat_extension_channel) {
+ case HT_IE_EXT_CHANNEL_ABOVE:
+ /* only above is allowed, disable below */
+ geo_ch->flags |= IEEE80211_CHAN_NO_FAT_BELOW;
+ break;
+ case HT_IE_EXT_CHANNEL_BELOW:
+ /* only below is allowed, disable above */
+ geo_ch->flags |= IEEE80211_CHAN_NO_FAT_ABOVE;
+ break;
+ case HT_IE_EXT_CHANNEL_NONE:
+ /* fat not allowed: disable both*/
+ geo_ch->flags |= (IEEE80211_CHAN_NO_FAT_ABOVE |
+ IEEE80211_CHAN_NO_FAT_BELOW);
+ break;
+ case HT_IE_EXT_CHANNEL_MAX:
+ /* both above and below are permitted */
+ break;
+ }
+
+ if (ch->max_power_avg > priv->max_channel_txpower_limit)
+ priv->max_channel_txpower_limit =
+ ch->max_power_avg;
+ } else {
+ geo_ch->flags |= IEEE80211_CHAN_DISABLED;
+ }
+
+ /* Save flags for reg domain usage */
+ geo_ch->orig_flags = geo_ch->flags;
+
+ IWL_DEBUG_INFO("Channel %d Freq=%d[%sGHz] %s flag=0%X\n",
+ ch->channel, geo_ch->center_freq,
+ is_channel_a_band(ch) ? "5.2" : "2.4",
+ geo_ch->flags & IEEE80211_CHAN_DISABLED ?
+ "restricted" : "valid",
+ geo_ch->flags);
+ }
+
+ if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) &&
+ priv->cfg->sku & IWL_SKU_A) {
+ printk(KERN_INFO DRV_NAME
+ ": Incorrectly detected BG card as ABG. Please send "
+ "your PCI ID 0x%04X:0x%04X to maintainer.\n",
+ priv->pci_dev->device, priv->pci_dev->subsystem_device);
+ priv->cfg->sku &= ~IWL_SKU_A;
+ }
+
+ printk(KERN_INFO DRV_NAME
+ ": Tunable channels: %d 802.11bg, %d 802.11a channels\n",
+ priv->bands[IEEE80211_BAND_2GHZ].n_channels,
+ priv->bands[IEEE80211_BAND_5GHZ].n_channels);
+
+
+ set_bit(STATUS_GEO_CONFIGURED, &priv->status);
+
+ return 0;
+}
+
+/*
+ * iwlcore_free_geos - undo allocations in iwlcore_init_geos
+ */
+static void iwlcore_free_geos(struct iwl_priv *priv)
+{
+ kfree(priv->ieee_channels);
+ kfree(priv->ieee_rates);
+ clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
+}
+
+#ifdef CONFIG_IWL4965_HT
+static u8 is_single_rx_stream(struct iwl_priv *priv)
+{
+ return !priv->current_ht_config.is_ht ||
+ ((priv->current_ht_config.supp_mcs_set[1] == 0) &&
+ (priv->current_ht_config.supp_mcs_set[2] == 0)) ||
+ priv->ps_mode == IWL_MIMO_PS_STATIC;
+}
+static u8 iwl_is_channel_extension(struct iwl_priv *priv,
+ enum ieee80211_band band,
+ u16 channel, u8 extension_chan_offset)
+{
+ const struct iwl_channel_info *ch_info;
+
+ ch_info = iwl_get_channel_info(priv, band, channel);
+ if (!is_channel_valid(ch_info))
+ return 0;
+
+ if (extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_NONE)
+ return 0;
+
+ if ((ch_info->fat_extension_channel == extension_chan_offset) ||
+ (ch_info->fat_extension_channel == HT_IE_EXT_CHANNEL_MAX))
+ return 1;
+
+ return 0;
+}
+
+u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
+ struct ieee80211_ht_info *sta_ht_inf)
+{
+ struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config;
+
+ if ((!iwl_ht_conf->is_ht) ||
+ (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) ||
+ (iwl_ht_conf->extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_NONE))
+ return 0;
+
+ if (sta_ht_inf) {
+ if ((!sta_ht_inf->ht_supported) ||
+ (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH)))
+ return 0;
+ }
+
+ return iwl_is_channel_extension(priv, priv->band,
+ iwl_ht_conf->control_channel,
+ iwl_ht_conf->extension_chan_offset);
+}
+EXPORT_SYMBOL(iwl_is_fat_tx_allowed);
+
+void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
+{
+ struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+ u32 val;
+
+ if (!ht_info->is_ht)
+ return;
+
+ /* Set up channel bandwidth: 20 MHz only, or 20/40 mixed if fat ok */
+ if (iwl_is_fat_tx_allowed(priv, NULL))
+ rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK;
+ else
+ rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
+ RXON_FLG_CHANNEL_MODE_PURE_40_MSK);
+
+ if (le16_to_cpu(rxon->channel) != ht_info->control_channel) {
+ IWL_DEBUG_ASSOC("control diff than current %d %d\n",
+ le16_to_cpu(rxon->channel),
+ ht_info->control_channel);
+ rxon->channel = cpu_to_le16(ht_info->control_channel);
+ return;
+ }
+
+ /* Note: control channel is opposite of extension channel */
+ switch (ht_info->extension_chan_offset) {
+ case IWL_EXT_CHANNEL_OFFSET_ABOVE:
+ rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
+ break;
+ case IWL_EXT_CHANNEL_OFFSET_BELOW:
+ rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
+ break;
+ case IWL_EXT_CHANNEL_OFFSET_NONE:
+ default:
+ rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK;
+ break;
+ }
+
+ val = ht_info->ht_protection;
+
+ rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS);
+
+ iwl_set_rxon_chain(priv);
+
+ IWL_DEBUG_ASSOC("supported HT rate 0x%X 0x%X 0x%X "
+ "rxon flags 0x%X operation mode :0x%X "
+ "extension channel offset 0x%x "
+ "control chan %d\n",
+ ht_info->supp_mcs_set[0],
+ ht_info->supp_mcs_set[1],
+ ht_info->supp_mcs_set[2],
+ le32_to_cpu(rxon->flags), ht_info->ht_protection,
+ ht_info->extension_chan_offset,
+ ht_info->control_channel);
+ return;
+}
+EXPORT_SYMBOL(iwl_set_rxon_ht);
+
+#else
+static inline u8 is_single_rx_stream(struct iwl_priv *priv)
+{
+ return 1;
+}
+#endif /*CONFIG_IWL4965_HT */
+
+/*
+ * Determine how many receiver/antenna chains to use.
+ * More provides better reception via diversity. Fewer saves power.
+ * MIMO (dual stream) requires at least 2, but works better with 3.
+ * This does not determine *which* chains to use, just how many.
+ */
+static int iwlcore_get_rx_chain_counter(struct iwl_priv *priv,
+ u8 *idle_state, u8 *rx_state)
+{
+ u8 is_single = is_single_rx_stream(priv);
+ u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1;
+
+ /* # of Rx chains to use when expecting MIMO. */
+ if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC)))
+ *rx_state = 2;
+ else
+ *rx_state = 3;
+
+ /* # Rx chains when idling and maybe trying to save power */
+ switch (priv->ps_mode) {
+ case IWL_MIMO_PS_STATIC:
+ case IWL_MIMO_PS_DYNAMIC:
+ *idle_state = (is_cam) ? 2 : 1;
+ break;
+ case IWL_MIMO_PS_NONE:
+ *idle_state = (is_cam) ? *rx_state : 1;
+ break;
+ default:
+ *idle_state = 1;
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * iwl_set_rxon_chain - Set up Rx chain usage in "staging" RXON image
+ *
+ * Selects how many and which Rx receivers/antennas/chains to use.
+ * This should not be used for scan command ... it puts data in wrong place.
+ */
+void iwl_set_rxon_chain(struct iwl_priv *priv)
+{
+ u8 is_single = is_single_rx_stream(priv);
+ u8 idle_state, rx_state;
+
+ priv->staging_rxon.rx_chain = 0;
+ rx_state = idle_state = 3;
+
+ /* Tell uCode which antennas are actually connected.
+ * Before first association, we assume all antennas are connected.
+ * Just after first association, iwl_chain_noise_calibration()
+ * checks which antennas actually *are* connected. */
+ priv->staging_rxon.rx_chain |=
+ cpu_to_le16(priv->hw_params.valid_rx_ant <<
+ RXON_RX_CHAIN_VALID_POS);
+
+ /* How many receivers should we use? */
+ iwlcore_get_rx_chain_counter(priv, &idle_state, &rx_state);
+ priv->staging_rxon.rx_chain |=
+ cpu_to_le16(rx_state << RXON_RX_CHAIN_MIMO_CNT_POS);
+ priv->staging_rxon.rx_chain |=
+ cpu_to_le16(idle_state << RXON_RX_CHAIN_CNT_POS);
+
+ if (!is_single && (rx_state >= 2) &&
+ !test_bit(STATUS_POWER_PMI, &priv->status))
+ priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
+ else
+ priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
+
+ IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain);
+}
+EXPORT_SYMBOL(iwl_set_rxon_chain);
/**
* iwlcore_set_rxon_channel - Set the phymode and channel values in staging RXON
@@ -188,7 +751,7 @@
* NOTE: Does not commit to the hardware; it sets appropriate bit fields
* in the staging RXON flag structure based on the phymode
*/
-int iwlcore_set_rxon_channel(struct iwl_priv *priv,
+int iwl_set_rxon_channel(struct iwl_priv *priv,
enum ieee80211_band band,
u16 channel)
{
@@ -214,41 +777,143 @@
return 0;
}
-EXPORT_SYMBOL(iwlcore_set_rxon_channel);
+EXPORT_SYMBOL(iwl_set_rxon_channel);
-static void iwlcore_init_hw(struct iwl_priv *priv)
+int iwl_setup_mac(struct iwl_priv *priv)
{
+ int ret;
struct ieee80211_hw *hw = priv->hw;
hw->rate_control_algorithm = "iwl-4965-rs";
- /* Tell mac80211 and its clients (e.g. Wireless Extensions)
- * the range of signal quality values that we'll provide.
- * Negative values for level/noise indicate that we'll provide dBm.
- * For WE, at least, non-0 values here *enable* display of values
- * in app (iwconfig). */
- hw->max_rssi = -20; /* signal level, negative indicates dBm */
- hw->max_noise = -20; /* noise level, negative indicates dBm */
- hw->max_signal = 100; /* link quality indication (%) */
-
- /* Tell mac80211 our Tx characteristics */
- hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
-
+ /* Tell mac80211 our characteristics */
+ hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_NOISE_DBM;
/* Default value; 4 EDCA QOS priorities */
hw->queues = 4;
#ifdef CONFIG_IWL4965_HT
/* Enhanced value; more queues, to support 11n aggregation */
- hw->queues = 16;
+ hw->ampdu_queues = 12;
#endif /* CONFIG_IWL4965_HT */
-}
-int iwl_setup(struct iwl_priv *priv)
+ hw->conf.beacon_int = 100;
+
+ if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
+ priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
+ &priv->bands[IEEE80211_BAND_2GHZ];
+ if (priv->bands[IEEE80211_BAND_5GHZ].n_channels)
+ priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+ &priv->bands[IEEE80211_BAND_5GHZ];
+
+ ret = ieee80211_register_hw(priv->hw);
+ if (ret) {
+ IWL_ERROR("Failed to register hw (error %d)\n", ret);
+ return ret;
+ }
+ priv->mac80211_registered = 1;
+
+ return 0;
+}
+EXPORT_SYMBOL(iwl_setup_mac);
+
+
+int iwl_init_drv(struct iwl_priv *priv)
{
- int ret = 0;
- iwlcore_init_hw(priv);
- ret = priv->cfg->ops->lib->init_drv(priv);
+ int ret;
+ int i;
+
+ priv->retry_rate = 1;
+ priv->ibss_beacon = NULL;
+
+ spin_lock_init(&priv->lock);
+ spin_lock_init(&priv->power_data.lock);
+ spin_lock_init(&priv->sta_lock);
+ spin_lock_init(&priv->hcmd_lock);
+ spin_lock_init(&priv->lq_mngr.lock);
+
+ for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++)
+ INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
+
+ INIT_LIST_HEAD(&priv->free_frames);
+
+ mutex_init(&priv->mutex);
+
+ /* Clear the driver's (not device's) station table */
+ iwlcore_clear_stations_table(priv);
+
+ priv->data_retry_limit = -1;
+ priv->ieee_channels = NULL;
+ priv->ieee_rates = NULL;
+ priv->band = IEEE80211_BAND_2GHZ;
+
+ priv->iw_mode = IEEE80211_IF_TYPE_STA;
+
+ priv->use_ant_b_for_management_frame = 1; /* start with ant B */
+ priv->ps_mode = IWL_MIMO_PS_NONE;
+
+ /* Choose which receivers/antennas to use */
+ iwl_set_rxon_chain(priv);
+
+ if (priv->cfg->mod_params->enable_qos)
+ priv->qos_data.qos_enable = 1;
+
+ iwl_reset_qos(priv);
+
+ priv->qos_data.qos_active = 0;
+ priv->qos_data.qos_cap.val = 0;
+
+ iwl_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6);
+
+ priv->rates_mask = IWL_RATES_MASK;
+ /* If power management is turned on, default to AC mode */
+ priv->power_mode = IWL_POWER_AC;
+ priv->user_txpower_limit = IWL_DEFAULT_TX_POWER;
+
+ ret = iwl_init_channel_map(priv);
+ if (ret) {
+ IWL_ERROR("initializing regulatory failed: %d\n", ret);
+ goto err;
+ }
+
+ ret = iwlcore_init_geos(priv);
+ if (ret) {
+ IWL_ERROR("initializing geos failed: %d\n", ret);
+ goto err_free_channel_map;
+ }
+
+ return 0;
+
+err_free_channel_map:
+ iwl_free_channel_map(priv);
+err:
return ret;
}
-EXPORT_SYMBOL(iwl_setup);
+EXPORT_SYMBOL(iwl_init_drv);
+
+void iwl_free_calib_results(struct iwl_priv *priv)
+{
+ kfree(priv->calib_results.lo_res);
+ priv->calib_results.lo_res = NULL;
+ priv->calib_results.lo_res_len = 0;
+
+ kfree(priv->calib_results.tx_iq_res);
+ priv->calib_results.tx_iq_res = NULL;
+ priv->calib_results.tx_iq_res_len = 0;
+
+ kfree(priv->calib_results.tx_iq_perd_res);
+ priv->calib_results.tx_iq_perd_res = NULL;
+ priv->calib_results.tx_iq_perd_res_len = 0;
+}
+EXPORT_SYMBOL(iwl_free_calib_results);
+
+void iwl_uninit_drv(struct iwl_priv *priv)
+{
+ iwl_free_calib_results(priv);
+ iwlcore_free_geos(priv);
+ iwl_free_channel_map(priv);
+ kfree(priv->scan);
+}
+EXPORT_SYMBOL(iwl_uninit_drv);
/* Low level driver call this function to update iwlcore with
* driver status.
@@ -263,8 +928,10 @@
if (ret)
IWL_ERROR("Unable to initialize RFKILL system. "
"Ignoring error: %d\n", ret);
+ iwl_power_initialize(priv);
break;
case IWLCORE_START_EVT:
+ iwl_power_update_mode(priv, 1);
break;
case IWLCORE_STOP_EVT:
break;
@@ -290,3 +957,319 @@
}
EXPORT_SYMBOL(iwl_send_statistics_request);
+/**
+ * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
+ * using sample data 100 bytes apart. If these sample points are good,
+ * it's a pretty good bet that everything between them is good, too.
+ */
+static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
+{
+ u32 val;
+ int ret = 0;
+ u32 errcnt = 0;
+ u32 i;
+
+ IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
+
+ ret = iwl_grab_nic_access(priv);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
+ /* read data comes through single port, auto-incr addr */
+ /* NOTE: Use the debugless read so we don't flood kernel log
+ * if IWL_DL_IO is set */
+ iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
+ i + RTC_INST_LOWER_BOUND);
+ val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+ if (val != le32_to_cpu(*image)) {
+ ret = -EIO;
+ errcnt++;
+ if (errcnt >= 3)
+ break;
+ }
+ }
+
+ iwl_release_nic_access(priv);
+
+ return ret;
+}
+
+/**
+ * iwlcore_verify_inst_full - verify runtime uCode image in card vs. host,
+ * looking at all data.
+ */
+static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image,
+ u32 len)
+{
+ u32 val;
+ u32 save_len = len;
+ int ret = 0;
+ u32 errcnt;
+
+ IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
+
+ ret = iwl_grab_nic_access(priv);
+ if (ret)
+ return ret;
+
+ iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND);
+
+ errcnt = 0;
+ for (; len > 0; len -= sizeof(u32), image++) {
+ /* read data comes through single port, auto-incr addr */
+ /* NOTE: Use the debugless read so we don't flood kernel log
+ * if IWL_DL_IO is set */
+ val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+ if (val != le32_to_cpu(*image)) {
+ IWL_ERROR("uCode INST section is invalid at "
+ "offset 0x%x, is 0x%x, s/b 0x%x\n",
+ save_len - len, val, le32_to_cpu(*image));
+ ret = -EIO;
+ errcnt++;
+ if (errcnt >= 20)
+ break;
+ }
+ }
+
+ iwl_release_nic_access(priv);
+
+ if (!errcnt)
+ IWL_DEBUG_INFO
+ ("ucode image in INSTRUCTION memory is good\n");
+
+ return ret;
+}
+
+/**
+ * iwl_verify_ucode - determine which instruction image is in SRAM,
+ * and verify its contents
+ */
+int iwl_verify_ucode(struct iwl_priv *priv)
+{
+ __le32 *image;
+ u32 len;
+ int ret;
+
+ /* Try bootstrap */
+ image = (__le32 *)priv->ucode_boot.v_addr;
+ len = priv->ucode_boot.len;
+ ret = iwlcore_verify_inst_sparse(priv, image, len);
+ if (!ret) {
+ IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n");
+ return 0;
+ }
+
+ /* Try initialize */
+ image = (__le32 *)priv->ucode_init.v_addr;
+ len = priv->ucode_init.len;
+ ret = iwlcore_verify_inst_sparse(priv, image, len);
+ if (!ret) {
+ IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n");
+ return 0;
+ }
+
+ /* Try runtime/protocol */
+ image = (__le32 *)priv->ucode_code.v_addr;
+ len = priv->ucode_code.len;
+ ret = iwlcore_verify_inst_sparse(priv, image, len);
+ if (!ret) {
+ IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n");
+ return 0;
+ }
+
+ IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
+
+ /* Since nothing seems to match, show first several data entries in
+ * instruction SRAM, so maybe visual inspection will give a clue.
+ * Selection of bootstrap image (vs. other images) is arbitrary. */
+ image = (__le32 *)priv->ucode_boot.v_addr;
+ len = priv->ucode_boot.len;
+ ret = iwl_verify_inst_full(priv, image, len);
+
+ return ret;
+}
+EXPORT_SYMBOL(iwl_verify_ucode);
+
+
+static const char *desc_lookup(int i)
+{
+ switch (i) {
+ case 1:
+ return "FAIL";
+ case 2:
+ return "BAD_PARAM";
+ case 3:
+ return "BAD_CHECKSUM";
+ case 4:
+ return "NMI_INTERRUPT";
+ case 5:
+ return "SYSASSERT";
+ case 6:
+ return "FATAL_ERROR";
+ }
+
+ return "UNKNOWN";
+}
+
+#define ERROR_START_OFFSET (1 * sizeof(u32))
+#define ERROR_ELEM_SIZE (7 * sizeof(u32))
+
+void iwl_dump_nic_error_log(struct iwl_priv *priv)
+{
+ u32 data2, line;
+ u32 desc, time, count, base, data1;
+ u32 blink1, blink2, ilink1, ilink2;
+ int ret;
+
+ if (priv->ucode_type == UCODE_INIT)
+ base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
+ else
+ base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
+
+ if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
+ IWL_ERROR("Not valid error log pointer 0x%08X\n", base);
+ return;
+ }
+
+ ret = iwl_grab_nic_access(priv);
+ if (ret) {
+ IWL_WARNING("Can not read from adapter at this time.\n");
+ return;
+ }
+
+ count = iwl_read_targ_mem(priv, base);
+
+ if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
+ IWL_ERROR("Start IWL Error Log Dump:\n");
+ IWL_ERROR("Status: 0x%08lX, count: %d\n", priv->status, count);
+ }
+
+ desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
+ blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
+ blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
+ ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32));
+ ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32));
+ data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32));
+ data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32));
+ line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
+ time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
+
+ IWL_ERROR("Desc Time "
+ "data1 data2 line\n");
+ IWL_ERROR("%-13s (#%d) %010u 0x%08X 0x%08X %u\n",
+ desc_lookup(desc), desc, time, data1, data2, line);
+ IWL_ERROR("blink1 blink2 ilink1 ilink2\n");
+ IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
+ ilink1, ilink2);
+
+ iwl_release_nic_access(priv);
+}
+EXPORT_SYMBOL(iwl_dump_nic_error_log);
+
+#define EVENT_START_OFFSET (4 * sizeof(u32))
+
+/**
+ * iwl_print_event_log - Dump error event log to syslog
+ *
+ * NOTE: Must be called with iwl4965_grab_nic_access() already obtained!
+ */
+void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+ u32 num_events, u32 mode)
+{
+ u32 i;
+ u32 base; /* SRAM byte address of event log header */
+ u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
+ u32 ptr; /* SRAM byte address of log data */
+ u32 ev, time, data; /* event log data */
+
+ if (num_events == 0)
+ return;
+ if (priv->ucode_type == UCODE_INIT)
+ base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
+ else
+ base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+
+ if (mode == 0)
+ event_size = 2 * sizeof(u32);
+ else
+ event_size = 3 * sizeof(u32);
+
+ ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
+
+ /* "time" is actually "data" for mode 0 (no timestamp).
+ * place event id # at far right for easier visual parsing. */
+ for (i = 0; i < num_events; i++) {
+ ev = iwl_read_targ_mem(priv, ptr);
+ ptr += sizeof(u32);
+ time = iwl_read_targ_mem(priv, ptr);
+ ptr += sizeof(u32);
+ if (mode == 0)
+ IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */
+ else {
+ data = iwl_read_targ_mem(priv, ptr);
+ ptr += sizeof(u32);
+ IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev);
+ }
+ }
+}
+EXPORT_SYMBOL(iwl_print_event_log);
+
+
+void iwl_dump_nic_event_log(struct iwl_priv *priv)
+{
+ int ret;
+ u32 base; /* SRAM byte address of event log header */
+ u32 capacity; /* event log capacity in # entries */
+ u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
+ u32 num_wraps; /* # times uCode wrapped to top of log */
+ u32 next_entry; /* index of next entry to be written by uCode */
+ u32 size; /* # entries that we'll print */
+
+ if (priv->ucode_type == UCODE_INIT)
+ base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
+ else
+ base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+
+ if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
+ IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
+ return;
+ }
+
+ ret = iwl_grab_nic_access(priv);
+ if (ret) {
+ IWL_WARNING("Can not read from adapter at this time.\n");
+ return;
+ }
+
+ /* event log header */
+ capacity = iwl_read_targ_mem(priv, base);
+ mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
+ num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
+ next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
+
+ size = num_wraps ? capacity : next_entry;
+
+ /* bail out if nothing in log */
+ if (size == 0) {
+ IWL_ERROR("Start IWL Event Log Dump: nothing in log\n");
+ iwl_release_nic_access(priv);
+ return;
+ }
+
+ IWL_ERROR("Start IWL Event Log Dump: display count %d, wraps %d\n",
+ size, num_wraps);
+
+ /* if uCode has wrapped back to top of log, start at the oldest entry,
+ * i.e the next one that uCode would fill. */
+ if (num_wraps)
+ iwl_print_event_log(priv, next_entry,
+ capacity - next_entry, mode);
+ /* (then/else) start at top of log */
+ iwl_print_event_log(priv, 0, next_entry, mode);
+
+ iwl_release_nic_access(priv);
+}
+EXPORT_SYMBOL(iwl_dump_nic_event_log);
+
+
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 7193d97..6b5af7a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -86,20 +86,42 @@
int (*rxon_assoc)(struct iwl_priv *priv);
};
struct iwl_hcmd_utils_ops {
- int (*enqueue_hcmd)(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
+ u16 (*get_hcmd_size)(u8 cmd_id, u16 len);
+ u16 (*build_addsta_hcmd)(const struct iwl_addsta_cmd *cmd, u8 *data);
+#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
+ void (*gain_computation)(struct iwl_priv *priv,
+ u32 *average_noise,
+ u16 min_average_noise_antennat_i,
+ u32 min_average_noise);
+ void (*chain_noise_reset)(struct iwl_priv *priv);
+#endif
};
struct iwl_lib_ops {
- /* iwlwifi driver (priv) init */
- int (*init_drv)(struct iwl_priv *priv);
/* set hw dependant perameters */
int (*set_hw_params)(struct iwl_priv *priv);
-
+ /* ucode shared memory */
+ int (*alloc_shared_mem)(struct iwl_priv *priv);
+ void (*free_shared_mem)(struct iwl_priv *priv);
+ int (*shared_mem_rx_idx)(struct iwl_priv *priv);
+ /* Handling TX */
void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv,
- struct iwl4965_tx_queue *txq,
+ struct iwl_tx_queue *txq,
u16 byte_cnt);
- /* nic init */
- int (*hw_nic_init)(struct iwl_priv *priv);
+ void (*txq_inval_byte_cnt_tbl)(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq);
+ void (*txq_set_sched)(struct iwl_priv *priv, u32 mask);
+#ifdef CONFIG_IWL4965_HT
+ /* aggregations */
+ int (*txq_agg_enable)(struct iwl_priv *priv, int txq_id, int tx_fifo,
+ int sta_id, int tid, u16 ssn_idx);
+ int (*txq_agg_disable)(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx,
+ u8 tx_fifo);
+#endif /* CONFIG_IWL4965_HT */
+ /* setup Rx handler */
+ void (*rx_handler_setup)(struct iwl_priv *priv);
+ /* alive notification after init uCode load */
+ void (*init_alive_start)(struct iwl_priv *priv);
/* alive notification */
int (*alive_notify)(struct iwl_priv *priv);
/* check validity of rtc data address */
@@ -108,6 +130,17 @@
int (*load_ucode)(struct iwl_priv *priv);
/* rfkill */
void (*radio_kill_sw)(struct iwl_priv *priv, int disable_radio);
+ /* power management */
+ struct {
+ int (*init)(struct iwl_priv *priv);
+ int (*reset)(struct iwl_priv *priv);
+ void (*stop)(struct iwl_priv *priv);
+ void (*config)(struct iwl_priv *priv);
+ int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src);
+ } apm_ops;
+ /* power */
+ int (*set_power)(struct iwl_priv *priv, void *cmd);
+ void (*update_chain_flags)(struct iwl_priv *priv);
/* eeprom operations (as defined in iwl-eeprom.h) */
struct iwl_eeprom_ops eeprom_ops;
};
@@ -127,12 +160,14 @@
int enable_qos; /* def: 1 = use quality of service */
int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */
int antenna; /* def: 0 = both antennas (use diversity) */
+ int restart_fw; /* def: 1 = restart firmware */
};
struct iwl_cfg {
const char *name;
const char *fw_name;
unsigned int sku;
+ int eeprom_size;
const struct iwl_ops *ops;
const struct iwl_mod_params *mod_params;
};
@@ -143,14 +178,66 @@
struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
struct ieee80211_ops *hw_ops);
+void iwl_hw_detect(struct iwl_priv *priv);
void iwlcore_clear_stations_table(struct iwl_priv *priv);
-void iwlcore_reset_qos(struct iwl_priv *priv);
-int iwlcore_set_rxon_channel(struct iwl_priv *priv,
+void iwl_free_calib_results(struct iwl_priv *priv);
+void iwl_reset_qos(struct iwl_priv *priv);
+void iwl_set_rxon_chain(struct iwl_priv *priv);
+int iwl_set_rxon_channel(struct iwl_priv *priv,
enum ieee80211_band band,
u16 channel);
+void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info);
+u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
+ struct ieee80211_ht_info *sta_ht_inf);
+int iwl_hw_nic_init(struct iwl_priv *priv);
+int iwl_setup_mac(struct iwl_priv *priv);
+int iwl_init_drv(struct iwl_priv *priv);
+void iwl_uninit_drv(struct iwl_priv *priv);
+/* "keep warm" functions */
+int iwl_kw_init(struct iwl_priv *priv);
+int iwl_kw_alloc(struct iwl_priv *priv);
+void iwl_kw_free(struct iwl_priv *priv);
-int iwl_setup(struct iwl_priv *priv);
+/*****************************************************
+* RX
+******************************************************/
+void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
+int iwl_rx_queue_alloc(struct iwl_priv *priv);
+void iwl_rx_handle(struct iwl_priv *priv);
+int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
+ struct iwl_rx_queue *q);
+void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
+void iwl_rx_replenish(struct iwl_priv *priv);
+int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
+/* FIXME: remove when TX is moved to iwl core */
+int iwl_rx_queue_restock(struct iwl_priv *priv);
+int iwl_rx_queue_space(const struct iwl_rx_queue *q);
+void iwl_rx_allocate(struct iwl_priv *priv);
+void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
+int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
+/* Handlers */
+void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb);
+
+/* TX helpers */
+
+/*****************************************************
+* TX
+******************************************************/
+int iwl_txq_ctx_reset(struct iwl_priv *priv);
+int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb);
+/* FIXME: remove when free Tx is fully merged into iwlcore */
+int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
+void iwl_hw_txq_ctx_free(struct iwl_priv *priv);
+int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd,
+ dma_addr_t addr, u16 len);
+int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
+#ifdef CONFIG_IWL4965_HT
+int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn);
+int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid);
+int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id);
+#endif
/*****************************************************
* S e n d i n g H o s t C o m m a n d s *
@@ -167,6 +254,17 @@
int (*callback)(struct iwl_priv *priv,
struct iwl_cmd *cmd,
struct sk_buff *skb));
+
+int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
+
+/*****************************************************
+* Error Handling Debugging
+******************************************************/
+void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+ u32 num_events, u32 mode);
+void iwl_dump_nic_error_log(struct iwl_priv *priv);
+void iwl_dump_nic_event_log(struct iwl_priv *priv);
+
/*************** DRIVER STATUS FUNCTIONS *****/
#define STATUS_HCMD_ACTIVE 0 /* host command in progress */
@@ -235,6 +333,7 @@
int iwlcore_low_level_notify(struct iwl_priv *priv,
enum iwlcore_card_notify notify);
extern int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags);
+extern int iwl_verify_ucode(struct iwl_priv *priv);
int iwl_send_lq_cmd(struct iwl_priv *priv,
struct iwl_link_quality_cmd *lq, u8 flags);
@@ -243,4 +342,10 @@
return priv->cfg->ops->hcmd->rxon_assoc(priv);
}
+static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
+ struct iwl_priv *priv, enum ieee80211_band band)
+{
+ return priv->hw->wiphy->bands[band];
+}
+
#endif /* __iwl_core_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index 1272579..545ed69 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -87,16 +87,16 @@
/* EEPROM reads */
#define CSR_EEPROM_REG (CSR_BASE+0x02c)
#define CSR_EEPROM_GP (CSR_BASE+0x030)
+#define CSR_GIO_REG (CSR_BASE+0x03C)
#define CSR_GP_UCODE (CSR_BASE+0x044)
#define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054)
#define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058)
#define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c)
#define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060)
-#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100)
#define CSR_LED_REG (CSR_BASE+0x094)
+#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100)
-/* Analog phase-lock-loop configuration (3945 only)
- * Set bit 24. */
+/* Analog phase-lock-loop configuration */
#define CSR_ANA_PLL_CFG (CSR_BASE+0x20c)
/*
* Indicates hardware rev, to determine CCK backoff for txpower calculation.
@@ -107,9 +107,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 +170,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 +195,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)
@@ -200,17 +214,15 @@
#define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000)
#define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180)
+/* CSR GIO */
+#define CSR_GIO_REG_VAL_L0S_ENABLED (0x00000002)
+
/* UCODE DRV GP */
#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001)
#define CSR_UCODE_SW_BIT_RFKILL (0x00000002)
#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004)
#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008)
-/* GPIO */
-#define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200)
-#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC (0x00000000)
-#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC CSR_GPIO_IN_BIT_AUX_POWER
-
/* GI Chicken Bits */
#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000)
#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000)
@@ -220,6 +232,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-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index c60724c..11de561 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -30,37 +30,36 @@
#define __iwl_debug_h__
#ifdef CONFIG_IWLWIFI_DEBUG
-extern u32 iwl_debug_level;
#define IWL_DEBUG(level, fmt, args...) \
-do { if (iwl_debug_level & (level)) \
- printk(KERN_ERR DRV_NAME": %c %s " fmt, \
+do { if (priv->debug_level & (level)) \
+ dev_printk(KERN_ERR, &(priv->hw->wiphy->dev), "%c %s " fmt, \
in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
#define IWL_DEBUG_LIMIT(level, fmt, args...) \
-do { if ((iwl_debug_level & (level)) && net_ratelimit()) \
- printk(KERN_ERR DRV_NAME": %c %s " fmt, \
+do { if ((priv->debug_level & (level)) && net_ratelimit()) \
+ dev_printk(KERN_ERR, &(priv->hw->wiphy->dev), "%c %s " fmt, \
in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
-static inline void iwl_print_hex_dump(int level, void *p, u32 len)
-{
- if (!(iwl_debug_level & level))
- return;
-
- print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1,
- p, len, 1);
-}
-
#ifdef CONFIG_IWLWIFI_DEBUGFS
struct iwl_debugfs {
const char *name;
struct dentry *dir_drv;
struct dentry *dir_data;
- struct dir_data_files{
+ struct dentry *dir_rf;
+ struct dir_data_files {
struct dentry *file_sram;
+ struct dentry *file_eeprom;
struct dentry *file_stations;
struct dentry *file_rx_statistics;
struct dentry *file_tx_statistics;
+ struct dentry *file_log_event;
} dbgfs_data_files;
+ struct dir_rf_files {
+#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
+ struct dentry *file_disable_sensitivity;
+ struct dentry *file_disable_chain_noise;
+#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */
+ } dbgfs_rf_files;
u32 sram_offset;
u32 sram_len;
};
@@ -76,9 +75,6 @@
static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...)
{
}
-static inline void iwl_print_hex_dump(int level, void *p, u32 len)
-{
-}
#endif /* CONFIG_IWLWIFI_DEBUG */
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 9a30e1d..29e16ba 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"
@@ -55,6 +55,13 @@
goto err; \
} while (0)
+#define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \
+ dbgfs->dbgfs_##parent##_files.file_##name = \
+ debugfs_create_bool(#name, 0644, dbgfs->dir_##parent, ptr); \
+ if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name)) \
+ goto err; \
+} while (0)
+
#define DEBUGFS_REMOVE(name) do { \
debugfs_remove(name); \
name = NULL; \
@@ -85,6 +92,14 @@
.open = iwl_dbgfs_open_file_generic, \
};
+#define DEBUGFS_WRITE_FILE_OPS(name) \
+ DEBUGFS_WRITE_FUNC(name); \
+static const struct file_operations iwl_dbgfs_##name##_ops = { \
+ .write = iwl_dbgfs_##name##_write, \
+ .open = iwl_dbgfs_open_file_generic, \
+};
+
+
#define DEBUGFS_READ_WRITE_FILE_OPS(name) \
DEBUGFS_READ_FUNC(name); \
DEBUGFS_WRITE_FUNC(name); \
@@ -206,7 +221,7 @@
size_t count, loff_t *ppos)
{
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
- struct iwl4965_station_entry *station;
+ struct iwl_station_entry *station;
int max_sta = priv->hw_params.max_stations;
char *buf;
int i, j, pos = 0;
@@ -277,8 +292,70 @@
return ret;
}
+static ssize_t iwl_dbgfs_eeprom_read(struct file *file,
+ char __user *user_buf,
+ size_t count,
+ loff_t *ppos)
+{
+ ssize_t ret;
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ int pos = 0, ofs = 0, buf_size = 0;
+ const u8 *ptr;
+ char *buf;
+ size_t eeprom_len = priv->cfg->eeprom_size;
+ buf_size = 4 * eeprom_len + 256;
+
+ if (eeprom_len % 16) {
+ IWL_ERROR("EEPROM size is not multiple of 16.\n");
+ return -ENODATA;
+ }
+
+ /* 4 characters for byte 0xYY */
+ buf = kzalloc(buf_size, GFP_KERNEL);
+ if (!buf) {
+ IWL_ERROR("Can not allocate Buffer\n");
+ return -ENOMEM;
+ }
+
+ ptr = priv->eeprom;
+ for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) {
+ pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs);
+ hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos,
+ buf_size - pos, 0);
+ pos += strlen(buf);
+ if (buf_size - pos > 0)
+ buf[pos++] = '\n';
+ }
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_log_event_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = file->private_data;
+ u32 event_log_flag;
+ char buf[8];
+ int buf_size;
+
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ if (sscanf(buf, "%d", &event_log_flag) != 1)
+ return -EFAULT;
+ if (event_log_flag == 1)
+ iwl_dump_nic_event_log(priv);
+
+ return count;
+}
DEBUGFS_READ_WRITE_FILE_OPS(sram);
+DEBUGFS_WRITE_FILE_OPS(log_event);
+DEBUGFS_READ_FILE_OPS(eeprom);
DEBUGFS_READ_FILE_OPS(stations);
DEBUGFS_READ_FILE_OPS(rx_statistics);
DEBUGFS_READ_FILE_OPS(tx_statistics);
@@ -290,6 +367,7 @@
int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
{
struct iwl_debugfs *dbgfs;
+ struct dentry *phyd = priv->hw->wiphy->debugfsdir;
dbgfs = kzalloc(sizeof(struct iwl_debugfs), GFP_KERNEL);
if (!dbgfs) {
@@ -298,17 +376,24 @@
priv->dbgfs = dbgfs;
dbgfs->name = name;
- dbgfs->dir_drv = debugfs_create_dir(name, NULL);
+ dbgfs->dir_drv = debugfs_create_dir(name, phyd);
if (!dbgfs->dir_drv || IS_ERR(dbgfs->dir_drv)){
goto err;
}
DEBUGFS_ADD_DIR(data, dbgfs->dir_drv);
+ DEBUGFS_ADD_DIR(rf, dbgfs->dir_drv);
+ DEBUGFS_ADD_FILE(eeprom, data);
DEBUGFS_ADD_FILE(sram, data);
+ DEBUGFS_ADD_FILE(log_event, data);
DEBUGFS_ADD_FILE(stations, data);
DEBUGFS_ADD_FILE(rx_statistics, data);
DEBUGFS_ADD_FILE(tx_statistics, data);
-
+#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
+ DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
+ DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
+ &priv->disable_chain_noise_cal);
+#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */
return 0;
err:
@@ -327,11 +412,18 @@
if (!(priv->dbgfs))
return;
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_eeprom);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_rx_statistics);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_tx_statistics);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram);
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations);
DEBUGFS_REMOVE(priv->dbgfs->dir_data);
+#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise);
+#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */
+ DEBUGFS_REMOVE(priv->dbgfs->dir_rf);
DEBUGFS_REMOVE(priv->dbgfs->dir_drv);
kfree(priv->dbgfs);
priv->dbgfs = NULL;
@@ -339,3 +431,4 @@
EXPORT_SYMBOL(iwl_dbgfs_unregister);
+
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
similarity index 80%
rename from drivers/net/wireless/iwlwifi/iwl-4965.h
rename to drivers/net/wireless/iwlwifi/iwl-dev.h
index 581b985..802f1a1 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:
@@ -91,7 +91,7 @@
#define DEFAULT_SHORT_RETRY_LIMIT 7U
#define DEFAULT_LONG_RETRY_LIMIT 4U
-struct iwl4965_rx_mem_buffer {
+struct iwl_rx_mem_buffer {
dma_addr_t dma_addr;
struct sk_buff *skb;
struct list_head list;
@@ -102,7 +102,7 @@
*
* Contains common data for Rx and Tx queues
*/
-struct iwl4965_queue {
+struct iwl_queue {
int n_bd; /* number of BDs in this queue */
int write_ptr; /* 1-st empty entry (index) host_w*/
int read_ptr; /* last used entry (index) host_r*/
@@ -118,13 +118,12 @@
#define MAX_NUM_OF_TBS (20)
/* One for each TFD */
-struct iwl4965_tx_info {
- struct ieee80211_tx_status status;
+struct iwl_tx_info {
struct sk_buff *skb[MAX_NUM_OF_TBS];
};
/**
- * struct iwl4965_tx_queue - Tx Queue for DMA
+ * struct iwl_tx_queue - Tx Queue for DMA
* @q: generic Rx/Tx queue descriptor
* @bd: base of circular buffer of TFDs
* @cmd: array of command/Tx buffers
@@ -136,12 +135,12 @@
* A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame
* descriptors) and required locking structures.
*/
-struct iwl4965_tx_queue {
- struct iwl4965_queue q;
- struct iwl4965_tfd_frame *bd;
+struct iwl_tx_queue {
+ struct iwl_queue q;
+ struct iwl_tfd_frame *bd;
struct iwl_cmd *cmd;
dma_addr_t dma_addr_cmd;
- struct iwl4965_tx_info *txb;
+ struct iwl_tx_info *txb;
int need_update;
int sched_retry;
int active;
@@ -199,9 +198,9 @@
struct iwl_channel_info {
struct iwl4965_channel_tgd_info tgd;
struct iwl4965_channel_tgh_info tgh;
- struct iwl4965_eeprom_channel eeprom; /* EEPROM regulatory limit */
- struct iwl4965_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for
- * FAT channel */
+ struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */
+ struct iwl_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for
+ * FAT channel */
u8 channel; /* channel number */
u8 flags; /* flags copied from EEPROM */
@@ -252,29 +251,9 @@
/* Power management (not Tx power) structures */
-struct iwl4965_power_vec_entry {
- struct iwl4965_powertable_cmd cmd;
- u8 no_dtim;
-};
-#define IWL_POWER_RANGE_0 (0)
-#define IWL_POWER_RANGE_1 (1)
-
-#define IWL_POWER_MODE_CAM 0x00 /* Continuously Aware Mode, always on */
-#define IWL_POWER_INDEX_3 0x03
-#define IWL_POWER_INDEX_5 0x05
-#define IWL_POWER_AC 0x06
-#define IWL_POWER_BATTERY 0x07
-#define IWL_POWER_LIMIT 0x07
-#define IWL_POWER_MASK 0x0F
-#define IWL_POWER_ENABLED 0x10
-#define IWL_POWER_LEVEL(x) ((x) & IWL_POWER_MASK)
-
-struct iwl4965_power_mgr {
- spinlock_t lock;
- struct iwl4965_power_vec_entry pwr_range_0[IWL_POWER_AC];
- struct iwl4965_power_vec_entry pwr_range_1[IWL_POWER_AC];
- u8 active_index;
- u32 dtim_val;
+enum iwl_pwr_src {
+ IWL_PWR_SRC_VMAIN,
+ IWL_PWR_SRC_VAUX,
};
#define IEEE80211_DATA_LEN 2304
@@ -282,7 +261,7 @@
#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN)
#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN)
-struct iwl4965_frame {
+struct iwl_frame {
union {
struct ieee80211_hdr frame;
struct iwl4965_tx_beacon_cmd beacon;
@@ -328,6 +307,8 @@
} __attribute__ ((packed));
+#define IWL_CMD_MAX_PAYLOAD 320
+
/**
* struct iwl_cmd
*
@@ -339,7 +320,7 @@
struct iwl_cmd_meta meta; /* driver data */
struct iwl_cmd_header hdr; /* uCode API */
union {
- struct iwl4965_addsta_cmd addsta;
+ struct iwl_addsta_cmd addsta;
struct iwl4965_led_cmd led;
u32 flags;
u8 val8;
@@ -349,11 +330,12 @@
struct iwl4965_rxon_time_cmd rxon_time;
struct iwl4965_powertable_cmd powertable;
struct iwl4965_qosparam_cmd qosparam;
- struct iwl4965_tx_cmd tx;
+ struct iwl_tx_cmd tx;
struct iwl4965_tx_beacon_cmd tx_beacon;
struct iwl4965_rxon_assoc_cmd rxon_assoc;
+ struct iwl_rem_sta_cmd rm_sta;
u8 *indirect;
- u8 payload[360];
+ u8 payload[IWL_CMD_MAX_PAYLOAD];
} __attribute__ ((packed)) cmd;
} __attribute__ ((packed));
@@ -378,7 +360,7 @@
#define SUP_RATE_11G_MAX_NUM_CHANNELS 12
/**
- * struct iwl4965_rx_queue - Rx queue
+ * struct iwl_rx_queue - Rx queue
* @processed: Internal index to last handled Rx packet
* @read: Shared index to newest available Rx buffer
* @write: Shared index to oldest written Rx packet
@@ -387,13 +369,13 @@
* @rx_used: List of Rx buffers with no SKB
* @need_update: flag to indicate we need to update read/write index
*
- * NOTE: rx_free and rx_used are used as a FIFO for iwl4965_rx_mem_buffers
+ * NOTE: rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers
*/
-struct iwl4965_rx_queue {
+struct iwl_rx_queue {
__le32 *bd;
dma_addr_t dma_addr;
- struct iwl4965_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
- struct iwl4965_rx_mem_buffer *queue[RX_QUEUE_SIZE];
+ struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
+ struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
u32 processed;
u32 read;
u32 write;
@@ -421,7 +403,7 @@
#ifdef CONFIG_IWL4965_HT
/**
- * struct iwl4965_ht_agg -- aggregation status while waiting for block-ack
+ * struct iwl_ht_agg -- aggregation status while waiting for block-ack
* @txq_id: Tx queue used for Tx attempt
* @frame_count: # frames attempted by Tx command
* @wait_for_ba: Expect block-ack before next Tx reply
@@ -434,7 +416,7 @@
* for block ack (REPLY_COMPRESSED_BA). This struct stores tx reply info
* until block ack arrives.
*/
-struct iwl4965_ht_agg {
+struct iwl_ht_agg {
u16 txq_id;
u16 frame_count;
u16 wait_for_ba;
@@ -450,19 +432,18 @@
#endif /* CONFIG_IWL4965_HT */
-struct iwl4965_tid_data {
+struct iwl_tid_data {
u16 seq_number;
u16 tfds_in_queue;
#ifdef CONFIG_IWL4965_HT
- struct iwl4965_ht_agg agg;
+ struct iwl_ht_agg agg;
#endif /* CONFIG_IWL4965_HT */
};
-struct iwl4965_hw_key {
+struct iwl_hw_key {
enum ieee80211_key_alg alg;
int keylen;
u8 keyidx;
- struct ieee80211_key_conf *conf;
u8 key[32];
};
@@ -474,7 +455,6 @@
};
};
-#ifdef CONFIG_IWL4965_HT
#define CFG_HT_RX_AMPDU_FACTOR_DEF (0x3)
#define CFG_HT_MPDU_DENSITY_2USEC (0x5)
#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC
@@ -497,7 +477,6 @@
u8 ht_protection;
u8 non_GF_STA_present;
};
-#endif /*CONFIG_IWL4965_HT */
union iwl4965_qos_capabity {
struct {
@@ -530,12 +509,12 @@
#define STA_PS_STATUS_WAKE 0
#define STA_PS_STATUS_SLEEP 1
-struct iwl4965_station_entry {
- struct iwl4965_addsta_cmd sta;
- struct iwl4965_tid_data tid[MAX_TID_COUNT];
+struct iwl_station_entry {
+ struct iwl_addsta_cmd sta;
+ struct iwl_tid_data tid[MAX_TID_COUNT];
u8 used;
u8 ps_status;
- struct iwl4965_hw_key keyinfo;
+ struct iwl_hw_key keyinfo;
};
/* one for each uCode image (inst/data, boot/init/runtime) */
@@ -566,20 +545,51 @@
struct list_head list;
};
+struct iwl_sensitivity_ranges {
+ u16 min_nrg_cck;
+ u16 max_nrg_cck;
+
+ u16 nrg_th_cck;
+ u16 nrg_th_ofdm;
+
+ u16 auto_corr_min_ofdm;
+ u16 auto_corr_min_ofdm_mrc;
+ u16 auto_corr_min_ofdm_x1;
+ u16 auto_corr_min_ofdm_mrc_x1;
+
+ u16 auto_corr_max_ofdm;
+ u16 auto_corr_max_ofdm_mrc;
+ u16 auto_corr_max_ofdm_x1;
+ u16 auto_corr_max_ofdm_mrc_x1;
+
+ u16 auto_corr_max_cck;
+ u16 auto_corr_max_cck_mrc;
+ u16 auto_corr_min_cck;
+ u16 auto_corr_min_cck_mrc;
+};
+
+
+#define IWL_FAT_CHANNEL_52 BIT(IEEE80211_BAND_5GHZ)
+
/**
* struct iwl_hw_params
* @max_txq_num: Max # Tx queues supported
- * @tx_cmd_len: Size of Tx command (but not including frame itself)
- * @tx_ant_num: Number of TX antennas
+ * @tx/rx_chains_num: Number of TX/RX chains
+ * @valid_tx/rx_ant: usable antennas
* @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2)
- * @rx_buffer_size:
* @max_rxq_log: Log-base-2 of max_rxq_size
+ * @rx_buf_size: Rx buffer size
* @max_stations:
* @bcast_sta_id:
+ * @fat_channel: is 40MHz width possible in band 2.4
+ * BIT(IEEE80211_BAND_5GHZ) BIT(IEEE80211_BAND_5GHZ)
+ * @sw_crypto: 0 for hw, 1 for sw
+ * @max_xxx_size: for ucode uses
+ * @ct_kill_threshold: temperature threshold
+ * @struct iwl_sensitivity_ranges: range of sensitivity values
*/
struct iwl_hw_params {
u16 max_txq_num;
- u16 tx_cmd_len;
u8 tx_chains_num;
u8 rx_chains_num;
u8 valid_tx_ant;
@@ -590,10 +600,19 @@
u32 max_pkt_size;
u8 max_stations;
u8 bcast_sta_id;
+ u8 fat_channel;
+ u8 sw_crypto;
+ u32 max_inst_size;
+ u32 max_data_size;
+ u32 max_bsm_size;
+ u32 ct_kill_threshold; /* value in hw-dependent units */
+#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
+ const struct iwl_sensitivity_ranges *sens;
+#endif
};
-#define HT_SHORT_GI_20MHZ_ONLY (1 << 0)
-#define HT_SHORT_GI_40MHZ_ONLY (1 << 1)
+#define HT_SHORT_GI_20MHZ (1 << 0)
+#define HT_SHORT_GI_40MHZ (1 << 1)
#define IWL_RX_HDR(x) ((struct iwl4965_rx_frame_hdr *)(\
@@ -612,43 +631,33 @@
* for use by iwl-*.c
*
*****************************************************************************/
-struct iwl4965_addsta_cmd;
-extern int iwl4965_send_add_station(struct iwl_priv *priv,
- struct iwl4965_addsta_cmd *sta, u8 flags);
-extern u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr,
- int is_ap, u8 flags, void *ht_data);
+struct iwl_addsta_cmd;
+extern int iwl_send_add_sta(struct iwl_priv *priv,
+ struct iwl_addsta_cmd *sta, u8 flags);
+u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap,
+ u8 flags, struct ieee80211_ht_info *ht_info);
extern int iwl4965_is_network_packet(struct iwl_priv *priv,
struct ieee80211_hdr *header);
extern int iwl4965_power_init_handle(struct iwl_priv *priv);
extern void iwl4965_handle_data_packet_monitor(struct iwl_priv *priv,
- struct iwl4965_rx_mem_buffer *rxb,
+ struct iwl_rx_mem_buffer *rxb,
void *data, short len,
struct ieee80211_rx_status *stats,
u16 phy_flags);
extern int iwl4965_is_duplicate_packet(struct iwl_priv *priv,
struct ieee80211_hdr *header);
-extern int iwl4965_rx_queue_alloc(struct iwl_priv *priv);
-extern void iwl4965_rx_queue_reset(struct iwl_priv *priv,
- struct iwl4965_rx_queue *rxq);
extern int iwl4965_calc_db_from_ratio(int sig_ratio);
extern int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm);
-extern int iwl4965_tx_queue_init(struct iwl_priv *priv,
- struct iwl4965_tx_queue *txq, int count, u32 id);
-extern void iwl4965_rx_replenish(void *data);
-extern void iwl4965_tx_queue_free(struct iwl_priv *priv, struct iwl4965_tx_queue *txq);
extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv,
struct ieee80211_hdr *hdr,
const u8 *dest, int left);
-extern int iwl4965_rx_queue_update_write_ptr(struct iwl_priv *priv,
- struct iwl4965_rx_queue *q);
-extern void iwl4965_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
- u32 decrypt_res,
- struct ieee80211_rx_status *stats);
-extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr);
+extern void iwl4965_update_chain_flags(struct iwl_priv *priv);
+int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src);
+
int iwl4965_init_geos(struct iwl_priv *priv);
void iwl4965_free_geos(struct iwl_priv *priv);
-extern const u8 iwl4965_broadcast_addr[ETH_ALEN];
+extern const u8 iwl_bcast_addr[ETH_ALEN];
int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
/*
@@ -674,50 +683,59 @@
* iwl4965_mac_ <-- mac80211 callback
*
****************************************************************************/
-extern void iwl4965_hw_rx_handler_setup(struct iwl_priv *priv);
extern void iwl4965_hw_setup_deferred_work(struct iwl_priv *priv);
extern void iwl4965_hw_cancel_deferred_work(struct iwl_priv *priv);
-extern int iwl4965_hw_rxq_stop(struct iwl_priv *priv);
extern int iwl4965_hw_set_hw_params(struct iwl_priv *priv);
-extern int iwl4965_hw_nic_init(struct iwl_priv *priv);
-extern int iwl4965_hw_nic_stop_master(struct iwl_priv *priv);
-extern void iwl4965_hw_txq_ctx_free(struct iwl_priv *priv);
-extern void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv);
-extern int iwl4965_hw_nic_reset(struct iwl_priv *priv);
-extern int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd,
- dma_addr_t addr, u16 len);
-extern int iwl4965_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl4965_tx_queue *txq);
+extern int iwl_rxq_stop(struct iwl_priv *priv);
+extern void iwl_txq_ctx_stop(struct iwl_priv *priv);
extern int iwl4965_hw_get_temperature(struct iwl_priv *priv);
-extern int iwl4965_hw_tx_queue_init(struct iwl_priv *priv,
- struct iwl4965_tx_queue *txq);
extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
- struct iwl4965_frame *frame, u8 rate);
-extern int iwl4965_hw_get_rx_read(struct iwl_priv *priv);
+ struct iwl_frame *frame, u8 rate);
extern void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv,
struct iwl_cmd *cmd,
- struct ieee80211_tx_control *ctrl,
+ struct ieee80211_tx_info *info,
struct ieee80211_hdr *hdr,
int sta_id, int tx_id);
extern int iwl4965_hw_reg_send_txpower(struct iwl_priv *priv);
extern int iwl4965_hw_reg_set_txpower(struct iwl_priv *priv, s8 power);
extern void iwl4965_hw_rx_statistics(struct iwl_priv *priv,
- struct iwl4965_rx_mem_buffer *rxb);
+ struct iwl_rx_mem_buffer *rxb);
extern void iwl4965_disable_events(struct iwl_priv *priv);
extern int iwl4965_get_temperature(const struct iwl_priv *priv);
+extern void iwl4965_rx_reply_rx(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb);
/**
- * iwl4965_hw_find_station - Find station id for a given BSSID
+ * iwl_find_station - Find station id for a given BSSID
* @bssid: MAC address of station ID to find
*
* NOTE: This should not be hardware specific but the code has
* not yet been merged into a single common layer for managing the
* station tables.
*/
-extern u8 iwl4965_hw_find_station(struct iwl_priv *priv, const u8 *bssid);
+extern u8 iwl_find_station(struct iwl_priv *priv, const u8 *bssid);
extern int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel);
-extern int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
-extern int iwl4965_queue_space(const struct iwl4965_queue *q);
+extern int iwl_queue_space(const struct iwl_queue *q);
+static inline int iwl_queue_used(const struct iwl_queue *q, int i)
+{
+ return q->write_ptr > q->read_ptr ?
+ (i >= q->read_ptr && i < q->write_ptr) :
+ !(i < q->read_ptr && i >= q->write_ptr);
+}
+
+
+static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge)
+{
+ /* This is for scan command, the big buffer at end of command array */
+ if (is_huge)
+ return q->n_window; /* must be power of 2 */
+
+ /* Otherwise, use normal size buffers */
+ return index & (q->n_window - 1);
+}
+
+
struct iwl_priv;
extern void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio);
@@ -725,45 +743,37 @@
* Forward declare iwl-4965.c functions for iwl-base.c
*/
extern int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv,
- struct iwl4965_tx_queue *txq,
+ struct iwl_tx_queue *txq,
u16 byte_cnt);
-extern void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr,
- int is_ap);
-extern void iwl4965_set_rxon_chain(struct iwl_priv *priv);
extern int iwl4965_alive_notify(struct iwl_priv *priv);
extern void iwl4965_update_rate_scaling(struct iwl_priv *priv, u8 mode);
-extern void iwl4965_chain_noise_reset(struct iwl_priv *priv);
-extern void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags,
- u8 force);
extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv);
extern void iwl4965_hwrate_to_tx_control(struct iwl_priv *priv,
u32 rate_n_flags,
- struct ieee80211_tx_control *control);
+ struct ieee80211_tx_info *info);
#ifdef CONFIG_IWL4965_HT
-void iwl4965_init_ht_hw_capab(struct iwl_priv *priv,
- struct ieee80211_ht_info *ht_info,
- enum ieee80211_band band);
+extern void iwl4965_init_ht_hw_capab(const struct iwl_priv *priv,
+ struct ieee80211_ht_info *ht_info,
+ enum ieee80211_band band);
void iwl4965_set_rxon_ht(struct iwl_priv *priv,
struct iwl_ht_info *ht_info);
-void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index,
- struct ieee80211_ht_info *sta_ht_inf);
int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
enum ieee80211_ampdu_mlme_action action,
const u8 *addr, u16 tid, u16 *ssn);
int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id,
u8 tid, int txq_id);
#else
-static inline void iwl4965_init_ht_hw_capab(struct iwl_priv *priv,
+static inline void iwl4965_init_ht_hw_capab(const struct iwl_priv *priv,
struct ieee80211_ht_info *ht_info,
enum ieee80211_band band) {}
#endif /*CONFIG_IWL4965_HT */
/* Structures, enum, and defines specific to the 4965 */
-#define IWL4965_KW_SIZE 0x1000 /*4k */
+#define IWL_KW_SIZE 0x1000 /*4k */
-struct iwl4965_kw {
+struct iwl_kw {
dma_addr_t dma_addr;
void *v_addr;
size_t size;
@@ -787,8 +797,8 @@
#define IWL_EXT_CHANNEL_OFFSET_RESERVE1 2
#define IWL_EXT_CHANNEL_OFFSET_BELOW 3
-#define NRG_NUM_PREV_STAT_L 20
-#define NUM_RX_CHAINS (3)
+#define IWL_TX_CRC_SIZE 4
+#define IWL_TX_DELIMITER_SIZE 4
#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
@@ -818,23 +828,8 @@
#define MAX_FA_CCK 50
#define MIN_FA_CCK 5
-#define NRG_MIN_CCK 97
-#define NRG_MAX_CCK 0
-
-#define AUTO_CORR_MIN_OFDM 85
-#define AUTO_CORR_MIN_OFDM_MRC 170
-#define AUTO_CORR_MIN_OFDM_X1 105
-#define AUTO_CORR_MIN_OFDM_MRC_X1 220
-#define AUTO_CORR_MAX_OFDM 120
-#define AUTO_CORR_MAX_OFDM_MRC 210
-#define AUTO_CORR_MAX_OFDM_X1 140
-#define AUTO_CORR_MAX_OFDM_MRC_X1 270
#define AUTO_CORR_STEP_OFDM 1
-#define AUTO_CORR_MIN_CCK (125)
-#define AUTO_CORR_MAX_CCK (200)
-#define AUTO_CORR_MIN_CCK_MRC 200
-#define AUTO_CORR_MAX_CCK_MRC 400
#define AUTO_CORR_STEP_CCK 3
#define AUTO_CORR_MAX_TH_CCK 160
@@ -853,6 +848,9 @@
#define IN_BAND_FILTER 0xFF
#define MIN_AVERAGE_NOISE_MAX_VALUE 0xFFFFFFFF
+#define NRG_NUM_PREV_STAT_L 20
+#define NUM_RX_CHAINS 3
+
enum iwl4965_false_alarm_state {
IWL_FA_TOO_MANY = 0,
IWL_FA_TOO_FEW = 1,
@@ -865,11 +863,6 @@
IWL_CHAIN_NOISE_CALIBRATED = 2,
};
-enum iwl4965_sensitivity_state {
- IWL_SENS_CALIB_ALLOWED = 0,
- IWL_SENS_CALIB_NEED_REINIT = 1,
-};
-
enum iwl4965_calib_enabled_state {
IWL_CALIB_DISABLED = 0, /* must be 0 */
IWL_CALIB_ENABLED = 1,
@@ -884,8 +877,24 @@
u32 beacon_energy_c;
};
+struct iwl_calib_results {
+ void *tx_iq_res;
+ void *tx_iq_perd_res;
+ void *lo_res;
+ u32 tx_iq_res_len;
+ u32 tx_iq_perd_res_len;
+ u32 lo_res_len;
+};
+
+enum ucode_type {
+ UCODE_NONE = 0,
+ UCODE_INIT,
+ UCODE_RT
+};
+
+#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
/* Sensitivity calib data */
-struct iwl4965_sensitivity_data {
+struct iwl_sensitivity_data {
u32 auto_corr_ofdm;
u32 auto_corr_ofdm_mrc;
u32 auto_corr_ofdm_x1;
@@ -909,12 +918,10 @@
s32 nrg_auto_corr_silence_diff;
u32 num_in_cck_no_fa;
u32 nrg_th_ofdm;
-
- u8 state;
};
/* Chain noise (differential Rx gain) calib data */
-struct iwl4965_chain_noise_data {
+struct iwl_chain_noise_data {
u8 state;
u16 beacon_count;
u32 chain_noise_a;
@@ -927,6 +934,7 @@
u8 delta_gain_code[NUM_RX_CHAINS];
u8 radio_write;
};
+#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */
#define EEPROM_SEM_TIMEOUT 10 /* milliseconds */
#define EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */
@@ -960,7 +968,7 @@
bool add_radiotap;
void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
- struct iwl4965_rx_mem_buffer *rxb);
+ struct iwl_rx_mem_buffer *rxb);
struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
@@ -985,6 +993,9 @@
s32 temperature; /* degrees Kelvin */
s32 last_temperature;
+ /* init calibration results */
+ struct iwl_calib_results calib_results;
+
/* Scan related variables */
unsigned long last_scan_jiffies;
unsigned long next_scan_jiffies;
@@ -1007,6 +1018,9 @@
/* pci hardware address support */
void __iomem *hw_base;
+ u32 hw_rev;
+ u32 hw_wa_rev;
+ u8 rev_id;
/* uCode images, save to reload in case of failure */
struct fw_desc ucode_code; /* runtime inst */
@@ -1015,6 +1029,8 @@
struct fw_desc ucode_init; /* initialization inst */
struct fw_desc ucode_init_data; /* initialization data */
struct fw_desc ucode_boot; /* bootstrap inst */
+ enum ucode_type ucode_type;
+ u8 ucode_write_complete; /* the image write is complete */
struct iwl4965_rxon_time_cmd rxon_timing;
@@ -1023,16 +1039,16 @@
* changed via explicit cast within the
* routines that actually update the physical
* hardware */
- const struct iwl4965_rxon_cmd active_rxon;
- struct iwl4965_rxon_cmd staging_rxon;
+ const struct iwl_rxon_cmd active_rxon;
+ struct iwl_rxon_cmd staging_rxon;
int error_recovering;
- struct iwl4965_rxon_cmd recovery_rxon;
+ struct iwl_rxon_cmd recovery_rxon;
/* 1st responses from initialize and runtime uCode images.
* 4965's initialize alive response contains some calibration data. */
- struct iwl4965_init_alive_resp card_alive_init;
- struct iwl4965_alive_resp card_alive;
+ struct iwl_init_alive_resp card_alive_init;
+ struct iwl_alive_resp card_alive;
#ifdef CONFIG_IWLWIFI_RFKILL
struct iwl_rfkill_mngr rfkill_mngr;
#endif
@@ -1050,13 +1066,12 @@
u8 assoc_station_added;
u8 use_ant_b_for_management_frame; /* Tx antenna selection */
- u8 valid_antenna; /* Bit mask of antennas actually connected */
-#ifdef CONFIG_IWL4965_SENSITIVITY
- struct iwl4965_sensitivity_data sensitivity_data;
- struct iwl4965_chain_noise_data chain_noise_data;
u8 start_calib;
+#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
+ struct iwl_sensitivity_data sensitivity_data;
+ struct iwl_chain_noise_data chain_noise_data;
__le16 sensitivity_tbl[HD_TABLE_SIZE];
-#endif /*CONFIG_IWL4965_SENSITIVITY*/
+#endif /*CONFIG_IWLWIFI_RUN_TIME_CALIB*/
#ifdef CONFIG_IWL4965_HT
struct iwl_ht_info current_ht_config;
@@ -1075,10 +1090,10 @@
int activity_timer_active;
/* Rx and Tx DMA processing queues */
- struct iwl4965_rx_queue rxq;
- struct iwl4965_tx_queue txq[IWL_MAX_NUM_QUEUES];
+ struct iwl_rx_queue rxq;
+ struct iwl_tx_queue txq[IWL_MAX_NUM_QUEUES];
unsigned long txq_ctx_active_msk;
- struct iwl4965_kw kw; /* keep warm address */
+ struct iwl_kw kw; /* keep warm address */
u32 scd_base_addr; /* scheduler sram base address */
unsigned long status;
@@ -1092,7 +1107,7 @@
u64 bytes;
} tx_stats[3], rx_stats[3];
- struct iwl4965_power_mgr power_data;
+ struct iwl_power_mgr power_data;
struct iwl4965_notif_statistics statistics;
unsigned long last_statistics_time;
@@ -1111,7 +1126,7 @@
/*station table variables */
spinlock_t sta_lock;
int num_stations;
- struct iwl4965_station_entry stations[IWL_STATION_COUNT];
+ struct iwl_station_entry stations[IWL_STATION_COUNT];
struct iwl_wep_key wep_keys[WEP_KEYS_MAX];
u8 default_wep_key;
u8 key_mapping_key;
@@ -1122,8 +1137,6 @@
u8 mac80211_registered;
- u32 notif_missed_beacons;
-
/* Rx'd packet timing information */
u32 last_beacon_time;
u64 last_tsf;
@@ -1137,7 +1150,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;
@@ -1151,6 +1165,7 @@
struct iwl_hw_params hw_params;
/* driver/uCode shared Tx Byte Counts and Rx status */
void *shared_virt;
+ int rb_closed_offset;
/* Physical Pointer to Tx Byte Counts and Rx status */
dma_addr_t shared_phys;
@@ -1176,6 +1191,7 @@
struct work_struct report_work;
struct work_struct request_scan;
struct work_struct beacon_update;
+ struct work_struct set_monitor;
struct tasklet_struct irq_tasklet;
@@ -1197,6 +1213,7 @@
#ifdef CONFIG_IWLWIFI_DEBUG
/* debugging info */
+ u32 debug_level;
u32 framecnt_to_us;
atomic_t restrict_refcnt;
#ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -1206,12 +1223,56 @@
#endif /* CONFIG_IWLWIFI_DEBUG */
struct work_struct txpower_work;
-#ifdef CONFIG_IWL4965_SENSITIVITY
+#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
+ u32 disable_sens_cal;
+ u32 disable_chain_noise_cal;
+#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */
+#ifdef CONFIG_IWL4965_RUN_TIME_CALIB
struct work_struct sensitivity_work;
-#endif
+#endif /* CONFIG_IWL4965_RUN_TIME_CALIB */
struct timer_list statistics_periodic;
}; /*iwl_priv */
+static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id)
+{
+ set_bit(txq_id, &priv->txq_ctx_active_msk);
+}
+
+static inline void iwl_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id)
+{
+ clear_bit(txq_id, &priv->txq_ctx_active_msk);
+}
+
+#ifdef CONFIG_IWLWIF_DEBUG
+const char *iwl_get_tx_fail_reason(u32 status);
+#else
+static inline const char *iwl_get_tx_fail_reason(u32 status) { return ""; }
+#endif
+
+
+#ifdef CONFIG_IWL4965_HT
+static inline int iwl_get_ra_sta_id(struct iwl_priv *priv,
+ struct ieee80211_hdr *hdr)
+{
+ if (priv->iw_mode == IEEE80211_IF_TYPE_STA) {
+ return IWL_AP_ID;
+ } else {
+ u8 *da = ieee80211_get_DA(hdr);
+ return iwl_find_station(priv, da);
+ }
+}
+
+static inline struct ieee80211_hdr *iwl_tx_queue_get_hdr(struct iwl_priv *priv,
+ int txq_id, int idx)
+{
+ if (priv->txq[txq_id].txb[idx].skb[0])
+ return (struct ieee80211_hdr *)priv->txq[txq_id].
+ txb[idx].skb[0]->data;
+ return NULL;
+}
+#endif
+
+
static inline int iwl_is_associated(struct iwl_priv *priv)
{
return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
@@ -1224,11 +1285,6 @@
return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0;
}
-static inline int is_channel_narrow(const struct iwl_channel_info *ch_info)
-{
- return (ch_info->flags & EEPROM_CHANNEL_NARROW) ? 1 : 0;
-}
-
static inline int is_channel_radar(const struct iwl_channel_info *ch_info)
{
return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0;
@@ -1254,6 +1310,23 @@
return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0;
}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level,
+ void *p, u32 len)
+{
+ if (!(priv->debug_level & level))
+ return;
+
+ print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1,
+ p, len, 1);
+}
+#else
+static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level,
+ void *p, u32 len)
+{
+}
+#endif
+
extern const struct iwl_channel_info *iwl_get_channel_info(
const struct iwl_priv *priv, enum ieee80211_band band, u16 channel);
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index a07d5dc..11f9d95 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:
@@ -317,13 +365,13 @@
? # x " " : "")
/**
- * iwl4965_set_fat_chan_info - Copy fat channel info into driver's priv.
+ * iwl_set_fat_chan_info - Copy fat channel info into driver's priv.
*
* Does not set up a command, or touch hardware.
*/
-static int iwl4965_set_fat_chan_info(struct iwl_priv *priv,
+static int iwl_set_fat_chan_info(struct iwl_priv *priv,
enum ieee80211_band band, u16 channel,
- const struct iwl4965_eeprom_channel *eeprom_ch,
+ const struct iwl_eeprom_channel *eeprom_ch,
u8 fat_extension_channel)
{
struct iwl_channel_info *ch_info;
@@ -334,7 +382,7 @@
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,
@@ -502,16 +542,16 @@
fat_extension_chan = HT_IE_EXT_CHANNEL_ABOVE;
/* Set up driver's info for lower half */
- iwl4965_set_fat_chan_info(priv, ieeeband,
- eeprom_ch_index[ch],
- &(eeprom_ch_info[ch]),
- fat_extension_chan);
+ iwl_set_fat_chan_info(priv, ieeeband,
+ eeprom_ch_index[ch],
+ &(eeprom_ch_info[ch]),
+ fat_extension_chan);
/* Set up driver's info for upper half */
- iwl4965_set_fat_chan_info(priv, ieeeband,
- (eeprom_ch_index[ch] + 4),
- &(eeprom_ch_info[ch]),
- HT_IE_EXT_CHANNEL_BELOW);
+ iwl_set_fat_chan_info(priv, ieeeband,
+ (eeprom_ch_index[ch] + 4),
+ &(eeprom_ch_info[ch]),
+ HT_IE_EXT_CHANNEL_BELOW);
}
}
@@ -520,23 +560,21 @@
EXPORT_SYMBOL(iwl_init_channel_map);
/*
- * iwl_free_channel_map - undo allocations in iwl4965_init_channel_map
+ * iwl_free_channel_map - undo allocations in iwl_init_channel_map
*/
void iwl_free_channel_map(struct iwl_priv *priv)
{
kfree(priv->channel_info);
priv->channel_count = 0;
}
-EXPORT_SYMBOL(iwl_free_channel_map);
/**
* iwl_get_channel_info - Find driver's private channel info
*
* Based on band and channel number.
*/
-const struct iwl_channel_info *iwl_get_channel_info(
- const struct iwl_priv *priv,
- enum ieee80211_band band, u16 channel)
+const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv,
+ enum ieee80211_band band, u16 channel)
{
int i;
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index bd0a042..d3a2a5b 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,55 @@
* 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)
+#define EEPROM_5000_XTAL ((2*0x128) | EEPROM_5000_CALIB_ALL)
+
+/* 5000 links */
+#define EEPROM_5000_LINK_HOST (2*0x64)
+#define EEPROM_5000_LINK_GENERAL (2*0x65)
+#define EEPROM_5000_LINK_REGULATORY (2*0x66)
+#define EEPROM_5000_LINK_CALIBRATION (2*0x67)
+#define EEPROM_5000_LINK_PROCESS_ADJST (2*0x68)
+#define EEPROM_5000_LINK_OTHERS (2*0x69)
+
+/* 5000 regulatory - indirect access */
+#define EEPROM_5000_REG_SKU_ID ((0x02)\
+ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 4 bytes */
+#define EEPROM_5000_REG_BAND_1_CHANNELS ((0x08)\
+ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 28 bytes */
+#define EEPROM_5000_REG_BAND_2_CHANNELS ((0x26)\
+ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 26 bytes */
+#define EEPROM_5000_REG_BAND_3_CHANNELS ((0x42)\
+ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */
+#define EEPROM_5000_REG_BAND_4_CHANNELS ((0x5C)\
+ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */
+#define EEPROM_5000_REG_BAND_5_CHANNELS ((0x74)\
+ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 12 bytes */
+#define EEPROM_5000_REG_BAND_24_FAT_CHANNELS ((0x82)\
+ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 14 bytes */
+#define EEPROM_5000_REG_BAND_52_FAT_CHANNELS ((0x92)\
+ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */
+
/* 2.4 GHz */
extern const u8 iwl_eeprom_band_1[14];
/*
- * 4965 factory calibration data for one txpower level, on one channel,
+ * factory calibration data for one txpower level, on one channel,
* measured on one of the 2 tx chains (radio transmitter and associated
* antenna). EEPROM contains:
*
@@ -154,7 +192,7 @@
*
* 4) RF power amplifier detector level measurement (not used).
*/
-struct iwl4965_eeprom_calib_measure {
+struct iwl_eeprom_calib_measure {
u8 temperature; /* Device temperature (Celsius) */
u8 gain_idx; /* Index into gain table */
u8 actual_pow; /* Measured RF output power, half-dBm */
@@ -163,22 +201,22 @@
/*
- * 4965 measurement set for one channel. EEPROM contains:
+ * measurement set for one channel. EEPROM contains:
*
* 1) Channel number measured
*
* 2) Measurements for each of 3 power levels for each of 2 radio transmitters
* (a.k.a. "tx chains") (6 measurements altogether)
*/
-struct iwl4965_eeprom_calib_ch_info {
+struct iwl_eeprom_calib_ch_info {
u8 ch_num;
- struct iwl4965_eeprom_calib_measure
+ struct iwl_eeprom_calib_measure
measurements[EEPROM_TX_POWER_TX_CHAINS]
[EEPROM_TX_POWER_MEASUREMENTS];
} __attribute__ ((packed));
/*
- * 4965 txpower subband info.
+ * txpower subband info.
*
* For each frequency subband, EEPROM contains the following:
*
@@ -187,16 +225,16 @@
*
* 2) Sample measurement sets for 2 channels close to the range endpoints.
*/
-struct iwl4965_eeprom_calib_subband_info {
+struct iwl_eeprom_calib_subband_info {
u8 ch_from; /* channel number of lowest channel in subband */
u8 ch_to; /* channel number of highest channel in subband */
- struct iwl4965_eeprom_calib_ch_info ch1;
- struct iwl4965_eeprom_calib_ch_info ch2;
+ struct iwl_eeprom_calib_ch_info ch1;
+ struct iwl_eeprom_calib_ch_info ch2;
} __attribute__ ((packed));
/*
- * 4965 txpower calibration info. EEPROM contains:
+ * txpower calibration info. EEPROM contains:
*
* 1) Factory-measured saturation power levels (maximum levels at which
* tx power amplifier can output a signal without too much distortion).
@@ -212,55 +250,58 @@
* 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 +310,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 +358,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..6c53736 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"
@@ -56,6 +56,7 @@
IWL_CMD(REPLY_RATE_SCALE);
IWL_CMD(REPLY_LEDS_CMD);
IWL_CMD(REPLY_TX_LINK_QUALITY_CMD);
+ IWL_CMD(COEX_PRIORITY_TABLE_CMD);
IWL_CMD(RADAR_NOTIFICATION);
IWL_CMD(REPLY_QUIET_CMD);
IWL_CMD(REPLY_CHANNEL_SWITCH);
@@ -89,6 +90,9 @@
IWL_CMD(REPLY_RX_MPDU_CMD);
IWL_CMD(REPLY_RX);
IWL_CMD(REPLY_COMPRESSED_BA);
+ IWL_CMD(CALIBRATION_CFG_CMD);
+ IWL_CMD(CALIBRATION_RES_NOTIFICATION);
+ IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION);
default:
return "UNKNOWN";
@@ -101,7 +105,7 @@
static int iwl_generic_cmd_callback(struct iwl_priv *priv,
struct iwl_cmd *cmd, struct sk_buff *skb)
{
- struct iwl4965_rx_packet *pkt = NULL;
+ struct iwl_rx_packet *pkt = NULL;
if (!skb) {
IWL_ERROR("Error: Response NULL in %s.\n",
@@ -109,7 +113,7 @@
return 1;
}
- pkt = (struct iwl4965_rx_packet *)skb->data;
+ pkt = (struct iwl_rx_packet *)skb->data;
if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERROR("Bad return from %s (0x%08X)\n",
get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
@@ -139,7 +143,7 @@
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return -EBUSY;
- ret = priv->cfg->ops->utils->enqueue_hcmd(priv, cmd);
+ ret = iwl_enqueue_hcmd(priv, cmd);
if (ret < 0) {
IWL_ERROR("Error sending %s: enqueue_hcmd failed: %d\n",
get_cmd_string(cmd->id), ret);
@@ -170,7 +174,7 @@
if (cmd->meta.flags & CMD_WANT_SKB)
cmd->meta.source = &cmd->meta;
- cmd_idx = priv->cfg->ops->utils->enqueue_hcmd(priv, cmd);
+ cmd_idx = iwl_enqueue_hcmd(priv, cmd);
if (cmd_idx < 0) {
ret = cmd_idx;
IWL_ERROR("Error sending %s: enqueue_hcmd failed: %d\n",
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
index a443472..dedefa0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-helpers.h
+++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h
@@ -136,6 +136,8 @@
#define KELVIN_TO_CELSIUS(x) ((x)-273)
#define CELSIUS_TO_KELVIN(x) ((x)+273)
+#define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
+
#define IEEE80211_CHAN_W_RADAR_DETECT 0x00000010
@@ -235,6 +237,25 @@
((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_RESP);
}
+static inline int ieee80211_is_qos_data(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_QOS_DATA);
+}
+/**
+ * ieee80211_get_qos_ctrl - get pointer to the QoS control field
+ *
+ * This function returns the pointer to 802.11 header QoS field (2 bytes)
+ * This function doesn't check whether hdr is a QoS hdr, use with care
+ * @hdr: struct ieee80211_hdr *hdr
+ * @hdr_len: header length
+ */
+
+static inline u8 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr, int hdr_len)
+{
+ return ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN);
+}
+
static inline int iwl_check_bits(unsigned long field, unsigned long mask)
{
return ((field & mask) == mask) ? 1 : 0;
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 c9cf8eef..70d9c75 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -239,40 +239,307 @@
#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)
+/*
+ * 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 IWL_SCD_TXFIFO_POS_TID (0)
+#define IWL_SCD_TXFIFO_POS_RA (4)
+#define IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF)
+
+/* 5000 SCD */
+#define IWL50_SCD_QUEUE_STTS_REG_POS_TXF (0)
+#define IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE (3)
+#define IWL50_SCD_QUEUE_STTS_REG_POS_WSL (4)
+#define IWL50_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (19)
+#define IWL50_SCD_QUEUE_STTS_REG_MSK (0x00FF0000)
+
+#define IWL50_SCD_QUEUE_CTX_REG1_CREDIT_POS (8)
+#define IWL50_SCD_QUEUE_CTX_REG1_CREDIT_MSK (0x00FFFF00)
+#define IWL50_SCD_QUEUE_CTX_REG1_SUPER_CREDIT_POS (24)
+#define IWL50_SCD_QUEUE_CTX_REG1_SUPER_CREDIT_MSK (0xFF000000)
+#define IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS (0)
+#define IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK (0x0000007F)
+#define IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16)
+#define IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000)
+
+#define IWL50_SCD_CONTEXT_DATA_OFFSET (0x600)
+#define IWL50_SCD_TX_STTS_BITMAP_OFFSET (0x7B1)
+#define IWL50_SCD_TRANSLATE_TBL_OFFSET (0x7E0)
+
+#define IWL50_SCD_CONTEXT_QUEUE_OFFSET(x)\
+ (IWL50_SCD_CONTEXT_DATA_OFFSET + ((x) * 8))
+
+#define IWL50_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \
+ ((IWL50_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffc)
+
+#define IWL50_SCD_QUEUECHAIN_SEL_ALL(x) (((1<<(x)) - 1) &\
+ (~(1<<IWL_CMD_QUEUE_NUM)))
+
#define IWL50_SCD_BASE (PRPH_BASE + 0xa02c00)
#define IWL50_SCD_SRAM_BASE_ADDR (IWL50_SCD_BASE + 0x0)
@@ -287,4 +554,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-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
new file mode 100644
index 0000000..cc61c93
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -0,0 +1,470 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <net/mac80211.h>
+#include "iwl-eeprom.h"
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-sta.h"
+#include "iwl-io.h"
+#include "iwl-calib.h"
+#include "iwl-helpers.h"
+/************************** RX-FUNCTIONS ****************************/
+/*
+ * Rx theory of operation
+ *
+ * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs),
+ * each of which point to Receive Buffers to be filled by the NIC. These get
+ * used not only for Rx frames, but for any command response or notification
+ * from the NIC. The driver and NIC manage the Rx buffers by means
+ * of indexes into the circular buffer.
+ *
+ * Rx Queue Indexes
+ * The host/firmware share two index registers for managing the Rx buffers.
+ *
+ * The READ index maps to the first position that the firmware may be writing
+ * to -- the driver can read up to (but not including) this position and get
+ * good data.
+ * The READ index is managed by the firmware once the card is enabled.
+ *
+ * The WRITE index maps to the last position the driver has read from -- the
+ * position preceding WRITE is the last slot the firmware can place a packet.
+ *
+ * The queue is empty (no good data) if WRITE = READ - 1, and is full if
+ * WRITE = READ.
+ *
+ * During initialization, the host sets up the READ queue position to the first
+ * INDEX position, and WRITE to the last (READ - 1 wrapped)
+ *
+ * When the firmware places a packet in a buffer, it will advance the READ index
+ * and fire the RX interrupt. The driver can then query the READ index and
+ * process as many packets as possible, moving the WRITE index forward as it
+ * resets the Rx queue buffers with new memory.
+ *
+ * The management in the driver is as follows:
+ * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When
+ * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
+ * to replenish the iwl->rxq->rx_free.
+ * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the
+ * iwl->rxq is replenished and the READ INDEX is updated (updating the
+ * 'processed' and 'read' driver indexes as well)
+ * + A received packet is processed and handed to the kernel network stack,
+ * detached from the iwl->rxq. The driver 'processed' index is updated.
+ * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free
+ * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ
+ * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there
+ * were enough free buffers and RX_STALLED is set it is cleared.
+ *
+ *
+ * Driver sequence:
+ *
+ * iwl_rx_queue_alloc() Allocates rx_free
+ * iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls
+ * iwl_rx_queue_restock
+ * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx
+ * queue, updates firmware pointers, and updates
+ * the WRITE index. If insufficient rx_free buffers
+ * are available, schedules iwl_rx_replenish
+ *
+ * -- enable interrupts --
+ * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the
+ * READ INDEX, detaching the SKB from the pool.
+ * Moves the packet buffer from queue to rx_used.
+ * Calls iwl_rx_queue_restock to refill any empty
+ * slots.
+ * ...
+ *
+ */
+
+/**
+ * iwl_rx_queue_space - Return number of free slots available in queue.
+ */
+int iwl_rx_queue_space(const struct iwl_rx_queue *q)
+{
+ int s = q->read - q->write;
+ if (s <= 0)
+ s += RX_QUEUE_SIZE;
+ /* keep some buffer to not confuse full and empty queue */
+ s -= 2;
+ if (s < 0)
+ s = 0;
+ return s;
+}
+EXPORT_SYMBOL(iwl_rx_queue_space);
+
+/**
+ * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
+ */
+int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
+{
+ u32 reg = 0;
+ int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&q->lock, flags);
+
+ if (q->need_update == 0)
+ goto exit_unlock;
+
+ /* If power-saving is in use, make sure device is awake */
+ if (test_bit(STATUS_POWER_PMI, &priv->status)) {
+ reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
+
+ if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+ iwl_set_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ goto exit_unlock;
+ }
+
+ ret = iwl_grab_nic_access(priv);
+ if (ret)
+ goto exit_unlock;
+
+ /* Device expects a multiple of 8 */
+ iwl_write_direct32(priv, FH_RSCSR_CHNL0_WPTR,
+ q->write & ~0x7);
+ iwl_release_nic_access(priv);
+
+ /* Else device is assumed to be awake */
+ } else
+ /* Device expects a multiple of 8 */
+ iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7);
+
+
+ q->need_update = 0;
+
+ exit_unlock:
+ spin_unlock_irqrestore(&q->lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL(iwl_rx_queue_update_write_ptr);
+/**
+ * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
+ */
+static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv,
+ dma_addr_t dma_addr)
+{
+ return cpu_to_le32((u32)(dma_addr >> 8));
+}
+
+/**
+ * iwl_rx_queue_restock - refill RX queue from pre-allocated pool
+ *
+ * If there are slots in the RX queue that need to be restocked,
+ * and we have free pre-allocated buffers, fill the ranks as much
+ * as we can, pulling from rx_free.
+ *
+ * This moves the 'write' index forward to catch up with 'processed', and
+ * also updates the memory address in the firmware to reference the new
+ * target buffer.
+ */
+int iwl_rx_queue_restock(struct iwl_priv *priv)
+{
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ struct list_head *element;
+ struct iwl_rx_mem_buffer *rxb;
+ unsigned long flags;
+ int write;
+ int ret = 0;
+
+ spin_lock_irqsave(&rxq->lock, flags);
+ write = rxq->write & ~0x7;
+ while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
+ /* Get next free Rx buffer, remove from free list */
+ element = rxq->rx_free.next;
+ rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+ list_del(element);
+
+ /* Point to Rx buffer via next RBD in circular buffer */
+ rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->dma_addr);
+ rxq->queue[rxq->write] = rxb;
+ rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
+ rxq->free_count--;
+ }
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ /* If the pre-allocated buffer pool is dropping low, schedule to
+ * refill it */
+ if (rxq->free_count <= RX_LOW_WATERMARK)
+ queue_work(priv->workqueue, &priv->rx_replenish);
+
+
+ /* If we've added more space for the firmware to place data, tell it.
+ * Increment device's write pointer in multiples of 8. */
+ if ((write != (rxq->write & ~0x7))
+ || (abs(rxq->write - rxq->read) > 7)) {
+ spin_lock_irqsave(&rxq->lock, flags);
+ rxq->need_update = 1;
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ ret = iwl_rx_queue_update_write_ptr(priv, rxq);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(iwl_rx_queue_restock);
+
+
+/**
+ * iwl_rx_replenish - Move all used packet from rx_used to rx_free
+ *
+ * When moving to rx_free an SKB is allocated for the slot.
+ *
+ * Also restock the Rx queue via iwl_rx_queue_restock.
+ * This is called as a scheduled work item (except for during initialization)
+ */
+void iwl_rx_allocate(struct iwl_priv *priv)
+{
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ struct list_head *element;
+ struct iwl_rx_mem_buffer *rxb;
+ unsigned long flags;
+ spin_lock_irqsave(&rxq->lock, flags);
+ while (!list_empty(&rxq->rx_used)) {
+ element = rxq->rx_used.next;
+ rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+
+ /* Alloc a new receive buffer */
+ rxb->skb = alloc_skb(priv->hw_params.rx_buf_size,
+ __GFP_NOWARN | GFP_ATOMIC);
+ if (!rxb->skb) {
+ if (net_ratelimit())
+ printk(KERN_CRIT DRV_NAME
+ ": Can not allocate SKB buffers\n");
+ /* We don't reschedule replenish work here -- we will
+ * call the restock method and if it still needs
+ * more buffers it will schedule replenish */
+ break;
+ }
+ priv->alloc_rxb_skb++;
+ list_del(element);
+
+ /* Get physical address of RB/SKB */
+ rxb->dma_addr =
+ pci_map_single(priv->pci_dev, rxb->skb->data,
+ priv->hw_params.rx_buf_size, PCI_DMA_FROMDEVICE);
+ list_add_tail(&rxb->list, &rxq->rx_free);
+ rxq->free_count++;
+ }
+ spin_unlock_irqrestore(&rxq->lock, flags);
+}
+EXPORT_SYMBOL(iwl_rx_allocate);
+
+void iwl_rx_replenish(struct iwl_priv *priv)
+{
+ unsigned long flags;
+
+ iwl_rx_allocate(priv);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_rx_queue_restock(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL(iwl_rx_replenish);
+
+
+/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
+ * If an SKB has been detached, the POOL needs to have its SKB set to NULL
+ * This free routine walks the list of POOL entries and if SKB is set to
+ * non NULL it is unmapped and freed
+ */
+void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+ int i;
+ for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
+ if (rxq->pool[i].skb != NULL) {
+ pci_unmap_single(priv->pci_dev,
+ rxq->pool[i].dma_addr,
+ priv->hw_params.rx_buf_size,
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(rxq->pool[i].skb);
+ }
+ }
+
+ pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
+ rxq->dma_addr);
+ rxq->bd = NULL;
+}
+EXPORT_SYMBOL(iwl_rx_queue_free);
+
+int iwl_rx_queue_alloc(struct iwl_priv *priv)
+{
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ struct pci_dev *dev = priv->pci_dev;
+ int i;
+
+ spin_lock_init(&rxq->lock);
+ INIT_LIST_HEAD(&rxq->rx_free);
+ INIT_LIST_HEAD(&rxq->rx_used);
+
+ /* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */
+ rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr);
+ if (!rxq->bd)
+ return -ENOMEM;
+
+ /* Fill the rx_used queue with _all_ of the Rx buffers */
+ for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
+ list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+
+ /* Set us so that we have processed and used all buffers, but have
+ * not restocked the Rx queue with fresh buffers */
+ rxq->read = rxq->write = 0;
+ rxq->free_count = 0;
+ rxq->need_update = 0;
+ return 0;
+}
+EXPORT_SYMBOL(iwl_rx_queue_alloc);
+
+void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+ unsigned long flags;
+ int i;
+ spin_lock_irqsave(&rxq->lock, flags);
+ INIT_LIST_HEAD(&rxq->rx_free);
+ INIT_LIST_HEAD(&rxq->rx_used);
+ /* Fill the rx_used queue with _all_ of the Rx buffers */
+ for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
+ /* In the reset function, these buffers may have been allocated
+ * to an SKB, so we need to unmap and free potential storage */
+ if (rxq->pool[i].skb != NULL) {
+ pci_unmap_single(priv->pci_dev,
+ rxq->pool[i].dma_addr,
+ priv->hw_params.rx_buf_size,
+ PCI_DMA_FROMDEVICE);
+ priv->alloc_rxb_skb--;
+ dev_kfree_skb(rxq->pool[i].skb);
+ rxq->pool[i].skb = NULL;
+ }
+ list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+ }
+
+ /* Set us so that we have processed and used all buffers, but have
+ * not restocked the Rx queue with fresh buffers */
+ rxq->read = rxq->write = 0;
+ rxq->free_count = 0;
+ spin_unlock_irqrestore(&rxq->lock, flags);
+}
+EXPORT_SYMBOL(iwl_rx_queue_reset);
+
+int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+ int ret;
+ unsigned long flags;
+ unsigned int rb_size;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ ret = iwl_grab_nic_access(priv);
+ if (ret) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return ret;
+ }
+
+ if (priv->cfg->mod_params->amsdu_size_8K)
+ rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
+ else
+ rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
+
+ /* Stop Rx DMA */
+ iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+
+ /* Reset driver's Rx queue write index */
+ iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
+
+ /* Tell device where to find RBD circular buffer in DRAM */
+ iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
+ rxq->dma_addr >> 8);
+
+ /* Tell device where in DRAM to update its Rx status */
+ iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
+ (priv->shared_phys + priv->rb_closed_offset) >> 4);
+
+ /* Enable Rx DMA, enable host interrupt, Rx buffer size 4k, 256 RBDs */
+ iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG,
+ FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
+ FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
+ rb_size |
+ /* 0x10 << 4 | */
+ (RX_QUEUE_SIZE_LOG <<
+ FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));
+
+ /*
+ * iwl_write32(priv,CSR_INT_COAL_REG,0);
+ */
+
+ iwl_release_nic_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+int iwl_rxq_stop(struct iwl_priv *priv)
+{
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ ret = iwl_grab_nic_access(priv);
+ if (unlikely(ret)) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return ret;
+ }
+
+ /* stop Rx DMA */
+ iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+ ret = iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
+ (1 << 24), 1000);
+ if (ret < 0)
+ IWL_ERROR("Can't stop Rx DMA.\n");
+
+ iwl_release_nic_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(iwl_rxq_stop);
+
+void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+
+{
+#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl4965_missed_beacon_notif *missed_beacon;
+
+ missed_beacon = &pkt->u.missed_beacon;
+ if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) {
+ IWL_DEBUG_CALIB("missed bcn cnsq %d totl %d rcd %d expctd %d\n",
+ le32_to_cpu(missed_beacon->consequtive_missed_beacons),
+ le32_to_cpu(missed_beacon->total_missed_becons),
+ le32_to_cpu(missed_beacon->num_recvd_beacons),
+ le32_to_cpu(missed_beacon->num_expected_beacons));
+ if (!test_bit(STATUS_SCANNING, &priv->status))
+ iwl_init_sensitivity(priv);
+ }
+#endif /* CONFIG_IWLWIFI_RUN_TIME_CALIB */
+}
+EXPORT_SYMBOL(iwl_rx_missed_beacon_notif);
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index e4fdfaa..983f107 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -28,16 +28,404 @@
*****************************************************************************/
#include <net/mac80211.h>
+#include <linux/etherdevice.h>
#include "iwl-eeprom.h"
-#include "iwl-4965.h"
+#include "iwl-dev.h"
#include "iwl-core.h"
#include "iwl-sta.h"
#include "iwl-io.h"
#include "iwl-helpers.h"
-#include "iwl-4965.h"
-#include "iwl-sta.h"
+
+#define IWL_STA_DRIVER_ACTIVE 0x1 /* ucode entry is active */
+#define IWL_STA_UCODE_ACTIVE 0x2 /* ucode entry is active */
+
+u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr)
+{
+ int i;
+ int start = 0;
+ int ret = IWL_INVALID_STATION;
+ unsigned long flags;
+ DECLARE_MAC_BUF(mac);
+
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) ||
+ (priv->iw_mode == IEEE80211_IF_TYPE_AP))
+ start = IWL_STA_ID;
+
+ if (is_broadcast_ether_addr(addr))
+ return priv->hw_params.bcast_sta_id;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ for (i = start; i < priv->hw_params.max_stations; i++)
+ if (priv->stations[i].used &&
+ (!compare_ether_addr(priv->stations[i].sta.sta.addr,
+ addr))) {
+ ret = i;
+ goto out;
+ }
+
+ IWL_DEBUG_ASSOC_LIMIT("can not find STA %s total %d\n",
+ print_mac(mac, addr), priv->num_stations);
+
+ out:
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL(iwl_find_station);
+
+static int iwl_add_sta_callback(struct iwl_priv *priv,
+ struct iwl_cmd *cmd, struct sk_buff *skb)
+{
+ struct iwl_rx_packet *res = NULL;
+
+ if (!skb) {
+ IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n");
+ return 1;
+ }
+
+ res = (struct iwl_rx_packet *)skb->data;
+ if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
+ res->hdr.flags);
+ return 1;
+ }
+
+ switch (res->u.add_sta.status) {
+ case ADD_STA_SUCCESS_MSK:
+ /* FIXME: implement iwl_sta_ucode_activate(priv, addr); */
+ /* fail through */
+ default:
+ IWL_DEBUG_HC("Received REPLY_ADD_STA:(0x%08X)\n",
+ res->u.add_sta.status);
+ break;
+ }
+
+ /* We didn't cache the SKB; let the caller free it */
+ return 1;
+}
+
+
+
+int iwl_send_add_sta(struct iwl_priv *priv,
+ struct iwl_addsta_cmd *sta, u8 flags)
+{
+ struct iwl_rx_packet *res = NULL;
+ int ret = 0;
+ u8 data[sizeof(*sta)];
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_ADD_STA,
+ .meta.flags = flags,
+ .data = data,
+ };
+
+ if (flags & CMD_ASYNC)
+ cmd.meta.u.callback = iwl_add_sta_callback;
+ else
+ cmd.meta.flags |= CMD_WANT_SKB;
+
+ cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data);
+ ret = iwl_send_cmd(priv, &cmd);
+
+ if (ret || (flags & CMD_ASYNC))
+ return ret;
+
+ res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
+ res->hdr.flags);
+ ret = -EIO;
+ }
+
+ if (ret == 0) {
+ switch (res->u.add_sta.status) {
+ case ADD_STA_SUCCESS_MSK:
+ IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n");
+ break;
+ default:
+ ret = -EIO;
+ IWL_WARNING("REPLY_ADD_STA failed\n");
+ break;
+ }
+ }
+
+ priv->alloc_rxb_skb--;
+ dev_kfree_skb_any(cmd.meta.u.skb);
+
+ return ret;
+}
+EXPORT_SYMBOL(iwl_send_add_sta);
+
+#ifdef CONFIG_IWL4965_HT
+
+static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
+ struct ieee80211_ht_info *sta_ht_inf)
+{
+ __le32 sta_flags;
+ u8 mimo_ps_mode;
+
+ if (!sta_ht_inf || !sta_ht_inf->ht_supported)
+ goto done;
+
+ mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2;
+
+ sta_flags = priv->stations[index].sta.station_flags;
+
+ sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK);
+
+ switch (mimo_ps_mode) {
+ case WLAN_HT_CAP_MIMO_PS_STATIC:
+ sta_flags |= STA_FLG_MIMO_DIS_MSK;
+ break;
+ case WLAN_HT_CAP_MIMO_PS_DYNAMIC:
+ sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK;
+ break;
+ case WLAN_HT_CAP_MIMO_PS_DISABLED:
+ break;
+ default:
+ IWL_WARNING("Invalid MIMO PS mode %d", mimo_ps_mode);
+ break;
+ }
+
+ sta_flags |= cpu_to_le32(
+ (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS);
+
+ sta_flags |= cpu_to_le32(
+ (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
+
+ if (iwl_is_fat_tx_allowed(priv, sta_ht_inf))
+ sta_flags |= STA_FLG_FAT_EN_MSK;
+ else
+ sta_flags &= ~STA_FLG_FAT_EN_MSK;
+
+ priv->stations[index].sta.station_flags = sta_flags;
+ done:
+ return;
+}
+#else
+static inline void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
+ struct ieee80211_ht_info *sta_ht_info)
+{
+}
+#endif
+
+/**
+ * iwl_add_station_flags - Add station to tables in driver and device
+ */
+u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap,
+ u8 flags, struct ieee80211_ht_info *ht_info)
+{
+ int i;
+ int index = IWL_INVALID_STATION;
+ struct iwl_station_entry *station;
+ unsigned long flags_spin;
+ DECLARE_MAC_BUF(mac);
+
+ spin_lock_irqsave(&priv->sta_lock, flags_spin);
+ if (is_ap)
+ index = IWL_AP_ID;
+ else if (is_broadcast_ether_addr(addr))
+ index = priv->hw_params.bcast_sta_id;
+ else
+ for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) {
+ if (!compare_ether_addr(priv->stations[i].sta.sta.addr,
+ addr)) {
+ index = i;
+ break;
+ }
+
+ if (!priv->stations[i].used &&
+ index == IWL_INVALID_STATION)
+ index = i;
+ }
+
+
+ /* These two conditions have the same outcome, but keep them separate
+ since they have different meanings */
+ if (unlikely(index == IWL_INVALID_STATION)) {
+ spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+ return index;
+ }
+
+ if (priv->stations[index].used &&
+ !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) {
+ spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+ return index;
+ }
+
+
+ IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr));
+ station = &priv->stations[index];
+ station->used = 1;
+ priv->num_stations++;
+
+ /* Set up the REPLY_ADD_STA command to send to device */
+ memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd));
+ memcpy(station->sta.sta.addr, addr, ETH_ALEN);
+ station->sta.mode = 0;
+ station->sta.sta.sta_id = index;
+ station->sta.station_flags = 0;
+
+ /* BCAST station and IBSS stations do not work in HT mode */
+ if (index != priv->hw_params.bcast_sta_id &&
+ priv->iw_mode != IEEE80211_IF_TYPE_IBSS)
+ iwl_set_ht_add_station(priv, index, ht_info);
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+
+ /* Add station to device's station table */
+ iwl_send_add_sta(priv, &station->sta, flags);
+ return index;
+
+}
+EXPORT_SYMBOL(iwl_add_station_flags);
+
+
+static int iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
+{
+ unsigned long flags;
+ u8 sta_id;
+ DECLARE_MAC_BUF(mac);
+
+ sta_id = iwl_find_station(priv, addr);
+ if (sta_id != IWL_INVALID_STATION) {
+ IWL_DEBUG_ASSOC("Removed STA from Ucode: %s\n",
+ print_mac(mac, addr));
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE;
+ memset(&priv->stations[sta_id], 0,
+ sizeof(struct iwl_station_entry));
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int iwl_remove_sta_callback(struct iwl_priv *priv,
+ struct iwl_cmd *cmd, struct sk_buff *skb)
+{
+ struct iwl_rx_packet *res = NULL;
+ const char *addr = cmd->cmd.rm_sta.addr;
+
+ if (!skb) {
+ IWL_ERROR("Error: Response NULL in REPLY_REMOVE_STA.\n");
+ return 1;
+ }
+
+ res = (struct iwl_rx_packet *)skb->data;
+ if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERROR("Bad return from REPLY_REMOVE_STA (0x%08X)\n",
+ res->hdr.flags);
+ return 1;
+ }
+
+ switch (res->u.rem_sta.status) {
+ case REM_STA_SUCCESS_MSK:
+ iwl_sta_ucode_deactivate(priv, addr);
+ break;
+ default:
+ break;
+ }
+
+ /* We didn't cache the SKB; let the caller free it */
+ return 1;
+}
+
+static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
+ u8 flags)
+{
+ struct iwl_rx_packet *res = NULL;
+ int ret;
+
+ struct iwl_rem_sta_cmd rm_sta_cmd;
+
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_REMOVE_STA,
+ .len = sizeof(struct iwl_rem_sta_cmd),
+ .meta.flags = flags,
+ .data = &rm_sta_cmd,
+ };
+
+ memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd));
+ rm_sta_cmd.num_sta = 1;
+ memcpy(&rm_sta_cmd.addr, addr , ETH_ALEN);
+
+ if (flags & CMD_ASYNC)
+ cmd.meta.u.callback = iwl_remove_sta_callback;
+ else
+ cmd.meta.flags |= CMD_WANT_SKB;
+ ret = iwl_send_cmd(priv, &cmd);
+
+ if (ret || (flags & CMD_ASYNC))
+ return ret;
+
+ res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERROR("Bad return from REPLY_REMOVE_STA (0x%08X)\n",
+ res->hdr.flags);
+ ret = -EIO;
+ }
+
+ if (!ret) {
+ switch (res->u.rem_sta.status) {
+ case REM_STA_SUCCESS_MSK:
+ iwl_sta_ucode_deactivate(priv, addr);
+ IWL_DEBUG_ASSOC("REPLY_REMOVE_STA PASSED\n");
+ break;
+ default:
+ ret = -EIO;
+ IWL_ERROR("REPLY_REMOVE_STA failed\n");
+ break;
+ }
+ }
+
+ priv->alloc_rxb_skb--;
+ dev_kfree_skb_any(cmd.meta.u.skb);
+
+ return ret;
+}
+/**
+ * iwl_remove_station - Remove driver's knowledge of station.
+ *
+ */
+u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
+{
+ int index = IWL_INVALID_STATION;
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
+ if (is_ap)
+ index = IWL_AP_ID;
+ else if (is_broadcast_ether_addr(addr))
+ index = priv->hw_params.bcast_sta_id;
+ else
+ for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++)
+ if (priv->stations[i].used &&
+ !compare_ether_addr(priv->stations[i].sta.sta.addr,
+ addr)) {
+ index = i;
+ break;
+ }
+
+ if (unlikely(index == IWL_INVALID_STATION))
+ goto out;
+
+ if (priv->stations[index].used) {
+ priv->stations[index].used = 0;
+ priv->num_stations--;
+ }
+
+ BUG_ON(priv->num_stations < 0);
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ iwl_send_remove_station(priv, addr, CMD_ASYNC);
+ return index;
+out:
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL(iwl_remove_station);
int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
{
int i;
@@ -91,6 +479,7 @@
else
return 0;
}
+EXPORT_SYMBOL(iwl_send_static_wepkey_cmd);
int iwl_remove_default_wep_key(struct iwl_priv *priv,
struct ieee80211_key_conf *keyconf)
@@ -111,6 +500,7 @@
return ret;
}
+EXPORT_SYMBOL(iwl_remove_default_wep_key);
int iwl_set_default_wep_key(struct iwl_priv *priv,
struct ieee80211_key_conf *keyconf)
@@ -119,7 +509,7 @@
unsigned long flags;
keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
- keyconf->hw_key_idx = keyconf->keyidx;
+ keyconf->hw_key_idx = HW_KEY_DEFAULT;
priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP;
spin_lock_irqsave(&priv->sta_lock, flags);
@@ -138,6 +528,7 @@
return ret;
}
+EXPORT_SYMBOL(iwl_set_default_wep_key);
static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
struct ieee80211_key_conf *keyconf,
@@ -148,7 +539,6 @@
int ret;
keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;
- keyconf->hw_key_idx = keyconf->keyidx;
key_flags |= (STA_KEY_FLG_WEP | STA_KEY_FLG_MAP_KEY_MSK);
key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
@@ -172,15 +562,18 @@
memcpy(&priv->stations[sta_id].sta.key.key[3],
keyconf->key, keyconf->keylen);
- priv->stations[sta_id].sta.key.key_offset =
+ if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
+ == STA_KEY_FLG_NO_ENC)
+ priv->stations[sta_id].sta.key.key_offset =
iwl_get_free_ucode_key_index(priv);
- priv->stations[sta_id].sta.key.key_flags = key_flags;
+ /* else, we are overriding an existing key => no need to allocated room
+ * in uCode. */
+ priv->stations[sta_id].sta.key.key_flags = key_flags;
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
- ret = iwl4965_send_add_station(priv,
- &priv->stations[sta_id].sta, CMD_ASYNC);
+ ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
spin_unlock_irqrestore(&priv->sta_lock, flags);
@@ -202,7 +595,6 @@
key_flags |= STA_KEY_MULTICAST_MSK;
keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- keyconf->hw_key_idx = keyconf->keyidx;
spin_lock_irqsave(&priv->sta_lock, flags);
priv->stations[sta_id].keyinfo.alg = keyconf->alg;
@@ -214,8 +606,13 @@
memcpy(priv->stations[sta_id].sta.key.key, keyconf->key,
keyconf->keylen);
- priv->stations[sta_id].sta.key.key_offset =
- iwl_get_free_ucode_key_index(priv);
+ if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
+ == STA_KEY_FLG_NO_ENC)
+ priv->stations[sta_id].sta.key.key_offset =
+ iwl_get_free_ucode_key_index(priv);
+ /* else, we are overriding an existing key => no need to allocated room
+ * in uCode. */
+
priv->stations[sta_id].sta.key.key_flags = key_flags;
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
@@ -223,8 +620,7 @@
spin_unlock_irqrestore(&priv->sta_lock, flags);
IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
- return iwl4965_send_add_station(priv,
- &priv->stations[sta_id].sta, CMD_ASYNC);
+ return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
}
static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
@@ -236,15 +632,18 @@
keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
- keyconf->hw_key_idx = keyconf->keyidx;
spin_lock_irqsave(&priv->sta_lock, flags);
priv->stations[sta_id].keyinfo.alg = keyconf->alg;
- priv->stations[sta_id].keyinfo.conf = keyconf;
priv->stations[sta_id].keyinfo.keylen = 16;
- priv->stations[sta_id].sta.key.key_offset =
+
+ if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
+ == STA_KEY_FLG_NO_ENC)
+ priv->stations[sta_id].sta.key.key_offset =
iwl_get_free_ucode_key_index(priv);
+ /* else, we are overriding an existing key => no need to allocated room
+ * in uCode. */
/* This copy is acutally not needed: we get the key with each TX */
memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16);
@@ -256,54 +655,78 @@
return ret;
}
-int iwl_remove_dynamic_key(struct iwl_priv *priv, u8 sta_id)
+int iwl_remove_dynamic_key(struct iwl_priv *priv,
+ struct ieee80211_key_conf *keyconf,
+ u8 sta_id)
{
unsigned long flags;
+ int ret = 0;
+ u16 key_flags;
+ u8 keyidx;
- priv->key_mapping_key = 0;
+ priv->key_mapping_key--;
spin_lock_irqsave(&priv->sta_lock, flags);
+ key_flags = le16_to_cpu(priv->stations[sta_id].sta.key.key_flags);
+ keyidx = (key_flags >> STA_KEY_FLG_KEYID_POS) & 0x3;
+
+ if (keyconf->keyidx != keyidx) {
+ /* We need to remove a key with index different that the one
+ * in the uCode. This means that the key we need to remove has
+ * been replaced by another one with different index.
+ * Don't do anything and return ok
+ */
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return 0;
+ }
+
if (!test_and_clear_bit(priv->stations[sta_id].sta.key.key_offset,
&priv->ucode_key_table))
IWL_ERROR("index %d not used in uCode key table.\n",
priv->stations[sta_id].sta.key.key_offset);
memset(&priv->stations[sta_id].keyinfo, 0,
- sizeof(struct iwl4965_hw_key));
+ sizeof(struct iwl_hw_key));
memset(&priv->stations[sta_id].sta.key, 0,
sizeof(struct iwl4965_keyinfo));
- priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
+ priv->stations[sta_id].sta.key.key_flags =
+ STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID;
+ priv->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET;
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
- spin_unlock_irqrestore(&priv->sta_lock, flags);
IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n");
- return iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0);
+ ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return ret;
}
+EXPORT_SYMBOL(iwl_remove_dynamic_key);
int iwl_set_dynamic_key(struct iwl_priv *priv,
- struct ieee80211_key_conf *key, u8 sta_id)
+ struct ieee80211_key_conf *keyconf, u8 sta_id)
{
int ret;
- priv->key_mapping_key = 1;
+ priv->key_mapping_key++;
+ keyconf->hw_key_idx = HW_KEY_DYNAMIC;
- switch (key->alg) {
+ switch (keyconf->alg) {
case ALG_CCMP:
- ret = iwl_set_ccmp_dynamic_key_info(priv, key, sta_id);
+ ret = iwl_set_ccmp_dynamic_key_info(priv, keyconf, sta_id);
break;
case ALG_TKIP:
- ret = iwl_set_tkip_dynamic_key_info(priv, key, sta_id);
+ ret = iwl_set_tkip_dynamic_key_info(priv, keyconf, sta_id);
break;
case ALG_WEP:
- ret = iwl_set_wep_dynamic_key_info(priv, key, sta_id);
+ ret = iwl_set_wep_dynamic_key_info(priv, keyconf, sta_id);
break;
default:
- IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, key->alg);
+ IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, keyconf->alg);
ret = -EINVAL;
}
return ret;
}
+EXPORT_SYMBOL(iwl_set_dynamic_key);
#ifdef CONFIG_IWLWIFI_DEBUG
static void iwl_dump_lq_cmd(struct iwl_priv *priv,
@@ -353,3 +776,168 @@
}
EXPORT_SYMBOL(iwl_send_lq_cmd);
+/**
+ * iwl_sta_init_lq - Initialize a station's hardware rate table
+ *
+ * The uCode's station table contains a table of fallback rates
+ * for automatic fallback during transmission.
+ *
+ * NOTE: This sets up a default set of values. These will be replaced later
+ * if the driver's iwl-4965-rs rate scaling algorithm is used, instead of
+ * rc80211_simple.
+ *
+ * NOTE: Run REPLY_ADD_STA command to set up station table entry, before
+ * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD,
+ * which requires station table entry to exist).
+ */
+static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap)
+{
+ int i, r;
+ struct iwl_link_quality_cmd link_cmd = {
+ .reserved1 = 0,
+ };
+ u16 rate_flags;
+
+ /* Set up the rate scaling to start at selected rate, fall back
+ * all the way down to 1M in IEEE order, and then spin on 1M */
+ if (is_ap)
+ r = IWL_RATE_54M_INDEX;
+ else if (priv->band == IEEE80211_BAND_5GHZ)
+ r = IWL_RATE_6M_INDEX;
+ else
+ r = IWL_RATE_1M_INDEX;
+
+ for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
+ rate_flags = 0;
+ if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
+ rate_flags |= RATE_MCS_CCK_MSK;
+
+ /* Use Tx antenna B only */
+ rate_flags |= RATE_MCS_ANT_B_MSK; /*FIXME:RS*/
+
+ link_cmd.rs_table[i].rate_n_flags =
+ iwl4965_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
+ r = iwl4965_get_prev_ieee_rate(r);
+ }
+
+ link_cmd.general_params.single_stream_ant_msk = 2;
+ link_cmd.general_params.dual_stream_ant_msk = 3;
+ link_cmd.agg_params.agg_dis_start_th = 3;
+ link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000);
+
+ /* Update the rate scaling for control frame Tx to AP */
+ link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id;
+
+ iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD,
+ sizeof(link_cmd), &link_cmd, NULL);
+}
+/**
+ * iwl_rxon_add_station - add station into station table.
+ *
+ * there is only one AP station with id= IWL_AP_ID
+ * NOTE: mutex must be held before calling this fnction
+ */
+int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
+{
+ u8 sta_id;
+
+ /* Add station to device's station table */
+#ifdef CONFIG_IWL4965_HT
+ struct ieee80211_conf *conf = &priv->hw->conf;
+ struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf;
+
+ if ((is_ap) &&
+ (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) &&
+ (priv->iw_mode == IEEE80211_IF_TYPE_STA))
+ sta_id = iwl_add_station_flags(priv, addr, is_ap,
+ 0, cur_ht_config);
+ else
+#endif /* CONFIG_IWL4965_HT */
+ sta_id = iwl_add_station_flags(priv, addr, is_ap,
+ 0, NULL);
+
+ /* Set up default rate scaling table in device's station table */
+ iwl_sta_init_lq(priv, addr, is_ap);
+
+ return sta_id;
+}
+EXPORT_SYMBOL(iwl_rxon_add_station);
+
+
+/**
+ * iwl_get_sta_id - Find station's index within station table
+ *
+ * If new IBSS station, create new entry in station table
+ */
+int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
+{
+ int sta_id;
+ u16 fc = le16_to_cpu(hdr->frame_control);
+ DECLARE_MAC_BUF(mac);
+
+ /* If this frame is broadcast or management, use broadcast station id */
+ if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
+ is_multicast_ether_addr(hdr->addr1))
+ return priv->hw_params.bcast_sta_id;
+
+ switch (priv->iw_mode) {
+
+ /* If we are a client station in a BSS network, use the special
+ * AP station entry (that's the only station we communicate with) */
+ case IEEE80211_IF_TYPE_STA:
+ return IWL_AP_ID;
+
+ /* If we are an AP, then find the station, or use BCAST */
+ case IEEE80211_IF_TYPE_AP:
+ sta_id = iwl_find_station(priv, hdr->addr1);
+ if (sta_id != IWL_INVALID_STATION)
+ return sta_id;
+ return priv->hw_params.bcast_sta_id;
+
+ /* If this frame is going out to an IBSS network, find the station,
+ * or create a new station table entry */
+ case IEEE80211_IF_TYPE_IBSS:
+ sta_id = iwl_find_station(priv, hdr->addr1);
+ if (sta_id != IWL_INVALID_STATION)
+ return sta_id;
+
+ /* Create new station table entry */
+ sta_id = iwl_add_station_flags(priv, hdr->addr1,
+ 0, CMD_ASYNC, NULL);
+
+ if (sta_id != IWL_INVALID_STATION)
+ return sta_id;
+
+ IWL_DEBUG_DROP("Station %s not in station map. "
+ "Defaulting to broadcast...\n",
+ print_mac(mac, hdr->addr1));
+ iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
+ return priv->hw_params.bcast_sta_id;
+
+ default:
+ IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode);
+ return priv->hw_params.bcast_sta_id;
+ }
+}
+EXPORT_SYMBOL(iwl_get_sta_id);
+
+
+/**
+ * iwl_sta_modify_enable_tid_tx - Enable Tx for this TID in station table
+ */
+void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid)
+{
+ unsigned long flags;
+
+ /* Remove "disable" flag, to enable Tx for this TID */
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX;
+ priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid));
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+}
+EXPORT_SYMBOL(iwl_sta_modify_enable_tid_tx);
+
+
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h
index 44f272e..3d55716 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.h
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.h
@@ -29,13 +29,8 @@
#ifndef __iwl_sta_h__
#define __iwl_sta_h__
-#include <net/mac80211.h>
-
-#include "iwl-eeprom.h"
-#include "iwl-core.h"
-#include "iwl-4965.h"
-#include "iwl-io.h"
-#include "iwl-helpers.h"
+#define HW_KEY_DYNAMIC 0
+#define HW_KEY_DEFAULT 1
int iwl_get_free_ucode_key_index(struct iwl_priv *priv);
int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty);
@@ -43,7 +38,12 @@
struct ieee80211_key_conf *key);
int iwl_set_default_wep_key(struct iwl_priv *priv,
struct ieee80211_key_conf *key);
-int iwl_remove_dynamic_key(struct iwl_priv *priv, u8 sta_id);
int iwl_set_dynamic_key(struct iwl_priv *priv,
struct ieee80211_key_conf *key, u8 sta_id);
+int iwl_remove_dynamic_key(struct iwl_priv *priv,
+ struct ieee80211_key_conf *key, u8 sta_id);
+int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap);
+u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap);
+int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
+void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid);
#endif /* __iwl_sta_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
new file mode 100644
index 0000000..cfe6f4b
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -0,0 +1,1393 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/etherdevice.h>
+#include <net/mac80211.h>
+#include "iwl-eeprom.h"
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-sta.h"
+#include "iwl-io.h"
+#include "iwl-helpers.h"
+
+#ifdef CONFIG_IWL4965_HT
+
+static const u16 default_tid_to_tx_fifo[] = {
+ IWL_TX_FIFO_AC1,
+ IWL_TX_FIFO_AC0,
+ IWL_TX_FIFO_AC0,
+ IWL_TX_FIFO_AC1,
+ IWL_TX_FIFO_AC2,
+ IWL_TX_FIFO_AC2,
+ IWL_TX_FIFO_AC3,
+ IWL_TX_FIFO_AC3,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_AC3
+};
+
+#endif /*CONFIG_IWL4965_HT */
+
+
+
+/**
+ * iwl_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
+ *
+ * Does NOT advance any TFD circular buffer read/write indexes
+ * Does NOT free the TFD itself (which is within circular buffer)
+ */
+int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+ struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0];
+ struct iwl_tfd_frame *bd = &bd_tmp[txq->q.read_ptr];
+ struct pci_dev *dev = priv->pci_dev;
+ int i;
+ int counter = 0;
+ int index, is_odd;
+
+ /* Host command buffers stay mapped in memory, nothing to clean */
+ if (txq->q.id == IWL_CMD_QUEUE_NUM)
+ return 0;
+
+ /* Sanity check on number of chunks */
+ counter = IWL_GET_BITS(*bd, num_tbs);
+ if (counter > MAX_NUM_OF_TBS) {
+ IWL_ERROR("Too many chunks: %i\n", counter);
+ /* @todo issue fatal error, it is quite serious situation */
+ return 0;
+ }
+
+ /* Unmap chunks, if any.
+ * TFD info for odd chunks is different format than for even chunks. */
+ for (i = 0; i < counter; i++) {
+ index = i / 2;
+ is_odd = i & 0x1;
+
+ if (is_odd)
+ pci_unmap_single(
+ dev,
+ IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) |
+ (IWL_GET_BITS(bd->pa[index],
+ tb2_addr_hi20) << 16),
+ IWL_GET_BITS(bd->pa[index], tb2_len),
+ PCI_DMA_TODEVICE);
+
+ else if (i > 0)
+ pci_unmap_single(dev,
+ le32_to_cpu(bd->pa[index].tb1_addr),
+ IWL_GET_BITS(bd->pa[index], tb1_len),
+ PCI_DMA_TODEVICE);
+
+ /* Free SKB, if any, for this chunk */
+ if (txq->txb[txq->q.read_ptr].skb[i]) {
+ struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[i];
+
+ dev_kfree_skb(skb);
+ txq->txb[txq->q.read_ptr].skb[i] = NULL;
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL(iwl_hw_txq_free_tfd);
+
+
+int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,
+ dma_addr_t addr, u16 len)
+{
+ int index, is_odd;
+ struct iwl_tfd_frame *tfd = ptr;
+ u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs);
+
+ /* Each TFD can point to a maximum 20 Tx buffers */
+ if ((num_tbs >= MAX_NUM_OF_TBS) || (num_tbs < 0)) {
+ IWL_ERROR("Error can not send more than %d chunks\n",
+ MAX_NUM_OF_TBS);
+ return -EINVAL;
+ }
+
+ index = num_tbs / 2;
+ is_odd = num_tbs & 0x1;
+
+ if (!is_odd) {
+ tfd->pa[index].tb1_addr = cpu_to_le32(addr);
+ IWL_SET_BITS(tfd->pa[index], tb1_addr_hi,
+ iwl_get_dma_hi_address(addr));
+ IWL_SET_BITS(tfd->pa[index], tb1_len, len);
+ } else {
+ IWL_SET_BITS(tfd->pa[index], tb2_addr_lo16,
+ (u32) (addr & 0xffff));
+ IWL_SET_BITS(tfd->pa[index], tb2_addr_hi20, addr >> 16);
+ IWL_SET_BITS(tfd->pa[index], tb2_len, len);
+ }
+
+ IWL_SET_BITS(*tfd, num_tbs, num_tbs + 1);
+
+ return 0;
+}
+EXPORT_SYMBOL(iwl_hw_txq_attach_buf_to_tfd);
+
+/**
+ * iwl_txq_update_write_ptr - Send new write index to hardware
+ */
+int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+ u32 reg = 0;
+ int ret = 0;
+ int txq_id = txq->q.id;
+
+ if (txq->need_update == 0)
+ return ret;
+
+ /* if we're trying to save power */
+ if (test_bit(STATUS_POWER_PMI, &priv->status)) {
+ /* wake up nic if it's powered down ...
+ * uCode will wake up, and interrupt us again, so next
+ * time we'll skip this part. */
+ reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
+
+ if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+ IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg);
+ iwl_set_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ return ret;
+ }
+
+ /* restore this queue's parameters in nic hardware. */
+ ret = iwl_grab_nic_access(priv);
+ if (ret)
+ return ret;
+ iwl_write_direct32(priv, HBUS_TARG_WRPTR,
+ txq->q.write_ptr | (txq_id << 8));
+ iwl_release_nic_access(priv);
+
+ /* else not in power-save mode, uCode will never sleep when we're
+ * trying to tx (during RFKILL, we're not trying to tx). */
+ } else
+ iwl_write32(priv, HBUS_TARG_WRPTR,
+ txq->q.write_ptr | (txq_id << 8));
+
+ txq->need_update = 0;
+
+ return ret;
+}
+EXPORT_SYMBOL(iwl_txq_update_write_ptr);
+
+
+/**
+ * iwl_tx_queue_free - Deallocate DMA queue.
+ * @txq: Transmit queue to deallocate.
+ *
+ * Empty queue by removing and destroying all BD's.
+ * Free all buffers.
+ * 0-fill, but do not free "txq" descriptor structure.
+ */
+static void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+ struct iwl_queue *q = &txq->q;
+ struct pci_dev *dev = priv->pci_dev;
+ int len;
+
+ if (q->n_bd == 0)
+ return;
+
+ /* first, empty all BD's */
+ for (; q->write_ptr != q->read_ptr;
+ q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd))
+ iwl_hw_txq_free_tfd(priv, txq);
+
+ len = sizeof(struct iwl_cmd) * q->n_window;
+ if (q->id == IWL_CMD_QUEUE_NUM)
+ len += IWL_MAX_SCAN_SIZE;
+
+ /* De-alloc array of command/tx buffers */
+ pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
+
+ /* De-alloc circular buffer of TFDs */
+ if (txq->q.n_bd)
+ pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) *
+ txq->q.n_bd, txq->bd, txq->q.dma_addr);
+
+ /* De-alloc array of per-TFD driver data */
+ kfree(txq->txb);
+ txq->txb = NULL;
+
+ /* 0-fill queue descriptor structure */
+ memset(txq, 0, sizeof(*txq));
+}
+
+/*************** DMA-QUEUE-GENERAL-FUNCTIONS *****
+ * DMA services
+ *
+ * Theory of operation
+ *
+ * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer
+ * of buffer descriptors, each of which points to one or more data buffers for
+ * the device to read from or fill. Driver and device exchange status of each
+ * queue via "read" and "write" pointers. Driver keeps minimum of 2 empty
+ * entries in each circular buffer, to protect against confusing empty and full
+ * queue states.
+ *
+ * The device reads or writes the data in the queues via the device's several
+ * DMA/FIFO channels. Each queue is mapped to a single DMA channel.
+ *
+ * For Tx queue, there are low mark and high mark limits. If, after queuing
+ * the packet for Tx, free space become < low mark, Tx queue stopped. When
+ * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
+ * Tx queue resumed.
+ *
+ * See more detailed info in iwl-4965-hw.h.
+ ***************************************************/
+
+int iwl_queue_space(const struct iwl_queue *q)
+{
+ int s = q->read_ptr - q->write_ptr;
+
+ if (q->read_ptr > q->write_ptr)
+ s -= q->n_bd;
+
+ if (s <= 0)
+ s += q->n_window;
+ /* keep some reserve to not confuse empty and full situations */
+ s -= 2;
+ if (s < 0)
+ s = 0;
+ return s;
+}
+EXPORT_SYMBOL(iwl_queue_space);
+
+
+/**
+ * iwl_queue_init - Initialize queue's high/low-water and read/write indexes
+ */
+static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
+ int count, int slots_num, u32 id)
+{
+ q->n_bd = count;
+ q->n_window = slots_num;
+ q->id = id;
+
+ /* count must be power-of-two size, otherwise iwl_queue_inc_wrap
+ * and iwl_queue_dec_wrap are broken. */
+ BUG_ON(!is_power_of_2(count));
+
+ /* slots_num must be power-of-two size, otherwise
+ * get_cmd_index is broken. */
+ BUG_ON(!is_power_of_2(slots_num));
+
+ q->low_mark = q->n_window / 4;
+ if (q->low_mark < 4)
+ q->low_mark = 4;
+
+ q->high_mark = q->n_window / 8;
+ if (q->high_mark < 2)
+ q->high_mark = 2;
+
+ q->write_ptr = q->read_ptr = 0;
+
+ return 0;
+}
+
+/**
+ * iwl_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue
+ */
+static int iwl_tx_queue_alloc(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq, u32 id)
+{
+ struct pci_dev *dev = priv->pci_dev;
+
+ /* Driver private data, only for Tx (not command) queues,
+ * not shared with device. */
+ if (id != IWL_CMD_QUEUE_NUM) {
+ txq->txb = kmalloc(sizeof(txq->txb[0]) *
+ TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
+ if (!txq->txb) {
+ IWL_ERROR("kmalloc for auxiliary BD "
+ "structures failed\n");
+ goto error;
+ }
+ } else
+ txq->txb = NULL;
+
+ /* Circular buffer of transmit frame descriptors (TFDs),
+ * shared with device */
+ txq->bd = pci_alloc_consistent(dev,
+ sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX,
+ &txq->q.dma_addr);
+
+ if (!txq->bd) {
+ IWL_ERROR("pci_alloc_consistent(%zd) failed\n",
+ sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX);
+ goto error;
+ }
+ txq->q.id = id;
+
+ return 0;
+
+ error:
+ kfree(txq->txb);
+ txq->txb = NULL;
+
+ return -ENOMEM;
+}
+
+/*
+ * Tell nic where to find circular buffer of Tx Frame Descriptors for
+ * given Tx queue, and enable the DMA channel used for that queue.
+ *
+ * 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA
+ * channels supported in hardware.
+ */
+static int iwl_hw_tx_queue_init(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq)
+{
+ int rc;
+ unsigned long flags;
+ int txq_id = txq->q.id;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_nic_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ /* Circular buffer (TFD queue in DRAM) physical base address */
+ iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
+ txq->q.dma_addr >> 8);
+
+ /* Enable DMA channel, using same id as for TFD queue */
+ iwl_write_direct32(
+ priv, FH_TCSR_CHNL_TX_CONFIG_REG(txq_id),
+ FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+ FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL);
+ iwl_release_nic_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+/**
+ * iwl_tx_queue_init - Allocate and initialize one tx/cmd queue
+ */
+static int iwl_tx_queue_init(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq,
+ int slots_num, u32 txq_id)
+{
+ struct pci_dev *dev = priv->pci_dev;
+ int len;
+ int rc = 0;
+
+ /*
+ * Alloc buffer array for commands (Tx or other types of commands).
+ * For the command queue (#4), allocate command space + one big
+ * command for scan, since scan command is very huge; the system will
+ * not have two scans at the same time, so only one is needed.
+ * For normal Tx queues (all other queues), no super-size command
+ * space is needed.
+ */
+ len = sizeof(struct iwl_cmd) * slots_num;
+ if (txq_id == IWL_CMD_QUEUE_NUM)
+ len += IWL_MAX_SCAN_SIZE;
+ txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd);
+ if (!txq->cmd)
+ return -ENOMEM;
+
+ /* Alloc driver data array and TFD circular buffer */
+ rc = iwl_tx_queue_alloc(priv, txq, txq_id);
+ if (rc) {
+ pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
+
+ return -ENOMEM;
+ }
+ txq->need_update = 0;
+
+ /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
+ * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
+ BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
+
+ /* Initialize queue's high/low-water marks, and head/tail indexes */
+ iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
+
+ /* Tell device where to find queue */
+ iwl_hw_tx_queue_init(priv, txq);
+
+ return 0;
+}
+/**
+ * iwl_hw_txq_ctx_free - Free TXQ Context
+ *
+ * Destroy all TX DMA queues and structures
+ */
+void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
+{
+ int txq_id;
+
+ /* Tx queues */
+ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
+ iwl_tx_queue_free(priv, &priv->txq[txq_id]);
+
+ /* Keep-warm buffer */
+ iwl_kw_free(priv);
+}
+EXPORT_SYMBOL(iwl_hw_txq_ctx_free);
+
+
+/**
+ * iwl_txq_ctx_reset - Reset TX queue context
+ * Destroys all DMA structures and initialise them again
+ *
+ * @param priv
+ * @return error code
+ */
+int iwl_txq_ctx_reset(struct iwl_priv *priv)
+{
+ int ret = 0;
+ int txq_id, slots_num;
+ unsigned long flags;
+
+ iwl_kw_free(priv);
+
+ /* Free all tx/cmd queues and keep-warm buffer */
+ iwl_hw_txq_ctx_free(priv);
+
+ /* Alloc keep-warm buffer */
+ ret = iwl_kw_alloc(priv);
+ if (ret) {
+ IWL_ERROR("Keep Warm allocation failed");
+ goto error_kw;
+ }
+ spin_lock_irqsave(&priv->lock, flags);
+ ret = iwl_grab_nic_access(priv);
+ if (unlikely(ret)) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ goto error_reset;
+ }
+
+ /* Turn off all Tx DMA fifos */
+ priv->cfg->ops->lib->txq_set_sched(priv, 0);
+
+ iwl_release_nic_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+
+ /* Tell nic where to find the keep-warm buffer */
+ ret = iwl_kw_init(priv);
+ if (ret) {
+ IWL_ERROR("kw_init failed\n");
+ goto error_reset;
+ }
+
+ /* Alloc and init all Tx queues, including the command queue (#4) */
+ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
+ slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
+ TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+ ret = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
+ txq_id);
+ if (ret) {
+ IWL_ERROR("Tx %d queue init failed\n", txq_id);
+ goto error;
+ }
+ }
+
+ return ret;
+
+ error:
+ iwl_hw_txq_ctx_free(priv);
+ error_reset:
+ iwl_kw_free(priv);
+ error_kw:
+ return ret;
+}
+/**
+ * iwl_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory
+ */
+void iwl_txq_ctx_stop(struct iwl_priv *priv)
+{
+
+ int txq_id;
+ unsigned long flags;
+
+
+ /* Turn off all Tx DMA fifos */
+ spin_lock_irqsave(&priv->lock, flags);
+ if (iwl_grab_nic_access(priv)) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return;
+ }
+
+ priv->cfg->ops->lib->txq_set_sched(priv, 0);
+
+ /* Stop each Tx DMA channel, and wait for it to be idle */
+ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
+ iwl_write_direct32(priv,
+ FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), 0x0);
+ iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG,
+ FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE
+ (txq_id), 200);
+ }
+ iwl_release_nic_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* Deallocate memory for all Tx queues */
+ iwl_hw_txq_ctx_free(priv);
+}
+EXPORT_SYMBOL(iwl_txq_ctx_stop);
+
+/*
+ * handle build REPLY_TX command notification.
+ */
+static void iwl_tx_cmd_build_basic(struct iwl_priv *priv,
+ struct iwl_tx_cmd *tx_cmd,
+ struct ieee80211_tx_info *info,
+ struct ieee80211_hdr *hdr,
+ int is_unicast, u8 std_id)
+{
+ u16 fc = le16_to_cpu(hdr->frame_control);
+ __le32 tx_flags = tx_cmd->tx_flags;
+
+ tx_cmd->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
+ tx_flags |= TX_CMD_FLG_ACK_MSK;
+ if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)
+ tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+ if (ieee80211_is_probe_response(fc) &&
+ !(le16_to_cpu(hdr->seq_ctrl) & 0xf))
+ tx_flags |= TX_CMD_FLG_TSF_MSK;
+ } else {
+ tx_flags &= (~TX_CMD_FLG_ACK_MSK);
+ tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+ }
+
+ if (ieee80211_is_back_request(fc))
+ tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK;
+
+
+ tx_cmd->sta_id = std_id;
+ if (ieee80211_get_morefrag(hdr))
+ tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
+
+ if (ieee80211_is_qos_data(fc)) {
+ u8 *qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc));
+ tx_cmd->tid_tspec = qc[0] & 0xf;
+ tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
+ } else {
+ tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+ }
+
+ if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
+ tx_flags |= TX_CMD_FLG_RTS_MSK;
+ tx_flags &= ~TX_CMD_FLG_CTS_MSK;
+ } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
+ tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+ tx_flags |= TX_CMD_FLG_CTS_MSK;
+ }
+
+ if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
+ tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
+
+ tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
+ if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
+ if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ ||
+ (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ)
+ tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(3);
+ else
+ tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(2);
+ } else {
+ tx_cmd->timeout.pm_frame_timeout = 0;
+ }
+
+ tx_cmd->driver_txop = 0;
+ tx_cmd->tx_flags = tx_flags;
+ tx_cmd->next_frame_len = 0;
+}
+
+#define RTS_HCCA_RETRY_LIMIT 3
+#define RTS_DFAULT_RETRY_LIMIT 60
+
+static void iwl_tx_cmd_build_rate(struct iwl_priv *priv,
+ struct iwl_tx_cmd *tx_cmd,
+ struct ieee80211_tx_info *info,
+ u16 fc, int sta_id,
+ int is_hcca)
+{
+ u8 rts_retry_limit = 0;
+ u8 data_retry_limit = 0;
+ u8 rate_plcp;
+ u16 rate_flags = 0;
+ int rate_idx;
+
+ rate_idx = min(ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xffff,
+ IWL_RATE_COUNT - 1);
+
+ rate_plcp = iwl_rates[rate_idx].plcp;
+
+ rts_retry_limit = (is_hcca) ?
+ RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT;
+
+ if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
+ rate_flags |= RATE_MCS_CCK_MSK;
+
+
+ if (ieee80211_is_probe_response(fc)) {
+ data_retry_limit = 3;
+ if (data_retry_limit < rts_retry_limit)
+ rts_retry_limit = data_retry_limit;
+ } else
+ data_retry_limit = IWL_DEFAULT_TX_RETRY;
+
+ if (priv->data_retry_limit != -1)
+ data_retry_limit = priv->data_retry_limit;
+
+
+ if (ieee80211_is_data(fc)) {
+ tx_cmd->initial_rate_index = 0;
+ tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
+ } else {
+ switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_AUTH:
+ case IEEE80211_STYPE_DEAUTH:
+ case IEEE80211_STYPE_ASSOC_REQ:
+ case IEEE80211_STYPE_REASSOC_REQ:
+ if (tx_cmd->tx_flags & TX_CMD_FLG_RTS_MSK) {
+ tx_cmd->tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+ tx_cmd->tx_flags |= TX_CMD_FLG_CTS_MSK;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Alternate between antenna A and B for successive frames */
+ if (priv->use_ant_b_for_management_frame) {
+ priv->use_ant_b_for_management_frame = 0;
+ rate_flags |= RATE_MCS_ANT_B_MSK;
+ } else {
+ priv->use_ant_b_for_management_frame = 1;
+ rate_flags |= RATE_MCS_ANT_A_MSK;
+ }
+ }
+
+ tx_cmd->rts_retry_limit = rts_retry_limit;
+ tx_cmd->data_retry_limit = data_retry_limit;
+ tx_cmd->rate_n_flags = iwl4965_hw_set_rate_n_flags(rate_plcp, rate_flags);
+}
+
+static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
+ struct ieee80211_tx_info *info,
+ struct iwl_tx_cmd *tx_cmd,
+ struct sk_buff *skb_frag,
+ int sta_id)
+{
+ struct ieee80211_key_conf *keyconf = info->control.hw_key;
+
+ switch (keyconf->alg) {
+ case ALG_CCMP:
+ tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
+ memcpy(tx_cmd->key, keyconf->key, keyconf->keylen);
+ if (info->flags & IEEE80211_TX_CTL_AMPDU)
+ tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK;
+ IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n");
+ break;
+
+ case ALG_TKIP:
+ tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
+ ieee80211_get_tkip_key(keyconf, skb_frag,
+ IEEE80211_TKIP_P2_KEY, tx_cmd->key);
+ IWL_DEBUG_TX("tx_cmd with tkip hwcrypto\n");
+ break;
+
+ case ALG_WEP:
+ tx_cmd->sec_ctl |= (TX_CMD_SEC_WEP |
+ (keyconf->keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT);
+
+ if (keyconf->keylen == WEP_KEY_LEN_128)
+ tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
+
+ memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen);
+
+ IWL_DEBUG_TX("Configuring packet for WEP encryption "
+ "with key %d\n", keyconf->keyidx);
+ break;
+
+ default:
+ printk(KERN_ERR "Unknown encode alg %d\n", keyconf->alg);
+ break;
+ }
+}
+
+static void iwl_update_tx_stats(struct iwl_priv *priv, u16 fc, u16 len)
+{
+ /* 0 - mgmt, 1 - cnt, 2 - data */
+ int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2;
+ priv->tx_stats[idx].cnt++;
+ priv->tx_stats[idx].bytes += len;
+}
+
+/*
+ * start REPLY_TX command process
+ */
+int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct iwl_tfd_frame *tfd;
+ u32 *control_flags;
+ int txq_id = skb_get_queue_mapping(skb);
+ struct iwl_tx_queue *txq = NULL;
+ struct iwl_queue *q = NULL;
+ dma_addr_t phys_addr;
+ dma_addr_t txcmd_phys;
+ dma_addr_t scratch_phys;
+ struct iwl_cmd *out_cmd = NULL;
+ struct iwl_tx_cmd *tx_cmd;
+ u16 len, idx, len_org;
+ u16 seq_number = 0;
+ u8 id, hdr_len, unicast;
+ u8 sta_id;
+ u16 fc;
+ u8 wait_write_ptr = 0;
+ u8 tid = 0;
+ u8 *qc = NULL;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (iwl_is_rfkill(priv)) {
+ IWL_DEBUG_DROP("Dropping - RF KILL\n");
+ goto drop_unlock;
+ }
+
+ if (!priv->vif) {
+ IWL_DEBUG_DROP("Dropping - !priv->vif\n");
+ goto drop_unlock;
+ }
+
+ if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) ==
+ IWL_INVALID_RATE) {
+ IWL_ERROR("ERROR: No TX rate available.\n");
+ goto drop_unlock;
+ }
+
+ unicast = !is_multicast_ether_addr(hdr->addr1);
+ id = 0;
+
+ fc = le16_to_cpu(hdr->frame_control);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (ieee80211_is_auth(fc))
+ IWL_DEBUG_TX("Sending AUTH frame\n");
+ else if (ieee80211_is_assoc_request(fc))
+ IWL_DEBUG_TX("Sending ASSOC frame\n");
+ else if (ieee80211_is_reassoc_request(fc))
+ IWL_DEBUG_TX("Sending REASSOC frame\n");
+#endif
+
+ /* drop all data frame if we are not associated */
+ if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
+ (!iwl_is_associated(priv) ||
+ ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id) ||
+ !priv->assoc_station_added)) {
+ IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n");
+ goto drop_unlock;
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ hdr_len = ieee80211_get_hdrlen(fc);
+
+ /* Find (or create) index into station table for destination station */
+ sta_id = iwl_get_sta_id(priv, hdr);
+ if (sta_id == IWL_INVALID_STATION) {
+ DECLARE_MAC_BUF(mac);
+
+ IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n",
+ print_mac(mac, hdr->addr1));
+ goto drop;
+ }
+
+ IWL_DEBUG_TX("station Id %d\n", sta_id);
+
+ if (ieee80211_is_qos_data(fc)) {
+ qc = ieee80211_get_qos_ctrl(hdr, hdr_len);
+ tid = qc[0] & 0xf;
+ seq_number = priv->stations[sta_id].tid[tid].seq_number &
+ IEEE80211_SCTL_SEQ;
+ hdr->seq_ctrl = cpu_to_le16(seq_number) |
+ (hdr->seq_ctrl &
+ __constant_cpu_to_le16(IEEE80211_SCTL_FRAG));
+ seq_number += 0x10;
+#ifdef CONFIG_IWL4965_HT
+ /* aggregation is on for this <sta,tid> */
+ if (info->flags & IEEE80211_TX_CTL_AMPDU)
+ txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
+ priv->stations[sta_id].tid[tid].tfds_in_queue++;
+#endif /* CONFIG_IWL4965_HT */
+ }
+
+ /* Descriptor for chosen Tx queue */
+ txq = &priv->txq[txq_id];
+ q = &txq->q;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* Set up first empty TFD within this queue's circular TFD buffer */
+ tfd = &txq->bd[q->write_ptr];
+ memset(tfd, 0, sizeof(*tfd));
+ control_flags = (u32 *) tfd;
+ idx = get_cmd_index(q, q->write_ptr, 0);
+
+ /* Set up driver data for this TFD */
+ memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
+ txq->txb[q->write_ptr].skb[0] = skb;
+
+ /* Set up first empty entry in queue's array of Tx/cmd buffers */
+ out_cmd = &txq->cmd[idx];
+ tx_cmd = &out_cmd->cmd.tx;
+ memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
+ memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd));
+
+ /*
+ * Set up the Tx-command (not MAC!) header.
+ * Store the chosen Tx queue and TFD index within the sequence field;
+ * after Tx, uCode's Tx response will return this value so driver can
+ * locate the frame within the tx queue and do post-tx processing.
+ */
+ out_cmd->hdr.cmd = REPLY_TX;
+ out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
+ INDEX_TO_SEQ(q->write_ptr)));
+
+ /* Copy MAC header from skb into command buffer */
+ memcpy(tx_cmd->hdr, hdr, hdr_len);
+
+ /*
+ * Use the first empty entry in this queue's command buffer array
+ * to contain the Tx command and MAC header concatenated together
+ * (payload data will be in another buffer).
+ * Size of this varies, due to varying MAC header length.
+ * If end is not dword aligned, we'll have 2 extra bytes at the end
+ * of the MAC header (device reads on dword boundaries).
+ * We'll tell device about this padding later.
+ */
+ len = sizeof(struct iwl_tx_cmd) +
+ sizeof(struct iwl_cmd_header) + hdr_len;
+
+ len_org = len;
+ len = (len + 3) & ~3;
+
+ if (len_org != len)
+ len_org = 1;
+ else
+ len_org = 0;
+
+ /* Physical address of this Tx command's header (not MAC header!),
+ * within command buffer array. */
+ txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx +
+ offsetof(struct iwl_cmd, hdr);
+
+ /* Add buffer containing Tx command and MAC(!) header to TFD's
+ * first entry */
+ iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
+
+ if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT))
+ iwl_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id);
+
+ /* Set up TFD's 2nd entry to point directly to remainder of skb,
+ * if any (802.11 null frames have no payload). */
+ len = skb->len - hdr_len;
+ if (len) {
+ phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
+ len, PCI_DMA_TODEVICE);
+ iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len);
+ }
+
+ /* Tell NIC about any 2-byte padding after MAC header */
+ if (len_org)
+ tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
+
+ /* Total # bytes to be transmitted */
+ len = (u16)skb->len;
+ tx_cmd->len = cpu_to_le16(len);
+ /* TODO need this for burst mode later on */
+ iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, unicast, sta_id);
+
+ /* set is_hcca to 0; it probably will never be implemented */
+ iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0);
+
+ iwl_update_tx_stats(priv, fc, len);
+
+ scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
+ offsetof(struct iwl_tx_cmd, scratch);
+ tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
+ tx_cmd->dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys);
+
+ if (!ieee80211_get_morefrag(hdr)) {
+ txq->need_update = 1;
+ if (qc)
+ priv->stations[sta_id].tid[tid].seq_number = seq_number;
+ } else {
+ wait_write_ptr = 1;
+ txq->need_update = 0;
+ }
+
+ iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
+
+ iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
+
+ /* Set up entry for this TFD in Tx byte-count array */
+ priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, len);
+
+ /* Tell device the write index *just past* this latest filled TFD */
+ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
+ ret = iwl_txq_update_write_ptr(priv, txq);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (ret)
+ return ret;
+
+ if ((iwl_queue_space(q) < q->high_mark)
+ && priv->mac80211_registered) {
+ if (wait_write_ptr) {
+ spin_lock_irqsave(&priv->lock, flags);
+ txq->need_update = 1;
+ iwl_txq_update_write_ptr(priv, txq);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+
+ ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb));
+ }
+
+ return 0;
+
+drop_unlock:
+ spin_unlock_irqrestore(&priv->lock, flags);
+drop:
+ return -1;
+}
+EXPORT_SYMBOL(iwl_tx_skb);
+
+/*************** HOST COMMAND QUEUE FUNCTIONS *****/
+
+/**
+ * iwl_enqueue_hcmd - enqueue a uCode command
+ * @priv: device private data point
+ * @cmd: a point to the ucode command structure
+ *
+ * The function returns < 0 values to indicate the operation is
+ * failed. On success, it turns the index (> 0) of command in the
+ * command queue.
+ */
+int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+ struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
+ struct iwl_queue *q = &txq->q;
+ struct iwl_tfd_frame *tfd;
+ u32 *control_flags;
+ struct iwl_cmd *out_cmd;
+ u32 idx;
+ u16 fix_size;
+ dma_addr_t phys_addr;
+ int ret;
+ unsigned long flags;
+
+ cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len);
+ fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
+
+ /* If any of the command structures end up being larger than
+ * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
+ * we will need to increase the size of the TFD entries */
+ BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
+ !(cmd->meta.flags & CMD_SIZE_HUGE));
+
+ if (iwl_is_rfkill(priv)) {
+ IWL_DEBUG_INFO("Not sending command - RF KILL");
+ return -EIO;
+ }
+
+ if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
+ IWL_ERROR("No space for Tx\n");
+ return -ENOSPC;
+ }
+
+ spin_lock_irqsave(&priv->hcmd_lock, flags);
+
+ tfd = &txq->bd[q->write_ptr];
+ memset(tfd, 0, sizeof(*tfd));
+
+ control_flags = (u32 *) tfd;
+
+ idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE);
+ out_cmd = &txq->cmd[idx];
+
+ out_cmd->hdr.cmd = cmd->id;
+ memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta));
+ memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len);
+
+ /* At this point, the out_cmd now has all of the incoming cmd
+ * information */
+
+ out_cmd->hdr.flags = 0;
+ out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
+ INDEX_TO_SEQ(q->write_ptr));
+ if (out_cmd->meta.flags & CMD_SIZE_HUGE)
+ out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME);
+
+ phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx +
+ offsetof(struct iwl_cmd, hdr);
+ iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size);
+
+ IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, "
+ "%d bytes at %d[%d]:%d\n",
+ get_cmd_string(out_cmd->hdr.cmd),
+ out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),
+ fix_size, q->write_ptr, idx, IWL_CMD_QUEUE_NUM);
+
+ txq->need_update = 1;
+
+ /* Set up entry in queue's byte count circular buffer */
+ priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, 0);
+
+ /* Increment and update queue's write index */
+ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
+ ret = iwl_txq_update_write_ptr(priv, txq);
+
+ spin_unlock_irqrestore(&priv->hcmd_lock, flags);
+ return ret ? ret : idx;
+}
+
+int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
+{
+ struct iwl_tx_queue *txq = &priv->txq[txq_id];
+ struct iwl_queue *q = &txq->q;
+ struct iwl_tx_info *tx_info;
+ int nfreed = 0;
+
+ if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) {
+ IWL_ERROR("Read index for DMA queue txq id (%d), index %d, "
+ "is out of range [0-%d] %d %d.\n", txq_id,
+ index, q->n_bd, q->write_ptr, q->read_ptr);
+ return 0;
+ }
+
+ for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index;
+ q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
+
+ tx_info = &txq->txb[txq->q.read_ptr];
+ ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]);
+ tx_info->skb[0] = NULL;
+
+ if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl)
+ priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq);
+
+ iwl_hw_txq_free_tfd(priv, txq);
+ nfreed++;
+ }
+ return nfreed;
+}
+EXPORT_SYMBOL(iwl_tx_queue_reclaim);
+
+
+/**
+ * iwl_hcmd_queue_reclaim - Reclaim TX command queue entries already Tx'd
+ *
+ * When FW advances 'R' index, all entries between old and new 'R' index
+ * need to be reclaimed. As result, some free space forms. If there is
+ * enough free space (> low mark), wake the stack that feeds us.
+ */
+static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
+{
+ struct iwl_tx_queue *txq = &priv->txq[txq_id];
+ struct iwl_queue *q = &txq->q;
+ int nfreed = 0;
+
+ if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) {
+ IWL_ERROR("Read index for DMA queue txq id (%d), index %d, "
+ "is out of range [0-%d] %d %d.\n", txq_id,
+ index, q->n_bd, q->write_ptr, q->read_ptr);
+ return;
+ }
+
+ for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index;
+ q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
+
+ if (nfreed > 1) {
+ IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index,
+ q->write_ptr, q->read_ptr);
+ queue_work(priv->workqueue, &priv->restart);
+ }
+ nfreed++;
+ }
+}
+
+/**
+ * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
+ * @rxb: Rx buffer to reclaim
+ *
+ * If an Rx buffer has an async callback associated with it the callback
+ * will be executed. The attached skb (if present) will only be freed
+ * if the callback returns 1
+ */
+void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+ int txq_id = SEQ_TO_QUEUE(sequence);
+ int index = SEQ_TO_INDEX(sequence);
+ int huge = sequence & SEQ_HUGE_FRAME;
+ int cmd_index;
+ struct iwl_cmd *cmd;
+
+ /* If a Tx command is being handled and it isn't in the actual
+ * command queue then there a command routing bug has been introduced
+ * in the queue management code. */
+ if (txq_id != IWL_CMD_QUEUE_NUM)
+ IWL_ERROR("Error wrong command queue %d command id 0x%X\n",
+ txq_id, pkt->hdr.cmd);
+ BUG_ON(txq_id != IWL_CMD_QUEUE_NUM);
+
+ cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
+ cmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
+
+ /* Input error checking is done when commands are added to queue. */
+ if (cmd->meta.flags & CMD_WANT_SKB) {
+ cmd->meta.source->u.skb = rxb->skb;
+ rxb->skb = NULL;
+ } else if (cmd->meta.u.callback &&
+ !cmd->meta.u.callback(priv, cmd, rxb->skb))
+ rxb->skb = NULL;
+
+ iwl_hcmd_queue_reclaim(priv, txq_id, index);
+
+ if (!(cmd->meta.flags & CMD_ASYNC)) {
+ clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+ wake_up_interruptible(&priv->wait_command_queue);
+ }
+}
+EXPORT_SYMBOL(iwl_tx_cmd_complete);
+
+
+#ifdef CONFIG_IWL4965_HT
+/*
+ * Find first available (lowest unused) Tx Queue, mark it "active".
+ * Called only when finding queue for aggregation.
+ * Should never return anything < 7, because they should already
+ * be in use as EDCA AC (0-3), Command (4), HCCA (5, 6).
+ */
+static int iwl_txq_ctx_activate_free(struct iwl_priv *priv)
+{
+ int txq_id;
+
+ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
+ if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk))
+ return txq_id;
+ return -1;
+}
+
+int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
+{
+ int sta_id;
+ int tx_fifo;
+ int txq_id;
+ int ret;
+ unsigned long flags;
+ struct iwl_tid_data *tid_data;
+ DECLARE_MAC_BUF(mac);
+
+ if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
+ tx_fifo = default_tid_to_tx_fifo[tid];
+ else
+ return -EINVAL;
+
+ IWL_WARNING("%s on ra = %s tid = %d\n",
+ __func__, print_mac(mac, ra), tid);
+
+ sta_id = iwl_find_station(priv, ra);
+ if (sta_id == IWL_INVALID_STATION)
+ return -ENXIO;
+
+ if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) {
+ IWL_ERROR("Start AGG when state is not IWL_AGG_OFF !\n");
+ return -ENXIO;
+ }
+
+ txq_id = iwl_txq_ctx_activate_free(priv);
+ if (txq_id == -1)
+ return -ENXIO;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ tid_data = &priv->stations[sta_id].tid[tid];
+ *ssn = SEQ_TO_SN(tid_data->seq_number);
+ tid_data->agg.txq_id = txq_id;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo,
+ sta_id, tid, *ssn);
+ if (ret)
+ return ret;
+
+ if (tid_data->tfds_in_queue == 0) {
+ printk(KERN_ERR "HW queue is empty\n");
+ tid_data->agg.state = IWL_AGG_ON;
+ ieee80211_start_tx_ba_cb_irqsafe(priv->hw, ra, tid);
+ } else {
+ IWL_DEBUG_HT("HW queue is NOT empty: %d packets in HW queue\n",
+ tid_data->tfds_in_queue);
+ tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(iwl_tx_agg_start);
+
+int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid)
+{
+ int tx_fifo_id, txq_id, sta_id, ssn = -1;
+ struct iwl_tid_data *tid_data;
+ int ret, write_ptr, read_ptr;
+ unsigned long flags;
+ DECLARE_MAC_BUF(mac);
+
+ if (!ra) {
+ IWL_ERROR("ra = NULL\n");
+ return -EINVAL;
+ }
+
+ if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
+ tx_fifo_id = default_tid_to_tx_fifo[tid];
+ else
+ return -EINVAL;
+
+ sta_id = iwl_find_station(priv, ra);
+
+ if (sta_id == IWL_INVALID_STATION)
+ return -ENXIO;
+
+ if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON)
+ IWL_WARNING("Stopping AGG while state not IWL_AGG_ON\n");
+
+ tid_data = &priv->stations[sta_id].tid[tid];
+ ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4;
+ txq_id = tid_data->agg.txq_id;
+ write_ptr = priv->txq[txq_id].q.write_ptr;
+ read_ptr = priv->txq[txq_id].q.read_ptr;
+
+ /* The queue is not empty */
+ if (write_ptr != read_ptr) {
+ IWL_DEBUG_HT("Stopping a non empty AGG HW QUEUE\n");
+ priv->stations[sta_id].tid[tid].agg.state =
+ IWL_EMPTYING_HW_QUEUE_DELBA;
+ return 0;
+ }
+
+ IWL_DEBUG_HT("HW queue is empty\n");
+ priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ ret = priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn,
+ tx_fifo_id);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (ret)
+ return ret;
+
+ ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, ra, tid);
+
+ return 0;
+}
+EXPORT_SYMBOL(iwl_tx_agg_stop);
+
+int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id)
+{
+ struct iwl_queue *q = &priv->txq[txq_id].q;
+ u8 *addr = priv->stations[sta_id].sta.sta.addr;
+ struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid];
+
+ switch (priv->stations[sta_id].tid[tid].agg.state) {
+ case IWL_EMPTYING_HW_QUEUE_DELBA:
+ /* We are reclaiming the last packet of the */
+ /* aggregated HW queue */
+ if (txq_id == tid_data->agg.txq_id &&
+ q->read_ptr == q->write_ptr) {
+ u16 ssn = SEQ_TO_SN(tid_data->seq_number);
+ int tx_fifo = default_tid_to_tx_fifo[tid];
+ IWL_DEBUG_HT("HW queue empty: continue DELBA flow\n");
+ priv->cfg->ops->lib->txq_agg_disable(priv, txq_id,
+ ssn, tx_fifo);
+ tid_data->agg.state = IWL_AGG_OFF;
+ ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, addr, tid);
+ }
+ break;
+ case IWL_EMPTYING_HW_QUEUE_ADDBA:
+ /* We are reclaiming the last packet of the queue */
+ if (tid_data->tfds_in_queue == 0) {
+ IWL_DEBUG_HT("HW queue empty: continue ADDBA flow\n");
+ tid_data->agg.state = IWL_AGG_ON;
+ ieee80211_start_tx_ba_cb_irqsafe(priv->hw, addr, tid);
+ }
+ break;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(iwl_txq_check_empty);
+#endif /* CONFIG_IWL4965_HT */
+
+#ifdef CONFIG_IWLWIF_DEBUG
+#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+
+const char *iwl_get_tx_fail_reason(u32 status)
+{
+ switch (status & TX_STATUS_MSK) {
+ case TX_STATUS_SUCCESS:
+ return "SUCCESS";
+ TX_STATUS_ENTRY(SHORT_LIMIT);
+ TX_STATUS_ENTRY(LONG_LIMIT);
+ TX_STATUS_ENTRY(FIFO_UNDERRUN);
+ TX_STATUS_ENTRY(MGMNT_ABORT);
+ TX_STATUS_ENTRY(NEXT_FRAG);
+ TX_STATUS_ENTRY(LIFE_EXPIRE);
+ TX_STATUS_ENTRY(DEST_PS);
+ TX_STATUS_ENTRY(ABORTED);
+ TX_STATUS_ENTRY(BT_RETRY);
+ TX_STATUS_ENTRY(STA_INVALID);
+ TX_STATUS_ENTRY(FRAG_DROPPED);
+ TX_STATUS_ENTRY(TID_DISABLE);
+ TX_STATUS_ENTRY(FRAME_FLUSHED);
+ TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL);
+ TX_STATUS_ENTRY(TX_LOCKED);
+ TX_STATUS_ENTRY(NO_BEACON_ON_RADAR);
+ }
+
+ return "UNKNOWN";
+}
+EXPORT_SYMBOL(iwl_get_tx_fail_reason);
+#endif /* CONFIG_IWLWIFI_DEBUG */
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 13925b6..72279e0 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -102,16 +102,6 @@
MODULE_AUTHOR(DRV_COPYRIGHT);
MODULE_LICENSE("GPL");
-static __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr)
-{
- u16 fc = le16_to_cpu(hdr->frame_control);
- int hdr_len = ieee80211_get_hdrlen(fc);
-
- if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA))
- return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN);
- return NULL;
-}
-
static const struct ieee80211_supported_band *iwl3945_get_band(
struct iwl3945_priv *priv, enum ieee80211_band band)
{
@@ -2386,12 +2376,13 @@
}
static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv,
- struct ieee80211_tx_control *ctl,
+ struct ieee80211_tx_info *info,
struct iwl3945_cmd *cmd,
struct sk_buff *skb_frag,
int last_frag)
{
- struct iwl3945_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo;
+ struct iwl3945_hw_key *keyinfo =
+ &priv->stations[info->control.hw_key->hw_key_idx].keyinfo;
switch (keyinfo->alg) {
case ALG_CCMP:
@@ -2414,7 +2405,7 @@
case ALG_WEP:
cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP |
- (ctl->key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
+ (info->control.hw_key->hw_key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
if (keyinfo->keylen == 13)
cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128;
@@ -2422,7 +2413,7 @@
memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen);
IWL_DEBUG_TX("Configuring packet for WEP encryption "
- "with key %d\n", ctl->key_idx);
+ "with key %d\n", info->control.hw_key->hw_key_idx);
break;
default:
@@ -2436,16 +2427,15 @@
*/
static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv,
struct iwl3945_cmd *cmd,
- struct ieee80211_tx_control *ctrl,
+ struct ieee80211_tx_info *info,
struct ieee80211_hdr *hdr,
int is_unicast, u8 std_id)
{
- __le16 *qc;
u16 fc = le16_to_cpu(hdr->frame_control);
__le32 tx_flags = cmd->cmd.tx.tx_flags;
cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
- if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) {
+ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
tx_flags |= TX_CMD_FLG_ACK_MSK;
if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)
tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
@@ -2461,17 +2451,18 @@
if (ieee80211_get_morefrag(hdr))
tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
- qc = ieee80211_get_qos_ctrl(hdr);
- if (qc) {
- cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf);
+ if (ieee80211_is_qos_data(fc)) {
+ u8 *qc = ieee80211_get_qos_ctrl(hdr, ieee80211_get_hdrlen(fc));
+ cmd->cmd.tx.tid_tspec = qc[0] & 0xf;
tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
- } else
+ } else {
tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+ }
- if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
+ if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
tx_flags |= TX_CMD_FLG_RTS_MSK;
tx_flags &= ~TX_CMD_FLG_CTS_MSK;
- } else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
+ } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
tx_flags &= ~TX_CMD_FLG_RTS_MSK;
tx_flags |= TX_CMD_FLG_CTS_MSK;
}
@@ -2555,25 +2546,27 @@
/*
* start REPLY_TX command process
*/
-static int iwl3945_tx_skb(struct iwl3945_priv *priv,
- struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl3945_tfd_frame *tfd;
u32 *control_flags;
- int txq_id = ctl->queue;
+ int txq_id = skb_get_queue_mapping(skb);
struct iwl3945_tx_queue *txq = NULL;
struct iwl3945_queue *q = NULL;
dma_addr_t phys_addr;
dma_addr_t txcmd_phys;
struct iwl3945_cmd *out_cmd = NULL;
- u16 len, idx, len_org;
- u8 id, hdr_len, unicast;
+ u16 len, idx, len_org, hdr_len;
+ u8 id;
+ u8 unicast;
u8 sta_id;
+ u8 tid = 0;
u16 seq_number = 0;
u16 fc;
- __le16 *qc;
u8 wait_write_ptr = 0;
+ u8 *qc = NULL;
unsigned long flags;
int rc;
@@ -2588,7 +2581,7 @@
goto drop_unlock;
}
- if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) {
+ if ((ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xFF) == IWL_INVALID_RATE) {
IWL_ERROR("ERROR: No TX rate available.\n");
goto drop_unlock;
}
@@ -2631,9 +2624,9 @@
IWL_DEBUG_RATE("station Id %d\n", sta_id);
- qc = ieee80211_get_qos_ctrl(hdr);
- if (qc) {
- u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
+ if (ieee80211_is_qos_data(fc)) {
+ qc = ieee80211_get_qos_ctrl(hdr, hdr_len);
+ tid = qc[0] & 0xf;
seq_number = priv->stations[sta_id].tid[tid].seq_number &
IEEE80211_SCTL_SEQ;
hdr->seq_ctrl = cpu_to_le16(seq_number) |
@@ -2657,8 +2650,6 @@
/* Set up driver data for this TFD */
memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl3945_tx_info));
txq->txb[q->write_ptr].skb[0] = skb;
- memcpy(&(txq->txb[q->write_ptr].status.control),
- ctl, sizeof(struct ieee80211_tx_control));
/* Init first empty entry in queue's array of Tx/cmd buffers */
out_cmd = &txq->cmd[idx];
@@ -2707,8 +2698,8 @@
* first entry */
iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
- if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
- iwl3945_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0);
+ if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT))
+ iwl3945_build_tx_cmd_hwcrypto(priv, info, out_cmd, skb, 0);
/* Set up TFD's 2nd entry to point directly to remainder of skb,
* if any (802.11 null frames have no payload). */
@@ -2733,10 +2724,10 @@
out_cmd->cmd.tx.len = cpu_to_le16(len);
/* TODO need this for burst mode later on */
- iwl3945_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id);
+ iwl3945_build_tx_cmd_basic(priv, out_cmd, info, hdr, unicast, sta_id);
/* set is_hcca to 0; it probably will never be implemented */
- iwl3945_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0);
+ iwl3945_hw_build_tx_cmd_rate(priv, out_cmd, info, hdr, sta_id, 0);
out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
@@ -2744,7 +2735,6 @@
if (!ieee80211_get_morefrag(hdr)) {
txq->need_update = 1;
if (qc) {
- u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
priv->stations[sta_id].tid[tid].seq_number = seq_number;
}
} else {
@@ -2775,7 +2765,7 @@
spin_unlock_irqrestore(&priv->lock, flags);
}
- ieee80211_stop_queue(priv->hw, ctl->queue);
+ ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb));
}
return 0;
@@ -3238,7 +3228,7 @@
struct sk_buff *beacon;
/* Pull updated AP beacon from mac80211. will fail if not in AP mode */
- beacon = ieee80211_beacon_get(priv->hw, priv->vif, NULL);
+ beacon = ieee80211_beacon_get(priv->hw, priv->vif);
if (!beacon) {
IWL_ERROR("update beacon failed\n");
@@ -4840,7 +4830,7 @@
ch_info->scan_power = eeprom_ch_info[ch].max_power_avg;
ch_info->min_power = 0;
- IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x"
+ IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x"
" %ddBm): Ad-Hoc %ssupported\n",
ch_info->channel,
is_channel_a_band(ch_info) ?
@@ -4850,7 +4840,6 @@
CHECK_AND_PRINT(ACTIVE),
CHECK_AND_PRINT(RADAR),
CHECK_AND_PRINT(WIDE),
- CHECK_AND_PRINT(NARROW),
CHECK_AND_PRINT(DFS),
eeprom_ch_info[ch].flags,
eeprom_ch_info[ch].max_power_avg,
@@ -4986,9 +4975,6 @@
if (scan_ch->type & 1)
scan_ch->type |= (direct_mask << 1);
- if (is_channel_narrow(ch_info))
- scan_ch->type |= (1 << 7);
-
scan_ch->active_dwell = cpu_to_le16(active_dwell);
scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
@@ -5835,7 +5821,7 @@
if (iwl3945_is_rfkill(priv))
return;
- ieee80211_start_queues(priv->hw);
+ ieee80211_wake_queues(priv->hw);
priv->active_rate = priv->rates_mask;
priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
@@ -5861,9 +5847,6 @@
/* Configure the adapter for unassociated operation */
iwl3945_commit_rxon(priv);
- /* At this point, the NIC is initialized and operational */
- priv->notif_missed_beacons = 0;
-
iwl3945_reg_txpower_periodic(priv);
iwl3945_led_register(priv);
@@ -6147,6 +6130,24 @@
mutex_unlock(&priv->mutex);
}
+static void iwl3945_bg_set_monitor(struct work_struct *work)
+{
+ struct iwl3945_priv *priv = container_of(work,
+ struct iwl3945_priv, set_monitor);
+
+ IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n");
+
+ mutex_lock(&priv->mutex);
+
+ if (!iwl3945_is_ready(priv))
+ IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n");
+ else
+ if (iwl3945_set_mode(priv, IEEE80211_IF_TYPE_MNTR) != 0)
+ IWL_ERROR("iwl3945_set_mode() failed\n");
+
+ mutex_unlock(&priv->mutex);
+}
+
#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
static void iwl3945_bg_scan_check(struct work_struct *data)
@@ -6675,8 +6676,7 @@
IWL_DEBUG_MAC80211("leave\n");
}
-static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_control *ctl)
+static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct iwl3945_priv *priv = hw->priv;
@@ -6688,9 +6688,9 @@
}
IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
- ctl->tx_rate->bitrate);
+ ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
- if (iwl3945_tx_skb(priv, skb, ctl))
+ if (iwl3945_tx_skb(priv, skb))
dev_kfree_skb_any(skb);
IWL_DEBUG_MAC80211("leave\n");
@@ -6999,7 +6999,22 @@
* XXX: dummy
* see also iwl3945_connection_init_rx_config
*/
- *total_flags = 0;
+ struct iwl3945_priv *priv = hw->priv;
+ int new_flags = 0;
+ if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) {
+ if (*total_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) {
+ IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n",
+ IEEE80211_IF_TYPE_MNTR,
+ changed_flags, *total_flags);
+ /* queue work 'cuz mac80211 is holding a lock which
+ * prevents us from issuing (synchronous) f/w cmds */
+ queue_work(priv->workqueue, &priv->set_monitor);
+ new_flags &= FIF_PROMISC_IN_BSS |
+ FIF_OTHER_BSS |
+ FIF_ALLMULTI;
+ }
+ }
+ *total_flags = new_flags;
}
static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw,
@@ -7057,9 +7072,10 @@
rc = -EAGAIN;
goto out_unlock;
}
- /* if we just finished scan ask for delay */
- if (priv->last_scan_jiffies && time_after(priv->last_scan_jiffies +
- IWL_DELAY_NEXT_SCAN, jiffies)) {
+ /* if we just finished scan ask for delay for a broadcast scan */
+ if ((len == 0) && priv->last_scan_jiffies &&
+ time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN,
+ jiffies)) {
rc = -EAGAIN;
goto out_unlock;
}
@@ -7146,7 +7162,7 @@
return rc;
}
-static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, int queue,
+static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct iwl3945_priv *priv = hw->priv;
@@ -7220,9 +7236,9 @@
q = &txq->q;
avail = iwl3945_queue_space(q);
- stats->data[i].len = q->n_window - avail;
- stats->data[i].limit = q->n_window - q->high_mark;
- stats->data[i].count = q->n_window;
+ stats[i].len = q->n_window - avail;
+ stats[i].limit = q->n_window - q->high_mark;
+ stats[i].count = q->n_window;
}
spin_unlock_irqrestore(&priv->lock, flags);
@@ -7311,8 +7327,7 @@
}
-static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct iwl3945_priv *priv = hw->priv;
unsigned long flags;
@@ -7875,6 +7890,7 @@
INIT_WORK(&priv->abort_scan, iwl3945_bg_abort_scan);
INIT_WORK(&priv->rf_kill, iwl3945_bg_rf_kill);
INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update);
+ INIT_WORK(&priv->set_monitor, iwl3945_bg_set_monitor);
INIT_DELAYED_WORK(&priv->post_associate, iwl3945_bg_post_associate);
INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start);
INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start);
@@ -7997,17 +8013,10 @@
priv->ibss_beacon = NULL;
- /* Tell mac80211 and its clients (e.g. Wireless Extensions)
- * the range of signal quality values that we'll provide.
- * Negative values for level/noise indicate that we'll provide dBm.
- * For WE, at least, non-0 values here *enable* display of values
- * in app (iwconfig). */
- hw->max_rssi = -20; /* signal level, negative indicates dBm */
- hw->max_noise = -20; /* noise level, negative indicates dBm */
- hw->max_signal = 100; /* link quality indication (%) */
-
- /* Tell mac80211 our Tx characteristics */
- hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
+ /* Tell mac80211 our characteristics */
+ hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_NOISE_DBM;
/* 4 EDCA QOS priorities */
hw->queues = 4;
@@ -8248,7 +8257,7 @@
iwl3945_free_channel_map(priv);
iwl3945_free_geos(priv);
-
+ kfree(priv->scan);
if (priv->ibss_beacon)
dev_kfree_skb(priv->ibss_beacon);
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 883b42f..c71daec 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -46,14 +46,13 @@
#include <asm/div64.h>
#include "iwl-eeprom.h"
-#include "iwl-4965.h"
+#include "iwl-dev.h"
#include "iwl-core.h"
#include "iwl-io.h"
#include "iwl-helpers.h"
#include "iwl-sta.h"
+#include "iwl-calib.h"
-static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv,
- struct iwl4965_tx_queue *txq);
/******************************************************************************
*
@@ -88,22 +87,6 @@
MODULE_AUTHOR(DRV_COPYRIGHT);
MODULE_LICENSE("GPL");
-__le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr)
-{
- u16 fc = le16_to_cpu(hdr->frame_control);
- int hdr_len = ieee80211_get_hdrlen(fc);
-
- if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA))
- return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN);
- return NULL;
-}
-
-static const struct ieee80211_supported_band *iwl4965_get_hw_mode(
- struct iwl_priv *priv, enum ieee80211_band band)
-{
- return priv->hw->wiphy->bands[band];
-}
-
static int iwl4965_is_empty_essid(const char *essid, int essid_len)
{
/* Single white space is for Linksys APs */
@@ -144,236 +127,6 @@
return escaped;
}
-/*************** DMA-QUEUE-GENERAL-FUNCTIONS *****
- * DMA services
- *
- * Theory of operation
- *
- * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer
- * of buffer descriptors, each of which points to one or more data buffers for
- * the device to read from or fill. Driver and device exchange status of each
- * queue via "read" and "write" pointers. Driver keeps minimum of 2 empty
- * entries in each circular buffer, to protect against confusing empty and full
- * queue states.
- *
- * The device reads or writes the data in the queues via the device's several
- * DMA/FIFO channels. Each queue is mapped to a single DMA channel.
- *
- * For Tx queue, there are low mark and high mark limits. If, after queuing
- * the packet for Tx, free space become < low mark, Tx queue stopped. When
- * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
- * Tx queue resumed.
- *
- * The 4965 operates with up to 17 queues: One receive queue, one transmit
- * queue (#4) for sending commands to the device firmware, and 15 other
- * Tx queues that may be mapped to prioritized Tx DMA/FIFO channels.
- *
- * See more detailed info in iwl-4965-hw.h.
- ***************************************************/
-
-int iwl4965_queue_space(const struct iwl4965_queue *q)
-{
- int s = q->read_ptr - q->write_ptr;
-
- if (q->read_ptr > q->write_ptr)
- s -= q->n_bd;
-
- if (s <= 0)
- s += q->n_window;
- /* keep some reserve to not confuse empty and full situations */
- s -= 2;
- if (s < 0)
- s = 0;
- return s;
-}
-
-
-static inline int x2_queue_used(const struct iwl4965_queue *q, int i)
-{
- return q->write_ptr > q->read_ptr ?
- (i >= q->read_ptr && i < q->write_ptr) :
- !(i < q->read_ptr && i >= q->write_ptr);
-}
-
-static inline u8 get_cmd_index(struct iwl4965_queue *q, u32 index, int is_huge)
-{
- /* This is for scan command, the big buffer at end of command array */
- if (is_huge)
- return q->n_window; /* must be power of 2 */
-
- /* Otherwise, use normal size buffers */
- return index & (q->n_window - 1);
-}
-
-/**
- * iwl4965_queue_init - Initialize queue's high/low-water and read/write indexes
- */
-static int iwl4965_queue_init(struct iwl_priv *priv, struct iwl4965_queue *q,
- int count, int slots_num, u32 id)
-{
- q->n_bd = count;
- q->n_window = slots_num;
- q->id = id;
-
- /* count must be power-of-two size, otherwise iwl_queue_inc_wrap
- * and iwl_queue_dec_wrap are broken. */
- BUG_ON(!is_power_of_2(count));
-
- /* slots_num must be power-of-two size, otherwise
- * get_cmd_index is broken. */
- BUG_ON(!is_power_of_2(slots_num));
-
- q->low_mark = q->n_window / 4;
- if (q->low_mark < 4)
- q->low_mark = 4;
-
- q->high_mark = q->n_window / 8;
- if (q->high_mark < 2)
- q->high_mark = 2;
-
- q->write_ptr = q->read_ptr = 0;
-
- return 0;
-}
-
-/**
- * iwl4965_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue
- */
-static int iwl4965_tx_queue_alloc(struct iwl_priv *priv,
- struct iwl4965_tx_queue *txq, u32 id)
-{
- struct pci_dev *dev = priv->pci_dev;
-
- /* Driver private data, only for Tx (not command) queues,
- * not shared with device. */
- if (id != IWL_CMD_QUEUE_NUM) {
- txq->txb = kmalloc(sizeof(txq->txb[0]) *
- TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
- if (!txq->txb) {
- IWL_ERROR("kmalloc for auxiliary BD "
- "structures failed\n");
- goto error;
- }
- } else
- txq->txb = NULL;
-
- /* Circular buffer of transmit frame descriptors (TFDs),
- * shared with device */
- txq->bd = pci_alloc_consistent(dev,
- sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX,
- &txq->q.dma_addr);
-
- if (!txq->bd) {
- IWL_ERROR("pci_alloc_consistent(%zd) failed\n",
- sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX);
- goto error;
- }
- txq->q.id = id;
-
- return 0;
-
- error:
- if (txq->txb) {
- kfree(txq->txb);
- txq->txb = NULL;
- }
-
- return -ENOMEM;
-}
-
-/**
- * iwl4965_tx_queue_init - Allocate and initialize one tx/cmd queue
- */
-int iwl4965_tx_queue_init(struct iwl_priv *priv,
- struct iwl4965_tx_queue *txq, int slots_num, u32 txq_id)
-{
- struct pci_dev *dev = priv->pci_dev;
- int len;
- int rc = 0;
-
- /*
- * Alloc buffer array for commands (Tx or other types of commands).
- * For the command queue (#4), allocate command space + one big
- * command for scan, since scan command is very huge; the system will
- * not have two scans at the same time, so only one is needed.
- * For normal Tx queues (all other queues), no super-size command
- * space is needed.
- */
- len = sizeof(struct iwl_cmd) * slots_num;
- if (txq_id == IWL_CMD_QUEUE_NUM)
- len += IWL_MAX_SCAN_SIZE;
- txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd);
- if (!txq->cmd)
- return -ENOMEM;
-
- /* Alloc driver data array and TFD circular buffer */
- rc = iwl4965_tx_queue_alloc(priv, txq, txq_id);
- if (rc) {
- pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
-
- return -ENOMEM;
- }
- txq->need_update = 0;
-
- /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
- * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
- BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
-
- /* Initialize queue's high/low-water marks, and head/tail indexes */
- iwl4965_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
-
- /* Tell device where to find queue */
- iwl4965_hw_tx_queue_init(priv, txq);
-
- return 0;
-}
-
-/**
- * iwl4965_tx_queue_free - Deallocate DMA queue.
- * @txq: Transmit queue to deallocate.
- *
- * Empty queue by removing and destroying all BD's.
- * Free all buffers.
- * 0-fill, but do not free "txq" descriptor structure.
- */
-void iwl4965_tx_queue_free(struct iwl_priv *priv, struct iwl4965_tx_queue *txq)
-{
- struct iwl4965_queue *q = &txq->q;
- struct pci_dev *dev = priv->pci_dev;
- int len;
-
- if (q->n_bd == 0)
- return;
-
- /* first, empty all BD's */
- for (; q->write_ptr != q->read_ptr;
- q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd))
- iwl4965_hw_txq_free_tfd(priv, txq);
-
- len = sizeof(struct iwl_cmd) * q->n_window;
- if (q->id == IWL_CMD_QUEUE_NUM)
- len += IWL_MAX_SCAN_SIZE;
-
- /* De-alloc array of command/tx buffers */
- pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
-
- /* De-alloc circular buffer of TFDs */
- if (txq->q.n_bd)
- pci_free_consistent(dev, sizeof(struct iwl4965_tfd_frame) *
- txq->q.n_bd, txq->bd, txq->q.dma_addr);
-
- /* De-alloc array of per-TFD driver data */
- if (txq->txb) {
- kfree(txq->txb);
- txq->txb = NULL;
- }
-
- /* 0-fill queue descriptor structure */
- memset(txq, 0, sizeof(*txq));
-}
-
-const u8 iwl4965_broadcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
-
/*************** STATION TABLE MANAGEMENT ****
* mac80211 should be examined to determine if sta_info is duplicating
* the functionality provided here
@@ -381,213 +134,11 @@
/**************************************************************/
-#if 0 /* temporary disable till we add real remove station */
-/**
- * iwl4965_remove_station - Remove driver's knowledge of station.
- *
- * NOTE: This does not remove station from device's station table.
- */
-static u8 iwl4965_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
-{
- int index = IWL_INVALID_STATION;
- int i;
- unsigned long flags;
- spin_lock_irqsave(&priv->sta_lock, flags);
-
- if (is_ap)
- index = IWL_AP_ID;
- else if (is_broadcast_ether_addr(addr))
- index = priv->hw_params.bcast_sta_id;
- else
- for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++)
- if (priv->stations[i].used &&
- !compare_ether_addr(priv->stations[i].sta.sta.addr,
- addr)) {
- index = i;
- break;
- }
-
- if (unlikely(index == IWL_INVALID_STATION))
- goto out;
-
- if (priv->stations[index].used) {
- priv->stations[index].used = 0;
- priv->num_stations--;
- }
-
- BUG_ON(priv->num_stations < 0);
-
-out:
- spin_unlock_irqrestore(&priv->sta_lock, flags);
- return 0;
-}
-#endif
-
-/**
- * iwl4965_add_station_flags - Add station to tables in driver and device
- */
-u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr,
- int is_ap, u8 flags, void *ht_data)
-{
- int i;
- int index = IWL_INVALID_STATION;
- struct iwl4965_station_entry *station;
- unsigned long flags_spin;
- DECLARE_MAC_BUF(mac);
-
- spin_lock_irqsave(&priv->sta_lock, flags_spin);
- if (is_ap)
- index = IWL_AP_ID;
- else if (is_broadcast_ether_addr(addr))
- index = priv->hw_params.bcast_sta_id;
- else
- for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) {
- if (!compare_ether_addr(priv->stations[i].sta.sta.addr,
- addr)) {
- index = i;
- break;
- }
-
- if (!priv->stations[i].used &&
- index == IWL_INVALID_STATION)
- index = i;
- }
-
-
- /* These two conditions have the same outcome, but keep them separate
- since they have different meanings */
- if (unlikely(index == IWL_INVALID_STATION)) {
- spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
- return index;
- }
-
- if (priv->stations[index].used &&
- !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) {
- spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
- return index;
- }
-
-
- IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr));
- station = &priv->stations[index];
- station->used = 1;
- priv->num_stations++;
-
- /* Set up the REPLY_ADD_STA command to send to device */
- memset(&station->sta, 0, sizeof(struct iwl4965_addsta_cmd));
- memcpy(station->sta.sta.addr, addr, ETH_ALEN);
- station->sta.mode = 0;
- station->sta.sta.sta_id = index;
- station->sta.station_flags = 0;
-
-#ifdef CONFIG_IWL4965_HT
- /* BCAST station and IBSS stations do not work in HT mode */
- if (index != priv->hw_params.bcast_sta_id &&
- priv->iw_mode != IEEE80211_IF_TYPE_IBSS)
- iwl4965_set_ht_add_station(priv, index,
- (struct ieee80211_ht_info *) ht_data);
-#endif /*CONFIG_IWL4965_HT*/
-
- spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
-
- /* Add station to device's station table */
- iwl4965_send_add_station(priv, &station->sta, flags);
- return index;
-
-}
-
-
-
-/*************** HOST COMMAND QUEUE FUNCTIONS *****/
-
-/**
- * iwl4965_enqueue_hcmd - enqueue a uCode command
- * @priv: device private data point
- * @cmd: a point to the ucode command structure
- *
- * The function returns < 0 values to indicate the operation is
- * failed. On success, it turns the index (> 0) of command in the
- * command queue.
- */
-int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
-{
- struct iwl4965_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
- struct iwl4965_queue *q = &txq->q;
- struct iwl4965_tfd_frame *tfd;
- u32 *control_flags;
- struct iwl_cmd *out_cmd;
- u32 idx;
- u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
- dma_addr_t phys_addr;
- int ret;
- unsigned long flags;
-
- /* If any of the command structures end up being larger than
- * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
- * we will need to increase the size of the TFD entries */
- BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
- !(cmd->meta.flags & CMD_SIZE_HUGE));
-
- if (iwl_is_rfkill(priv)) {
- IWL_DEBUG_INFO("Not sending command - RF KILL");
- return -EIO;
- }
-
- if (iwl4965_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
- IWL_ERROR("No space for Tx\n");
- return -ENOSPC;
- }
-
- spin_lock_irqsave(&priv->hcmd_lock, flags);
-
- tfd = &txq->bd[q->write_ptr];
- memset(tfd, 0, sizeof(*tfd));
-
- control_flags = (u32 *) tfd;
-
- idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE);
- out_cmd = &txq->cmd[idx];
-
- out_cmd->hdr.cmd = cmd->id;
- memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta));
- memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len);
-
- /* At this point, the out_cmd now has all of the incoming cmd
- * information */
-
- out_cmd->hdr.flags = 0;
- out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
- INDEX_TO_SEQ(q->write_ptr));
- if (out_cmd->meta.flags & CMD_SIZE_HUGE)
- out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME);
-
- phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx +
- offsetof(struct iwl_cmd, hdr);
- iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size);
-
- IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, "
- "%d bytes at %d[%d]:%d\n",
- get_cmd_string(out_cmd->hdr.cmd),
- out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),
- fix_size, q->write_ptr, idx, IWL_CMD_QUEUE_NUM);
-
- txq->need_update = 1;
-
- /* Set up entry in queue's byte count circular buffer */
- priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, 0);
-
- /* Increment and update queue's write index */
- q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
- ret = iwl4965_tx_queue_update_write_ptr(priv, txq);
-
- spin_unlock_irqrestore(&priv->hcmd_lock, flags);
- return ret ? ret : idx;
-}
static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
{
- struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon;
+ struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
if (hw_decrypt)
rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
@@ -597,45 +148,13 @@
}
/**
- * iwl4965_rxon_add_station - add station into station table.
- *
- * there is only one AP station with id= IWL_AP_ID
- * NOTE: mutex must be held before calling this fnction
- */
-static int iwl4965_rxon_add_station(struct iwl_priv *priv,
- const u8 *addr, int is_ap)
-{
- u8 sta_id;
-
- /* Add station to device's station table */
-#ifdef CONFIG_IWL4965_HT
- struct ieee80211_conf *conf = &priv->hw->conf;
- struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf;
-
- if ((is_ap) &&
- (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) &&
- (priv->iw_mode == IEEE80211_IF_TYPE_STA))
- sta_id = iwl4965_add_station_flags(priv, addr, is_ap,
- 0, cur_ht_config);
- else
-#endif /* CONFIG_IWL4965_HT */
- sta_id = iwl4965_add_station_flags(priv, addr, is_ap,
- 0, NULL);
-
- /* Set up default rate scaling table in device's station table */
- iwl4965_add_station(priv, addr, is_ap);
-
- return sta_id;
-}
-
-/**
* iwl4965_check_rxon_cmd - validate RXON structure is valid
*
* NOTE: This is really only useful during development and can eventually
* be #ifdef'd out once the driver is stable and folks aren't actively
* making changes
*/
-static int iwl4965_check_rxon_cmd(struct iwl4965_rxon_cmd *rxon)
+static int iwl4965_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
{
int error = 0;
int counter = 1;
@@ -760,7 +279,7 @@
static int iwl4965_commit_rxon(struct iwl_priv *priv)
{
/* cast away the const for active_rxon in this function */
- struct iwl4965_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
+ struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
DECLARE_MAC_BUF(mac);
int rc = 0;
@@ -795,14 +314,6 @@
/* station table will be cleared */
priv->assoc_station_added = 0;
-#ifdef CONFIG_IWL4965_SENSITIVITY
- priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT;
- if (!priv->error_recovering)
- priv->start_calib = 0;
-
- iwl4965_init_sensitivity(priv, CMD_ASYNC, 1);
-#endif /* CONFIG_IWL4965_SENSITIVITY */
-
/* If we are currently associated and the new config requires
* an RXON_ASSOC and the new config wants the associated mask enabled,
* we must clear the associated from the active configuration
@@ -813,7 +324,7 @@
active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
- sizeof(struct iwl4965_rxon_cmd),
+ sizeof(struct iwl_rxon_cmd),
&priv->active_rxon);
/* If the mask clearing failed then we set
@@ -835,24 +346,22 @@
le16_to_cpu(priv->staging_rxon.channel),
print_mac(mac, priv->staging_rxon.bssid_addr));
- iwl4965_set_rxon_hwcrypto(priv, !priv->cfg->mod_params->sw_crypto);
+ iwl4965_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto);
/* Apply the new configuration */
rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
- sizeof(struct iwl4965_rxon_cmd), &priv->staging_rxon);
+ sizeof(struct iwl_rxon_cmd), &priv->staging_rxon);
if (rc) {
IWL_ERROR("Error setting new configuration (%d).\n", rc);
return rc;
}
+ iwl_remove_station(priv, iwl_bcast_addr, 0);
iwlcore_clear_stations_table(priv);
-#ifdef CONFIG_IWL4965_SENSITIVITY
if (!priv->error_recovering)
priv->start_calib = 0;
- priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT;
- iwl4965_init_sensitivity(priv, CMD_ASYNC, 1);
-#endif /* CONFIG_IWL4965_SENSITIVITY */
+ iwl_init_sensitivity(priv);
memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
@@ -865,7 +374,7 @@
}
/* Add the broadcast address so we can send broadcast frames */
- if (iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0) ==
+ if (iwl_rxon_add_station(priv, iwl_bcast_addr, 0) ==
IWL_INVALID_STATION) {
IWL_ERROR("Error adding BROADCAST address for transmit.\n");
return -EIO;
@@ -875,7 +384,7 @@
* add the IWL_AP_ID to the station rate table */
if (iwl_is_associated(priv) &&
(priv->iw_mode == IEEE80211_IF_TYPE_STA)) {
- if (iwl4965_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1)
+ if (iwl_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1)
== IWL_INVALID_STATION) {
IWL_ERROR("Error adding AP address for transmit.\n");
return -EIO;
@@ -889,6 +398,13 @@
return 0;
}
+void iwl4965_update_chain_flags(struct iwl_priv *priv)
+{
+
+ iwl_set_rxon_chain(priv);
+ iwl4965_commit_rxon(priv);
+}
+
static int iwl4965_send_bt_config(struct iwl_priv *priv)
{
struct iwl4965_bt_cmd bt_cmd = {
@@ -905,8 +421,8 @@
static int iwl4965_send_scan_abort(struct iwl_priv *priv)
{
- int rc = 0;
- struct iwl4965_rx_packet *res;
+ int ret = 0;
+ struct iwl_rx_packet *res;
struct iwl_host_cmd cmd = {
.id = REPLY_SCAN_ABORT_CMD,
.meta.flags = CMD_WANT_SKB,
@@ -920,13 +436,13 @@
return 0;
}
- rc = iwl_send_cmd_sync(priv, &cmd);
- if (rc) {
+ ret = iwl_send_cmd_sync(priv, &cmd);
+ if (ret) {
clear_bit(STATUS_SCAN_ABORTING, &priv->status);
- return rc;
+ return ret;
}
- res = (struct iwl4965_rx_packet *)cmd.meta.u.skb->data;
+ res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
if (res->u.status != CAN_ABORT_STATUS) {
/* The scan abort will return 1 for success or
* 2 for "failure". A failure condition can be
@@ -941,14 +457,7 @@
dev_kfree_skb_any(cmd.meta.u.skb);
- return rc;
-}
-
-static int iwl4965_card_state_sync_callback(struct iwl_priv *priv,
- struct iwl_cmd *cmd,
- struct sk_buff *skb)
-{
- return 1;
+ return ret;
}
/*
@@ -970,88 +479,10 @@
.meta.flags = meta_flag,
};
- if (meta_flag & CMD_ASYNC)
- cmd.meta.u.callback = iwl4965_card_state_sync_callback;
-
return iwl_send_cmd(priv, &cmd);
}
-static int iwl4965_add_sta_sync_callback(struct iwl_priv *priv,
- struct iwl_cmd *cmd, struct sk_buff *skb)
-{
- struct iwl4965_rx_packet *res = NULL;
-
- if (!skb) {
- IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n");
- return 1;
- }
-
- res = (struct iwl4965_rx_packet *)skb->data;
- if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
- IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
- res->hdr.flags);
- return 1;
- }
-
- switch (res->u.add_sta.status) {
- case ADD_STA_SUCCESS_MSK:
- break;
- default:
- break;
- }
-
- /* We didn't cache the SKB; let the caller free it */
- return 1;
-}
-
-int iwl4965_send_add_station(struct iwl_priv *priv,
- struct iwl4965_addsta_cmd *sta, u8 flags)
-{
- struct iwl4965_rx_packet *res = NULL;
- int rc = 0;
- struct iwl_host_cmd cmd = {
- .id = REPLY_ADD_STA,
- .len = sizeof(struct iwl4965_addsta_cmd),
- .meta.flags = flags,
- .data = sta,
- };
-
- if (flags & CMD_ASYNC)
- cmd.meta.u.callback = iwl4965_add_sta_sync_callback;
- else
- cmd.meta.flags |= CMD_WANT_SKB;
-
- rc = iwl_send_cmd(priv, &cmd);
-
- if (rc || (flags & CMD_ASYNC))
- return rc;
-
- res = (struct iwl4965_rx_packet *)cmd.meta.u.skb->data;
- if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
- IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
- res->hdr.flags);
- rc = -EIO;
- }
-
- if (rc == 0) {
- switch (res->u.add_sta.status) {
- case ADD_STA_SUCCESS_MSK:
- IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n");
- break;
- default:
- rc = -EIO;
- IWL_WARNING("REPLY_ADD_STA failed\n");
- break;
- }
- }
-
- priv->alloc_rxb_skb--;
- dev_kfree_skb_any(cmd.meta.u.skb);
-
- return rc;
-}
-
-static void iwl4965_clear_free_frames(struct iwl_priv *priv)
+static void iwl_clear_free_frames(struct iwl_priv *priv)
{
struct list_head *element;
@@ -1061,7 +492,7 @@
while (!list_empty(&priv->free_frames)) {
element = priv->free_frames.next;
list_del(element);
- kfree(list_entry(element, struct iwl4965_frame, list));
+ kfree(list_entry(element, struct iwl_frame, list));
priv->frames_count--;
}
@@ -1072,9 +503,9 @@
}
}
-static struct iwl4965_frame *iwl4965_get_free_frame(struct iwl_priv *priv)
+static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv)
{
- struct iwl4965_frame *frame;
+ struct iwl_frame *frame;
struct list_head *element;
if (list_empty(&priv->free_frames)) {
frame = kzalloc(sizeof(*frame), GFP_KERNEL);
@@ -1089,10 +520,10 @@
element = priv->free_frames.next;
list_del(element);
- return list_entry(element, struct iwl4965_frame, list);
+ return list_entry(element, struct iwl_frame, list);
}
-static void iwl4965_free_frame(struct iwl_priv *priv, struct iwl4965_frame *frame)
+static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame)
{
memset(frame, 0, sizeof(*frame));
list_add(&frame->list, &priv->free_frames);
@@ -1116,27 +547,39 @@
return priv->ibss_beacon->len;
}
-static u8 iwl4965_rate_get_lowest_plcp(int rate_mask)
+static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv)
{
- u8 i;
+ int i;
+ int rate_mask;
+ /* Set rate mask*/
+ if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)
+ rate_mask = priv->active_rate_basic & 0xF;
+ else
+ rate_mask = priv->active_rate_basic & 0xFF0;
+
+ /* Find lowest valid rate */
for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
- i = iwl4965_rates[i].next_ieee) {
+ i = iwl_rates[i].next_ieee) {
if (rate_mask & (1 << i))
- return iwl4965_rates[i].plcp;
+ return iwl_rates[i].plcp;
}
- return IWL_RATE_INVALID;
+ /* No valid rate was found. Assign the lowest one */
+ if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)
+ return IWL_RATE_1M_PLCP;
+ else
+ return IWL_RATE_6M_PLCP;
}
static int iwl4965_send_beacon_cmd(struct iwl_priv *priv)
{
- struct iwl4965_frame *frame;
+ struct iwl_frame *frame;
unsigned int frame_size;
int rc;
u8 rate;
- frame = iwl4965_get_free_frame(priv);
+ frame = iwl_get_free_frame(priv);
if (!frame) {
IWL_ERROR("Could not obtain free frame buffer for beacon "
@@ -1144,23 +587,14 @@
return -ENOMEM;
}
- if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) {
- rate = iwl4965_rate_get_lowest_plcp(priv->active_rate_basic &
- 0xFF0);
- if (rate == IWL_INVALID_RATE)
- rate = IWL_RATE_6M_PLCP;
- } else {
- rate = iwl4965_rate_get_lowest_plcp(priv->active_rate_basic & 0xF);
- if (rate == IWL_INVALID_RATE)
- rate = IWL_RATE_1M_PLCP;
- }
+ rate = iwl4965_rate_get_lowest_plcp(priv);
frame_size = iwl4965_hw_get_beacon_cmd(priv, frame, rate);
rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
&frame->u.cmd[0]);
- iwl4965_free_frame(priv, frame);
+ iwl_free_frame(priv, frame);
return rc;
}
@@ -1171,15 +605,6 @@
*
******************************************************************************/
-static void iwl4965_unset_hw_params(struct iwl_priv *priv)
-{
- if (priv->shared_virt)
- pci_free_consistent(priv->pci_dev,
- sizeof(struct iwl4965_shared),
- priv->shared_virt,
- priv->shared_phys);
-}
-
/**
* iwl4965_supported_rate_to_ie - fill in the supported rate in IE field
*
@@ -1196,7 +621,7 @@
for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) {
if (bit & supported_rate) {
ret_rates |= bit;
- rates[*cnt] = iwl4965_rates[i].ieee |
+ rates[*cnt] = iwl_rates[i].ieee |
((bit & basic_rate) ? 0x80 : 0x00);
(*cnt)++;
(*left)--;
@@ -1209,6 +634,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 |= HT_SHORT_GI_20MHZ;
+ if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40)
+ iwl_conf->sgf |= HT_SHORT_GI_40MHZ;
+
+ iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD);
+ iwl_conf->max_amsdu_size =
+ !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU);
+
+ iwl_conf->supported_chan_width =
+ !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH);
+ iwl_conf->extension_chan_offset =
+ ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET;
+ /* If no above or below channel supplied disable FAT channel */
+ if (iwl_conf->extension_chan_offset != IWL_EXT_CHANNEL_OFFSET_ABOVE &&
+ iwl_conf->extension_chan_offset != IWL_EXT_CHANNEL_OFFSET_BELOW)
+ iwl_conf->supported_chan_width = 0;
+
+ iwl_conf->tx_mimo_ps_mode =
+ (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2);
+ memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16);
+
+ iwl_conf->control_channel = ht_bss_conf->primary_channel;
+ iwl_conf->tx_chan_width =
+ !!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH);
+ iwl_conf->ht_protection =
+ ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION;
+ iwl_conf->non_GF_STA_present =
+ !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT);
+
+ IWL_DEBUG_MAC80211("control channel %d\n", iwl_conf->control_channel);
+ IWL_DEBUG_MAC80211("leave\n");
+}
+
+static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband,
+ u8 *pos, int *left)
+{
+ struct ieee80211_ht_cap *ht_cap;
+
+ if (!sband || !sband->ht_info.ht_supported)
+ return;
+
+ if (*left < sizeof(struct ieee80211_ht_cap))
+ return;
+
+ *pos++ = sizeof(struct ieee80211_ht_cap);
+ ht_cap = (struct ieee80211_ht_cap *) pos;
+
+ ht_cap->cap_info = cpu_to_le16(sband->ht_info.cap);
+ memcpy(ht_cap->supp_mcs_set, sband->ht_info.supp_mcs_set, 16);
+ ht_cap->ampdu_params_info =
+ (sband->ht_info.ampdu_factor & IEEE80211_HT_CAP_AMPDU_FACTOR) |
+ ((sband->ht_info.ampdu_density << 2) &
+ IEEE80211_HT_CAP_AMPDU_DENSITY);
+ *left -= sizeof(struct ieee80211_ht_cap);
+}
+#else
+static inline void iwl4965_ht_conf(struct iwl_priv *priv,
+ struct ieee80211_bss_conf *bss_conf)
+{
+}
+static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband,
+ u8 *pos, int *left)
+{
+}
+#endif
+
+
/**
* iwl4965_fill_probe_req - fill in all required fields and IE for probe request
*/
@@ -1220,10 +730,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 */
@@ -1233,9 +741,9 @@
len += 24;
frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
- memcpy(frame->da, iwl4965_broadcast_addr, ETH_ALEN);
+ memcpy(frame->da, iwl_bcast_addr, ETH_ALEN);
memcpy(frame->sa, priv->mac_addr, ETH_ALEN);
- memcpy(frame->bssid, iwl4965_broadcast_addr, ETH_ALEN);
+ memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN);
frame->seq_ctrl = 0;
/* fill in our indirect SSID IE */
@@ -1306,24 +814,19 @@
if (*pos > 0)
len += 2 + *pos;
-#ifdef CONFIG_IWL4965_HT
- if (sband && sband->ht_info.ht_supported) {
- struct ieee80211_ht_cap *ht_cap;
- pos += (*pos) + 1;
- *pos++ = WLAN_EID_HT_CAPABILITY;
- *pos++ = sizeof(struct ieee80211_ht_cap);
- ht_cap = (struct ieee80211_ht_cap *)pos;
- ht_cap->cap_info = cpu_to_le16(sband->ht_info.cap);
- memcpy(ht_cap->supp_mcs_set, sband->ht_info.supp_mcs_set, 16);
- ht_cap->ampdu_params_info =(sband->ht_info.ampdu_factor &
- IEEE80211_HT_CAP_AMPDU_FACTOR) |
- ((sband->ht_info.ampdu_density << 2) &
- IEEE80211_HT_CAP_AMPDU_DENSITY);
- len += 2 + sizeof(struct ieee80211_ht_cap);
- }
-#endif /*CONFIG_IWL4965_HT */
-
fill_end:
+ /* fill in HT IE */
+ left -= 2;
+ if (left < 0)
+ return 0;
+
+ *pos++ = WLAN_EID_HT_CAPABILITY;
+ *pos = 0;
+
+ iwl_ht_cap_to_ie(sband, pos, &left);
+
+ if (*pos > 0)
+ len += 2 + *pos;
return (u16)len;
}
@@ -1376,184 +879,6 @@
}
}
-/*
- * Power management (not Tx power!) functions
- */
-#define MSEC_TO_USEC 1024
-
-#define NOSLP __constant_cpu_to_le16(0), 0, 0
-#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0
-#define SLP_TIMEOUT(T) __constant_cpu_to_le32((T) * MSEC_TO_USEC)
-#define SLP_VEC(X0, X1, X2, X3, X4) {__constant_cpu_to_le32(X0), \
- __constant_cpu_to_le32(X1), \
- __constant_cpu_to_le32(X2), \
- __constant_cpu_to_le32(X3), \
- __constant_cpu_to_le32(X4)}
-
-
-/* default power management (not Tx power) table values */
-/* for tim 0-10 */
-static struct iwl4965_power_vec_entry range_0[IWL_POWER_AC] = {
- {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
- {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
- {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0},
- {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), SLP_VEC(2, 6, 9, 9, 10)}, 0},
- {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 10)}, 1},
- {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1}
-};
-
-/* for tim > 10 */
-static struct iwl4965_power_vec_entry range_1[IWL_POWER_AC] = {
- {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
- {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500),
- SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
- {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300),
- SLP_VEC(2, 4, 6, 7, 0xFF)}, 0},
- {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100),
- SLP_VEC(2, 6, 9, 9, 0xFF)}, 0},
- {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
- {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25),
- SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
-};
-
-int iwl4965_power_init_handle(struct iwl_priv *priv)
-{
- int rc = 0, i;
- struct iwl4965_power_mgr *pow_data;
- int size = sizeof(struct iwl4965_power_vec_entry) * IWL_POWER_AC;
- u16 pci_pm;
-
- IWL_DEBUG_POWER("Initialize power \n");
-
- pow_data = &(priv->power_data);
-
- memset(pow_data, 0, sizeof(*pow_data));
-
- pow_data->active_index = IWL_POWER_RANGE_0;
- pow_data->dtim_val = 0xffff;
-
- memcpy(&pow_data->pwr_range_0[0], &range_0[0], size);
- memcpy(&pow_data->pwr_range_1[0], &range_1[0], size);
-
- rc = pci_read_config_word(priv->pci_dev, PCI_LINK_CTRL, &pci_pm);
- if (rc != 0)
- return 0;
- else {
- struct iwl4965_powertable_cmd *cmd;
-
- IWL_DEBUG_POWER("adjust power command flags\n");
-
- for (i = 0; i < IWL_POWER_AC; i++) {
- cmd = &pow_data->pwr_range_0[i].cmd;
-
- if (pci_pm & 0x1)
- cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
- else
- cmd->flags |= IWL_POWER_PCI_PM_MSK;
- }
- }
- return rc;
-}
-
-static int iwl4965_update_power_cmd(struct iwl_priv *priv,
- struct iwl4965_powertable_cmd *cmd, u32 mode)
-{
- int rc = 0, i;
- u8 skip;
- u32 max_sleep = 0;
- struct iwl4965_power_vec_entry *range;
- u8 period = 0;
- struct iwl4965_power_mgr *pow_data;
-
- if (mode > IWL_POWER_INDEX_5) {
- IWL_DEBUG_POWER("Error invalid power mode \n");
- return -1;
- }
- pow_data = &(priv->power_data);
-
- if (pow_data->active_index == IWL_POWER_RANGE_0)
- range = &pow_data->pwr_range_0[0];
- else
- range = &pow_data->pwr_range_1[1];
-
- memcpy(cmd, &range[mode].cmd, sizeof(struct iwl4965_powertable_cmd));
-
-#ifdef IWL_MAC80211_DISABLE
- if (priv->assoc_network != NULL) {
- unsigned long flags;
-
- period = priv->assoc_network->tim.tim_period;
- }
-#endif /*IWL_MAC80211_DISABLE */
- skip = range[mode].no_dtim;
-
- if (period == 0) {
- period = 1;
- skip = 0;
- }
-
- if (skip == 0) {
- max_sleep = period;
- cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
- } else {
- __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1];
- max_sleep = (le32_to_cpu(slp_itrvl) / period) * period;
- cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
- }
-
- for (i = 0; i < IWL_POWER_VEC_SIZE; i++) {
- if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep)
- cmd->sleep_interval[i] = cpu_to_le32(max_sleep);
- }
-
- IWL_DEBUG_POWER("Flags value = 0x%08X\n", cmd->flags);
- IWL_DEBUG_POWER("Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout));
- IWL_DEBUG_POWER("Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout));
- IWL_DEBUG_POWER("Sleep interval vector = { %d , %d , %d , %d , %d }\n",
- le32_to_cpu(cmd->sleep_interval[0]),
- le32_to_cpu(cmd->sleep_interval[1]),
- le32_to_cpu(cmd->sleep_interval[2]),
- le32_to_cpu(cmd->sleep_interval[3]),
- le32_to_cpu(cmd->sleep_interval[4]));
-
- return rc;
-}
-
-static int iwl4965_send_power_mode(struct iwl_priv *priv, u32 mode)
-{
- u32 uninitialized_var(final_mode);
- int rc;
- struct iwl4965_powertable_cmd cmd;
-
- /* If on battery, set to 3,
- * if plugged into AC power, set to CAM ("continuously aware mode"),
- * else user level */
- switch (mode) {
- case IWL_POWER_BATTERY:
- final_mode = IWL_POWER_INDEX_3;
- break;
- case IWL_POWER_AC:
- final_mode = IWL_POWER_MODE_CAM;
- break;
- default:
- final_mode = mode;
- break;
- }
-
- cmd.keep_alive_beacons = 0;
-
- iwl4965_update_power_cmd(priv, &cmd, final_mode);
-
- rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd);
-
- if (final_mode == IWL_POWER_MODE_CAM)
- clear_bit(STATUS_POWER_PMI, &priv->status);
- else
- set_bit(STATUS_POWER_PMI, &priv->status);
-
- return rc;
-}
-
int iwl4965_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
{
/* Filter incoming packets to determine if they are targeted toward
@@ -1584,33 +909,7 @@
return 1;
}
-#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
-static const char *iwl4965_get_tx_fail_reason(u32 status)
-{
- switch (status & TX_STATUS_MSK) {
- case TX_STATUS_SUCCESS:
- return "SUCCESS";
- TX_STATUS_ENTRY(SHORT_LIMIT);
- TX_STATUS_ENTRY(LONG_LIMIT);
- TX_STATUS_ENTRY(FIFO_UNDERRUN);
- TX_STATUS_ENTRY(MGMNT_ABORT);
- TX_STATUS_ENTRY(NEXT_FRAG);
- TX_STATUS_ENTRY(LIFE_EXPIRE);
- TX_STATUS_ENTRY(DEST_PS);
- TX_STATUS_ENTRY(ABORTED);
- TX_STATUS_ENTRY(BT_RETRY);
- TX_STATUS_ENTRY(STA_INVALID);
- TX_STATUS_ENTRY(FRAG_DROPPED);
- TX_STATUS_ENTRY(TID_DISABLE);
- TX_STATUS_ENTRY(FRAME_FLUSHED);
- TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL);
- TX_STATUS_ENTRY(TX_LOCKED);
- TX_STATUS_ENTRY(NO_BEACON_ON_RADAR);
- }
-
- return "UNKNOWN";
-}
/**
* iwl4965_scan_cancel - Cancel any currently executing HW scan
@@ -1785,8 +1084,8 @@
}
-static void iwl4965_set_flags_for_phymode(struct iwl_priv *priv,
- enum ieee80211_band band)
+static void iwl_set_flags_for_band(struct iwl_priv *priv,
+ enum ieee80211_band band)
{
if (band == IEEE80211_BAND_5GHZ) {
priv->staging_rxon.flags &=
@@ -1871,7 +1170,7 @@
priv->staging_rxon.channel = cpu_to_le16(ch_info->channel);
priv->band = ch_info->band;
- iwl4965_set_flags_for_phymode(priv, priv->band);
+ iwl_set_flags_for_band(priv, priv->band);
priv->staging_rxon.ofdm_basic_rates =
(IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
@@ -1884,7 +1183,7 @@
memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN);
priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff;
priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff;
- iwl4965_set_rxon_chain(priv);
+ iwl_set_rxon_chain(priv);
}
static int iwl4965_set_mode(struct iwl_priv *priv, int mode)
@@ -1926,448 +1225,13 @@
return 0;
}
-static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
- struct ieee80211_tx_control *ctl,
- struct iwl_cmd *cmd,
- struct sk_buff *skb_frag,
- int sta_id)
-{
- struct iwl4965_hw_key *keyinfo = &priv->stations[sta_id].keyinfo;
- struct iwl_wep_key *wepkey;
- int keyidx = 0;
-
- BUG_ON(ctl->key_idx > 3);
-
- switch (keyinfo->alg) {
- case ALG_CCMP:
- cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM;
- memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen);
- if (ctl->flags & IEEE80211_TXCTL_AMPDU)
- cmd->cmd.tx.tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK;
- IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n");
- break;
-
- case ALG_TKIP:
- cmd->cmd.tx.sec_ctl = TX_CMD_SEC_TKIP;
- ieee80211_get_tkip_key(keyinfo->conf, skb_frag,
- IEEE80211_TKIP_P2_KEY, cmd->cmd.tx.key);
- IWL_DEBUG_TX("tx_cmd with tkip hwcrypto\n");
- break;
-
- case ALG_WEP:
- wepkey = &priv->wep_keys[ctl->key_idx];
- cmd->cmd.tx.sec_ctl = 0;
- if (priv->default_wep_key) {
- /* the WEP key was sent as static */
- keyidx = ctl->key_idx;
- memcpy(&cmd->cmd.tx.key[3], wepkey->key,
- wepkey->key_size);
- if (wepkey->key_size == WEP_KEY_LEN_128)
- cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128;
- } else {
- /* the WEP key was sent as dynamic */
- keyidx = keyinfo->keyidx;
- memcpy(&cmd->cmd.tx.key[3], keyinfo->key,
- keyinfo->keylen);
- if (keyinfo->keylen == WEP_KEY_LEN_128)
- cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128;
- }
-
- cmd->cmd.tx.sec_ctl |= (TX_CMD_SEC_WEP |
- (keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT);
-
- IWL_DEBUG_TX("Configuring packet for WEP encryption "
- "with key %d\n", keyidx);
- break;
-
- default:
- printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg);
- break;
- }
-}
-
-/*
- * handle build REPLY_TX command notification.
- */
-static void iwl4965_build_tx_cmd_basic(struct iwl_priv *priv,
- struct iwl_cmd *cmd,
- struct ieee80211_tx_control *ctrl,
- struct ieee80211_hdr *hdr,
- int is_unicast, u8 std_id)
-{
- __le16 *qc;
- u16 fc = le16_to_cpu(hdr->frame_control);
- __le32 tx_flags = cmd->cmd.tx.tx_flags;
-
- cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
- if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) {
- tx_flags |= TX_CMD_FLG_ACK_MSK;
- if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)
- tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
- if (ieee80211_is_probe_response(fc) &&
- !(le16_to_cpu(hdr->seq_ctrl) & 0xf))
- tx_flags |= TX_CMD_FLG_TSF_MSK;
- } else {
- tx_flags &= (~TX_CMD_FLG_ACK_MSK);
- tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
- }
-
- if (ieee80211_is_back_request(fc))
- tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK;
-
-
- cmd->cmd.tx.sta_id = std_id;
- if (ieee80211_get_morefrag(hdr))
- tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
-
- qc = ieee80211_get_qos_ctrl(hdr);
- if (qc) {
- cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf);
- tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
- } else
- tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
-
- if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
- tx_flags |= TX_CMD_FLG_RTS_MSK;
- tx_flags &= ~TX_CMD_FLG_CTS_MSK;
- } else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
- tx_flags &= ~TX_CMD_FLG_RTS_MSK;
- tx_flags |= TX_CMD_FLG_CTS_MSK;
- }
-
- if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
- tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
-
- tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
- if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
- if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ ||
- (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ)
- cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(3);
- else
- cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(2);
- } else {
- cmd->cmd.tx.timeout.pm_frame_timeout = 0;
- }
-
- cmd->cmd.tx.driver_txop = 0;
- cmd->cmd.tx.tx_flags = tx_flags;
- cmd->cmd.tx.next_frame_len = 0;
-}
-static void iwl_update_tx_stats(struct iwl_priv *priv, u16 fc, u16 len)
-{
- /* 0 - mgmt, 1 - cnt, 2 - data */
- int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2;
- priv->tx_stats[idx].cnt++;
- priv->tx_stats[idx].bytes += len;
-}
-/**
- * iwl4965_get_sta_id - Find station's index within station table
- *
- * If new IBSS station, create new entry in station table
- */
-static int iwl4965_get_sta_id(struct iwl_priv *priv,
- struct ieee80211_hdr *hdr)
-{
- int sta_id;
- u16 fc = le16_to_cpu(hdr->frame_control);
- DECLARE_MAC_BUF(mac);
-
- /* If this frame is broadcast or management, use broadcast station id */
- if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
- is_multicast_ether_addr(hdr->addr1))
- return priv->hw_params.bcast_sta_id;
-
- switch (priv->iw_mode) {
-
- /* If we are a client station in a BSS network, use the special
- * AP station entry (that's the only station we communicate with) */
- case IEEE80211_IF_TYPE_STA:
- return IWL_AP_ID;
-
- /* If we are an AP, then find the station, or use BCAST */
- case IEEE80211_IF_TYPE_AP:
- sta_id = iwl4965_hw_find_station(priv, hdr->addr1);
- if (sta_id != IWL_INVALID_STATION)
- return sta_id;
- return priv->hw_params.bcast_sta_id;
-
- /* If this frame is going out to an IBSS network, find the station,
- * or create a new station table entry */
- case IEEE80211_IF_TYPE_IBSS:
- sta_id = iwl4965_hw_find_station(priv, hdr->addr1);
- if (sta_id != IWL_INVALID_STATION)
- return sta_id;
-
- /* Create new station table entry */
- sta_id = iwl4965_add_station_flags(priv, hdr->addr1,
- 0, CMD_ASYNC, NULL);
-
- if (sta_id != IWL_INVALID_STATION)
- return sta_id;
-
- IWL_DEBUG_DROP("Station %s not in station map. "
- "Defaulting to broadcast...\n",
- print_mac(mac, hdr->addr1));
- iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
- return priv->hw_params.bcast_sta_id;
-
- default:
- IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode);
- return priv->hw_params.bcast_sta_id;
- }
-}
-
-/*
- * start REPLY_TX command process
- */
-static int iwl4965_tx_skb(struct iwl_priv *priv,
- struct sk_buff *skb, struct ieee80211_tx_control *ctl)
-{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- struct iwl4965_tfd_frame *tfd;
- u32 *control_flags;
- int txq_id = ctl->queue;
- struct iwl4965_tx_queue *txq = NULL;
- struct iwl4965_queue *q = NULL;
- dma_addr_t phys_addr;
- dma_addr_t txcmd_phys;
- dma_addr_t scratch_phys;
- struct iwl_cmd *out_cmd = NULL;
- u16 len, idx, len_org;
- u8 id, hdr_len, unicast;
- u8 sta_id;
- u16 seq_number = 0;
- u16 fc;
- __le16 *qc;
- u8 wait_write_ptr = 0;
- unsigned long flags;
- int rc;
-
- spin_lock_irqsave(&priv->lock, flags);
- if (iwl_is_rfkill(priv)) {
- IWL_DEBUG_DROP("Dropping - RF KILL\n");
- goto drop_unlock;
- }
-
- if (!priv->vif) {
- IWL_DEBUG_DROP("Dropping - !priv->vif\n");
- goto drop_unlock;
- }
-
- if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) {
- IWL_ERROR("ERROR: No TX rate available.\n");
- goto drop_unlock;
- }
-
- unicast = !is_multicast_ether_addr(hdr->addr1);
- id = 0;
-
- fc = le16_to_cpu(hdr->frame_control);
-
-#ifdef CONFIG_IWLWIFI_DEBUG
- if (ieee80211_is_auth(fc))
- IWL_DEBUG_TX("Sending AUTH frame\n");
- else if (ieee80211_is_assoc_request(fc))
- IWL_DEBUG_TX("Sending ASSOC frame\n");
- else if (ieee80211_is_reassoc_request(fc))
- IWL_DEBUG_TX("Sending REASSOC frame\n");
-#endif
-
- /* drop all data frame if we are not associated */
- if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
- (!iwl_is_associated(priv) ||
- ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id) ||
- !priv->assoc_station_added)) {
- IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n");
- goto drop_unlock;
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- hdr_len = ieee80211_get_hdrlen(fc);
-
- /* Find (or create) index into station table for destination station */
- sta_id = iwl4965_get_sta_id(priv, hdr);
- if (sta_id == IWL_INVALID_STATION) {
- DECLARE_MAC_BUF(mac);
-
- IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n",
- print_mac(mac, hdr->addr1));
- goto drop;
- }
-
- IWL_DEBUG_RATE("station Id %d\n", sta_id);
-
- qc = ieee80211_get_qos_ctrl(hdr);
- if (qc) {
- u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
- seq_number = priv->stations[sta_id].tid[tid].seq_number &
- IEEE80211_SCTL_SEQ;
- hdr->seq_ctrl = cpu_to_le16(seq_number) |
- (hdr->seq_ctrl &
- __constant_cpu_to_le16(IEEE80211_SCTL_FRAG));
- seq_number += 0x10;
-#ifdef CONFIG_IWL4965_HT
- /* aggregation is on for this <sta,tid> */
- if (ctl->flags & IEEE80211_TXCTL_AMPDU)
- txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
- priv->stations[sta_id].tid[tid].tfds_in_queue++;
-#endif /* CONFIG_IWL4965_HT */
- }
-
- /* Descriptor for chosen Tx queue */
- txq = &priv->txq[txq_id];
- q = &txq->q;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- /* Set up first empty TFD within this queue's circular TFD buffer */
- tfd = &txq->bd[q->write_ptr];
- memset(tfd, 0, sizeof(*tfd));
- control_flags = (u32 *) tfd;
- idx = get_cmd_index(q, q->write_ptr, 0);
-
- /* Set up driver data for this TFD */
- memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl4965_tx_info));
- txq->txb[q->write_ptr].skb[0] = skb;
- memcpy(&(txq->txb[q->write_ptr].status.control),
- ctl, sizeof(struct ieee80211_tx_control));
-
- /* Set up first empty entry in queue's array of Tx/cmd buffers */
- out_cmd = &txq->cmd[idx];
- memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
- memset(&out_cmd->cmd.tx, 0, sizeof(out_cmd->cmd.tx));
-
- /*
- * Set up the Tx-command (not MAC!) header.
- * Store the chosen Tx queue and TFD index within the sequence field;
- * after Tx, uCode's Tx response will return this value so driver can
- * locate the frame within the tx queue and do post-tx processing.
- */
- out_cmd->hdr.cmd = REPLY_TX;
- out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
- INDEX_TO_SEQ(q->write_ptr)));
-
- /* Copy MAC header from skb into command buffer */
- memcpy(out_cmd->cmd.tx.hdr, hdr, hdr_len);
-
- /*
- * Use the first empty entry in this queue's command buffer array
- * to contain the Tx command and MAC header concatenated together
- * (payload data will be in another buffer).
- * Size of this varies, due to varying MAC header length.
- * If end is not dword aligned, we'll have 2 extra bytes at the end
- * of the MAC header (device reads on dword boundaries).
- * We'll tell device about this padding later.
- */
- len = priv->hw_params.tx_cmd_len +
- sizeof(struct iwl_cmd_header) + hdr_len;
-
- len_org = len;
- len = (len + 3) & ~3;
-
- if (len_org != len)
- len_org = 1;
- else
- len_org = 0;
-
- /* Physical address of this Tx command's header (not MAC header!),
- * within command buffer array. */
- txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx +
- offsetof(struct iwl_cmd, hdr);
-
- /* Add buffer containing Tx command and MAC(!) header to TFD's
- * first entry */
- iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
-
- if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
- iwl4965_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, sta_id);
-
- /* Set up TFD's 2nd entry to point directly to remainder of skb,
- * if any (802.11 null frames have no payload). */
- len = skb->len - hdr_len;
- if (len) {
- phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
- len, PCI_DMA_TODEVICE);
- iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len);
- }
-
- /* Tell 4965 about any 2-byte padding after MAC header */
- if (len_org)
- out_cmd->cmd.tx.tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
-
- /* Total # bytes to be transmitted */
- len = (u16)skb->len;
- out_cmd->cmd.tx.len = cpu_to_le16(len);
-
- /* TODO need this for burst mode later on */
- iwl4965_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id);
-
- /* set is_hcca to 0; it probably will never be implemented */
- iwl4965_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0);
-
- iwl_update_tx_stats(priv, fc, len);
-
- scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
- offsetof(struct iwl4965_tx_cmd, scratch);
- out_cmd->cmd.tx.dram_lsb_ptr = cpu_to_le32(scratch_phys);
- out_cmd->cmd.tx.dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys);
-
- if (!ieee80211_get_morefrag(hdr)) {
- txq->need_update = 1;
- if (qc) {
- u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
- priv->stations[sta_id].tid[tid].seq_number = seq_number;
- }
- } else {
- wait_write_ptr = 1;
- txq->need_update = 0;
- }
-
- iwl_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload,
- sizeof(out_cmd->cmd.tx));
-
- iwl_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr,
- ieee80211_get_hdrlen(fc));
-
- /* Set up entry for this TFD in Tx byte-count array */
- priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, len);
-
- /* Tell device the write index *just past* this latest filled TFD */
- q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
- rc = iwl4965_tx_queue_update_write_ptr(priv, txq);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- if (rc)
- return rc;
-
- if ((iwl4965_queue_space(q) < q->high_mark)
- && priv->mac80211_registered) {
- if (wait_write_ptr) {
- spin_lock_irqsave(&priv->lock, flags);
- txq->need_update = 1;
- iwl4965_tx_queue_update_write_ptr(priv, txq);
- spin_unlock_irqrestore(&priv->lock, flags);
- }
-
- ieee80211_stop_queue(priv->hw, ctl->queue);
- }
-
- return 0;
-
-drop_unlock:
- spin_unlock_irqrestore(&priv->lock, flags);
-drop:
- return -1;
-}
-
static void iwl4965_set_rate(struct iwl_priv *priv)
{
const struct ieee80211_supported_band *hw = NULL;
struct ieee80211_rate *rate;
int i;
- hw = iwl4965_get_hw_mode(priv, priv->band);
+ 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 +1330,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)
@@ -2629,7 +1454,7 @@
u8 type)
{
struct iwl4965_spectrum_cmd spectrum;
- struct iwl4965_rx_packet *res;
+ struct iwl_rx_packet *res;
struct iwl_host_cmd cmd = {
.id = REPLY_SPECTRUM_MEASUREMENT_CMD,
.data = (void *)&spectrum,
@@ -2674,7 +1499,7 @@
if (rc)
return rc;
- res = (struct iwl4965_rx_packet *)cmd.meta.u.skb->data;
+ res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n");
rc = -EIO;
@@ -2704,351 +1529,16 @@
}
#endif
-static void iwl4965_txstatus_to_ieee(struct iwl_priv *priv,
- struct iwl4965_tx_info *tx_sta)
-{
-
- tx_sta->status.ack_signal = 0;
- tx_sta->status.excessive_retries = 0;
- tx_sta->status.queue_length = 0;
- tx_sta->status.queue_number = 0;
-
- if (in_interrupt())
- ieee80211_tx_status_irqsafe(priv->hw,
- tx_sta->skb[0], &(tx_sta->status));
- else
- ieee80211_tx_status(priv->hw,
- tx_sta->skb[0], &(tx_sta->status));
-
- tx_sta->skb[0] = NULL;
-}
-
-/**
- * iwl4965_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd
- *
- * When FW advances 'R' index, all entries between old and new 'R' index
- * need to be reclaimed. As result, some free space forms. If there is
- * enough free space (> low mark), wake the stack that feeds us.
- */
-int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
-{
- struct iwl4965_tx_queue *txq = &priv->txq[txq_id];
- struct iwl4965_queue *q = &txq->q;
- int nfreed = 0;
-
- if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) {
- IWL_ERROR("Read index for DMA queue txq id (%d), index %d, "
- "is out of range [0-%d] %d %d.\n", txq_id,
- index, q->n_bd, q->write_ptr, q->read_ptr);
- return 0;
- }
-
- for (index = iwl_queue_inc_wrap(index, q->n_bd);
- q->read_ptr != index;
- q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
- if (txq_id != IWL_CMD_QUEUE_NUM) {
- iwl4965_txstatus_to_ieee(priv,
- &(txq->txb[txq->q.read_ptr]));
- iwl4965_hw_txq_free_tfd(priv, txq);
- } else if (nfreed > 1) {
- IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index,
- q->write_ptr, q->read_ptr);
- queue_work(priv->workqueue, &priv->restart);
- }
- nfreed++;
- }
-
-/* if (iwl4965_queue_space(q) > q->low_mark && (txq_id >= 0) &&
- (txq_id != IWL_CMD_QUEUE_NUM) &&
- priv->mac80211_registered)
- ieee80211_wake_queue(priv->hw, txq_id); */
-
-
- return nfreed;
-}
-
-static int iwl4965_is_tx_success(u32 status)
-{
- status &= TX_STATUS_MSK;
- return (status == TX_STATUS_SUCCESS)
- || (status == TX_STATUS_DIRECT_DONE);
-}
-
/******************************************************************************
*
* Generic RX handler implementations
*
******************************************************************************/
-#ifdef CONFIG_IWL4965_HT
-
-static inline int iwl4965_get_ra_sta_id(struct iwl_priv *priv,
- struct ieee80211_hdr *hdr)
+static void iwl_rx_reply_alive(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
{
- if (priv->iw_mode == IEEE80211_IF_TYPE_STA)
- return IWL_AP_ID;
- else {
- u8 *da = ieee80211_get_DA(hdr);
- return iwl4965_hw_find_station(priv, da);
- }
-}
-
-static struct ieee80211_hdr *iwl4965_tx_queue_get_hdr(
- struct iwl_priv *priv, int txq_id, int idx)
-{
- if (priv->txq[txq_id].txb[idx].skb[0])
- return (struct ieee80211_hdr *)priv->txq[txq_id].
- txb[idx].skb[0]->data;
- return NULL;
-}
-
-static inline u32 iwl4965_get_scd_ssn(struct iwl4965_tx_resp *tx_resp)
-{
- __le32 *scd_ssn = (__le32 *)((u32 *)&tx_resp->status +
- tx_resp->frame_count);
- return le32_to_cpu(*scd_ssn) & MAX_SN;
-
-}
-
-/**
- * iwl4965_tx_status_reply_tx - Handle Tx rspnse for frames in aggregation queue
- */
-static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
- struct iwl4965_ht_agg *agg,
- struct iwl4965_tx_resp_agg *tx_resp,
- u16 start_idx)
-{
- u16 status;
- struct agg_tx_status *frame_status = &tx_resp->status;
- struct ieee80211_tx_status *tx_status = NULL;
- struct ieee80211_hdr *hdr = NULL;
- int i, sh;
- int txq_id, idx;
- u16 seq;
-
- if (agg->wait_for_ba)
- IWL_DEBUG_TX_REPLY("got tx response w/o block-ack\n");
-
- agg->frame_count = tx_resp->frame_count;
- agg->start_idx = start_idx;
- agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
- agg->bitmap = 0;
-
- /* # frames attempted by Tx command */
- if (agg->frame_count == 1) {
- /* Only one frame was attempted; no block-ack will arrive */
- status = le16_to_cpu(frame_status[0].status);
- seq = le16_to_cpu(frame_status[0].sequence);
- idx = SEQ_TO_INDEX(seq);
- txq_id = SEQ_TO_QUEUE(seq);
-
- /* FIXME: code repetition */
- IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d idx=%d\n",
- agg->frame_count, agg->start_idx, idx);
-
- tx_status = &(priv->txq[txq_id].txb[idx].status);
- tx_status->retry_count = tx_resp->failure_frame;
- tx_status->queue_number = status & 0xff;
- tx_status->queue_length = tx_resp->failure_rts;
- tx_status->control.flags &= ~IEEE80211_TXCTL_AMPDU;
- tx_status->flags = iwl4965_is_tx_success(status)?
- IEEE80211_TX_STATUS_ACK : 0;
- iwl4965_hwrate_to_tx_control(priv,
- le32_to_cpu(tx_resp->rate_n_flags),
- &tx_status->control);
- /* FIXME: code repetition end */
-
- IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n",
- status & 0xff, tx_resp->failure_frame);
- IWL_DEBUG_TX_REPLY("Rate Info rate_n_flags=%x\n",
- iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags));
-
- agg->wait_for_ba = 0;
- } else {
- /* Two or more frames were attempted; expect block-ack */
- u64 bitmap = 0;
- int start = agg->start_idx;
-
- /* Construct bit-map of pending frames within Tx window */
- for (i = 0; i < agg->frame_count; i++) {
- u16 sc;
- status = le16_to_cpu(frame_status[i].status);
- seq = le16_to_cpu(frame_status[i].sequence);
- idx = SEQ_TO_INDEX(seq);
- txq_id = SEQ_TO_QUEUE(seq);
-
- if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
- AGG_TX_STATE_ABORT_MSK))
- continue;
-
- IWL_DEBUG_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n",
- agg->frame_count, txq_id, idx);
-
- hdr = iwl4965_tx_queue_get_hdr(priv, txq_id, idx);
-
- sc = le16_to_cpu(hdr->seq_ctrl);
- if (idx != (SEQ_TO_SN(sc) & 0xff)) {
- IWL_ERROR("BUG_ON idx doesn't match seq control"
- " idx=%d, seq_idx=%d, seq=%d\n",
- idx, SEQ_TO_SN(sc),
- hdr->seq_ctrl);
- return -1;
- }
-
- IWL_DEBUG_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n",
- i, idx, SEQ_TO_SN(sc));
-
- sh = idx - start;
- if (sh > 64) {
- sh = (start - idx) + 0xff;
- bitmap = bitmap << sh;
- sh = 0;
- start = idx;
- } else if (sh < -64)
- sh = 0xff - (start - idx);
- else if (sh < 0) {
- sh = start - idx;
- start = idx;
- bitmap = bitmap << sh;
- sh = 0;
- }
- bitmap |= (1 << sh);
- IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%x\n",
- start, (u32)(bitmap & 0xFFFFFFFF));
- }
-
- agg->bitmap = bitmap;
- agg->start_idx = start;
- agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
- IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%llx\n",
- agg->frame_count, agg->start_idx,
- (unsigned long long)agg->bitmap);
-
- if (bitmap)
- agg->wait_for_ba = 1;
- }
- return 0;
-}
-#endif
-
-/**
- * iwl4965_rx_reply_tx - Handle standard (non-aggregation) Tx response
- */
-static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
- struct iwl4965_rx_mem_buffer *rxb)
-{
- struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
- u16 sequence = le16_to_cpu(pkt->hdr.sequence);
- int txq_id = SEQ_TO_QUEUE(sequence);
- int index = SEQ_TO_INDEX(sequence);
- struct iwl4965_tx_queue *txq = &priv->txq[txq_id];
- struct ieee80211_tx_status *tx_status;
- struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
- u32 status = le32_to_cpu(tx_resp->status);
-#ifdef CONFIG_IWL4965_HT
- int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION;
- struct ieee80211_hdr *hdr;
- __le16 *qc;
-#endif
-
- if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) {
- IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
- "is out of range [0-%d] %d %d\n", txq_id,
- index, txq->q.n_bd, txq->q.write_ptr,
- txq->q.read_ptr);
- return;
- }
-
-#ifdef CONFIG_IWL4965_HT
- hdr = iwl4965_tx_queue_get_hdr(priv, txq_id, index);
- qc = ieee80211_get_qos_ctrl(hdr);
-
- if (qc)
- tid = le16_to_cpu(*qc) & 0xf;
-
- sta_id = iwl4965_get_ra_sta_id(priv, hdr);
- if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) {
- IWL_ERROR("Station not known\n");
- return;
- }
-
- if (txq->sched_retry) {
- const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp);
- struct iwl4965_ht_agg *agg = NULL;
-
- if (!qc)
- return;
-
- agg = &priv->stations[sta_id].tid[tid].agg;
-
- iwl4965_tx_status_reply_tx(priv, agg,
- (struct iwl4965_tx_resp_agg *)tx_resp, index);
-
- if ((tx_resp->frame_count == 1) &&
- !iwl4965_is_tx_success(status)) {
- /* TODO: send BAR */
- }
-
- if (txq->q.read_ptr != (scd_ssn & 0xff)) {
- int freed;
- index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
- IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn "
- "%d index %d\n", scd_ssn , index);
- freed = iwl4965_tx_queue_reclaim(priv, txq_id, index);
- priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
-
- if (iwl4965_queue_space(&txq->q) > txq->q.low_mark &&
- txq_id >= 0 && priv->mac80211_registered &&
- agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)
- ieee80211_wake_queue(priv->hw, txq_id);
-
- iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id);
- }
- } else {
-#endif /* CONFIG_IWL4965_HT */
- tx_status = &(txq->txb[txq->q.read_ptr].status);
-
- tx_status->retry_count = tx_resp->failure_frame;
- tx_status->queue_number = status;
- tx_status->queue_length = tx_resp->bt_kill_count;
- tx_status->queue_length |= tx_resp->failure_rts;
- tx_status->flags =
- iwl4965_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0;
- iwl4965_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags),
- &tx_status->control);
-
- IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x "
- "retries %d\n", txq_id, iwl4965_get_tx_fail_reason(status),
- status, le32_to_cpu(tx_resp->rate_n_flags),
- tx_resp->failure_frame);
-
- IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
- if (index != -1) {
- int freed = iwl4965_tx_queue_reclaim(priv, txq_id, index);
-#ifdef CONFIG_IWL4965_HT
- if (tid != MAX_TID_COUNT)
- priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
- if (iwl4965_queue_space(&txq->q) > txq->q.low_mark &&
- (txq_id >= 0) &&
- priv->mac80211_registered)
- ieee80211_wake_queue(priv->hw, txq_id);
- if (tid != MAX_TID_COUNT)
- iwl4965_check_empty_hw_queue(priv, sta_id, tid, txq_id);
-#endif
- }
-#ifdef CONFIG_IWL4965_HT
- }
-#endif /* CONFIG_IWL4965_HT */
-
- if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
- IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n");
-}
-
-
-static void iwl4965_rx_reply_alive(struct iwl_priv *priv,
- struct iwl4965_rx_mem_buffer *rxb)
-{
- struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
- struct iwl4965_alive_resp *palive;
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_alive_resp *palive;
struct delayed_work *pwork;
palive = &pkt->u.alive_frame;
@@ -3062,12 +1552,12 @@
IWL_DEBUG_INFO("Initialization Alive received.\n");
memcpy(&priv->card_alive_init,
&pkt->u.alive_frame,
- sizeof(struct iwl4965_init_alive_resp));
+ sizeof(struct iwl_init_alive_resp));
pwork = &priv->init_alive_start;
} else {
IWL_DEBUG_INFO("Runtime Alive received.\n");
memcpy(&priv->card_alive, &pkt->u.alive_frame,
- sizeof(struct iwl4965_alive_resp));
+ sizeof(struct iwl_alive_resp));
pwork = &priv->alive_start;
}
@@ -3080,19 +1570,10 @@
IWL_WARNING("uCode did not respond OK.\n");
}
-static void iwl4965_rx_reply_add_sta(struct iwl_priv *priv,
- struct iwl4965_rx_mem_buffer *rxb)
-{
- struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
-
- IWL_DEBUG_RX("Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status);
- return;
-}
-
static void iwl4965_rx_reply_error(struct iwl_priv *priv,
- struct iwl4965_rx_mem_buffer *rxb)
+ struct iwl_rx_mem_buffer *rxb)
{
- struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) "
"seq 0x%04X ser 0x%08X\n",
@@ -3105,10 +1586,10 @@
#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
-static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl4965_rx_mem_buffer *rxb)
+static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
{
- struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
- struct iwl4965_rxon_cmd *rxon = (void *)&priv->active_rxon;
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon;
struct iwl4965_csa_notification *csa = &(pkt->u.csa_notif);
IWL_DEBUG_11H("CSA notif: channel %d, status %d\n",
le16_to_cpu(csa->channel), le32_to_cpu(csa->status));
@@ -3117,15 +1598,15 @@
}
static void iwl4965_rx_spectrum_measure_notif(struct iwl_priv *priv,
- struct iwl4965_rx_mem_buffer *rxb)
+ struct iwl_rx_mem_buffer *rxb)
{
#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
- struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
struct iwl4965_spectrum_notification *report = &(pkt->u.spectrum_notif);
if (!report->state) {
- IWL_DEBUG(IWL_DL_11H | IWL_DL_INFO,
- "Spectrum Measure Notification: Start\n");
+ IWL_DEBUG(IWL_DL_11H,
+ "Spectrum Measure Notification: Start\n");
return;
}
@@ -3135,10 +1616,10 @@
}
static void iwl4965_rx_pm_sleep_notif(struct iwl_priv *priv,
- struct iwl4965_rx_mem_buffer *rxb)
+ struct iwl_rx_mem_buffer *rxb)
{
#ifdef CONFIG_IWLWIFI_DEBUG
- struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
struct iwl4965_sleep_notification *sleep = &(pkt->u.sleep_notif);
IWL_DEBUG_RX("sleep mode: %d, src: %d\n",
sleep->pm_sleep_mode, sleep->pm_wakeup_src);
@@ -3146,13 +1627,13 @@
}
static void iwl4965_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
- struct iwl4965_rx_mem_buffer *rxb)
+ struct iwl_rx_mem_buffer *rxb)
{
- struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
IWL_DEBUG_RADIO("Dumping %d bytes of unhandled "
"notification for %s:\n",
le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
- iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
+ iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
}
static void iwl4965_bg_beacon_update(struct work_struct *work)
@@ -3162,7 +1643,7 @@
struct sk_buff *beacon;
/* Pull updated AP beacon from mac80211. will fail if not in AP mode */
- beacon = ieee80211_beacon_get(priv->hw, priv->vif, NULL);
+ beacon = ieee80211_beacon_get(priv->hw, priv->vif);
if (!beacon) {
IWL_ERROR("update beacon failed\n");
@@ -3181,10 +1662,10 @@
}
static void iwl4965_rx_beacon_notif(struct iwl_priv *priv,
- struct iwl4965_rx_mem_buffer *rxb)
+ struct iwl_rx_mem_buffer *rxb)
{
#ifdef CONFIG_IWLWIFI_DEBUG
- struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
struct iwl4965_beacon_notif *beacon = &(pkt->u.beacon_status);
u8 rate = iwl4965_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
@@ -3204,10 +1685,10 @@
/* Service response to REPLY_SCAN_CMD (0x80) */
static void iwl4965_rx_reply_scan(struct iwl_priv *priv,
- struct iwl4965_rx_mem_buffer *rxb)
+ struct iwl_rx_mem_buffer *rxb)
{
#ifdef CONFIG_IWLWIFI_DEBUG
- struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
struct iwl4965_scanreq_notification *notif =
(struct iwl4965_scanreq_notification *)pkt->u.raw;
@@ -3217,9 +1698,9 @@
/* Service SCAN_START_NOTIFICATION (0x82) */
static void iwl4965_rx_scan_start_notif(struct iwl_priv *priv,
- struct iwl4965_rx_mem_buffer *rxb)
+ struct iwl_rx_mem_buffer *rxb)
{
- struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
struct iwl4965_scanstart_notification *notif =
(struct iwl4965_scanstart_notification *)pkt->u.raw;
priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
@@ -3234,9 +1715,9 @@
/* Service SCAN_RESULTS_NOTIFICATION (0x83) */
static void iwl4965_rx_scan_results_notif(struct iwl_priv *priv,
- struct iwl4965_rx_mem_buffer *rxb)
+ struct iwl_rx_mem_buffer *rxb)
{
- struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
struct iwl4965_scanresults_notification *notif =
(struct iwl4965_scanresults_notification *)pkt->u.raw;
@@ -3259,9 +1740,9 @@
/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
static void iwl4965_rx_scan_complete_notif(struct iwl_priv *priv,
- struct iwl4965_rx_mem_buffer *rxb)
+ struct iwl_rx_mem_buffer *rxb)
{
- struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
struct iwl4965_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
@@ -3317,9 +1798,9 @@
/* Handle notification from uCode that card's power state is changing
* due to software, hardware, or critical temperature RFKILL */
static void iwl4965_rx_card_state_notif(struct iwl_priv *priv,
- struct iwl4965_rx_mem_buffer *rxb)
+ struct iwl_rx_mem_buffer *rxb)
{
- struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
unsigned long status = priv->status;
@@ -3385,6 +1866,17 @@
wake_up_interruptible(&priv->wait_command_queue);
}
+/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD).
+ * This will be used later in iwl4965_rx_reply_rx() for REPLY_RX_MPDU_CMD. */
+static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ priv->last_phy_res[0] = 1;
+ memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]),
+ sizeof(struct iwl4965_rx_phy_res));
+}
+
/**
* iwl4965_setup_rx_handlers - Initialize Rx handler callbacks
*
@@ -3396,8 +1888,7 @@
*/
static void iwl4965_setup_rx_handlers(struct iwl_priv *priv)
{
- priv->rx_handlers[REPLY_ALIVE] = iwl4965_rx_reply_alive;
- priv->rx_handlers[REPLY_ADD_STA] = iwl4965_rx_reply_add_sta;
+ priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive;
priv->rx_handlers[REPLY_ERROR] = iwl4965_rx_reply_error;
priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl4965_rx_csa;
priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
@@ -3414,408 +1905,150 @@
*/
priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl4965_hw_rx_statistics;
priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl4965_hw_rx_statistics;
-
+ /* scan handlers */
priv->rx_handlers[REPLY_SCAN_CMD] = iwl4965_rx_reply_scan;
priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl4965_rx_scan_start_notif;
priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] =
iwl4965_rx_scan_results_notif;
priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] =
iwl4965_rx_scan_complete_notif;
+ /* status change handler */
priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl4965_rx_card_state_notif;
- priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx;
+ priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] =
+ iwl_rx_missed_beacon_notif;
+ /* Rx handlers */
+ priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl4965_rx_reply_rx_phy;
+ priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl4965_rx_reply_rx;
/* Set up hardware specific Rx handlers */
- iwl4965_hw_rx_handler_setup(priv);
-}
-
-/**
- * iwl4965_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
- * @rxb: Rx buffer to reclaim
- *
- * If an Rx buffer has an async callback associated with it the callback
- * will be executed. The attached skb (if present) will only be freed
- * if the callback returns 1
- */
-static void iwl4965_tx_cmd_complete(struct iwl_priv *priv,
- struct iwl4965_rx_mem_buffer *rxb)
-{
- struct iwl4965_rx_packet *pkt = (struct iwl4965_rx_packet *)rxb->skb->data;
- u16 sequence = le16_to_cpu(pkt->hdr.sequence);
- int txq_id = SEQ_TO_QUEUE(sequence);
- int index = SEQ_TO_INDEX(sequence);
- int huge = sequence & SEQ_HUGE_FRAME;
- int cmd_index;
- struct iwl_cmd *cmd;
-
- /* If a Tx command is being handled and it isn't in the actual
- * command queue then there a command routing bug has been introduced
- * in the queue management code. */
- if (txq_id != IWL_CMD_QUEUE_NUM)
- IWL_ERROR("Error wrong command queue %d command id 0x%X\n",
- txq_id, pkt->hdr.cmd);
- BUG_ON(txq_id != IWL_CMD_QUEUE_NUM);
-
- cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
- cmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
-
- /* Input error checking is done when commands are added to queue. */
- if (cmd->meta.flags & CMD_WANT_SKB) {
- cmd->meta.source->u.skb = rxb->skb;
- rxb->skb = NULL;
- } else if (cmd->meta.u.callback &&
- !cmd->meta.u.callback(priv, cmd, rxb->skb))
- rxb->skb = NULL;
-
- iwl4965_tx_queue_reclaim(priv, txq_id, index);
-
- if (!(cmd->meta.flags & CMD_ASYNC)) {
- clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
- wake_up_interruptible(&priv->wait_command_queue);
- }
-}
-
-/************************** RX-FUNCTIONS ****************************/
-/*
- * Rx theory of operation
- *
- * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs),
- * each of which point to Receive Buffers to be filled by 4965. These get
- * used not only for Rx frames, but for any command response or notification
- * from the 4965. The driver and 4965 manage the Rx buffers by means
- * of indexes into the circular buffer.
- *
- * Rx Queue Indexes
- * The host/firmware share two index registers for managing the Rx buffers.
- *
- * The READ index maps to the first position that the firmware may be writing
- * to -- the driver can read up to (but not including) this position and get
- * good data.
- * The READ index is managed by the firmware once the card is enabled.
- *
- * The WRITE index maps to the last position the driver has read from -- the
- * position preceding WRITE is the last slot the firmware can place a packet.
- *
- * The queue is empty (no good data) if WRITE = READ - 1, and is full if
- * WRITE = READ.
- *
- * During initialization, the host sets up the READ queue position to the first
- * INDEX position, and WRITE to the last (READ - 1 wrapped)
- *
- * When the firmware places a packet in a buffer, it will advance the READ index
- * and fire the RX interrupt. The driver can then query the READ index and
- * process as many packets as possible, moving the WRITE index forward as it
- * resets the Rx queue buffers with new memory.
- *
- * The management in the driver is as follows:
- * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When
- * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
- * to replenish the iwl->rxq->rx_free.
- * + In iwl4965_rx_replenish (scheduled) if 'processed' != 'read' then the
- * iwl->rxq is replenished and the READ INDEX is updated (updating the
- * 'processed' and 'read' driver indexes as well)
- * + A received packet is processed and handed to the kernel network stack,
- * detached from the iwl->rxq. The driver 'processed' index is updated.
- * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free
- * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ
- * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there
- * were enough free buffers and RX_STALLED is set it is cleared.
- *
- *
- * Driver sequence:
- *
- * iwl4965_rx_queue_alloc() Allocates rx_free
- * iwl4965_rx_replenish() Replenishes rx_free list from rx_used, and calls
- * iwl4965_rx_queue_restock
- * iwl4965_rx_queue_restock() Moves available buffers from rx_free into Rx
- * queue, updates firmware pointers, and updates
- * the WRITE index. If insufficient rx_free buffers
- * are available, schedules iwl4965_rx_replenish
- *
- * -- enable interrupts --
- * ISR - iwl4965_rx() Detach iwl4965_rx_mem_buffers from pool up to the
- * READ INDEX, detaching the SKB from the pool.
- * Moves the packet buffer from queue to rx_used.
- * Calls iwl4965_rx_queue_restock to refill any empty
- * slots.
- * ...
- *
- */
-
-/**
- * iwl4965_rx_queue_space - Return number of free slots available in queue.
- */
-static int iwl4965_rx_queue_space(const struct iwl4965_rx_queue *q)
-{
- int s = q->read - q->write;
- if (s <= 0)
- s += RX_QUEUE_SIZE;
- /* keep some buffer to not confuse full and empty queue */
- s -= 2;
- if (s < 0)
- s = 0;
- return s;
-}
-
-/**
- * iwl4965_rx_queue_update_write_ptr - Update the write pointer for the RX queue
- */
-int iwl4965_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl4965_rx_queue *q)
-{
- u32 reg = 0;
- int rc = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&q->lock, flags);
-
- if (q->need_update == 0)
- goto exit_unlock;
-
- /* If power-saving is in use, make sure device is awake */
- if (test_bit(STATUS_POWER_PMI, &priv->status)) {
- reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
-
- if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
- iwl_set_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
- goto exit_unlock;
- }
-
- rc = iwl_grab_nic_access(priv);
- if (rc)
- goto exit_unlock;
-
- /* Device expects a multiple of 8 */
- iwl_write_direct32(priv, FH_RSCSR_CHNL0_WPTR,
- q->write & ~0x7);
- iwl_release_nic_access(priv);
-
- /* Else device is assumed to be awake */
- } else
- /* Device expects a multiple of 8 */
- iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7);
-
-
- q->need_update = 0;
-
- exit_unlock:
- spin_unlock_irqrestore(&q->lock, flags);
- return rc;
-}
-
-/**
- * iwl4965_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
- */
-static inline __le32 iwl4965_dma_addr2rbd_ptr(struct iwl_priv *priv,
- dma_addr_t dma_addr)
-{
- return cpu_to_le32((u32)(dma_addr >> 8));
-}
-
-
-/**
- * iwl4965_rx_queue_restock - refill RX queue from pre-allocated pool
- *
- * If there are slots in the RX queue that need to be restocked,
- * and we have free pre-allocated buffers, fill the ranks as much
- * as we can, pulling from rx_free.
- *
- * This moves the 'write' index forward to catch up with 'processed', and
- * also updates the memory address in the firmware to reference the new
- * target buffer.
- */
-static int iwl4965_rx_queue_restock(struct iwl_priv *priv)
-{
- struct iwl4965_rx_queue *rxq = &priv->rxq;
- struct list_head *element;
- struct iwl4965_rx_mem_buffer *rxb;
- unsigned long flags;
- int write, rc;
-
- spin_lock_irqsave(&rxq->lock, flags);
- write = rxq->write & ~0x7;
- while ((iwl4965_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
- /* Get next free Rx buffer, remove from free list */
- element = rxq->rx_free.next;
- rxb = list_entry(element, struct iwl4965_rx_mem_buffer, list);
- list_del(element);
-
- /* Point to Rx buffer via next RBD in circular buffer */
- rxq->bd[rxq->write] = iwl4965_dma_addr2rbd_ptr(priv, rxb->dma_addr);
- rxq->queue[rxq->write] = rxb;
- rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
- rxq->free_count--;
- }
- spin_unlock_irqrestore(&rxq->lock, flags);
- /* If the pre-allocated buffer pool is dropping low, schedule to
- * refill it */
- if (rxq->free_count <= RX_LOW_WATERMARK)
- queue_work(priv->workqueue, &priv->rx_replenish);
-
-
- /* If we've added more space for the firmware to place data, tell it.
- * Increment device's write pointer in multiples of 8. */
- if ((write != (rxq->write & ~0x7))
- || (abs(rxq->write - rxq->read) > 7)) {
- spin_lock_irqsave(&rxq->lock, flags);
- rxq->need_update = 1;
- spin_unlock_irqrestore(&rxq->lock, flags);
- rc = iwl4965_rx_queue_update_write_ptr(priv, rxq);
- if (rc)
- return rc;
- }
-
- return 0;
-}
-
-/**
- * iwl4965_rx_replenish - Move all used packet from rx_used to rx_free
- *
- * When moving to rx_free an SKB is allocated for the slot.
- *
- * Also restock the Rx queue via iwl4965_rx_queue_restock.
- * This is called as a scheduled work item (except for during initialization)
- */
-static void iwl4965_rx_allocate(struct iwl_priv *priv)
-{
- struct iwl4965_rx_queue *rxq = &priv->rxq;
- struct list_head *element;
- struct iwl4965_rx_mem_buffer *rxb;
- unsigned long flags;
- spin_lock_irqsave(&rxq->lock, flags);
- while (!list_empty(&rxq->rx_used)) {
- element = rxq->rx_used.next;
- rxb = list_entry(element, struct iwl4965_rx_mem_buffer, list);
-
- /* Alloc a new receive buffer */
- rxb->skb =
- alloc_skb(priv->hw_params.rx_buf_size,
- __GFP_NOWARN | GFP_ATOMIC);
- if (!rxb->skb) {
- if (net_ratelimit())
- printk(KERN_CRIT DRV_NAME
- ": Can not allocate SKB buffers\n");
- /* We don't reschedule replenish work here -- we will
- * call the restock method and if it still needs
- * more buffers it will schedule replenish */
- break;
- }
- priv->alloc_rxb_skb++;
- list_del(element);
-
- /* Get physical address of RB/SKB */
- rxb->dma_addr =
- pci_map_single(priv->pci_dev, rxb->skb->data,
- priv->hw_params.rx_buf_size, PCI_DMA_FROMDEVICE);
- list_add_tail(&rxb->list, &rxq->rx_free);
- rxq->free_count++;
- }
- spin_unlock_irqrestore(&rxq->lock, flags);
+ priv->cfg->ops->lib->rx_handler_setup(priv);
}
/*
* this should be called while priv->lock is locked
*/
-static void __iwl4965_rx_replenish(void *data)
+static void __iwl_rx_replenish(struct iwl_priv *priv)
{
- struct iwl_priv *priv = data;
-
- iwl4965_rx_allocate(priv);
- iwl4965_rx_queue_restock(priv);
+ iwl_rx_allocate(priv);
+ iwl_rx_queue_restock(priv);
}
-void iwl4965_rx_replenish(void *data)
-{
- struct iwl_priv *priv = data;
- unsigned long flags;
-
- iwl4965_rx_allocate(priv);
-
- spin_lock_irqsave(&priv->lock, flags);
- iwl4965_rx_queue_restock(priv);
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
- * If an SKB has been detached, the POOL needs to have its SKB set to NULL
- * This free routine walks the list of POOL entries and if SKB is set to
- * non NULL it is unmapped and freed
+/**
+ * iwl_rx_handle - Main entry function for receiving responses from uCode
+ *
+ * Uses the priv->rx_handlers callback function array to invoke
+ * the appropriate handlers, including command responses,
+ * frame-received notifications, and other notifications.
*/
-static void iwl4965_rx_queue_free(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq)
+void iwl_rx_handle(struct iwl_priv *priv)
{
- int i;
- for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
- if (rxq->pool[i].skb != NULL) {
- pci_unmap_single(priv->pci_dev,
- rxq->pool[i].dma_addr,
- priv->hw_params.rx_buf_size,
- PCI_DMA_FROMDEVICE);
- dev_kfree_skb(rxq->pool[i].skb);
- }
- }
-
- pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
- rxq->dma_addr);
- rxq->bd = NULL;
-}
-
-int iwl4965_rx_queue_alloc(struct iwl_priv *priv)
-{
- struct iwl4965_rx_queue *rxq = &priv->rxq;
- struct pci_dev *dev = priv->pci_dev;
- int i;
-
- spin_lock_init(&rxq->lock);
- INIT_LIST_HEAD(&rxq->rx_free);
- INIT_LIST_HEAD(&rxq->rx_used);
-
- /* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */
- rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr);
- if (!rxq->bd)
- return -ENOMEM;
-
- /* Fill the rx_used queue with _all_ of the Rx buffers */
- for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
- list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
-
- /* Set us so that we have processed and used all buffers, but have
- * not restocked the Rx queue with fresh buffers */
- rxq->read = rxq->write = 0;
- rxq->free_count = 0;
- rxq->need_update = 0;
- return 0;
-}
-
-void iwl4965_rx_queue_reset(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq)
-{
+ struct iwl_rx_mem_buffer *rxb;
+ struct iwl_rx_packet *pkt;
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ u32 r, i;
+ int reclaim;
unsigned long flags;
- int i;
- spin_lock_irqsave(&rxq->lock, flags);
- INIT_LIST_HEAD(&rxq->rx_free);
- INIT_LIST_HEAD(&rxq->rx_used);
- /* Fill the rx_used queue with _all_ of the Rx buffers */
- for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
- /* In the reset function, these buffers may have been allocated
- * to an SKB, so we need to unmap and free potential storage */
- if (rxq->pool[i].skb != NULL) {
- pci_unmap_single(priv->pci_dev,
- rxq->pool[i].dma_addr,
- priv->hw_params.rx_buf_size,
- PCI_DMA_FROMDEVICE);
- priv->alloc_rxb_skb--;
- dev_kfree_skb(rxq->pool[i].skb);
- rxq->pool[i].skb = NULL;
+ u8 fill_rx = 0;
+ u32 count = 8;
+
+ /* uCode's read index (stored in shared DRAM) indicates the last Rx
+ * buffer that the driver may process (last buffer filled by ucode). */
+ r = priv->cfg->ops->lib->shared_mem_rx_idx(priv);
+ i = rxq->read;
+
+ /* Rx interrupt, but nothing sent from uCode */
+ if (i == r)
+ IWL_DEBUG(IWL_DL_RX, "r = %d, i = %d\n", r, i);
+
+ if (iwl_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2))
+ fill_rx = 1;
+
+ while (i != r) {
+ rxb = rxq->queue[i];
+
+ /* If an RXB doesn't have a Rx queue slot associated with it,
+ * then a bug has been introduced in the queue refilling
+ * routines -- catch it here */
+ BUG_ON(rxb == NULL);
+
+ rxq->queue[i] = NULL;
+
+ pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
+ priv->hw_params.rx_buf_size,
+ PCI_DMA_FROMDEVICE);
+ pkt = (struct iwl_rx_packet *)rxb->skb->data;
+
+ /* Reclaim a command buffer only if this packet is a response
+ * to a (driver-originated) command.
+ * If the packet (e.g. Rx frame) originated from uCode,
+ * there is no command buffer to reclaim.
+ * Ucode should set SEQ_RX_FRAME bit if ucode-originated,
+ * but apparently a few don't get set; catch them here. */
+ reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
+ (pkt->hdr.cmd != REPLY_RX_PHY_CMD) &&
+ (pkt->hdr.cmd != REPLY_RX) &&
+ (pkt->hdr.cmd != REPLY_COMPRESSED_BA) &&
+ (pkt->hdr.cmd != STATISTICS_NOTIFICATION) &&
+ (pkt->hdr.cmd != REPLY_TX);
+
+ /* Based on type of command response or notification,
+ * handle those that need handling via function in
+ * rx_handlers table. See iwl4965_setup_rx_handlers() */
+ if (priv->rx_handlers[pkt->hdr.cmd]) {
+ IWL_DEBUG(IWL_DL_RX, "r = %d, i = %d, %s, 0x%02x\n", r,
+ i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
+ priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
+ } else {
+ /* No handling needed */
+ IWL_DEBUG(IWL_DL_RX,
+ "r %d i %d No handler needed for %s, 0x%02x\n",
+ r, i, get_cmd_string(pkt->hdr.cmd),
+ pkt->hdr.cmd);
}
- list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+
+ if (reclaim) {
+ /* Invoke any callbacks, transfer the skb to caller, and
+ * fire off the (possibly) blocking iwl_send_cmd()
+ * as we reclaim the driver command queue */
+ if (rxb && rxb->skb)
+ iwl_tx_cmd_complete(priv, rxb);
+ else
+ IWL_WARNING("Claim null rxb?\n");
+ }
+
+ /* For now we just don't re-use anything. We can tweak this
+ * later to try and re-use notification packets and SKBs that
+ * fail to Rx correctly */
+ if (rxb->skb != NULL) {
+ priv->alloc_rxb_skb--;
+ dev_kfree_skb_any(rxb->skb);
+ rxb->skb = NULL;
+ }
+
+ pci_unmap_single(priv->pci_dev, rxb->dma_addr,
+ priv->hw_params.rx_buf_size,
+ PCI_DMA_FROMDEVICE);
+ spin_lock_irqsave(&rxq->lock, flags);
+ list_add_tail(&rxb->list, &priv->rxq.rx_used);
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ i = (i + 1) & RX_QUEUE_MASK;
+ /* If there are a lot of unused frames,
+ * restock the Rx queue so ucode wont assert. */
+ if (fill_rx) {
+ count++;
+ if (count >= 8) {
+ priv->rxq.read = i;
+ __iwl_rx_replenish(priv);
+ count = 0;
+ }
+ }
}
- /* Set us so that we have processed and used all buffers, but have
- * not restocked the Rx queue with fresh buffers */
- rxq->read = rxq->write = 0;
- rxq->free_count = 0;
- spin_unlock_irqrestore(&rxq->lock, flags);
+ /* Backtrack one entry */
+ priv->rxq.read = i;
+ iwl_rx_queue_restock(priv);
}
-
/* Convert linear signal-to-noise ratio into dB */
static u8 ratio2dB[100] = {
/* 0 1 2 3 4 5 6 7 8 9 */
@@ -3894,176 +2127,14 @@
return sig_qual;
}
-/**
- * iwl4965_rx_handle - Main entry function for receiving responses from uCode
- *
- * Uses the priv->rx_handlers callback function array to invoke
- * the appropriate handlers, including command responses,
- * frame-received notifications, and other notifications.
- */
-static void iwl4965_rx_handle(struct iwl_priv *priv)
-{
- struct iwl4965_rx_mem_buffer *rxb;
- struct iwl4965_rx_packet *pkt;
- struct iwl4965_rx_queue *rxq = &priv->rxq;
- u32 r, i;
- int reclaim;
- unsigned long flags;
- u8 fill_rx = 0;
- u32 count = 8;
-
- /* uCode's read index (stored in shared DRAM) indicates the last Rx
- * buffer that the driver may process (last buffer filled by ucode). */
- r = iwl4965_hw_get_rx_read(priv);
- i = rxq->read;
-
- /* Rx interrupt, but nothing sent from uCode */
- if (i == r)
- IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i);
-
- if (iwl4965_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2))
- fill_rx = 1;
-
- while (i != r) {
- rxb = rxq->queue[i];
-
- /* If an RXB doesn't have a Rx queue slot associated with it,
- * then a bug has been introduced in the queue refilling
- * routines -- catch it here */
- BUG_ON(rxb == NULL);
-
- rxq->queue[i] = NULL;
-
- pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
- priv->hw_params.rx_buf_size,
- PCI_DMA_FROMDEVICE);
- pkt = (struct iwl4965_rx_packet *)rxb->skb->data;
-
- /* Reclaim a command buffer only if this packet is a response
- * to a (driver-originated) command.
- * If the packet (e.g. Rx frame) originated from uCode,
- * there is no command buffer to reclaim.
- * Ucode should set SEQ_RX_FRAME bit if ucode-originated,
- * but apparently a few don't get set; catch them here. */
- reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
- (pkt->hdr.cmd != REPLY_RX_PHY_CMD) &&
- (pkt->hdr.cmd != REPLY_RX) &&
- (pkt->hdr.cmd != REPLY_COMPRESSED_BA) &&
- (pkt->hdr.cmd != STATISTICS_NOTIFICATION) &&
- (pkt->hdr.cmd != REPLY_TX);
-
- /* Based on type of command response or notification,
- * handle those that need handling via function in
- * rx_handlers table. See iwl4965_setup_rx_handlers() */
- if (priv->rx_handlers[pkt->hdr.cmd]) {
- IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
- "r = %d, i = %d, %s, 0x%02x\n", r, i,
- get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
- priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
- } else {
- /* No handling needed */
- IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
- "r %d i %d No handler needed for %s, 0x%02x\n",
- r, i, get_cmd_string(pkt->hdr.cmd),
- pkt->hdr.cmd);
- }
-
- if (reclaim) {
- /* Invoke any callbacks, transfer the skb to caller, and
- * fire off the (possibly) blocking iwl_send_cmd()
- * as we reclaim the driver command queue */
- if (rxb && rxb->skb)
- iwl4965_tx_cmd_complete(priv, rxb);
- else
- IWL_WARNING("Claim null rxb?\n");
- }
-
- /* For now we just don't re-use anything. We can tweak this
- * later to try and re-use notification packets and SKBs that
- * fail to Rx correctly */
- if (rxb->skb != NULL) {
- priv->alloc_rxb_skb--;
- dev_kfree_skb_any(rxb->skb);
- rxb->skb = NULL;
- }
-
- pci_unmap_single(priv->pci_dev, rxb->dma_addr,
- priv->hw_params.rx_buf_size,
- PCI_DMA_FROMDEVICE);
- spin_lock_irqsave(&rxq->lock, flags);
- list_add_tail(&rxb->list, &priv->rxq.rx_used);
- spin_unlock_irqrestore(&rxq->lock, flags);
- i = (i + 1) & RX_QUEUE_MASK;
- /* If there are a lot of unused frames,
- * restock the Rx queue so ucode wont assert. */
- if (fill_rx) {
- count++;
- if (count >= 8) {
- priv->rxq.read = i;
- __iwl4965_rx_replenish(priv);
- count = 0;
- }
- }
- }
-
- /* Backtrack one entry */
- priv->rxq.read = i;
- iwl4965_rx_queue_restock(priv);
-}
-
-/**
- * iwl4965_tx_queue_update_write_ptr - Send new write index to hardware
- */
-static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv,
- struct iwl4965_tx_queue *txq)
-{
- u32 reg = 0;
- int rc = 0;
- int txq_id = txq->q.id;
-
- if (txq->need_update == 0)
- return rc;
-
- /* if we're trying to save power */
- if (test_bit(STATUS_POWER_PMI, &priv->status)) {
- /* wake up nic if it's powered down ...
- * uCode will wake up, and interrupt us again, so next
- * time we'll skip this part. */
- reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
-
- if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
- IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg);
- iwl_set_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
- return rc;
- }
-
- /* restore this queue's parameters in nic hardware. */
- rc = iwl_grab_nic_access(priv);
- if (rc)
- return rc;
- iwl_write_direct32(priv, HBUS_TARG_WRPTR,
- txq->q.write_ptr | (txq_id << 8));
- iwl_release_nic_access(priv);
-
- /* else not in power-save mode, uCode will never sleep when we're
- * trying to tx (during RFKILL, we're not trying to tx). */
- } else
- iwl_write32(priv, HBUS_TARG_WRPTR,
- txq->q.write_ptr | (txq_id << 8));
-
- txq->need_update = 0;
-
- return rc;
-}
-
#ifdef CONFIG_IWLWIFI_DEBUG
-static void iwl4965_print_rx_config_cmd(struct iwl4965_rxon_cmd *rxon)
+static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv)
{
+ struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
DECLARE_MAC_BUF(mac);
IWL_DEBUG_RADIO("RX CONFIG:\n");
- iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
+ iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n",
@@ -4109,173 +2180,6 @@
IWL_DEBUG_ISR("Disabled interrupts\n");
}
-static const char *desc_lookup(int i)
-{
- switch (i) {
- case 1:
- return "FAIL";
- case 2:
- return "BAD_PARAM";
- case 3:
- return "BAD_CHECKSUM";
- case 4:
- return "NMI_INTERRUPT";
- case 5:
- return "SYSASSERT";
- case 6:
- return "FATAL_ERROR";
- }
-
- return "UNKNOWN";
-}
-
-#define ERROR_START_OFFSET (1 * sizeof(u32))
-#define ERROR_ELEM_SIZE (7 * sizeof(u32))
-
-static void iwl4965_dump_nic_error_log(struct iwl_priv *priv)
-{
- u32 data2, line;
- u32 desc, time, count, base, data1;
- u32 blink1, blink2, ilink1, ilink2;
- int rc;
-
- base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
-
- if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
- IWL_ERROR("Not valid error log pointer 0x%08X\n", base);
- return;
- }
-
- rc = iwl_grab_nic_access(priv);
- if (rc) {
- IWL_WARNING("Can not read from adapter at this time.\n");
- return;
- }
-
- count = iwl_read_targ_mem(priv, base);
-
- if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
- IWL_ERROR("Start IWL Error Log Dump:\n");
- IWL_ERROR("Status: 0x%08lX, count: %d\n", priv->status, count);
- }
-
- desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
- blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
- blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
- ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32));
- ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32));
- data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32));
- data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32));
- line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
- time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
-
- IWL_ERROR("Desc Time "
- "data1 data2 line\n");
- IWL_ERROR("%-13s (#%d) %010u 0x%08X 0x%08X %u\n",
- desc_lookup(desc), desc, time, data1, data2, line);
- IWL_ERROR("blink1 blink2 ilink1 ilink2\n");
- IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
- ilink1, ilink2);
-
- iwl_release_nic_access(priv);
-}
-
-#define EVENT_START_OFFSET (4 * sizeof(u32))
-
-/**
- * iwl4965_print_event_log - Dump error event log to syslog
- *
- * NOTE: Must be called with iwl_grab_nic_access() already obtained!
- */
-static void iwl4965_print_event_log(struct iwl_priv *priv, u32 start_idx,
- u32 num_events, u32 mode)
-{
- u32 i;
- u32 base; /* SRAM byte address of event log header */
- u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
- u32 ptr; /* SRAM byte address of log data */
- u32 ev, time, data; /* event log data */
-
- if (num_events == 0)
- return;
-
- base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
-
- if (mode == 0)
- event_size = 2 * sizeof(u32);
- else
- event_size = 3 * sizeof(u32);
-
- ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
-
- /* "time" is actually "data" for mode 0 (no timestamp).
- * place event id # at far right for easier visual parsing. */
- for (i = 0; i < num_events; i++) {
- ev = iwl_read_targ_mem(priv, ptr);
- ptr += sizeof(u32);
- time = iwl_read_targ_mem(priv, ptr);
- ptr += sizeof(u32);
- if (mode == 0)
- IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */
- else {
- data = iwl_read_targ_mem(priv, ptr);
- ptr += sizeof(u32);
- IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev);
- }
- }
-}
-
-static void iwl4965_dump_nic_event_log(struct iwl_priv *priv)
-{
- int rc;
- u32 base; /* SRAM byte address of event log header */
- u32 capacity; /* event log capacity in # entries */
- u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
- u32 num_wraps; /* # times uCode wrapped to top of log */
- u32 next_entry; /* index of next entry to be written by uCode */
- u32 size; /* # entries that we'll print */
-
- base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
- if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
- IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
- return;
- }
-
- rc = iwl_grab_nic_access(priv);
- if (rc) {
- IWL_WARNING("Can not read from adapter at this time.\n");
- return;
- }
-
- /* event log header */
- capacity = iwl_read_targ_mem(priv, base);
- mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
- num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
- next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
-
- size = num_wraps ? capacity : next_entry;
-
- /* bail out if nothing in log */
- if (size == 0) {
- IWL_ERROR("Start IWL Event Log Dump: nothing in log\n");
- iwl_release_nic_access(priv);
- return;
- }
-
- IWL_ERROR("Start IWL Event Log Dump: display count %d, wraps %d\n",
- size, num_wraps);
-
- /* if uCode has wrapped back to top of log, start at the oldest entry,
- * i.e the next one that uCode would fill. */
- if (num_wraps)
- iwl4965_print_event_log(priv, next_entry,
- capacity - next_entry, mode);
-
- /* (then/else) start at top of log */
- iwl4965_print_event_log(priv, 0, next_entry, mode);
-
- iwl_release_nic_access(priv);
-}
/**
* iwl4965_irq_handle_error - called for HW or SW error interrupt from card
@@ -4289,10 +2193,10 @@
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
#ifdef CONFIG_IWLWIFI_DEBUG
- if (iwl_debug_level & IWL_DL_FW_ERRORS) {
- iwl4965_dump_nic_error_log(priv);
- iwl4965_dump_nic_event_log(priv);
- iwl4965_print_rx_config_cmd(&priv->staging_rxon);
+ if (priv->debug_level & IWL_DL_FW_ERRORS) {
+ iwl_dump_nic_error_log(priv);
+ iwl_dump_nic_event_log(priv);
+ iwl4965_print_rx_config_cmd(priv);
}
#endif
@@ -4303,7 +2207,7 @@
clear_bit(STATUS_READY, &priv->status);
if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
- IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS,
+ IWL_DEBUG(IWL_DL_FW_ERRORS,
"Restarting adapter due to uCode error.\n");
if (iwl_is_associated(priv)) {
@@ -4311,7 +2215,8 @@
sizeof(priv->recovery_rxon));
priv->error_recovering = 1;
}
- queue_work(priv->workqueue, &priv->restart);
+ if (priv->cfg->mod_params->restart_fw)
+ queue_work(priv->workqueue, &priv->restart);
}
}
@@ -4324,7 +2229,7 @@
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
iwl4965_commit_rxon(priv);
- iwl4965_rxon_add_station(priv, priv->bssid, 1);
+ iwl_rxon_add_station(priv, priv->bssid, 1);
spin_lock_irqsave(&priv->lock, flags);
priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id);
@@ -4356,7 +2261,7 @@
iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
#ifdef CONFIG_IWLWIFI_DEBUG
- if (iwl_debug_level & IWL_DL_ISR) {
+ if (priv->debug_level & IWL_DL_ISR) {
/* just for debug */
inta_mask = iwl_read32(priv, CSR_INT_MASK);
IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
@@ -4390,7 +2295,7 @@
}
#ifdef CONFIG_IWLWIFI_DEBUG
- if (iwl_debug_level & (IWL_DL_ISR)) {
+ if (priv->debug_level & (IWL_DL_ISR)) {
/* NIC fires this, but we don't use it, redundant with WAKEUP */
if (inta & CSR_INT_BIT_SCD)
IWL_DEBUG_ISR("Scheduler finished to transmit "
@@ -4411,8 +2316,7 @@
CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
hw_rf_kill = 1;
- IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR,
- "RF_KILL bit toggled to %s.\n",
+ IWL_DEBUG(IWL_DL_RF_KILL, "RF_KILL bit toggled to %s.\n",
hw_rf_kill ? "disable radio":"enable radio");
/* Queue restart only if RF_KILL switch was set to "kill"
@@ -4444,13 +2348,13 @@
/* uCode wakes up after power-down sleep */
if (inta & CSR_INT_BIT_WAKEUP) {
IWL_DEBUG_ISR("Wakeup interrupt\n");
- iwl4965_rx_queue_update_write_ptr(priv, &priv->rxq);
- iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[0]);
- iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[1]);
- iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[2]);
- iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[3]);
- iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[4]);
- iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[5]);
+ iwl_rx_queue_update_write_ptr(priv, &priv->rxq);
+ iwl_txq_update_write_ptr(priv, &priv->txq[0]);
+ iwl_txq_update_write_ptr(priv, &priv->txq[1]);
+ iwl_txq_update_write_ptr(priv, &priv->txq[2]);
+ iwl_txq_update_write_ptr(priv, &priv->txq[3]);
+ iwl_txq_update_write_ptr(priv, &priv->txq[4]);
+ iwl_txq_update_write_ptr(priv, &priv->txq[5]);
handled |= CSR_INT_BIT_WAKEUP;
}
@@ -4459,13 +2363,16 @@
* Rx "responses" (frame-received notification), and other
* notifications from uCode come through here*/
if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
- iwl4965_rx_handle(priv);
+ iwl_rx_handle(priv);
handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
}
if (inta & CSR_INT_BIT_FH_TX) {
IWL_DEBUG_ISR("Tx interrupt\n");
handled |= CSR_INT_BIT_FH_TX;
+ /* FH finished to write, send event */
+ priv->ucode_write_complete = 1;
+ wake_up_interruptible(&priv->wait_command_queue);
}
if (inta & ~handled)
@@ -4483,7 +2390,7 @@
iwl4965_enable_interrupts(priv);
#ifdef CONFIG_IWLWIFI_DEBUG
- if (iwl_debug_level & (IWL_DL_ISR)) {
+ if (priv->debug_level & (IWL_DL_ISR)) {
inta = iwl_read32(priv, CSR_INT);
inta_mask = iwl_read32(priv, CSR_INT_MASK);
inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
@@ -4620,7 +2527,7 @@
u16 active_dwell = 0;
int added, i;
- sband = iwl4965_get_hw_mode(priv, band);
+ sband = iwl_get_hw_mode(priv, band);
if (!sband)
return 0;
@@ -4652,9 +2559,6 @@
if (scan_ch->type & 1)
scan_ch->type |= (direct_mask << 1);
- if (is_channel_narrow(ch_info))
- scan_ch->type |= (1 << 7);
-
scan_ch->active_dwell = cpu_to_le16(active_dwell);
scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
@@ -4687,163 +2591,6 @@
return added;
}
-static void iwl4965_init_hw_rates(struct iwl_priv *priv,
- struct ieee80211_rate *rates)
-{
- int i;
-
- for (i = 0; i < IWL_RATE_COUNT; i++) {
- rates[i].bitrate = iwl4965_rates[i].ieee * 5;
- rates[i].hw_value = i; /* Rate scaling will work on indexes */
- rates[i].hw_value_short = i;
- rates[i].flags = 0;
- if ((i > IWL_LAST_OFDM_RATE) || (i < IWL_FIRST_OFDM_RATE)) {
- /*
- * If CCK != 1M then set short preamble rate flag.
- */
- rates[i].flags |=
- (iwl4965_rates[i].plcp == IWL_RATE_1M_PLCP) ?
- 0 : IEEE80211_RATE_SHORT_PREAMBLE;
- }
- }
-}
-
-/**
- * iwl4965_init_geos - Initialize mac80211's geo/channel info based from eeprom
- */
-int iwl4965_init_geos(struct iwl_priv *priv)
-{
- struct iwl_channel_info *ch;
- struct ieee80211_supported_band *sband;
- struct ieee80211_channel *channels;
- struct ieee80211_channel *geo_ch;
- struct ieee80211_rate *rates;
- int i = 0;
-
- if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates ||
- priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) {
- IWL_DEBUG_INFO("Geography modes already initialized.\n");
- set_bit(STATUS_GEO_CONFIGURED, &priv->status);
- return 0;
- }
-
- channels = kzalloc(sizeof(struct ieee80211_channel) *
- priv->channel_count, GFP_KERNEL);
- if (!channels)
- return -ENOMEM;
-
- rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_RATE_COUNT + 1)),
- GFP_KERNEL);
- if (!rates) {
- kfree(channels);
- return -ENOMEM;
- }
-
- /* 5.2GHz channels start after the 2.4GHz channels */
- sband = &priv->bands[IEEE80211_BAND_5GHZ];
- sband->channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
- /* just OFDM */
- sband->bitrates = &rates[IWL_FIRST_OFDM_RATE];
- sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE;
-
- iwl4965_init_ht_hw_capab(priv, &sband->ht_info, IEEE80211_BAND_5GHZ);
-
- sband = &priv->bands[IEEE80211_BAND_2GHZ];
- sband->channels = channels;
- /* OFDM & CCK */
- sband->bitrates = rates;
- sband->n_bitrates = IWL_RATE_COUNT;
-
- iwl4965_init_ht_hw_capab(priv, &sband->ht_info, IEEE80211_BAND_2GHZ);
-
- priv->ieee_channels = channels;
- priv->ieee_rates = rates;
-
- iwl4965_init_hw_rates(priv, rates);
-
- for (i = 0; i < priv->channel_count; i++) {
- ch = &priv->channel_info[i];
-
- /* FIXME: might be removed if scan is OK */
- if (!is_channel_valid(ch))
- continue;
-
- if (is_channel_a_band(ch))
- sband = &priv->bands[IEEE80211_BAND_5GHZ];
- else
- sband = &priv->bands[IEEE80211_BAND_2GHZ];
-
- geo_ch = &sband->channels[sband->n_channels++];
-
- geo_ch->center_freq = ieee80211_channel_to_frequency(ch->channel);
- geo_ch->max_power = ch->max_power_avg;
- geo_ch->max_antenna_gain = 0xff;
- geo_ch->hw_value = ch->channel;
-
- if (is_channel_valid(ch)) {
- if (!(ch->flags & EEPROM_CHANNEL_IBSS))
- geo_ch->flags |= IEEE80211_CHAN_NO_IBSS;
-
- if (!(ch->flags & EEPROM_CHANNEL_ACTIVE))
- geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN;
-
- if (ch->flags & EEPROM_CHANNEL_RADAR)
- geo_ch->flags |= IEEE80211_CHAN_RADAR;
-
- if (ch->max_power_avg > priv->max_channel_txpower_limit)
- priv->max_channel_txpower_limit =
- ch->max_power_avg;
- } else {
- geo_ch->flags |= IEEE80211_CHAN_DISABLED;
- }
-
- /* Save flags for reg domain usage */
- geo_ch->orig_flags = geo_ch->flags;
-
- IWL_DEBUG_INFO("Channel %d Freq=%d[%sGHz] %s flag=0%X\n",
- ch->channel, geo_ch->center_freq,
- is_channel_a_band(ch) ? "5.2" : "2.4",
- geo_ch->flags & IEEE80211_CHAN_DISABLED ?
- "restricted" : "valid",
- geo_ch->flags);
- }
-
- if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) &&
- priv->cfg->sku & IWL_SKU_A) {
- printk(KERN_INFO DRV_NAME
- ": Incorrectly detected BG card as ABG. Please send "
- "your PCI ID 0x%04X:0x%04X to maintainer.\n",
- priv->pci_dev->device, priv->pci_dev->subsystem_device);
- priv->cfg->sku &= ~IWL_SKU_A;
- }
-
- printk(KERN_INFO DRV_NAME
- ": Tunable channels: %d 802.11bg, %d 802.11a channels\n",
- priv->bands[IEEE80211_BAND_2GHZ].n_channels,
- priv->bands[IEEE80211_BAND_5GHZ].n_channels);
-
- if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
- priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
- &priv->bands[IEEE80211_BAND_2GHZ];
- if (priv->bands[IEEE80211_BAND_5GHZ].n_channels)
- priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
- &priv->bands[IEEE80211_BAND_5GHZ];
-
- set_bit(STATUS_GEO_CONFIGURED, &priv->status);
-
- return 0;
-}
-
-/*
- * iwl4965_free_geos - undo allocations in iwl4965_init_geos
- */
-void iwl4965_free_geos(struct iwl_priv *priv)
-{
- kfree(priv->ieee_channels);
- kfree(priv->ieee_rates);
- clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
-}
-
/******************************************************************************
*
* uCode download functions
@@ -4860,146 +2607,6 @@
iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot);
}
-/**
- * iwl4965_verify_inst_full - verify runtime uCode image in card vs. host,
- * looking at all data.
- */
-static int iwl4965_verify_inst_full(struct iwl_priv *priv, __le32 *image,
- u32 len)
-{
- u32 val;
- u32 save_len = len;
- int rc = 0;
- u32 errcnt;
-
- IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
-
- rc = iwl_grab_nic_access(priv);
- if (rc)
- return rc;
-
- iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND);
-
- errcnt = 0;
- for (; len > 0; len -= sizeof(u32), image++) {
- /* read data comes through single port, auto-incr addr */
- /* NOTE: Use the debugless read so we don't flood kernel log
- * if IWL_DL_IO is set */
- val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
- if (val != le32_to_cpu(*image)) {
- IWL_ERROR("uCode INST section is invalid at "
- "offset 0x%x, is 0x%x, s/b 0x%x\n",
- save_len - len, val, le32_to_cpu(*image));
- rc = -EIO;
- errcnt++;
- if (errcnt >= 20)
- break;
- }
- }
-
- iwl_release_nic_access(priv);
-
- if (!errcnt)
- IWL_DEBUG_INFO
- ("ucode image in INSTRUCTION memory is good\n");
-
- return rc;
-}
-
-
-/**
- * iwl4965_verify_inst_sparse - verify runtime uCode image in card vs. host,
- * using sample data 100 bytes apart. If these sample points are good,
- * it's a pretty good bet that everything between them is good, too.
- */
-static int iwl4965_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
-{
- u32 val;
- int rc = 0;
- u32 errcnt = 0;
- u32 i;
-
- IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
-
- rc = iwl_grab_nic_access(priv);
- if (rc)
- return rc;
-
- for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
- /* read data comes through single port, auto-incr addr */
- /* NOTE: Use the debugless read so we don't flood kernel log
- * if IWL_DL_IO is set */
- iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
- i + RTC_INST_LOWER_BOUND);
- val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
- if (val != le32_to_cpu(*image)) {
-#if 0 /* Enable this if you want to see details */
- IWL_ERROR("uCode INST section is invalid at "
- "offset 0x%x, is 0x%x, s/b 0x%x\n",
- i, val, *image);
-#endif
- rc = -EIO;
- errcnt++;
- if (errcnt >= 3)
- break;
- }
- }
-
- iwl_release_nic_access(priv);
-
- return rc;
-}
-
-
-/**
- * iwl4965_verify_ucode - determine which instruction image is in SRAM,
- * and verify its contents
- */
-static int iwl4965_verify_ucode(struct iwl_priv *priv)
-{
- __le32 *image;
- u32 len;
- int rc = 0;
-
- /* Try bootstrap */
- image = (__le32 *)priv->ucode_boot.v_addr;
- len = priv->ucode_boot.len;
- rc = iwl4965_verify_inst_sparse(priv, image, len);
- if (rc == 0) {
- IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n");
- return 0;
- }
-
- /* Try initialize */
- image = (__le32 *)priv->ucode_init.v_addr;
- len = priv->ucode_init.len;
- rc = iwl4965_verify_inst_sparse(priv, image, len);
- if (rc == 0) {
- IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n");
- return 0;
- }
-
- /* Try runtime/protocol */
- image = (__le32 *)priv->ucode_code.v_addr;
- len = priv->ucode_code.len;
- rc = iwl4965_verify_inst_sparse(priv, image, len);
- if (rc == 0) {
- IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n");
- return 0;
- }
-
- IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
-
- /* Since nothing seems to match, show first several data entries in
- * instruction SRAM, so maybe visual inspection will give a clue.
- * Selection of bootstrap image (vs. other images) is arbitrary. */
- image = (__le32 *)priv->ucode_boot.v_addr;
- len = priv->ucode_boot.len;
- rc = iwl4965_verify_inst_full(priv, image, len);
-
- return rc;
-}
-
static void iwl4965_nic_start(struct iwl_priv *priv)
{
/* Remove all resets to allow NIC to operate */
@@ -5075,34 +2682,34 @@
}
/* Verify that uCode images will fit in card's SRAM */
- if (inst_size > IWL_MAX_INST_SIZE) {
+ if (inst_size > priv->hw_params.max_inst_size) {
IWL_DEBUG_INFO("uCode instr len %d too large to fit in\n",
inst_size);
ret = -EINVAL;
goto err_release;
}
- if (data_size > IWL_MAX_DATA_SIZE) {
+ if (data_size > priv->hw_params.max_data_size) {
IWL_DEBUG_INFO("uCode data len %d too large to fit in\n",
data_size);
ret = -EINVAL;
goto err_release;
}
- if (init_size > IWL_MAX_INST_SIZE) {
+ if (init_size > priv->hw_params.max_inst_size) {
IWL_DEBUG_INFO
("uCode init instr len %d too large to fit in\n",
init_size);
ret = -EINVAL;
goto err_release;
}
- if (init_data_size > IWL_MAX_DATA_SIZE) {
+ if (init_data_size > priv->hw_params.max_data_size) {
IWL_DEBUG_INFO
("uCode init data len %d too large to fit in\n",
init_data_size);
ret = -EINVAL;
goto err_release;
}
- if (boot_size > IWL_MAX_BSM_SIZE) {
+ if (boot_size > priv->hw_params.max_bsm_size) {
IWL_DEBUG_INFO
("uCode boot instr len %d too large to fit in\n",
boot_size);
@@ -5203,111 +2810,12 @@
return ret;
}
-
/**
- * iwl4965_set_ucode_ptrs - Set uCode address location
- *
- * Tell initialization uCode where to find runtime uCode.
- *
- * BSM registers initially contain pointers to initialization uCode.
- * We need to replace them to load runtime uCode inst and data,
- * and to save runtime data when powering down.
- */
-static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv)
-{
- dma_addr_t pinst;
- dma_addr_t pdata;
- int rc = 0;
- unsigned long flags;
-
- /* bits 35:4 for 4965 */
- pinst = priv->ucode_code.p_addr >> 4;
- pdata = priv->ucode_data_backup.p_addr >> 4;
-
- spin_lock_irqsave(&priv->lock, flags);
- rc = iwl_grab_nic_access(priv);
- if (rc) {
- spin_unlock_irqrestore(&priv->lock, flags);
- return rc;
- }
-
- /* Tell bootstrap uCode where to find image to load */
- iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
- iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
- iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG,
- priv->ucode_data.len);
-
- /* Inst bytecount must be last to set up, bit 31 signals uCode
- * that all new ptr/size info is in place */
- iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG,
- priv->ucode_code.len | BSM_DRAM_INST_LOAD);
-
- iwl_release_nic_access(priv);
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- IWL_DEBUG_INFO("Runtime uCode pointers are set.\n");
-
- return rc;
-}
-
-/**
- * iwl4965_init_alive_start - Called after REPLY_ALIVE notification received
- *
- * Called after REPLY_ALIVE notification received from "initialize" uCode.
- *
- * The 4965 "initialize" ALIVE reply contains calibration data for:
- * Voltage, temperature, and MIMO tx gain correction, now stored in priv
- * (3945 does not contain this data).
- *
- * Tell "initialize" uCode to go ahead and load the runtime uCode.
-*/
-static void iwl4965_init_alive_start(struct iwl_priv *priv)
-{
- /* Check alive response for "valid" sign from uCode */
- if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
- /* We had an error bringing up the hardware, so take it
- * all the way back down so we can try again */
- IWL_DEBUG_INFO("Initialize Alive failed.\n");
- goto restart;
- }
-
- /* Bootstrap uCode has loaded initialize uCode ... verify inst image.
- * This is a paranoid check, because we would not have gotten the
- * "initialize" alive if code weren't properly loaded. */
- if (iwl4965_verify_ucode(priv)) {
- /* Runtime instruction load was bad;
- * take it all the way back down so we can try again */
- IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n");
- goto restart;
- }
-
- /* Calculate temperature */
- priv->temperature = iwl4965_get_temperature(priv);
-
- /* Send pointers to protocol/runtime uCode image ... init code will
- * load and launch runtime uCode, which will send us another "Alive"
- * notification. */
- IWL_DEBUG_INFO("Initialization Alive received.\n");
- if (iwl4965_set_ucode_ptrs(priv)) {
- /* Runtime instruction load won't happen;
- * take it all the way back down so we can try again */
- IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n");
- goto restart;
- }
- return;
-
- restart:
- queue_work(priv->workqueue, &priv->restart);
-}
-
-
-/**
- * iwl4965_alive_start - called after REPLY_ALIVE notification received
+ * iwl_alive_start - called after REPLY_ALIVE notification received
* from protocol/runtime uCode (initialization uCode's
- * Alive gets handled by iwl4965_init_alive_start()).
+ * Alive gets handled by iwl_init_alive_start()).
*/
-static void iwl4965_alive_start(struct iwl_priv *priv)
+static void iwl_alive_start(struct iwl_priv *priv)
{
int ret = 0;
@@ -5323,7 +2831,7 @@
/* Initialize uCode has loaded Runtime uCode ... verify inst image.
* This is a paranoid check, because we would not have gotten the
* "runtime" alive if code weren't properly loaded. */
- if (iwl4965_verify_ucode(priv)) {
+ if (iwl_verify_ucode(priv)) {
/* Runtime instruction load was bad;
* take it all the way back down so we can try again */
IWL_DEBUG_INFO("Bad runtime uCode load.\n");
@@ -5331,7 +2839,6 @@
}
iwlcore_clear_stations_table(priv);
-
ret = priv->cfg->ops->lib->alive_notify(priv);
if (ret) {
IWL_WARNING("Could not complete ALIVE transition [ntf]: %d\n",
@@ -5348,16 +2855,14 @@
if (iwl_is_rfkill(priv))
return;
- ieee80211_start_queues(priv->hw);
+ ieee80211_wake_queues(priv->hw);
priv->active_rate = priv->rates_mask;
priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
- iwl4965_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode));
-
if (iwl_is_associated(priv)) {
- struct iwl4965_rxon_cmd *active_rxon =
- (struct iwl4965_rxon_cmd *)(&priv->active_rxon);
+ struct iwl_rxon_cmd *active_rxon =
+ (struct iwl_rxon_cmd *)&priv->active_rxon;
memcpy(&priv->staging_rxon, &priv->active_rxon,
sizeof(priv->staging_rxon));
@@ -5371,12 +2876,12 @@
/* Configure Bluetooth device coexistence support */
iwl4965_send_bt_config(priv);
+ iwl_reset_run_time_calib(priv);
+
/* Configure the adapter for unassociated operation */
iwl4965_commit_rxon(priv);
/* At this point, the NIC is initialized and operational */
- priv->notif_missed_beacons = 0;
-
iwl4965_rf_kill_ct_config(priv);
iwl_leds_register(priv);
@@ -5402,12 +2907,9 @@
{
unsigned long flags;
int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status);
- struct ieee80211_conf *conf = NULL;
IWL_DEBUG_INFO(DRV_NAME " is going down\n");
- conf = ieee80211_get_hw_conf(priv->hw);
-
if (!exit_pending)
set_bit(STATUS_EXIT_PENDING, &priv->status);
@@ -5469,8 +2971,8 @@
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
spin_unlock_irqrestore(&priv->lock, flags);
- iwl4965_hw_txq_ctx_stop(priv);
- iwl4965_hw_rxq_stop(priv);
+ iwl_txq_ctx_stop(priv);
+ iwl_rxq_stop(priv);
spin_lock_irqsave(&priv->lock, flags);
if (!iwl_grab_nic_access(priv)) {
@@ -5482,19 +2984,19 @@
udelay(5);
- iwl4965_hw_nic_stop_master(priv);
- iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
- iwl4965_hw_nic_reset(priv);
+ /* FIXME: apm_ops.suspend(priv) */
+ priv->cfg->ops->lib->apm_ops.reset(priv);
+ priv->cfg->ops->lib->free_shared_mem(priv);
exit:
- memset(&priv->card_alive, 0, sizeof(struct iwl4965_alive_resp));
+ memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
if (priv->ibss_beacon)
dev_kfree_skb(priv->ibss_beacon);
priv->ibss_beacon = NULL;
/* clear out any free frames */
- iwl4965_clear_free_frames(priv);
+ iwl_clear_free_frames(priv);
}
static void iwl4965_down(struct iwl_priv *priv)
@@ -5546,7 +3048,13 @@
iwl_rfkill_set_hw_state(priv);
iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
- ret = priv->cfg->ops->lib->hw_nic_init(priv);
+ ret = priv->cfg->ops->lib->alloc_shared_mem(priv);
+ if (ret) {
+ IWL_ERROR("Unable to allocate shared memory\n");
+ return ret;
+ }
+
+ ret = iwl_hw_nic_init(priv);
if (ret) {
IWL_ERROR("Unable to init nic\n");
return ret;
@@ -5613,7 +3121,7 @@
*
*****************************************************************************/
-static void iwl4965_bg_init_alive_start(struct work_struct *data)
+static void iwl_bg_init_alive_start(struct work_struct *data)
{
struct iwl_priv *priv =
container_of(data, struct iwl_priv, init_alive_start.work);
@@ -5622,11 +3130,11 @@
return;
mutex_lock(&priv->mutex);
- iwl4965_init_alive_start(priv);
+ priv->cfg->ops->lib->init_alive_start(priv);
mutex_unlock(&priv->mutex);
}
-static void iwl4965_bg_alive_start(struct work_struct *data)
+static void iwl_bg_alive_start(struct work_struct *data)
{
struct iwl_priv *priv =
container_of(data, struct iwl_priv, alive_start.work);
@@ -5635,7 +3143,7 @@
return;
mutex_lock(&priv->mutex);
- iwl4965_alive_start(priv);
+ iwl_alive_start(priv);
mutex_unlock(&priv->mutex);
}
@@ -5651,7 +3159,7 @@
mutex_lock(&priv->mutex);
if (!iwl_is_rfkill(priv)) {
- IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL,
+ IWL_DEBUG(IWL_DL_RF_KILL,
"HW and/or SW RF Kill no longer active, restarting "
"device\n");
if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
@@ -5674,6 +3182,24 @@
mutex_unlock(&priv->mutex);
}
+static void iwl4965_bg_set_monitor(struct work_struct *work)
+{
+ struct iwl_priv *priv = container_of(work,
+ struct iwl_priv, set_monitor);
+
+ IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n");
+
+ mutex_lock(&priv->mutex);
+
+ if (!iwl_is_ready(priv))
+ IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n");
+ else
+ if (iwl4965_set_mode(priv, IEEE80211_IF_TYPE_MNTR) != 0)
+ IWL_ERROR("iwl4965_set_mode() failed\n");
+
+ mutex_unlock(&priv->mutex);
+}
+
#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
static void iwl4965_bg_scan_check(struct work_struct *data)
@@ -5687,9 +3213,9 @@
mutex_lock(&priv->mutex);
if (test_bit(STATUS_SCANNING, &priv->status) ||
test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
- IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN,
- "Scan completion watchdog resetting adapter (%dms)\n",
- jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
+ IWL_DEBUG(IWL_DL_SCAN, "Scan completion watchdog resetting "
+ "adapter (%dms)\n",
+ jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
iwl4965_send_scan_abort(priv);
@@ -5887,6 +3413,8 @@
direct_mask,
(void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
+ scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
+ RXON_FILTER_BCON_AWARE_MSK);
cmd.len += le16_to_cpu(scan->tx_cmd.len) +
scan->channel_count * sizeof(struct iwl4965_scan_channel);
cmd.data = scan;
@@ -5941,7 +3469,7 @@
return;
mutex_lock(&priv->mutex);
- iwl4965_rx_replenish(priv);
+ iwl_rx_replenish(priv);
mutex_unlock(&priv->mutex);
}
@@ -5989,9 +3517,9 @@
#ifdef CONFIG_IWL4965_HT
if (priv->current_ht_config.is_ht)
- iwl4965_set_rxon_ht(priv, &priv->current_ht_config);
+ iwl_set_rxon_ht(priv, &priv->current_ht_config);
#endif /* CONFIG_IWL4965_HT*/
- iwl4965_set_rxon_chain(priv);
+ iwl_set_rxon_chain(priv);
priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
IWL_DEBUG_ASSOC("assoc id %d beacon interval %d\n",
@@ -6025,8 +3553,8 @@
/* clear out the station table */
iwlcore_clear_stations_table(priv);
- iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0);
- iwl4965_rxon_add_station(priv, priv->bssid, 0);
+ iwl_rxon_add_station(priv, iwl_bcast_addr, 0);
+ iwl_rxon_add_station(priv, priv->bssid, 0);
iwl4965_rate_scale_init(priv->hw, IWL_STA_ID);
iwl4965_send_beacon_cmd(priv);
@@ -6040,17 +3568,16 @@
iwl4965_sequence_reset(priv);
-#ifdef CONFIG_IWL4965_SENSITIVITY
/* Enable Rx differential gain and sensitivity calibrations */
- iwl4965_chain_noise_reset(priv);
+ iwl_chain_noise_reset(priv);
priv->start_calib = 1;
-#endif /* CONFIG_IWL4965_SENSITIVITY */
if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
priv->assoc_station_added = 1;
iwl4965_activate_qos(priv, 0);
+ iwl_power_update_mode(priv, 0);
/* we have just associated, don't start scan too early */
priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
}
@@ -6089,7 +3616,7 @@
struct iwl_priv *priv =
container_of(work, struct iwl_priv, scan_completed);
- IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, "SCAN complete scan\n");
+ IWL_DEBUG(IWL_DL_SCAN, "SCAN complete scan\n");
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
@@ -6138,7 +3665,7 @@
/* we should be verifying the device is ready to be opened */
mutex_lock(&priv->mutex);
- memset(&priv->staging_rxon, 0, sizeof(struct iwl4965_rxon_cmd));
+ memset(&priv->staging_rxon, 0, sizeof(struct iwl_rxon_cmd));
/* fetch ucode file from disk, alloc and copy to bus-master buffers ...
* ucode filename and max sizes are card-specific. */
@@ -6163,21 +3690,23 @@
if (test_bit(STATUS_IN_SUSPEND, &priv->status))
return 0;
- /* Wait for START_ALIVE from ucode. Otherwise callbacks from
+ /* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from
* mac80211 will not be run successfully. */
- ret = wait_event_interruptible_timeout(priv->wait_command_queue,
- test_bit(STATUS_READY, &priv->status),
- UCODE_READY_TIMEOUT);
- if (!ret) {
- if (!test_bit(STATUS_READY, &priv->status)) {
- IWL_ERROR("Wait for START_ALIVE timeout after %dms.\n",
- jiffies_to_msecs(UCODE_READY_TIMEOUT));
- ret = -ETIMEDOUT;
- goto out_release_irq;
+ if (priv->ucode_type == UCODE_RT) {
+ ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+ test_bit(STATUS_READY, &priv->status),
+ UCODE_READY_TIMEOUT);
+ if (!ret) {
+ if (!test_bit(STATUS_READY, &priv->status)) {
+ IWL_ERROR("START_ALIVE timeout after %dms.\n",
+ jiffies_to_msecs(UCODE_READY_TIMEOUT));
+ ret = -ETIMEDOUT;
+ goto out_release_irq;
+ }
}
- }
- priv->is_open = 1;
+ priv->is_open = 1;
+ }
IWL_DEBUG_MAC80211("leave\n");
return 0;
@@ -6225,8 +3754,7 @@
IWL_DEBUG_MAC80211("leave\n");
}
-static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_control *ctl)
+static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct iwl_priv *priv = hw->priv;
@@ -6238,9 +3766,9 @@
}
IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
- ctl->tx_rate->bitrate);
+ ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
- if (iwl4965_tx_skb(priv, skb, ctl))
+ if (iwl_tx_skb(priv, skb))
dev_kfree_skb_any(skb);
IWL_DEBUG_MAC80211("leave\n");
@@ -6295,6 +3823,7 @@
const struct iwl_channel_info *ch_info;
unsigned long flags;
int ret = 0;
+ u16 channel;
mutex_lock(&priv->mutex);
IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value);
@@ -6315,22 +3844,21 @@
return 0;
}
- spin_lock_irqsave(&priv->lock, flags);
-
- ch_info = iwl_get_channel_info(priv, conf->channel->band,
- ieee80211_frequency_to_channel(conf->channel->center_freq));
+ channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
+ ch_info = iwl_get_channel_info(priv, conf->channel->band, channel);
if (!is_channel_valid(ch_info)) {
IWL_DEBUG_MAC80211("leave - invalid channel\n");
- spin_unlock_irqrestore(&priv->lock, flags);
ret = -EINVAL;
goto out;
}
+ spin_lock_irqsave(&priv->lock, flags);
+
#ifdef CONFIG_IWL4965_HT
/* if we are switching from ht to 2.4 clear flags
* from any ht related info since 2.4 does not
* support ht */
- if ((le16_to_cpu(priv->staging_rxon.channel) != conf->channel->hw_value)
+ if ((le16_to_cpu(priv->staging_rxon.channel) != channel)
#ifdef IEEE80211_CONF_CHANNEL_SWITCH
&& !(conf->flags & IEEE80211_CONF_CHANNEL_SWITCH)
#endif
@@ -6338,10 +3866,9 @@
priv->staging_rxon.flags = 0;
#endif /* CONFIG_IWL4965_HT */
- iwlcore_set_rxon_channel(priv, conf->channel->band,
- ieee80211_frequency_to_channel(conf->channel->center_freq));
+ iwl_set_rxon_channel(priv, conf->channel->band, channel);
- iwl4965_set_flags_for_phymode(priv, conf->channel->band);
+ iwl_set_flags_for_band(priv, conf->channel->band);
/* The list of supported rates and rate mask can be different
* for each band; since the band may have changed, reset
@@ -6410,7 +3937,7 @@
IWL_WARNING("REPLY_RXON_TIMING failed - "
"Attempting to continue.\n");
- iwl4965_set_rxon_chain(priv);
+ iwl_set_rxon_chain(priv);
/* FIXME: what should be the assoc_id for AP? */
priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
@@ -6438,7 +3965,7 @@
priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
iwl4965_commit_rxon(priv);
iwl4965_activate_qos(priv, 1);
- iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0);
+ iwl_rxon_add_station(priv, iwl_bcast_addr, 0);
}
iwl4965_send_beacon_cmd(priv);
@@ -6527,7 +4054,7 @@
else {
rc = iwl4965_commit_rxon(priv);
if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc)
- iwl4965_rxon_add_station(
+ iwl_rxon_add_station(
priv, priv->active_rxon.bssid_addr, 1);
}
@@ -6562,7 +4089,22 @@
* XXX: dummy
* see also iwl4965_connection_init_rx_config
*/
- *total_flags = 0;
+ struct iwl_priv *priv = hw->priv;
+ int new_flags = 0;
+ if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) {
+ if (*total_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) {
+ IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n",
+ IEEE80211_IF_TYPE_MNTR,
+ changed_flags, *total_flags);
+ /* queue work 'cuz mac80211 is holding a lock which
+ * prevents us from issuing (synchronous) f/w cmds */
+ queue_work(priv->workqueue, &priv->set_monitor);
+ new_flags &= FIF_PROMISC_IN_BSS |
+ FIF_OTHER_BSS |
+ FIF_ALLMULTI;
+ }
+ }
+ *total_flags = new_flags;
}
static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw,
@@ -6592,64 +4134,6 @@
}
-
-#ifdef CONFIG_IWL4965_HT
-static void iwl4965_ht_conf(struct iwl_priv *priv,
- struct ieee80211_bss_conf *bss_conf)
-{
- struct ieee80211_ht_info *ht_conf = bss_conf->ht_conf;
- struct ieee80211_ht_bss_info *ht_bss_conf = bss_conf->ht_bss_conf;
- struct iwl_ht_info *iwl_conf = &priv->current_ht_config;
-
- IWL_DEBUG_MAC80211("enter: \n");
-
- iwl_conf->is_ht = bss_conf->assoc_ht;
-
- if (!iwl_conf->is_ht)
- return;
-
- priv->ps_mode = (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2);
-
- if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20)
- iwl_conf->sgf |= 0x1;
- if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40)
- iwl_conf->sgf |= 0x2;
-
- iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD);
- iwl_conf->max_amsdu_size =
- !!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU);
-
- iwl_conf->supported_chan_width =
- !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH);
- iwl_conf->extension_chan_offset =
- ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET;
- /* If no above or below channel supplied disable FAT channel */
- if (iwl_conf->extension_chan_offset != IWL_EXT_CHANNEL_OFFSET_ABOVE &&
- iwl_conf->extension_chan_offset != IWL_EXT_CHANNEL_OFFSET_BELOW)
- iwl_conf->supported_chan_width = 0;
-
- iwl_conf->tx_mimo_ps_mode =
- (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2);
- memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16);
-
- iwl_conf->control_channel = ht_bss_conf->primary_channel;
- iwl_conf->tx_chan_width =
- !!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH);
- iwl_conf->ht_protection =
- ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION;
- iwl_conf->non_GF_STA_present =
- !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT);
-
- IWL_DEBUG_MAC80211("control channel %d\n", iwl_conf->control_channel);
- IWL_DEBUG_MAC80211("leave\n");
-}
-#else
-static inline void iwl4965_ht_conf(struct iwl_priv *priv,
- struct ieee80211_bss_conf *bss_conf)
-{
-}
-#endif
-
#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
@@ -6680,7 +4164,7 @@
if (changes & BSS_CHANGED_HT) {
IWL_DEBUG_MAC80211("HT %d\n", bss_conf->assoc_ht);
iwl4965_ht_conf(priv, bss_conf);
- iwl4965_set_rxon_chain(priv);
+ iwl_set_rxon_chain(priv);
}
if (changes & BSS_CHANGED_ASSOC) {
@@ -6780,7 +4264,7 @@
IWL_DEBUG_MAC80211("enter\n");
- sta_id = iwl4965_hw_find_station(priv, addr);
+ sta_id = iwl_find_station(priv, addr);
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
print_mac(mac, addr));
@@ -6808,7 +4292,7 @@
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
- iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+ iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
spin_unlock_irqrestore(&priv->sta_lock, flags);
@@ -6827,7 +4311,7 @@
IWL_DEBUG_MAC80211("enter\n");
- if (priv->cfg->mod_params->sw_crypto) {
+ if (priv->hw_params.sw_crypto) {
IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n");
return -EOPNOTSUPP;
}
@@ -6836,7 +4320,7 @@
/* only support pairwise keys */
return -EOPNOTSUPP;
- sta_id = iwl4965_hw_find_station(priv, addr);
+ sta_id = iwl_find_station(priv, addr);
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
print_mac(mac, addr));
@@ -6857,7 +4341,8 @@
if (cmd == SET_KEY)
is_default_wep_key = !priv->key_mapping_key;
else
- is_default_wep_key = priv->default_wep_key;
+ is_default_wep_key =
+ (key->hw_key_idx == HW_KEY_DEFAULT);
}
switch (cmd) {
@@ -6873,7 +4358,7 @@
if (is_default_wep_key)
ret = iwl_remove_default_wep_key(priv, key);
else
- ret = iwl_remove_dynamic_key(priv, sta_id);
+ ret = iwl_remove_dynamic_key(priv, key, sta_id);
IWL_DEBUG_MAC80211("disable hwcrypto key\n");
break;
@@ -6886,7 +4371,7 @@
return ret;
}
-static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, int queue,
+static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct iwl_priv *priv = hw->priv;
@@ -6942,8 +4427,8 @@
{
struct iwl_priv *priv = hw->priv;
int i, avail;
- struct iwl4965_tx_queue *txq;
- struct iwl4965_queue *q;
+ struct iwl_tx_queue *txq;
+ struct iwl_queue *q;
unsigned long flags;
IWL_DEBUG_MAC80211("enter\n");
@@ -6958,11 +4443,11 @@
for (i = 0; i < AC_NUM; i++) {
txq = &priv->txq[i];
q = &txq->q;
- avail = iwl4965_queue_space(q);
+ avail = iwl_queue_space(q);
- stats->data[i].len = q->n_window - avail;
- stats->data[i].limit = q->n_window - q->high_mark;
- stats->data[i].count = q->n_window;
+ stats[i].len = q->n_window - avail;
+ stats[i].limit = q->n_window - q->high_mark;
+ stats[i].count = q->n_window;
}
spin_unlock_irqrestore(&priv->lock, flags);
@@ -6975,6 +4460,9 @@
static int iwl4965_mac_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats)
{
+ struct iwl_priv *priv = hw->priv;
+
+ priv = hw->priv;
IWL_DEBUG_MAC80211("enter\n");
IWL_DEBUG_MAC80211("leave\n");
@@ -6983,6 +4471,9 @@
static u64 iwl4965_mac_get_tsf(struct ieee80211_hw *hw)
{
+ struct iwl_priv *priv;
+
+ priv = hw->priv;
IWL_DEBUG_MAC80211("enter\n");
IWL_DEBUG_MAC80211("leave\n");
@@ -7004,7 +4495,7 @@
spin_unlock_irqrestore(&priv->lock, flags);
#endif /* CONFIG_IWL4965_HT */
- iwlcore_reset_qos(priv);
+ iwl_reset_qos(priv);
cancel_delayed_work(&priv->post_associate);
@@ -7041,6 +4532,8 @@
iwl4965_commit_rxon(priv);
}
+ iwl_power_update_mode(priv, 0);
+
/* Per mac80211.h: This is only used in IBSS mode... */
if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
@@ -7056,8 +4549,7 @@
IWL_DEBUG_MAC80211("leave\n");
}
-static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct iwl_priv *priv = hw->priv;
unsigned long flags;
@@ -7089,7 +4581,7 @@
IWL_DEBUG_MAC80211("leave\n");
spin_unlock_irqrestore(&priv->lock, flags);
- iwlcore_reset_qos(priv);
+ iwl_reset_qos(priv);
queue_work(priv->workqueue, &priv->post_associate.work);
@@ -7114,13 +4606,18 @@
* See the level definitions in iwl for details.
*/
-static ssize_t show_debug_level(struct device_driver *d, char *buf)
+static ssize_t show_debug_level(struct device *d,
+ struct device_attribute *attr, char *buf)
{
- return sprintf(buf, "0x%08X\n", iwl_debug_level);
+ struct iwl_priv *priv = d->driver_data;
+
+ return sprintf(buf, "0x%08X\n", priv->debug_level);
}
-static ssize_t store_debug_level(struct device_driver *d,
+static ssize_t store_debug_level(struct device *d,
+ struct device_attribute *attr,
const char *buf, size_t count)
{
+ struct iwl_priv *priv = d->driver_data;
char *p = (char *)buf;
u32 val;
@@ -7129,17 +4626,37 @@
printk(KERN_INFO DRV_NAME
": %s is not in hex or decimal form.\n", buf);
else
- iwl_debug_level = val;
+ priv->debug_level = val;
return strnlen(buf, count);
}
-static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
- show_debug_level, store_debug_level);
+static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO,
+ show_debug_level, store_debug_level);
+
#endif /* CONFIG_IWLWIFI_DEBUG */
+static ssize_t show_version(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = d->driver_data;
+ struct iwl_alive_resp *palive = &priv->card_alive;
+
+ if (palive->is_valid)
+ return sprintf(buf, "fw version: 0x%01X.0x%01X.0x%01X.0x%01X\n"
+ "fw type: 0x%01X 0x%01X\n",
+ palive->ucode_major, palive->ucode_minor,
+ palive->sw_rev[0], palive->sw_rev[1],
+ palive->ver_type, palive->ver_subtype);
+
+ else
+ return sprintf(buf, "fw not loaded\n");
+}
+
+static DEVICE_ATTR(version, S_IWUSR | S_IRUGO, show_version, NULL);
+
static ssize_t show_temperature(struct device *d,
struct device_attribute *attr, char *buf)
{
@@ -7372,20 +4889,11 @@
goto out;
}
- if ((mode < 1) || (mode > IWL_POWER_LIMIT) || (mode == IWL_POWER_AC))
- mode = IWL_POWER_AC;
- else
- mode |= IWL_POWER_ENABLED;
-
- if (mode != priv->power_mode) {
- rc = iwl4965_send_power_mode(priv, IWL_POWER_LEVEL(mode));
- if (rc) {
- IWL_DEBUG_MAC80211("failed setting power mode.\n");
- goto out;
- }
- priv->power_mode = mode;
+ rc = iwl_power_set_user_mode(priv, mode);
+ if (rc) {
+ IWL_DEBUG_MAC80211("failed setting power mode.\n");
+ goto out;
}
-
rc = count;
out:
@@ -7415,7 +4923,7 @@
struct device_attribute *attr, char *buf)
{
struct iwl_priv *priv = dev_get_drvdata(d);
- int level = IWL_POWER_LEVEL(priv->power_mode);
+ int level = priv->power_data.power_mode;
char *p = buf;
p += sprintf(p, "%d ", level);
@@ -7433,14 +4941,14 @@
timeout_duration[level - 1] / 1000,
period_duration[level - 1] / 1000);
}
-
+/*
if (!(priv->power_mode & IWL_POWER_ENABLED))
p += sprintf(p, " OFF\n");
else
p += sprintf(p, " \n");
-
+*/
+ p += sprintf(p, " \n");
return (p - buf + 1);
-
}
static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
@@ -7493,44 +5001,6 @@
static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL);
-static ssize_t show_antenna(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
-
- if (!iwl_is_alive(priv))
- return -EAGAIN;
-
- return sprintf(buf, "%d\n", priv->antenna);
-}
-
-static ssize_t store_antenna(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- int ant;
- struct iwl_priv *priv = dev_get_drvdata(d);
-
- if (count == 0)
- return 0;
-
- if (sscanf(buf, "%1i", &ant) != 1) {
- IWL_DEBUG_INFO("not in hex or decimal form.\n");
- return count;
- }
-
- if ((ant >= 0) && (ant <= 2)) {
- IWL_DEBUG_INFO("Setting antenna select to %d.\n", ant);
- priv->antenna = (enum iwl4965_antenna)ant;
- } else
- IWL_DEBUG_INFO("Bad antenna select value %d.\n", ant);
-
-
- return count;
-}
-
-static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna);
-
static ssize_t show_status(struct device *d,
struct device_attribute *attr, char *buf)
{
@@ -7542,34 +5012,6 @@
static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
-static ssize_t dump_error_log(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- char *p = (char *)buf;
-
- if (p[0] == '1')
- iwl4965_dump_nic_error_log((struct iwl_priv *)d->driver_data);
-
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log);
-
-static ssize_t dump_event_log(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- char *p = (char *)buf;
-
- if (p[0] == '1')
- iwl4965_dump_nic_event_log((struct iwl_priv *)d->driver_data);
-
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);
-
/*****************************************************************************
*
* driver setup and teardown
@@ -7590,9 +5032,10 @@
INIT_WORK(&priv->abort_scan, iwl4965_bg_abort_scan);
INIT_WORK(&priv->rf_kill, iwl4965_bg_rf_kill);
INIT_WORK(&priv->beacon_update, iwl4965_bg_beacon_update);
+ INIT_WORK(&priv->set_monitor, iwl4965_bg_set_monitor);
INIT_DELAYED_WORK(&priv->post_associate, iwl4965_bg_post_associate);
- INIT_DELAYED_WORK(&priv->init_alive_start, iwl4965_bg_init_alive_start);
- INIT_DELAYED_WORK(&priv->alive_start, iwl4965_bg_alive_start);
+ INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
+ INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
INIT_DELAYED_WORK(&priv->scan_check, iwl4965_bg_scan_check);
iwl4965_hw_setup_deferred_work(priv);
@@ -7613,10 +5056,7 @@
}
static struct attribute *iwl4965_sysfs_entries[] = {
- &dev_attr_antenna.attr,
&dev_attr_channels.attr,
- &dev_attr_dump_errors.attr,
- &dev_attr_dump_events.attr,
&dev_attr_flags.attr,
&dev_attr_filter_flags.attr,
#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
@@ -7629,6 +5069,10 @@
&dev_attr_status.attr,
&dev_attr_temperature.attr,
&dev_attr_tx_power.attr,
+#ifdef CONFIG_IWLWIFI_DEBUG
+ &dev_attr_debug_level.attr,
+#endif
+ &dev_attr_version.attr,
NULL
};
@@ -7678,7 +5122,9 @@
/* Disabling hardware scan means that mac80211 will perform scans
* "the hard way", rather than using device's scan. */
if (cfg->mod_params->disable_hw_scan) {
- IWL_DEBUG_INFO("Disabling hw_scan\n");
+ if (cfg->mod_params->debug & IWL_DL_INFO)
+ dev_printk(KERN_DEBUG, &(pdev->dev),
+ "Disabling hw_scan\n");
iwl4965_hw_ops.hw_scan = NULL;
}
@@ -7697,7 +5143,7 @@
priv->pci_dev = pdev;
#ifdef CONFIG_IWLWIFI_DEBUG
- iwl_debug_level = priv->cfg->mod_params->debug;
+ priv->debug_level = priv->cfg->mod_params->debug;
atomic_set(&priv->restrict_refcnt, 0);
#endif
@@ -7711,13 +5157,19 @@
pci_set_master(pdev);
- err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
if (!err)
- err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ if (err) {
+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (!err)
+ err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ /* both attempts failed: */
if (err) {
- printk(KERN_WARNING DRV_NAME
- ": No suitable DMA available.\n");
+ printk(KERN_WARNING "%s: No suitable DMA available.\n",
+ DRV_NAME);
goto out_pci_disable_device;
+ }
}
err = pci_request_regions(pdev, DRV_NAME);
@@ -7743,31 +5195,31 @@
(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;
}
- /* MAC Address location in EEPROM same for 3945/4965 */
+ err = iwl_eeprom_check_version(priv);
+ if (err)
+ goto out_iounmap;
+
+ /* extract MAC Address */
iwl_eeprom_get_mac(priv, priv->mac_addr);
IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr));
SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
@@ -7778,16 +5230,16 @@
/* Device-specific setup */
if (priv->cfg->ops->lib->set_hw_params(priv)) {
IWL_ERROR("failed to set hw parameters\n");
- goto out_iounmap;
+ goto out_free_eeprom;
}
/*******************
- * 6. Setup hw/priv
+ * 6. Setup priv
*******************/
- err = iwl_setup(priv);
+ err = iwl_init_drv(priv);
if (err)
- goto out_unset_hw_params;
+ goto out_free_eeprom;
/* At this point both hw and priv are initialized. */
/**********************************
@@ -7800,9 +5252,6 @@
IWL_DEBUG_INFO("Radio disabled.\n");
}
- if (priv->cfg->mod_params->enable_qos)
- priv->qos_data.qos_enable = 1;
-
/********************
* 8. Setup services
********************/
@@ -7813,14 +5262,9 @@
err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group);
if (err) {
IWL_ERROR("failed to create sysfs device attributes\n");
- goto out_unset_hw_params;
+ goto out_uninit_drv;
}
- err = iwl_dbgfs_register(priv, DRV_NAME);
- if (err) {
- IWL_ERROR("failed to create debugfs files\n");
- goto out_remove_sysfs;
- }
iwl4965_setup_deferred_work(priv);
iwl4965_setup_rx_handlers(priv);
@@ -7831,14 +5275,28 @@
pci_save_state(pdev);
pci_disable_device(pdev);
+ /**********************************
+ * 10. Setup and register mac80211
+ **********************************/
+
+ err = iwl_setup_mac(priv);
+ if (err)
+ goto out_remove_sysfs;
+
+ err = iwl_dbgfs_register(priv, DRV_NAME);
+ if (err)
+ IWL_ERROR("failed to create debugfs files\n");
+
/* notify iwlcore to init */
iwlcore_low_level_notify(priv, IWLCORE_INIT_EVT);
return 0;
out_remove_sysfs:
sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
- out_unset_hw_params:
- iwl4965_unset_hw_params(priv);
+ out_uninit_drv:
+ iwl_uninit_drv(priv);
+ out_free_eeprom:
+ iwl_eeprom_free(priv);
out_iounmap:
pci_iounmap(pdev, priv->hw_base);
out_pci_release_regions:
@@ -7864,6 +5322,9 @@
IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n");
+ iwl_dbgfs_unregister(priv);
+ sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
+
if (priv->mac80211_registered) {
ieee80211_unregister_hw(priv->hw);
priv->mac80211_registered = 0;
@@ -7891,17 +5352,15 @@
}
iwlcore_low_level_notify(priv, IWLCORE_REMOVE_EVT);
- iwl_dbgfs_unregister(priv);
- sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
iwl4965_dealloc_ucode_pci(priv);
if (priv->rxq.bd)
- iwl4965_rx_queue_free(priv, &priv->rxq);
- iwl4965_hw_txq_ctx_free(priv);
+ iwl_rx_queue_free(priv, &priv->rxq);
+ iwl_hw_txq_ctx_free(priv);
- iwl4965_unset_hw_params(priv);
iwlcore_clear_stations_table(priv);
+ iwl_eeprom_free(priv);
/*netif_stop_queue(dev); */
@@ -7918,8 +5377,7 @@
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
- iwl_free_channel_map(priv);
- iwl4965_free_geos(priv);
+ iwl_uninit_drv(priv);
if (priv->ibss_beacon)
dev_kfree_skb(priv->ibss_beacon);
@@ -7969,6 +5427,11 @@
static struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)},
{IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)},
+#ifdef CONFIG_IWL5000
+ {IWL_PCI_DEVICE(0x4235, PCI_ANY_ID, iwl5300_agn_cfg)},
+ {IWL_PCI_DEVICE(0x4232, PCI_ANY_ID, iwl5100_agn_cfg)},
+ {IWL_PCI_DEVICE(0x423A, PCI_ANY_ID, iwl5350_agn_cfg)},
+#endif /* CONFIG_IWL5000 */
{0}
};
MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
@@ -8002,20 +5465,9 @@
IWL_ERROR("Unable to initialize PCI module\n");
goto error_register;
}
-#ifdef CONFIG_IWLWIFI_DEBUG
- ret = driver_create_file(&iwl_driver.driver, &driver_attr_debug_level);
- if (ret) {
- IWL_ERROR("Unable to create driver sysfs file\n");
- goto error_debug;
- }
-#endif
return ret;
-#ifdef CONFIG_IWLWIFI_DEBUG
-error_debug:
- pci_unregister_driver(&iwl_driver);
-#endif
error_register:
iwl4965_rate_control_unregister();
return ret;
@@ -8023,9 +5475,6 @@
static void __exit iwl4965_exit(void)
{
-#ifdef CONFIG_IWLWIFI_DEBUG
- driver_remove_file(&iwl_driver.driver, &driver_attr_debug_level);
-#endif
pci_unregister_driver(&iwl_driver);
iwl4965_rate_control_unregister();
}
diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile
index f0724e3..02080a3 100644
--- a/drivers/net/wireless/libertas/Makefile
+++ b/drivers/net/wireless/libertas/Makefile
@@ -1,9 +1,5 @@
-libertas-objs := main.o wext.o \
- rx.o tx.o cmd.o \
- cmdresp.o scan.o \
- 11d.o \
- debugfs.o \
- ethtool.o assoc.o
+libertas-objs := main.o wext.o rx.o tx.o cmd.o cmdresp.o scan.o 11d.o \
+ debugfs.o persistcfg.o ethtool.o assoc.o
usb8xxx-objs += if_usb.o
libertas_cs-objs += if_cs.o
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index c9c3640..a267d6e 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -603,7 +603,8 @@
/* Change mesh channel first; 21.p21 firmware won't let
you change channel otherwise (even though it'll return
an error to this */
- lbs_mesh_config(priv, 0, assoc_req->channel);
+ lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
+ assoc_req->channel);
}
lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
@@ -642,7 +643,8 @@
restore_mesh:
if (priv->mesh_dev)
- lbs_mesh_config(priv, 1, priv->curbssparams.channel);
+ lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
+ priv->curbssparams.channel);
done:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
@@ -1248,7 +1250,7 @@
lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
- if (!priv->auto_rate) {
+ if (!priv->enablehwauto) {
for (i = 0; i < tmp_size; i++) {
if (tmp[i] == priv->cur_rate)
goto done;
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 8124fd9..75427e6 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -4,6 +4,7 @@
*/
#include <net/iw_handler.h>
+#include <net/ieee80211.h>
#include <linux/kfifo.h>
#include "host.h"
#include "hostcmd.h"
@@ -109,7 +110,7 @@
* CF card firmware 5.0.16p0: cap 0x00000303
* USB dongle firmware 5.110.17p2: cap 0x00000303
*/
- printk("libertas: %s, fw %u.%u.%up%u, cap 0x%08x\n",
+ lbs_pr_info("%s, fw %u.%u.%up%u, cap 0x%08x\n",
print_mac(mac, cmd.permanentaddr),
priv->fwrelease >> 24 & 0xff,
priv->fwrelease >> 16 & 0xff,
@@ -675,58 +676,60 @@
return 0;
}
-static int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
- struct cmd_ds_command *cmd,
- u16 cmd_action)
+static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok)
{
- struct cmd_ds_802_11_rate_adapt_rateset
- *rateadapt = &cmd->params.rateset;
+/* Bit Rate
+* 15:13 Reserved
+* 12 54 Mbps
+* 11 48 Mbps
+* 10 36 Mbps
+* 9 24 Mbps
+* 8 18 Mbps
+* 7 12 Mbps
+* 6 9 Mbps
+* 5 6 Mbps
+* 4 Reserved
+* 3 11 Mbps
+* 2 5.5 Mbps
+* 1 2 Mbps
+* 0 1 Mbps
+**/
- lbs_deb_enter(LBS_DEB_CMD);
- cmd->size =
- cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset)
- + S_DS_GEN);
- cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET);
-
- rateadapt->action = cpu_to_le16(cmd_action);
- rateadapt->enablehwauto = cpu_to_le16(priv->enablehwauto);
- rateadapt->bitmap = cpu_to_le16(priv->ratebitmap);
-
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
+ uint16_t ratemask;
+ int i = lbs_data_rate_to_fw_index(rate);
+ if (lower_rates_ok)
+ ratemask = (0x1fef >> (12 - i));
+ else
+ ratemask = (1 << i);
+ return cpu_to_le16(ratemask);
}
-/**
- * @brief Get the current data rate
- *
- * @param priv A pointer to struct lbs_private structure
- *
- * @return The data rate on success, error on failure
- */
-int lbs_get_data_rate(struct lbs_private *priv)
+int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
+ uint16_t cmd_action)
{
- struct cmd_ds_802_11_data_rate cmd;
- int ret = -1;
+ struct cmd_ds_802_11_rate_adapt_rateset cmd;
+ int ret;
lbs_deb_enter(LBS_DEB_CMD);
- memset(&cmd, 0, sizeof(cmd));
+ if (!priv->cur_rate && !priv->enablehwauto)
+ return -EINVAL;
+
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
- cmd.action = cpu_to_le16(CMD_ACT_GET_TX_RATE);
- ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
- if (ret)
- goto out;
+ cmd.action = cpu_to_le16(cmd_action);
+ cmd.enablehwauto = cpu_to_le16(priv->enablehwauto);
+ cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto);
+ ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, &cmd);
+ if (!ret && cmd_action == CMD_ACT_GET) {
+ priv->ratebitmap = le16_to_cpu(cmd.bitmap);
+ priv->enablehwauto = le16_to_cpu(cmd.enablehwauto);
+ }
- lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof (cmd));
-
- ret = (int) lbs_fw_index_to_data_rate(cmd.rates[0]);
- lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", ret);
-
-out:
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
+EXPORT_SYMBOL_GPL(lbs_cmd_802_11_rate_adapt_rateset);
/**
* @brief Set the data rate
@@ -778,28 +781,6 @@
return ret;
}
-static int lbs_cmd_mac_multicast_adr(struct lbs_private *priv,
- struct cmd_ds_command *cmd,
- u16 cmd_action)
-{
- struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;
-
- lbs_deb_enter(LBS_DEB_CMD);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
- S_DS_GEN);
- cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR);
-
- lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs);
- pMCastAdr->action = cpu_to_le16(cmd_action);
- pMCastAdr->nr_of_adrs =
- cpu_to_le16((u16) priv->nr_of_multicastmacaddr);
- memcpy(pMCastAdr->maclist, priv->multicastlist,
- priv->nr_of_multicastmacaddr * ETH_ALEN);
-
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
-}
-
/**
* @brief Get the radio channel
*
@@ -1052,24 +1033,69 @@
return ret;
}
-int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan)
+int lbs_mesh_config_send(struct lbs_private *priv,
+ struct cmd_ds_mesh_config *cmd,
+ uint16_t action, uint16_t type)
+{
+ int ret;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ cmd->hdr.command = cpu_to_le16(CMD_MESH_CONFIG);
+ cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
+ cmd->hdr.result = 0;
+
+ cmd->type = cpu_to_le16(type);
+ cmd->action = cpu_to_le16(action);
+
+ ret = lbs_cmd_with_response(priv, CMD_MESH_CONFIG, cmd);
+
+ lbs_deb_leave(LBS_DEB_CMD);
+ return ret;
+}
+
+/* This function is the CMD_MESH_CONFIG legacy function. It only handles the
+ * START and STOP actions. The extended actions supported by CMD_MESH_CONFIG
+ * are all handled by preparing a struct cmd_ds_mesh_config and passing it to
+ * lbs_mesh_config_send.
+ */
+int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
{
struct cmd_ds_mesh_config cmd;
+ struct mrvl_meshie *ie;
memset(&cmd, 0, sizeof(cmd));
- cmd.action = cpu_to_le16(enable);
cmd.channel = cpu_to_le16(chan);
- cmd.type = cpu_to_le16(priv->mesh_tlv);
- cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+ ie = (struct mrvl_meshie *)cmd.data;
- if (enable) {
- cmd.length = cpu_to_le16(priv->mesh_ssid_len);
- memcpy(cmd.data, priv->mesh_ssid, priv->mesh_ssid_len);
+ switch (action) {
+ case CMD_ACT_MESH_CONFIG_START:
+ ie->hdr.id = MFIE_TYPE_GENERIC;
+ ie->val.oui[0] = 0x00;
+ ie->val.oui[1] = 0x50;
+ ie->val.oui[2] = 0x43;
+ ie->val.type = MARVELL_MESH_IE_TYPE;
+ ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
+ ie->val.version = MARVELL_MESH_IE_VERSION;
+ ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
+ ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
+ ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
+ ie->val.mesh_id_len = priv->mesh_ssid_len;
+ memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
+ ie->hdr.len = sizeof(struct mrvl_meshie_val) -
+ IW_ESSID_MAX_SIZE + priv->mesh_ssid_len;
+ cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
+ break;
+ case CMD_ACT_MESH_CONFIG_STOP:
+ break;
+ default:
+ return -1;
}
- lbs_deb_cmd("mesh config enable %d TLV %x channel %d SSID %s\n",
- enable, priv->mesh_tlv, chan,
+ lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
+ action, priv->mesh_tlv, chan,
escape_essid(priv->mesh_ssid, priv->mesh_ssid_len));
- return lbs_cmd_with_response(priv, CMD_MESH_CONFIG, &cmd);
+
+ return lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
}
static int lbs_cmd_bcn_ctrl(struct lbs_private * priv,
@@ -1144,7 +1170,7 @@
struct cmd_header *cmd;
uint16_t cmdsize;
uint16_t command;
- int timeo = 5 * HZ;
+ int timeo = 3 * HZ;
int ret;
lbs_deb_enter(LBS_DEB_HOST);
@@ -1162,7 +1188,7 @@
/* These commands take longer */
if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE ||
command == CMD_802_11_AUTHENTICATE)
- timeo = 10 * HZ;
+ timeo = 5 * HZ;
lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n",
command, le16_to_cpu(cmd->seqnum), cmdsize);
@@ -1174,7 +1200,7 @@
lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret);
/* Let the timer kick in and retry, and potentially reset
the whole thing if the condition persists */
- timeo = HZ;
+ timeo = HZ/4;
}
/* Setup the timer after transmit command */
@@ -1279,8 +1305,7 @@
cmd.action = cpu_to_le16(priv->mac_control);
cmd.reserved = 0;
- lbs_cmd_async(priv, CMD_MAC_CONTROL,
- &cmd.hdr, sizeof(cmd));
+ lbs_cmd_async(priv, CMD_MAC_CONTROL, &cmd.hdr, sizeof(cmd));
lbs_deb_leave(LBS_DEB_CMD);
}
@@ -1387,15 +1412,6 @@
cmd_action, pdata_buf);
break;
- case CMD_802_11_RATE_ADAPT_RATESET:
- ret = lbs_cmd_802_11_rate_adapt_rateset(priv,
- cmdptr, cmd_action);
- break;
-
- case CMD_MAC_MULTICAST_ADR:
- ret = lbs_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
- break;
-
case CMD_802_11_MONITOR_MODE:
ret = lbs_cmd_802_11_monitor_mode(cmdptr,
cmd_action, pdata_buf);
@@ -1484,7 +1500,7 @@
ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
break;
default:
- lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no);
+ lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no);
ret = -1;
break;
}
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h
index 3dfc2d4..a53b51f 100644
--- a/drivers/net/wireless/libertas/cmd.h
+++ b/drivers/net/wireless/libertas/cmd.h
@@ -34,18 +34,22 @@
int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
struct cmd_ds_mesh_access *cmd);
-int lbs_get_data_rate(struct lbs_private *priv);
int lbs_set_data_rate(struct lbs_private *priv, u8 rate);
int lbs_get_channel(struct lbs_private *priv);
int lbs_set_channel(struct lbs_private *priv, u8 channel);
+int lbs_mesh_config_send(struct lbs_private *priv,
+ struct cmd_ds_mesh_config *cmd,
+ uint16_t action, uint16_t type);
int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria);
int lbs_suspend(struct lbs_private *priv);
-int lbs_resume(struct lbs_private *priv);
+void lbs_resume(struct lbs_private *priv);
+int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
+ uint16_t cmd_action);
int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
uint16_t cmd_action, uint16_t *timeout);
int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 5abecb7..24de3c3 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -203,22 +203,6 @@
return 0;
}
-static int lbs_ret_802_11_rate_adapt_rateset(struct lbs_private *priv,
- struct cmd_ds_command *resp)
-{
- struct cmd_ds_802_11_rate_adapt_rateset *rates = &resp->params.rateset;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- if (rates->action == CMD_ACT_GET) {
- priv->enablehwauto = le16_to_cpu(rates->enablehwauto);
- priv->ratebitmap = le16_to_cpu(rates->bitmap);
- }
-
- lbs_deb_leave(LBS_DEB_CMD);
- return 0;
-}
-
static int lbs_ret_802_11_rssi(struct lbs_private *priv,
struct cmd_ds_command *resp)
{
@@ -316,16 +300,11 @@
break;
- case CMD_RET(CMD_MAC_MULTICAST_ADR):
case CMD_RET(CMD_802_11_RESET):
case CMD_RET(CMD_802_11_AUTHENTICATE):
case CMD_RET(CMD_802_11_BEACON_STOP):
break;
- case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET):
- ret = lbs_ret_802_11_rate_adapt_rateset(priv, resp);
- break;
-
case CMD_RET(CMD_802_11_RSSI):
ret = lbs_ret_802_11_rssi(priv, resp);
break;
@@ -376,8 +355,8 @@
break;
default:
- lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n",
- le16_to_cpu(resp->command));
+ lbs_pr_err("CMD_RESP: unknown cmd response 0x%04x\n",
+ le16_to_cpu(resp->command));
break;
}
lbs_deb_leave(LBS_DEB_HOST);
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index b652fa3..a8ac974 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -60,13 +60,17 @@
void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str);
+/* persistcfg.c */
+void lbs_persist_config_init(struct net_device *net);
+void lbs_persist_config_remove(struct net_device *net);
+
/* main.c */
struct chan_freq_power *lbs_get_region_cfp_table(u8 region,
int *cfp_no);
struct lbs_private *lbs_add_card(void *card, struct device *dmdev);
-int lbs_remove_card(struct lbs_private *priv);
+void lbs_remove_card(struct lbs_private *priv);
int lbs_start_card(struct lbs_private *priv);
-int lbs_stop_card(struct lbs_private *priv);
+void lbs_stop_card(struct lbs_private *priv);
void lbs_host_to_card_done(struct lbs_private *priv);
int lbs_update_channel(struct lbs_private *priv);
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index d395201..12e6875 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -40,6 +40,7 @@
#define LBS_DEB_THREAD 0x00100000
#define LBS_DEB_HEX 0x00200000
#define LBS_DEB_SDIO 0x00400000
+#define LBS_DEB_SYSFS 0x00800000
extern unsigned int lbs_debug;
@@ -81,7 +82,8 @@
#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args)
#define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args)
#define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args)
-#define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " thread", fmt, ##args)
+#define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " sdio", fmt, ##args)
+#define lbs_deb_sysfs(fmt, args...) LBS_DEB_LL(LBS_DEB_SYSFS, " sysfs", fmt, ##args)
#define lbs_pr_info(format, args...) \
printk(KERN_INFO DRV_NAME": " format, ## args)
@@ -170,6 +172,16 @@
#define MARVELL_MESH_IE_LENGTH 9
+/* Values used to populate the struct mrvl_mesh_ie. The only time you need this
+ * is when enabling the mesh using CMD_MESH_CONFIG.
+ */
+#define MARVELL_MESH_IE_TYPE 4
+#define MARVELL_MESH_IE_SUBTYPE 0
+#define MARVELL_MESH_IE_VERSION 0
+#define MARVELL_MESH_PROTO_ID_HWMP 0
+#define MARVELL_MESH_METRIC_ID 0
+#define MARVELL_MESH_CAPABILITY 0
+
/** INT status Bit Definition*/
#define MRVDRV_TX_DNLD_RDY 0x0001
#define MRVDRV_RX_UPLD_RDY 0x0002
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 0d9edb9..f5bb40c 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -140,6 +140,8 @@
wait_queue_head_t waitq;
struct workqueue_struct *work_thread;
+ struct work_struct mcast_work;
+
/** Scanning */
struct delayed_work scan_work;
struct delayed_work assoc_work;
@@ -151,6 +153,7 @@
/** Hardware access */
int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
+ void (*reset_card) (struct lbs_private *priv);
/* Wake On LAN */
uint32_t wol_criteria;
@@ -234,8 +237,8 @@
/** 802.11 statistics */
// struct cmd_DS_802_11_GET_STAT wlan802_11Stat;
- u16 enablehwauto;
- u16 ratebitmap;
+ uint16_t enablehwauto;
+ uint16_t ratebitmap;
u32 fragthsd;
u32 rtsthsd;
@@ -293,7 +296,6 @@
/** data rate stuff */
u8 cur_rate;
- u8 auto_rate;
/** RF calibration data */
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index 3915c31..c92e41b 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -256,6 +256,23 @@
CMD_ACT_MESH_GET_AUTOSTART_ENABLED,
};
+/* Define actions and types for CMD_MESH_CONFIG */
+enum cmd_mesh_config_actions {
+ CMD_ACT_MESH_CONFIG_STOP = 0,
+ CMD_ACT_MESH_CONFIG_START,
+ CMD_ACT_MESH_CONFIG_SET,
+ CMD_ACT_MESH_CONFIG_GET,
+};
+
+enum cmd_mesh_config_types {
+ CMD_TYPE_MESH_SET_BOOTFLAG = 1,
+ CMD_TYPE_MESH_SET_BOOTTIME,
+ CMD_TYPE_MESH_SET_DEF_CHANNEL,
+ CMD_TYPE_MESH_SET_MESH_IE,
+ CMD_TYPE_MESH_GET_DEFAULTS,
+ CMD_TYPE_MESH_GET_MESH_IE, /* GET_DEFAULTS is superset of GET_MESHIE */
+};
+
/** Card Event definition */
#define MACREG_INT_CODE_TX_PPA_FREE 0
#define MACREG_INT_CODE_TX_DMA_DONE 1
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
index f29bc5b..913b480 100644
--- a/drivers/net/wireless/libertas/hostcmd.h
+++ b/drivers/net/wireless/libertas/hostcmd.h
@@ -219,6 +219,7 @@
};
struct cmd_ds_mac_multicast_adr {
+ struct cmd_header hdr;
__le16 action;
__le16 nr_of_adrs;
u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
@@ -499,6 +500,7 @@
};
struct cmd_ds_802_11_rate_adapt_rateset {
+ struct cmd_header hdr;
__le16 action;
__le16 enablehwauto;
__le16 bitmap;
@@ -702,8 +704,6 @@
struct cmd_ds_802_11_rf_tx_power txp;
struct cmd_ds_802_11_rf_antenna rant;
struct cmd_ds_802_11_monitor_mode monitor;
- struct cmd_ds_802_11_rate_adapt_rateset rateset;
- struct cmd_ds_mac_multicast_adr madr;
struct cmd_ds_802_11_ad_hoc_join adj;
struct cmd_ds_802_11_rssi rssi;
struct cmd_ds_802_11_rssi_rsp rssirsp;
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index 54280e2..873ab10 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -148,76 +148,72 @@
{
int i;
- for (i = 0; i < 1000; i++) {
+ for (i = 0; i < 100000; i++) {
u8 val = if_cs_read8(card, addr);
if (val == reg)
return i;
- udelay(500);
+ udelay(5);
}
return -ETIME;
}
-/* Host control registers and their bit definitions */
+/* First the bitmasks for the host/card interrupt/status registers: */
+#define IF_CS_BIT_TX 0x0001
+#define IF_CS_BIT_RX 0x0002
+#define IF_CS_BIT_COMMAND 0x0004
+#define IF_CS_BIT_RESP 0x0008
+#define IF_CS_BIT_EVENT 0x0010
+#define IF_CS_BIT_MASK 0x001f
-#define IF_CS_H_STATUS 0x00000000
-#define IF_CS_H_STATUS_TX_OVER 0x0001
-#define IF_CS_H_STATUS_RX_OVER 0x0002
-#define IF_CS_H_STATUS_DNLD_OVER 0x0004
+/* And now the individual registers and assorted masks */
+#define IF_CS_HOST_STATUS 0x00000000
-#define IF_CS_H_INT_CAUSE 0x00000002
-#define IF_CS_H_IC_TX_OVER 0x0001
-#define IF_CS_H_IC_RX_OVER 0x0002
-#define IF_CS_H_IC_DNLD_OVER 0x0004
-#define IF_CS_H_IC_POWER_DOWN 0x0008
-#define IF_CS_H_IC_HOST_EVENT 0x0010
-#define IF_CS_H_IC_MASK 0x001f
+#define IF_CS_HOST_INT_CAUSE 0x00000002
-#define IF_CS_H_INT_MASK 0x00000004
-#define IF_CS_H_IM_MASK 0x001f
+#define IF_CS_HOST_INT_MASK 0x00000004
-#define IF_CS_H_WRITE_LEN 0x00000014
+#define IF_CS_HOST_WRITE 0x00000016
+#define IF_CS_HOST_WRITE_LEN 0x00000014
-#define IF_CS_H_WRITE 0x00000016
+#define IF_CS_HOST_CMD 0x0000001A
+#define IF_CS_HOST_CMD_LEN 0x00000018
-#define IF_CS_H_CMD_LEN 0x00000018
+#define IF_CS_READ 0x00000010
+#define IF_CS_READ_LEN 0x00000024
-#define IF_CS_H_CMD 0x0000001A
+#define IF_CS_CARD_CMD 0x00000012
+#define IF_CS_CARD_CMD_LEN 0x00000030
-#define IF_CS_C_READ_LEN 0x00000024
+#define IF_CS_CARD_STATUS 0x00000020
+#define IF_CS_CARD_STATUS_MASK 0x7f00
-#define IF_CS_H_READ 0x00000010
+#define IF_CS_CARD_INT_CAUSE 0x00000022
-/* Card control registers and their bit definitions */
-
-#define IF_CS_C_STATUS 0x00000020
-#define IF_CS_C_S_TX_DNLD_RDY 0x0001
-#define IF_CS_C_S_RX_UPLD_RDY 0x0002
-#define IF_CS_C_S_CMD_DNLD_RDY 0x0004
-#define IF_CS_C_S_CMD_UPLD_RDY 0x0008
-#define IF_CS_C_S_CARDEVENT 0x0010
-#define IF_CS_C_S_MASK 0x001f
-#define IF_CS_C_S_STATUS_MASK 0x7f00
-
-#define IF_CS_C_INT_CAUSE 0x00000022
-#define IF_CS_C_IC_MASK 0x001f
-
-#define IF_CS_C_SQ_READ_LOW 0x00000028
-#define IF_CS_C_SQ_HELPER_OK 0x10
-
-#define IF_CS_C_CMD_LEN 0x00000030
-
-#define IF_CS_C_CMD 0x00000012
+#define IF_CS_CARD_SQ_READ_LOW 0x00000028
+#define IF_CS_CARD_SQ_HELPER_OK 0x10
#define IF_CS_SCRATCH 0x0000003F
/********************************************************************/
-/* I/O */
+/* I/O and interrupt handling */
/********************************************************************/
+static inline void if_cs_enable_ints(struct if_cs_card *card)
+{
+ lbs_deb_enter(LBS_DEB_CS);
+ if_cs_write16(card, IF_CS_HOST_INT_MASK, 0);
+}
+
+static inline void if_cs_disable_ints(struct if_cs_card *card)
+{
+ lbs_deb_enter(LBS_DEB_CS);
+ if_cs_write16(card, IF_CS_HOST_INT_MASK, IF_CS_BIT_MASK);
+}
+
/*
* Called from if_cs_host_to_card to send a command to the hardware
*/
@@ -228,11 +224,12 @@
int loops = 0;
lbs_deb_enter(LBS_DEB_CS);
+ if_cs_disable_ints(card);
/* Is hardware ready? */
while (1) {
- u16 val = if_cs_read16(card, IF_CS_C_STATUS);
- if (val & IF_CS_C_S_CMD_DNLD_RDY)
+ u16 val = if_cs_read16(card, IF_CS_CARD_STATUS);
+ if (val & IF_CS_BIT_COMMAND)
break;
if (++loops > 100) {
lbs_pr_err("card not ready for commands\n");
@@ -241,51 +238,56 @@
mdelay(1);
}
- if_cs_write16(card, IF_CS_H_CMD_LEN, nb);
+ if_cs_write16(card, IF_CS_HOST_CMD_LEN, nb);
- if_cs_write16_rep(card, IF_CS_H_CMD, buf, nb / 2);
+ if_cs_write16_rep(card, IF_CS_HOST_CMD, buf, nb / 2);
/* Are we supposed to transfer an odd amount of bytes? */
if (nb & 1)
- if_cs_write8(card, IF_CS_H_CMD, buf[nb-1]);
+ if_cs_write8(card, IF_CS_HOST_CMD, buf[nb-1]);
/* "Assert the download over interrupt command in the Host
* status register" */
- if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);
+ if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND);
/* "Assert the download over interrupt command in the Card
* interrupt case register" */
- if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);
+ if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND);
ret = 0;
done:
+ if_cs_enable_ints(card);
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
return ret;
}
-
/*
* Called from if_cs_host_to_card to send a data to the hardware
*/
static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb)
{
struct if_cs_card *card = (struct if_cs_card *)priv->card;
+ u16 status;
lbs_deb_enter(LBS_DEB_CS);
+ if_cs_disable_ints(card);
- if_cs_write16(card, IF_CS_H_WRITE_LEN, nb);
+ status = if_cs_read16(card, IF_CS_CARD_STATUS);
+ BUG_ON((status & IF_CS_BIT_TX) == 0);
+
+ if_cs_write16(card, IF_CS_HOST_WRITE_LEN, nb);
/* write even number of bytes, then odd byte if necessary */
- if_cs_write16_rep(card, IF_CS_H_WRITE, buf, nb / 2);
+ if_cs_write16_rep(card, IF_CS_HOST_WRITE, buf, nb / 2);
if (nb & 1)
- if_cs_write8(card, IF_CS_H_WRITE, buf[nb-1]);
+ if_cs_write8(card, IF_CS_HOST_WRITE, buf[nb-1]);
- if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_TX_OVER);
- if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_STATUS_TX_OVER);
+ if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_TX);
+ if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_TX);
+ if_cs_enable_ints(card);
lbs_deb_leave(LBS_DEB_CS);
}
-
/*
* Get the command result out of the card.
*/
@@ -293,27 +295,28 @@
{
unsigned long flags;
int ret = -1;
- u16 val;
+ u16 status;
lbs_deb_enter(LBS_DEB_CS);
/* is hardware ready? */
- val = if_cs_read16(priv->card, IF_CS_C_STATUS);
- if ((val & IF_CS_C_S_CMD_UPLD_RDY) == 0) {
- lbs_pr_err("card not ready for CMD\n");
+ status = if_cs_read16(priv->card, IF_CS_CARD_STATUS);
+ if ((status & IF_CS_BIT_RESP) == 0) {
+ lbs_pr_err("no cmd response in card\n");
+ *len = 0;
goto out;
}
- *len = if_cs_read16(priv->card, IF_CS_C_CMD_LEN);
+ *len = if_cs_read16(priv->card, IF_CS_CARD_CMD_LEN);
if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) {
lbs_pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len);
goto out;
}
/* read even number of bytes, then odd byte if necessary */
- if_cs_read16_rep(priv->card, IF_CS_C_CMD, data, *len/sizeof(u16));
+ if_cs_read16_rep(priv->card, IF_CS_CARD_CMD, data, *len/sizeof(u16));
if (*len & 1)
- data[*len-1] = if_cs_read8(priv->card, IF_CS_C_CMD);
+ data[*len-1] = if_cs_read8(priv->card, IF_CS_CARD_CMD);
/* This is a workaround for a firmware that reports too much
* bytes */
@@ -330,7 +333,6 @@
return ret;
}
-
static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
{
struct sk_buff *skb = NULL;
@@ -339,7 +341,7 @@
lbs_deb_enter(LBS_DEB_CS);
- len = if_cs_read16(priv->card, IF_CS_C_READ_LEN);
+ len = if_cs_read16(priv->card, IF_CS_READ_LEN);
if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len);
priv->stats.rx_dropped++;
@@ -354,38 +356,19 @@
data = skb->data;
/* read even number of bytes, then odd byte if necessary */
- if_cs_read16_rep(priv->card, IF_CS_H_READ, data, len/sizeof(u16));
+ if_cs_read16_rep(priv->card, IF_CS_READ, data, len/sizeof(u16));
if (len & 1)
- data[len-1] = if_cs_read8(priv->card, IF_CS_H_READ);
+ data[len-1] = if_cs_read8(priv->card, IF_CS_READ);
dat_err:
- if_cs_write16(priv->card, IF_CS_H_STATUS, IF_CS_H_STATUS_RX_OVER);
- if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_RX_OVER);
+ if_cs_write16(priv->card, IF_CS_HOST_STATUS, IF_CS_BIT_RX);
+ if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_RX);
out:
lbs_deb_leave_args(LBS_DEB_CS, "ret %p", skb);
return skb;
}
-
-
-/********************************************************************/
-/* Interrupts */
-/********************************************************************/
-
-static inline void if_cs_enable_ints(struct if_cs_card *card)
-{
- lbs_deb_enter(LBS_DEB_CS);
- if_cs_write16(card, IF_CS_H_INT_MASK, 0);
-}
-
-static inline void if_cs_disable_ints(struct if_cs_card *card)
-{
- lbs_deb_enter(LBS_DEB_CS);
- if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK);
-}
-
-
static irqreturn_t if_cs_interrupt(int irq, void *data)
{
struct if_cs_card *card = data;
@@ -394,10 +377,8 @@
lbs_deb_enter(LBS_DEB_CS);
- cause = if_cs_read16(card, IF_CS_C_INT_CAUSE);
- if_cs_write16(card, IF_CS_C_INT_CAUSE, cause & IF_CS_C_IC_MASK);
-
- lbs_deb_cs("cause 0x%04x\n", cause);
+ /* Ask card interrupt cause register if there is something for us */
+ cause = if_cs_read16(card, IF_CS_CARD_INT_CAUSE);
if (cause == 0) {
/* Not for us */
return IRQ_NONE;
@@ -409,11 +390,11 @@
return IRQ_HANDLED;
}
- /* TODO: I'm not sure what the best ordering is */
+ /* Clear interrupt cause */
+ if_cs_write16(card, IF_CS_CARD_INT_CAUSE, cause & IF_CS_BIT_MASK);
+ lbs_deb_cs("cause 0x%04x\n", cause);
- cause = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK;
-
- if (cause & IF_CS_C_S_RX_UPLD_RDY) {
+ if (cause & IF_CS_BIT_RX) {
struct sk_buff *skb;
lbs_deb_cs("rx packet\n");
skb = if_cs_receive_data(priv);
@@ -421,16 +402,16 @@
lbs_process_rxed_packet(priv, skb);
}
- if (cause & IF_CS_H_IC_TX_OVER) {
- lbs_deb_cs("tx over\n");
+ if (cause & IF_CS_BIT_TX) {
+ lbs_deb_cs("tx done\n");
lbs_host_to_card_done(priv);
}
- if (cause & IF_CS_C_S_CMD_UPLD_RDY) {
+ if (cause & IF_CS_BIT_RESP) {
unsigned long flags;
u8 i;
- lbs_deb_cs("cmd upload ready\n");
+ lbs_deb_cs("cmd resp\n");
spin_lock_irqsave(&priv->driver_lock, flags);
i = (priv->resp_idx == 0) ? 1 : 0;
spin_unlock_irqrestore(&priv->driver_lock, flags);
@@ -444,15 +425,16 @@
spin_unlock_irqrestore(&priv->driver_lock, flags);
}
- if (cause & IF_CS_H_IC_HOST_EVENT) {
- u16 event = if_cs_read16(priv->card, IF_CS_C_STATUS)
- & IF_CS_C_S_STATUS_MASK;
- if_cs_write16(priv->card, IF_CS_H_INT_CAUSE,
- IF_CS_H_IC_HOST_EVENT);
- lbs_deb_cs("eventcause 0x%04x\n", event);
+ if (cause & IF_CS_BIT_EVENT) {
+ u16 event = if_cs_read16(priv->card, IF_CS_CARD_STATUS)
+ & IF_CS_CARD_STATUS_MASK;
+ if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE,
+ IF_CS_BIT_EVENT);
+ lbs_deb_cs("host event 0x%04x\n", event);
lbs_queue_event(priv, event >> 8 & 0xff);
}
+ lbs_deb_leave(LBS_DEB_CS);
return IRQ_HANDLED;
}
@@ -514,26 +496,26 @@
/* "write the number of bytes to be sent to the I/O Command
* write length register" */
- if_cs_write16(card, IF_CS_H_CMD_LEN, count);
+ if_cs_write16(card, IF_CS_HOST_CMD_LEN, count);
/* "write this to I/O Command port register as 16 bit writes */
if (count)
- if_cs_write16_rep(card, IF_CS_H_CMD,
+ if_cs_write16_rep(card, IF_CS_HOST_CMD,
&fw->data[sent],
count >> 1);
/* "Assert the download over interrupt command in the Host
* status register" */
- if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);
+ if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND);
/* "Assert the download over interrupt command in the Card
* interrupt case register" */
- if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);
+ if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND);
/* "The host polls the Card Status register ... for 50 ms before
declaring a failure */
- ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS,
- IF_CS_C_S_CMD_DNLD_RDY);
+ ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS,
+ IF_CS_BIT_COMMAND);
if (ret < 0) {
lbs_pr_err("can't download helper at 0x%x, ret %d\n",
sent, ret);
@@ -575,14 +557,15 @@
}
lbs_deb_cs("fw size %td\n", fw->size);
- ret = if_cs_poll_while_fw_download(card, IF_CS_C_SQ_READ_LOW, IF_CS_C_SQ_HELPER_OK);
+ ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_SQ_READ_LOW,
+ IF_CS_CARD_SQ_HELPER_OK);
if (ret < 0) {
lbs_pr_err("helper firmware doesn't answer\n");
goto err_release;
}
for (sent = 0; sent < fw->size; sent += len) {
- len = if_cs_read16(card, IF_CS_C_SQ_READ_LOW);
+ len = if_cs_read16(card, IF_CS_CARD_SQ_READ_LOW);
if (len & 1) {
retry++;
lbs_pr_info("odd, need to retry this firmware block\n");
@@ -600,16 +583,16 @@
}
- if_cs_write16(card, IF_CS_H_CMD_LEN, len);
+ if_cs_write16(card, IF_CS_HOST_CMD_LEN, len);
- if_cs_write16_rep(card, IF_CS_H_CMD,
+ if_cs_write16_rep(card, IF_CS_HOST_CMD,
&fw->data[sent],
(len+1) >> 1);
- if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);
- if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);
+ if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND);
+ if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND);
- ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS,
- IF_CS_C_S_CMD_DNLD_RDY);
+ ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS,
+ IF_CS_BIT_COMMAND);
if (ret < 0) {
lbs_pr_err("can't download firmware at 0x%x\n", sent);
goto err_release;
@@ -837,7 +820,7 @@
/* Clear any interrupt cause that happend while sending
* firmware/initializing card */
- if_cs_write16(card, IF_CS_C_INT_CAUSE, IF_CS_C_IC_MASK);
+ if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK);
if_cs_enable_ints(card);
/* And finally bring the card up */
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 8032df7..2478310 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -7,6 +7,10 @@
#include <linux/netdevice.h>
#include <linux/usb.h>
+#ifdef CONFIG_OLPC
+#include <asm/olpc.h>
+#endif
+
#define DRV_NAME "usb8xxx"
#include "host.h"
@@ -146,6 +150,14 @@
wake_up(&cardp->fw_wq);
}
+#ifdef CONFIG_OLPC
+static void if_usb_reset_olpc_card(struct lbs_private *priv)
+{
+ printk(KERN_CRIT "Resetting OLPC wireless via EC...\n");
+ olpc_ec_cmd(0x25, NULL, 0, NULL, 0);
+}
+#endif
+
/**
* @brief sets the configuration values
* @param ifnum interface number
@@ -231,6 +243,11 @@
cardp->priv->fw_ready = 1;
priv->hw_host_to_card = if_usb_host_to_card;
+#ifdef CONFIG_OLPC
+ if (machine_is_olpc())
+ priv->reset_card = if_usb_reset_olpc_card;
+#endif
+
cardp->boot2_version = udev->descriptor.bcdDevice;
if_usb_submit_rx_urb(cardp);
@@ -364,6 +381,11 @@
ret = usb_reset_device(cardp->udev);
msleep(100);
+#ifdef CONFIG_OLPC
+ if (ret && machine_is_olpc())
+ if_usb_reset_olpc_card(NULL);
+#endif
+
lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
return ret;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index acfc4bf..abd6d9e 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -11,6 +11,7 @@
#include <linux/if_arp.h>
#include <linux/kthread.h>
#include <linux/kfifo.h>
+#include <linux/stddef.h>
#include <net/iw_handler.h>
#include <net/ieee80211.h>
@@ -343,14 +344,15 @@
{
struct lbs_private *priv = to_net_dev(dev)->priv;
int enable;
- int ret;
+ int ret, action = CMD_ACT_MESH_CONFIG_STOP;
sscanf(buf, "%x", &enable);
enable = !!enable;
if (enable == !!priv->mesh_dev)
return count;
-
- ret = lbs_mesh_config(priv, enable, priv->curbssparams.channel);
+ if (enable)
+ action = CMD_ACT_MESH_CONFIG_START;
+ ret = lbs_mesh_config(priv, action, priv->curbssparams.channel);
if (ret)
return ret;
@@ -446,6 +448,8 @@
spin_unlock_irq(&priv->driver_lock);
+ schedule_work(&priv->mcast_work);
+
lbs_deb_leave(LBS_DEB_MESH);
return 0;
}
@@ -467,6 +471,8 @@
netif_stop_queue(dev);
spin_unlock_irq(&priv->driver_lock);
+ schedule_work(&priv->mcast_work);
+
lbs_deb_leave(LBS_DEB_NET);
return 0;
}
@@ -563,87 +569,114 @@
return ret;
}
-static int lbs_copy_multicast_address(struct lbs_private *priv,
- struct net_device *dev)
-{
- int i = 0;
- struct dev_mc_list *mcptr = dev->mc_list;
- for (i = 0; i < dev->mc_count; i++) {
- memcpy(&priv->multicastlist[i], mcptr->dmi_addr, ETH_ALEN);
- mcptr = mcptr->next;
+static inline int mac_in_list(unsigned char *list, int list_len,
+ unsigned char *mac)
+{
+ while (list_len) {
+ if (!memcmp(list, mac, ETH_ALEN))
+ return 1;
+ list += ETH_ALEN;
+ list_len--;
}
+ return 0;
+}
+
+
+static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd,
+ struct net_device *dev, int nr_addrs)
+{
+ int i = nr_addrs;
+ struct dev_mc_list *mc_list;
+ DECLARE_MAC_BUF(mac);
+
+ if ((dev->flags & (IFF_UP|IFF_MULTICAST)) != (IFF_UP|IFF_MULTICAST))
+ return nr_addrs;
+
+ netif_tx_lock_bh(dev);
+ for (mc_list = dev->mc_list; mc_list; mc_list = mc_list->next) {
+ if (mac_in_list(cmd->maclist, nr_addrs, mc_list->dmi_addr)) {
+ lbs_deb_net("mcast address %s:%s skipped\n", dev->name,
+ print_mac(mac, mc_list->dmi_addr));
+ continue;
+ }
+
+ if (i == MRVDRV_MAX_MULTICAST_LIST_SIZE)
+ break;
+ memcpy(&cmd->maclist[6*i], mc_list->dmi_addr, ETH_ALEN);
+ lbs_deb_net("mcast address %s:%s added to filter\n", dev->name,
+ print_mac(mac, mc_list->dmi_addr));
+ i++;
+ }
+ netif_tx_unlock_bh(dev);
+ if (mc_list)
+ return -EOVERFLOW;
+
return i;
}
+static void lbs_set_mcast_worker(struct work_struct *work)
+{
+ struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work);
+ struct cmd_ds_mac_multicast_adr mcast_cmd;
+ int dev_flags;
+ int nr_addrs;
+ int old_mac_control = priv->mac_control;
+
+ lbs_deb_enter(LBS_DEB_NET);
+
+ dev_flags = priv->dev->flags;
+ if (priv->mesh_dev)
+ dev_flags |= priv->mesh_dev->flags;
+
+ if (dev_flags & IFF_PROMISC) {
+ priv->mac_control |= CMD_ACT_MAC_PROMISCUOUS_ENABLE;
+ priv->mac_control &= ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE |
+ CMD_ACT_MAC_MULTICAST_ENABLE);
+ goto out_set_mac_control;
+ } else if (dev_flags & IFF_ALLMULTI) {
+ do_allmulti:
+ priv->mac_control |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
+ priv->mac_control &= ~(CMD_ACT_MAC_PROMISCUOUS_ENABLE |
+ CMD_ACT_MAC_MULTICAST_ENABLE);
+ goto out_set_mac_control;
+ }
+
+ /* Once for priv->dev, again for priv->mesh_dev if it exists */
+ nr_addrs = lbs_add_mcast_addrs(&mcast_cmd, priv->dev, 0);
+ if (nr_addrs >= 0 && priv->mesh_dev)
+ nr_addrs = lbs_add_mcast_addrs(&mcast_cmd, priv->mesh_dev, nr_addrs);
+ if (nr_addrs < 0)
+ goto do_allmulti;
+
+ if (nr_addrs) {
+ int size = offsetof(struct cmd_ds_mac_multicast_adr,
+ maclist[6*nr_addrs]);
+
+ mcast_cmd.action = cpu_to_le16(CMD_ACT_SET);
+ mcast_cmd.hdr.size = cpu_to_le16(size);
+ mcast_cmd.nr_of_adrs = cpu_to_le16(nr_addrs);
+
+ lbs_cmd_async(priv, CMD_MAC_MULTICAST_ADR, &mcast_cmd.hdr, size);
+
+ priv->mac_control |= CMD_ACT_MAC_MULTICAST_ENABLE;
+ } else
+ priv->mac_control &= ~CMD_ACT_MAC_MULTICAST_ENABLE;
+
+ priv->mac_control &= ~(CMD_ACT_MAC_PROMISCUOUS_ENABLE |
+ CMD_ACT_MAC_ALL_MULTICAST_ENABLE);
+ out_set_mac_control:
+ if (priv->mac_control != old_mac_control)
+ lbs_set_mac_control(priv);
+
+ lbs_deb_leave(LBS_DEB_NET);
+}
+
static void lbs_set_multicast_list(struct net_device *dev)
{
struct lbs_private *priv = dev->priv;
- int old_mac_control;
- DECLARE_MAC_BUF(mac);
- lbs_deb_enter(LBS_DEB_NET);
-
- old_mac_control = priv->mac_control;
-
- if (dev->flags & IFF_PROMISC) {
- lbs_deb_net("enable promiscuous mode\n");
- priv->mac_control |=
- CMD_ACT_MAC_PROMISCUOUS_ENABLE;
- priv->mac_control &=
- ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE |
- CMD_ACT_MAC_MULTICAST_ENABLE);
- } else {
- /* Multicast */
- priv->mac_control &=
- ~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
-
- if (dev->flags & IFF_ALLMULTI || dev->mc_count >
- MRVDRV_MAX_MULTICAST_LIST_SIZE) {
- lbs_deb_net( "enabling all multicast\n");
- priv->mac_control |=
- CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
- priv->mac_control &=
- ~CMD_ACT_MAC_MULTICAST_ENABLE;
- } else {
- priv->mac_control &=
- ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
-
- if (!dev->mc_count) {
- lbs_deb_net("no multicast addresses, "
- "disabling multicast\n");
- priv->mac_control &=
- ~CMD_ACT_MAC_MULTICAST_ENABLE;
- } else {
- int i;
-
- priv->mac_control |=
- CMD_ACT_MAC_MULTICAST_ENABLE;
-
- priv->nr_of_multicastmacaddr =
- lbs_copy_multicast_address(priv, dev);
-
- lbs_deb_net("multicast addresses: %d\n",
- dev->mc_count);
-
- for (i = 0; i < dev->mc_count; i++) {
- lbs_deb_net("Multicast address %d: %s\n",
- i, print_mac(mac,
- priv->multicastlist[i]));
- }
- /* send multicast addresses to firmware */
- lbs_prepare_and_send_command(priv,
- CMD_MAC_MULTICAST_ADR,
- CMD_ACT_SET, 0, 0,
- NULL);
- }
- }
- }
-
- if (priv->mac_control != old_mac_control)
- lbs_set_mac_control(priv);
-
- lbs_deb_leave(LBS_DEB_NET);
+ schedule_work(&priv->mcast_work);
}
/**
@@ -689,20 +722,20 @@
shouldsleep = 1; /* Something is en route to the device already */
else if (priv->tx_pending_len > 0)
shouldsleep = 0; /* We've a packet to send */
+ else if (priv->resp_len[priv->resp_idx])
+ shouldsleep = 0; /* We have a command response */
else if (priv->cur_cmd)
shouldsleep = 1; /* Can't send a command; one already running */
else if (!list_empty(&priv->cmdpendingq))
shouldsleep = 0; /* We have a command to send */
else if (__kfifo_len(priv->event_fifo))
shouldsleep = 0; /* We have an event to process */
- else if (priv->resp_len[priv->resp_idx])
- shouldsleep = 0; /* We have a command response */
else
shouldsleep = 1; /* No command */
if (shouldsleep) {
lbs_deb_thread("sleeping, connect_status %d, "
- "ps_mode %d, ps_state %d\n",
+ "psmode %d, psstate %d\n",
priv->connect_status,
priv->psmode, priv->psstate);
spin_unlock_irq(&priv->driver_lock);
@@ -749,16 +782,21 @@
if (priv->cmd_timed_out && priv->cur_cmd) {
struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
- if (++priv->nr_retries > 10) {
- lbs_pr_info("Excessive timeouts submitting command %x\n",
- le16_to_cpu(cmdnode->cmdbuf->command));
+ if (++priv->nr_retries > 3) {
+ lbs_pr_info("Excessive timeouts submitting "
+ "command 0x%04x\n",
+ le16_to_cpu(cmdnode->cmdbuf->command));
lbs_complete_command(priv, cmdnode, -ETIMEDOUT);
priv->nr_retries = 0;
+ if (priv->reset_card)
+ priv->reset_card(priv);
} else {
priv->cur_cmd = NULL;
priv->dnld_sent = DNLD_RES_RECEIVED;
- lbs_pr_info("requeueing command %x due to timeout (#%d)\n",
- le16_to_cpu(cmdnode->cmdbuf->command), priv->nr_retries);
+ lbs_pr_info("requeueing command 0x%04x due "
+ "to timeout (#%d)\n",
+ le16_to_cpu(cmdnode->cmdbuf->command),
+ priv->nr_retries);
/* Stick it back at the _top_ of the pending queue
for immediate resubmission */
@@ -890,7 +928,7 @@
}
EXPORT_SYMBOL_GPL(lbs_suspend);
-int lbs_resume(struct lbs_private *priv)
+void lbs_resume(struct lbs_private *priv)
{
lbs_deb_enter(LBS_DEB_FW);
@@ -906,7 +944,6 @@
netif_device_attach(priv->mesh_dev);
lbs_deb_leave(LBS_DEB_FW);
- return 0;
}
EXPORT_SYMBOL_GPL(lbs_resume);
@@ -929,20 +966,10 @@
*/
memset(priv->current_addr, 0xff, ETH_ALEN);
ret = lbs_update_hw_spec(priv);
- if (ret) {
- ret = -1;
+ if (ret)
goto done;
- }
lbs_set_mac_control(priv);
-
- ret = lbs_get_data_rate(priv);
- if (ret < 0) {
- ret = -1;
- goto done;
- }
-
- ret = 0;
done:
lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
return ret;
@@ -960,12 +987,11 @@
lbs_deb_enter(LBS_DEB_CMD);
spin_lock_irqsave(&priv->driver_lock, flags);
- if (!priv->cur_cmd) {
- lbs_pr_info("Command timer expired; no pending command\n");
+ if (!priv->cur_cmd)
goto out;
- }
- lbs_pr_info("Command %x timed out\n", le16_to_cpu(priv->cur_cmd->cmdbuf->command));
+ lbs_pr_info("command 0x%04x timed out\n",
+ le16_to_cpu(priv->cur_cmd->cmdbuf->command));
priv->cmd_timed_out = 1;
wake_up_interruptible(&priv->waitq);
@@ -1019,7 +1045,7 @@
priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL;
priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
priv->radioon = RADIO_ON;
- priv->auto_rate = 1;
+ priv->enablehwauto = 1;
priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
priv->psmode = LBS802_11POWERMODECAM;
priv->psstate = PS_STATE_FULL_POWER;
@@ -1134,6 +1160,7 @@
priv->work_thread = create_singlethread_workqueue("lbs_worker");
INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker);
INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
+ INIT_WORK(&priv->mcast_work, lbs_set_mcast_worker);
INIT_WORK(&priv->sync_channel, lbs_sync_channel_worker);
sprintf(priv->mesh_ssid, "mesh");
@@ -1156,7 +1183,7 @@
EXPORT_SYMBOL_GPL(lbs_add_card);
-int lbs_remove_card(struct lbs_private *priv)
+void lbs_remove_card(struct lbs_private *priv)
{
struct net_device *dev = priv->dev;
union iwreq_data wrqu;
@@ -1168,8 +1195,9 @@
dev = priv->dev;
- cancel_delayed_work(&priv->scan_work);
- cancel_delayed_work(&priv->assoc_work);
+ cancel_delayed_work_sync(&priv->scan_work);
+ cancel_delayed_work_sync(&priv->assoc_work);
+ cancel_work_sync(&priv->mcast_work);
destroy_workqueue(priv->work_thread);
if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
@@ -1191,7 +1219,6 @@
free_netdev(dev);
lbs_deb_leave(LBS_DEB_MAIN);
- return 0;
}
EXPORT_SYMBOL_GPL(lbs_remove_card);
@@ -1236,9 +1263,11 @@
useful */
priv->mesh_tlv = 0x100 + 291;
- if (lbs_mesh_config(priv, 1, priv->curbssparams.channel)) {
+ if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
+ priv->curbssparams.channel)) {
priv->mesh_tlv = 0x100 + 37;
- if (lbs_mesh_config(priv, 1, priv->curbssparams.channel))
+ if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
+ priv->curbssparams.channel))
priv->mesh_tlv = 0;
}
if (priv->mesh_tlv) {
@@ -1262,24 +1291,28 @@
EXPORT_SYMBOL_GPL(lbs_start_card);
-int lbs_stop_card(struct lbs_private *priv)
+void lbs_stop_card(struct lbs_private *priv)
{
struct net_device *dev = priv->dev;
- int ret = -1;
struct cmd_ctrl_node *cmdnode;
unsigned long flags;
lbs_deb_enter(LBS_DEB_MAIN);
+ if (!priv)
+ goto out;
+
netif_stop_queue(priv->dev);
netif_carrier_off(priv->dev);
lbs_debugfs_remove_one(priv);
device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
- if (priv->mesh_tlv)
+ if (priv->mesh_tlv) {
device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
+ }
/* Flush pending command nodes */
+ del_timer_sync(&priv->command_timer);
spin_lock_irqsave(&priv->driver_lock, flags);
list_for_each_entry(cmdnode, &priv->cmdpendingq, list) {
cmdnode->result = -ENOENT;
@@ -1290,8 +1323,8 @@
unregister_netdev(dev);
- lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
- return ret;
+out:
+ lbs_deb_leave(LBS_DEB_MAIN);
}
EXPORT_SYMBOL_GPL(lbs_stop_card);
@@ -1332,6 +1365,8 @@
#ifdef WIRELESS_EXT
mesh_dev->wireless_handlers = (struct iw_handler_def *)&mesh_handler_def;
#endif
+ mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+ mesh_dev->set_multicast_list = lbs_set_multicast_list;
/* Register virtual mesh interface */
ret = register_netdev(mesh_dev);
if (ret) {
@@ -1343,6 +1378,8 @@
if (ret)
goto err_unregister;
+ lbs_persist_config_init(mesh_dev);
+
/* Everything successful */
ret = 0;
goto done;
@@ -1369,8 +1406,9 @@
lbs_deb_enter(LBS_DEB_MESH);
netif_stop_queue(mesh_dev);
- netif_carrier_off(priv->mesh_dev);
+ netif_carrier_off(mesh_dev);
sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
+ lbs_persist_config_remove(mesh_dev);
unregister_netdev(mesh_dev);
priv->mesh_dev = NULL;
free_netdev(mesh_dev);
@@ -1533,10 +1571,11 @@
{
lbs_deb_enter(LBS_DEB_MAIN);
if (priv->rtap_net_dev == NULL)
- return;
+ goto out;
unregister_netdev(priv->rtap_net_dev);
free_netdev(priv->rtap_net_dev);
priv->rtap_net_dev = NULL;
+out:
lbs_deb_leave(LBS_DEB_MAIN);
}
@@ -1563,7 +1602,6 @@
rtap_dev->stop = lbs_rtap_stop;
rtap_dev->get_stats = lbs_rtap_get_stats;
rtap_dev->hard_start_xmit = lbs_rtap_hard_start_xmit;
- rtap_dev->set_multicast_list = lbs_set_multicast_list;
rtap_dev->priv = priv;
SET_NETDEV_DEV(rtap_dev, priv->dev->dev.parent);
diff --git a/drivers/net/wireless/libertas/persistcfg.c b/drivers/net/wireless/libertas/persistcfg.c
new file mode 100644
index 0000000..6d0ff8d
--- /dev/null
+++ b/drivers/net/wireless/libertas/persistcfg.c
@@ -0,0 +1,453 @@
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/kthread.h>
+#include <linux/kfifo.h>
+
+#include "host.h"
+#include "decl.h"
+#include "dev.h"
+#include "wext.h"
+#include "debugfs.h"
+#include "scan.h"
+#include "assoc.h"
+#include "cmd.h"
+
+static int mesh_get_default_parameters(struct device *dev,
+ struct mrvl_mesh_defaults *defs)
+{
+ struct lbs_private *priv = to_net_dev(dev)->priv;
+ struct cmd_ds_mesh_config cmd;
+ int ret;
+
+ memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
+ ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
+ CMD_TYPE_MESH_GET_DEFAULTS);
+
+ if (ret)
+ return -EOPNOTSUPP;
+
+ memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
+
+ return 0;
+}
+
+/**
+ * @brief Get function for sysfs attribute bootflag
+ */
+static ssize_t bootflag_get(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mrvl_mesh_defaults defs;
+ int ret;
+
+ ret = mesh_get_default_parameters(dev, &defs);
+
+ if (ret)
+ return ret;
+
+ return snprintf(buf, 12, "0x%x\n", le32_to_cpu(defs.bootflag));
+}
+
+/**
+ * @brief Set function for sysfs attribute bootflag
+ */
+static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct lbs_private *priv = to_net_dev(dev)->priv;
+ struct cmd_ds_mesh_config cmd;
+ uint32_t datum;
+ int ret;
+
+ memset(&cmd, 0, sizeof(cmd));
+ ret = sscanf(buf, "%x", &datum);
+ if (ret != 1)
+ return -EINVAL;
+
+ *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
+ cmd.length = cpu_to_le16(sizeof(uint32_t));
+ ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+ CMD_TYPE_MESH_SET_BOOTFLAG);
+ if (ret)
+ return ret;
+
+ return strlen(buf);
+}
+
+/**
+ * @brief Get function for sysfs attribute boottime
+ */
+static ssize_t boottime_get(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mrvl_mesh_defaults defs;
+ int ret;
+
+ ret = mesh_get_default_parameters(dev, &defs);
+
+ if (ret)
+ return ret;
+
+ return snprintf(buf, 12, "0x%x\n", defs.boottime);
+}
+
+/**
+ * @brief Set function for sysfs attribute boottime
+ */
+static ssize_t boottime_set(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct lbs_private *priv = to_net_dev(dev)->priv;
+ struct cmd_ds_mesh_config cmd;
+ uint32_t datum;
+ int ret;
+
+ memset(&cmd, 0, sizeof(cmd));
+ ret = sscanf(buf, "%x", &datum);
+ if (ret != 1)
+ return -EINVAL;
+
+ /* A too small boot time will result in the device booting into
+ * standalone (no-host) mode before the host can take control of it,
+ * so the change will be hard to revert. This may be a desired
+ * feature (e.g to configure a very fast boot time for devices that
+ * will not be attached to a host), but dangerous. So I'm enforcing a
+ * lower limit of 20 seconds: remove and recompile the driver if this
+ * does not work for you.
+ */
+ datum = (datum < 20) ? 20 : datum;
+ cmd.data[0] = datum;
+ cmd.length = cpu_to_le16(sizeof(uint8_t));
+ ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+ CMD_TYPE_MESH_SET_BOOTTIME);
+ if (ret)
+ return ret;
+
+ return strlen(buf);
+}
+
+/**
+ * @brief Get function for sysfs attribute channel
+ */
+static ssize_t channel_get(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mrvl_mesh_defaults defs;
+ int ret;
+
+ ret = mesh_get_default_parameters(dev, &defs);
+
+ if (ret)
+ return ret;
+
+ return snprintf(buf, 12, "0x%x\n", le16_to_cpu(defs.channel));
+}
+
+/**
+ * @brief Set function for sysfs attribute channel
+ */
+static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct lbs_private *priv = to_net_dev(dev)->priv;
+ struct cmd_ds_mesh_config cmd;
+ uint16_t datum;
+ int ret;
+
+ memset(&cmd, 0, sizeof(cmd));
+ ret = sscanf(buf, "%hx", &datum);
+ if (ret != 1 || datum < 1 || datum > 11)
+ return -EINVAL;
+
+ *((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
+ cmd.length = cpu_to_le16(sizeof(uint16_t));
+ ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+ CMD_TYPE_MESH_SET_DEF_CHANNEL);
+ if (ret)
+ return ret;
+
+ return strlen(buf);
+}
+
+/**
+ * @brief Get function for sysfs attribute mesh_id
+ */
+static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct mrvl_mesh_defaults defs;
+ int maxlen;
+ int ret;
+
+ ret = mesh_get_default_parameters(dev, &defs);
+
+ if (ret)
+ return ret;
+
+ if (defs.meshie.val.mesh_id_len > IW_ESSID_MAX_SIZE) {
+ lbs_pr_err("inconsistent mesh ID length");
+ defs.meshie.val.mesh_id_len = IW_ESSID_MAX_SIZE;
+ }
+
+ /* SSID not null terminated: reserve room for \0 + \n */
+ maxlen = defs.meshie.val.mesh_id_len + 2;
+ maxlen = (PAGE_SIZE > maxlen) ? maxlen : PAGE_SIZE;
+
+ defs.meshie.val.mesh_id[defs.meshie.val.mesh_id_len] = '\0';
+
+ return snprintf(buf, maxlen, "%s\n", defs.meshie.val.mesh_id);
+}
+
+/**
+ * @brief Set function for sysfs attribute mesh_id
+ */
+static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cmd_ds_mesh_config cmd;
+ struct mrvl_mesh_defaults defs;
+ struct mrvl_meshie *ie;
+ struct lbs_private *priv = to_net_dev(dev)->priv;
+ int len;
+ int ret;
+
+ if (count < 2 || count > IW_ESSID_MAX_SIZE + 1)
+ return -EINVAL;
+
+ memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
+ ie = (struct mrvl_meshie *) &cmd.data[0];
+
+ /* fetch all other Information Element parameters */
+ ret = mesh_get_default_parameters(dev, &defs);
+
+ cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
+
+ /* transfer IE elements */
+ memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
+
+ len = count - 1;
+ memcpy(ie->val.mesh_id, buf, len);
+ /* SSID len */
+ ie->val.mesh_id_len = len;
+ /* IE len */
+ ie->hdr.len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len;
+
+ ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+ CMD_TYPE_MESH_SET_MESH_IE);
+ if (ret)
+ return ret;
+
+ return strlen(buf);
+}
+
+/**
+ * @brief Get function for sysfs attribute protocol_id
+ */
+static ssize_t protocol_id_get(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mrvl_mesh_defaults defs;
+ int ret;
+
+ ret = mesh_get_default_parameters(dev, &defs);
+
+ if (ret)
+ return ret;
+
+ return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id);
+}
+
+/**
+ * @brief Set function for sysfs attribute protocol_id
+ */
+static ssize_t protocol_id_set(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct cmd_ds_mesh_config cmd;
+ struct mrvl_mesh_defaults defs;
+ struct mrvl_meshie *ie;
+ struct lbs_private *priv = to_net_dev(dev)->priv;
+ uint32_t datum;
+ int ret;
+
+ memset(&cmd, 0, sizeof(cmd));
+ ret = sscanf(buf, "%x", &datum);
+ if (ret != 1)
+ return -EINVAL;
+
+ /* fetch all other Information Element parameters */
+ ret = mesh_get_default_parameters(dev, &defs);
+
+ cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
+
+ /* transfer IE elements */
+ ie = (struct mrvl_meshie *) &cmd.data[0];
+ memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
+ /* update protocol id */
+ ie->val.active_protocol_id = datum;
+
+ ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+ CMD_TYPE_MESH_SET_MESH_IE);
+ if (ret)
+ return ret;
+
+ return strlen(buf);
+}
+
+/**
+ * @brief Get function for sysfs attribute metric_id
+ */
+static ssize_t metric_id_get(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mrvl_mesh_defaults defs;
+ int ret;
+
+ ret = mesh_get_default_parameters(dev, &defs);
+
+ if (ret)
+ return ret;
+
+ return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id);
+}
+
+/**
+ * @brief Set function for sysfs attribute metric_id
+ */
+static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cmd_ds_mesh_config cmd;
+ struct mrvl_mesh_defaults defs;
+ struct mrvl_meshie *ie;
+ struct lbs_private *priv = to_net_dev(dev)->priv;
+ uint32_t datum;
+ int ret;
+
+ memset(&cmd, 0, sizeof(cmd));
+ ret = sscanf(buf, "%x", &datum);
+ if (ret != 1)
+ return -EINVAL;
+
+ /* fetch all other Information Element parameters */
+ ret = mesh_get_default_parameters(dev, &defs);
+
+ cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
+
+ /* transfer IE elements */
+ ie = (struct mrvl_meshie *) &cmd.data[0];
+ memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
+ /* update metric id */
+ ie->val.active_metric_id = datum;
+
+ ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+ CMD_TYPE_MESH_SET_MESH_IE);
+ if (ret)
+ return ret;
+
+ return strlen(buf);
+}
+
+/**
+ * @brief Get function for sysfs attribute capability
+ */
+static ssize_t capability_get(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mrvl_mesh_defaults defs;
+ int ret;
+
+ ret = mesh_get_default_parameters(dev, &defs);
+
+ if (ret)
+ return ret;
+
+ return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability);
+}
+
+/**
+ * @brief Set function for sysfs attribute capability
+ */
+static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cmd_ds_mesh_config cmd;
+ struct mrvl_mesh_defaults defs;
+ struct mrvl_meshie *ie;
+ struct lbs_private *priv = to_net_dev(dev)->priv;
+ uint32_t datum;
+ int ret;
+
+ memset(&cmd, 0, sizeof(cmd));
+ ret = sscanf(buf, "%x", &datum);
+ if (ret != 1)
+ return -EINVAL;
+
+ /* fetch all other Information Element parameters */
+ ret = mesh_get_default_parameters(dev, &defs);
+
+ cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
+
+ /* transfer IE elements */
+ ie = (struct mrvl_meshie *) &cmd.data[0];
+ memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
+ /* update value */
+ ie->val.mesh_capability = datum;
+
+ ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
+ CMD_TYPE_MESH_SET_MESH_IE);
+ if (ret)
+ return ret;
+
+ return strlen(buf);
+}
+
+
+static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
+static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
+static DEVICE_ATTR(channel, 0644, channel_get, channel_set);
+static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
+static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
+static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
+static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
+
+static struct attribute *boot_opts_attrs[] = {
+ &dev_attr_bootflag.attr,
+ &dev_attr_boottime.attr,
+ &dev_attr_channel.attr,
+ NULL
+};
+
+static struct attribute_group boot_opts_group = {
+ .name = "boot_options",
+ .attrs = boot_opts_attrs,
+};
+
+static struct attribute *mesh_ie_attrs[] = {
+ &dev_attr_mesh_id.attr,
+ &dev_attr_protocol_id.attr,
+ &dev_attr_metric_id.attr,
+ &dev_attr_capability.attr,
+ NULL
+};
+
+static struct attribute_group mesh_ie_group = {
+ .name = "mesh_ie",
+ .attrs = mesh_ie_attrs,
+};
+
+void lbs_persist_config_init(struct net_device *dev)
+{
+ int ret;
+ ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group);
+ ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
+}
+
+void lbs_persist_config_remove(struct net_device *dev)
+{
+ sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
+ sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
+}
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
index 05af731..5749f22 100644
--- a/drivers/net/wireless/libertas/rx.c
+++ b/drivers/net/wireless/libertas/rx.c
@@ -237,7 +237,7 @@
/* Take the data rate from the rxpd structure
* only if the rate is auto
*/
- if (priv->auto_rate)
+ if (priv->enablehwauto)
priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate);
lbs_compute_rssi(priv, p_rx_pd);
@@ -383,7 +383,7 @@
/* Take the data rate from the rxpd structure
* only if the rate is auto
*/
- if (priv->auto_rate)
+ if (priv->enablehwauto)
priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate);
lbs_compute_rssi(priv, prxpd);
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
index 4031be4..e0c2599 100644
--- a/drivers/net/wireless/libertas/types.h
+++ b/drivers/net/wireless/libertas/types.h
@@ -6,6 +6,8 @@
#include <linux/if_ether.h>
#include <asm/byteorder.h>
+#include <linux/wireless.h>
+#include <net/ieee80211.h>
struct ieeetypes_cfparamset {
u8 elementid;
@@ -252,4 +254,32 @@
struct led_bhv ledbhv[1];
} __attribute__ ((packed));
+/* Meant to be packed as the value member of a struct ieee80211_info_element.
+ * Note that the len member of the ieee80211_info_element varies depending on
+ * the mesh_id_len */
+struct mrvl_meshie_val {
+ uint8_t oui[P80211_OUI_LEN];
+ uint8_t type;
+ uint8_t subtype;
+ uint8_t version;
+ uint8_t active_protocol_id;
+ uint8_t active_metric_id;
+ uint8_t mesh_capability;
+ uint8_t mesh_id_len;
+ uint8_t mesh_id[IW_ESSID_MAX_SIZE];
+} __attribute__ ((packed));
+
+struct mrvl_meshie {
+ struct ieee80211_info_element hdr;
+ struct mrvl_meshie_val val;
+} __attribute__ ((packed));
+
+struct mrvl_mesh_defaults {
+ __le32 bootflag;
+ uint8_t boottime;
+ uint8_t reserved;
+ __le16 channel;
+ struct mrvl_meshie meshie;
+} __attribute__ ((packed));
+
#endif
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index 0973d01..8b3ed77 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -1002,7 +1002,7 @@
else if (priv->mode == IW_MODE_ADHOC)
lbs_stop_adhoc_network(priv);
}
- lbs_mesh_config(priv, 1, fwrq->m);
+ lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m);
lbs_update_channel(priv);
ret = 0;
@@ -1021,29 +1021,38 @@
lbs_deb_enter(LBS_DEB_WEXT);
lbs_deb_wext("vwrq->value %d\n", vwrq->value);
+ lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed);
+
+ if (vwrq->fixed && vwrq->value == -1)
+ goto out;
/* Auto rate? */
- if (vwrq->value == -1) {
- priv->auto_rate = 1;
+ priv->enablehwauto = !vwrq->fixed;
+
+ if (vwrq->value == -1)
priv->cur_rate = 0;
- } else {
+ else {
if (vwrq->value % 100000)
goto out;
+ new_rate = vwrq->value / 500000;
+ priv->cur_rate = new_rate;
+ /* the rest is only needed for lbs_set_data_rate() */
memset(rates, 0, sizeof(rates));
copy_active_data_rates(priv, rates);
- new_rate = vwrq->value / 500000;
if (!memchr(rates, new_rate, sizeof(rates))) {
lbs_pr_alert("fixed data rate 0x%X out of range\n",
new_rate);
goto out;
}
-
- priv->cur_rate = new_rate;
- priv->auto_rate = 0;
}
- ret = lbs_set_data_rate(priv, new_rate);
+ /* Try the newer command first (Firmware Spec 5.1 and above) */
+ ret = lbs_cmd_802_11_rate_adapt_rateset(priv, CMD_ACT_SET);
+
+ /* Fallback to older version */
+ if (ret)
+ ret = lbs_set_data_rate(priv, new_rate);
out:
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
@@ -1060,7 +1069,7 @@
if (priv->connect_status == LBS_CONNECTED) {
vwrq->value = priv->cur_rate * 500000;
- if (priv->auto_rate)
+ if (priv->enablehwauto)
vwrq->fixed = 0;
else
vwrq->fixed = 1;
@@ -2011,7 +2020,8 @@
priv->mesh_ssid_len = dwrq->length;
}
- lbs_mesh_config(priv, 1, priv->curbssparams.channel);
+ lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
+ priv->curbssparams.channel);
out:
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
return ret;
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..9f7224d 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;
}
}
@@ -355,7 +355,7 @@
struct ieee80211_rx_status rx_status = {0};
u16 freq = le16_to_cpu(hdr->freq);
- rx_status.ssi = hdr->rssi;
+ rx_status.signal = hdr->rssi;
/* XX correct? */
rx_status.rate_idx = hdr->rate & 0xf;
rx_status.freq = freq;
@@ -375,11 +375,8 @@
struct p54_common *priv = dev->priv;
int i;
- /* ieee80211_start_queues is great if all queues are really empty.
- * But, what if some are full? */
-
for (i = 0; i < dev->queues; i++)
- if (priv->tx_stats.data[i].len < priv->tx_stats.data[i].limit)
+ if (priv->tx_stats[i].len < priv->tx_stats[i].limit)
ieee80211_wake_queue(dev, i);
}
@@ -395,45 +392,42 @@
u32 last_addr = priv->rx_start;
while (entry != (struct sk_buff *)&priv->tx_queue) {
- range = (struct memrecord *)&entry->cb;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
+ range = (void *)info->driver_data;
if (range->start_addr == addr) {
- struct ieee80211_tx_status status;
struct p54_control_hdr *entry_hdr;
struct p54_tx_control_allocdata *entry_data;
int pad = 0;
- if (entry->next != (struct sk_buff *)&priv->tx_queue)
- freed = ((struct memrecord *)&entry->next->cb)->start_addr - last_addr;
- else
+ if (entry->next != (struct sk_buff *)&priv->tx_queue) {
+ struct ieee80211_tx_info *ni;
+ struct memrecord *mr;
+
+ ni = IEEE80211_SKB_CB(entry->next);
+ mr = (struct memrecord *)ni->driver_data;
+ freed = mr->start_addr - last_addr;
+ } else
freed = priv->rx_end - last_addr;
last_addr = range->end_addr;
__skb_unlink(entry, &priv->tx_queue);
- if (!range->control) {
- kfree_skb(entry);
- break;
- }
- memset(&status, 0, sizeof(status));
- memcpy(&status.control, range->control,
- sizeof(status.control));
- kfree(range->control);
- priv->tx_stats.data[status.control.queue].len--;
-
+ memset(&info->status, 0, sizeof(info->status));
+ priv->tx_stats[skb_get_queue_mapping(skb)].len--;
entry_hdr = (struct p54_control_hdr *) entry->data;
entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data;
if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0)
pad = entry_data->align[0];
- if (!(status.control.flags & IEEE80211_TXCTL_NO_ACK)) {
+ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
if (!(payload->status & 0x01))
- status.flags |= IEEE80211_TX_STATUS_ACK;
+ info->flags |= IEEE80211_TX_STAT_ACK;
else
- status.excessive_retries = 1;
+ info->status.excessive_retries = 1;
}
- status.retry_count = payload->retries - 1;
- status.ack_signal = le16_to_cpu(payload->ack_rssi);
+ info->status.retry_count = payload->retries - 1;
+ info->status.ack_signal = le16_to_cpu(payload->ack_rssi);
skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
- ieee80211_tx_status_irqsafe(dev, entry, &status);
+ ieee80211_tx_status_irqsafe(dev, entry);
break;
} else
last_addr = range->end_addr;
@@ -498,13 +492,11 @@
* allocated areas.
*/
static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
- struct p54_control_hdr *data, u32 len,
- struct ieee80211_tx_control *control)
+ struct p54_control_hdr *data, u32 len)
{
struct p54_common *priv = dev->priv;
struct sk_buff *entry = priv->tx_queue.next;
struct sk_buff *target_skb = NULL;
- struct memrecord *range;
u32 last_addr = priv->rx_start;
u32 largest_hole = 0;
u32 target_addr = priv->rx_start;
@@ -516,7 +508,8 @@
left = skb_queue_len(&priv->tx_queue);
while (left--) {
u32 hole_size;
- range = (struct memrecord *)&entry->cb;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
+ struct memrecord *range = (void *)info->driver_data;
hole_size = range->start_addr - last_addr;
if (!target_skb && hole_size >= len) {
target_skb = entry->prev;
@@ -531,17 +524,18 @@
target_skb = priv->tx_queue.prev;
largest_hole = max(largest_hole, priv->rx_end - last_addr - len);
if (!skb_queue_empty(&priv->tx_queue)) {
- range = (struct memrecord *)&target_skb->cb;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(target_skb);
+ struct memrecord *range = (void *)info->driver_data;
target_addr = range->end_addr;
}
} else
largest_hole = max(largest_hole, priv->rx_end - last_addr);
if (skb) {
- range = (struct memrecord *)&skb->cb;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct memrecord *range = (void *)info->driver_data;
range->start_addr = target_addr;
range->end_addr = target_addr + len;
- range->control = control;
__skb_queue_after(&priv->tx_queue, target_skb, skb);
if (largest_hole < IEEE80211_MAX_RTS_THRESHOLD + 0x170 +
sizeof(struct p54_control_hdr))
@@ -552,32 +546,27 @@
data->req_id = cpu_to_le32(target_addr + 0x70);
}
-static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
{
- struct ieee80211_tx_queue_stats_data *current_queue;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_tx_queue_stats *current_queue;
struct p54_common *priv = dev->priv;
struct p54_control_hdr *hdr;
struct p54_tx_control_allocdata *txhdr;
- struct ieee80211_tx_control *control_copy;
size_t padding, len;
u8 rate;
- current_queue = &priv->tx_stats.data[control->queue];
+ current_queue = &priv->tx_stats[skb_get_queue_mapping(skb)];
if (unlikely(current_queue->len > current_queue->limit))
return NETDEV_TX_BUSY;
current_queue->len++;
current_queue->count++;
if (current_queue->len == current_queue->limit)
- ieee80211_stop_queue(dev, control->queue);
+ ieee80211_stop_queue(dev, skb_get_queue_mapping(skb));
padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
len = skb->len;
- control_copy = kmalloc(sizeof(*control), GFP_ATOMIC);
- if (control_copy)
- memcpy(control_copy, control, sizeof(*control));
-
txhdr = (struct p54_tx_control_allocdata *)
skb_push(skb, sizeof(*txhdr) + padding);
hdr = (struct p54_control_hdr *) skb_push(skb, sizeof(*hdr));
@@ -587,35 +576,37 @@
else
hdr->magic1 = cpu_to_le16(0x0010);
hdr->len = cpu_to_le16(len);
- hdr->type = (control->flags & IEEE80211_TXCTL_NO_ACK) ? 0 : cpu_to_le16(1);
- hdr->retry1 = hdr->retry2 = control->retry_limit;
- p54_assign_address(dev, skb, hdr, skb->len, control_copy);
+ hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1);
+ hdr->retry1 = hdr->retry2 = info->control.retry_limit;
memset(txhdr->wep_key, 0x0, 16);
txhdr->padding = 0;
txhdr->padding2 = 0;
/* TODO: add support for alternate retry TX rates */
- rate = control->tx_rate->hw_value;
- if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE)
+ rate = ieee80211_get_tx_rate(dev, info)->hw_value;
+ if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE)
rate |= 0x10;
- if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
+ if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
rate |= 0x40;
- else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+ else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
rate |= 0x20;
memset(txhdr->rateset, rate, 8);
txhdr->wep_key_present = 0;
txhdr->wep_key_len = 0;
- txhdr->frame_type = cpu_to_le32(control->queue + 4);
+ txhdr->frame_type = cpu_to_le32(skb_get_queue_mapping(skb) + 4);
txhdr->magic4 = 0;
- txhdr->antenna = (control->antenna_sel_tx == 0) ?
- 2 : control->antenna_sel_tx - 1;
+ txhdr->antenna = (info->antenna_sel_tx == 0) ?
+ 2 : info->antenna_sel_tx - 1;
txhdr->output_power = 0x7f; // HW Maximum
- txhdr->magic5 = (control->flags & IEEE80211_TXCTL_NO_ACK) ?
+ txhdr->magic5 = (info->flags & IEEE80211_TX_CTL_NO_ACK) ?
0 : ((rate > 0x3) ? cpu_to_le32(0x33) : cpu_to_le32(0x23));
if (padding)
txhdr->align[0] = padding;
+ /* modifies skb->cb and with it info, so must be last! */
+ p54_assign_address(dev, skb, hdr, skb->len);
+
priv->tx(dev, hdr, skb->len, 0);
return 0;
}
@@ -638,7 +629,7 @@
filter = (struct p54_tx_control_filter *) hdr->data;
hdr->magic1 = cpu_to_le16(0x8001);
hdr->len = cpu_to_le16(sizeof(*filter));
- p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*filter), NULL);
+ p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*filter));
hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET);
filter->filter_type = cpu_to_le16(filter_type);
@@ -682,7 +673,7 @@
hdr->magic1 = cpu_to_le16(0x8001);
hdr->len = cpu_to_le16(sizeof(*chan));
hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE);
- p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + payload_len, NULL);
+ p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + payload_len);
chan->magic1 = cpu_to_le16(0x1);
chan->magic2 = cpu_to_le16(0x0);
@@ -755,7 +746,7 @@
hdr->magic1 = cpu_to_le16(0x8001);
hdr->len = cpu_to_le16(sizeof(*led));
hdr->type = cpu_to_le16(P54_CONTROL_TYPE_LED);
- p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*led), NULL);
+ p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*led));
led = (struct p54_tx_control_led *) hdr->data;
led->mode = cpu_to_le16(mode);
@@ -805,7 +796,7 @@
hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len;
- p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*vdcf), NULL);
+ p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*vdcf));
vdcf = (struct p54_tx_control_vdcf *) hdr->data;
@@ -841,12 +832,8 @@
{
struct p54_common *priv = dev->priv;
struct sk_buff *skb;
- while ((skb = skb_dequeue(&priv->tx_queue))) {
- struct memrecord *range = (struct memrecord *)&skb->cb;
- if (range->control)
- kfree(range->control);
+ while ((skb = skb_dequeue(&priv->tx_queue)))
kfree_skb(skb);
- }
priv->stop(dev);
priv->mode = IEEE80211_IF_TYPE_INVALID;
}
@@ -936,7 +923,7 @@
}
}
-static int p54_conf_tx(struct ieee80211_hw *dev, int queue,
+static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct p54_common *priv = dev->priv;
@@ -945,7 +932,7 @@
vdcf = (struct p54_tx_control_vdcf *)(((struct p54_control_hdr *)
((void *)priv->cached_vdcf + priv->tx_hdr_len))->data);
- if ((params) && !((queue < 0) || (queue > 4))) {
+ if ((params) && !(queue > 4)) {
P54_SET_QUEUE(vdcf->queue[queue], params->aifs,
params->cw_min, params->cw_max, params->txop);
} else
@@ -967,11 +954,8 @@
struct ieee80211_tx_queue_stats *stats)
{
struct p54_common *priv = dev->priv;
- unsigned int i;
- for (i = 0; i < dev->queues; i++)
- memcpy(&stats->data[i], &priv->tx_stats.data[i],
- sizeof(stats->data[i]));
+ memcpy(stats, &priv->tx_stats, sizeof(stats[0]) * dev->queues);
return 0;
}
@@ -1004,11 +988,12 @@
skb_queue_head_init(&priv->tx_queue);
dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz;
dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */
- IEEE80211_HW_RX_INCLUDES_FCS;
+ IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_SIGNAL_UNSPEC;
dev->channel_change_time = 1000; /* TODO: find actual value */
- dev->max_rssi = 127;
+ dev->max_signal = 127;
- priv->tx_stats.data[0].limit = 5;
+ priv->tx_stats[0].limit = 5;
dev->queues = 1;
dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 +
diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h
index c15b56e..2245fcc 100644
--- a/drivers/net/wireless/p54/p54common.h
+++ b/drivers/net/wireless/p54/p54common.h
@@ -152,7 +152,6 @@
struct memrecord {
u32 start_addr;
u32 end_addr;
- struct ieee80211_tx_control *control;
};
struct p54_eeprom_lm86 {
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index fa52772..7dd4add 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -665,7 +665,7 @@
if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) {
p54p_open(dev);
- ieee80211_start_queues(dev);
+ ieee80211_wake_queues(dev);
}
return 0;
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 18c9931..3954897 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -1135,7 +1135,7 @@
/* fill in 802.11g rates */
if (has_80211g_rates) {
num = range->num_bitrates;
- for (i = 0; i < sizeof(rates_80211g); i++) {
+ for (i = 0; i < ARRAY_SIZE(rates_80211g); i++) {
for (j = 0; j < num; j++) {
if (range->bitrate[j] ==
rates_80211g[i] * 1000000)
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..900140d 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -620,48 +620,38 @@
static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry)
{
- struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data;
+ struct queue_entry_priv_pci *entry_priv = entry->priv_data;
u32 word;
- rt2x00_desc_read(priv_rx->desc, 2, &word);
+ rt2x00_desc_read(entry_priv->desc, 2, &word);
rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH,
entry->queue->data_size);
- rt2x00_desc_write(priv_rx->desc, 2, word);
+ rt2x00_desc_write(entry_priv->desc, 2, word);
- rt2x00_desc_read(priv_rx->desc, 1, &word);
- rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, priv_rx->data_dma);
- rt2x00_desc_write(priv_rx->desc, 1, word);
+ rt2x00_desc_read(entry_priv->desc, 1, &word);
+ rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
+ rt2x00_desc_write(entry_priv->desc, 1, word);
- rt2x00_desc_read(priv_rx->desc, 0, &word);
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
- rt2x00_desc_write(priv_rx->desc, 0, word);
+ rt2x00_desc_write(entry_priv->desc, 0, word);
}
static void rt2400pci_init_txentry(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry)
{
- struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data;
+ struct queue_entry_priv_pci *entry_priv = entry->priv_data;
u32 word;
- rt2x00_desc_read(priv_tx->desc, 1, &word);
- rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, priv_tx->data_dma);
- rt2x00_desc_write(priv_tx->desc, 1, word);
-
- rt2x00_desc_read(priv_tx->desc, 2, &word);
- rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH,
- entry->queue->data_size);
- rt2x00_desc_write(priv_tx->desc, 2, word);
-
- rt2x00_desc_read(priv_tx->desc, 0, &word);
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
rt2x00_set_field32(&word, TXD_W0_VALID, 0);
rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
- rt2x00_desc_write(priv_tx->desc, 0, word);
+ rt2x00_desc_write(entry_priv->desc, 0, word);
}
static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev)
{
- struct queue_entry_priv_pci_rx *priv_rx;
- struct queue_entry_priv_pci_tx *priv_tx;
+ struct queue_entry_priv_pci *entry_priv;
u32 reg;
/*
@@ -674,28 +664,28 @@
rt2x00_set_field32(®, TXCSR2_NUM_PRIO, rt2x00dev->tx[0].limit);
rt2x00pci_register_write(rt2x00dev, TXCSR2, reg);
- priv_tx = rt2x00dev->tx[1].entries[0].priv_data;
+ entry_priv = rt2x00dev->tx[1].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, TXCSR3, ®);
rt2x00_set_field32(®, TXCSR3_TX_RING_REGISTER,
- priv_tx->desc_dma);
+ entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, TXCSR3, reg);
- priv_tx = rt2x00dev->tx[0].entries[0].priv_data;
+ entry_priv = rt2x00dev->tx[0].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, TXCSR5, ®);
rt2x00_set_field32(®, TXCSR5_PRIO_RING_REGISTER,
- priv_tx->desc_dma);
+ entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, TXCSR5, reg);
- priv_tx = rt2x00dev->bcn[1].entries[0].priv_data;
+ entry_priv = rt2x00dev->bcn[1].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, TXCSR4, ®);
rt2x00_set_field32(®, TXCSR4_ATIM_RING_REGISTER,
- priv_tx->desc_dma);
+ entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, TXCSR4, reg);
- priv_tx = rt2x00dev->bcn[0].entries[0].priv_data;
+ entry_priv = rt2x00dev->bcn[0].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, TXCSR6, ®);
rt2x00_set_field32(®, TXCSR6_BEACON_RING_REGISTER,
- priv_tx->desc_dma);
+ entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, TXCSR6, reg);
rt2x00pci_register_read(rt2x00dev, RXCSR1, ®);
@@ -703,9 +693,10 @@
rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->limit);
rt2x00pci_register_write(rt2x00dev, RXCSR1, reg);
- priv_rx = rt2x00dev->rx->entries[0].priv_data;
+ entry_priv = rt2x00dev->rx->entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, RXCSR2, ®);
- rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, priv_rx->desc_dma);
+ rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER,
+ entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, RXCSR2, reg);
return 0;
@@ -1001,17 +992,22 @@
*/
static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
- struct txentry_desc *txdesc,
- struct ieee80211_tx_control *control)
+ struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+ struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
__le32 *txd = skbdesc->desc;
u32 word;
/*
* Start writing the descriptor words.
*/
+ rt2x00_desc_read(entry_priv->desc, 1, &word);
+ rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
+ rt2x00_desc_write(entry_priv->desc, 1, word);
+
rt2x00_desc_read(txd, 2, &word);
+ rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, skbdesc->data_len);
rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, skbdesc->data_len);
rt2x00_desc_write(txd, 2, word);
@@ -1046,8 +1042,7 @@
test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
- !!(control->flags &
- IEEE80211_TXCTL_LONG_RETRY_LIMIT));
+ test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
rt2x00_desc_write(txd, 0, word);
}
@@ -1055,11 +1050,11 @@
* 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 +1066,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);
}
@@ -1086,16 +1078,15 @@
static void rt2400pci_fill_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc)
{
- struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data;
+ struct queue_entry_priv_pci *entry_priv = entry->priv_data;
u32 word0;
u32 word2;
u32 word3;
- rt2x00_desc_read(priv_rx->desc, 0, &word0);
- rt2x00_desc_read(priv_rx->desc, 2, &word2);
- rt2x00_desc_read(priv_rx->desc, 3, &word3);
+ rt2x00_desc_read(entry_priv->desc, 0, &word0);
+ rt2x00_desc_read(entry_priv->desc, 2, &word2);
+ rt2x00_desc_read(entry_priv->desc, 3, &word3);
- rxdesc->flags = 0;
if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
@@ -1111,7 +1102,7 @@
entry->queue->rt2x00dev->rssi_offset;
rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
- rxdesc->dev_flags = RXDONE_SIGNAL_PLCP;
+ rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP;
if (rt2x00_get_field32(word0, RXD_W0_MY_BSS))
rxdesc->dev_flags |= RXDONE_MY_BSS;
}
@@ -1120,18 +1111,18 @@
* Interrupt functions.
*/
static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev,
- const enum ieee80211_tx_queue queue_idx)
+ const enum data_queue_qid queue_idx)
{
struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, queue_idx);
- struct queue_entry_priv_pci_tx *priv_tx;
+ struct queue_entry_priv_pci *entry_priv;
struct queue_entry *entry;
struct txdone_entry_desc txdesc;
u32 word;
while (!rt2x00queue_empty(queue)) {
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
- priv_tx = entry->priv_data;
- rt2x00_desc_read(priv_tx->desc, 0, &word);
+ entry_priv = entry->priv_data;
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
!rt2x00_get_field32(word, TXD_W0_VALID))
@@ -1140,7 +1131,18 @@
/*
* Obtain the status about this packet.
*/
- txdesc.status = rt2x00_get_field32(word, TXD_W0_RESULT);
+ txdesc.flags = 0;
+ switch (rt2x00_get_field32(word, TXD_W0_RESULT)) {
+ case 0: /* Success */
+ case 1: /* Success with retry */
+ __set_bit(TXDONE_SUCCESS, &txdesc.flags);
+ break;
+ case 2: /* Failure, excessive retries */
+ __set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags);
+ /* Don't break, this is a failed frame! */
+ default: /* Failure */
+ __set_bit(TXDONE_FAILURE, &txdesc.flags);
+ }
txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
rt2x00pci_txdone(rt2x00dev, entry, &txdesc);
@@ -1187,19 +1189,19 @@
* 3 - Atim ring transmit done interrupt.
*/
if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING))
- rt2400pci_txdone(rt2x00dev, RT2X00_BCN_QUEUE_ATIM);
+ rt2400pci_txdone(rt2x00dev, QID_ATIM);
/*
* 4 - Priority ring transmit done interrupt.
*/
if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING))
- rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
+ rt2400pci_txdone(rt2x00dev, QID_AC_BE);
/*
* 5 - Tx ring transmit done interrupt.
*/
if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
- rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
+ rt2400pci_txdone(rt2x00dev, QID_AC_BK);
return IRQ_HANDLED;
}
@@ -1364,11 +1366,9 @@
/*
* Initialize all hw fields.
*/
- rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+ rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+ IEEE80211_HW_SIGNAL_DBM;
rt2x00dev->hw->extra_tx_headroom = 0;
- rt2x00dev->hw->max_signal = MAX_SIGNAL;
- rt2x00dev->hw->max_rssi = MAX_RX_SSI;
- rt2x00dev->hw->queues = 2;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
@@ -1445,8 +1445,7 @@
return 0;
}
-static int rt2400pci_conf_tx(struct ieee80211_hw *hw,
- int queue,
+static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -1456,7 +1455,7 @@
* per queue. So by default we only configure the TX queue,
* and ignore all other configurations.
*/
- if (queue != IEEE80211_TX_QUEUE_DATA0)
+ if (queue != 0)
return -EINVAL;
if (rt2x00mac_conf_tx(hw, queue, params))
@@ -1485,18 +1484,27 @@
return tsf;
}
-static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
- struct rt2x00_intf *intf = vif_to_intf(control->vif);
- struct queue_entry_priv_pci_tx *priv_tx;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
+ struct queue_entry_priv_pci *entry_priv;
struct skb_frame_desc *skbdesc;
+ struct txentry_desc txdesc;
u32 reg;
if (unlikely(!intf->beacon))
return -ENOBUFS;
- priv_tx = intf->beacon->priv_data;
+ entry_priv = intf->beacon->priv_data;
+
+ /*
+ * Copy all TX descriptor information into txdesc,
+ * after that we are free to use the skb->cb array
+ * for our information.
+ */
+ intf->beacon->skb = skb;
+ rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
/*
* Fill in skb descriptor
@@ -1506,7 +1514,7 @@
skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED;
skbdesc->data = skb->data;
skbdesc->data_len = skb->len;
- skbdesc->desc = priv_tx->desc;
+ skbdesc->desc = entry_priv->desc;
skbdesc->desc_len = intf->beacon->queue->desc_size;
skbdesc->entry = intf->beacon;
@@ -1521,20 +1529,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.
*/
- memcpy(priv_tx->data, skb->data, skb->len);
- rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue);
+ memcpy(entry_priv->data, skb->data, skb->len);
+ rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
+ rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
return 0;
}
@@ -1593,28 +1594,28 @@
.entry_num = RX_ENTRIES,
.data_size = DATA_FRAME_SIZE,
.desc_size = RXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci_rx),
+ .priv_size = sizeof(struct queue_entry_priv_pci),
};
static const struct data_queue_desc rt2400pci_queue_tx = {
.entry_num = TX_ENTRIES,
.data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci_tx),
+ .priv_size = sizeof(struct queue_entry_priv_pci),
};
static const struct data_queue_desc rt2400pci_queue_bcn = {
.entry_num = BEACON_ENTRIES,
.data_size = MGMT_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci_tx),
+ .priv_size = sizeof(struct queue_entry_priv_pci),
};
static const struct data_queue_desc rt2400pci_queue_atim = {
.entry_num = ATIM_ENTRIES,
.data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci_tx),
+ .priv_size = sizeof(struct queue_entry_priv_pci),
};
static const struct rt2x00_ops rt2400pci_ops = {
@@ -1623,6 +1624,7 @@
.max_ap_intf = 1,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
+ .tx_queues = NUM_TX_QUEUES,
.rx = &rt2400pci_queue_rx,
.tx = &rt2400pci_queue_tx,
.bcn = &rt2400pci_queue_bcn,
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h
index a5210f9..e9aa326 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.h
+++ b/drivers/net/wireless/rt2x00/rt2400pci.h
@@ -52,6 +52,11 @@
#define RF_SIZE 0x0010
/*
+ * Number of TX queues.
+ */
+#define NUM_TX_QUEUES 2
+
+/*
* Control/Status Registers(CSR).
* Some values are set in TU, whereas 1 TU == 1024 us.
*/
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index a5ed54b..6733509 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;
@@ -716,38 +715,33 @@
static void rt2500pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry)
{
- struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data;
+ struct queue_entry_priv_pci *entry_priv = entry->priv_data;
u32 word;
- rt2x00_desc_read(priv_rx->desc, 1, &word);
- rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, priv_rx->data_dma);
- rt2x00_desc_write(priv_rx->desc, 1, word);
+ rt2x00_desc_read(entry_priv->desc, 1, &word);
+ rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
+ rt2x00_desc_write(entry_priv->desc, 1, word);
- rt2x00_desc_read(priv_rx->desc, 0, &word);
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
- rt2x00_desc_write(priv_rx->desc, 0, word);
+ rt2x00_desc_write(entry_priv->desc, 0, word);
}
static void rt2500pci_init_txentry(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry)
{
- struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data;
+ struct queue_entry_priv_pci *entry_priv = entry->priv_data;
u32 word;
- rt2x00_desc_read(priv_tx->desc, 1, &word);
- rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, priv_tx->data_dma);
- rt2x00_desc_write(priv_tx->desc, 1, word);
-
- rt2x00_desc_read(priv_tx->desc, 0, &word);
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
rt2x00_set_field32(&word, TXD_W0_VALID, 0);
rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
- rt2x00_desc_write(priv_tx->desc, 0, word);
+ rt2x00_desc_write(entry_priv->desc, 0, word);
}
static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev)
{
- struct queue_entry_priv_pci_rx *priv_rx;
- struct queue_entry_priv_pci_tx *priv_tx;
+ struct queue_entry_priv_pci *entry_priv;
u32 reg;
/*
@@ -760,28 +754,28 @@
rt2x00_set_field32(®, TXCSR2_NUM_PRIO, rt2x00dev->tx[0].limit);
rt2x00pci_register_write(rt2x00dev, TXCSR2, reg);
- priv_tx = rt2x00dev->tx[1].entries[0].priv_data;
+ entry_priv = rt2x00dev->tx[1].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, TXCSR3, ®);
rt2x00_set_field32(®, TXCSR3_TX_RING_REGISTER,
- priv_tx->desc_dma);
+ entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, TXCSR3, reg);
- priv_tx = rt2x00dev->tx[0].entries[0].priv_data;
+ entry_priv = rt2x00dev->tx[0].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, TXCSR5, ®);
rt2x00_set_field32(®, TXCSR5_PRIO_RING_REGISTER,
- priv_tx->desc_dma);
+ entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, TXCSR5, reg);
- priv_tx = rt2x00dev->bcn[1].entries[0].priv_data;
+ entry_priv = rt2x00dev->bcn[1].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, TXCSR4, ®);
rt2x00_set_field32(®, TXCSR4_ATIM_RING_REGISTER,
- priv_tx->desc_dma);
+ entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, TXCSR4, reg);
- priv_tx = rt2x00dev->bcn[0].entries[0].priv_data;
+ entry_priv = rt2x00dev->bcn[0].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, TXCSR6, ®);
rt2x00_set_field32(®, TXCSR6_BEACON_RING_REGISTER,
- priv_tx->desc_dma);
+ entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, TXCSR6, reg);
rt2x00pci_register_read(rt2x00dev, RXCSR1, ®);
@@ -789,9 +783,10 @@
rt2x00_set_field32(®, RXCSR1_NUM_RXD, rt2x00dev->rx->limit);
rt2x00pci_register_write(rt2x00dev, RXCSR1, reg);
- priv_rx = rt2x00dev->rx->entries[0].priv_data;
+ entry_priv = rt2x00dev->rx->entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, RXCSR2, ®);
- rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER, priv_rx->desc_dma);
+ rt2x00_set_field32(®, RXCSR2_RX_RING_REGISTER,
+ entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, RXCSR2, reg);
return 0;
@@ -1156,16 +1151,20 @@
*/
static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
- struct txentry_desc *txdesc,
- struct ieee80211_tx_control *control)
+ struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+ struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
__le32 *txd = skbdesc->desc;
u32 word;
/*
* Start writing the descriptor words.
*/
+ rt2x00_desc_read(entry_priv->desc, 1, &word);
+ rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry_priv->data_dma);
+ rt2x00_desc_write(entry_priv->desc, 1, word);
+
rt2x00_desc_read(txd, 2, &word);
rt2x00_set_field32(&word, TXD_W2_IV_OFFSET, IEEE80211_HEADER);
rt2x00_set_field32(&word, TXD_W2_AIFS, txdesc->aifs);
@@ -1199,9 +1198,7 @@
rt2x00_set_field32(&word, TXD_W0_CIPHER_OWNER, 1);
rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
- !!(control->flags &
- IEEE80211_TXCTL_LONG_RETRY_LIMIT));
- rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len);
+ test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
rt2x00_desc_write(txd, 0, word);
}
@@ -1210,11 +1207,11 @@
* 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 +1223,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);
}
@@ -1241,14 +1235,13 @@
static void rt2500pci_fill_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc)
{
- struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data;
+ struct queue_entry_priv_pci *entry_priv = entry->priv_data;
u32 word0;
u32 word2;
- rt2x00_desc_read(priv_rx->desc, 0, &word0);
- rt2x00_desc_read(priv_rx->desc, 2, &word2);
+ rt2x00_desc_read(entry_priv->desc, 0, &word0);
+ rt2x00_desc_read(entry_priv->desc, 2, &word2);
- rxdesc->flags = 0;
if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
@@ -1265,7 +1258,6 @@
entry->queue->rt2x00dev->rssi_offset;
rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
- rxdesc->dev_flags = 0;
if (rt2x00_get_field32(word0, RXD_W0_OFDM))
rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP;
if (rt2x00_get_field32(word0, RXD_W0_MY_BSS))
@@ -1276,18 +1268,18 @@
* Interrupt functions.
*/
static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev,
- const enum ieee80211_tx_queue queue_idx)
+ const enum data_queue_qid queue_idx)
{
struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, queue_idx);
- struct queue_entry_priv_pci_tx *priv_tx;
+ struct queue_entry_priv_pci *entry_priv;
struct queue_entry *entry;
struct txdone_entry_desc txdesc;
u32 word;
while (!rt2x00queue_empty(queue)) {
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
- priv_tx = entry->priv_data;
- rt2x00_desc_read(priv_tx->desc, 0, &word);
+ entry_priv = entry->priv_data;
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
!rt2x00_get_field32(word, TXD_W0_VALID))
@@ -1296,7 +1288,18 @@
/*
* Obtain the status about this packet.
*/
- txdesc.status = rt2x00_get_field32(word, TXD_W0_RESULT);
+ txdesc.flags = 0;
+ switch (rt2x00_get_field32(word, TXD_W0_RESULT)) {
+ case 0: /* Success */
+ case 1: /* Success with retry */
+ __set_bit(TXDONE_SUCCESS, &txdesc.flags);
+ break;
+ case 2: /* Failure, excessive retries */
+ __set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags);
+ /* Don't break, this is a failed frame! */
+ default: /* Failure */
+ __set_bit(TXDONE_FAILURE, &txdesc.flags);
+ }
txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
rt2x00pci_txdone(rt2x00dev, entry, &txdesc);
@@ -1343,19 +1346,19 @@
* 3 - Atim ring transmit done interrupt.
*/
if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING))
- rt2500pci_txdone(rt2x00dev, RT2X00_BCN_QUEUE_ATIM);
+ rt2500pci_txdone(rt2x00dev, QID_ATIM);
/*
* 4 - Priority ring transmit done interrupt.
*/
if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING))
- rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
+ rt2500pci_txdone(rt2x00dev, QID_AC_BE);
/*
* 5 - Tx ring transmit done interrupt.
*/
if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
- rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
+ rt2500pci_txdone(rt2x00dev, QID_AC_BK);
return IRQ_HANDLED;
}
@@ -1684,11 +1687,10 @@
/*
* Initialize all hw fields.
*/
- rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+ rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+ IEEE80211_HW_SIGNAL_DBM;
+
rt2x00dev->hw->extra_tx_headroom = 0;
- rt2x00dev->hw->max_signal = MAX_SIGNAL;
- rt2x00dev->hw->max_rssi = MAX_RX_SSI;
- rt2x00dev->hw->queues = 2;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
@@ -1797,19 +1799,28 @@
return tsf;
}
-static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
- struct rt2x00_intf *intf = vif_to_intf(control->vif);
- struct queue_entry_priv_pci_tx *priv_tx;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
+ struct queue_entry_priv_pci *entry_priv;
struct skb_frame_desc *skbdesc;
+ struct txentry_desc txdesc;
u32 reg;
if (unlikely(!intf->beacon))
return -ENOBUFS;
- priv_tx = intf->beacon->priv_data;
+ entry_priv = intf->beacon->priv_data;
+
+ /*
+ * Copy all TX descriptor information into txdesc,
+ * after that we are free to use the skb->cb array
+ * for our information.
+ */
+ intf->beacon->skb = skb;
+ rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
/*
* Fill in skb descriptor
@@ -1819,7 +1830,7 @@
skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED;
skbdesc->data = skb->data;
skbdesc->data_len = skb->len;
- skbdesc->desc = priv_tx->desc;
+ skbdesc->desc = entry_priv->desc;
skbdesc->desc_len = intf->beacon->queue->desc_size;
skbdesc->entry = intf->beacon;
@@ -1834,20 +1845,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.
*/
- memcpy(priv_tx->data, skb->data, skb->len);
- rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue);
+ memcpy(entry_priv->data, skb->data, skb->len);
+ rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
+ rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
return 0;
}
@@ -1906,28 +1910,28 @@
.entry_num = RX_ENTRIES,
.data_size = DATA_FRAME_SIZE,
.desc_size = RXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci_rx),
+ .priv_size = sizeof(struct queue_entry_priv_pci),
};
static const struct data_queue_desc rt2500pci_queue_tx = {
.entry_num = TX_ENTRIES,
.data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci_tx),
+ .priv_size = sizeof(struct queue_entry_priv_pci),
};
static const struct data_queue_desc rt2500pci_queue_bcn = {
.entry_num = BEACON_ENTRIES,
.data_size = MGMT_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci_tx),
+ .priv_size = sizeof(struct queue_entry_priv_pci),
};
static const struct data_queue_desc rt2500pci_queue_atim = {
.entry_num = ATIM_ENTRIES,
.data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci_tx),
+ .priv_size = sizeof(struct queue_entry_priv_pci),
};
static const struct rt2x00_ops rt2500pci_ops = {
@@ -1936,6 +1940,7 @@
.max_ap_intf = 1,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
+ .tx_queues = NUM_TX_QUEUES,
.rx = &rt2500pci_queue_rx,
.tx = &rt2500pci_queue_tx,
.bcn = &rt2500pci_queue_bcn,
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h
index 1389955..ea93b8f4 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.h
+++ b/drivers/net/wireless/rt2x00/rt2500pci.h
@@ -63,6 +63,11 @@
#define RF_SIZE 0x0014
/*
+ * Number of TX queues.
+ */
+#define NUM_TX_QUEUES 2
+
+/*
* Control/Status Registers(CSR).
* Some values are set in TU, whereas 1 TU == 1024 us.
*/
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index fdbd0ef..cca1504 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)
@@ -1033,8 +1033,7 @@
*/
static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
- struct txentry_desc *txdesc,
- struct ieee80211_tx_control *control)
+ struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
__le32 *txd = skbdesc->desc;
@@ -1058,7 +1057,7 @@
rt2x00_desc_write(txd, 2, word);
rt2x00_desc_read(txd, 0, &word);
- rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, control->retry_limit);
+ rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, txdesc->retry_limit);
rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_ACK,
@@ -1068,7 +1067,7 @@
rt2x00_set_field32(&word, TXD_W0_OFDM,
test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_NEW_SEQ,
- !!(control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT));
+ test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len);
rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE);
@@ -1094,11 +1093,11 @@
* 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, ®);
@@ -1125,30 +1124,32 @@
static void rt2500usb_fill_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc)
{
- struct queue_entry_priv_usb_rx *priv_rx = entry->priv_data;
+ struct queue_entry_priv_usb *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
__le32 *rxd =
(__le32 *)(entry->skb->data +
- (priv_rx->urb->actual_length - entry->queue->desc_size));
- unsigned int offset = entry->queue->desc_size + 2;
+ (entry_priv->urb->actual_length -
+ entry->queue->desc_size));
u32 word0;
u32 word1;
/*
- * Copy descriptor to the available headroom inside the skbuffer.
+ * Copy descriptor to the skb->cb array, this has 2 benefits:
+ * 1) Each descriptor word is 4 byte aligned.
+ * 2) Descriptor is safe from moving of frame data in rt2x00usb.
*/
- skb_push(entry->skb, offset);
- memcpy(entry->skb->data, rxd, entry->queue->desc_size);
- rxd = (__le32 *)entry->skb->data;
+ skbdesc->desc_len =
+ min_t(u16, entry->queue->desc_size, sizeof(entry->skb->cb));
+ memcpy(entry->skb->cb, rxd, skbdesc->desc_len);
+ skbdesc->desc = entry->skb->cb;
+ rxd = (__le32 *)skbdesc->desc;
/*
- * The descriptor is now aligned to 4 bytes and thus it is
- * now safe to read it on all architectures.
+ * It is now safe to read the descriptor on all architectures.
*/
rt2x00_desc_read(rxd, 0, &word0);
rt2x00_desc_read(rxd, 1, &word1);
- rxdesc->flags = 0;
if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
@@ -1165,7 +1166,6 @@
entry->queue->rt2x00dev->rssi_offset;
rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
- rxdesc->dev_flags = 0;
if (rt2x00_get_field32(word0, RXD_W0_OFDM))
rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP;
if (rt2x00_get_field32(word0, RXD_W0_MY_BSS))
@@ -1174,16 +1174,9 @@
/*
* Adjust the skb memory window to the frame boundaries.
*/
- skb_pull(entry->skb, offset);
skb_trim(entry->skb, rxdesc->size);
-
- /*
- * Set descriptor and data pointer.
- */
skbdesc->data = entry->skb->data;
skbdesc->data_len = rxdesc->size;
- skbdesc->desc = rxd;
- skbdesc->desc_len = entry->queue->desc_size;
}
/*
@@ -1192,7 +1185,7 @@
static void rt2500usb_beacondone(struct urb *urb)
{
struct queue_entry *entry = (struct queue_entry *)urb->context;
- struct queue_entry_priv_usb_bcn *priv_bcn = entry->priv_data;
+ struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
if (!test_bit(DEVICE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags))
return;
@@ -1203,9 +1196,9 @@
* Otherwise we should free the sk_buffer, the device
* should be doing the rest of the work now.
*/
- if (priv_bcn->guardian_urb == urb) {
- usb_submit_urb(priv_bcn->urb, GFP_ATOMIC);
- } else if (priv_bcn->urb == urb) {
+ if (bcn_priv->guardian_urb == urb) {
+ usb_submit_urb(bcn_priv->urb, GFP_ATOMIC);
+ } else if (bcn_priv->urb == urb) {
dev_kfree_skb(entry->skb);
entry->skb = NULL;
}
@@ -1587,11 +1580,10 @@
rt2x00dev->hw->flags =
IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+ IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+ IEEE80211_HW_SIGNAL_DBM;
+
rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
- rt2x00dev->hw->max_signal = MAX_SIGNAL;
- rt2x00dev->hw->max_rssi = MAX_RX_SSI;
- rt2x00dev->hw->queues = 2;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
@@ -1674,15 +1666,15 @@
/*
* IEEE80211 stack callback functions.
*/
-static int rt2500usb_beacon_update(struct ieee80211_hw *hw,
- struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+static int rt2500usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev);
- struct rt2x00_intf *intf = vif_to_intf(control->vif);
- struct queue_entry_priv_usb_bcn *priv_bcn;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
+ struct queue_entry_priv_usb_bcn *bcn_priv;
struct skb_frame_desc *skbdesc;
+ struct txentry_desc txdesc;
int pipe = usb_sndbulkpipe(usb_dev, 1);
int length;
u16 reg;
@@ -1690,7 +1682,15 @@
if (unlikely(!intf->beacon))
return -ENOBUFS;
- priv_bcn = intf->beacon->priv_data;
+ bcn_priv = intf->beacon->priv_data;
+
+ /*
+ * Copy all TX descriptor information into txdesc,
+ * after that we are free to use the skb->cb array
+ * for our information.
+ */
+ intf->beacon->skb = skb;
+ rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
/*
* Add the descriptor in front of the skb.
@@ -1720,13 +1720,7 @@
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);
+ rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
/*
* USB devices cannot blindly pass the skb->len as the
@@ -1735,7 +1729,7 @@
*/
length = rt2500usb_get_tx_data_len(rt2x00dev, skb);
- usb_fill_bulk_urb(priv_bcn->urb, usb_dev, pipe,
+ usb_fill_bulk_urb(bcn_priv->urb, usb_dev, pipe,
skb->data, length, rt2500usb_beacondone,
intf->beacon);
@@ -1744,20 +1738,20 @@
* We only need a single byte, so lets recycle
* the 'flags' field we are not using for beacons.
*/
- priv_bcn->guardian_data = 0;
- usb_fill_bulk_urb(priv_bcn->guardian_urb, usb_dev, pipe,
- &priv_bcn->guardian_data, 1, rt2500usb_beacondone,
+ bcn_priv->guardian_data = 0;
+ usb_fill_bulk_urb(bcn_priv->guardian_urb, usb_dev, pipe,
+ &bcn_priv->guardian_data, 1, rt2500usb_beacondone,
intf->beacon);
/*
* Send out the guardian byte.
*/
- usb_submit_urb(priv_bcn->guardian_urb, GFP_ATOMIC);
+ usb_submit_urb(bcn_priv->guardian_urb, GFP_ATOMIC);
/*
* Enable beacon generation.
*/
- rt2500usb_kick_tx_queue(rt2x00dev, control->queue);
+ rt2500usb_kick_tx_queue(rt2x00dev, QID_BEACON);
return 0;
}
@@ -1803,14 +1797,14 @@
.entry_num = RX_ENTRIES,
.data_size = DATA_FRAME_SIZE,
.desc_size = RXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_usb_rx),
+ .priv_size = sizeof(struct queue_entry_priv_usb),
};
static const struct data_queue_desc rt2500usb_queue_tx = {
.entry_num = TX_ENTRIES,
.data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_usb_tx),
+ .priv_size = sizeof(struct queue_entry_priv_usb),
};
static const struct data_queue_desc rt2500usb_queue_bcn = {
@@ -1824,7 +1818,7 @@
.entry_num = ATIM_ENTRIES,
.data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_usb_tx),
+ .priv_size = sizeof(struct queue_entry_priv_usb),
};
static const struct rt2x00_ops rt2500usb_ops = {
@@ -1833,6 +1827,7 @@
.max_ap_intf = 1,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
+ .tx_queues = NUM_TX_QUEUES,
.rx = &rt2500usb_queue_rx,
.tx = &rt2500usb_queue_tx,
.bcn = &rt2500usb_queue_bcn,
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h
index a37a068..7d50098 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.h
+++ b/drivers/net/wireless/rt2x00/rt2500usb.h
@@ -63,6 +63,11 @@
#define RF_SIZE 0x0014
/*
+ * Number of TX queues.
+ */
+#define NUM_TX_QUEUES 2
+
+/*
* Control/Status Registers(CSR).
* Some values are set in TU, whereas 1 TU == 1024 us.
*/
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 611d983..15ec797 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.6"
#define DRV_PROJECT "http://rt2x00.serialmonkey.com"
/*
@@ -409,7 +409,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
@@ -545,15 +545,13 @@
*/
void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
- struct txentry_desc *txdesc,
- struct ieee80211_tx_control *control);
+ struct txentry_desc *txdesc);
int (*write_tx_data) (struct rt2x00_dev *rt2x00dev,
- struct data_queue *queue, struct sk_buff *skb,
- struct ieee80211_tx_control *control);
+ struct data_queue *queue, struct sk_buff *skb);
int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb);
void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev,
- const unsigned int queue);
+ const enum data_queue_qid queue);
/*
* RX control handlers
@@ -597,6 +595,7 @@
const unsigned int max_ap_intf;
const unsigned int eeprom_size;
const unsigned int rf_size;
+ const unsigned int tx_queues;
const struct data_queue_desc *rx;
const struct data_queue_desc *tx;
const struct data_queue_desc *bcn;
@@ -626,7 +625,6 @@
/*
* Driver features
*/
- DRIVER_SUPPORT_MIXED_INTERFACES,
DRIVER_REQUIRE_FIRMWARE,
DRIVER_REQUIRE_BEACON_GUARD,
DRIVER_REQUIRE_ATIM_QUEUE,
@@ -933,17 +931,49 @@
}
/**
- * rt2x00queue_get_queue - Convert mac80211 queue index to rt2x00 queue
+ * rt2x00queue_create_tx_descriptor - Create TX descriptor from mac80211 input
+ * @entry: The entry which will be used to transfer the TX frame.
+ * @txdesc: rt2x00 TX descriptor which will be initialized by this function.
+ *
+ * This function will initialize the &struct txentry_desc based on information
+ * from mac80211. This descriptor can then be used by rt2x00lib and the drivers
+ * to correctly initialize the hardware descriptor.
+ * Note that before calling this function the skb->cb array must be untouched
+ * by rt2x00lib. Only after this function completes will it be save to
+ * overwrite the skb->cb information.
+ * The reason for this is that mac80211 writes its own tx information into
+ * the skb->cb array, and this function will use that information to initialize
+ * the &struct txentry_desc structure.
+ */
+void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
+ struct txentry_desc *txdesc);
+
+/**
+ * rt2x00queue_write_tx_descriptor - Write TX descriptor to hardware
+ * @entry: The entry which will be used to transfer the TX frame.
+ * @txdesc: TX descriptor which will be used to write hardware descriptor
+ *
+ * This function will write a TX descriptor initialized by
+ * &rt2x00queue_create_tx_descriptor to the hardware. After this call
+ * has completed the frame is now owned by the hardware, the hardware
+ * queue will have automatically be kicked unless this frame was generated
+ * by rt2x00lib, in which case the frame is "special" and must be kicked
+ * by the caller.
+ */
+void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
+ struct txentry_desc *txdesc);
+
+/**
+ * rt2x00queue_get_queue - Convert queue index to queue pointer
* @rt2x00dev: Pointer to &struct rt2x00_dev.
- * @queue: mac80211/rt2x00 queue index
- * (see &enum ieee80211_tx_queue and &enum rt2x00_bcn_queue).
+ * @queue: rt2x00 queue index (see &enum data_queue_qid).
*/
struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
- const unsigned int queue);
+ const enum data_queue_qid queue);
/**
* rt2x00queue_get_entry - Get queue entry where the given index points to.
- * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @queue: Pointer to &struct data_queue from where we obtain the entry.
* @index: Index identifier for obtaining the correct index.
*/
struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
@@ -952,7 +982,7 @@
/**
* 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
@@ -971,17 +1001,9 @@
struct rxdone_entry_desc *rxdesc);
/*
- * TX descriptor initializer
- */
-void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev,
- struct sk_buff *skb,
- struct ieee80211_tx_control *control);
-
-/*
* mac80211 handlers.
*/
-int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_control *control);
+int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
int rt2x00mac_start(struct ieee80211_hw *hw);
void rt2x00mac_stop(struct ieee80211_hw *hw);
int rt2x00mac_add_interface(struct ieee80211_hw *hw,
@@ -1004,7 +1026,7 @@
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/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index bfab3b8..bd92cb8 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -115,7 +115,7 @@
};
void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
- struct sk_buff *skb)
+ enum rt2x00_dump_type type, struct sk_buff *skb)
{
struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
struct skb_frame_desc *desc = get_skb_frame_desc(skb);
@@ -148,7 +148,7 @@
dump_hdr->chip_rt = cpu_to_le16(rt2x00dev->chip.rt);
dump_hdr->chip_rf = cpu_to_le16(rt2x00dev->chip.rf);
dump_hdr->chip_rev = cpu_to_le32(rt2x00dev->chip.rev);
- dump_hdr->type = cpu_to_le16(desc->frame_type);
+ dump_hdr->type = cpu_to_le16(type);
dump_hdr->queue_index = desc->entry->queue->qid;
dump_hdr->entry_index = desc->entry->entry_idx;
dump_hdr->timestamp_sec = cpu_to_le32(timestamp.tv_sec);
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 2673d56..dc5ab90 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -28,7 +28,6 @@
#include "rt2x00.h"
#include "rt2x00lib.h"
-#include "rt2x00dump.h"
/*
* Link tuning handlers
@@ -126,7 +125,7 @@
/*
* Start the TX queues.
*/
- ieee80211_start_queues(rt2x00dev->hw);
+ ieee80211_wake_queues(rt2x00dev->hw);
return 0;
}
@@ -416,7 +415,6 @@
struct rt2x00_dev *rt2x00dev = data;
struct rt2x00_intf *intf = vif_to_intf(vif);
struct sk_buff *skb;
- struct ieee80211_tx_control control;
struct ieee80211_bss_conf conf;
int delayed_flags;
@@ -434,9 +432,9 @@
spin_unlock(&intf->lock);
if (delayed_flags & DELAYED_UPDATE_BEACON) {
- skb = ieee80211_beacon_get(rt2x00dev->hw, vif, &control);
- if (skb && rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw,
- skb, &control))
+ skb = ieee80211_beacon_get(rt2x00dev->hw, vif);
+ if (skb &&
+ rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, skb))
dev_kfree_skb(skb);
}
@@ -495,64 +493,55 @@
struct txdone_entry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- struct skb_frame_desc *skbdesc;
- struct ieee80211_tx_status tx_status;
- int success = !!(txdesc->status == TX_SUCCESS ||
- txdesc->status == TX_SUCCESS_RETRY);
- int fail = !!(txdesc->status == TX_FAIL_RETRY ||
- txdesc->status == TX_FAIL_INVALID ||
- txdesc->status == TX_FAIL_OTHER);
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
+
+ /*
+ * Send frame to debugfs immediately, after this call is completed
+ * we are going to overwrite the skb->cb array.
+ */
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TXDONE, entry->skb);
/*
* Update TX statistics.
*/
- rt2x00dev->link.qual.tx_success += success;
- rt2x00dev->link.qual.tx_failed += fail;
+ rt2x00dev->link.qual.tx_success +=
+ test_bit(TXDONE_SUCCESS, &txdesc->flags);
+ rt2x00dev->link.qual.tx_failed +=
+ test_bit(TXDONE_FAILURE, &txdesc->flags);
/*
* Initialize TX status
*/
- tx_status.flags = 0;
- tx_status.ack_signal = 0;
- tx_status.excessive_retries = (txdesc->status == TX_FAIL_RETRY);
- tx_status.retry_count = txdesc->retry;
- memcpy(&tx_status.control, txdesc->control, sizeof(*txdesc->control));
+ memset(&tx_info->status, 0, sizeof(tx_info->status));
+ tx_info->status.ack_signal = 0;
+ tx_info->status.excessive_retries =
+ test_bit(TXDONE_EXCESSIVE_RETRY, &txdesc->flags);
+ tx_info->status.retry_count = txdesc->retry;
- if (!(tx_status.control.flags & IEEE80211_TXCTL_NO_ACK)) {
- if (success)
- tx_status.flags |= IEEE80211_TX_STATUS_ACK;
- else
+ if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
+ if (test_bit(TXDONE_SUCCESS, &txdesc->flags))
+ tx_info->flags |= IEEE80211_TX_STAT_ACK;
+ else if (test_bit(TXDONE_FAILURE, &txdesc->flags))
rt2x00dev->low_level_stats.dot11ACKFailureCount++;
}
- tx_status.queue_length = entry->queue->limit;
- tx_status.queue_number = tx_status.control.queue;
-
- if (tx_status.control.flags & IEEE80211_TXCTL_USE_RTS_CTS) {
- if (success)
+ if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
+ if (test_bit(TXDONE_SUCCESS, &txdesc->flags))
rt2x00dev->low_level_stats.dot11RTSSuccessCount++;
- else
+ else if (test_bit(TXDONE_FAILURE, &txdesc->flags))
rt2x00dev->low_level_stats.dot11RTSFailureCount++;
}
/*
- * Send the tx_status to debugfs. Only send the status report
- * to mac80211 when the frame originated from there. If this was
- * a extra frame coming through a mac80211 library call (RTS/CTS)
- * then we should not send the status report back.
- * If send to mac80211, mac80211 will clean up the skb structure,
- * otherwise we have to do it ourself.
+ * Only send the status report to mac80211 when TX status was
+ * requested by it. If this was a extra frame coming through
+ * a mac80211 library call (RTS/CTS) then we should not send the
+ * status report back.
*/
- skbdesc = get_skb_frame_desc(entry->skb);
- skbdesc->frame_type = DUMP_FRAME_TXDONE;
-
- rt2x00debug_dump_frame(rt2x00dev, entry->skb);
-
- if (!(skbdesc->flags & FRAME_DESC_DRIVER_GENERATED))
- ieee80211_tx_status_irqsafe(rt2x00dev->hw,
- entry->skb, &tx_status);
+ if (tx_info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)
+ ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb);
else
- dev_kfree_skb(entry->skb);
+ dev_kfree_skb_irq(entry->skb);
entry->skb = NULL;
}
EXPORT_SYMBOL_GPL(rt2x00lib_txdone);
@@ -603,9 +592,9 @@
rt2x00dev->link.qual.rx_success++;
rx_status->rate_idx = idx;
- rx_status->signal =
+ rx_status->qual =
rt2x00lib_calculate_link_signal(rt2x00dev, rxdesc->rssi);
- rx_status->ssi = rxdesc->rssi;
+ rx_status->signal = rxdesc->rssi;
rx_status->flag = rxdesc->flags;
rx_status->antenna = rt2x00dev->link.ant.active.rx;
@@ -613,155 +602,13 @@
* Send frame to mac80211 & debugfs.
* mac80211 will clean up the skb structure.
*/
- get_skb_frame_desc(entry->skb)->frame_type = DUMP_FRAME_RXDONE;
- rt2x00debug_dump_frame(rt2x00dev, entry->skb);
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb, rx_status);
entry->skb = NULL;
}
EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
/*
- * TX descriptor initializer
- */
-void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev,
- struct sk_buff *skb,
- struct ieee80211_tx_control *control)
-{
- struct txentry_desc txdesc;
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skbdesc->data;
- const struct rt2x00_rate *rate;
- int tx_rate;
- int length;
- int duration;
- int residual;
- u16 frame_control;
- u16 seq_ctrl;
-
- memset(&txdesc, 0, sizeof(txdesc));
-
- txdesc.queue = skbdesc->entry->queue->qid;
- txdesc.cw_min = skbdesc->entry->queue->cw_min;
- txdesc.cw_max = skbdesc->entry->queue->cw_max;
- txdesc.aifs = skbdesc->entry->queue->aifs;
-
- /*
- * Read required fields from ieee80211 header.
- */
- frame_control = le16_to_cpu(hdr->frame_control);
- seq_ctrl = le16_to_cpu(hdr->seq_ctrl);
-
- tx_rate = control->tx_rate->hw_value;
-
- /*
- * Check whether this frame is to be acked
- */
- if (!(control->flags & IEEE80211_TXCTL_NO_ACK))
- __set_bit(ENTRY_TXD_ACK, &txdesc.flags);
-
- /*
- * Check if this is a RTS/CTS frame
- */
- if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) {
- __set_bit(ENTRY_TXD_BURST, &txdesc.flags);
- if (is_rts_frame(frame_control)) {
- __set_bit(ENTRY_TXD_RTS_FRAME, &txdesc.flags);
- __set_bit(ENTRY_TXD_ACK, &txdesc.flags);
- } else
- __clear_bit(ENTRY_TXD_ACK, &txdesc.flags);
- if (control->rts_cts_rate)
- tx_rate = control->rts_cts_rate->hw_value;
- }
-
- rate = rt2x00_get_rate(tx_rate);
-
- /*
- * Check if more fragments are pending
- */
- if (ieee80211_get_morefrag(hdr)) {
- __set_bit(ENTRY_TXD_BURST, &txdesc.flags);
- __set_bit(ENTRY_TXD_MORE_FRAG, &txdesc.flags);
- }
-
- /*
- * Beacons and probe responses require the tsf timestamp
- * to be inserted into the frame.
- */
- if (control->queue == RT2X00_BCN_QUEUE_BEACON ||
- is_probe_resp(frame_control))
- __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc.flags);
-
- /*
- * Determine with what IFS priority this frame should be send.
- * Set ifs to IFS_SIFS when the this is not the first fragment,
- * or this fragment came after RTS/CTS.
- */
- if ((seq_ctrl & IEEE80211_SCTL_FRAG) > 0 ||
- test_bit(ENTRY_TXD_RTS_FRAME, &txdesc.flags))
- txdesc.ifs = IFS_SIFS;
- else
- txdesc.ifs = IFS_BACKOFF;
-
- /*
- * PLCP setup
- * Length calculation depends on OFDM/CCK rate.
- */
- txdesc.signal = rate->plcp;
- txdesc.service = 0x04;
-
- length = skbdesc->data_len + FCS_LEN;
- if (rate->flags & DEV_RATE_OFDM) {
- __set_bit(ENTRY_TXD_OFDM_RATE, &txdesc.flags);
-
- txdesc.length_high = (length >> 6) & 0x3f;
- txdesc.length_low = length & 0x3f;
- } else {
- /*
- * Convert length to microseconds.
- */
- residual = get_duration_res(length, rate->bitrate);
- duration = get_duration(length, rate->bitrate);
-
- if (residual != 0) {
- duration++;
-
- /*
- * Check if we need to set the Length Extension
- */
- if (rate->bitrate == 110 && residual <= 30)
- txdesc.service |= 0x80;
- }
-
- txdesc.length_high = (duration >> 8) & 0xff;
- txdesc.length_low = duration & 0xff;
-
- /*
- * When preamble is enabled we should set the
- * preamble bit for the signal.
- */
- if (rt2x00_get_rate_preamble(tx_rate))
- txdesc.signal |= 0x08;
- }
-
- rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, skb, &txdesc, control);
-
- /*
- * Update queue entry.
- */
- skbdesc->entry->skb = skb;
-
- /*
- * The frame has been completely initialized and ready
- * for sending to the device. The caller will push the
- * frame to the device, but we are going to push the
- * frame to debugfs here.
- */
- skbdesc->frame_type = DUMP_FRAME_TX;
- rt2x00debug_dump_frame(rt2x00dev, skb);
-}
-EXPORT_SYMBOL_GPL(rt2x00lib_write_tx_desc);
-
-/*
* Driver initialization handlers.
*/
const struct rt2x00_rate rt2x00_supported_rates[12] = {
@@ -977,6 +824,11 @@
return status;
/*
+ * Initialize HW fields.
+ */
+ rt2x00dev->hw->queues = rt2x00dev->ops->tx_queues;
+
+ /*
* Register HW.
*/
status = ieee80211_register_hw(rt2x00dev->hw);
@@ -1331,7 +1183,7 @@
* In that case we have disabled the TX queue and should
* now enable it again
*/
- ieee80211_start_queues(rt2x00dev->hw);
+ ieee80211_wake_queues(rt2x00dev->hw);
/*
* During interface iteration we might have changed the
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index 41ee02c..c4ce534 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -26,6 +26,8 @@
#ifndef RT2X00LIB_H
#define RT2X00LIB_H
+#include "rt2x00dump.h"
+
/*
* Interval defines
* Both the link tuner as the rfkill will be called once per second.
@@ -128,7 +130,8 @@
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
void rt2x00debug_register(struct rt2x00_dev *rt2x00dev);
void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev);
-void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
+void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
+ enum rt2x00_dump_type type, struct sk_buff *skb);
#else
static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
{
@@ -139,6 +142,7 @@
}
static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
+ enum rt2x00_dump_type type,
struct sk_buff *skb)
{
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 87e280a..b02dbc8 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -31,14 +31,15 @@
static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue,
- struct sk_buff *frag_skb,
- struct ieee80211_tx_control *control)
+ struct sk_buff *frag_skb)
{
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(frag_skb);
struct skb_frame_desc *skbdesc;
+ struct ieee80211_tx_info *rts_info;
struct sk_buff *skb;
int size;
- if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+ if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
size = sizeof(struct ieee80211_cts);
else
size = sizeof(struct ieee80211_rts);
@@ -52,13 +53,33 @@
skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom);
skb_put(skb, size);
- if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
- ieee80211_ctstoself_get(rt2x00dev->hw, control->vif,
- frag_skb->data, frag_skb->len, control,
+ /*
+ * Copy TX information over from original frame to
+ * RTS/CTS frame. Note that we set the no encryption flag
+ * since we don't want this frame to be encrypted.
+ * RTS frames should be acked, while CTS-to-self frames
+ * should not. The ready for TX flag is cleared to prevent
+ * it being automatically send when the descriptor is
+ * written to the hardware.
+ */
+ memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb));
+ rts_info = IEEE80211_SKB_CB(skb);
+ rts_info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
+ rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT;
+ rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS;
+
+ if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
+ rts_info->flags |= IEEE80211_TX_CTL_NO_ACK;
+ else
+ rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
+
+ if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
+ ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif,
+ frag_skb->data, size, tx_info,
(struct ieee80211_cts *)(skb->data));
else
- ieee80211_rts_get(rt2x00dev->hw, control->vif,
- frag_skb->data, frag_skb->len, control,
+ ieee80211_rts_get(rt2x00dev->hw, tx_info->control.vif,
+ frag_skb->data, size, tx_info,
(struct ieee80211_rts *)(skb->data));
/*
@@ -68,7 +89,7 @@
memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED;
- if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb, control)) {
+ if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb)) {
WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n");
return NETDEV_TX_BUSY;
}
@@ -76,13 +97,13 @@
return NETDEV_TX_OK;
}
-int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
+ enum data_queue_qid qid = skb_get_queue_mapping(skb);
struct data_queue *queue;
- struct skb_frame_desc *skbdesc;
u16 frame_control;
/*
@@ -100,16 +121,15 @@
/*
* Determine which queue to put packet on.
*/
- if (control->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM &&
+ if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM &&
test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags))
- queue = rt2x00queue_get_queue(rt2x00dev, RT2X00_BCN_QUEUE_ATIM);
+ queue = rt2x00queue_get_queue(rt2x00dev, QID_ATIM);
else
- queue = rt2x00queue_get_queue(rt2x00dev, control->queue);
+ queue = rt2x00queue_get_queue(rt2x00dev, qid);
if (unlikely(!queue)) {
ERROR(rt2x00dev,
"Attempt to send packet over invalid queue %d.\n"
- "Please file bug report to %s.\n",
- control->queue, DRV_PROJECT);
+ "Please file bug report to %s.\n", qid, DRV_PROJECT);
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -119,38 +139,37 @@
* create and queue that frame first. But make sure we have
* at least enough entries available to send this CTS/RTS
* frame as well as the data frame.
+ * Note that when the driver has set the set_rts_threshold()
+ * callback function it doesn't need software generation of
+ * neither RTS or CTS-to-self frames and handles everything
+ * inside the hardware.
*/
frame_control = le16_to_cpu(ieee80211hdr->frame_control);
if (!is_rts_frame(frame_control) && !is_cts_frame(frame_control) &&
- (control->flags & (IEEE80211_TXCTL_USE_RTS_CTS |
- IEEE80211_TXCTL_USE_CTS_PROTECT))) {
+ (tx_info->flags & (IEEE80211_TX_CTL_USE_RTS_CTS |
+ IEEE80211_TX_CTL_USE_CTS_PROTECT)) &&
+ !rt2x00dev->ops->hw->set_rts_threshold) {
if (rt2x00queue_available(queue) <= 1) {
- ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+ ieee80211_stop_queue(rt2x00dev->hw, qid);
return NETDEV_TX_BUSY;
}
- if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb, control)) {
- ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+ if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb)) {
+ ieee80211_stop_queue(rt2x00dev->hw, qid);
return NETDEV_TX_BUSY;
}
}
- /*
- * Initialize skb descriptor
- */
- skbdesc = get_skb_frame_desc(skb);
- memset(skbdesc, 0, sizeof(*skbdesc));
-
- if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb, control)) {
- ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+ if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, queue, skb)) {
+ ieee80211_stop_queue(rt2x00dev->hw, qid);
return NETDEV_TX_BUSY;
}
if (rt2x00queue_full(queue))
- ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+ ieee80211_stop_queue(rt2x00dev->hw, qid);
if (rt2x00dev->ops->lib->kick_tx_queue)
- rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue);
+ rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, qid);
return NETDEV_TX_OK;
}
@@ -183,8 +202,7 @@
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(conf->vif);
- struct data_queue *queue =
- rt2x00queue_get_queue(rt2x00dev, RT2X00_BCN_QUEUE_BEACON);
+ struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, QID_BEACON);
struct queue_entry *entry = NULL;
unsigned int i;
@@ -197,13 +215,12 @@
return -ENODEV;
/*
- * When we don't support mixed interfaces (a combination
- * of sta and ap virtual interfaces) then we can only
- * add this interface when the rival interface count is 0.
+ * We don't support mixed combinations of sta and ap virtual
+ * interfaces. We can only add this interface when the rival
+ * interface count is 0.
*/
- if (!test_bit(DRIVER_SUPPORT_MIXED_INTERFACES, &rt2x00dev->flags) &&
- ((conf->type == IEEE80211_IF_TYPE_AP && rt2x00dev->intf_sta_count) ||
- (conf->type != IEEE80211_IF_TYPE_AP && rt2x00dev->intf_ap_count)))
+ if ((conf->type == IEEE80211_IF_TYPE_AP && rt2x00dev->intf_sta_count) ||
+ (conf->type != IEEE80211_IF_TYPE_AP && rt2x00dev->intf_ap_count))
return -ENOBUFS;
/*
@@ -378,9 +395,7 @@
if (conf->type != IEEE80211_IF_TYPE_AP || !conf->beacon)
return 0;
- status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw,
- conf->beacon,
- conf->beacon_control);
+ status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, conf->beacon);
if (status)
dev_kfree_skb(conf->beacon);
@@ -454,10 +469,10 @@
struct rt2x00_dev *rt2x00dev = hw->priv;
unsigned int i;
- for (i = 0; i < hw->queues; i++) {
- stats->data[i].len = rt2x00dev->tx[i].length;
- stats->data[i].limit = rt2x00dev->tx[i].limit;
- stats->data[i].count = rt2x00dev->tx[i].count;
+ for (i = 0; i < rt2x00dev->ops->tx_queues; i++) {
+ stats[i].len = rt2x00dev->tx[i].length;
+ stats[i].limit = rt2x00dev->tx[i].limit;
+ stats[i].count = rt2x00dev->tx[i].count;
}
return 0;
@@ -515,7 +530,7 @@
}
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..70a3d13 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -35,42 +35,50 @@
* TX data handlers.
*/
int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
- struct data_queue *queue, struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+ struct data_queue *queue, struct sk_buff *skb)
{
struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
- struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data;
+ struct queue_entry_priv_pci *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc;
+ struct txentry_desc txdesc;
u32 word;
if (rt2x00queue_full(queue))
return -EINVAL;
- rt2x00_desc_read(priv_tx->desc, 0, &word);
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
if (rt2x00_get_field32(word, TXD_ENTRY_OWNER_NIC) ||
rt2x00_get_field32(word, TXD_ENTRY_VALID)) {
ERROR(rt2x00dev,
"Arrived at non-free entry in the non-full queue %d.\n"
"Please file bug report to %s.\n",
- control->queue, DRV_PROJECT);
+ entry->queue->qid, DRV_PROJECT);
return -EINVAL;
}
/*
+ * Copy all TX descriptor information into txdesc,
+ * after that we are free to use the skb->cb array
+ * for our information.
+ */
+ entry->skb = skb;
+ rt2x00queue_create_tx_descriptor(entry, &txdesc);
+
+ /*
* Fill in skb descriptor
*/
skbdesc = get_skb_frame_desc(skb);
+ memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->data = skb->data;
skbdesc->data_len = skb->len;
- skbdesc->desc = priv_tx->desc;
+ skbdesc->desc = entry_priv->desc;
skbdesc->desc_len = queue->desc_size;
skbdesc->entry = entry;
- memcpy(&priv_tx->control, control, sizeof(priv_tx->control));
- memcpy(priv_tx->data, skb->data, skb->len);
- rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
+ memcpy(entry_priv->data, skb->data, skb->len);
+ rt2x00queue_write_tx_descriptor(entry, &txdesc);
rt2x00queue_index_inc(queue, Q_INDEX);
return 0;
@@ -84,7 +92,7 @@
{
struct data_queue *queue = rt2x00dev->rx;
struct queue_entry *entry;
- struct queue_entry_priv_pci_rx *priv_rx;
+ struct queue_entry_priv_pci *entry_priv;
struct ieee80211_hdr *hdr;
struct skb_frame_desc *skbdesc;
struct rxdone_entry_desc rxdesc;
@@ -94,8 +102,8 @@
while (1) {
entry = rt2x00queue_get_entry(queue, Q_INDEX);
- priv_rx = entry->priv_data;
- rt2x00_desc_read(priv_rx->desc, 0, &word);
+ entry_priv = entry->priv_data;
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC))
break;
@@ -103,7 +111,7 @@
memset(&rxdesc, 0, sizeof(rxdesc));
rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
- hdr = (struct ieee80211_hdr *)priv_rx->data;
+ hdr = (struct ieee80211_hdr *)entry_priv->data;
header_size =
ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
@@ -123,7 +131,7 @@
skb_reserve(entry->skb, align);
memcpy(skb_put(entry->skb, rxdesc.size),
- priv_rx->data, rxdesc.size);
+ entry_priv->data, rxdesc.size);
/*
* Fill in skb descriptor
@@ -132,7 +140,7 @@
memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->data = entry->skb->data;
skbdesc->data_len = entry->skb->len;
- skbdesc->desc = priv_rx->desc;
+ skbdesc->desc = entry_priv->desc;
skbdesc->desc_len = queue->desc_size;
skbdesc->entry = entry;
@@ -143,7 +151,7 @@
if (test_bit(DEVICE_ENABLED_RADIO, &queue->rt2x00dev->flags)) {
rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1);
- rt2x00_desc_write(priv_rx->desc, 0, word);
+ rt2x00_desc_write(entry_priv->desc, 0, word);
}
rt2x00queue_index_inc(queue, Q_INDEX);
@@ -154,10 +162,10 @@
void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct queue_entry *entry,
struct txdone_entry_desc *txdesc)
{
- struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data;
+ struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
u32 word;
- txdesc->control = &priv_tx->control;
rt2x00lib_txdone(entry, txdesc);
/*
@@ -165,10 +173,10 @@
*/
entry->flags = 0;
- rt2x00_desc_read(priv_tx->desc, 0, &word);
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
rt2x00_set_field32(&word, TXD_ENTRY_OWNER_NIC, 0);
rt2x00_set_field32(&word, TXD_ENTRY_VALID, 0);
- rt2x00_desc_write(priv_tx->desc, 0, word);
+ rt2x00_desc_write(entry_priv->desc, 0, word);
rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
@@ -178,7 +186,7 @@
* is reenabled when the txdone handler has finished.
*/
if (!rt2x00queue_full(entry->queue))
- ieee80211_wake_queue(rt2x00dev->hw, priv_tx->control.queue);
+ ieee80211_wake_queue(rt2x00dev->hw, qid);
}
EXPORT_SYMBOL_GPL(rt2x00pci_txdone);
@@ -217,14 +225,9 @@
struct data_queue *queue)
{
struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
- struct queue_entry_priv_pci_rx *priv_rx;
- struct queue_entry_priv_pci_tx *priv_tx;
+ struct queue_entry_priv_pci *entry_priv;
void *addr;
dma_addr_t dma;
- void *desc_addr;
- dma_addr_t desc_dma;
- void *data_addr;
- dma_addr_t data_dma;
unsigned int i;
/*
@@ -240,24 +243,11 @@
* Initialize all queue entries to contain valid addresses.
*/
for (i = 0; i < queue->limit; i++) {
- desc_addr = desc_offset(queue, addr, i);
- desc_dma = desc_offset(queue, dma, i);
- data_addr = data_offset(queue, addr, i);
- data_dma = data_offset(queue, dma, i);
-
- if (queue->qid == QID_RX) {
- priv_rx = queue->entries[i].priv_data;
- priv_rx->desc = desc_addr;
- priv_rx->desc_dma = desc_dma;
- priv_rx->data = data_addr;
- priv_rx->data_dma = data_dma;
- } else {
- priv_tx = queue->entries[i].priv_data;
- priv_tx->desc = desc_addr;
- priv_tx->desc_dma = desc_dma;
- priv_tx->data = data_addr;
- priv_tx->data_dma = data_dma;
- }
+ entry_priv = queue->entries[i].priv_data;
+ entry_priv->desc = desc_offset(queue, addr, i);
+ entry_priv->desc_dma = desc_offset(queue, dma, i);
+ entry_priv->data = data_offset(queue, addr, i);
+ entry_priv->data_dma = data_offset(queue, dma, i);
}
return 0;
@@ -267,28 +257,13 @@
struct data_queue *queue)
{
struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
- struct queue_entry_priv_pci_rx *priv_rx;
- struct queue_entry_priv_pci_tx *priv_tx;
- void *data_addr;
- dma_addr_t data_dma;
+ struct queue_entry_priv_pci *entry_priv =
+ queue->entries[0].priv_data;
- if (queue->qid == QID_RX) {
- priv_rx = queue->entries[0].priv_data;
- data_addr = priv_rx->data;
- data_dma = priv_rx->data_dma;
-
- priv_rx->data = NULL;
- } else {
- priv_tx = queue->entries[0].priv_data;
- data_addr = priv_tx->data;
- data_dma = priv_tx->data_dma;
-
- priv_tx->data = NULL;
- }
-
- if (data_addr)
+ if (entry_priv->data)
pci_free_consistent(pci_dev, dma_size(queue),
- data_addr, data_dma);
+ entry_priv->data, entry_priv->data_dma);
+ entry_priv->data = NULL;
}
int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h
index 9d1cdb9..37c851e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.h
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.h
@@ -91,40 +91,22 @@
* TX data handlers.
*/
int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
- struct data_queue *queue, struct sk_buff *skb,
- struct ieee80211_tx_control *control);
+ struct data_queue *queue, struct sk_buff *skb);
/**
- * struct queue_entry_priv_pci_rx: Per RX entry PCI specific information
- *
- * @desc: Pointer to device descriptor.
- * @data: Pointer to device's entry memory.
- * @dma: DMA pointer to &data.
- */
-struct queue_entry_priv_pci_rx {
- __le32 *desc;
- dma_addr_t desc_dma;
-
- void *data;
- dma_addr_t data_dma;
-};
-
-/**
- * struct queue_entry_priv_pci_tx: Per TX entry PCI specific information
+ * struct queue_entry_priv_pci: Per entry PCI specific information
*
* @desc: Pointer to device descriptor
+ * @desc_dma: DMA pointer to &desc.
* @data: Pointer to device's entry memory.
- * @dma: DMA pointer to &data.
- * @control: mac80211 control structure used to transmit data.
+ * @data_dma: DMA pointer to &data.
*/
-struct queue_entry_priv_pci_tx {
+struct queue_entry_priv_pci {
__le32 *desc;
dma_addr_t desc_dma;
void *data;
dma_addr_t data_dma;
-
- struct ieee80211_tx_control control;
};
/**
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 659e9f4..e69ef4b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -29,20 +29,179 @@
#include "rt2x00.h"
#include "rt2x00lib.h"
+void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
+ struct txentry_desc *txdesc)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data;
+ struct ieee80211_rate *rate =
+ ieee80211_get_tx_rate(rt2x00dev->hw, tx_info);
+ const struct rt2x00_rate *hwrate;
+ unsigned int data_length;
+ unsigned int duration;
+ unsigned int residual;
+ u16 frame_control;
+
+ memset(txdesc, 0, sizeof(*txdesc));
+
+ /*
+ * Initialize information from queue
+ */
+ txdesc->queue = entry->queue->qid;
+ txdesc->cw_min = entry->queue->cw_min;
+ txdesc->cw_max = entry->queue->cw_max;
+ txdesc->aifs = entry->queue->aifs;
+
+ /* Data length should be extended with 4 bytes for CRC */
+ data_length = entry->skb->len + 4;
+
+ /*
+ * Read required fields from ieee80211 header.
+ */
+ frame_control = le16_to_cpu(hdr->frame_control);
+
+ /*
+ * Check whether this frame is to be acked.
+ */
+ if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK))
+ __set_bit(ENTRY_TXD_ACK, &txdesc->flags);
+
+ /*
+ * Check if this is a RTS/CTS frame
+ */
+ if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) {
+ __set_bit(ENTRY_TXD_BURST, &txdesc->flags);
+ if (is_rts_frame(frame_control))
+ __set_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags);
+ else
+ __set_bit(ENTRY_TXD_CTS_FRAME, &txdesc->flags);
+ if (tx_info->control.rts_cts_rate_idx >= 0)
+ rate =
+ ieee80211_get_rts_cts_rate(rt2x00dev->hw, tx_info);
+ }
+
+ /*
+ * Determine retry information.
+ */
+ txdesc->retry_limit = tx_info->control.retry_limit;
+ if (tx_info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
+ __set_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags);
+
+ /*
+ * Check if more fragments are pending
+ */
+ if (ieee80211_get_morefrag(hdr)) {
+ __set_bit(ENTRY_TXD_BURST, &txdesc->flags);
+ __set_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags);
+ }
+
+ /*
+ * Beacons and probe responses require the tsf timestamp
+ * to be inserted into the frame.
+ */
+ if (txdesc->queue == QID_BEACON || is_probe_resp(frame_control))
+ __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags);
+
+ /*
+ * Determine with what IFS priority this frame should be send.
+ * Set ifs to IFS_SIFS when the this is not the first fragment,
+ * or this fragment came after RTS/CTS.
+ */
+ if (test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)) {
+ txdesc->ifs = IFS_SIFS;
+ } else if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) {
+ __set_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags);
+ txdesc->ifs = IFS_BACKOFF;
+ } else {
+ txdesc->ifs = IFS_SIFS;
+ }
+
+ /*
+ * PLCP setup
+ * Length calculation depends on OFDM/CCK rate.
+ */
+ hwrate = rt2x00_get_rate(rate->hw_value);
+ txdesc->signal = hwrate->plcp;
+ txdesc->service = 0x04;
+
+ if (hwrate->flags & DEV_RATE_OFDM) {
+ __set_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags);
+
+ txdesc->length_high = (data_length >> 6) & 0x3f;
+ txdesc->length_low = data_length & 0x3f;
+ } else {
+ /*
+ * Convert length to microseconds.
+ */
+ residual = get_duration_res(data_length, hwrate->bitrate);
+ duration = get_duration(data_length, hwrate->bitrate);
+
+ if (residual != 0) {
+ duration++;
+
+ /*
+ * Check if we need to set the Length Extension
+ */
+ if (hwrate->bitrate == 110 && residual <= 30)
+ txdesc->service |= 0x80;
+ }
+
+ txdesc->length_high = (duration >> 8) & 0xff;
+ txdesc->length_low = duration & 0xff;
+
+ /*
+ * When preamble is enabled we should set the
+ * preamble bit for the signal.
+ */
+ if (rt2x00_get_rate_preamble(rate->hw_value))
+ txdesc->signal |= 0x08;
+ }
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_create_tx_descriptor);
+
+void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
+ struct txentry_desc *txdesc)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+
+ rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, entry->skb, txdesc);
+
+ /*
+ * All processing on the frame has been completed, this means
+ * it is now ready to be dumped to userspace through debugfs.
+ */
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, entry->skb);
+
+ /*
+ * We are done writing the frame to the queue entry,
+ * also kick the queue in case the correct flags are set,
+ * note that this will automatically filter beacons and
+ * RTS/CTS frames since those frames don't have this flag
+ * set.
+ */
+ if (rt2x00dev->ops->lib->kick_tx_queue &&
+ !(skbdesc->flags & FRAME_DESC_DRIVER_GENERATED))
+ rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev,
+ entry->queue->qid);
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_write_tx_descriptor);
+
struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
- const unsigned int queue)
+ const enum data_queue_qid queue)
{
int atim = test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
- if (queue < rt2x00dev->hw->queues && rt2x00dev->tx)
+ if (queue < rt2x00dev->ops->tx_queues && rt2x00dev->tx)
return &rt2x00dev->tx[queue];
if (!rt2x00dev->bcn)
return NULL;
- if (queue == RT2X00_BCN_QUEUE_BEACON)
+ if (queue == QID_BEACON)
return &rt2x00dev->bcn[0];
- else if (queue == RT2X00_BCN_QUEUE_ATIM && atim)
+ else if (queue == QID_ATIM && atim)
return &rt2x00dev->bcn[1];
return NULL;
@@ -255,11 +414,11 @@
/*
* We need the following queues:
* RX: 1
- * TX: hw->queues
+ * TX: ops->tx_queues
* Beacon: 1
* Atim: 1 (if required)
*/
- rt2x00dev->data_queues = 2 + rt2x00dev->hw->queues + req_atim;
+ rt2x00dev->data_queues = 2 + rt2x00dev->ops->tx_queues + req_atim;
queue = kzalloc(rt2x00dev->data_queues * sizeof(*queue), GFP_KERNEL);
if (!queue) {
@@ -272,7 +431,7 @@
*/
rt2x00dev->rx = queue;
rt2x00dev->tx = &queue[1];
- rt2x00dev->bcn = &queue[1 + rt2x00dev->hw->queues];
+ rt2x00dev->bcn = &queue[1 + rt2x00dev->ops->tx_queues];
/*
* Initialize queue parameters.
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index 7027c9f..4d00ced 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,21 +75,8 @@
QID_MGMT = 13,
QID_RX = 14,
QID_OTHER = 15,
-};
-
-/**
- * enum rt2x00_bcn_queue: Beacon queue index
- *
- * Start counting with a high offset, this because this enumeration
- * supplements &enum ieee80211_tx_queue and we should prevent value
- * conflicts.
- *
- * @RT2X00_BCN_QUEUE_BEACON: Beacon queue
- * @RT2X00_BCN_QUEUE_ATIM: Atim queue (sends frame after beacon)
- */
-enum rt2x00_bcn_queue {
- RT2X00_BCN_QUEUE_BEACON = 100,
- RT2X00_BCN_QUEUE_ATIM = 101,
+ QID_BEACON,
+ QID_ATIM,
};
/**
@@ -94,38 +92,39 @@
/**
* struct skb_frame_desc: Descriptor information for the skb buffer
*
- * This structure is placed over the skb->cb array, this means that
- * this structure should not exceed the size of that array (48 bytes).
+ * This structure is placed over the driver_data array, this means that
+ * this structure should not exceed the size of that array (40 bytes).
*
* @flags: Frame flags, see &enum skb_frame_desc_flags.
- * @frame_type: Frame type, see &enum rt2x00_dump_type.
* @data: Pointer to data part of frame (Start of ieee80211 header).
* @desc: Pointer to descriptor part of the frame.
* Note that this pointer could point to something outside
* of the scope of the skb->data pointer.
* @data_len: Length of the frame data.
* @desc_len: Length of the frame descriptor.
-
* @entry: The entry to which this sk buffer belongs.
*/
struct skb_frame_desc {
unsigned int flags;
- unsigned int frame_type;
+ unsigned short data_len;
+ unsigned short desc_len;
void *data;
void *desc;
- unsigned int data_len;
- unsigned int desc_len;
-
struct queue_entry *entry;
};
+/**
+ * get_skb_frame_desc - Obtain the rt2x00 frame descriptor from a sk_buff.
+ * @skb: &struct sk_buff from where we obtain the &struct skb_frame_desc
+ */
static inline struct skb_frame_desc* get_skb_frame_desc(struct sk_buff *skb)
{
- BUILD_BUG_ON(sizeof(struct skb_frame_desc) > sizeof(skb->cb));
- return (struct skb_frame_desc *)&skb->cb[0];
+ BUILD_BUG_ON(sizeof(struct skb_frame_desc) >
+ IEEE80211_TX_INFO_DRIVER_DATA_SIZE);
+ return (struct skb_frame_desc *)&IEEE80211_SKB_CB(skb)->driver_data;
}
/**
@@ -161,18 +160,32 @@
};
/**
+ * enum txdone_entry_desc_flags: Flags for &struct txdone_entry_desc
+ *
+ * @TXDONE_UNKNOWN: Hardware could not determine success of transmission.
+ * @TXDONE_SUCCESS: Frame was successfully send
+ * @TXDONE_FAILURE: Frame was not successfully send
+ * @TXDONE_EXCESSIVE_RETRY: In addition to &TXDONE_FAILURE, the
+ * frame transmission failed due to excessive retries.
+ */
+enum txdone_entry_desc_flags {
+ TXDONE_UNKNOWN = 1 << 0,
+ TXDONE_SUCCESS = 1 << 1,
+ TXDONE_FAILURE = 1 << 2,
+ TXDONE_EXCESSIVE_RETRY = 1 << 3,
+};
+
+/**
* struct txdone_entry_desc: TX done entry descriptor
*
* Summary of information that has been read from the TX frame descriptor
* after the device is done with transmission.
*
- * @control: Control structure which was used to transmit the frame.
- * @status: TX status (See &enum tx_status).
+ * @flags: TX done flags (See &enum txdone_entry_desc_flags).
* @retry: Retry count.
*/
struct txdone_entry_desc {
- struct ieee80211_tx_control *control;
- int status;
+ unsigned long flags;
int retry;
};
@@ -180,19 +193,25 @@
* enum txentry_desc_flags: Status flags for TX entry descriptor
*
* @ENTRY_TXD_RTS_FRAME: This frame is a RTS frame.
+ * @ENTRY_TXD_CTS_FRAME: This frame is a CTS-to-self frame.
* @ENTRY_TXD_OFDM_RATE: This frame is send out with an OFDM rate.
+ * @ENTRY_TXD_FIRST_FRAGMENT: This is the first frame.
* @ENTRY_TXD_MORE_FRAG: This frame is followed by another fragment.
* @ENTRY_TXD_REQ_TIMESTAMP: Require timestamp to be inserted.
* @ENTRY_TXD_BURST: This frame belongs to the same burst event.
* @ENTRY_TXD_ACK: An ACK is required for this frame.
+ * @ENTRY_TXD_RETRY_MODE: When set, the long retry count is used.
*/
enum txentry_desc_flags {
ENTRY_TXD_RTS_FRAME,
+ ENTRY_TXD_CTS_FRAME,
ENTRY_TXD_OFDM_RATE,
+ ENTRY_TXD_FIRST_FRAGMENT,
ENTRY_TXD_MORE_FRAG,
ENTRY_TXD_REQ_TIMESTAMP,
ENTRY_TXD_BURST,
ENTRY_TXD_ACK,
+ ENTRY_TXD_RETRY_MODE,
};
/**
@@ -206,6 +225,7 @@
* @length_low: PLCP length low word.
* @signal: PLCP signal.
* @service: PLCP service.
+ * @retry_limit: Max number of retries.
* @aifs: AIFS value.
* @ifs: IFS value.
* @cw_min: cwmin value.
@@ -221,10 +241,11 @@
u16 signal;
u16 service;
- int aifs;
- int ifs;
- int cw_min;
- int cw_max;
+ short retry_limit;
+ short aifs;
+ short ifs;
+ short cw_min;
+ short cw_max;
};
/**
@@ -240,7 +261,6 @@
* encryption or decryption. The entry should only be touched after
* the device has signaled it is done with it.
*/
-
enum queue_entry_flags {
ENTRY_BCN_ASSIGNED,
ENTRY_OWNER_DEVICE_DATA,
@@ -369,7 +389,7 @@
* the end of the TX queue array.
*/
#define tx_queue_end(__dev) \
- &(__dev)->tx[(__dev)->hw->queues]
+ &(__dev)->tx[(__dev)->ops->tx_queues]
/**
* queue_loop - Loop through the queues within a specific range (HELPER MACRO).
diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h
index 0325bed..3f255df 100644
--- a/drivers/net/wireless/rt2x00/rt2x00reg.h
+++ b/drivers/net/wireless/rt2x00/rt2x00reg.h
@@ -27,17 +27,6 @@
#define RT2X00REG_H
/*
- * TX result flags.
- */
-enum tx_status {
- TX_SUCCESS = 0,
- TX_SUCCESS_RETRY = 1,
- TX_FAIL_RETRY = 2,
- TX_FAIL_INVALID = 3,
- TX_FAIL_OTHER = 4,
-};
-
-/*
* Antenna values
*/
enum antenna {
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 5a33167..52d12fd 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -129,9 +129,9 @@
{
struct queue_entry *entry = (struct queue_entry *)urb->context;
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- struct queue_entry_priv_usb_tx *priv_tx = entry->priv_data;
struct txdone_entry_desc txdesc;
__le32 *txd = (__le32 *)entry->skb->data;
+ enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
u32 word;
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
@@ -147,10 +147,18 @@
/*
* Obtain the status about this packet.
+ * Note that when the status is 0 it does not mean the
+ * frame was send out correctly. It only means the frame
+ * was succesfully pushed to the hardware, we have no
+ * way to determine the transmission status right now.
+ * (Only indirectly by looking at the failed TX counters
+ * in the register).
*/
- txdesc.status = !urb->status ? TX_SUCCESS : TX_FAIL_RETRY;
+ if (!urb->status)
+ __set_bit(TXDONE_UNKNOWN, &txdesc.flags);
+ else
+ __set_bit(TXDONE_FAILURE, &txdesc.flags);
txdesc.retry = 0;
- txdesc.control = &priv_tx->control;
rt2x00lib_txdone(entry, &txdesc);
@@ -166,17 +174,17 @@
* is reenabled when the txdone handler has finished.
*/
if (!rt2x00queue_full(entry->queue))
- ieee80211_wake_queue(rt2x00dev->hw, priv_tx->control.queue);
+ ieee80211_wake_queue(rt2x00dev->hw, qid);
}
int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
- struct data_queue *queue, struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+ struct data_queue *queue, struct sk_buff *skb)
{
struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev);
struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
- struct queue_entry_priv_usb_tx *priv_tx = entry->priv_data;
+ struct queue_entry_priv_usb *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc;
+ struct txentry_desc txdesc;
u32 length;
if (rt2x00queue_full(queue))
@@ -186,11 +194,19 @@
ERROR(rt2x00dev,
"Arrived at non-free entry in the non-full queue %d.\n"
"Please file bug report to %s.\n",
- control->queue, DRV_PROJECT);
+ entry->queue->qid, DRV_PROJECT);
return -EINVAL;
}
/*
+ * Copy all TX descriptor information into txdesc,
+ * after that we are free to use the skb->cb array
+ * for our information.
+ */
+ entry->skb = skb;
+ rt2x00queue_create_tx_descriptor(entry, &txdesc);
+
+ /*
* Add the descriptor in front of the skb.
*/
skb_push(skb, queue->desc_size);
@@ -200,14 +216,14 @@
* Fill in skb descriptor
*/
skbdesc = get_skb_frame_desc(skb);
+ memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->data = skb->data + queue->desc_size;
skbdesc->data_len = skb->len - queue->desc_size;
skbdesc->desc = skb->data;
skbdesc->desc_len = queue->desc_size;
skbdesc->entry = entry;
- memcpy(&priv_tx->control, control, sizeof(priv_tx->control));
- rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
+ rt2x00queue_write_tx_descriptor(entry, &txdesc);
/*
* USB devices cannot blindly pass the skb->len as the
@@ -220,9 +236,9 @@
* Initialize URB and send the frame to the device.
*/
__set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
- usb_fill_bulk_urb(priv_tx->urb, usb_dev, usb_sndbulkpipe(usb_dev, 1),
+ usb_fill_bulk_urb(entry_priv->urb, usb_dev, usb_sndbulkpipe(usb_dev, 1),
skb->data, length, rt2x00usb_interrupt_txdone, entry);
- usb_submit_urb(priv_tx->urb, GFP_ATOMIC);
+ usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
rt2x00queue_index_inc(queue, Q_INDEX);
@@ -237,22 +253,35 @@
{
struct sk_buff *skb;
unsigned int frame_size;
+ unsigned int reserved_size;
/*
- * As alignment we use 2 and not NET_IP_ALIGN because we need
- * to be sure we have 2 bytes room in the head. (NET_IP_ALIGN
- * can be 0 on some hardware). We use these 2 bytes for frame
- * alignment later, we assume that the chance that
- * header_size % 4 == 2 is bigger then header_size % 2 == 0
- * and thus optimize alignment by reserving the 2 bytes in
- * advance.
+ * The frame size includes descriptor size, because the
+ * hardware directly receive the frame into the skbuffer.
*/
frame_size = queue->data_size + queue->desc_size;
- skb = dev_alloc_skb(queue->desc_size + frame_size + 2);
+
+ /*
+ * For the allocation we should keep a few things in mind:
+ * 1) 4byte alignment of 802.11 payload
+ *
+ * For (1) we need at most 4 bytes to guarentee the correct
+ * alignment. We are going to optimize the fact that the chance
+ * that the 802.11 header_size % 4 == 2 is much bigger then
+ * anything else. However since we need to move the frame up
+ * to 3 bytes to the front, which means we need to preallocate
+ * 6 bytes.
+ */
+ reserved_size = 6;
+
+ /*
+ * Allocate skbuffer.
+ */
+ skb = dev_alloc_skb(frame_size + reserved_size);
if (!skb)
return NULL;
- skb_reserve(skb, queue->desc_size + 2);
+ skb_reserve(skb, reserved_size);
skb_put(skb, frame_size);
return skb;
@@ -265,7 +294,8 @@
struct sk_buff *skb;
struct skb_frame_desc *skbdesc;
struct rxdone_entry_desc rxdesc;
- int header_size;
+ unsigned int header_size;
+ unsigned int align;
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
@@ -289,19 +319,29 @@
memset(&rxdesc, 0, sizeof(rxdesc));
rt2x00dev->ops->lib->fill_rxdone(entry, &rxdesc);
+ header_size = ieee80211_get_hdrlen_from_skb(entry->skb);
+
/*
* The data behind the ieee80211 header must be
- * aligned on a 4 byte boundary.
+ * aligned on a 4 byte boundary. We already reserved
+ * 2 bytes for header_size % 4 == 2 optimization.
+ * To determine the number of bytes which the data
+ * should be moved to the left, we must add these
+ * 2 bytes to the header_size.
*/
- header_size = ieee80211_get_hdrlen_from_skb(entry->skb);
- if (header_size % 4 == 0) {
- skb_push(entry->skb, 2);
- memmove(entry->skb->data, entry->skb->data + 2,
- entry->skb->len - 2);
- skbdesc->data = entry->skb->data;
- skb_trim(entry->skb,entry->skb->len - 2);
+ align = (header_size + 2) % 4;
+
+ if (align) {
+ skb_push(entry->skb, align);
+ /* Move entire frame in 1 command */
+ memmove(entry->skb->data, entry->skb->data + align,
+ rxdesc.size);
}
+ /* Update data pointers, trim buffer to correct size */
+ skbdesc->data = entry->skb->data;
+ skb_trim(entry->skb, rxdesc.size);
+
/*
* Allocate a new sk buffer to replace the current one.
* If allocation fails, we should drop the current frame
@@ -338,44 +378,28 @@
*/
void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
{
- struct queue_entry_priv_usb_rx *priv_rx;
- struct queue_entry_priv_usb_tx *priv_tx;
- struct queue_entry_priv_usb_bcn *priv_bcn;
- struct data_queue *queue;
+ struct queue_entry_priv_usb *entry_priv;
+ struct queue_entry_priv_usb_bcn *bcn_priv;
unsigned int i;
- rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0x0000, 0x0000,
+ rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0, 0,
REGISTER_TIMEOUT);
/*
* Cancel all queues.
*/
for (i = 0; i < rt2x00dev->rx->limit; i++) {
- priv_rx = rt2x00dev->rx->entries[i].priv_data;
- usb_kill_urb(priv_rx->urb);
+ entry_priv = rt2x00dev->rx->entries[i].priv_data;
+ usb_kill_urb(entry_priv->urb);
}
- tx_queue_for_each(rt2x00dev, queue) {
- for (i = 0; i < queue->limit; i++) {
- priv_tx = queue->entries[i].priv_data;
- usb_kill_urb(priv_tx->urb);
- }
- }
-
+ /*
+ * Kill guardian urb.
+ */
for (i = 0; i < rt2x00dev->bcn->limit; i++) {
- priv_bcn = rt2x00dev->bcn->entries[i].priv_data;
- usb_kill_urb(priv_bcn->urb);
-
- if (priv_bcn->guardian_urb)
- usb_kill_urb(priv_bcn->guardian_urb);
- }
-
- if (!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags))
- return;
-
- for (i = 0; i < rt2x00dev->bcn[1].limit; i++) {
- priv_tx = rt2x00dev->bcn[1].entries[i].priv_data;
- usb_kill_urb(priv_tx->urb);
+ bcn_priv = rt2x00dev->bcn->entries[i].priv_data;
+ if (bcn_priv->guardian_urb)
+ usb_kill_urb(bcn_priv->guardian_urb);
}
}
EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
@@ -387,15 +411,15 @@
struct queue_entry *entry)
{
struct usb_device *usb_dev = rt2x00dev_usb_dev(rt2x00dev);
- struct queue_entry_priv_usb_rx *priv_rx = entry->priv_data;
+ struct queue_entry_priv_usb *entry_priv = entry->priv_data;
- usb_fill_bulk_urb(priv_rx->urb, usb_dev,
+ usb_fill_bulk_urb(entry_priv->urb, usb_dev,
usb_rcvbulkpipe(usb_dev, 1),
entry->skb->data, entry->skb->len,
rt2x00usb_interrupt_rxdone, entry);
__set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
- usb_submit_urb(priv_rx->urb, GFP_ATOMIC);
+ usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
}
EXPORT_SYMBOL_GPL(rt2x00usb_init_rxentry);
@@ -409,38 +433,31 @@
static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue)
{
- struct queue_entry_priv_usb_rx *priv_rx;
- struct queue_entry_priv_usb_tx *priv_tx;
- struct queue_entry_priv_usb_bcn *priv_bcn;
- struct urb *urb;
- unsigned int guardian =
- test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags);
+ struct queue_entry_priv_usb *entry_priv;
+ struct queue_entry_priv_usb_bcn *bcn_priv;
unsigned int i;
- /*
- * Allocate the URB's
- */
for (i = 0; i < queue->limit; i++) {
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb)
+ entry_priv = queue->entries[i].priv_data;
+ entry_priv->urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!entry_priv->urb)
return -ENOMEM;
+ }
- if (queue->qid == QID_RX) {
- priv_rx = queue->entries[i].priv_data;
- priv_rx->urb = urb;
- } else if (queue->qid == QID_MGMT && guardian) {
- priv_bcn = queue->entries[i].priv_data;
- priv_bcn->urb = urb;
+ /*
+ * If this is not the beacon queue or
+ * no guardian byte was required for the beacon,
+ * then we are done.
+ */
+ if (rt2x00dev->bcn != queue ||
+ !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))
+ return 0;
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb)
- return -ENOMEM;
-
- priv_bcn->guardian_urb = urb;
- } else {
- priv_tx = queue->entries[i].priv_data;
- priv_tx->urb = urb;
- }
+ for (i = 0; i < queue->limit; i++) {
+ bcn_priv = queue->entries[i].priv_data;
+ bcn_priv->guardian_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!bcn_priv->guardian_urb)
+ return -ENOMEM;
}
return 0;
@@ -449,38 +466,35 @@
static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue)
{
- struct queue_entry_priv_usb_rx *priv_rx;
- struct queue_entry_priv_usb_tx *priv_tx;
- struct queue_entry_priv_usb_bcn *priv_bcn;
- struct urb *urb;
- unsigned int guardian =
- test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags);
+ struct queue_entry_priv_usb *entry_priv;
+ struct queue_entry_priv_usb_bcn *bcn_priv;
unsigned int i;
if (!queue->entries)
return;
for (i = 0; i < queue->limit; i++) {
- if (queue->qid == QID_RX) {
- priv_rx = queue->entries[i].priv_data;
- urb = priv_rx->urb;
- } else if (queue->qid == QID_MGMT && guardian) {
- priv_bcn = queue->entries[i].priv_data;
-
- usb_kill_urb(priv_bcn->guardian_urb);
- usb_free_urb(priv_bcn->guardian_urb);
-
- urb = priv_bcn->urb;
- } else {
- priv_tx = queue->entries[i].priv_data;
- urb = priv_tx->urb;
- }
-
- usb_kill_urb(urb);
- usb_free_urb(urb);
+ entry_priv = queue->entries[i].priv_data;
+ usb_kill_urb(entry_priv->urb);
+ usb_free_urb(entry_priv->urb);
if (queue->entries[i].skb)
kfree_skb(queue->entries[i].skb);
}
+
+ /*
+ * If this is not the beacon queue or
+ * no guardian byte was required for the beacon,
+ * then we are done.
+ */
+ if (rt2x00dev->bcn != queue ||
+ !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))
+ return;
+
+ for (i = 0; i < queue->limit; i++) {
+ bcn_priv = queue->entries[i].priv_data;
+ usb_kill_urb(bcn_priv->guardian_urb);
+ usb_free_urb(bcn_priv->guardian_urb);
+ }
}
int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h
index 11e5518..26f53f8 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));
}
/*
@@ -203,47 +216,31 @@
* TX data handlers.
*/
int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
- struct data_queue *queue, struct sk_buff *skb,
- struct ieee80211_tx_control *control);
+ struct data_queue *queue, struct sk_buff *skb);
/**
- * struct queue_entry_priv_usb_rx: Per RX entry USB specific information
+ * struct queue_entry_priv_usb: Per entry USB specific information
*
* @urb: Urb structure used for device communication.
*/
-struct queue_entry_priv_usb_rx {
+struct queue_entry_priv_usb {
struct urb *urb;
};
/**
- * struct queue_entry_priv_usb_tx: Per TX entry USB specific information
+ * struct queue_entry_priv_usb_bcn: Per TX entry USB specific information
*
- * @urb: Urb structure used for device communication.
- * @control: mac80211 control structure used to transmit data.
- */
-struct queue_entry_priv_usb_tx {
- struct urb *urb;
-
- struct ieee80211_tx_control control;
-};
-
-/**
- * struct queue_entry_priv_usb_tx: Per TX entry USB specific information
- *
- * The first section should match &struct queue_entry_priv_usb_tx exactly.
+ * The first section should match &struct queue_entry_priv_usb exactly.
* rt2500usb can use this structure to send a guardian byte when working
* with beacons.
*
* @urb: Urb structure used for device communication.
- * @control: mac80211 control structure used to transmit data.
* @guardian_data: Set to 0, used for sending the guardian data.
* @guardian_urb: Urb structure used to send the guardian data.
*/
struct queue_entry_priv_usb_bcn {
struct urb *urb;
- struct ieee80211_tx_control control;
-
unsigned int guardian_data;
struct urb *guardian_urb;
};
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 14bc7b2..e13ed5c 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1018,49 +1018,34 @@
static void rt61pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry)
{
- struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data;
+ struct queue_entry_priv_pci *entry_priv = entry->priv_data;
u32 word;
- rt2x00_desc_read(priv_rx->desc, 5, &word);
+ rt2x00_desc_read(entry_priv->desc, 5, &word);
rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS,
- priv_rx->data_dma);
- rt2x00_desc_write(priv_rx->desc, 5, word);
+ entry_priv->data_dma);
+ rt2x00_desc_write(entry_priv->desc, 5, word);
- rt2x00_desc_read(priv_rx->desc, 0, &word);
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
- rt2x00_desc_write(priv_rx->desc, 0, word);
+ rt2x00_desc_write(entry_priv->desc, 0, word);
}
static void rt61pci_init_txentry(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry)
{
- struct queue_entry_priv_pci_tx *priv_tx = entry->priv_data;
+ struct queue_entry_priv_pci *entry_priv = entry->priv_data;
u32 word;
- rt2x00_desc_read(priv_tx->desc, 1, &word);
- rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1);
- rt2x00_desc_write(priv_tx->desc, 1, word);
-
- rt2x00_desc_read(priv_tx->desc, 5, &word);
- rt2x00_set_field32(&word, TXD_W5_PID_TYPE, entry->queue->qid);
- rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, entry->entry_idx);
- rt2x00_desc_write(priv_tx->desc, 5, word);
-
- rt2x00_desc_read(priv_tx->desc, 6, &word);
- rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
- priv_tx->data_dma);
- rt2x00_desc_write(priv_tx->desc, 6, word);
-
- rt2x00_desc_read(priv_tx->desc, 0, &word);
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
rt2x00_set_field32(&word, TXD_W0_VALID, 0);
rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
- rt2x00_desc_write(priv_tx->desc, 0, word);
+ rt2x00_desc_write(entry_priv->desc, 0, word);
}
static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev)
{
- struct queue_entry_priv_pci_rx *priv_rx;
- struct queue_entry_priv_pci_tx *priv_tx;
+ struct queue_entry_priv_pci *entry_priv;
u32 reg;
/*
@@ -1082,28 +1067,28 @@
rt2x00dev->tx[0].desc_size / 4);
rt2x00pci_register_write(rt2x00dev, TX_RING_CSR1, reg);
- priv_tx = rt2x00dev->tx[0].entries[0].priv_data;
+ entry_priv = rt2x00dev->tx[0].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, AC0_BASE_CSR, ®);
rt2x00_set_field32(®, AC0_BASE_CSR_RING_REGISTER,
- priv_tx->desc_dma);
+ entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, AC0_BASE_CSR, reg);
- priv_tx = rt2x00dev->tx[1].entries[0].priv_data;
+ entry_priv = rt2x00dev->tx[1].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, AC1_BASE_CSR, ®);
rt2x00_set_field32(®, AC1_BASE_CSR_RING_REGISTER,
- priv_tx->desc_dma);
+ entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, AC1_BASE_CSR, reg);
- priv_tx = rt2x00dev->tx[2].entries[0].priv_data;
+ entry_priv = rt2x00dev->tx[2].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, AC2_BASE_CSR, ®);
rt2x00_set_field32(®, AC2_BASE_CSR_RING_REGISTER,
- priv_tx->desc_dma);
+ entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, AC2_BASE_CSR, reg);
- priv_tx = rt2x00dev->tx[3].entries[0].priv_data;
+ entry_priv = rt2x00dev->tx[3].entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, AC3_BASE_CSR, ®);
rt2x00_set_field32(®, AC3_BASE_CSR_RING_REGISTER,
- priv_tx->desc_dma);
+ entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, AC3_BASE_CSR, reg);
rt2x00pci_register_read(rt2x00dev, RX_RING_CSR, ®);
@@ -1113,10 +1098,10 @@
rt2x00_set_field32(®, RX_RING_CSR_RXD_WRITEBACK_SIZE, 4);
rt2x00pci_register_write(rt2x00dev, RX_RING_CSR, reg);
- priv_rx = rt2x00dev->rx->entries[0].priv_data;
+ entry_priv = rt2x00dev->rx->entries[0].priv_data;
rt2x00pci_register_read(rt2x00dev, RX_BASE_CSR, ®);
rt2x00_set_field32(®, RX_BASE_CSR_RING_REGISTER,
- priv_rx->desc_dma);
+ entry_priv->desc_dma);
rt2x00pci_register_write(rt2x00dev, RX_BASE_CSR, reg);
rt2x00pci_register_read(rt2x00dev, TX_DMA_DST_CSR, ®);
@@ -1526,10 +1511,10 @@
*/
static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
- struct txentry_desc *txdesc,
- struct ieee80211_tx_control *control)
+ struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
+ struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
__le32 *txd = skbdesc->desc;
u32 word;
@@ -1543,6 +1528,7 @@
rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1);
+ rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1);
rt2x00_desc_write(txd, 1, word);
rt2x00_desc_read(txd, 2, &word);
@@ -1553,11 +1539,19 @@
rt2x00_desc_write(txd, 2, word);
rt2x00_desc_read(txd, 5, &word);
+ rt2x00_set_field32(&word, TXD_W5_PID_TYPE, skbdesc->entry->queue->qid);
+ rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE,
+ skbdesc->entry->entry_idx);
rt2x00_set_field32(&word, TXD_W5_TX_POWER,
TXPOWER_TO_DEV(rt2x00dev->tx_power));
rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
rt2x00_desc_write(txd, 5, word);
+ rt2x00_desc_read(txd, 6, &word);
+ rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
+ entry_priv->data_dma);
+ rt2x00_desc_write(txd, 6, word);
+
if (skbdesc->desc_len > TXINFO_SIZE) {
rt2x00_desc_read(txd, 11, &word);
rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, skbdesc->data_len);
@@ -1577,8 +1571,7 @@
test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
- !!(control->flags &
- IEEE80211_TXCTL_LONG_RETRY_LIMIT));
+ test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0);
rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len);
rt2x00_set_field32(&word, TXD_W0_BURST,
@@ -1591,11 +1584,11 @@
* TX data initialization
*/
static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
- const unsigned int queue)
+ const enum data_queue_qid queue)
{
u32 reg;
- if (queue == RT2X00_BCN_QUEUE_BEACON) {
+ if (queue == QID_BEACON) {
/*
* For Wi-Fi faily generated beacons between participating
* stations. Set TBTT phase adaptive adjustment step to 8us.
@@ -1613,14 +1606,10 @@
}
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);
}
@@ -1671,14 +1660,13 @@
static void rt61pci_fill_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc)
{
- struct queue_entry_priv_pci_rx *priv_rx = entry->priv_data;
+ struct queue_entry_priv_pci *entry_priv = entry->priv_data;
u32 word0;
u32 word1;
- rt2x00_desc_read(priv_rx->desc, 0, &word0);
- rt2x00_desc_read(priv_rx->desc, 1, &word1);
+ rt2x00_desc_read(entry_priv->desc, 0, &word0);
+ rt2x00_desc_read(entry_priv->desc, 1, &word1);
- rxdesc->flags = 0;
if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
@@ -1692,7 +1680,6 @@
rxdesc->rssi = rt61pci_agc_to_rssi(entry->queue->rt2x00dev, word1);
rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
- rxdesc->dev_flags = 0;
if (rt2x00_get_field32(word0, RXD_W0_OFDM))
rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP;
if (rt2x00_get_field32(word0, RXD_W0_MY_BSS))
@@ -1707,7 +1694,7 @@
struct data_queue *queue;
struct queue_entry *entry;
struct queue_entry *entry_done;
- struct queue_entry_priv_pci_tx *priv_tx;
+ struct queue_entry_priv_pci *entry_priv;
struct txdone_entry_desc txdesc;
u32 word;
u32 reg;
@@ -1752,8 +1739,8 @@
continue;
entry = &queue->entries[index];
- priv_tx = entry->priv_data;
- rt2x00_desc_read(priv_tx->desc, 0, &word);
+ entry_priv = entry->priv_data;
+ rt2x00_desc_read(entry_priv->desc, 0, &word);
if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
!rt2x00_get_field32(word, TXD_W0_VALID))
@@ -1768,7 +1755,8 @@
"TX status report missed for entry %d\n",
entry_done->entry_idx);
- txdesc.status = TX_FAIL_OTHER;
+ txdesc.flags = 0;
+ __set_bit(TXDONE_UNKNOWN, &txdesc.flags);
txdesc.retry = 0;
rt2x00pci_txdone(rt2x00dev, entry_done, &txdesc);
@@ -1778,7 +1766,17 @@
/*
* Obtain the status about this packet.
*/
- txdesc.status = rt2x00_get_field32(reg, STA_CSR4_TX_RESULT);
+ txdesc.flags = 0;
+ switch (rt2x00_get_field32(reg, STA_CSR4_TX_RESULT)) {
+ case 0: /* Success, maybe with retry */
+ __set_bit(TXDONE_SUCCESS, &txdesc.flags);
+ break;
+ case 6: /* Failure, excessive retries */
+ __set_bit(TXDONE_EXCESSIVE_RETRY, &txdesc.flags);
+ /* Don't break, this is a failed frame! */
+ default: /* Failure */
+ __set_bit(TXDONE_FAILURE, &txdesc.flags);
+ }
txdesc.retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT);
rt2x00pci_txdone(rt2x00dev, entry, &txdesc);
@@ -2249,11 +2247,9 @@
*/
rt2x00dev->hw->flags =
IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+ IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+ IEEE80211_HW_SIGNAL_DBM;
rt2x00dev->hw->extra_tx_headroom = 0;
- rt2x00dev->hw->max_signal = MAX_SIGNAL;
- rt2x00dev->hw->max_rssi = MAX_RX_SSI;
- rt2x00dev->hw->queues = 4;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
@@ -2361,21 +2357,30 @@
return tsf;
}
-static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
- struct rt2x00_intf *intf = vif_to_intf(control->vif);
- struct queue_entry_priv_pci_tx *priv_tx;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
+ struct queue_entry_priv_pci *entry_priv;
struct skb_frame_desc *skbdesc;
+ struct txentry_desc txdesc;
unsigned int beacon_base;
u32 reg;
if (unlikely(!intf->beacon))
return -ENOBUFS;
- priv_tx = intf->beacon->priv_data;
- memset(priv_tx->desc, 0, intf->beacon->queue->desc_size);
+ /*
+ * Copy all TX descriptor information into txdesc,
+ * after that we are free to use the skb->cb array
+ * for our information.
+ */
+ intf->beacon->skb = skb;
+ rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
+
+ entry_priv = intf->beacon->priv_data;
+ memset(entry_priv->desc, 0, intf->beacon->queue->desc_size);
/*
* Fill in skb descriptor
@@ -2385,7 +2390,7 @@
skbdesc->flags |= FRAME_DESC_DRIVER_GENERATED;
skbdesc->data = skb->data;
skbdesc->data_len = skb->len;
- skbdesc->desc = priv_tx->desc;
+ skbdesc->desc = entry_priv->desc;
skbdesc->desc_len = intf->beacon->queue->desc_size;
skbdesc->entry = intf->beacon;
@@ -2400,24 +2405,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.
*/
+ rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
rt2x00pci_register_multiwrite(rt2x00dev, beacon_base,
skbdesc->desc, skbdesc->desc_len);
rt2x00pci_register_multiwrite(rt2x00dev,
beacon_base + skbdesc->desc_len,
skbdesc->data, skbdesc->data_len);
- rt61pci_kick_tx_queue(rt2x00dev, control->queue);
+ rt61pci_kick_tx_queue(rt2x00dev, QID_BEACON);
return 0;
}
@@ -2469,21 +2467,21 @@
.entry_num = RX_ENTRIES,
.data_size = DATA_FRAME_SIZE,
.desc_size = RXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci_rx),
+ .priv_size = sizeof(struct queue_entry_priv_pci),
};
static const struct data_queue_desc rt61pci_queue_tx = {
.entry_num = TX_ENTRIES,
.data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci_tx),
+ .priv_size = sizeof(struct queue_entry_priv_pci),
};
static const struct data_queue_desc rt61pci_queue_bcn = {
.entry_num = 4 * BEACON_ENTRIES,
.data_size = 0, /* No DMA required for beacons */
.desc_size = TXINFO_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci_tx),
+ .priv_size = sizeof(struct queue_entry_priv_pci),
};
static const struct rt2x00_ops rt61pci_ops = {
@@ -2492,6 +2490,7 @@
.max_ap_intf = 4,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
+ .tx_queues = NUM_TX_QUEUES,
.rx = &rt61pci_queue_rx,
.tx = &rt61pci_queue_tx,
.bcn = &rt61pci_queue_bcn,
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
index 3511bba7..c5a04b9 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -54,6 +54,11 @@
#define RF_SIZE 0x0014
/*
+ * Number of TX queues.
+ */
+#define NUM_TX_QUEUES 4
+
+/*
* PCI registers.
*/
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index da19a3a..26c2e0a 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;
}
@@ -1256,8 +1255,7 @@
*/
static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb,
- struct txentry_desc *txdesc,
- struct ieee80211_tx_control *control)
+ struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
__le32 *txd = skbdesc->desc;
@@ -1302,8 +1300,7 @@
test_bit(ENTRY_TXD_OFDM_RATE, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
- !!(control->flags &
- IEEE80211_TXCTL_LONG_RETRY_LIMIT));
+ test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0);
rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len);
rt2x00_set_field32(&word, TXD_W0_BURST2,
@@ -1331,11 +1328,11 @@
* TX data initialization
*/
static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
- const unsigned int queue)
+ const enum data_queue_qid queue)
{
u32 reg;
- if (queue != RT2X00_BCN_QUEUE_BEACON)
+ if (queue != QID_BEACON)
return;
/*
@@ -1406,25 +1403,26 @@
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
__le32 *rxd = (__le32 *)entry->skb->data;
- unsigned int offset = entry->queue->desc_size + 2;
u32 word0;
u32 word1;
/*
- * Copy descriptor to the available headroom inside the skbuffer.
+ * Copy descriptor to the skb->cb array, this has 2 benefits:
+ * 1) Each descriptor word is 4 byte aligned.
+ * 2) Descriptor is safe from moving of frame data in rt2x00usb.
*/
- skb_push(entry->skb, offset);
- memcpy(entry->skb->data, rxd, entry->queue->desc_size);
- rxd = (__le32 *)entry->skb->data;
+ skbdesc->desc_len =
+ min_t(u16, entry->queue->desc_size, sizeof(entry->skb->cb));
+ memcpy(entry->skb->cb, rxd, skbdesc->desc_len);
+ skbdesc->desc = entry->skb->cb;
+ rxd = (__le32 *)skbdesc->desc;
/*
- * The descriptor is now aligned to 4 bytes and thus it is
- * now safe to read it on all architectures.
+ * It is now safe to read the descriptor on all architectures.
*/
rt2x00_desc_read(rxd, 0, &word0);
rt2x00_desc_read(rxd, 1, &word1);
- rxdesc->flags = 0;
if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
@@ -1438,25 +1436,18 @@
rxdesc->rssi = rt73usb_agc_to_rssi(entry->queue->rt2x00dev, word1);
rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
- rxdesc->dev_flags = 0;
if (rt2x00_get_field32(word0, RXD_W0_OFDM))
rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP;
if (rt2x00_get_field32(word0, RXD_W0_MY_BSS))
rxdesc->dev_flags |= RXDONE_MY_BSS;
/*
- * Adjust the skb memory window to the frame boundaries.
+ * Set skb pointers, and update frame information.
*/
- skb_pull(entry->skb, offset + entry->queue->desc_size);
+ skb_pull(entry->skb, entry->queue->desc_size);
skb_trim(entry->skb, rxdesc->size);
-
- /*
- * Set descriptor and data pointer.
- */
skbdesc->data = entry->skb->data;
skbdesc->data_len = rxdesc->size;
- skbdesc->desc = rxd;
- skbdesc->desc_len = entry->queue->desc_size;
}
/*
@@ -1831,11 +1822,9 @@
*/
rt2x00dev->hw->flags =
IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+ IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+ IEEE80211_HW_SIGNAL_DBM;
rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
- rt2x00dev->hw->max_signal = MAX_SIGNAL;
- rt2x00dev->hw->max_rssi = MAX_RX_SSI;
- rt2x00dev->hw->queues = 4;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);
SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
@@ -1959,20 +1948,28 @@
#define rt73usb_get_tsf NULL
#endif
-static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
- struct rt2x00_intf *intf = vif_to_intf(control->vif);
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
struct skb_frame_desc *skbdesc;
+ struct txentry_desc txdesc;
unsigned int beacon_base;
- unsigned int timeout;
u32 reg;
if (unlikely(!intf->beacon))
return -ENOBUFS;
/*
+ * Copy all TX descriptor information into txdesc,
+ * after that we are free to use the skb->cb array
+ * for our information.
+ */
+ intf->beacon->skb = skb;
+ rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
+
+ /*
* Add the descriptor in front of the skb.
*/
skb_push(skb, intf->beacon->queue->desc_size);
@@ -2001,23 +1998,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.
*/
+ rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
- timeout = REGISTER_TIMEOUT * (skb->len / sizeof(u32));
rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE,
USB_VENDOR_REQUEST_OUT, beacon_base, 0,
- skb->data, skb->len, timeout);
- rt73usb_kick_tx_queue(rt2x00dev, control->queue);
+ skb->data, skb->len,
+ REGISTER_TIMEOUT32(skb->len));
+ rt73usb_kick_tx_queue(rt2x00dev, QID_BEACON);
return 0;
}
@@ -2068,21 +2058,21 @@
.entry_num = RX_ENTRIES,
.data_size = DATA_FRAME_SIZE,
.desc_size = RXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_usb_rx),
+ .priv_size = sizeof(struct queue_entry_priv_usb),
};
static const struct data_queue_desc rt73usb_queue_tx = {
.entry_num = TX_ENTRIES,
.data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_usb_tx),
+ .priv_size = sizeof(struct queue_entry_priv_usb),
};
static const struct data_queue_desc rt73usb_queue_bcn = {
.entry_num = 4 * BEACON_ENTRIES,
.data_size = MGMT_FRAME_SIZE,
.desc_size = TXINFO_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_usb_tx),
+ .priv_size = sizeof(struct queue_entry_priv_usb),
};
static const struct rt2x00_ops rt73usb_ops = {
@@ -2091,6 +2081,7 @@
.max_ap_intf = 4,
.eeprom_size = EEPROM_SIZE,
.rf_size = RF_SIZE,
+ .tx_queues = NUM_TX_QUEUES,
.rx = &rt73usb_queue_rx,
.tx = &rt73usb_queue_tx,
.bcn = &rt73usb_queue_bcn,
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
index 06d6874..25cdcc9 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.h
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -54,6 +54,11 @@
#define RF_SIZE 0x0014
/*
+ * Number of TX queues.
+ */
+#define NUM_TX_QUEUES 4
+
+/*
* USB registers.
*/
diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c
index c181f23..b7172a1 100644
--- a/drivers/net/wireless/rtl8180_dev.c
+++ b/drivers/net/wireless/rtl8180_dev.c
@@ -132,8 +132,8 @@
rx_status.antenna = (flags2 >> 15) & 1;
/* TODO: improve signal/rssi reporting */
- rx_status.signal = flags2 & 0xFF;
- rx_status.ssi = (flags2 >> 8) & 0x7F;
+ rx_status.qual = flags2 & 0xFF;
+ rx_status.signal = (flags2 >> 8) & 0x7F;
/* XXX: is this correct? */
rx_status.rate_idx = (flags >> 20) & 0xF;
rx_status.freq = dev->conf.channel->center_freq;
@@ -170,34 +170,29 @@
while (skb_queue_len(&ring->queue)) {
struct rtl8180_tx_desc *entry = &ring->desc[ring->idx];
struct sk_buff *skb;
- struct ieee80211_tx_status status;
- struct ieee80211_tx_control *control;
+ struct ieee80211_tx_info *info;
u32 flags = le32_to_cpu(entry->flags);
if (flags & RTL8180_TX_DESC_FLAG_OWN)
return;
- memset(&status, 0, sizeof(status));
-
ring->idx = (ring->idx + 1) % ring->entries;
skb = __skb_dequeue(&ring->queue);
pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf),
skb->len, PCI_DMA_TODEVICE);
- control = *((struct ieee80211_tx_control **)skb->cb);
- if (control)
- memcpy(&status.control, control, sizeof(*control));
- kfree(control);
+ info = IEEE80211_SKB_CB(skb);
+ memset(&info->status, 0, sizeof(info->status));
- if (!(status.control.flags & IEEE80211_TXCTL_NO_ACK)) {
+ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
if (flags & RTL8180_TX_DESC_FLAG_TX_OK)
- status.flags = IEEE80211_TX_STATUS_ACK;
+ info->flags |= IEEE80211_TX_STAT_ACK;
else
- status.excessive_retries = 1;
+ info->status.excessive_retries = 1;
}
- status.retry_count = flags & 0xFF;
+ info->status.retry_count = flags & 0xFF;
- ieee80211_tx_status_irqsafe(dev, skb, &status);
+ ieee80211_tx_status_irqsafe(dev, skb);
if (ring->entries - skb_queue_len(&ring->queue) == 2)
ieee80211_wake_queue(dev, prio);
}
@@ -238,9 +233,9 @@
return IRQ_HANDLED;
}
-static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct rtl8180_priv *priv = dev->priv;
struct rtl8180_tx_ring *ring;
struct rtl8180_tx_desc *entry;
@@ -251,46 +246,40 @@
u16 plcp_len = 0;
__le16 rts_duration = 0;
- prio = control->queue;
+ prio = skb_get_queue_mapping(skb);
ring = &priv->tx_ring[prio];
mapping = pci_map_single(priv->pdev, skb->data,
skb->len, PCI_DMA_TODEVICE);
- BUG_ON(!control->tx_rate);
-
tx_flags = RTL8180_TX_DESC_FLAG_OWN | RTL8180_TX_DESC_FLAG_FS |
RTL8180_TX_DESC_FLAG_LS |
- (control->tx_rate->hw_value << 24) | skb->len;
+ (ieee80211_get_tx_rate(dev, info)->hw_value << 24) |
+ skb->len;
if (priv->r8185)
tx_flags |= RTL8180_TX_DESC_FLAG_DMA |
RTL8180_TX_DESC_FLAG_NO_ENC;
- if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
- BUG_ON(!control->rts_cts_rate);
+ if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
tx_flags |= RTL8180_TX_DESC_FLAG_RTS;
- tx_flags |= control->rts_cts_rate->hw_value << 19;
- } else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
- BUG_ON(!control->rts_cts_rate);
+ tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
+ } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
tx_flags |= RTL8180_TX_DESC_FLAG_CTS;
- tx_flags |= control->rts_cts_rate->hw_value << 19;
+ tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
}
- *((struct ieee80211_tx_control **) skb->cb) =
- kmemdup(control, sizeof(*control), GFP_ATOMIC);
-
- if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
+ if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len,
- control);
+ info);
if (!priv->r8185) {
unsigned int remainder;
plcp_len = DIV_ROUND_UP(16 * (skb->len + 4),
- (control->tx_rate->bitrate * 2) / 10);
+ (ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10);
remainder = (16 * (skb->len + 4)) %
- ((control->tx_rate->bitrate * 2) / 10);
+ ((ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10);
if (remainder > 0 && remainder <= 6)
plcp_len |= 1 << 15;
}
@@ -303,13 +292,13 @@
entry->plcp_len = cpu_to_le16(plcp_len);
entry->tx_buf = cpu_to_le32(mapping);
entry->frame_len = cpu_to_le32(skb->len);
- entry->flags2 = control->alt_retry_rate != NULL ?
- control->alt_retry_rate->bitrate << 4 : 0;
- entry->retry_limit = control->retry_limit;
+ entry->flags2 = info->control.alt_retry_rate_idx >= 0 ?
+ ieee80211_get_alt_retry_rate(dev, info)->bitrate << 4 : 0;
+ entry->retry_limit = info->control.retry_limit;
entry->flags = cpu_to_le32(tx_flags);
__skb_queue_tail(&ring->queue, skb);
if (ring->entries - skb_queue_len(&ring->queue) < 2)
- ieee80211_stop_queue(dev, control->queue);
+ ieee80211_stop_queue(dev, skb_get_queue_mapping(skb));
spin_unlock_irqrestore(&priv->lock, flags);
rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4)));
@@ -525,7 +514,6 @@
pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf),
skb->len, PCI_DMA_TODEVICE);
- kfree(*((struct ieee80211_tx_control **) skb->cb));
kfree_skb(skb);
ring->idx = (ring->idx + 1) % ring->entries;
}
@@ -894,9 +882,10 @@
dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_RX_INCLUDES_FCS;
+ IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_SIGNAL_UNSPEC;
dev->queues = 1;
- dev->max_rssi = 65;
+ dev->max_signal = 65;
reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
reg &= RTL818X_TX_CONF_HWVER_MASK;
diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h
index 076d88b..a0cfb666 100644
--- a/drivers/net/wireless/rtl8187.h
+++ b/drivers/net/wireless/rtl8187.h
@@ -44,12 +44,6 @@
__le64 mac_time;
} __attribute__((packed));
-struct rtl8187_tx_info {
- struct ieee80211_tx_control *control;
- struct urb *urb;
- struct ieee80211_hw *dev;
-};
-
struct rtl8187_tx_hdr {
__le32 flags;
#define RTL8187_TX_FLAG_NO_ENCRYPT (1 << 15)
diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c
index 9223ada..0078c7e 100644
--- a/drivers/net/wireless/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl8187_dev.c
@@ -150,27 +150,22 @@
static void rtl8187_tx_cb(struct urb *urb)
{
- struct ieee80211_tx_status status;
struct sk_buff *skb = (struct sk_buff *)urb->context;
- struct rtl8187_tx_info *info = (struct rtl8187_tx_info *)skb->cb;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_hw *hw = info->driver_data[0];
- memset(&status, 0, sizeof(status));
-
- usb_free_urb(info->urb);
- if (info->control)
- memcpy(&status.control, info->control, sizeof(status.control));
- kfree(info->control);
+ usb_free_urb(info->driver_data[1]);
skb_pull(skb, sizeof(struct rtl8187_tx_hdr));
- status.flags |= IEEE80211_TX_STATUS_ACK;
- ieee80211_tx_status_irqsafe(info->dev, skb, &status);
+ memset(&info->status, 0, sizeof(info->status));
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ ieee80211_tx_status_irqsafe(hw, skb);
}
-static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
{
struct rtl8187_priv *priv = dev->priv;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct rtl8187_tx_hdr *hdr;
- struct rtl8187_tx_info *info;
struct urb *urb;
__le16 rts_dur = 0;
u32 flags;
@@ -185,33 +180,27 @@
flags = skb->len;
flags |= RTL8187_TX_FLAG_NO_ENCRYPT;
- BUG_ON(!control->tx_rate);
-
- flags |= control->tx_rate->hw_value << 24;
+ flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24;
if (ieee80211_get_morefrag((struct ieee80211_hdr *)skb->data))
flags |= RTL8187_TX_FLAG_MORE_FRAG;
- if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
- BUG_ON(!control->rts_cts_rate);
+ if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
flags |= RTL8187_TX_FLAG_RTS;
- flags |= control->rts_cts_rate->hw_value << 19;
+ flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
rts_dur = ieee80211_rts_duration(dev, priv->vif,
- skb->len, control);
- } else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
- BUG_ON(!control->rts_cts_rate);
+ skb->len, info);
+ } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
flags |= RTL8187_TX_FLAG_CTS;
- flags |= control->rts_cts_rate->hw_value << 19;
+ flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
}
hdr = (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr));
hdr->flags = cpu_to_le32(flags);
hdr->len = 0;
hdr->rts_duration = rts_dur;
- hdr->retry = cpu_to_le32(control->retry_limit << 8);
+ hdr->retry = cpu_to_le32(info->control.retry_limit << 8);
- info = (struct rtl8187_tx_info *)skb->cb;
- info->control = kmemdup(control, sizeof(*control), GFP_ATOMIC);
- info->urb = urb;
- info->dev = dev;
+ info->driver_data[0] = dev;
+ info->driver_data[1] = urb;
usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, 2),
hdr, skb->len, rtl8187_tx_cb, skb);
rc = usb_submit_urb(urb, GFP_ATOMIC);
@@ -271,8 +260,8 @@
}
rx_status.antenna = (hdr->signal >> 7) & 1;
- rx_status.signal = 64 - min(hdr->noise, (u8)64);
- rx_status.ssi = signal;
+ rx_status.qual = 64 - min(hdr->noise, (u8)64);
+ rx_status.signal = signal;
rx_status.rate_idx = rate;
rx_status.freq = dev->conf.channel->center_freq;
rx_status.band = dev->conf.channel->band;
@@ -750,11 +739,11 @@
priv->mode = IEEE80211_IF_TYPE_MNTR;
dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_RX_INCLUDES_FCS;
+ IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_SIGNAL_UNSPEC;
dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr);
dev->queues = 1;
- dev->max_rssi = 65;
- dev->max_signal = 64;
+ dev->max_signal = 65;
eeprom.data = dev;
eeprom.register_read = rtl8187_eeprom_register_read;
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 418606a..6d86b36 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -224,36 +224,6 @@
return r;
}
-/**
- * clear_tx_skb_control_block - clears the control block of tx skbuffs
- * @skb: a &struct sk_buff pointer
- *
- * This clears the control block of skbuff buffers, which were transmitted to
- * the device. Notify that the function is not thread-safe, so prevent
- * multiple calls.
- */
-static void clear_tx_skb_control_block(struct sk_buff *skb)
-{
- struct zd_tx_skb_control_block *cb =
- (struct zd_tx_skb_control_block *)skb->cb;
-
- kfree(cb->control);
- cb->control = NULL;
-}
-
-/**
- * kfree_tx_skb - frees a tx skbuff
- * @skb: a &struct sk_buff pointer
- *
- * Frees the tx skbuff. Frees also the allocated control structure in the
- * control block if necessary.
- */
-static void kfree_tx_skb(struct sk_buff *skb)
-{
- clear_tx_skb_control_block(skb);
- dev_kfree_skb_any(skb);
-}
-
static void zd_op_stop(struct ieee80211_hw *hw)
{
struct zd_mac *mac = zd_hw_mac(hw);
@@ -276,40 +246,15 @@
while ((skb = skb_dequeue(ack_wait_queue)))
- kfree_tx_skb(skb);
-}
-
-/**
- * init_tx_skb_control_block - initializes skb control block
- * @skb: a &sk_buff pointer
- * @dev: pointer to the mac80221 device
- * @control: mac80211 tx control applying for the frame in @skb
- *
- * Initializes the control block of the skbuff to be transmitted.
- */
-static int init_tx_skb_control_block(struct sk_buff *skb,
- struct ieee80211_hw *hw,
- struct ieee80211_tx_control *control)
-{
- struct zd_tx_skb_control_block *cb =
- (struct zd_tx_skb_control_block *)skb->cb;
-
- ZD_ASSERT(sizeof(*cb) <= sizeof(skb->cb));
- memset(cb, 0, sizeof(*cb));
- cb->hw= hw;
- cb->control = kmalloc(sizeof(*control), GFP_ATOMIC);
- if (cb->control == NULL)
- return -ENOMEM;
- memcpy(cb->control, control, sizeof(*control));
-
- return 0;
+ dev_kfree_skb_any(skb);
}
/**
* tx_status - reports tx status of a packet if required
* @hw - a &struct ieee80211_hw pointer
* @skb - a sk-buffer
- * @status - the tx status of the packet without control information
+ * @flags: extra flags to set in the TX status info
+ * @ackssi: ACK signal strength
* @success - True for successfull transmission of the frame
*
* This information calls ieee80211_tx_status_irqsafe() if required by the
@@ -319,18 +264,17 @@
* If no status information has been requested, the skb is freed.
*/
static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_status *status,
- bool success)
+ u32 flags, int ackssi, bool success)
{
- struct zd_tx_skb_control_block *cb = (struct zd_tx_skb_control_block *)
- skb->cb;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- ZD_ASSERT(cb->control != NULL);
- memcpy(&status->control, cb->control, sizeof(status->control));
+ memset(&info->status, 0, sizeof(info->status));
+
if (!success)
- status->excessive_retries = 1;
- clear_tx_skb_control_block(skb);
- ieee80211_tx_status_irqsafe(hw, skb, status);
+ info->status.excessive_retries = 1;
+ info->flags |= flags;
+ info->status.ack_signal = ackssi;
+ ieee80211_tx_status_irqsafe(hw, skb);
}
/**
@@ -345,15 +289,12 @@
{
struct sk_buff_head *q = &zd_hw_mac(hw)->ack_wait_queue;
struct sk_buff *skb;
- struct ieee80211_tx_status status;
skb = skb_dequeue(q);
if (skb == NULL)
return;
- memset(&status, 0, sizeof(status));
-
- tx_status(hw, skb, &status, 0);
+ tx_status(hw, skb, 0, 0, 0);
}
/**
@@ -368,28 +309,20 @@
*/
void zd_mac_tx_to_dev(struct sk_buff *skb, int error)
{
- struct zd_tx_skb_control_block *cb =
- (struct zd_tx_skb_control_block *)skb->cb;
- struct ieee80211_hw *hw = cb->hw;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_hw *hw = info->driver_data[0];
- if (likely(cb->control)) {
- skb_pull(skb, sizeof(struct zd_ctrlset));
- if (unlikely(error ||
- (cb->control->flags & IEEE80211_TXCTL_NO_ACK)))
- {
- struct ieee80211_tx_status status;
- memset(&status, 0, sizeof(status));
- tx_status(hw, skb, &status, !error);
- } else {
- struct sk_buff_head *q =
- &zd_hw_mac(hw)->ack_wait_queue;
-
- skb_queue_tail(q, skb);
- while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS)
- zd_mac_tx_failed(hw);
- }
+ skb_pull(skb, sizeof(struct zd_ctrlset));
+ if (unlikely(error ||
+ (info->flags & IEEE80211_TX_CTL_NO_ACK))) {
+ tx_status(hw, skb, 0, 0, !error);
} else {
- kfree_tx_skb(skb);
+ struct sk_buff_head *q =
+ &zd_hw_mac(hw)->ack_wait_queue;
+
+ skb_queue_tail(q, skb);
+ while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS)
+ zd_mac_tx_failed(hw);
}
}
@@ -454,7 +387,7 @@
cs->control = 0;
/* First fragment */
- if (flags & IEEE80211_TXCTL_FIRST_FRAGMENT)
+ if (flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
cs->control |= ZD_CS_NEED_RANDOM_BACKOFF;
/* Multicast */
@@ -466,10 +399,10 @@
(IEEE80211_FTYPE_CTL|IEEE80211_STYPE_PSPOLL))
cs->control |= ZD_CS_PS_POLL_FRAME;
- if (flags & IEEE80211_TXCTL_USE_RTS_CTS)
+ if (flags & IEEE80211_TX_CTL_USE_RTS_CTS)
cs->control |= ZD_CS_RTS;
- if (flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+ if (flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
cs->control |= ZD_CS_SELF_CTS;
/* FIXME: Management frame? */
@@ -516,25 +449,28 @@
}
static int fill_ctrlset(struct zd_mac *mac,
- struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+ struct sk_buff *skb)
{
int r;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
unsigned int frag_len = skb->len + FCS_LEN;
unsigned int packet_length;
+ struct ieee80211_rate *txrate;
struct zd_ctrlset *cs = (struct zd_ctrlset *)
skb_push(skb, sizeof(struct zd_ctrlset));
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
ZD_ASSERT(frag_len <= 0xffff);
- cs->modulation = control->tx_rate->hw_value;
- if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE)
- cs->modulation = control->tx_rate->hw_value_short;
+ txrate = ieee80211_get_tx_rate(mac->hw, info);
+
+ cs->modulation = txrate->hw_value;
+ if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE)
+ cs->modulation = txrate->hw_value_short;
cs->tx_length = cpu_to_le16(frag_len);
- cs_set_control(mac, cs, hdr, control->flags);
+ cs_set_control(mac, cs, hdr, info->flags);
packet_length = frag_len + sizeof(struct zd_ctrlset) + 10;
ZD_ASSERT(packet_length <= 0xffff);
@@ -579,24 +515,21 @@
* control block of the skbuff will be initialized. If necessary the incoming
* mac80211 queues will be stopped.
*/
-static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct zd_mac *mac = zd_hw_mac(hw);
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int r;
- r = fill_ctrlset(mac, skb, control);
+ r = fill_ctrlset(mac, skb);
if (r)
return r;
- r = init_tx_skb_control_block(skb, hw, control);
+ info->driver_data[0] = hw;
+
+ r = zd_usb_tx(&mac->chip.usb, skb);
if (r)
return r;
- r = zd_usb_tx(&mac->chip.usb, skb);
- if (r) {
- clear_tx_skb_control_block(skb);
- return r;
- }
return 0;
}
@@ -634,13 +567,8 @@
tx_hdr = (struct ieee80211_hdr *)skb->data;
if (likely(!compare_ether_addr(tx_hdr->addr2, rx_hdr->addr1)))
{
- struct ieee80211_tx_status status;
-
- memset(&status, 0, sizeof(status));
- status.flags = IEEE80211_TX_STATUS_ACK;
- status.ack_signal = stats->ssi;
__skb_unlink(skb, q);
- tx_status(hw, skb, &status, 1);
+ tx_status(hw, skb, IEEE80211_TX_STAT_ACK, stats->signal, 1);
goto out;
}
}
@@ -691,8 +619,8 @@
stats.freq = zd_channels[_zd_chip_get_channel(&mac->chip) - 1].center_freq;
stats.band = IEEE80211_BAND_2GHZ;
- stats.ssi = status->signal_strength;
- stats.signal = zd_rx_qual_percent(buffer,
+ stats.signal = status->signal_strength;
+ stats.qual = zd_rx_qual_percent(buffer,
length - sizeof(struct rx_status),
status);
@@ -751,6 +679,7 @@
case IEEE80211_IF_TYPE_MNTR:
case IEEE80211_IF_TYPE_MESH_POINT:
case IEEE80211_IF_TYPE_STA:
+ case IEEE80211_IF_TYPE_IBSS:
mac->type = conf->type;
break;
default:
@@ -781,7 +710,8 @@
struct zd_mac *mac = zd_hw_mac(hw);
int associated;
- if (mac->type == IEEE80211_IF_TYPE_MESH_POINT) {
+ if (mac->type == IEEE80211_IF_TYPE_MESH_POINT ||
+ mac->type == IEEE80211_IF_TYPE_IBSS) {
associated = true;
if (conf->beacon) {
zd_mac_config_beacon(hw, conf->beacon);
@@ -941,6 +871,17 @@
}
}
+static int zd_op_beacon_update(struct ieee80211_hw *hw,
+ struct sk_buff *skb)
+{
+ struct zd_mac *mac = zd_hw_mac(hw);
+ zd_mac_config_beacon(hw, skb);
+ kfree_skb(skb);
+ zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS |
+ hw->conf.beacon_int);
+ return 0;
+}
+
static const struct ieee80211_ops zd_ops = {
.tx = zd_op_tx,
.start = zd_op_start,
@@ -951,6 +892,7 @@
.config_interface = zd_op_config_interface,
.configure_filter = zd_op_configure_filter,
.bss_info_changed = zd_op_bss_info_changed,
+ .beacon_update = zd_op_beacon_update,
};
struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
@@ -982,10 +924,10 @@
hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band;
hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
- hw->max_rssi = 100;
- hw->max_signal = 100;
+ IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
+ IEEE80211_HW_SIGNAL_DB;
+ hw->max_signal = 100;
hw->queues = 1;
hw->extra_tx_headroom = sizeof(struct zd_ctrlset);
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index 7117024..18c1d56 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -149,22 +149,6 @@
struct delayed_work link_led_work;
};
-/**
- * struct zd_tx_skb_control_block - control block for tx skbuffs
- * @control: &struct ieee80211_tx_control pointer
- * @context: context pointer
- *
- * This structure is used to fill the cb field in an &sk_buff to transmit.
- * The control field is NULL, if there is no requirement from the mac80211
- * stack to report about the packet ACK. This is the case if the flag
- * IEEE80211_TXCTL_NO_ACK is not set in &struct ieee80211_tx_control.
- */
-struct zd_tx_skb_control_block {
- struct ieee80211_tx_control *control;
- struct ieee80211_hw *hw;
- void *context;
-};
-
#define ZD_MAC_STATS_BUFFER_SIZE 16
#define ZD_MAC_MAX_ACK_WAITERS 10
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 8941f5e..1ccff24 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -169,10 +169,11 @@
if (flags & REBOOT) {
u8 ret;
+ /* Use "DMA-aware" buffer. */
r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
USB_REQ_FIRMWARE_CONFIRM,
USB_DIR_IN | USB_TYPE_VENDOR,
- 0, 0, &ret, sizeof(ret), 5000 /* ms */);
+ 0, 0, p, sizeof(ret), 5000 /* ms */);
if (r != sizeof(ret)) {
dev_err(&udev->dev,
"control request firmeware confirmation failed."
@@ -181,6 +182,7 @@
r = -ENODEV;
goto error;
}
+ ret = p[0];
if (ret & 0x80) {
dev_err(&udev->dev,
"Internal error while downloading."
@@ -312,22 +314,31 @@
{
int r;
struct usb_device *udev = zd_usb_to_usbdev(usb);
+ u8 *buf;
+ /* Use "DMA-aware" buffer. */
+ buf = kmalloc(len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
USB_REQ_FIRMWARE_READ_DATA, USB_DIR_IN | 0x40, addr, 0,
- data, len, 5000);
+ buf, len, 5000);
if (r < 0) {
dev_err(&udev->dev,
"read over firmware interface failed: %d\n", r);
- return r;
+ goto exit;
} else if (r != len) {
dev_err(&udev->dev,
"incomplete read over firmware interface: %d/%d\n",
r, len);
- return -EIO;
+ r = -EIO;
+ goto exit;
}
-
- return 0;
+ r = 0;
+ memcpy(data, buf, len);
+exit:
+ kfree(buf);
+ return r;
}
#define urb_dev(urb) (&(urb)->dev->dev)
@@ -869,7 +880,7 @@
{
int r;
struct sk_buff *skb;
- struct zd_tx_skb_control_block *cb;
+ struct ieee80211_tx_info *info;
struct zd_usb *usb;
switch (urb->status) {
@@ -893,8 +904,8 @@
* grab 'usb' pointer before handing off the skb (since
* it might be freed by zd_mac_tx_to_dev or mac80211)
*/
- cb = (struct zd_tx_skb_control_block *)skb->cb;
- usb = &zd_hw_mac(cb->hw)->chip.usb;
+ info = IEEE80211_SKB_CB(skb);
+ usb = &zd_hw_mac(info->driver_data[0])->chip.usb;
zd_mac_tx_to_dev(skb, urb->status);
free_tx_urb(usb, urb);
tx_dec_submitted_urbs(usb);
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/linux/brcmphy.h b/include/linux/brcmphy.h
new file mode 100644
index 0000000..9b64b6d
--- /dev/null
+++ b/include/linux/brcmphy.h
@@ -0,0 +1,6 @@
+#define PHY_BRCM_WIRESPEED_ENABLE 0x00000001
+#define PHY_BRCM_AUTO_PWRDWN_ENABLE 0x00000002
+#define PHY_BRCM_APD_CLK125_ENABLE 0x00000004
+#define PHY_BRCM_STD_IBND_DISABLE 0x00000008
+#define PHY_BRCM_EXT_IBND_RX_ENABLE 0x00000010
+#define PHY_BRCM_EXT_IBND_TX_ENABLE 0x00000020
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 0b5e03e..9300f37 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -306,20 +306,32 @@
#define IEEE80211_HT_CAP_SGI_40 0x0040
#define IEEE80211_HT_CAP_DELAY_BA 0x0400
#define IEEE80211_HT_CAP_MAX_AMSDU 0x0800
+/* 802.11n HT capability AMPDU settings */
#define IEEE80211_HT_CAP_AMPDU_FACTOR 0x03
#define IEEE80211_HT_CAP_AMPDU_DENSITY 0x1C
+/* 802.11n HT capability MSC set */
+#define IEEE80211_SUPP_MCS_SET_UEQM 4
+#define IEEE80211_HT_CAP_MAX_STREAMS 4
+#define IEEE80211_SUPP_MCS_SET_LEN 10
+/* maximum streams the spec allows */
+#define IEEE80211_HT_CAP_MCS_TX_DEFINED 0x01
+#define IEEE80211_HT_CAP_MCS_TX_RX_DIFF 0x02
+#define IEEE80211_HT_CAP_MCS_TX_STREAMS 0x0C
+#define IEEE80211_HT_CAP_MCS_TX_UEQM 0x10
/* 802.11n HT IE masks */
#define IEEE80211_HT_IE_CHA_SEC_OFFSET 0x03
+#define IEEE80211_HT_IE_CHA_SEC_ABOVE 0x01
+#define IEEE80211_HT_IE_CHA_SEC_BELOW 0x03
#define IEEE80211_HT_IE_CHA_WIDTH 0x04
#define IEEE80211_HT_IE_HT_PROTECTION 0x0003
#define IEEE80211_HT_IE_NON_GF_STA_PRSNT 0x0004
#define IEEE80211_HT_IE_NON_HT_STA_PRSNT 0x0010
/* MIMO Power Save Modes */
-#define WLAN_HT_CAP_MIMO_PS_STATIC 0
-#define WLAN_HT_CAP_MIMO_PS_DYNAMIC 1
-#define WLAN_HT_CAP_MIMO_PS_INVALID 2
-#define WLAN_HT_CAP_MIMO_PS_DISABLED 3
+#define WLAN_HT_CAP_MIMO_PS_STATIC 0
+#define WLAN_HT_CAP_MIMO_PS_DYNAMIC 1
+#define WLAN_HT_CAP_MIMO_PS_INVALID 2
+#define WLAN_HT_CAP_MIMO_PS_DISABLED 3
/* Authentication algorithms */
#define WLAN_AUTH_OPEN 0
@@ -552,16 +564,17 @@
*/
static inline u8 *ieee80211_get_SA(struct ieee80211_hdr *hdr)
{
- u8 *raw = (u8 *) hdr;
- u8 tofrom = (*(raw+1)) & 3; /* get the TODS and FROMDS bits */
+ __le16 fc = hdr->frame_control;
+ fc &= cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS);
- switch (tofrom) {
- case 2:
- return hdr->addr3;
- case 3:
- return hdr->addr4;
+ switch (fc) {
+ case __constant_cpu_to_le16(IEEE80211_FCTL_FROMDS):
+ return hdr->addr3;
+ case __constant_cpu_to_le16(IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS):
+ return hdr->addr4;
+ default:
+ return hdr->addr2;
}
- return hdr->addr2;
}
/**
@@ -577,12 +590,13 @@
*/
static inline u8 *ieee80211_get_DA(struct ieee80211_hdr *hdr)
{
- u8 *raw = (u8 *) hdr;
- u8 to_ds = (*(raw+1)) & 1; /* get the TODS bit */
+ __le16 fc = hdr->frame_control;
+ fc &= cpu_to_le16(IEEE80211_FCTL_TODS);
- if (to_ds)
+ if (fc)
return hdr->addr3;
- return hdr->addr1;
+ else
+ return hdr->addr1;
}
/**
@@ -595,8 +609,8 @@
*/
static inline int ieee80211_get_morefrag(struct ieee80211_hdr *hdr)
{
- return (le16_to_cpu(hdr->frame_control) &
- IEEE80211_FCTL_MOREFRAGS) != 0;
+ __le16 fc = hdr->frame_control;
+ return !!(fc & cpu_to_le16(IEEE80211_FCTL_MOREFRAGS));
}
#endif /* IEEE80211_H */
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index 950e13d..6badb3e 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -4,8 +4,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: if_bridge.h,v 1.1 2000/02/18 16:47:01 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/include/linux/if_ppp.h b/include/linux/if_ppp.h
index 0f2f70d..c3b1f85 100644
--- a/include/linux/if_ppp.h
+++ b/include/linux/if_ppp.h
@@ -1,5 +1,3 @@
-/* $Id: if_ppp.h,v 1.21 2000/03/27 06:03:36 paulus Exp $ */
-
/*
* if_ppp.h - Point-to-Point Protocol definitions.
*
diff --git a/include/linux/if_tun.h b/include/linux/if_tun.h
index 8c71fe2..18f31b6 100644
--- a/include/linux/if_tun.h
+++ b/include/linux/if_tun.h
@@ -11,8 +11,6 @@
* 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.
- *
- * $Id: if_tun.h,v 1.2 2001/06/01 18:39:47 davem Exp $
*/
#ifndef __IF_TUN_H
diff --git a/include/linux/ip6_tunnel.h b/include/linux/ip6_tunnel.h
index af3f4a7..1e7cc4a 100644
--- a/include/linux/ip6_tunnel.h
+++ b/include/linux/ip6_tunnel.h
@@ -1,7 +1,3 @@
-/*
- * $Id$
- */
-
#ifndef _IP6_TUNNEL_H
#define _IP6_TUNNEL_H
diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h
index 0a383ac..759bc04 100644
--- a/include/linux/netfilter/nfnetlink_conntrack.h
+++ b/include/linux/netfilter/nfnetlink_conntrack.h
@@ -81,6 +81,7 @@
CTA_PROTOINFO_UNSPEC,
CTA_PROTOINFO_TCP,
CTA_PROTOINFO_DCCP,
+ CTA_PROTOINFO_SCTP,
__CTA_PROTOINFO_MAX
};
#define CTA_PROTOINFO_MAX (__CTA_PROTOINFO_MAX - 1)
@@ -103,6 +104,15 @@
};
#define CTA_PROTOINFO_DCCP_MAX (__CTA_PROTOINFO_DCCP_MAX - 1)
+enum ctattr_protoinfo_sctp {
+ CTA_PROTOINFO_SCTP_UNSPEC,
+ CTA_PROTOINFO_SCTP_STATE,
+ CTA_PROTOINFO_SCTP_VTAG_ORIGINAL,
+ CTA_PROTOINFO_SCTP_VTAG_REPLY,
+ __CTA_PROTOINFO_SCTP_MAX
+};
+#define CTA_PROTOINFO_SCTP_MAX (__CTA_PROTOINFO_SCTP_MAX - 1)
+
enum ctattr_counters {
CTA_COUNTERS_UNSPEC,
CTA_COUNTERS_PACKETS, /* old 64bit counters */
diff --git a/include/linux/netfilter_bridge/ebt_ip6.h b/include/linux/netfilter_bridge/ebt_ip6.h
new file mode 100644
index 0000000..2273c3a
--- /dev/null
+++ b/include/linux/netfilter_bridge/ebt_ip6.h
@@ -0,0 +1,40 @@
+/*
+ * ebt_ip6
+ *
+ * Authors:
+ * Kuo-Lang Tseng <kuo-lang.tseng@intel.com>
+ * Manohar Castelino <manohar.r.castelino@intel.com>
+ *
+ * Jan 11, 2008
+ *
+ */
+
+#ifndef __LINUX_BRIDGE_EBT_IP6_H
+#define __LINUX_BRIDGE_EBT_IP6_H
+
+#define EBT_IP6_SOURCE 0x01
+#define EBT_IP6_DEST 0x02
+#define EBT_IP6_TCLASS 0x04
+#define EBT_IP6_PROTO 0x08
+#define EBT_IP6_SPORT 0x10
+#define EBT_IP6_DPORT 0x20
+#define EBT_IP6_MASK (EBT_IP6_SOURCE | EBT_IP6_DEST | EBT_IP6_TCLASS |\
+ EBT_IP6_PROTO | EBT_IP6_SPORT | EBT_IP6_DPORT)
+#define EBT_IP6_MATCH "ip6"
+
+/* the same values are used for the invflags */
+struct ebt_ip6_info
+{
+ struct in6_addr saddr;
+ struct in6_addr daddr;
+ struct in6_addr smsk;
+ struct in6_addr dmsk;
+ uint8_t tclass;
+ uint8_t protocol;
+ uint8_t bitmask;
+ uint8_t invflags;
+ uint16_t sport[2];
+ uint16_t dport[2];
+};
+
+#endif
diff --git a/include/linux/netfilter_bridge/ebt_log.h b/include/linux/netfilter_bridge/ebt_log.h
index 96e231a..b76e653 100644
--- a/include/linux/netfilter_bridge/ebt_log.h
+++ b/include/linux/netfilter_bridge/ebt_log.h
@@ -4,7 +4,8 @@
#define EBT_LOG_IP 0x01 /* if the frame is made by ip, log the ip information */
#define EBT_LOG_ARP 0x02
#define EBT_LOG_NFLOG 0x04
-#define EBT_LOG_MASK (EBT_LOG_IP | EBT_LOG_ARP)
+#define EBT_LOG_IP6 0x08
+#define EBT_LOG_MASK (EBT_LOG_IP | EBT_LOG_ARP | EBT_LOG_IP6)
#define EBT_LOG_PREFIX_SIZE 30
#define EBT_LOG_WATCHER "log"
diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h
index 650318b..29c7727 100644
--- a/include/linux/netfilter_ipv4.h
+++ b/include/linux/netfilter_ipv4.h
@@ -60,6 +60,7 @@
NF_IP_PRI_MANGLE = -150,
NF_IP_PRI_NAT_DST = -100,
NF_IP_PRI_FILTER = 0,
+ NF_IP_PRI_SECURITY = 50,
NF_IP_PRI_NAT_SRC = 100,
NF_IP_PRI_SELINUX_LAST = 225,
NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,
diff --git a/include/linux/netfilter_ipv6.h b/include/linux/netfilter_ipv6.h
index 3475a65..fd50988 100644
--- a/include/linux/netfilter_ipv6.h
+++ b/include/linux/netfilter_ipv6.h
@@ -64,6 +64,7 @@
NF_IP6_PRI_MANGLE = -150,
NF_IP6_PRI_NAT_DST = -100,
NF_IP6_PRI_FILTER = 0,
+ NF_IP6_PRI_SECURITY = 50,
NF_IP6_PRI_NAT_SRC = 100,
NF_IP6_PRI_SELINUX_LAST = 225,
NF_IP6_PRI_LAST = INT_MAX,
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index bec1062..9ff1b54 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -193,7 +193,7 @@
/* finegrained unicast helpers: */
struct sock *netlink_getsockbyfilp(struct file *filp);
-int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock,
+int netlink_attachskb(struct sock *sk, struct sk_buff *skb,
long *timeo, struct sock *ssk);
void netlink_detachskb(struct sock *sk, struct sk_buff *skb);
int netlink_sendskb(struct sock *sk, struct sk_buff *skb);
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index eafc9d6..caa0005 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1981,6 +1981,7 @@
#define PCI_DEVICE_ID_TIGON3_5787M 0x1693
#define PCI_DEVICE_ID_TIGON3_5782 0x1696
#define PCI_DEVICE_ID_TIGON3_5784 0x1698
+#define PCI_DEVICE_ID_TIGON3_5785 0x1699
#define PCI_DEVICE_ID_TIGON3_5786 0x169a
#define PCI_DEVICE_ID_TIGON3_5787 0x169b
#define PCI_DEVICE_ID_TIGON3_5788 0x169c
diff --git a/include/linux/ppp-comp.h b/include/linux/ppp-comp.h
index e86a7a5..b8d4ddd 100644
--- a/include/linux/ppp-comp.h
+++ b/include/linux/ppp-comp.h
@@ -23,8 +23,6 @@
* ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
* OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
* OR MODIFICATIONS.
- *
- * $Id: ppp-comp.h,v 1.6 1997/11/27 06:04:44 paulus Exp $
*/
/*
diff --git a/include/linux/ppp_defs.h b/include/linux/ppp_defs.h
index c6b13ff..6e8adc7 100644
--- a/include/linux/ppp_defs.h
+++ b/include/linux/ppp_defs.h
@@ -1,5 +1,3 @@
-/* $Id: ppp_defs.h,v 1.2 1994/09/21 01:31:06 paulus Exp $ */
-
/*
* ppp_defs.h - PPP definitions.
*
diff --git a/include/linux/smc911x.h b/include/linux/smc911x.h
new file mode 100644
index 0000000..b58f54c
--- /dev/null
+++ b/include/linux/smc911x.h
@@ -0,0 +1,12 @@
+#ifndef __SMC911X_H__
+#define __SMC911X_H__
+
+#define SMC911X_USE_16BIT (1 << 0)
+#define SMC911X_USE_32BIT (1 << 1)
+
+struct smc911x_platdata {
+ unsigned long flags;
+ unsigned long irq_flags; /* IRQF_... */
+};
+
+#endif /* __SMC911X_H__ */
diff --git a/include/linux/sunrpc/auth_gss.h b/include/linux/sunrpc/auth_gss.h
index fec6899..d48d4e6 100644
--- a/include/linux/sunrpc/auth_gss.h
+++ b/include/linux/sunrpc/auth_gss.h
@@ -7,8 +7,6 @@
* Andy Adamson <andros@umich.edu>
* Bruce Fields <bfields@umich.edu>
* Copyright (c) 2000 The Regents of the University of Michigan
- *
- * $Id$
*/
#ifndef _LINUX_SUNRPC_AUTH_GSS_H
diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h
index 459c5fc..03f3333 100644
--- a/include/linux/sunrpc/gss_api.h
+++ b/include/linux/sunrpc/gss_api.h
@@ -7,8 +7,6 @@
* Andy Adamson <andros@umich.edu>
* Bruce Fields <bfields@umich.edu>
* Copyright (c) 2000 The Regents of the University of Michigan
- *
- * $Id$
*/
#ifndef _LINUX_SUNRPC_GSS_API_H
diff --git a/include/linux/sunrpc/svcauth_gss.h b/include/linux/sunrpc/svcauth_gss.h
index 417a1de..c9165d9 100644
--- a/include/linux/sunrpc/svcauth_gss.h
+++ b/include/linux/sunrpc/svcauth_gss.h
@@ -3,9 +3,6 @@
*
* Bruce Fields <bfields@umich.edu>
* Copyright (c) 2002 The Regents of the Unviersity of Michigan
- *
- * $Id$
- *
*/
#ifndef _LINUX_SUNRPC_SVCAUTH_GSS_H
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index b31b6b7..07e79bd 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -291,10 +291,9 @@
u32 rcv_ssthresh; /* Current window clamp */
u32 frto_highmark; /* snd_nxt when RTO occurred */
- u8 reordering; /* Packet reordering metric. */
+ u16 advmss; /* Advertised MSS */
u8 frto_counter; /* Number of new acks after RTO */
u8 nonagle; /* Disable Nagle algorithm? */
- u8 keepalive_probes; /* num of allowed keep alive probes */
/* RTT measurement */
u32 srtt; /* smoothed round trip time << 3 */
@@ -305,6 +304,10 @@
u32 packets_out; /* Packets which are "in flight" */
u32 retrans_out; /* Retransmitted packets out */
+
+ u16 urg_data; /* Saved octet of OOB data and control flags */
+ u8 urg_mode; /* In urgent mode */
+ u8 ecn_flags; /* ECN status bits. */
/*
* Options received (usually on last packet, some only on SYN packets).
*/
@@ -320,13 +323,24 @@
u32 snd_cwnd_used;
u32 snd_cwnd_stamp;
- struct sk_buff_head out_of_order_queue; /* Out of order segments go here */
-
u32 rcv_wnd; /* Current receiver window */
u32 write_seq; /* Tail(+1) of data held in tcp send buffer */
u32 pushed_seq; /* Last pushed seq, required to talk to windows */
+ u32 lost_out; /* Lost packets */
+ u32 sacked_out; /* SACK'd packets */
+ u32 fackets_out; /* FACK'd packets */
+ u32 tso_deferred;
+ u32 bytes_acked; /* Appropriate Byte Counting - RFC3465 */
-/* SACKs data */
+ /* from STCP, retrans queue hinting */
+ struct sk_buff* lost_skb_hint;
+ struct sk_buff *scoreboard_skb_hint;
+ struct sk_buff *retransmit_skb_hint;
+ struct sk_buff *forward_skb_hint;
+
+ struct sk_buff_head out_of_order_queue; /* Out of order segments go here */
+
+ /* SACKs data, these 2 need to be together (see tcp_build_and_update_options) */
struct tcp_sack_block duplicate_sack[1]; /* D-SACK block */
struct tcp_sack_block selective_acks[4]; /* The SACKS themselves*/
@@ -337,23 +351,14 @@
* sacked_out > 0)
*/
- /* from STCP, retrans queue hinting */
- struct sk_buff* lost_skb_hint;
-
- struct sk_buff *scoreboard_skb_hint;
- struct sk_buff *retransmit_skb_hint;
- struct sk_buff *forward_skb_hint;
-
int lost_cnt_hint;
int retransmit_cnt_hint;
u32 lost_retrans_low; /* Sent seq after any rxmit (lowest) */
- u16 advmss; /* Advertised MSS */
+ u8 reordering; /* Packet reordering metric. */
+ u8 keepalive_probes; /* num of allowed keep alive probes */
u32 prior_ssthresh; /* ssthresh saved at recovery start */
- u32 lost_out; /* Lost packets */
- u32 sacked_out; /* SACK'd packets */
- u32 fackets_out; /* FACK'd packets */
u32 high_seq; /* snd_nxt at onset of congestion */
u32 retrans_stamp; /* Timestamp of the last retransmit,
@@ -361,23 +366,16 @@
* the first SYN. */
u32 undo_marker; /* tracking retrans started here. */
int undo_retrans; /* number of undoable retransmissions. */
- u32 urg_seq; /* Seq of received urgent pointer */
- u16 urg_data; /* Saved octet of OOB data and control flags */
- u8 urg_mode; /* In urgent mode */
- u8 ecn_flags; /* ECN status bits. */
- u32 snd_up; /* Urgent pointer */
-
u32 total_retrans; /* Total retransmits for entire connection */
- u32 bytes_acked; /* Appropriate Byte Counting - RFC3465 */
+
+ u32 urg_seq; /* Seq of received urgent pointer */
+ u32 snd_up; /* Urgent pointer */
unsigned int keepalive_time; /* time before keep alive takes place */
unsigned int keepalive_intvl; /* time interval between keep alive probes */
- int linger2;
unsigned long last_synq_overflow;
- u32 tso_deferred;
-
/* Receiver side RTT estimation */
struct {
u32 rtt;
@@ -405,6 +403,8 @@
/* TCP MD5 Signagure Option information */
struct tcp_md5sig_info *md5sig_info;
#endif
+
+ int linger2;
};
static inline struct tcp_sock *tcp_sk(const struct sock *sk)
diff --git a/include/linux/tipc_config.h b/include/linux/tipc_config.h
index b0c916d..2bc6fa4 100644
--- a/include/linux/tipc_config.h
+++ b/include/linux/tipc_config.h
@@ -2,7 +2,7 @@
* include/linux/tipc_config.h: Include file for TIPC configuration interface
*
* Copyright (c) 2003-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -136,6 +136,14 @@
#define TIPC_CMD_SET_NETID 0x800B /* tx unsigned, rx none */
/*
+ * Reserved commands:
+ * May not be issued by any process.
+ * Used internally by TIPC.
+ */
+
+#define TIPC_CMD_NOT_NET_ADMIN 0xC001 /* tx none, rx none */
+
+/*
* TLV types defined for TIPC
*/
diff --git a/include/linux/wanrouter.h b/include/linux/wanrouter.h
index 3add874..e0aa396 100644
--- a/include/linux/wanrouter.h
+++ b/include/linux/wanrouter.h
@@ -522,7 +522,7 @@
extern void wanrouter_proc_cleanup(void);
extern int wanrouter_proc_add(struct wan_device *wandev);
extern int wanrouter_proc_delete(struct wan_device *wandev);
-extern int wanrouter_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+extern long wanrouter_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
/* Public Data */
/* list of registered devices */
diff --git a/include/linux/wireless.h b/include/linux/wireless.h
index 0a9b5b4..4a95a0e 100644
--- a/include/linux/wireless.h
+++ b/include/linux/wireless.h
@@ -611,6 +611,7 @@
#define IW_ENCODE_ALG_WEP 1
#define IW_ENCODE_ALG_TKIP 2
#define IW_ENCODE_ALG_CCMP 3
+#define IW_ENCODE_ALG_PMK 4
/* struct iw_encode_ext ->ext_flags */
#define IW_ENCODE_EXT_TX_SEQ_VALID 0x00000001
#define IW_ENCODE_EXT_RX_SEQ_VALID 0x00000002
@@ -630,6 +631,7 @@
#define IW_ENC_CAPA_WPA2 0x00000002
#define IW_ENC_CAPA_CIPHER_TKIP 0x00000004
#define IW_ENC_CAPA_CIPHER_CCMP 0x00000008
+#define IW_ENC_CAPA_4WAY_HANDSHAKE 0x00000010
/* Event capability macros - in (struct iw_range *)->event_capa
* Because we have more than 32 possible events, we use an array of
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index bbd3d58..06b2814 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -121,7 +121,8 @@
*/
extern int ipv6_addr_label_init(void);
extern void ipv6_addr_label_rtnl_register(void);
-extern u32 ipv6_addr_label(const struct in6_addr *addr,
+extern u32 ipv6_addr_label(struct net *net,
+ const struct in6_addr *addr,
int type, int ifindex);
/*
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/if_inet6.h b/include/net/if_inet6.h
index b2cfc49..db66c79 100644
--- a/include/net/if_inet6.h
+++ b/include/net/if_inet6.h
@@ -148,7 +148,6 @@
#define IFA_HOST IPV6_ADDR_LOOPBACK
#define IFA_LINK IPV6_ADDR_LINKLOCAL
#define IFA_SITE IPV6_ADDR_SITELOCAL
-#define IFA_GLOBAL 0x0000U
struct ipv6_devstat {
struct proc_dir_entry *proc_dir_entry;
diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h
index ad8404b..15e1f8fe 100644
--- a/include/net/inetpeer.h
+++ b/include/net/inetpeer.h
@@ -1,8 +1,6 @@
/*
* INETPEER - A storage for permanent information about peers
*
- * Version: $Id: inetpeer.h,v 1.2 2002/01/12 07:54:56 davem Exp $
- *
* Authors: Andrey V. Savochkin <saw@msu.ru>
*/
diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h
index 6512d85..83b4e00 100644
--- a/include/net/ip6_tunnel.h
+++ b/include/net/ip6_tunnel.h
@@ -1,7 +1,3 @@
-/*
- * $Id$
- */
-
#ifndef _NET_IP6_TUNNEL_H
#define _NET_IP6_TUNNEL_H
@@ -19,7 +15,6 @@
struct ip6_tnl {
struct ip6_tnl *next; /* next tunnel in list */
struct net_device *dev; /* virtual device associated with tunnel */
- struct net_device_stats stat; /* statistics for tunnel device */
int recursion; /* depth of hard_start_xmit recursion */
struct ip6_tnl_parm parms; /* tunnel configuration parameters */
struct flowi fl; /* flowi template for xmit */
diff --git a/include/net/ipconfig.h b/include/net/ipconfig.h
index 3924d7d..c74cc1b 100644
--- a/include/net/ipconfig.h
+++ b/include/net/ipconfig.h
@@ -1,6 +1,4 @@
/*
- * $Id: ipconfig.h,v 1.4 2001/04/30 04:51:46 davem Exp $
- *
* Copyright (C) 1997 Martin Mares
*
* Automatic IP Layer Configuration
diff --git a/include/net/ipip.h b/include/net/ipip.h
index 633ed4d..a85bda6 100644
--- a/include/net/ipip.h
+++ b/include/net/ipip.h
@@ -11,7 +11,6 @@
{
struct ip_tunnel *next;
struct net_device *dev;
- struct net_device_stats stat;
int recursion; /* Depth of hard_start_xmit recursion */
int err_count; /* Number of arrived ICMP errors */
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index e0a612b..7f7db8d 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -4,8 +4,6 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: ipv6.h,v 1.1 2002/05/20 15:13:07 jgrimm Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index dae3f9e..1196de8 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;
@@ -229,91 +201,128 @@
};
/**
- * enum mac80211_tx_control_flags - flags to describe Tx configuration for
- * the Tx frame
+ * enum mac80211_tx_flags - flags to transmission information/status
*
- * These flags are used with the @flags member of &ieee80211_tx_control
+ * These flags are used with the @flags member of &ieee80211_tx_info
*
- * @IEEE80211_TXCTL_REQ_TX_STATUS: request TX status callback for this frame.
- * @IEEE80211_TXCTL_DO_NOT_ENCRYPT: send this frame without encryption;
- * e.g., for EAPOL frame
- * @IEEE80211_TXCTL_USE_RTS_CTS: use RTS-CTS before sending frame
- * @IEEE80211_TXCTL_USE_CTS_PROTECT: use CTS protection for the frame (e.g.,
- * for combined 802.11g / 802.11b networks)
- * @IEEE80211_TXCTL_NO_ACK: tell the low level not to wait for an ack
- * @IEEE80211_TXCTL_RATE_CTRL_PROBE
- * @EEE80211_TXCTL_CLEAR_PS_FILT: clear powersave filter
- * for destination station
- * @IEEE80211_TXCTL_REQUEUE:
- * @IEEE80211_TXCTL_FIRST_FRAGMENT: this is a first fragment of the frame
- * @IEEE80211_TXCTL_LONG_RETRY_LIMIT: this frame should be send using the
- * through set_retry_limit configured long
- * retry value
- * @IEEE80211_TXCTL_EAPOL_FRAME: internal to mac80211
- * @IEEE80211_TXCTL_SEND_AFTER_DTIM: send this frame after DTIM beacon
- * @IEEE80211_TXCTL_AMPDU: this frame should be sent as part of an A-MPDU
- * @IEEE80211_TXCTL_OFDM_HT: this frame can be sent in HT OFDM rates. number
- * of streams when this flag is on can be extracted
- * from antenna_sel_tx, so if 1 antenna is marked
- * use SISO, 2 antennas marked use MIMO, n antennas
- * marked use MIMO_n.
- * @IEEE80211_TXCTL_GREEN_FIELD: use green field protection for this frame
- * @IEEE80211_TXCTL_40_MHZ_WIDTH: send this frame using 40 Mhz channel width
- * @IEEE80211_TXCTL_DUP_DATA: duplicate data frame on both 20 Mhz channels
- * @IEEE80211_TXCTL_SHORT_GI: send this frame using short guard interval
+ * @IEEE80211_TX_CTL_REQ_TX_STATUS: request TX status callback for this frame.
+ * @IEEE80211_TX_CTL_DO_NOT_ENCRYPT: send this frame without encryption;
+ * e.g., for EAPOL frame
+ * @IEEE80211_TX_CTL_USE_RTS_CTS: use RTS-CTS before sending frame
+ * @IEEE80211_TX_CTL_USE_CTS_PROTECT: use CTS protection for the frame (e.g.,
+ * for combined 802.11g / 802.11b networks)
+ * @IEEE80211_TX_CTL_NO_ACK: tell the low level not to wait for an ack
+ * @IEEE80211_TX_CTL_RATE_CTRL_PROBE
+ * @IEEE80211_TX_CTL_CLEAR_PS_FILT: clear powersave filter for destination
+ * station
+ * @IEEE80211_TX_CTL_REQUEUE:
+ * @IEEE80211_TX_CTL_FIRST_FRAGMENT: this is a first fragment of the frame
+ * @IEEE80211_TX_CTL_LONG_RETRY_LIMIT: this frame should be send using the
+ * through set_retry_limit configured long retry value
+ * @IEEE80211_TX_CTL_EAPOL_FRAME: internal to mac80211
+ * @IEEE80211_TX_CTL_SEND_AFTER_DTIM: send this frame after DTIM beacon
+ * @IEEE80211_TX_CTL_AMPDU: this frame should be sent as part of an A-MPDU
+ * @IEEE80211_TX_CTL_OFDM_HT: this frame can be sent in HT OFDM rates. number
+ * of streams when this flag is on can be extracted from antenna_sel_tx,
+ * so if 1 antenna is marked use SISO, 2 antennas marked use MIMO, n
+ * antennas marked use MIMO_n.
+ * @IEEE80211_TX_CTL_GREEN_FIELD: use green field protection for this frame
+ * @IEEE80211_TX_CTL_40_MHZ_WIDTH: send this frame using 40 Mhz channel width
+ * @IEEE80211_TX_CTL_DUP_DATA: duplicate data frame on both 20 Mhz channels
+ * @IEEE80211_TX_CTL_SHORT_GI: send this frame using short guard interval
+ * @IEEE80211_TX_STAT_TX_FILTERED: The frame was not transmitted
+ * because the destination STA was in powersave mode.
+ * @IEEE80211_TX_STAT_ACK: Frame was acknowledged
+ * @IEEE80211_TX_STAT_AMPDU: The frame was aggregated, so status
+ * is for the whole aggregation.
*/
enum mac80211_tx_control_flags {
- IEEE80211_TXCTL_REQ_TX_STATUS = (1<<0),
- IEEE80211_TXCTL_DO_NOT_ENCRYPT = (1<<1),
- IEEE80211_TXCTL_USE_RTS_CTS = (1<<2),
- IEEE80211_TXCTL_USE_CTS_PROTECT = (1<<3),
- IEEE80211_TXCTL_NO_ACK = (1<<4),
- IEEE80211_TXCTL_RATE_CTRL_PROBE = (1<<5),
- IEEE80211_TXCTL_CLEAR_PS_FILT = (1<<6),
- IEEE80211_TXCTL_REQUEUE = (1<<7),
- IEEE80211_TXCTL_FIRST_FRAGMENT = (1<<8),
- IEEE80211_TXCTL_SHORT_PREAMBLE = (1<<9),
- IEEE80211_TXCTL_LONG_RETRY_LIMIT = (1<<10),
- IEEE80211_TXCTL_EAPOL_FRAME = (1<<11),
- IEEE80211_TXCTL_SEND_AFTER_DTIM = (1<<12),
- IEEE80211_TXCTL_AMPDU = (1<<13),
- IEEE80211_TXCTL_OFDM_HT = (1<<14),
- IEEE80211_TXCTL_GREEN_FIELD = (1<<15),
- IEEE80211_TXCTL_40_MHZ_WIDTH = (1<<16),
- IEEE80211_TXCTL_DUP_DATA = (1<<17),
- IEEE80211_TXCTL_SHORT_GI = (1<<18),
+ IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0),
+ IEEE80211_TX_CTL_DO_NOT_ENCRYPT = BIT(1),
+ IEEE80211_TX_CTL_USE_RTS_CTS = BIT(2),
+ IEEE80211_TX_CTL_USE_CTS_PROTECT = BIT(3),
+ IEEE80211_TX_CTL_NO_ACK = BIT(4),
+ IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(5),
+ IEEE80211_TX_CTL_CLEAR_PS_FILT = BIT(6),
+ IEEE80211_TX_CTL_REQUEUE = BIT(7),
+ IEEE80211_TX_CTL_FIRST_FRAGMENT = BIT(8),
+ IEEE80211_TX_CTL_SHORT_PREAMBLE = BIT(9),
+ IEEE80211_TX_CTL_LONG_RETRY_LIMIT = BIT(10),
+ IEEE80211_TX_CTL_EAPOL_FRAME = BIT(11),
+ IEEE80211_TX_CTL_SEND_AFTER_DTIM = BIT(12),
+ IEEE80211_TX_CTL_AMPDU = BIT(13),
+ IEEE80211_TX_CTL_OFDM_HT = BIT(14),
+ IEEE80211_TX_CTL_GREEN_FIELD = BIT(15),
+ IEEE80211_TX_CTL_40_MHZ_WIDTH = BIT(16),
+ IEEE80211_TX_CTL_DUP_DATA = BIT(17),
+ IEEE80211_TX_CTL_SHORT_GI = BIT(18),
+ IEEE80211_TX_CTL_INJECTED = BIT(19),
+ IEEE80211_TX_STAT_TX_FILTERED = BIT(20),
+ IEEE80211_TX_STAT_ACK = BIT(21),
+ IEEE80211_TX_STAT_AMPDU = BIT(22),
};
-/* Transmit control fields. This data structure is passed to low-level driver
- * with each TX frame. The low-level driver is responsible for configuring
- * the hardware to use given values (depending on what is supported). */
-struct ieee80211_tx_control {
- struct ieee80211_vif *vif;
- struct ieee80211_rate *tx_rate;
+#define IEEE80211_TX_INFO_DRIVER_DATA_SIZE \
+ (sizeof(((struct sk_buff *)0)->cb) - 8)
+#define IEEE80211_TX_INFO_DRIVER_DATA_PTRS \
+ (IEEE80211_TX_INFO_DRIVER_DATA_SIZE / sizeof(void *))
- /* Transmit rate for RTS/CTS frame */
- struct ieee80211_rate *rts_cts_rate;
+/**
+ * struct ieee80211_tx_info - skb transmit information
+ *
+ * This structure is placed in skb->cb for three uses:
+ * (1) mac80211 TX control - mac80211 tells the driver what to do
+ * (2) driver internal use (if applicable)
+ * (3) TX status information - driver tells mac80211 what happened
+ *
+ * @flags: transmit info flags, defined above
+ * @retry_count: number of retries
+ * @excessive_retries: set to 1 if the frame was retried many times
+ * but not acknowledged
+ * @ampdu_ack_len: number of aggregated frames.
+ * relevant only if IEEE80211_TX_STATUS_AMPDU was set.
+ * @ampdu_ack_map: block ack bit map for the aggregation.
+ * relevant only if IEEE80211_TX_STATUS_AMPDU was set.
+ * @ack_signal: signal strength of the ACK frame
+ */
+struct ieee80211_tx_info {
+ /* common information */
+ u32 flags;
+ u8 band;
+ s8 tx_rate_idx;
+ u8 antenna_sel_tx;
- /* retry rate for the last retries */
- struct ieee80211_rate *alt_retry_rate;
+ /* 1 byte hole */
- u32 flags; /* tx control flags defined above */
- u8 key_idx; /* keyidx from hw->set_key(), undefined if
- * IEEE80211_TXCTL_DO_NOT_ENCRYPT is set */
- u8 retry_limit; /* 1 = only first attempt, 2 = one retry, ..
- * This could be used when set_retry_limit
- * is not implemented by the driver */
- u8 antenna_sel_tx; /* 0 = default/diversity, otherwise bit
- * position represents antenna number used */
- u8 icv_len; /* length of the ICV/MIC field in octets */
- u8 iv_len; /* length of the IV field in octets */
- u8 queue; /* hardware queue to use for this frame;
- * 0 = highest, hw->queues-1 = lowest */
- u16 aid; /* Station AID */
- int type; /* internal */
+ union {
+ struct {
+ struct ieee80211_vif *vif;
+ struct ieee80211_key_conf *hw_key;
+ unsigned long jiffies;
+ int ifindex;
+ u16 aid;
+ s8 rts_cts_rate_idx, alt_retry_rate_idx;
+ u8 retry_limit;
+ u8 icv_len;
+ u8 iv_len;
+ } control;
+ struct {
+ u64 ampdu_ack_map;
+ int ack_signal;
+ u8 retry_count;
+ bool excessive_retries;
+ u8 ampdu_ack_len;
+ } status;
+ void *driver_data[IEEE80211_TX_INFO_DRIVER_DATA_PTRS];
+ };
};
+static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb)
+{
+ return (struct ieee80211_tx_info *)skb->cb;
+}
+
/**
* enum mac80211_rx_flags - receive flags
@@ -353,13 +362,16 @@
* The low-level driver should provide this information (the subset
* supported by hardware) to the 802.11 code with each received
* frame.
+ *
* @mactime: value in microseconds of the 64-bit Time Synchronization Function
* (TSF) timer when the first data symbol (MPDU) arrived at the hardware.
* @band: the active band when this frame was received
* @freq: frequency the radio was tuned to when receiving this frame, in MHz
- * @ssi: signal strength when receiving this frame
- * @signal: used as 'qual' in statistics reporting
- * @noise: PHY noise when receiving this frame
+ * @signal: signal strength when receiving this frame, either in dBm, in dB or
+ * unspecified depending on the hardware capabilities flags
+ * @IEEE80211_HW_SIGNAL_*
+ * @noise: noise when receiving this frame, in dBm.
+ * @qual: overall signal quality indication, in percent (0-100).
* @antenna: antenna used
* @rate_idx: index of data rate into band's supported rates
* @flag: %RX_FLAG_*
@@ -368,64 +380,15 @@
u64 mactime;
enum ieee80211_band band;
int freq;
- int ssi;
int signal;
int noise;
+ int qual;
int antenna;
int rate_idx;
int flag;
};
/**
- * enum ieee80211_tx_status_flags - transmit status flags
- *
- * Status flags to indicate various transmit conditions.
- *
- * @IEEE80211_TX_STATUS_TX_FILTERED: The frame was not transmitted
- * because the destination STA was in powersave mode.
- * @IEEE80211_TX_STATUS_ACK: Frame was acknowledged
- * @IEEE80211_TX_STATUS_AMPDU: The frame was aggregated, so status
- * is for the whole aggregation.
- */
-enum ieee80211_tx_status_flags {
- IEEE80211_TX_STATUS_TX_FILTERED = 1<<0,
- IEEE80211_TX_STATUS_ACK = 1<<1,
- IEEE80211_TX_STATUS_AMPDU = 1<<2,
-};
-
-/**
- * struct ieee80211_tx_status - transmit status
- *
- * As much information as possible should be provided for each transmitted
- * frame with ieee80211_tx_status().
- *
- * @control: a copy of the &struct ieee80211_tx_control passed to the driver
- * in the tx() callback.
- * @flags: transmit status flags, defined above
- * @retry_count: number of retries
- * @excessive_retries: set to 1 if the frame was retried many times
- * but not acknowledged
- * @ampdu_ack_len: number of aggregated frames.
- * relevant only if IEEE80211_TX_STATUS_AMPDU was set.
- * @ampdu_ack_map: block ack bit map for the aggregation.
- * relevant only if IEEE80211_TX_STATUS_AMPDU was set.
- * @ack_signal: signal strength of the ACK frame
- * @queue_length: ?? REMOVE
- * @queue_number: ?? REMOVE
- */
-struct ieee80211_tx_status {
- struct ieee80211_tx_control control;
- u8 flags;
- u8 retry_count;
- bool excessive_retries;
- u8 ampdu_ack_len;
- u64 ampdu_ack_map;
- int ack_signal;
- int queue_length;
- int queue_number;
-};
-
-/**
* enum ieee80211_conf_flags - configuration flags
*
* Flags to define PHY configuration options
@@ -580,7 +543,6 @@
u8 *ssid;
size_t ssid_len;
struct sk_buff *beacon;
- struct ieee80211_tx_control *beacon_control;
};
/**
@@ -610,11 +572,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,
};
/**
@@ -721,6 +686,25 @@
* @IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE:
* Hardware is not capable of receiving frames with short preamble on
* the 2.4 GHz band.
+ *
+ * @IEEE80211_HW_SIGNAL_UNSPEC:
+ * Hardware can provide signal values but we don't know its units. We
+ * expect values between 0 and @max_signal.
+ * If possible please provide dB or dBm instead.
+ *
+ * @IEEE80211_HW_SIGNAL_DB:
+ * Hardware gives signal values in dB, decibel difference from an
+ * arbitrary, fixed reference. We expect values between 0 and @max_signal.
+ * If possible please provide dBm instead.
+ *
+ * @IEEE80211_HW_SIGNAL_DBM:
+ * Hardware gives signal values in dBm, decibel difference from
+ * one milliwatt. This is the preferred method since it is standardized
+ * between different devices. @max_signal does not need to be set.
+ *
+ * @IEEE80211_HW_NOISE_DBM:
+ * Hardware can provide noise (radio interference) values in units dBm,
+ * decibel difference from one milliwatt.
*/
enum ieee80211_hw_flags {
IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE = 1<<0,
@@ -728,6 +712,10 @@
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING = 1<<2,
IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE = 1<<3,
IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE = 1<<4,
+ IEEE80211_HW_SIGNAL_UNSPEC = 1<<5,
+ IEEE80211_HW_SIGNAL_DB = 1<<6,
+ IEEE80211_HW_SIGNAL_DBM = 1<<7,
+ IEEE80211_HW_NOISE_DBM = 1<<8,
};
/**
@@ -758,15 +746,18 @@
*
* @channel_change_time: time (in microseconds) it takes to change channels.
*
- * @max_rssi: Maximum value for ssi in RX information, use
- * negative numbers for dBm and 0 to indicate no support.
- *
- * @max_signal: like @max_rssi, but for the signal value.
- *
- * @max_noise: like @max_rssi, but for the noise value.
+ * @max_signal: Maximum value for signal (rssi) in RX information, used
+ * only when @IEEE80211_HW_SIGNAL_UNSPEC or @IEEE80211_HW_SIGNAL_DB
*
* @queues: number of available hardware transmit queues for
- * data packets. WMM/QoS requires at least four.
+ * data packets. WMM/QoS requires at least four, these
+ * queues need to have configurable access parameters.
+ *
+ * @ampdu_queues: number of available hardware transmit queues
+ * for A-MPDU packets, these have no access parameters
+ * because they're used only for A-MPDU frames. Note that
+ * mac80211 will not currently use any of the regular queues
+ * for aggregation.
*
* @rate_control_algorithm: rate control algorithm for this hardware.
* If unset (NULL), the default algorithm will be used. Must be
@@ -785,10 +776,8 @@
unsigned int extra_tx_headroom;
int channel_change_time;
int vif_data_size;
- u8 queues;
- s8 max_rssi;
+ u16 queues, ampdu_queues;
s8 max_signal;
- s8 max_noise;
};
/**
@@ -813,6 +802,51 @@
memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN);
}
+static inline int ieee80211_num_regular_queues(struct ieee80211_hw *hw)
+{
+#ifdef CONFIG_MAC80211_QOS
+ return hw->queues;
+#else
+ return 1;
+#endif
+}
+
+static inline int ieee80211_num_queues(struct ieee80211_hw *hw)
+{
+#ifdef CONFIG_MAC80211_QOS
+ return hw->queues + hw->ampdu_queues;
+#else
+ return 1;
+#endif
+}
+
+static inline struct ieee80211_rate *
+ieee80211_get_tx_rate(const struct ieee80211_hw *hw,
+ const struct ieee80211_tx_info *c)
+{
+ if (WARN_ON(c->tx_rate_idx < 0))
+ return NULL;
+ return &hw->wiphy->bands[c->band]->bitrates[c->tx_rate_idx];
+}
+
+static inline struct ieee80211_rate *
+ieee80211_get_rts_cts_rate(const struct ieee80211_hw *hw,
+ const struct ieee80211_tx_info *c)
+{
+ if (c->control.rts_cts_rate_idx < 0)
+ return NULL;
+ return &hw->wiphy->bands[c->band]->bitrates[c->control.rts_cts_rate_idx];
+}
+
+static inline struct ieee80211_rate *
+ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
+ const struct ieee80211_tx_info *c)
+{
+ if (c->control.alt_retry_rate_idx < 0)
+ return NULL;
+ return &hw->wiphy->bands[c->band]->bitrates[c->control.alt_retry_rate_idx];
+}
+
/**
* DOC: Hardware crypto acceleration
*
@@ -970,8 +1004,10 @@
* @tx: Handler that 802.11 module calls for each transmitted frame.
* skb contains the buffer starting from the IEEE 802.11 header.
* The low-level driver should send the frame out based on
- * configuration in the TX control data. Must be implemented and
- * atomic.
+ * configuration in the TX control data. This handler should,
+ * preferably, never fail and stop queues appropriately, more
+ * importantly, however, it must never fail for A-MPDU-queues.
+ * Must be implemented and atomic.
*
* @start: Called before the first netdevice attached to the hardware
* is enabled. This should turn on the hardware and must turn on
@@ -1063,15 +1099,13 @@
* of assocaited station or AP.
*
* @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
- * bursting) for a hardware TX queue. The @queue parameter uses the
- * %IEEE80211_TX_QUEUE_* constants. Must be atomic.
+ * bursting) for a hardware TX queue. Must be atomic.
*
* @get_tx_stats: Get statistics of the current TX queue status. This is used
* to get number of currently queued packets (queue length), maximum queue
* size (limit), and total number of packets sent using each TX queue
- * (count). This information is used for WMM to find out which TX
- * queues have room for more packets and by hostapd to provide
- * statistics about the current queueing state to external programs.
+ * (count). The 'stats' pointer points to an array that has hw->queues +
+ * hw->ampdu_queues items.
*
* @get_tsf: Get the current TSF timer value from firmware/hardware. Currently,
* this is only used for IBSS mode debugging and, as such, is not a
@@ -1107,8 +1141,7 @@
* that TX/RX_STOP can pass NULL for this parameter.
*/
struct ieee80211_ops {
- int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_control *control);
+ int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
int (*start)(struct ieee80211_hw *hw);
void (*stop)(struct ieee80211_hw *hw);
int (*add_interface)(struct ieee80211_hw *hw,
@@ -1145,15 +1178,14 @@
u32 short_retry, u32 long_retr);
void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum sta_notify_cmd, const u8 *addr);
- int (*conf_tx)(struct ieee80211_hw *hw, int queue,
+ int (*conf_tx)(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params);
int (*get_tx_stats)(struct ieee80211_hw *hw,
struct ieee80211_tx_queue_stats *stats);
u64 (*get_tsf)(struct ieee80211_hw *hw);
void (*reset_tsf)(struct ieee80211_hw *hw);
int (*beacon_update)(struct ieee80211_hw *hw,
- struct sk_buff *skb,
- struct ieee80211_tx_control *control);
+ struct sk_buff *skb);
int (*tx_last_beacon)(struct ieee80211_hw *hw);
int (*ampdu_action)(struct ieee80211_hw *hw,
enum ieee80211_ampdu_mlme_action action,
@@ -1349,13 +1381,9 @@
*
* @hw: the hardware the frame was transmitted by
* @skb: the frame that was transmitted, owned by mac80211 after this call
- * @status: status information for this frame; the status pointer need not
- * be valid after this function returns and is not freed by mac80211,
- * it is recommended that it points to a stack area
*/
void ieee80211_tx_status(struct ieee80211_hw *hw,
- struct sk_buff *skb,
- struct ieee80211_tx_status *status);
+ struct sk_buff *skb);
/**
* ieee80211_tx_status_irqsafe - irq-safe transmit status callback
@@ -1368,13 +1396,9 @@
*
* @hw: the hardware the frame was transmitted by
* @skb: the frame that was transmitted, owned by mac80211 after this call
- * @status: status information for this frame; the status pointer need not
- * be valid after this function returns and is not freed by mac80211,
- * it is recommended that it points to a stack area
*/
void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
- struct sk_buff *skb,
- struct ieee80211_tx_status *status);
+ struct sk_buff *skb);
/**
* ieee80211_beacon_get - beacon generation function
@@ -1390,8 +1414,7 @@
* is responsible of freeing it.
*/
struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_tx_control *control);
+ struct ieee80211_vif *vif);
/**
* ieee80211_rts_get - RTS frame generation function
@@ -1399,7 +1422,7 @@
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
* @frame: pointer to the frame that is going to be protected by the RTS.
* @frame_len: the frame length (in octets).
- * @frame_txctl: &struct ieee80211_tx_control of the frame.
+ * @frame_txctl: &struct ieee80211_tx_info of the frame.
* @rts: The buffer where to store the RTS frame.
*
* If the RTS frames are generated by the host system (i.e., not in
@@ -1409,7 +1432,7 @@
*/
void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
const void *frame, size_t frame_len,
- const struct ieee80211_tx_control *frame_txctl,
+ const struct ieee80211_tx_info *frame_txctl,
struct ieee80211_rts *rts);
/**
@@ -1417,7 +1440,7 @@
* @hw: pointer obtained from ieee80211_alloc_hw().
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
* @frame_len: the length of the frame that is going to be protected by the RTS.
- * @frame_txctl: &struct ieee80211_tx_control of the frame.
+ * @frame_txctl: &struct ieee80211_tx_info of the frame.
*
* If the RTS is generated in firmware, but the host system must provide
* the duration field, the low-level driver uses this function to receive
@@ -1425,7 +1448,7 @@
*/
__le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, size_t frame_len,
- const struct ieee80211_tx_control *frame_txctl);
+ const struct ieee80211_tx_info *frame_txctl);
/**
* ieee80211_ctstoself_get - CTS-to-self frame generation function
@@ -1433,7 +1456,7 @@
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
* @frame: pointer to the frame that is going to be protected by the CTS-to-self.
* @frame_len: the frame length (in octets).
- * @frame_txctl: &struct ieee80211_tx_control of the frame.
+ * @frame_txctl: &struct ieee80211_tx_info of the frame.
* @cts: The buffer where to store the CTS-to-self frame.
*
* If the CTS-to-self frames are generated by the host system (i.e., not in
@@ -1444,7 +1467,7 @@
void ieee80211_ctstoself_get(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
const void *frame, size_t frame_len,
- const struct ieee80211_tx_control *frame_txctl,
+ const struct ieee80211_tx_info *frame_txctl,
struct ieee80211_cts *cts);
/**
@@ -1452,7 +1475,7 @@
* @hw: pointer obtained from ieee80211_alloc_hw().
* @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf.
* @frame_len: the length of the frame that is going to be protected by the CTS-to-self.
- * @frame_txctl: &struct ieee80211_tx_control of the frame.
+ * @frame_txctl: &struct ieee80211_tx_info of the frame.
*
* If the CTS-to-self is generated in firmware, but the host system must provide
* the duration field, the low-level driver uses this function to receive
@@ -1461,7 +1484,7 @@
__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
size_t frame_len,
- const struct ieee80211_tx_control *frame_txctl);
+ const struct ieee80211_tx_info *frame_txctl);
/**
* ieee80211_generic_frame_duration - Calculate the duration field for a frame
@@ -1500,8 +1523,7 @@
* use common code for all beacons.
*/
struct sk_buff *
-ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_tx_control *control);
+ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
/**
* ieee80211_get_hdrlen_from_skb - get header length from data
@@ -1559,14 +1581,6 @@
void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue);
/**
- * ieee80211_start_queues - start all queues
- * @hw: pointer to as obtained from ieee80211_alloc_hw().
- *
- * Drivers should use this function instead of netif_start_queue.
- */
-void ieee80211_start_queues(struct ieee80211_hw *hw);
-
-/**
* ieee80211_stop_queues - stop all queues
* @hw: pointer as obtained from ieee80211_alloc_hw().
*
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index aa540e6..8df751b 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -201,8 +201,11 @@
struct ctl_path;
struct ctl_table;
struct ctl_table_header;
+
extern struct ctl_table_header *register_net_sysctl_table(struct net *net,
const struct ctl_path *path, struct ctl_table *table);
+extern struct ctl_table_header *register_net_sysctl_rotable(
+ const struct ctl_path *path, struct ctl_table *table);
extern void unregister_net_sysctl_table(struct ctl_table_header *header);
#endif /* __NET_NET_NAMESPACE_H */
diff --git a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h
index 9bf0598..7573d52 100644
--- a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h
+++ b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h
@@ -9,8 +9,6 @@
#ifndef _NF_CONNTRACK_IPV4_H
#define _NF_CONNTRACK_IPV4_H
-/* Returns new sk_buff, or NULL */
-struct sk_buff *nf_ct_ipv4_ct_gather_frags(struct sk_buff *skb);
extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4;
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index 2dbd6c0..d77dec7 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -223,6 +223,25 @@
__nf_ct_refresh_acct(ct, 0, skb, extra_jiffies, 0);
}
+extern void __nf_ct_kill_acct(struct nf_conn *ct,
+ enum ip_conntrack_info ctinfo,
+ const struct sk_buff *skb,
+ int do_acct);
+
+/* kill conntrack and do accounting */
+static inline void nf_ct_kill_acct(struct nf_conn *ct,
+ enum ip_conntrack_info ctinfo,
+ const struct sk_buff *skb)
+{
+ __nf_ct_kill_acct(ct, ctinfo, skb, 1);
+}
+
+/* kill conntrack without accounting */
+static inline void nf_ct_kill(struct nf_conn *ct)
+{
+ __nf_ct_kill_acct(ct, 0, NULL, 0);
+}
+
/* These are for NAT. Icky. */
/* Update TCP window tracking data when NAT mangles the packet */
extern void nf_conntrack_tcp_update(const struct sk_buff *skb,
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
index 34ee348..6ef90b5 100644
--- a/include/net/netns/ipv4.h
+++ b/include/net/netns/ipv4.h
@@ -36,6 +36,7 @@
struct xt_table *iptable_mangle;
struct xt_table *iptable_raw;
struct xt_table *arptable_filter;
+ struct xt_table *iptable_security;
#endif
int sysctl_icmp_echo_ignore_all;
diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
index ac053be..5bacd83 100644
--- a/include/net/netns/ipv6.h
+++ b/include/net/netns/ipv6.h
@@ -35,6 +35,7 @@
struct xt_table *ip6table_filter;
struct xt_table *ip6table_mangle;
struct xt_table *ip6table_raw;
+ struct xt_table *ip6table_security;
#endif
struct rt6_info *ip6_null_entry;
struct rt6_statistics *rt6_stats;
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 7f25195..fbc27ac 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;
@@ -946,6 +947,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.
@@ -1553,6 +1555,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? */
@@ -1662,6 +1665,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..f205b10f 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/snmp.h b/include/net/snmp.h
index ce2f485..57c9362 100644
--- a/include/net/snmp.h
+++ b/include/net/snmp.h
@@ -14,8 +14,6 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * $Id: snmp.h,v 1.19 2001/06/14 13:40:46 davem Exp $
- *
*/
#ifndef _SNMP_H
diff --git a/include/net/tcp.h b/include/net/tcp.h
index cf54034..b5a1b9e 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -398,6 +398,8 @@
struct tcp_options_received *opt_rx,
int estab);
+extern u8 *tcp_parse_md5sig_option(struct tcphdr *th);
+
/*
* TCP v4 functions exported for the inet6 API
*/
@@ -1113,13 +1115,19 @@
#define TCP_MD5SIG_MAXKEYS (~(u32)0) /* really?! */
/* - functions */
+extern int tcp_calc_md5_hash(char *md5_hash,
+ struct tcp_md5sig_key *key,
+ int bplen,
+ struct tcphdr *th,
+ unsigned int tcplen,
+ struct tcp_md5sig_pool *hp);
+
extern int tcp_v4_calc_md5_hash(char *md5_hash,
struct tcp_md5sig_key *key,
struct sock *sk,
struct dst_entry *dst,
struct request_sock *req,
struct tcphdr *th,
- int protocol,
unsigned int tcplen);
extern struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk,
struct sock *addr_sk);
@@ -1132,6 +1140,16 @@
extern int tcp_v4_md5_do_del(struct sock *sk,
__be32 addr);
+#ifdef CONFIG_TCP_MD5SIG
+#define tcp_twsk_md5_key(twsk) ((twsk)->tw_md5_keylen ? \
+ &(struct tcp_md5sig_key) { \
+ .key = (twsk)->tw_md5_key, \
+ .keylen = (twsk)->tw_md5_keylen, \
+ } : NULL)
+#else
+#define tcp_twsk_md5_key(twsk) NULL
+#endif
+
extern struct tcp_md5sig_pool **tcp_alloc_md5sig_pool(void);
extern void tcp_free_md5sig_pool(void);
@@ -1369,7 +1387,6 @@
struct dst_entry *dst,
struct request_sock *req,
struct tcphdr *th,
- int protocol,
unsigned int len);
int (*md5_add) (struct sock *sk,
struct sock *addr_sk,
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/include/net/udp.h b/include/net/udp.h
index ccce837..7a86848 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -196,8 +196,8 @@
struct udp_iter_state {
struct seq_net_private p;
sa_family_t family;
- struct hlist_head *hashtable;
int bucket;
+ struct hlist_head *hashtable;
};
#ifdef CONFIG_PROC_FS
diff --git a/include/net/wireless.h b/include/net/wireless.h
index 667b408..9324f8d 100644
--- a/include/net/wireless.h
+++ b/include/net/wireless.h
@@ -39,12 +39,18 @@
* on this channel.
* @IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel.
* @IEEE80211_CHAN_RADAR: Radar detection is required on this channel.
+ * @IEEE80211_CHAN_NO_FAT_ABOVE: extension channel above this channel
+ * is not permitted.
+ * @IEEE80211_CHAN_NO_FAT_BELOW: extension channel below this channel
+ * is not permitted.
*/
enum ieee80211_channel_flags {
IEEE80211_CHAN_DISABLED = 1<<0,
IEEE80211_CHAN_PASSIVE_SCAN = 1<<1,
IEEE80211_CHAN_NO_IBSS = 1<<2,
IEEE80211_CHAN_RADAR = 1<<3,
+ IEEE80211_CHAN_NO_FAT_ABOVE = 1<<4,
+ IEEE80211_CHAN_NO_FAT_BELOW = 1<<5,
};
/**
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index b3b69fd..3e84b95 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -1054,7 +1054,7 @@
}
timeo = MAX_SCHEDULE_TIMEOUT;
- ret = netlink_attachskb(sock, nc, 0, &timeo, NULL);
+ ret = netlink_attachskb(sock, nc, &timeo, NULL);
if (ret == 1)
goto retry;
if (ret) {
diff --git a/net/bluetooth/bnep/bnep.h b/net/bluetooth/bnep/bnep.h
index e69244d..b69bf4e 100644
--- a/net/bluetooth/bnep/bnep.h
+++ b/net/bluetooth/bnep/bnep.h
@@ -16,10 +16,6 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-/*
- * $Id: bnep.h,v 1.5 2002/08/04 21:23:58 maxk Exp $
- */
-
#ifndef _BNEP_H
#define _BNEP_H
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index f85d946..1d98a1b 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -25,10 +25,6 @@
SOFTWARE IS DISCLAIMED.
*/
-/*
- * $Id: core.c,v 1.20 2002/08/04 21:23:58 maxk Exp $
- */
-
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c
index 95e3837..d9fa0ab 100644
--- a/net/bluetooth/bnep/netdev.c
+++ b/net/bluetooth/bnep/netdev.c
@@ -25,10 +25,6 @@
SOFTWARE IS DISCLAIMED.
*/
-/*
- * $Id: netdev.c,v 1.8 2002/08/04 21:23:58 maxk Exp $
- */
-
#include <linux/module.h>
#include <linux/socket.h>
diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c
index 201e5b1..8ffb57f 100644
--- a/net/bluetooth/bnep/sock.c
+++ b/net/bluetooth/bnep/sock.c
@@ -24,10 +24,6 @@
SOFTWARE IS DISCLAIMED.
*/
-/*
- * $Id: sock.c,v 1.4 2002/08/04 21:23:58 maxk Exp $
- */
-
#include <linux/module.h>
#include <linux/types.h>
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 0c2c937..b4fb84e 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -23,8 +23,6 @@
/*
* Bluetooth RFCOMM core.
- *
- * $Id: core.c,v 1.42 2002/10/01 23:26:25 maxk Exp $
*/
#include <linux/module.h>
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 5083adc..c905448 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -23,8 +23,6 @@
/*
* RFCOMM sockets.
- *
- * $Id: sock.c,v 1.24 2002/10/03 01:00:34 maxk Exp $
*/
#include <linux/module.h>
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index c919187..be84f4f 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -23,8 +23,6 @@
/*
* RFCOMM TTY.
- *
- * $Id: tty.c,v 1.24 2002/10/03 01:54:38 holtmann Exp $
*/
#include <linux/module.h>
diff --git a/net/bridge/br.c b/net/bridge/br.c
index 8f3c58e..cede010 100644
--- a/net/bridge/br.c
+++ b/net/bridge/br.c
@@ -5,8 +5,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br.c,v 1.47 2001/12/24 00:56:41 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index bf77873..a6ffc6c 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -5,8 +5,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_device.c,v 1.6 2001/12/24 00:59:55 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -21,12 +19,6 @@
#include <asm/uaccess.h>
#include "br_private.h"
-static struct net_device_stats *br_dev_get_stats(struct net_device *dev)
-{
- struct net_bridge *br = netdev_priv(dev);
- return &br->statistics;
-}
-
/* net device transmit always called with no BH (preempt_disabled) */
int br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
{
@@ -34,8 +26,8 @@
const unsigned char *dest = skb->data;
struct net_bridge_fdb_entry *dst;
- br->statistics.tx_packets++;
- br->statistics.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
skb_reset_mac_header(skb);
skb_pull(skb, ETH_HLEN);
@@ -161,7 +153,6 @@
ether_setup(dev);
dev->do_ioctl = br_dev_ioctl;
- dev->get_stats = br_dev_get_stats;
dev->hard_start_xmit = br_dev_xmit;
dev->open = br_dev_open;
dev->set_multicast_list = br_dev_set_multicast_list;
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 72c5976..4de74cd 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -5,8 +5,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_fdb.c,v 1.6 2002/01/17 00:57:07 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index bdd7c35..5126457 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -5,8 +5,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_forward.c,v 1.4 2001/08/14 22:05:57 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -115,7 +113,7 @@
struct sk_buff *skb2;
if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) {
- br->statistics.tx_dropped++;
+ br->dev->stats.tx_dropped++;
kfree_skb(skb);
return;
}
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index c2397f5..143c954 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -5,8 +5,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_if.c,v 1.7 2001/12/24 00:59:55 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 255c00f..0145e94 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -5,8 +5,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_input.c,v 1.10 2001/12/24 04:50:20 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -24,13 +22,13 @@
static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb)
{
- struct net_device *indev;
+ struct net_device *indev, *brdev = br->dev;
- br->statistics.rx_packets++;
- br->statistics.rx_bytes += skb->len;
+ brdev->stats.rx_packets++;
+ brdev->stats.rx_bytes += skb->len;
indev = skb->dev;
- skb->dev = br->dev;
+ skb->dev = brdev;
NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,
netif_receive_skb);
@@ -64,7 +62,7 @@
dst = NULL;
if (is_multicast_ether_addr(dest)) {
- br->statistics.multicast++;
+ br->dev->stats.multicast++;
skb2 = skb;
} else if ((dst = __br_fdb_get(br, dest)) && dst->is_local) {
skb2 = skb;
diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
index 0655a5f..eeee218 100644
--- a/net/bridge/br_ioctl.c
+++ b/net/bridge/br_ioctl.c
@@ -5,8 +5,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_ioctl.c,v 1.4 2000/11/08 05:16:40 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c
index 00644a5..88d8ec7b 100644
--- a/net/bridge/br_notify.c
+++ b/net/bridge/br_notify.c
@@ -5,8 +5,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_notify.c,v 1.2 2000/02/21 15:51:34 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index c11b554..83ff586 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -4,8 +4,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_private.h,v 1.7 2001/12/24 00:59:55 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -90,7 +88,6 @@
spinlock_t lock;
struct list_head port_list;
struct net_device *dev;
- struct net_device_stats statistics;
spinlock_t hash_lock;
struct hlist_head hash[BR_HASH_SIZE];
struct list_head age_list;
diff --git a/net/bridge/br_private_stp.h b/net/bridge/br_private_stp.h
index e29f01a..8b650f7 100644
--- a/net/bridge/br_private_stp.h
+++ b/net/bridge/br_private_stp.h
@@ -4,8 +4,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_private_stp.h,v 1.3 2001/02/05 06:03:47 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
index e38034a..284d1b2 100644
--- a/net/bridge/br_stp.c
+++ b/net/bridge/br_stp.c
@@ -5,8 +5,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_stp.c,v 1.4 2000/06/19 10:13:35 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c
index ddeb6e5..9dc2de6 100644
--- a/net/bridge/br_stp_bpdu.c
+++ b/net/bridge/br_stp_bpdu.c
@@ -5,8 +5,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_stp_bpdu.c,v 1.3 2001/11/10 02:35:25 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index 1a430ec..1a4e5c3 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -5,8 +5,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_stp_if.c,v 1.4 2001/04/14 21:14:39 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/bridge/br_stp_timer.c b/net/bridge/br_stp_timer.c
index 77f5255..772a140 100644
--- a/net/bridge/br_stp_timer.c
+++ b/net/bridge/br_stp_timer.c
@@ -5,8 +5,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_stp_timer.c,v 1.3 2000/05/05 02:17:17 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig
index 7beeefa..fb684c2 100644
--- a/net/bridge/netfilter/Kconfig
+++ b/net/bridge/netfilter/Kconfig
@@ -83,6 +83,15 @@
To compile it as a module, choose M here. If unsure, say N.
+config BRIDGE_EBT_IP6
+ tristate "ebt: IP6 filter support"
+ depends on BRIDGE_NF_EBTABLES
+ help
+ This option adds the IP6 match, which allows basic IPV6 header field
+ filtering.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config BRIDGE_EBT_LIMIT
tristate "ebt: limit match support"
depends on BRIDGE_NF_EBTABLES
diff --git a/net/bridge/netfilter/Makefile b/net/bridge/netfilter/Makefile
index 83715d7..dd96064 100644
--- a/net/bridge/netfilter/Makefile
+++ b/net/bridge/netfilter/Makefile
@@ -14,6 +14,7 @@
obj-$(CONFIG_BRIDGE_EBT_AMONG) += ebt_among.o
obj-$(CONFIG_BRIDGE_EBT_ARP) += ebt_arp.o
obj-$(CONFIG_BRIDGE_EBT_IP) += ebt_ip.o
+obj-$(CONFIG_BRIDGE_EBT_IP) += ebt_ip6.o
obj-$(CONFIG_BRIDGE_EBT_LIMIT) += ebt_limit.o
obj-$(CONFIG_BRIDGE_EBT_MARK) += ebt_mark_m.o
obj-$(CONFIG_BRIDGE_EBT_PKTTYPE) += ebt_pkttype.o
diff --git a/net/bridge/netfilter/ebt_ip6.c b/net/bridge/netfilter/ebt_ip6.c
new file mode 100644
index 0000000..36efb3a
--- /dev/null
+++ b/net/bridge/netfilter/ebt_ip6.c
@@ -0,0 +1,144 @@
+/*
+ * ebt_ip6
+ *
+ * Authors:
+ * Manohar Castelino <manohar.r.castelino@intel.com>
+ * Kuo-Lang Tseng <kuo-lang.tseng@intel.com>
+ * Jan Engelhardt <jengelh@computergmbh.de>
+ *
+ * Summary:
+ * This is just a modification of the IPv4 code written by
+ * Bart De Schuymer <bdschuym@pandora.be>
+ * with the changes required to support IPv6
+ *
+ * Jan, 2008
+ */
+
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_ip6.h>
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
+#include <linux/in.h>
+#include <linux/module.h>
+#include <net/dsfield.h>
+
+struct tcpudphdr {
+ __be16 src;
+ __be16 dst;
+};
+
+static int ebt_filter_ip6(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out, const void *data,
+ unsigned int datalen)
+{
+ const struct ebt_ip6_info *info = (struct ebt_ip6_info *)data;
+ const struct ipv6hdr *ih6;
+ struct ipv6hdr _ip6h;
+ const struct tcpudphdr *pptr;
+ struct tcpudphdr _ports;
+ struct in6_addr tmp_addr;
+ int i;
+
+ ih6 = skb_header_pointer(skb, 0, sizeof(_ip6h), &_ip6h);
+ if (ih6 == NULL)
+ return EBT_NOMATCH;
+ if (info->bitmask & EBT_IP6_TCLASS &&
+ FWINV(info->tclass != ipv6_get_dsfield(ih6), EBT_IP6_TCLASS))
+ return EBT_NOMATCH;
+ for (i = 0; i < 4; i++)
+ tmp_addr.in6_u.u6_addr32[i] = ih6->saddr.in6_u.u6_addr32[i] &
+ info->smsk.in6_u.u6_addr32[i];
+ if (info->bitmask & EBT_IP6_SOURCE &&
+ FWINV((ipv6_addr_cmp(&tmp_addr, &info->saddr) != 0),
+ EBT_IP6_SOURCE))
+ return EBT_NOMATCH;
+ for (i = 0; i < 4; i++)
+ tmp_addr.in6_u.u6_addr32[i] = ih6->daddr.in6_u.u6_addr32[i] &
+ info->dmsk.in6_u.u6_addr32[i];
+ if (info->bitmask & EBT_IP6_DEST &&
+ FWINV((ipv6_addr_cmp(&tmp_addr, &info->daddr) != 0), EBT_IP6_DEST))
+ return EBT_NOMATCH;
+ if (info->bitmask & EBT_IP6_PROTO) {
+ uint8_t nexthdr = ih6->nexthdr;
+ int offset_ph;
+
+ offset_ph = ipv6_skip_exthdr(skb, sizeof(_ip6h), &nexthdr);
+ if (offset_ph == -1)
+ return EBT_NOMATCH;
+ if (FWINV(info->protocol != nexthdr, EBT_IP6_PROTO))
+ return EBT_NOMATCH;
+ if (!(info->bitmask & EBT_IP6_DPORT) &&
+ !(info->bitmask & EBT_IP6_SPORT))
+ return EBT_MATCH;
+ pptr = skb_header_pointer(skb, offset_ph, sizeof(_ports),
+ &_ports);
+ if (pptr == NULL)
+ return EBT_NOMATCH;
+ if (info->bitmask & EBT_IP6_DPORT) {
+ u32 dst = ntohs(pptr->dst);
+ if (FWINV(dst < info->dport[0] ||
+ dst > info->dport[1], EBT_IP6_DPORT))
+ return EBT_NOMATCH;
+ }
+ if (info->bitmask & EBT_IP6_SPORT) {
+ u32 src = ntohs(pptr->src);
+ if (FWINV(src < info->sport[0] ||
+ src > info->sport[1], EBT_IP6_SPORT))
+ return EBT_NOMATCH;
+ }
+ return EBT_MATCH;
+ }
+ return EBT_MATCH;
+}
+
+static int ebt_ip6_check(const char *tablename, unsigned int hookmask,
+ const struct ebt_entry *e, void *data, unsigned int datalen)
+{
+ struct ebt_ip6_info *info = (struct ebt_ip6_info *)data;
+
+ if (datalen != EBT_ALIGN(sizeof(struct ebt_ip6_info)))
+ return -EINVAL;
+ if (e->ethproto != htons(ETH_P_IPV6) || e->invflags & EBT_IPROTO)
+ return -EINVAL;
+ if (info->bitmask & ~EBT_IP6_MASK || info->invflags & ~EBT_IP6_MASK)
+ return -EINVAL;
+ if (info->bitmask & (EBT_IP6_DPORT | EBT_IP6_SPORT)) {
+ if (info->invflags & EBT_IP6_PROTO)
+ return -EINVAL;
+ if (info->protocol != IPPROTO_TCP &&
+ info->protocol != IPPROTO_UDP &&
+ info->protocol != IPPROTO_UDPLITE &&
+ info->protocol != IPPROTO_SCTP &&
+ info->protocol != IPPROTO_DCCP)
+ return -EINVAL;
+ }
+ if (info->bitmask & EBT_IP6_DPORT && info->dport[0] > info->dport[1])
+ return -EINVAL;
+ if (info->bitmask & EBT_IP6_SPORT && info->sport[0] > info->sport[1])
+ return -EINVAL;
+ return 0;
+}
+
+static struct ebt_match filter_ip6 =
+{
+ .name = EBT_IP6_MATCH,
+ .match = ebt_filter_ip6,
+ .check = ebt_ip6_check,
+ .me = THIS_MODULE,
+};
+
+static int __init ebt_ip6_init(void)
+{
+ return ebt_register_match(&filter_ip6);
+}
+
+static void __exit ebt_ip6_fini(void)
+{
+ ebt_unregister_match(&filter_ip6);
+}
+
+module_init(ebt_ip6_init);
+module_exit(ebt_ip6_fini);
+MODULE_DESCRIPTION("Ebtables: IPv6 protocol packet match");
+MODULE_LICENSE("GPL");
diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c
index 0b209e4..c883ec8 100644
--- a/net/bridge/netfilter/ebt_log.c
+++ b/net/bridge/netfilter/ebt_log.c
@@ -18,6 +18,9 @@
#include <linux/if_arp.h>
#include <linux/spinlock.h>
#include <net/netfilter/nf_log.h>
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
+#include <linux/in6.h>
static DEFINE_SPINLOCK(ebt_log_lock);
@@ -58,6 +61,27 @@
printk("%02x%c", *p, i == ETH_ALEN - 1 ? ' ':':');
}
+static void
+print_ports(const struct sk_buff *skb, uint8_t protocol, int offset)
+{
+ if (protocol == IPPROTO_TCP ||
+ protocol == IPPROTO_UDP ||
+ protocol == IPPROTO_UDPLITE ||
+ protocol == IPPROTO_SCTP ||
+ protocol == IPPROTO_DCCP) {
+ const struct tcpudphdr *pptr;
+ struct tcpudphdr _ports;
+
+ pptr = skb_header_pointer(skb, offset,
+ sizeof(_ports), &_ports);
+ if (pptr == NULL) {
+ printk(" INCOMPLETE TCP/UDP header");
+ return;
+ }
+ printk(" SPT=%u DPT=%u", ntohs(pptr->src), ntohs(pptr->dst));
+ }
+}
+
#define myNIPQUAD(a) a[0], a[1], a[2], a[3]
static void
ebt_log_packet(unsigned int pf, unsigned int hooknum,
@@ -95,23 +119,31 @@
printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u, IP "
"tos=0x%02X, IP proto=%d", NIPQUAD(ih->saddr),
NIPQUAD(ih->daddr), ih->tos, ih->protocol);
- if (ih->protocol == IPPROTO_TCP ||
- ih->protocol == IPPROTO_UDP ||
- ih->protocol == IPPROTO_UDPLITE ||
- ih->protocol == IPPROTO_SCTP ||
- ih->protocol == IPPROTO_DCCP) {
- const struct tcpudphdr *pptr;
- struct tcpudphdr _ports;
+ print_ports(skb, ih->protocol, ih->ihl*4);
+ goto out;
+ }
- pptr = skb_header_pointer(skb, ih->ihl*4,
- sizeof(_ports), &_ports);
- if (pptr == NULL) {
- printk(" INCOMPLETE TCP/UDP header");
- goto out;
- }
- printk(" SPT=%u DPT=%u", ntohs(pptr->src),
- ntohs(pptr->dst));
+ if ((bitmask & EBT_LOG_IP6) && eth_hdr(skb)->h_proto ==
+ htons(ETH_P_IPV6)) {
+ const struct ipv6hdr *ih;
+ struct ipv6hdr _iph;
+ uint8_t nexthdr;
+ int offset_ph;
+
+ ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
+ if (ih == NULL) {
+ printk(" INCOMPLETE IPv6 header");
+ goto out;
}
+ printk(" IPv6 SRC=%x:%x:%x:%x:%x:%x:%x:%x "
+ "IPv6 DST=%x:%x:%x:%x:%x:%x:%x:%x, IPv6 "
+ "priority=0x%01X, Next Header=%d", NIP6(ih->saddr),
+ NIP6(ih->daddr), ih->priority, ih->nexthdr);
+ nexthdr = ih->nexthdr;
+ offset_ph = ipv6_skip_exthdr(skb, sizeof(_iph), &nexthdr);
+ if (offset_ph == -1)
+ goto out;
+ print_ports(skb, nexthdr, offset_ph);
goto out;
}
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 90e2177..dccd737 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -242,11 +242,11 @@
offset % sizeof(unsigned long) != 0);
read_lock(&dev_base_lock);
- if (dev_isalive(dev) && dev->get_stats &&
- (stats = (*dev->get_stats)(dev)))
+ if (dev_isalive(dev)) {
+ stats = dev->get_stats(dev);
ret = sprintf(buf, fmt_ulong,
*(unsigned long *)(((u8 *) stats) + offset));
-
+ }
read_unlock(&dev_base_lock);
return ret;
}
@@ -457,8 +457,7 @@
strlcpy(dev->bus_id, net->name, BUS_ID_SIZE);
#ifdef CONFIG_SYSFS
- if (net->get_stats)
- *groups++ = &netstat_group;
+ *groups++ = &netstat_group;
#ifdef CONFIG_WIRELESS_EXT
if (net->wireless_handlers && net->wireless_handlers->get_wireless_stats)
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index a9a7721..6c8d7f0 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -607,6 +607,8 @@
{
struct ifinfomsg *ifm;
struct nlmsghdr *nlh;
+ struct net_device_stats *stats;
+ struct nlattr *attr;
nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags);
if (nlh == NULL)
@@ -653,19 +655,13 @@
NLA_PUT(skb, IFLA_BROADCAST, dev->addr_len, dev->broadcast);
}
- if (dev->get_stats) {
- struct net_device_stats *stats = dev->get_stats(dev);
- if (stats) {
- struct nlattr *attr;
+ attr = nla_reserve(skb, IFLA_STATS,
+ sizeof(struct rtnl_link_stats));
+ if (attr == NULL)
+ goto nla_put_failure;
- attr = nla_reserve(skb, IFLA_STATS,
- sizeof(struct rtnl_link_stats));
- if (attr == NULL)
- goto nla_put_failure;
-
- copy_rtnl_link_stats(nla_data(attr), stats);
- }
- }
+ stats = dev->get_stats(dev);
+ copy_rtnl_link_stats(nla_data(attr), stats);
if (dev->rtnl_link_ops) {
if (rtnl_link_fill(skb, dev) < 0)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 1e556d3..3e18f85 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -4,8 +4,6 @@
* Authors: Alan Cox <iiitac@pyr.swan.ac.uk>
* Florian La Roche <rzsfl@rz.uni-sb.de>
*
- * Version: $Id: skbuff.c,v 1.90 2001/11/07 05:56:19 davem Exp $
- *
* Fixes:
* Alan Cox : Fixed the worst of the load
* balancer bugs.
diff --git a/net/core/sock.c b/net/core/sock.c
index 88094cb..3879bf6 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -7,8 +7,6 @@
* handler for protocols to use and generic option handler.
*
*
- * Version: $Id: sock.c,v 1.117 2002/02/01 22:01:03 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Florian La Roche, <flla@stud.uni-sb.de>
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 5fc8010..a570e2a 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -125,14 +125,6 @@
#endif /* CONFIG_XFRM */
#endif /* CONFIG_NET */
{
- .ctl_name = NET_CORE_SOMAXCONN,
- .procname = "somaxconn",
- .data = &init_net.core.sysctl_somaxconn,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec
- },
- {
.ctl_name = NET_CORE_BUDGET,
.procname = "netdev_budget",
.data = &netdev_budget,
@@ -151,6 +143,18 @@
{ .ctl_name = 0 }
};
+static struct ctl_table netns_core_table[] = {
+ {
+ .ctl_name = NET_CORE_SOMAXCONN,
+ .procname = "somaxconn",
+ .data = &init_net.core.sysctl_somaxconn,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec
+ },
+ { .ctl_name = 0 }
+};
+
static __net_initdata struct ctl_path net_core_path[] = {
{ .procname = "net", .ctl_name = CTL_NET, },
{ .procname = "core", .ctl_name = NET_CORE, },
@@ -159,23 +163,17 @@
static __net_init int sysctl_core_net_init(struct net *net)
{
- struct ctl_table *tbl, *tmp;
+ struct ctl_table *tbl;
net->core.sysctl_somaxconn = SOMAXCONN;
- tbl = net_core_table;
+ tbl = netns_core_table;
if (net != &init_net) {
- tbl = kmemdup(tbl, sizeof(net_core_table), GFP_KERNEL);
+ tbl = kmemdup(tbl, sizeof(netns_core_table), GFP_KERNEL);
if (tbl == NULL)
goto err_dup;
- for (tmp = tbl; tmp->procname; tmp++) {
- if (tmp->data >= (void *)&init_net &&
- tmp->data < (void *)(&init_net + 1))
- tmp->data += (char *)net - (char *)&init_net;
- else
- tmp->mode &= ~0222;
- }
+ tbl[0].data = &net->core.sysctl_somaxconn;
}
net->core.sysctl_hdr = register_net_sysctl_table(net,
@@ -186,7 +184,7 @@
return 0;
err_reg:
- if (tbl != net_core_table)
+ if (tbl != netns_core_table)
kfree(tbl);
err_dup:
return -ENOMEM;
@@ -198,7 +196,7 @@
tbl = net->core.sysctl_hdr->ctl_table_arg;
unregister_net_sysctl_table(net->core.sysctl_hdr);
- BUG_ON(tbl == net_core_table);
+ BUG_ON(tbl == netns_core_table);
kfree(tbl);
}
@@ -209,6 +207,7 @@
static __init int sysctl_core_init(void)
{
+ register_net_sysctl_rotable(net_core_path, net_core_table);
return register_pernet_subsys(&sysctl_core_ops);
}
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
index 200ee1e..69dbc34 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -391,7 +391,7 @@
wstats.updated = 0;
if (rx_stats->mask & IEEE80211_STATMASK_RSSI) {
- wstats.level = rx_stats->rssi;
+ wstats.level = rx_stats->signal;
wstats.updated |= IW_QUAL_LEVEL_UPDATED;
} else
wstats.updated |= IW_QUAL_LEVEL_INVALID;
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/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 24eca23..42bd24b 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -5,8 +5,6 @@
*
* PF_INET protocol family socket handler.
*
- * Version: $Id: af_inet.c,v 1.137 2002/02/01 22:01:03 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Florian La Roche, <flla@stud.uni-sb.de>
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 9b539fa..20c515a 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -1,7 +1,5 @@
/* linux/net/ipv4/arp.c
*
- * Version: $Id: arp.c,v 1.99 2001/08/30 22:55:42 davem Exp $
- *
* Copyright (C) 1994 by Florian La Roche
*
* This module implements the Address Resolution Protocol ARP (RFC 826),
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 79a7ef6..f8c0b0a 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1,8 +1,6 @@
/*
* NET3 IP device support routines.
*
- * Version: $Id: devinet.c,v 1.44 2001/10/31 21:55:54 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -1013,7 +1011,7 @@
memcpy(old, ifa->ifa_label, IFNAMSIZ);
memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
if (named++ == 0)
- continue;
+ goto skip;
dot = strchr(old, ':');
if (dot == NULL) {
sprintf(old, ":%d", named);
@@ -1024,6 +1022,8 @@
} else {
strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
}
+skip:
+ rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
}
}
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 0b2ac6a..5ad01d6 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -5,8 +5,6 @@
*
* IPv4 Forwarding Information Base: FIB frontend.
*
- * Version: $Id: fib_frontend.c,v 1.26 2001/10/31 21:55:54 davem Exp $
- *
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c
index 2e2fc33..eeec4bf 100644
--- a/net/ipv4/fib_hash.c
+++ b/net/ipv4/fib_hash.c
@@ -5,8 +5,6 @@
*
* IPv4 FIB: lookup engine and maintenance routines.
*
- * Version: $Id: fib_hash.c,v 1.13 2001/10/31 21:55:54 davem Exp $
- *
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 0d4d728..ded2ae3 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -5,8 +5,6 @@
*
* IPv4 Forwarding Information Base: semantics.
*
- * Version: $Id: fib_semantics.c,v 1.19 2002/01/12 07:54:56 davem Exp $
- *
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 4b02d14..394db9c 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -22,8 +22,6 @@
* IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson
* IEEE Journal on Selected Areas in Communications, 17(6):1083-1092, June 1999
*
- * Version: $Id: fib_trie.c,v 1.3 2005/06/08 14:20:01 robert Exp $
- *
*
* Code from fib_hash has been reused which includes the following header:
*
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 8739735..aa7cf46 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -3,8 +3,6 @@
*
* Alan Cox, <alan@redhat.com>
*
- * Version: $Id: icmp.c,v 1.85 2002/02/01 22:01:03 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 2769dc4..68e84a9 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -8,8 +8,6 @@
* the older version didn't come out right using gcc 2.5.8, the newer one
* seems to fall out with gcc 2.6.2.
*
- * Version: $Id: igmp.c,v 1.47 2002/02/01 22:01:03 davem Exp $
- *
* Authors:
* Alan Cox <Alan.Cox@linux.org>
*
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index da97695..c10036e 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -1,8 +1,6 @@
/*
* inet_diag.c Module for monitoring INET transport protocols sockets.
*
- * Version: $Id: inet_diag.c,v 1.3 2002/02/01 22:01:04 davem Exp $
- *
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index af99519..a456cee 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -3,8 +3,6 @@
*
* This source is covered by the GNU GPL, the same as all kernel sources.
*
- * Version: $Id: inetpeer.c,v 1.7 2001/09/20 21:22:50 davem Exp $
- *
* Authors: Andrey V. Savochkin <saw@msu.ru>
*/
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c
index 4813c39..37d36a3 100644
--- a/net/ipv4/ip_forward.c
+++ b/net/ipv4/ip_forward.c
@@ -5,8 +5,6 @@
*
* The IP forwarding functionality.
*
- * Version: $Id: ip_forward.c,v 1.48 2000/12/13 18:31:48 davem Exp $
- *
* Authors: see ip.c
*
* Fixes:
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index cd6ce6a..91e3214 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -5,8 +5,6 @@
*
* The IP fragmentation functionality.
*
- * Version: $Id: ip_fragment.c,v 1.59 2002/01/12 07:54:56 davem Exp $
- *
* Authors: Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
* Alan Cox <Alan.Cox@linux.org>
*
@@ -598,7 +596,7 @@
#ifdef CONFIG_SYSCTL
static int zero;
-static struct ctl_table ip4_frags_ctl_table[] = {
+static struct ctl_table ip4_frags_ns_ctl_table[] = {
{
.ctl_name = NET_IPV4_IPFRAG_HIGH_THRESH,
.procname = "ipfrag_high_thresh",
@@ -624,6 +622,10 @@
.proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies
},
+ { }
+};
+
+static struct ctl_table ip4_frags_ctl_table[] = {
{
.ctl_name = NET_IPV4_IPFRAG_SECRET_INTERVAL,
.procname = "ipfrag_secret_interval",
@@ -644,22 +646,20 @@
{ }
};
-static int ip4_frags_ctl_register(struct net *net)
+static int ip4_frags_ns_ctl_register(struct net *net)
{
struct ctl_table *table;
struct ctl_table_header *hdr;
- table = ip4_frags_ctl_table;
+ table = ip4_frags_ns_ctl_table;
if (net != &init_net) {
- table = kmemdup(table, sizeof(ip4_frags_ctl_table), GFP_KERNEL);
+ table = kmemdup(table, sizeof(ip4_frags_ns_ctl_table), GFP_KERNEL);
if (table == NULL)
goto err_alloc;
table[0].data = &net->ipv4.frags.high_thresh;
table[1].data = &net->ipv4.frags.low_thresh;
table[2].data = &net->ipv4.frags.timeout;
- table[3].mode &= ~0222;
- table[4].mode &= ~0222;
}
hdr = register_net_sysctl_table(net, net_ipv4_ctl_path, table);
@@ -676,7 +676,7 @@
return -ENOMEM;
}
-static void ip4_frags_ctl_unregister(struct net *net)
+static void ip4_frags_ns_ctl_unregister(struct net *net)
{
struct ctl_table *table;
@@ -684,13 +684,22 @@
unregister_net_sysctl_table(net->ipv4.frags_hdr);
kfree(table);
}
+
+static void ip4_frags_ctl_register(void)
+{
+ register_net_sysctl_rotable(net_ipv4_ctl_path, ip4_frags_ctl_table);
+}
#else
-static inline int ip4_frags_ctl_register(struct net *net)
+static inline int ip4_frags_ns_ctl_register(struct net *net)
{
return 0;
}
-static inline void ip4_frags_ctl_unregister(struct net *net)
+static inline void ip4_frags_ns_ctl_unregister(struct net *net)
+{
+}
+
+static inline void ip4_frags_ctl_register(void)
{
}
#endif
@@ -714,12 +723,12 @@
inet_frags_init_net(&net->ipv4.frags);
- return ip4_frags_ctl_register(net);
+ return ip4_frags_ns_ctl_register(net);
}
static void ipv4_frags_exit_net(struct net *net)
{
- ip4_frags_ctl_unregister(net);
+ ip4_frags_ns_ctl_unregister(net);
inet_frags_exit_net(&net->ipv4.frags, &ip4_frags);
}
@@ -730,6 +739,7 @@
void __init ipfrag_init(void)
{
+ ip4_frags_ctl_register();
register_pernet_subsys(&ip4_frags_ops);
ip4_frags.hashfn = ip4_hashfn;
ip4_frags.constructor = ip4_frag_init;
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 4342cba..2a61158 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -473,6 +473,8 @@
read_lock(&ipgre_lock);
if ((tunnel = ipgre_tunnel_lookup(dev_net(skb->dev),
iph->saddr, iph->daddr, key)) != NULL) {
+ struct net_device_stats *stats = &tunnel->dev->stats;
+
secpath_reset(skb);
skb->protocol = *(__be16*)(h + 2);
@@ -497,28 +499,28 @@
/* Looped back packet, drop it! */
if (skb->rtable->fl.iif == 0)
goto drop;
- tunnel->stat.multicast++;
+ stats->multicast++;
skb->pkt_type = PACKET_BROADCAST;
}
#endif
if (((flags&GRE_CSUM) && csum) ||
(!(flags&GRE_CSUM) && tunnel->parms.i_flags&GRE_CSUM)) {
- tunnel->stat.rx_crc_errors++;
- tunnel->stat.rx_errors++;
+ stats->rx_crc_errors++;
+ stats->rx_errors++;
goto drop;
}
if (tunnel->parms.i_flags&GRE_SEQ) {
if (!(flags&GRE_SEQ) ||
(tunnel->i_seqno && (s32)(seqno - tunnel->i_seqno) < 0)) {
- tunnel->stat.rx_fifo_errors++;
- tunnel->stat.rx_errors++;
+ stats->rx_fifo_errors++;
+ stats->rx_errors++;
goto drop;
}
tunnel->i_seqno = seqno + 1;
}
- tunnel->stat.rx_packets++;
- tunnel->stat.rx_bytes += skb->len;
+ stats->rx_packets++;
+ stats->rx_bytes += skb->len;
skb->dev = tunnel->dev;
dst_release(skb->dst);
skb->dst = NULL;
@@ -540,7 +542,7 @@
static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
- struct net_device_stats *stats = &tunnel->stat;
+ struct net_device_stats *stats = &tunnel->dev->stats;
struct iphdr *old_iph = ip_hdr(skb);
struct iphdr *tiph;
u8 tos;
@@ -554,7 +556,7 @@
int mtu;
if (tunnel->recursion++) {
- tunnel->stat.collisions++;
+ stats->collisions++;
goto tx_error;
}
@@ -570,7 +572,7 @@
/* NBMA tunnel */
if (skb->dst == NULL) {
- tunnel->stat.tx_fifo_errors++;
+ stats->tx_fifo_errors++;
goto tx_error;
}
@@ -621,7 +623,7 @@
.tos = RT_TOS(tos) } },
.proto = IPPROTO_GRE };
if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
- tunnel->stat.tx_carrier_errors++;
+ stats->tx_carrier_errors++;
goto tx_error;
}
}
@@ -629,7 +631,7 @@
if (tdev == dev) {
ip_rt_put(rt);
- tunnel->stat.collisions++;
+ stats->collisions++;
goto tx_error;
}
@@ -954,11 +956,6 @@
return err;
}
-static struct net_device_stats *ipgre_tunnel_get_stats(struct net_device *dev)
-{
- return &(((struct ip_tunnel*)netdev_priv(dev))->stat);
-}
-
static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
@@ -1084,7 +1081,6 @@
dev->uninit = ipgre_tunnel_uninit;
dev->destructor = free_netdev;
dev->hard_start_xmit = ipgre_tunnel_xmit;
- dev->get_stats = ipgre_tunnel_get_stats;
dev->do_ioctl = ipgre_tunnel_ioctl;
dev->change_mtu = ipgre_tunnel_change_mtu;
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index ff77a4a..7c26428 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -5,8 +5,6 @@
*
* The Internet Protocol (IP) module.
*
- * Version: $Id: ip_input.c,v 1.55 2002/01/12 07:39:45 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Donald Becker, <becker@super.org>
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
index 33126ad..be3f18a 100644
--- a/net/ipv4/ip_options.c
+++ b/net/ipv4/ip_options.c
@@ -5,8 +5,6 @@
*
* The options processing module for ip.c
*
- * Version: $Id: ip_options.c,v 1.21 2001/09/01 00:31:50 davem Exp $
- *
* Authors: A.N.Kuznetsov
*
*/
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index e527628..f1278ee 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -5,8 +5,6 @@
*
* The Internet Protocol (IP) output module.
*
- * Version: $Id: ip_output.c,v 1.100 2002/02/01 22:01:03 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Donald Becker, <becker@super.org>
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index e0514e82..105d92a 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -5,8 +5,6 @@
*
* The IP to API glue.
*
- * Version: $Id: ip_sockglue.c,v 1.62 2002/02/01 22:01:04 davem Exp $
- *
* Authors: see ip.c
*
* Fixes:
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index ed45037..b88aa9a 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -1,6 +1,4 @@
/*
- * $Id: ipconfig.c,v 1.46 2002/02/01 22:01:04 davem Exp $
- *
* Automatic Configuration of IP -- use DHCP, BOOTP, RARP, or
* user-supplied information to configure own IP address and routes.
*
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index af5cb53..4c6d2ca 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -1,8 +1,6 @@
/*
* Linux NET3: IP/IP protocol decoder.
*
- * Version: $Id: ipip.c,v 1.50 2001/10/02 02:22:36 davem Exp $
- *
* Authors:
* Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95
*
@@ -368,8 +366,8 @@
skb->protocol = htons(ETH_P_IP);
skb->pkt_type = PACKET_HOST;
- tunnel->stat.rx_packets++;
- tunnel->stat.rx_bytes += skb->len;
+ tunnel->dev->stats.rx_packets++;
+ tunnel->dev->stats.rx_bytes += skb->len;
skb->dev = tunnel->dev;
dst_release(skb->dst);
skb->dst = NULL;
@@ -392,7 +390,7 @@
static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
- struct net_device_stats *stats = &tunnel->stat;
+ struct net_device_stats *stats = &tunnel->dev->stats;
struct iphdr *tiph = &tunnel->parms.iph;
u8 tos = tunnel->parms.iph.tos;
__be16 df = tiph->frag_off;
@@ -405,7 +403,7 @@
int mtu;
if (tunnel->recursion++) {
- tunnel->stat.collisions++;
+ stats->collisions++;
goto tx_error;
}
@@ -418,7 +416,7 @@
if (!dst) {
/* NBMA tunnel */
if ((rt = skb->rtable) == NULL) {
- tunnel->stat.tx_fifo_errors++;
+ stats->tx_fifo_errors++;
goto tx_error;
}
if ((dst = rt->rt_gateway) == 0)
@@ -433,7 +431,7 @@
.tos = RT_TOS(tos) } },
.proto = IPPROTO_IPIP };
if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
- tunnel->stat.tx_carrier_errors++;
+ stats->tx_carrier_errors++;
goto tx_error_icmp;
}
}
@@ -441,7 +439,7 @@
if (tdev == dev) {
ip_rt_put(rt);
- tunnel->stat.collisions++;
+ stats->collisions++;
goto tx_error;
}
@@ -451,7 +449,7 @@
mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu;
if (mtu < 68) {
- tunnel->stat.collisions++;
+ stats->collisions++;
ip_rt_put(rt);
goto tx_error;
}
@@ -685,11 +683,6 @@
return err;
}
-static struct net_device_stats *ipip_tunnel_get_stats(struct net_device *dev)
-{
- return &(((struct ip_tunnel*)netdev_priv(dev))->stat);
-}
-
static int ipip_tunnel_change_mtu(struct net_device *dev, int new_mtu)
{
if (new_mtu < 68 || new_mtu > 0xFFF8 - sizeof(struct iphdr))
@@ -702,7 +695,6 @@
{
dev->uninit = ipip_tunnel_uninit;
dev->hard_start_xmit = ipip_tunnel_xmit;
- dev->get_stats = ipip_tunnel_get_stats;
dev->do_ioctl = ipip_tunnel_ioctl;
dev->change_mtu = ipip_tunnel_change_mtu;
dev->destructor = free_netdev;
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 11700a4..300ab0c 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -9,8 +9,6 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Version: $Id: ipmr.c,v 1.65 2001/10/31 21:55:54 davem Exp $
- *
* Fixes:
* Michael Chastain : Incorrect size of copying.
* Alan Cox : Added the cache manager code
@@ -181,26 +179,20 @@
static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
{
read_lock(&mrt_lock);
- ((struct net_device_stats*)netdev_priv(dev))->tx_bytes += skb->len;
- ((struct net_device_stats*)netdev_priv(dev))->tx_packets++;
+ dev->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
ipmr_cache_report(skb, reg_vif_num, IGMPMSG_WHOLEPKT);
read_unlock(&mrt_lock);
kfree_skb(skb);
return 0;
}
-static struct net_device_stats *reg_vif_get_stats(struct net_device *dev)
-{
- return (struct net_device_stats*)netdev_priv(dev);
-}
-
static void reg_vif_setup(struct net_device *dev)
{
dev->type = ARPHRD_PIMREG;
dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 8;
dev->flags = IFF_NOARP;
dev->hard_start_xmit = reg_vif_xmit;
- dev->get_stats = reg_vif_get_stats;
dev->destructor = free_netdev;
}
@@ -209,8 +201,7 @@
struct net_device *dev;
struct in_device *in_dev;
- dev = alloc_netdev(sizeof(struct net_device_stats), "pimreg",
- reg_vif_setup);
+ dev = alloc_netdev(0, "pimreg", reg_vif_setup);
if (dev == NULL)
return NULL;
@@ -1170,8 +1161,8 @@
if (vif->flags & VIFF_REGISTER) {
vif->pkt_out++;
vif->bytes_out+=skb->len;
- ((struct net_device_stats*)netdev_priv(vif->dev))->tx_bytes += skb->len;
- ((struct net_device_stats*)netdev_priv(vif->dev))->tx_packets++;
+ vif->dev->stats.tx_bytes += skb->len;
+ vif->dev->stats.tx_packets++;
ipmr_cache_report(skb, vifi, IGMPMSG_WHOLEPKT);
kfree_skb(skb);
return;
@@ -1230,8 +1221,8 @@
if (vif->flags & VIFF_TUNNEL) {
ip_encap(skb, vif->local, vif->remote);
/* FIXME: extra output firewall step used to be here. --RR */
- ((struct ip_tunnel *)netdev_priv(vif->dev))->stat.tx_packets++;
- ((struct ip_tunnel *)netdev_priv(vif->dev))->stat.tx_bytes+=skb->len;
+ vif->dev->stats.tx_packets++;
+ vif->dev->stats.tx_bytes += skb->len;
}
IPCB(skb)->flags |= IPSKB_FORWARDED;
@@ -1487,8 +1478,8 @@
skb->pkt_type = PACKET_HOST;
dst_release(skb->dst);
skb->dst = NULL;
- ((struct net_device_stats*)netdev_priv(reg_dev))->rx_bytes += skb->len;
- ((struct net_device_stats*)netdev_priv(reg_dev))->rx_packets++;
+ reg_dev->stats.rx_bytes += skb->len;
+ reg_dev->stats.rx_packets++;
nf_reset(skb);
netif_rx(skb);
dev_put(reg_dev);
@@ -1542,8 +1533,8 @@
skb->ip_summed = 0;
skb->pkt_type = PACKET_HOST;
dst_release(skb->dst);
- ((struct net_device_stats*)netdev_priv(reg_dev))->rx_bytes += skb->len;
- ((struct net_device_stats*)netdev_priv(reg_dev))->rx_packets++;
+ reg_dev->stats.rx_bytes += skb->len;
+ reg_dev->stats.rx_packets++;
skb->dst = NULL;
nf_reset(skb);
netif_rx(skb);
diff --git a/net/ipv4/ipvs/ip_vs_app.c b/net/ipv4/ipvs/ip_vs_app.c
index 535abe0..1f1897a 100644
--- a/net/ipv4/ipvs/ip_vs_app.c
+++ b/net/ipv4/ipvs/ip_vs_app.c
@@ -1,8 +1,6 @@
/*
* ip_vs_app.c: Application module support for IPVS
*
- * Version: $Id: ip_vs_app.c,v 1.17 2003/03/22 06:31:21 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index 65f1ba11..f8bdae4 100644
--- a/net/ipv4/ipvs/ip_vs_conn.c
+++ b/net/ipv4/ipvs/ip_vs_conn.c
@@ -5,8 +5,6 @@
* high-performance and highly available server based on a
* cluster of servers.
*
- * Version: $Id: ip_vs_conn.c,v 1.31 2003/04/18 09:03:16 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
* Peter Kese <peter.kese@ijs.si>
* Julian Anastasov <ja@ssi.bg>
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index 963981a..bcf6276 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -5,8 +5,6 @@
* high-performance and highly available server based on a
* cluster of servers.
*
- * Version: $Id: ip_vs_core.c,v 1.34 2003/05/10 03:05:23 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
* Peter Kese <peter.kese@ijs.si>
* Julian Anastasov <ja@ssi.bg>
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index 94c5767..9a5ace0 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -5,8 +5,6 @@
* high-performance and highly available server based on a
* cluster of servers.
*
- * Version: $Id: ip_vs_ctl.c,v 1.36 2003/06/08 09:31:19 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
* Peter Kese <peter.kese@ijs.si>
* Julian Anastasov <ja@ssi.bg>
diff --git a/net/ipv4/ipvs/ip_vs_dh.c b/net/ipv4/ipvs/ip_vs_dh.c
index dcf5d46..8afc150 100644
--- a/net/ipv4/ipvs/ip_vs_dh.c
+++ b/net/ipv4/ipvs/ip_vs_dh.c
@@ -1,8 +1,6 @@
/*
* IPVS: Destination Hashing scheduling module
*
- * Version: $Id: ip_vs_dh.c,v 1.5 2002/09/15 08:14:08 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@gnuchina.org>
*
* Inspired by the consistent hashing scheduler patch from
diff --git a/net/ipv4/ipvs/ip_vs_est.c b/net/ipv4/ipvs/ip_vs_est.c
index dfa0d71..bc04eed 100644
--- a/net/ipv4/ipvs/ip_vs_est.c
+++ b/net/ipv4/ipvs/ip_vs_est.c
@@ -1,8 +1,6 @@
/*
* ip_vs_est.c: simple rate estimator for IPVS
*
- * Version: $Id: ip_vs_est.c,v 1.4 2002/11/30 01:50:35 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/ipvs/ip_vs_ftp.c b/net/ipv4/ipvs/ip_vs_ftp.c
index 59aa166..c1c758e 100644
--- a/net/ipv4/ipvs/ip_vs_ftp.c
+++ b/net/ipv4/ipvs/ip_vs_ftp.c
@@ -1,8 +1,6 @@
/*
* ip_vs_ftp.c: IPVS ftp application module
*
- * Version: $Id: ip_vs_ftp.c,v 1.13 2002/09/15 08:14:08 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
*
* Changes:
diff --git a/net/ipv4/ipvs/ip_vs_lblc.c b/net/ipv4/ipvs/ip_vs_lblc.c
index 3888642..0efa3db 100644
--- a/net/ipv4/ipvs/ip_vs_lblc.c
+++ b/net/ipv4/ipvs/ip_vs_lblc.c
@@ -1,8 +1,6 @@
/*
* IPVS: Locality-Based Least-Connection scheduling module
*
- * Version: $Id: ip_vs_lblc.c,v 1.10 2002/09/15 08:14:08 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@gnuchina.org>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/ipvs/ip_vs_lblcr.c b/net/ipv4/ipvs/ip_vs_lblcr.c
index daa260e..8e3bbeb 100644
--- a/net/ipv4/ipvs/ip_vs_lblcr.c
+++ b/net/ipv4/ipvs/ip_vs_lblcr.c
@@ -1,8 +1,6 @@
/*
* IPVS: Locality-Based Least-Connection with Replication scheduler
*
- * Version: $Id: ip_vs_lblcr.c,v 1.11 2002/09/15 08:14:08 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@gnuchina.org>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/ipvs/ip_vs_lc.c b/net/ipv4/ipvs/ip_vs_lc.c
index d88fef9..ac9f08e 100644
--- a/net/ipv4/ipvs/ip_vs_lc.c
+++ b/net/ipv4/ipvs/ip_vs_lc.c
@@ -1,8 +1,6 @@
/*
* IPVS: Least-Connection Scheduling module
*
- * Version: $Id: ip_vs_lc.c,v 1.10 2003/04/18 09:03:16 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/ipvs/ip_vs_nq.c b/net/ipv4/ipvs/ip_vs_nq.c
index bc2a9e5..a46bf25 100644
--- a/net/ipv4/ipvs/ip_vs_nq.c
+++ b/net/ipv4/ipvs/ip_vs_nq.c
@@ -1,8 +1,6 @@
/*
* IPVS: Never Queue scheduling module
*
- * Version: $Id: ip_vs_nq.c,v 1.2 2003/06/08 09:31:19 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/ipvs/ip_vs_proto.c b/net/ipv4/ipvs/ip_vs_proto.c
index 4b1c16c..876714f 100644
--- a/net/ipv4/ipvs/ip_vs_proto.c
+++ b/net/ipv4/ipvs/ip_vs_proto.c
@@ -1,8 +1,6 @@
/*
* ip_vs_proto.c: transport protocol load balancing support for IPVS
*
- * Version: $Id: ip_vs_proto.c,v 1.2 2003/04/18 09:03:16 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
* Julian Anastasov <ja@ssi.bg>
*
diff --git a/net/ipv4/ipvs/ip_vs_proto_ah.c b/net/ipv4/ipvs/ip_vs_proto_ah.c
index 4bf835e..73e0ea8 100644
--- a/net/ipv4/ipvs/ip_vs_proto_ah.c
+++ b/net/ipv4/ipvs/ip_vs_proto_ah.c
@@ -1,8 +1,6 @@
/*
* ip_vs_proto_ah.c: AH IPSec load balancing support for IPVS
*
- * Version: $Id: ip_vs_proto_ah.c,v 1.1 2003/07/04 15:04:37 wensong Exp $
- *
* Authors: Julian Anastasov <ja@ssi.bg>, February 2002
* Wensong Zhang <wensong@linuxvirtualserver.org>
*
diff --git a/net/ipv4/ipvs/ip_vs_proto_esp.c b/net/ipv4/ipvs/ip_vs_proto_esp.c
index db6a6b7..21d70c8 100644
--- a/net/ipv4/ipvs/ip_vs_proto_esp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_esp.c
@@ -1,8 +1,6 @@
/*
* ip_vs_proto_esp.c: ESP IPSec load balancing support for IPVS
*
- * Version: $Id: ip_vs_proto_esp.c,v 1.1 2003/07/04 15:04:37 wensong Exp $
- *
* Authors: Julian Anastasov <ja@ssi.bg>, February 2002
* Wensong Zhang <wensong@linuxvirtualserver.org>
*
diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c
index b83dc14..d0ea467 100644
--- a/net/ipv4/ipvs/ip_vs_proto_tcp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c
@@ -1,8 +1,6 @@
/*
* ip_vs_proto_tcp.c: TCP load balancing support for IPVS
*
- * Version: $Id: ip_vs_proto_tcp.c,v 1.3 2002/11/30 01:50:35 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
* Julian Anastasov <ja@ssi.bg>
*
diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c
index 75771cb..c6be5d5 100644
--- a/net/ipv4/ipvs/ip_vs_proto_udp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_udp.c
@@ -1,8 +1,6 @@
/*
* ip_vs_proto_udp.c: UDP load balancing support for IPVS
*
- * Version: $Id: ip_vs_proto_udp.c,v 1.3 2002/11/30 01:50:35 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
* Julian Anastasov <ja@ssi.bg>
*
diff --git a/net/ipv4/ipvs/ip_vs_rr.c b/net/ipv4/ipvs/ip_vs_rr.c
index 433f8a9..c8db12d 100644
--- a/net/ipv4/ipvs/ip_vs_rr.c
+++ b/net/ipv4/ipvs/ip_vs_rr.c
@@ -1,8 +1,6 @@
/*
* IPVS: Round-Robin Scheduling module
*
- * Version: $Id: ip_vs_rr.c,v 1.9 2002/09/15 08:14:08 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
* Peter Kese <peter.kese@ijs.si>
*
diff --git a/net/ipv4/ipvs/ip_vs_sched.c b/net/ipv4/ipvs/ip_vs_sched.c
index 121a32b..b647673 100644
--- a/net/ipv4/ipvs/ip_vs_sched.c
+++ b/net/ipv4/ipvs/ip_vs_sched.c
@@ -5,8 +5,6 @@
* high-performance and highly available server based on a
* cluster of servers.
*
- * Version: $Id: ip_vs_sched.c,v 1.13 2003/05/10 03:05:23 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
* Peter Kese <peter.kese@ijs.si>
*
diff --git a/net/ipv4/ipvs/ip_vs_sed.c b/net/ipv4/ipvs/ip_vs_sed.c
index dd7c128..2a7d313 100644
--- a/net/ipv4/ipvs/ip_vs_sed.c
+++ b/net/ipv4/ipvs/ip_vs_sed.c
@@ -1,8 +1,6 @@
/*
* IPVS: Shortest Expected Delay scheduling module
*
- * Version: $Id: ip_vs_sed.c,v 1.1 2003/05/10 03:06:08 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/ipvs/ip_vs_sh.c b/net/ipv4/ipvs/ip_vs_sh.c
index 1b25b00..b8fdfac 100644
--- a/net/ipv4/ipvs/ip_vs_sh.c
+++ b/net/ipv4/ipvs/ip_vs_sh.c
@@ -1,8 +1,6 @@
/*
* IPVS: Source Hashing scheduling module
*
- * Version: $Id: ip_vs_sh.c,v 1.5 2002/09/15 08:14:08 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@gnuchina.org>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c
index eff54ef..2d4a86f 100644
--- a/net/ipv4/ipvs/ip_vs_sync.c
+++ b/net/ipv4/ipvs/ip_vs_sync.c
@@ -5,8 +5,6 @@
* high-performance and highly available server based on a
* cluster of servers.
*
- * Version: $Id: ip_vs_sync.c,v 1.13 2003/06/08 09:31:19 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
*
* ip_vs_sync: sync connection info from master load balancer to backups
diff --git a/net/ipv4/ipvs/ip_vs_wlc.c b/net/ipv4/ipvs/ip_vs_wlc.c
index 8a9d913..772c3cb 100644
--- a/net/ipv4/ipvs/ip_vs_wlc.c
+++ b/net/ipv4/ipvs/ip_vs_wlc.c
@@ -1,8 +1,6 @@
/*
* IPVS: Weighted Least-Connection Scheduling module
*
- * Version: $Id: ip_vs_wlc.c,v 1.13 2003/04/18 09:03:16 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
* Peter Kese <peter.kese@ijs.si>
*
diff --git a/net/ipv4/ipvs/ip_vs_wrr.c b/net/ipv4/ipvs/ip_vs_wrr.c
index 85c680a..1d6932d 100644
--- a/net/ipv4/ipvs/ip_vs_wrr.c
+++ b/net/ipv4/ipvs/ip_vs_wrr.c
@@ -1,8 +1,6 @@
/*
* IPVS: Weighted Round-Robin Scheduling module
*
- * Version: $Id: ip_vs_wrr.c,v 1.12 2002/09/15 08:14:08 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c
index f63006cae..9892d4a 100644
--- a/net/ipv4/ipvs/ip_vs_xmit.c
+++ b/net/ipv4/ipvs/ip_vs_xmit.c
@@ -1,8 +1,6 @@
/*
* ip_vs_xmit.c: various packet transmitters for IPVS
*
- * Version: $Id: ip_vs_xmit.c,v 1.2 2002/11/30 01:50:35 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
* Julian Anastasov <ja@ssi.bg>
*
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 2767841..6e25140 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -365,6 +365,18 @@
If you want to compile it as a module, say M here and read
<file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
+# security table for MAC policy
+config IP_NF_SECURITY
+ tristate "Security table"
+ depends on IP_NF_IPTABLES
+ depends on SECURITY
+ default m if NETFILTER_ADVANCED=n
+ help
+ This option adds a `security' table to iptables, for use
+ with Mandatory Access Control (MAC) policy.
+
+ If unsure, say N.
+
# ARP tables
config IP_NF_ARPTABLES
tristate "ARP tables support"
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index d9b92fb..3f31291f 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -42,6 +42,7 @@
obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o
obj-$(CONFIG_NF_NAT) += iptable_nat.o
obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
+obj-$(CONFIG_IP_NF_SECURITY) += iptable_security.o
# matches
obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index 26a37ce..aa33a4a 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -156,7 +156,6 @@
case IPQ_COPY_META:
case IPQ_COPY_NONE:
size = NLMSG_SPACE(sizeof(*pmsg));
- data_len = 0;
break;
case IPQ_COPY_PACKET:
@@ -224,8 +223,6 @@
return skb;
nlmsg_failure:
- if (skb)
- kfree_skb(skb);
*errp = -EINVAL;
printk(KERN_ERR "ip_queue: error creating packet message\n");
return NULL;
diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c
new file mode 100644
index 0000000..2b472ac
--- /dev/null
+++ b/net/ipv4/netfilter/iptable_security.c
@@ -0,0 +1,180 @@
+/*
+ * "security" table
+ *
+ * This is for use by Mandatory Access Control (MAC) security models,
+ * which need to be able to manage security policy in separate context
+ * to DAC.
+ *
+ * Based on iptable_mangle.c
+ *
+ * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ * Copyright (C) 2000-2004 Netfilter Core Team <coreteam <at> netfilter.org>
+ * Copyright (C) 2008 Red Hat, Inc., James Morris <jmorris <at> redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <net/ip.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("James Morris <jmorris <at> redhat.com>");
+MODULE_DESCRIPTION("iptables security table, for MAC rules");
+
+#define SECURITY_VALID_HOOKS (1 << NF_INET_LOCAL_IN) | \
+ (1 << NF_INET_FORWARD) | \
+ (1 << NF_INET_LOCAL_OUT)
+
+static struct
+{
+ struct ipt_replace repl;
+ struct ipt_standard entries[3];
+ struct ipt_error term;
+} initial_table __initdata = {
+ .repl = {
+ .name = "security",
+ .valid_hooks = SECURITY_VALID_HOOKS,
+ .num_entries = 4,
+ .size = sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error),
+ .hook_entry = {
+ [NF_INET_LOCAL_IN] = 0,
+ [NF_INET_FORWARD] = sizeof(struct ipt_standard),
+ [NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard) * 2,
+ },
+ .underflow = {
+ [NF_INET_LOCAL_IN] = 0,
+ [NF_INET_FORWARD] = sizeof(struct ipt_standard),
+ [NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard) * 2,
+ },
+ },
+ .entries = {
+ IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */
+ IPT_STANDARD_INIT(NF_ACCEPT), /* FORWARD */
+ IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
+ },
+ .term = IPT_ERROR_INIT, /* ERROR */
+};
+
+static struct xt_table security_table = {
+ .name = "security",
+ .valid_hooks = SECURITY_VALID_HOOKS,
+ .lock = __RW_LOCK_UNLOCKED(security_table.lock),
+ .me = THIS_MODULE,
+ .af = AF_INET,
+};
+
+static unsigned int
+ipt_local_in_hook(unsigned int hook,
+ struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ return ipt_do_table(skb, hook, in, out,
+ nf_local_in_net(in, out)->ipv4.iptable_security);
+}
+
+static unsigned int
+ipt_forward_hook(unsigned int hook,
+ struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ return ipt_do_table(skb, hook, in, out,
+ nf_forward_net(in, out)->ipv4.iptable_security);
+}
+
+static unsigned int
+ipt_local_out_hook(unsigned int hook,
+ struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ /* Somebody is playing with raw sockets. */
+ if (skb->len < sizeof(struct iphdr)
+ || ip_hdrlen(skb) < sizeof(struct iphdr)) {
+ if (net_ratelimit())
+ printk(KERN_INFO "iptable_security: ignoring short "
+ "SOCK_RAW packet.\n");
+ return NF_ACCEPT;
+ }
+ return ipt_do_table(skb, hook, in, out,
+ nf_local_out_net(in, out)->ipv4.iptable_security);
+}
+
+static struct nf_hook_ops ipt_ops[] __read_mostly = {
+ {
+ .hook = ipt_local_in_hook,
+ .owner = THIS_MODULE,
+ .pf = PF_INET,
+ .hooknum = NF_INET_LOCAL_IN,
+ .priority = NF_IP_PRI_SECURITY,
+ },
+ {
+ .hook = ipt_forward_hook,
+ .owner = THIS_MODULE,
+ .pf = PF_INET,
+ .hooknum = NF_INET_FORWARD,
+ .priority = NF_IP_PRI_SECURITY,
+ },
+ {
+ .hook = ipt_local_out_hook,
+ .owner = THIS_MODULE,
+ .pf = PF_INET,
+ .hooknum = NF_INET_LOCAL_OUT,
+ .priority = NF_IP_PRI_SECURITY,
+ },
+};
+
+static int __net_init iptable_security_net_init(struct net *net)
+{
+ net->ipv4.iptable_security =
+ ipt_register_table(net, &security_table, &initial_table.repl);
+
+ if (IS_ERR(net->ipv4.iptable_security))
+ return PTR_ERR(net->ipv4.iptable_security);
+
+ return 0;
+}
+
+static void __net_exit iptable_security_net_exit(struct net *net)
+{
+ ipt_unregister_table(net->ipv4.iptable_security);
+}
+
+static struct pernet_operations iptable_security_net_ops = {
+ .init = iptable_security_net_init,
+ .exit = iptable_security_net_exit,
+};
+
+static int __init iptable_security_init(void)
+{
+ int ret;
+
+ ret = register_pernet_subsys(&iptable_security_net_ops);
+ if (ret < 0)
+ return ret;
+
+ ret = nf_register_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
+ if (ret < 0)
+ goto cleanup_table;
+
+ return ret;
+
+cleanup_table:
+ unregister_pernet_subsys(&iptable_security_net_ops);
+ return ret;
+}
+
+static void __exit iptable_security_fini(void)
+{
+ nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
+ unregister_pernet_subsys(&iptable_security_net_ops);
+}
+
+module_init(iptable_security_init);
+module_exit(iptable_security_fini);
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
index 78ab19a..9779104 100644
--- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
@@ -87,9 +87,8 @@
means this will only run once even if count hits zero twice
(theoretically possible with SMP) */
if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
- if (atomic_dec_and_test(&ct->proto.icmp.count)
- && del_timer(&ct->timeout))
- ct->timeout.function((unsigned long)ct);
+ if (atomic_dec_and_test(&ct->proto.icmp.count))
+ nf_ct_kill_acct(ct, ctinfo, skb);
} else {
atomic_inc(&ct->proto.icmp.count);
nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index 552169b..eb5cee2 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -7,8 +7,6 @@
* PROC file system. It is mainly used for debugging and
* statistics.
*
- * Version: $Id: proc.c,v 1.45 2001/05/16 16:45:35 davem Exp $
- *
* Authors: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de>
* Fred Baumgarten, <dc6iq@insu1.etec.uni-karlsruhe.de>
diff --git a/net/ipv4/protocol.c b/net/ipv4/protocol.c
index 971ab93..ea50da0 100644
--- a/net/ipv4/protocol.c
+++ b/net/ipv4/protocol.c
@@ -5,8 +5,6 @@
*
* INET protocol dispatch tables.
*
- * Version: $Id: protocol.c,v 1.14 2001/05/18 02:25:49 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
*
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index e7e091d..1d0c97c 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -5,8 +5,6 @@
*
* RAW - implementation of IP "raw" sockets.
*
- * Version: $Id: raw.c,v 1.64 2002/02/01 22:01:04 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
*
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 96be336..fe3a022 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -5,8 +5,6 @@
*
* ROUTE - implementation of the IP router.
*
- * Version: $Id: route.c,v 1.103 2002/01/12 07:44:09 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Alan Cox, <gw4pts@gw4pts.ampr.org>
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index d182a2a..fdde2ae 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -8,8 +8,6 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
- *
- * $Id: syncookies.c,v 1.18 2002/02/01 22:01:04 davem Exp $
*/
#include <linux/tcp.h>
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index c437f804..9016070 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -1,8 +1,6 @@
/*
* sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem.
*
- * $Id: sysctl_net_ipv4.c,v 1.50 2001/10/20 00:00:11 davem Exp $
- *
* Begun April 1, 1996, Mike Shaver.
* Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS]
*/
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index fc54a48..cf0850c 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -5,8 +5,6 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp.c,v 1.216 2002/02/01 22:01:04 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Mark Evans, <evansmp@uhura.aston.ac.uk>
@@ -2463,6 +2461,76 @@
static struct tcp_md5sig_pool **tcp_md5sig_pool;
static DEFINE_SPINLOCK(tcp_md5sig_pool_lock);
+int tcp_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
+ int bplen,
+ struct tcphdr *th, unsigned int tcplen,
+ struct tcp_md5sig_pool *hp)
+{
+ struct scatterlist sg[4];
+ __u16 data_len;
+ int block = 0;
+ __sum16 cksum;
+ struct hash_desc *desc = &hp->md5_desc;
+ int err;
+ unsigned int nbytes = 0;
+
+ sg_init_table(sg, 4);
+
+ /* 1. The TCP pseudo-header */
+ sg_set_buf(&sg[block++], &hp->md5_blk, bplen);
+ nbytes += bplen;
+
+ /* 2. The TCP header, excluding options, and assuming a
+ * checksum of zero
+ */
+ cksum = th->check;
+ th->check = 0;
+ sg_set_buf(&sg[block++], th, sizeof(*th));
+ nbytes += sizeof(*th);
+
+ /* 3. The TCP segment data (if any) */
+ data_len = tcplen - (th->doff << 2);
+ if (data_len > 0) {
+ u8 *data = (u8 *)th + (th->doff << 2);
+ sg_set_buf(&sg[block++], data, data_len);
+ nbytes += data_len;
+ }
+
+ /* 4. an independently-specified key or password, known to both
+ * TCPs and presumably connection-specific
+ */
+ sg_set_buf(&sg[block++], key->key, key->keylen);
+ nbytes += key->keylen;
+
+ sg_mark_end(&sg[block - 1]);
+
+ /* Now store the hash into the packet */
+ err = crypto_hash_init(desc);
+ if (err) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "%s(): hash_init failed\n", __func__);
+ return -1;
+ }
+ err = crypto_hash_update(desc, sg, nbytes);
+ if (err) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "%s(): hash_update failed\n", __func__);
+ return -1;
+ }
+ err = crypto_hash_final(desc, md5_hash);
+ if (err) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "%s(): hash_final failed\n", __func__);
+ return -1;
+ }
+
+ /* Reset header */
+ th->check = cksum;
+
+ return 0;
+}
+EXPORT_SYMBOL(tcp_calc_md5_hash);
+
static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool)
{
int cpu;
diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c
index 2fbcc7d..838d491 100644
--- a/net/ipv4/tcp_diag.c
+++ b/net/ipv4/tcp_diag.c
@@ -1,8 +1,6 @@
/*
* tcp_diag.c Module for monitoring TCP transport protocols sockets.
*
- * Version: $Id: tcp_diag.c,v 1.3 2002/02/01 22:01:04 davem Exp $
- *
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index cad73b7..de30e70 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5,8 +5,6 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_input.c,v 1.243 2002/02/01 22:01:04 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Mark Evans, <evansmp@uhura.aston.ac.uk>
@@ -3450,6 +3448,43 @@
return 1;
}
+#ifdef CONFIG_TCP_MD5SIG
+/*
+ * Parse MD5 Signature option
+ */
+u8 *tcp_parse_md5sig_option(struct tcphdr *th)
+{
+ int length = (th->doff << 2) - sizeof (*th);
+ u8 *ptr = (u8*)(th + 1);
+
+ /* If the TCP option is too short, we can short cut */
+ if (length < TCPOLEN_MD5SIG)
+ return NULL;
+
+ while (length > 0) {
+ int opcode = *ptr++;
+ int opsize;
+
+ switch(opcode) {
+ case TCPOPT_EOL:
+ return NULL;
+ case TCPOPT_NOP:
+ length--;
+ continue;
+ default:
+ opsize = *ptr++;
+ if (opsize < 2 || opsize > length)
+ return NULL;
+ if (opcode == TCPOPT_MD5SIG)
+ return ptr;
+ }
+ ptr += opsize - 2;
+ length -= opsize;
+ }
+ return NULL;
+}
+#endif
+
static inline void tcp_store_ts_recent(struct tcp_sock *tp)
{
tp->rx_opt.ts_recent = tp->rx_opt.rcv_tsval;
@@ -5422,6 +5457,9 @@
EXPORT_SYMBOL(sysctl_tcp_reordering);
EXPORT_SYMBOL(sysctl_tcp_adv_win_scale);
EXPORT_SYMBOL(tcp_parse_options);
+#ifdef CONFIG_TCP_MD5SIG
+EXPORT_SYMBOL(tcp_parse_md5sig_option);
+#endif
EXPORT_SYMBOL(tcp_rcv_established);
EXPORT_SYMBOL(tcp_rcv_state_process);
EXPORT_SYMBOL(tcp_initialize_rcv_mss);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 97a2300..b219a7a 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -5,8 +5,6 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_ipv4.c,v 1.240 2002/02/01 22:01:04 davem Exp $
- *
* IPv4 specific functions
*
*
@@ -95,8 +93,13 @@
__be32 addr);
static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
__be32 saddr, __be32 daddr,
- struct tcphdr *th, int protocol,
- unsigned int tcplen);
+ struct tcphdr *th, unsigned int tcplen);
+#else
+static inline
+struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr)
+{
+ return NULL;
+}
#endif
struct inet_hashinfo __cacheline_aligned tcp_hashinfo = {
@@ -586,8 +589,7 @@
key,
ip_hdr(skb)->daddr,
ip_hdr(skb)->saddr,
- &rep.th, IPPROTO_TCP,
- arg.iov[0].iov_len);
+ &rep.th, arg.iov[0].iov_len);
}
#endif
arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr,
@@ -606,9 +608,9 @@
outside socket context is ugly, certainly. What can I do?
*/
-static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk,
- struct sk_buff *skb, u32 seq, u32 ack,
- u32 win, u32 ts)
+static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
+ u32 win, u32 ts, int oif,
+ struct tcp_md5sig_key *key)
{
struct tcphdr *th = tcp_hdr(skb);
struct {
@@ -620,10 +622,6 @@
];
} rep;
struct ip_reply_arg arg;
-#ifdef CONFIG_TCP_MD5SIG
- struct tcp_md5sig_key *key;
- struct tcp_md5sig_key tw_key;
-#endif
memset(&rep.th, 0, sizeof(struct tcphdr));
memset(&arg, 0, sizeof(arg));
@@ -649,23 +647,6 @@
rep.th.window = htons(win);
#ifdef CONFIG_TCP_MD5SIG
- /*
- * The SKB holds an imcoming packet, but may not have a valid ->sk
- * pointer. This is especially the case when we're dealing with a
- * TIME_WAIT ack, because the sk structure is long gone, and only
- * the tcp_timewait_sock remains. So the md5 key is stashed in that
- * structure, and we use it in preference. I believe that (twsk ||
- * skb->sk) holds true, but we program defensively.
- */
- if (!twsk && skb->sk) {
- key = tcp_v4_md5_do_lookup(skb->sk, ip_hdr(skb)->daddr);
- } else if (twsk && twsk->tw_md5_keylen) {
- tw_key.key = twsk->tw_md5_key;
- tw_key.keylen = twsk->tw_md5_keylen;
- key = &tw_key;
- } else
- key = NULL;
-
if (key) {
int offset = (ts) ? 3 : 0;
@@ -680,16 +661,15 @@
key,
ip_hdr(skb)->daddr,
ip_hdr(skb)->saddr,
- &rep.th, IPPROTO_TCP,
- arg.iov[0].iov_len);
+ &rep.th, arg.iov[0].iov_len);
}
#endif
arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr,
ip_hdr(skb)->saddr, /* XXX */
arg.iov[0].iov_len, IPPROTO_TCP, 0);
arg.csumoffset = offsetof(struct tcphdr, check) / 2;
- if (twsk)
- arg.bound_dev_if = twsk->tw_sk.tw_bound_dev_if;
+ if (oif)
+ arg.bound_dev_if = oif;
ip_send_reply(dev_net(skb->dev)->ipv4.tcp_sock, skb,
&arg, arg.iov[0].iov_len);
@@ -702,9 +682,12 @@
struct inet_timewait_sock *tw = inet_twsk(sk);
struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
- tcp_v4_send_ack(tcptw, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
+ tcp_v4_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
- tcptw->tw_ts_recent);
+ tcptw->tw_ts_recent,
+ tw->tw_bound_dev_if,
+ tcp_twsk_md5_key(tcptw)
+ );
inet_twsk_put(tw);
}
@@ -712,9 +695,11 @@
static void tcp_v4_reqsk_send_ack(struct sk_buff *skb,
struct request_sock *req)
{
- tcp_v4_send_ack(NULL, skb, tcp_rsk(req)->snt_isn + 1,
+ tcp_v4_send_ack(skb, tcp_rsk(req)->snt_isn + 1,
tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd,
- req->ts_recent);
+ req->ts_recent,
+ 0,
+ tcp_v4_md5_do_lookup(skb->sk, ip_hdr(skb)->daddr));
}
/*
@@ -1006,18 +991,12 @@
static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
__be32 saddr, __be32 daddr,
- struct tcphdr *th, int protocol,
+ struct tcphdr *th,
unsigned int tcplen)
{
- struct scatterlist sg[4];
- __u16 data_len;
- int block = 0;
- __sum16 old_checksum;
struct tcp_md5sig_pool *hp;
struct tcp4_pseudohdr *bp;
- struct hash_desc *desc;
int err;
- unsigned int nbytes = 0;
/*
* Okay, so RFC2385 is turned on for this connection,
@@ -1029,63 +1008,25 @@
goto clear_hash_noput;
bp = &hp->md5_blk.ip4;
- desc = &hp->md5_desc;
/*
- * 1. the TCP pseudo-header (in the order: source IP address,
+ * The TCP pseudo-header (in the order: source IP address,
* destination IP address, zero-padded protocol number, and
* segment length)
*/
bp->saddr = saddr;
bp->daddr = daddr;
bp->pad = 0;
- bp->protocol = protocol;
+ bp->protocol = IPPROTO_TCP;
bp->len = htons(tcplen);
- sg_init_table(sg, 4);
-
- sg_set_buf(&sg[block++], bp, sizeof(*bp));
- nbytes += sizeof(*bp);
-
- /* 2. the TCP header, excluding options, and assuming a
- * checksum of zero/
- */
- old_checksum = th->check;
- th->check = 0;
- sg_set_buf(&sg[block++], th, sizeof(struct tcphdr));
- nbytes += sizeof(struct tcphdr);
-
- /* 3. the TCP segment data (if any) */
- data_len = tcplen - (th->doff << 2);
- if (data_len > 0) {
- unsigned char *data = (unsigned char *)th + (th->doff << 2);
- sg_set_buf(&sg[block++], data, data_len);
- nbytes += data_len;
- }
-
- /* 4. an independently-specified key or password, known to both
- * TCPs and presumably connection-specific
- */
- sg_set_buf(&sg[block++], key->key, key->keylen);
- nbytes += key->keylen;
-
- sg_mark_end(&sg[block - 1]);
-
- /* Now store the Hash into the packet */
- err = crypto_hash_init(desc);
- if (err)
- goto clear_hash;
- err = crypto_hash_update(desc, sg, nbytes);
- if (err)
- goto clear_hash;
- err = crypto_hash_final(desc, md5_hash);
+ err = tcp_calc_md5_hash(md5_hash, key, sizeof(*bp),
+ th, tcplen, hp);
if (err)
goto clear_hash;
- /* Reset header, and free up the crypto */
+ /* Free up the crypto pool */
tcp_put_md5sig_pool();
- th->check = old_checksum;
-
out:
return 0;
clear_hash:
@@ -1099,7 +1040,7 @@
struct sock *sk,
struct dst_entry *dst,
struct request_sock *req,
- struct tcphdr *th, int protocol,
+ struct tcphdr *th,
unsigned int tcplen)
{
__be32 saddr, daddr;
@@ -1115,7 +1056,7 @@
}
return tcp_v4_do_calc_md5_hash(md5_hash, key,
saddr, daddr,
- th, protocol, tcplen);
+ th, tcplen);
}
EXPORT_SYMBOL(tcp_v4_calc_md5_hash);
@@ -1134,52 +1075,12 @@
struct tcp_md5sig_key *hash_expected;
const struct iphdr *iph = ip_hdr(skb);
struct tcphdr *th = tcp_hdr(skb);
- int length = (th->doff << 2) - sizeof(struct tcphdr);
int genhash;
- unsigned char *ptr;
unsigned char newhash[16];
hash_expected = tcp_v4_md5_do_lookup(sk, iph->saddr);
+ hash_location = tcp_parse_md5sig_option(th);
- /*
- * If the TCP option length is less than the TCP_MD5SIG
- * option length, then we can shortcut
- */
- if (length < TCPOLEN_MD5SIG) {
- if (hash_expected)
- return 1;
- else
- return 0;
- }
-
- /* Okay, we can't shortcut - we have to grub through the options */
- ptr = (unsigned char *)(th + 1);
- while (length > 0) {
- int opcode = *ptr++;
- int opsize;
-
- switch (opcode) {
- case TCPOPT_EOL:
- goto done_opts;
- case TCPOPT_NOP:
- length--;
- continue;
- default:
- opsize = *ptr++;
- if (opsize < 2)
- goto done_opts;
- if (opsize > length)
- goto done_opts;
-
- if (opcode == TCPOPT_MD5SIG) {
- hash_location = ptr;
- goto done_opts;
- }
- }
- ptr += opsize-2;
- length -= opsize;
- }
-done_opts:
/* We've parsed the options - do we have a hash? */
if (!hash_expected && !hash_location)
return 0;
@@ -1206,8 +1107,7 @@
genhash = tcp_v4_do_calc_md5_hash(newhash,
hash_expected,
iph->saddr, iph->daddr,
- th, sk->sk_protocol,
- skb->len);
+ th, skb->len);
if (genhash || memcmp(hash_location, newhash, 16) != 0) {
if (net_ratelimit()) {
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 8245247..ea68a47 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -5,8 +5,6 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_minisocks.c,v 1.15 2002/02/01 22:01:04 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Mark Evans, <evansmp@uhura.aston.ac.uk>
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index ad993ec..8f83ab4 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -5,8 +5,6 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_output.c,v 1.146 2002/02/01 22:01:04 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Mark Evans, <evansmp@uhura.aston.ac.uk>
@@ -607,7 +605,6 @@
md5,
sk, NULL, NULL,
tcp_hdr(skb),
- sk->sk_protocol,
skb->len);
}
#endif
@@ -2266,7 +2263,7 @@
tp->af_specific->calc_md5_hash(md5_hash_location,
md5,
NULL, dst, req,
- tcp_hdr(skb), sk->sk_protocol,
+ tcp_hdr(skb),
skb->len);
}
#endif
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 63ed9d6..3e358cb 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -5,8 +5,6 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_timer.c,v 1.88 2002/02/01 22:01:04 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Mark Evans, <evansmp@uhura.aston.ac.uk>
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 56fcda3..355e6d6 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -5,8 +5,6 @@
*
* The User Datagram Protocol (UDP).
*
- * Version: $Id: udp.c,v 1.102 2002/02/01 22:01:04 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Arnt Gulbrandsen, <agulbra@nvg.unit.no>
diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c
index 72ce26b..4ad16b6 100644
--- a/net/ipv4/udplite.c
+++ b/net/ipv4/udplite.c
@@ -1,8 +1,6 @@
/*
* UDPLITE An implementation of the UDP-Lite protocol (RFC 3828).
*
- * Version: $Id: udplite.c,v 1.25 2006/10/19 07:22:36 gerrit Exp $
- *
* Authors: Gerrit Renker <gerrit@erg.abdn.ac.uk>
*
* Changes:
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 147588f..9be6be3 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -6,8 +6,6 @@
* Pedro Roque <roque@di.fc.ul.pt>
* Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
*
- * $Id: addrconf.c,v 1.69 2001/10/31 21:55:54 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -231,6 +229,12 @@
return (dev->qdisc != &noop_qdisc);
}
+/* Check if a route is valid prefix route */
+static inline int addrconf_is_prefix_route(const struct rt6_info *rt)
+{
+ return ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0);
+}
+
static void addrconf_del_timer(struct inet6_ifaddr *ifp)
{
if (del_timer(&ifp->timer))
@@ -777,7 +781,7 @@
ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len);
rt = rt6_lookup(net, &prefix, NULL, ifp->idev->dev->ifindex, 1);
- if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
+ if (rt && addrconf_is_prefix_route(rt)) {
if (onlink == 0) {
ip6_del_rt(rt);
rt = NULL;
@@ -958,7 +962,8 @@
return 0;
}
-static int ipv6_get_saddr_eval(struct ipv6_saddr_score *score,
+static int ipv6_get_saddr_eval(struct net *net,
+ struct ipv6_saddr_score *score,
struct ipv6_saddr_dst *dst,
int i)
{
@@ -1037,7 +1042,8 @@
break;
case IPV6_SADDR_RULE_LABEL:
/* Rule 6: Prefer matching label */
- ret = ipv6_addr_label(&score->ifa->addr, score->addr_type,
+ ret = ipv6_addr_label(net,
+ &score->ifa->addr, score->addr_type,
score->ifa->idev->dev->ifindex) == dst->label;
break;
#ifdef CONFIG_IPV6_PRIVACY
@@ -1091,7 +1097,7 @@
dst.addr = daddr;
dst.ifindex = dst_dev ? dst_dev->ifindex : 0;
dst.scope = __ipv6_addr_src_scope(dst_type);
- dst.label = ipv6_addr_label(daddr, dst_type, dst.ifindex);
+ dst.label = ipv6_addr_label(net, daddr, dst_type, dst.ifindex);
dst.prefs = prefs;
hiscore->rule = -1;
@@ -1159,8 +1165,8 @@
for (i = 0; i < IPV6_SADDR_RULE_MAX; i++) {
int minihiscore, miniscore;
- minihiscore = ipv6_get_saddr_eval(hiscore, &dst, i);
- miniscore = ipv6_get_saddr_eval(score, &dst, i);
+ minihiscore = ipv6_get_saddr_eval(net, hiscore, &dst, i);
+ miniscore = ipv6_get_saddr_eval(net, score, &dst, i);
if (minihiscore > miniscore) {
if (i == IPV6_SADDR_RULE_SCOPE &&
@@ -1788,7 +1794,7 @@
rt = rt6_lookup(dev_net(dev), &pinfo->prefix, NULL,
dev->ifindex, 1);
- if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
+ if (rt && addrconf_is_prefix_route(rt)) {
/* Autoconf prefix route */
if (valid_lft == 0) {
ip6_del_rt(rt);
diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c
index 9bfa884..0890903 100644
--- a/net/ipv6/addrlabel.c
+++ b/net/ipv6/addrlabel.c
@@ -29,6 +29,9 @@
*/
struct ip6addrlbl_entry
{
+#ifdef CONFIG_NET_NS
+ struct net *lbl_net;
+#endif
struct in6_addr prefix;
int prefixlen;
int ifindex;
@@ -46,6 +49,16 @@
u32 seq;
} ip6addrlbl_table;
+static inline
+struct net *ip6addrlbl_net(const struct ip6addrlbl_entry *lbl)
+{
+#ifdef CONFIG_NET_NS
+ return lbl->lbl_net;
+#else
+ return &init_net;
+#endif
+}
+
/*
* Default policy table (RFC3484 + extensions)
*
@@ -65,7 +78,7 @@
#define IPV6_ADDR_LABEL_DEFAULT 0xffffffffUL
-static const __initdata struct ip6addrlbl_init_table
+static const __net_initdata struct ip6addrlbl_init_table
{
const struct in6_addr *prefix;
int prefixlen;
@@ -108,6 +121,9 @@
/* Object management */
static inline void ip6addrlbl_free(struct ip6addrlbl_entry *p)
{
+#ifdef CONFIG_NET_NS
+ release_net(p->lbl_net);
+#endif
kfree(p);
}
@@ -128,10 +144,13 @@
}
/* Find label */
-static int __ip6addrlbl_match(struct ip6addrlbl_entry *p,
+static int __ip6addrlbl_match(struct net *net,
+ struct ip6addrlbl_entry *p,
const struct in6_addr *addr,
int addrtype, int ifindex)
{
+ if (!net_eq(ip6addrlbl_net(p), net))
+ return 0;
if (p->ifindex && p->ifindex != ifindex)
return 0;
if (p->addrtype && p->addrtype != addrtype)
@@ -141,19 +160,21 @@
return 1;
}
-static struct ip6addrlbl_entry *__ipv6_addr_label(const struct in6_addr *addr,
+static struct ip6addrlbl_entry *__ipv6_addr_label(struct net *net,
+ const struct in6_addr *addr,
int type, int ifindex)
{
struct hlist_node *pos;
struct ip6addrlbl_entry *p;
hlist_for_each_entry_rcu(p, pos, &ip6addrlbl_table.head, list) {
- if (__ip6addrlbl_match(p, addr, type, ifindex))
+ if (__ip6addrlbl_match(net, p, addr, type, ifindex))
return p;
}
return NULL;
}
-u32 ipv6_addr_label(const struct in6_addr *addr, int type, int ifindex)
+u32 ipv6_addr_label(struct net *net,
+ const struct in6_addr *addr, int type, int ifindex)
{
u32 label;
struct ip6addrlbl_entry *p;
@@ -161,7 +182,7 @@
type &= IPV6_ADDR_MAPPED | IPV6_ADDR_COMPATv4 | IPV6_ADDR_LOOPBACK;
rcu_read_lock();
- p = __ipv6_addr_label(addr, type, ifindex);
+ p = __ipv6_addr_label(net, addr, type, ifindex);
label = p ? p->label : IPV6_ADDR_LABEL_DEFAULT;
rcu_read_unlock();
@@ -174,7 +195,8 @@
}
/* allocate one entry */
-static struct ip6addrlbl_entry *ip6addrlbl_alloc(const struct in6_addr *prefix,
+static struct ip6addrlbl_entry *ip6addrlbl_alloc(struct net *net,
+ const struct in6_addr *prefix,
int prefixlen, int ifindex,
u32 label)
{
@@ -216,6 +238,9 @@
newp->addrtype = addrtype;
newp->label = label;
INIT_HLIST_NODE(&newp->list);
+#ifdef CONFIG_NET_NS
+ newp->lbl_net = hold_net(net);
+#endif
atomic_set(&newp->refcnt, 1);
return newp;
}
@@ -237,6 +262,7 @@
hlist_for_each_entry_safe(p, pos, n,
&ip6addrlbl_table.head, list) {
if (p->prefixlen == newp->prefixlen &&
+ net_eq(ip6addrlbl_net(p), ip6addrlbl_net(newp)) &&
p->ifindex == newp->ifindex &&
ipv6_addr_equal(&p->prefix, &newp->prefix)) {
if (!replace) {
@@ -261,7 +287,8 @@
}
/* add a label */
-static int ip6addrlbl_add(const struct in6_addr *prefix, int prefixlen,
+static int ip6addrlbl_add(struct net *net,
+ const struct in6_addr *prefix, int prefixlen,
int ifindex, u32 label, int replace)
{
struct ip6addrlbl_entry *newp;
@@ -274,7 +301,7 @@
(unsigned int)label,
replace);
- newp = ip6addrlbl_alloc(prefix, prefixlen, ifindex, label);
+ newp = ip6addrlbl_alloc(net, prefix, prefixlen, ifindex, label);
if (IS_ERR(newp))
return PTR_ERR(newp);
spin_lock(&ip6addrlbl_table.lock);
@@ -286,7 +313,8 @@
}
/* remove a label */
-static int __ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen,
+static int __ip6addrlbl_del(struct net *net,
+ const struct in6_addr *prefix, int prefixlen,
int ifindex)
{
struct ip6addrlbl_entry *p = NULL;
@@ -300,6 +328,7 @@
hlist_for_each_entry_safe(p, pos, n, &ip6addrlbl_table.head, list) {
if (p->prefixlen == prefixlen &&
+ net_eq(ip6addrlbl_net(p), net) &&
p->ifindex == ifindex &&
ipv6_addr_equal(&p->prefix, prefix)) {
hlist_del_rcu(&p->list);
@@ -311,7 +340,8 @@
return ret;
}
-static int ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen,
+static int ip6addrlbl_del(struct net *net,
+ const struct in6_addr *prefix, int prefixlen,
int ifindex)
{
struct in6_addr prefix_buf;
@@ -324,13 +354,13 @@
ipv6_addr_prefix(&prefix_buf, prefix, prefixlen);
spin_lock(&ip6addrlbl_table.lock);
- ret = __ip6addrlbl_del(&prefix_buf, prefixlen, ifindex);
+ ret = __ip6addrlbl_del(net, &prefix_buf, prefixlen, ifindex);
spin_unlock(&ip6addrlbl_table.lock);
return ret;
}
/* add default label */
-static __init int ip6addrlbl_init(void)
+static int __net_init ip6addrlbl_net_init(struct net *net)
{
int err = 0;
int i;
@@ -338,7 +368,8 @@
ADDRLABEL(KERN_DEBUG "%s()\n", __func__);
for (i = 0; i < ARRAY_SIZE(ip6addrlbl_init_table); i++) {
- int ret = ip6addrlbl_add(ip6addrlbl_init_table[i].prefix,
+ int ret = ip6addrlbl_add(net,
+ ip6addrlbl_init_table[i].prefix,
ip6addrlbl_init_table[i].prefixlen,
0,
ip6addrlbl_init_table[i].label, 0);
@@ -349,11 +380,32 @@
return err;
}
+static void __net_exit ip6addrlbl_net_exit(struct net *net)
+{
+ struct ip6addrlbl_entry *p = NULL;
+ struct hlist_node *pos, *n;
+
+ /* Remove all labels belonging to the exiting net */
+ spin_lock(&ip6addrlbl_table.lock);
+ hlist_for_each_entry_safe(p, pos, n, &ip6addrlbl_table.head, list) {
+ if (net_eq(ip6addrlbl_net(p), net)) {
+ hlist_del_rcu(&p->list);
+ ip6addrlbl_put(p);
+ }
+ }
+ spin_unlock(&ip6addrlbl_table.lock);
+}
+
+static struct pernet_operations ipv6_addr_label_ops = {
+ .init = ip6addrlbl_net_init,
+ .exit = ip6addrlbl_net_exit,
+};
+
int __init ipv6_addr_label_init(void)
{
spin_lock_init(&ip6addrlbl_table.lock);
- return ip6addrlbl_init();
+ return register_pernet_subsys(&ipv6_addr_label_ops);
}
static const struct nla_policy ifal_policy[IFAL_MAX+1] = {
@@ -371,9 +423,6 @@
u32 label;
int err = 0;
- if (net != &init_net)
- return 0;
-
err = nlmsg_parse(nlh, sizeof(*ifal), tb, IFAL_MAX, ifal_policy);
if (err < 0)
return err;
@@ -385,7 +434,7 @@
return -EINVAL;
if (ifal->ifal_index &&
- !__dev_get_by_index(&init_net, ifal->ifal_index))
+ !__dev_get_by_index(net, ifal->ifal_index))
return -EINVAL;
if (!tb[IFAL_ADDRESS])
@@ -403,12 +452,12 @@
switch(nlh->nlmsg_type) {
case RTM_NEWADDRLABEL:
- err = ip6addrlbl_add(pfx, ifal->ifal_prefixlen,
+ err = ip6addrlbl_add(net, pfx, ifal->ifal_prefixlen,
ifal->ifal_index, label,
nlh->nlmsg_flags & NLM_F_REPLACE);
break;
case RTM_DELADDRLABEL:
- err = ip6addrlbl_del(pfx, ifal->ifal_prefixlen,
+ err = ip6addrlbl_del(net, pfx, ifal->ifal_prefixlen,
ifal->ifal_index);
break;
default:
@@ -458,12 +507,10 @@
int idx = 0, s_idx = cb->args[0];
int err;
- if (net != &init_net)
- return 0;
-
rcu_read_lock();
hlist_for_each_entry_rcu(p, pos, &ip6addrlbl_table.head, list) {
- if (idx >= s_idx) {
+ if (idx >= s_idx &&
+ net_eq(ip6addrlbl_net(p), net)) {
if ((err = ip6addrlbl_fill(skb, p,
ip6addrlbl_table.seq,
NETLINK_CB(cb->skb).pid,
@@ -499,9 +546,6 @@
struct ip6addrlbl_entry *p;
struct sk_buff *skb;
- if (net != &init_net)
- return 0;
-
err = nlmsg_parse(nlh, sizeof(*ifal), tb, IFAL_MAX, ifal_policy);
if (err < 0)
return err;
@@ -513,7 +557,7 @@
return -EINVAL;
if (ifal->ifal_index &&
- !__dev_get_by_index(&init_net, ifal->ifal_index))
+ !__dev_get_by_index(net, ifal->ifal_index))
return -EINVAL;
if (!tb[IFAL_ADDRESS])
@@ -524,7 +568,7 @@
return -EINVAL;
rcu_read_lock();
- p = __ipv6_addr_label(addr, ipv6_addr_type(addr), ifal->ifal_index);
+ p = __ipv6_addr_label(net, addr, ipv6_addr_type(addr), ifal->ifal_index);
if (p && ip6addrlbl_hold(p))
p = NULL;
lseq = ip6addrlbl_table.seq;
@@ -552,7 +596,7 @@
goto out;
}
- err = rtnl_unicast(skb, &init_net, NETLINK_CB(in_skb).pid);
+ err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid);
out:
return err;
}
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index e84b3fd..350457c 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -7,8 +7,6 @@
*
* Adapted from linux/net/ipv4/af_inet.c
*
- * $Id: af_inet6.c,v 1.66 2002/02/01 22:01:04 davem Exp $
- *
* Fixes:
* piggy, Karl Knutson : Socket protocol table
* Hideaki YOSHIFUJI : sin6_scope_id support
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 0f0f94a..f7b535d 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -5,8 +5,6 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: datagram.c,v 1.24 2002/02/01 22:01:04 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 3cd1c99..602ea82 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -7,8 +7,6 @@
* Andi Kleen <ak@muc.de>
* Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
*
- * $Id: exthdrs.c,v 1.13 2001/06/19 15:58:56 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index d42dd16..399d41f 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -5,8 +5,6 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: icmp.c,v 1.38 2002/02/08 03:57:19 davem Exp $
- *
* Based on net/ipv4/icmp.c
*
* RFC 1885
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 1ee4fa1..4de2b9e 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -5,8 +5,6 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: ip6_fib.c,v 1.25 2001/10/31 21:55:55 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 4e5c861..f77a601 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -6,8 +6,6 @@
* Pedro Roque <roque@di.fc.ul.pt>
* Ian P. Morris <I.P.Morris@soton.ac.uk>
*
- * $Id: ip6_input.c,v 1.19 2000/12/13 18:31:50 davem Exp $
- *
* Based in linux/net/ipv4/ip_input.c
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 48cdce9..40a2813 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -5,8 +5,6 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: ip6_output.c,v 1.34 2002/02/01 22:01:04 davem Exp $
- *
* Based on linux/net/ipv4/ip_output.c
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 2bda3ba..17c7b09 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -6,8 +6,6 @@
* Ville Nuorvala <vnuorval@tcs.hut.fi>
* Yasuyuki Kozakai <kozakai@linux-ipv6.org>
*
- * $Id$
- *
* Based on:
* linux/net/ipv6/sit.c and linux/net/ipv4/ipip.c
*
@@ -711,7 +709,7 @@
}
if (!ip6_tnl_rcv_ctl(t)) {
- t->stat.rx_dropped++;
+ t->dev->stats.rx_dropped++;
read_unlock(&ip6_tnl_lock);
goto discard;
}
@@ -728,8 +726,8 @@
dscp_ecn_decapsulate(t, ipv6h, skb);
- t->stat.rx_packets++;
- t->stat.rx_bytes += skb->len;
+ t->dev->stats.rx_packets++;
+ t->dev->stats.rx_bytes += skb->len;
netif_rx(skb);
read_unlock(&ip6_tnl_lock);
return 0;
@@ -849,7 +847,7 @@
__u32 *pmtu)
{
struct ip6_tnl *t = netdev_priv(dev);
- struct net_device_stats *stats = &t->stat;
+ struct net_device_stats *stats = &t->dev->stats;
struct ipv6hdr *ipv6h = ipv6_hdr(skb);
struct ipv6_tel_txoption opt;
struct dst_entry *dst;
@@ -1043,11 +1041,11 @@
ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ip6_tnl *t = netdev_priv(dev);
- struct net_device_stats *stats = &t->stat;
+ struct net_device_stats *stats = &t->dev->stats;
int ret;
if (t->recursion++) {
- t->stat.collisions++;
+ stats->collisions++;
goto tx_err;
}
@@ -1289,19 +1287,6 @@
}
/**
- * ip6_tnl_get_stats - return the stats for tunnel device
- * @dev: virtual device associated with tunnel
- *
- * Return: stats for device
- **/
-
-static struct net_device_stats *
-ip6_tnl_get_stats(struct net_device *dev)
-{
- return &(((struct ip6_tnl *)netdev_priv(dev))->stat);
-}
-
-/**
* ip6_tnl_change_mtu - change mtu manually for tunnel device
* @dev: virtual device associated with tunnel
* @new_mtu: the new mtu
@@ -1334,7 +1319,6 @@
dev->uninit = ip6_tnl_dev_uninit;
dev->destructor = free_netdev;
dev->hard_start_xmit = ip6_tnl_xmit;
- dev->get_stats = ip6_tnl_get_stats;
dev->do_ioctl = ip6_tnl_ioctl;
dev->change_mtu = ip6_tnl_change_mtu;
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 1479618..90e7630 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -388,8 +388,8 @@
skb->ip_summed = 0;
skb->pkt_type = PACKET_HOST;
dst_release(skb->dst);
- ((struct net_device_stats *)netdev_priv(reg_dev))->rx_bytes += skb->len;
- ((struct net_device_stats *)netdev_priv(reg_dev))->rx_packets++;
+ reg_dev->stats.rx_bytes += skb->len;
+ reg_dev->stats.rx_packets++;
skb->dst = NULL;
nf_reset(skb);
netif_rx(skb);
@@ -409,26 +409,20 @@
static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
{
read_lock(&mrt_lock);
- ((struct net_device_stats *)netdev_priv(dev))->tx_bytes += skb->len;
- ((struct net_device_stats *)netdev_priv(dev))->tx_packets++;
+ dev->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
ip6mr_cache_report(skb, reg_vif_num, MRT6MSG_WHOLEPKT);
read_unlock(&mrt_lock);
kfree_skb(skb);
return 0;
}
-static struct net_device_stats *reg_vif_get_stats(struct net_device *dev)
-{
- return (struct net_device_stats *)netdev_priv(dev);
-}
-
static void reg_vif_setup(struct net_device *dev)
{
dev->type = ARPHRD_PIMREG;
dev->mtu = 1500 - sizeof(struct ipv6hdr) - 8;
dev->flags = IFF_NOARP;
dev->hard_start_xmit = reg_vif_xmit;
- dev->get_stats = reg_vif_get_stats;
dev->destructor = free_netdev;
}
@@ -436,9 +430,7 @@
{
struct net_device *dev;
- dev = alloc_netdev(sizeof(struct net_device_stats), "pim6reg",
- reg_vif_setup);
-
+ dev = alloc_netdev(0, "pim6reg", reg_vif_setup);
if (dev == NULL)
return NULL;
@@ -1248,7 +1240,7 @@
#endif
/*
- * Spurious command, or MRT_VERSION which you cannot
+ * Spurious command, or MRT6_VERSION which you cannot
* set.
*/
default:
@@ -1377,8 +1369,8 @@
if (vif->flags & MIFF_REGISTER) {
vif->pkt_out++;
vif->bytes_out += skb->len;
- ((struct net_device_stats *)netdev_priv(vif->dev))->tx_bytes += skb->len;
- ((struct net_device_stats *)netdev_priv(vif->dev))->tx_packets++;
+ vif->dev->stats.tx_bytes += skb->len;
+ vif->dev->stats.tx_packets++;
ip6mr_cache_report(skb, vifi, MRT6MSG_WHOLEPKT);
kfree_skb(skb);
return 0;
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index c042ce1..a998884 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -7,8 +7,6 @@
*
* Based on linux/net/ipv4/ip_sockglue.c
*
- * $Id: ipv6_sockglue.c,v 1.41 2002/02/01 22:01:04 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index fd632dd..bd2fe4c 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -5,8 +5,6 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: mcast.c,v 1.40 2002/02/08 03:57:19 davem Exp $
- *
* Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c
*
* This program is free software; you can redistribute it and/or
@@ -164,7 +162,6 @@
((MLDV2_MASK(value, nbmant) | (1<<(nbmant))) << \
(MLDV2_MASK((value) >> (nbmant), nbexp) + (nbexp))))
-#define MLDV2_QQIC(value) MLDV2_EXP(0x80, 4, 3, value)
#define MLDV2_MRC(value) MLDV2_EXP(0x8000, 12, 3, value)
#define IPV6_MLD_MAX_MSF 64
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index 6cae547..689dec8 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -208,5 +208,17 @@
If you want to compile it as a module, say M here and read
<file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
+# security table for MAC policy
+config IP6_NF_SECURITY
+ tristate "Security table"
+ depends on IP6_NF_IPTABLES
+ depends on SECURITY
+ default m if NETFILTER_ADVANCED=n
+ help
+ This option adds a `security' table to iptables, for use
+ with Mandatory Access Control (MAC) policy.
+
+ If unsure, say N.
+
endmenu
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index fbf2c14..3f17c94 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -8,6 +8,7 @@
obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
+obj-$(CONFIG_IP6_NF_SECURITY) += ip6table_security.o
# objects for l3 independent conntrack
nf_conntrack_ipv6-objs := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o nf_conntrack_reasm.o
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index 2eff3ae..1b8815f 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -159,7 +159,6 @@
case IPQ_COPY_META:
case IPQ_COPY_NONE:
size = NLMSG_SPACE(sizeof(*pmsg));
- data_len = 0;
break;
case IPQ_COPY_PACKET:
@@ -226,8 +225,6 @@
return skb;
nlmsg_failure:
- if (skb)
- kfree_skb(skb);
*errp = -EINVAL;
printk(KERN_ERR "ip6_queue: error creating packet message\n");
return NULL;
diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c
new file mode 100644
index 0000000..063a3d9
--- /dev/null
+++ b/net/ipv6/netfilter/ip6table_security.c
@@ -0,0 +1,172 @@
+/*
+ * "security" table for IPv6
+ *
+ * This is for use by Mandatory Access Control (MAC) security models,
+ * which need to be able to manage security policy in separate context
+ * to DAC.
+ *
+ * Based on iptable_mangle.c
+ *
+ * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ * Copyright (C) 2000-2004 Netfilter Core Team <coreteam <at> netfilter.org>
+ * Copyright (C) 2008 Red Hat, Inc., James Morris <jmorris <at> redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("James Morris <jmorris <at> redhat.com>");
+MODULE_DESCRIPTION("ip6tables security table, for MAC rules");
+
+#define SECURITY_VALID_HOOKS (1 << NF_INET_LOCAL_IN) | \
+ (1 << NF_INET_FORWARD) | \
+ (1 << NF_INET_LOCAL_OUT)
+
+static struct
+{
+ struct ip6t_replace repl;
+ struct ip6t_standard entries[3];
+ struct ip6t_error term;
+} initial_table __initdata = {
+ .repl = {
+ .name = "security",
+ .valid_hooks = SECURITY_VALID_HOOKS,
+ .num_entries = 4,
+ .size = sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error),
+ .hook_entry = {
+ [NF_INET_LOCAL_IN] = 0,
+ [NF_INET_FORWARD] = sizeof(struct ip6t_standard),
+ [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2,
+ },
+ .underflow = {
+ [NF_INET_LOCAL_IN] = 0,
+ [NF_INET_FORWARD] = sizeof(struct ip6t_standard),
+ [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2,
+ },
+ },
+ .entries = {
+ IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */
+ IP6T_STANDARD_INIT(NF_ACCEPT), /* FORWARD */
+ IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
+ },
+ .term = IP6T_ERROR_INIT, /* ERROR */
+};
+
+static struct xt_table security_table = {
+ .name = "security",
+ .valid_hooks = SECURITY_VALID_HOOKS,
+ .lock = __RW_LOCK_UNLOCKED(security_table.lock),
+ .me = THIS_MODULE,
+ .af = AF_INET6,
+};
+
+static unsigned int
+ip6t_local_in_hook(unsigned int hook,
+ struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ return ip6t_do_table(skb, hook, in, out,
+ init_net.ipv6.ip6table_security);
+}
+
+static unsigned int
+ip6t_forward_hook(unsigned int hook,
+ struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ return ip6t_do_table(skb, hook, in, out,
+ init_net.ipv6.ip6table_security);
+}
+
+static unsigned int
+ip6t_local_out_hook(unsigned int hook,
+ struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ /* TBD: handle short packets via raw socket */
+ return ip6t_do_table(skb, hook, in, out,
+ init_net.ipv6.ip6table_security);
+}
+
+static struct nf_hook_ops ip6t_ops[] __read_mostly = {
+ {
+ .hook = ip6t_local_in_hook,
+ .owner = THIS_MODULE,
+ .pf = PF_INET6,
+ .hooknum = NF_INET_LOCAL_IN,
+ .priority = NF_IP6_PRI_SECURITY,
+ },
+ {
+ .hook = ip6t_forward_hook,
+ .owner = THIS_MODULE,
+ .pf = PF_INET6,
+ .hooknum = NF_INET_FORWARD,
+ .priority = NF_IP6_PRI_SECURITY,
+ },
+ {
+ .hook = ip6t_local_out_hook,
+ .owner = THIS_MODULE,
+ .pf = PF_INET6,
+ .hooknum = NF_INET_LOCAL_OUT,
+ .priority = NF_IP6_PRI_SECURITY,
+ },
+};
+
+static int __net_init ip6table_security_net_init(struct net *net)
+{
+ net->ipv6.ip6table_security =
+ ip6t_register_table(net, &security_table, &initial_table.repl);
+
+ if (IS_ERR(net->ipv6.ip6table_security))
+ return PTR_ERR(net->ipv6.ip6table_security);
+
+ return 0;
+}
+
+static void __net_exit ip6table_security_net_exit(struct net *net)
+{
+ ip6t_unregister_table(net->ipv6.ip6table_security);
+}
+
+static struct pernet_operations ip6table_security_net_ops = {
+ .init = ip6table_security_net_init,
+ .exit = ip6table_security_net_exit,
+};
+
+static int __init ip6table_security_init(void)
+{
+ int ret;
+
+ ret = register_pernet_subsys(&ip6table_security_net_ops);
+ if (ret < 0)
+ return ret;
+
+ ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
+ if (ret < 0)
+ goto cleanup_table;
+
+ return ret;
+
+cleanup_table:
+ unregister_pernet_subsys(&ip6table_security_net_ops);
+ return ret;
+}
+
+static void __exit ip6table_security_fini(void)
+{
+ nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
+ unregister_pernet_subsys(&ip6table_security_net_ops);
+}
+
+module_init(ip6table_security_init);
+module_exit(ip6table_security_fini);
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index ee713b0..14d47d8 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -89,9 +89,8 @@
means this will only run once even if count hits zero twice
(theoretically possible with SMP) */
if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
- if (atomic_dec_and_test(&ct->proto.icmp.count)
- && del_timer(&ct->timeout))
- ct->timeout.function((unsigned long)ct);
+ if (atomic_dec_and_test(&ct->proto.icmp.count))
+ nf_ct_kill_acct(ct, ctinfo, skb);
} else {
atomic_inc(&ct->proto.icmp.count);
nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c
index df0736a..cbc7e51 100644
--- a/net/ipv6/proc.c
+++ b/net/ipv6/proc.c
@@ -7,8 +7,6 @@
* PROC file system. This is very similar to the IPv4 version,
* except it reports the sockets in the INET6 address family.
*
- * Version: $Id: proc.c,v 1.17 2002/02/01 22:01:04 davem Exp $
- *
* Authors: David S. Miller (davem@caip.rutgers.edu)
* YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
*
diff --git a/net/ipv6/protocol.c b/net/ipv6/protocol.c
index f929f47..9ab7891 100644
--- a/net/ipv6/protocol.c
+++ b/net/ipv6/protocol.c
@@ -5,8 +5,6 @@
*
* PF_INET6 protocol dispatch tables.
*
- * Version: $Id: protocol.c,v 1.10 2001/05/18 02:25:49 davem Exp $
- *
* Authors: Pedro Roque <roque@di.fc.ul.pt>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 3aee123..70a57e4 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -7,8 +7,6 @@
*
* Adapted from linux/net/ipv4/raw.c
*
- * $Id: raw.c,v 1.51 2002/02/01 22:01:04 davem Exp $
- *
* Fixes:
* Hideaki YOSHIFUJI : sin6_scope_id support
* YOSHIFUJI,H.@USAGI : raw checksum (RFC2292(bis) compliance)
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 798cabc..13509f9 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -5,8 +5,6 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: reassembly.c,v 1.26 2001/03/07 22:00:57 davem Exp $
- *
* Based on: net/ipv4/ip_fragment.c
*
* This program is free software; you can redistribute it and/or
@@ -632,7 +630,7 @@
};
#ifdef CONFIG_SYSCTL
-static struct ctl_table ip6_frags_ctl_table[] = {
+static struct ctl_table ip6_frags_ns_ctl_table[] = {
{
.ctl_name = NET_IPV6_IP6FRAG_HIGH_THRESH,
.procname = "ip6frag_high_thresh",
@@ -658,6 +656,10 @@
.proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies,
},
+ { }
+};
+
+static struct ctl_table ip6_frags_ctl_table[] = {
{
.ctl_name = NET_IPV6_IP6FRAG_SECRET_INTERVAL,
.procname = "ip6frag_secret_interval",
@@ -670,21 +672,20 @@
{ }
};
-static int ip6_frags_sysctl_register(struct net *net)
+static int ip6_frags_ns_sysctl_register(struct net *net)
{
struct ctl_table *table;
struct ctl_table_header *hdr;
- table = ip6_frags_ctl_table;
+ table = ip6_frags_ns_ctl_table;
if (net != &init_net) {
- table = kmemdup(table, sizeof(ip6_frags_ctl_table), GFP_KERNEL);
+ table = kmemdup(table, sizeof(ip6_frags_ns_ctl_table), GFP_KERNEL);
if (table == NULL)
goto err_alloc;
table[0].data = &net->ipv6.frags.high_thresh;
table[1].data = &net->ipv6.frags.low_thresh;
table[2].data = &net->ipv6.frags.timeout;
- table[3].mode &= ~0222;
}
hdr = register_net_sysctl_table(net, net_ipv6_ctl_path, table);
@@ -701,7 +702,7 @@
return -ENOMEM;
}
-static void ip6_frags_sysctl_unregister(struct net *net)
+static void ip6_frags_ns_sysctl_unregister(struct net *net)
{
struct ctl_table *table;
@@ -709,13 +710,36 @@
unregister_net_sysctl_table(net->ipv6.sysctl.frags_hdr);
kfree(table);
}
+
+static struct ctl_table_header *ip6_ctl_header;
+
+static int ip6_frags_sysctl_register(void)
+{
+ ip6_ctl_header = register_net_sysctl_rotable(net_ipv6_ctl_path,
+ ip6_frags_ctl_table);
+ return ip6_ctl_header == NULL ? -ENOMEM : 0;
+}
+
+static void ip6_frags_sysctl_unregister(void)
+{
+ unregister_net_sysctl_table(ip6_ctl_header);
+}
#else
-static inline int ip6_frags_sysctl_register(struct net *net)
+static inline int ip6_frags_ns_sysctl_register(struct net *net)
{
return 0;
}
-static inline void ip6_frags_sysctl_unregister(struct net *net)
+static inline void ip6_frags_ns_sysctl_unregister(struct net *net)
+{
+}
+
+static inline int ip6_frags_sysctl_register(void)
+{
+ return 0;
+}
+
+static inline void ip6_frags_sysctl_unregister(void)
{
}
#endif
@@ -728,12 +752,12 @@
inet_frags_init_net(&net->ipv6.frags);
- return ip6_frags_sysctl_register(net);
+ return ip6_frags_ns_sysctl_register(net);
}
static void ipv6_frags_exit_net(struct net *net)
{
- ip6_frags_sysctl_unregister(net);
+ ip6_frags_ns_sysctl_unregister(net);
inet_frags_exit_net(&net->ipv6.frags, &ip6_frags);
}
@@ -750,7 +774,13 @@
if (ret)
goto out;
- register_pernet_subsys(&ip6_frags_ops);
+ ret = ip6_frags_sysctl_register();
+ if (ret)
+ goto err_sysctl;
+
+ ret = register_pernet_subsys(&ip6_frags_ops);
+ if (ret)
+ goto err_pernet;
ip6_frags.hashfn = ip6_hashfn;
ip6_frags.constructor = ip6_frag_init;
@@ -763,11 +793,18 @@
inet_frags_init(&ip6_frags);
out:
return ret;
+
+err_pernet:
+ ip6_frags_sysctl_unregister();
+err_sysctl:
+ inet6_del_protocol(&frag_protocol, IPPROTO_FRAGMENT);
+ goto out;
}
void ipv6_frag_exit(void)
{
inet_frags_fini(&ip6_frags);
+ ip6_frags_sysctl_unregister();
unregister_pernet_subsys(&ip6_frags_ops);
inet6_del_protocol(&frag_protocol, IPPROTO_FRAGMENT);
}
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index d1f3e19..efe036a 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -5,8 +5,6 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: route.c,v 1.56 2001/10/31 21:55:55 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 3de6ffd..b0c5080 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -6,8 +6,6 @@
* Pedro Roque <roque@di.fc.ul.pt>
* Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
*
- * $Id: sit.c,v 1.53 2001/09/25 05:09:53 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -491,13 +489,13 @@
if ((tunnel->dev->priv_flags & IFF_ISATAP) &&
!isatap_chksrc(skb, iph, tunnel)) {
- tunnel->stat.rx_errors++;
+ tunnel->dev->stats.rx_errors++;
read_unlock(&ipip6_lock);
kfree_skb(skb);
return 0;
}
- tunnel->stat.rx_packets++;
- tunnel->stat.rx_bytes += skb->len;
+ tunnel->dev->stats.rx_packets++;
+ tunnel->dev->stats.rx_bytes += skb->len;
skb->dev = tunnel->dev;
dst_release(skb->dst);
skb->dst = NULL;
@@ -537,7 +535,7 @@
static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
- struct net_device_stats *stats = &tunnel->stat;
+ struct net_device_stats *stats = &tunnel->dev->stats;
struct iphdr *tiph = &tunnel->parms.iph;
struct ipv6hdr *iph6 = ipv6_hdr(skb);
u8 tos = tunnel->parms.iph.tos;
@@ -551,7 +549,7 @@
int addr_type;
if (tunnel->recursion++) {
- tunnel->stat.collisions++;
+ stats->collisions++;
goto tx_error;
}
@@ -618,20 +616,20 @@
.oif = tunnel->parms.link,
.proto = IPPROTO_IPV6 };
if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
- tunnel->stat.tx_carrier_errors++;
+ stats->tx_carrier_errors++;
goto tx_error_icmp;
}
}
if (rt->rt_type != RTN_UNICAST) {
ip_rt_put(rt);
- tunnel->stat.tx_carrier_errors++;
+ stats->tx_carrier_errors++;
goto tx_error_icmp;
}
tdev = rt->u.dst.dev;
if (tdev == dev) {
ip_rt_put(rt);
- tunnel->stat.collisions++;
+ stats->collisions++;
goto tx_error;
}
@@ -641,7 +639,7 @@
mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu;
if (mtu < 68) {
- tunnel->stat.collisions++;
+ stats->collisions++;
ip_rt_put(rt);
goto tx_error;
}
@@ -916,11 +914,6 @@
return err;
}
-static struct net_device_stats *ipip6_tunnel_get_stats(struct net_device *dev)
-{
- return &(((struct ip_tunnel*)netdev_priv(dev))->stat);
-}
-
static int ipip6_tunnel_change_mtu(struct net_device *dev, int new_mtu)
{
if (new_mtu < IPV6_MIN_MTU || new_mtu > 0xFFF8 - sizeof(struct iphdr))
@@ -934,7 +927,6 @@
dev->uninit = ipip6_tunnel_uninit;
dev->destructor = free_netdev;
dev->hard_start_xmit = ipip6_tunnel_xmit;
- dev->get_stats = ipip6_tunnel_get_stats;
dev->do_ioctl = ipip6_tunnel_ioctl;
dev->change_mtu = ipip6_tunnel_change_mtu;
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
index 3804dcb..5c992745 100644
--- a/net/ipv6/sysctl_net_ipv6.c
+++ b/net/ipv6/sysctl_net_ipv6.c
@@ -37,6 +37,10 @@
.mode = 0644,
.proc_handler = &proc_dointvec
},
+ { .ctl_name = 0 }
+};
+
+static ctl_table ipv6_table[] = {
{
.ctl_name = NET_IPV6_MLD_MAX_MSF,
.procname = "mld_max_msf",
@@ -80,12 +84,6 @@
ipv6_table[2].data = &net->ipv6.sysctl.bindv6only;
- /* We don't want this value to be per namespace, it should be global
- to all namespaces, so make it read-only when we are not in the
- init network namespace */
- if (net != &init_net)
- ipv6_table[3].mode = 0444;
-
net->ipv6.sysctl.table = register_net_sysctl_table(net, net_ipv6_ctl_path,
ipv6_table);
if (!net->ipv6.sysctl.table)
@@ -126,12 +124,29 @@
.exit = ipv6_sysctl_net_exit,
};
+static struct ctl_table_header *ip6_header;
+
int ipv6_sysctl_register(void)
{
- return register_pernet_subsys(&ipv6_sysctl_net_ops);
+ int err = -ENOMEM;;
+
+ ip6_header = register_net_sysctl_rotable(net_ipv6_ctl_path, ipv6_table);
+ if (ip6_header == NULL)
+ goto out;
+
+ err = register_pernet_subsys(&ipv6_sysctl_net_ops);
+ if (err)
+ goto err_pernet;
+out:
+ return err;
+
+err_pernet:
+ unregister_net_sysctl_table(ip6_header);
+ goto out;
}
void ipv6_sysctl_unregister(void)
{
+ unregister_net_sysctl_table(ip6_header);
unregister_pernet_subsys(&ipv6_sysctl_net_ops);
}
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index cb46749..ebed5d3 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -5,8 +5,6 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: tcp_ipv6.c,v 1.144 2002/02/01 22:01:04 davem Exp $
- *
* Based on:
* linux/net/ipv4/tcp.c
* linux/net/ipv4/tcp_input.c
@@ -82,6 +80,12 @@
#ifdef CONFIG_TCP_MD5SIG
static struct tcp_sock_af_ops tcp_sock_ipv6_specific;
static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific;
+#else
+static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
+ struct in6_addr *addr)
+{
+ return NULL;
+}
#endif
static void tcp_v6_hash(struct sock *sk)
@@ -736,78 +740,34 @@
static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
struct in6_addr *saddr,
struct in6_addr *daddr,
- struct tcphdr *th, int protocol,
- unsigned int tcplen)
+ struct tcphdr *th, unsigned int tcplen)
{
- struct scatterlist sg[4];
- __u16 data_len;
- int block = 0;
- __sum16 cksum;
struct tcp_md5sig_pool *hp;
struct tcp6_pseudohdr *bp;
- struct hash_desc *desc;
int err;
- unsigned int nbytes = 0;
hp = tcp_get_md5sig_pool();
if (!hp) {
printk(KERN_WARNING "%s(): hash pool not found...\n", __func__);
goto clear_hash_noput;
}
+
bp = &hp->md5_blk.ip6;
- desc = &hp->md5_desc;
/* 1. TCP pseudo-header (RFC2460) */
ipv6_addr_copy(&bp->saddr, saddr);
ipv6_addr_copy(&bp->daddr, daddr);
bp->len = htonl(tcplen);
- bp->protocol = htonl(protocol);
+ bp->protocol = htonl(IPPROTO_TCP);
- sg_init_table(sg, 4);
+ err = tcp_calc_md5_hash(md5_hash, key, sizeof(*bp),
+ th, tcplen, hp);
- sg_set_buf(&sg[block++], bp, sizeof(*bp));
- nbytes += sizeof(*bp);
-
- /* 2. TCP header, excluding options */
- cksum = th->check;
- th->check = 0;
- sg_set_buf(&sg[block++], th, sizeof(*th));
- nbytes += sizeof(*th);
-
- /* 3. TCP segment data (if any) */
- data_len = tcplen - (th->doff << 2);
- if (data_len > 0) {
- u8 *data = (u8 *)th + (th->doff << 2);
- sg_set_buf(&sg[block++], data, data_len);
- nbytes += data_len;
- }
-
- /* 4. shared key */
- sg_set_buf(&sg[block++], key->key, key->keylen);
- nbytes += key->keylen;
-
- sg_mark_end(&sg[block - 1]);
-
- /* Now store the hash into the packet */
- err = crypto_hash_init(desc);
- if (err) {
- printk(KERN_WARNING "%s(): hash_init failed\n", __func__);
+ if (err)
goto clear_hash;
- }
- err = crypto_hash_update(desc, sg, nbytes);
- if (err) {
- printk(KERN_WARNING "%s(): hash_update failed\n", __func__);
- goto clear_hash;
- }
- err = crypto_hash_final(desc, md5_hash);
- if (err) {
- printk(KERN_WARNING "%s(): hash_final failed\n", __func__);
- goto clear_hash;
- }
- /* Reset header, and free up the crypto */
+ /* Free up the crypto pool */
tcp_put_md5sig_pool();
- th->check = cksum;
out:
return 0;
clear_hash:
@@ -821,8 +781,7 @@
struct sock *sk,
struct dst_entry *dst,
struct request_sock *req,
- struct tcphdr *th, int protocol,
- unsigned int tcplen)
+ struct tcphdr *th, unsigned int tcplen)
{
struct in6_addr *saddr, *daddr;
@@ -835,7 +794,7 @@
}
return tcp_v6_do_calc_md5_hash(md5_hash, key,
saddr, daddr,
- th, protocol, tcplen);
+ th, tcplen);
}
static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb)
@@ -844,43 +803,12 @@
struct tcp_md5sig_key *hash_expected;
struct ipv6hdr *ip6h = ipv6_hdr(skb);
struct tcphdr *th = tcp_hdr(skb);
- int length = (th->doff << 2) - sizeof (*th);
int genhash;
- u8 *ptr;
u8 newhash[16];
hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr);
+ hash_location = tcp_parse_md5sig_option(th);
- /* If the TCP option is too short, we can short cut */
- if (length < TCPOLEN_MD5SIG)
- return hash_expected ? 1 : 0;
-
- /* parse options */
- ptr = (u8*)(th + 1);
- while (length > 0) {
- int opcode = *ptr++;
- int opsize;
-
- switch(opcode) {
- case TCPOPT_EOL:
- goto done_opts;
- case TCPOPT_NOP:
- length--;
- continue;
- default:
- opsize = *ptr++;
- if (opsize < 2 || opsize > length)
- goto done_opts;
- if (opcode == TCPOPT_MD5SIG) {
- hash_location = ptr;
- goto done_opts;
- }
- }
- ptr += opsize - 2;
- length -= opsize;
- }
-
-done_opts:
/* do we have a hash as expected? */
if (!hash_expected) {
if (!hash_location)
@@ -910,8 +838,7 @@
genhash = tcp_v6_do_calc_md5_hash(newhash,
hash_expected,
&ip6h->saddr, &ip6h->daddr,
- th, sk->sk_protocol,
- skb->len);
+ th, skb->len);
if (genhash || memcmp(hash_location, newhash, 16) != 0) {
if (net_ratelimit()) {
printk(KERN_INFO "MD5 Hash %s for "
@@ -1051,7 +978,7 @@
tcp_v6_do_calc_md5_hash((__u8 *)&opt[1], key,
&ipv6_hdr(skb)->daddr,
&ipv6_hdr(skb)->saddr,
- t1, IPPROTO_TCP, tot_len);
+ t1, tot_len);
}
#endif
@@ -1088,8 +1015,8 @@
kfree_skb(buff);
}
-static void tcp_v6_send_ack(struct tcp_timewait_sock *tw,
- struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts)
+static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts,
+ struct tcp_md5sig_key *key)
{
struct tcphdr *th = tcp_hdr(skb), *t1;
struct sk_buff *buff;
@@ -1098,22 +1025,6 @@
struct sock *ctl_sk = net->ipv6.tcp_sk;
unsigned int tot_len = sizeof(struct tcphdr);
__be32 *topt;
-#ifdef CONFIG_TCP_MD5SIG
- struct tcp_md5sig_key *key;
- struct tcp_md5sig_key tw_key;
-#endif
-
-#ifdef CONFIG_TCP_MD5SIG
- if (!tw && skb->sk) {
- key = tcp_v6_md5_do_lookup(skb->sk, &ipv6_hdr(skb)->daddr);
- } else if (tw && tw->tw_md5_keylen) {
- tw_key.key = tw->tw_md5_key;
- tw_key.keylen = tw->tw_md5_keylen;
- key = &tw_key;
- } else {
- key = NULL;
- }
-#endif
if (ts)
tot_len += TCPOLEN_TSTAMP_ALIGNED;
@@ -1157,7 +1068,7 @@
tcp_v6_do_calc_md5_hash((__u8 *)topt, key,
&ipv6_hdr(skb)->daddr,
&ipv6_hdr(skb)->saddr,
- t1, IPPROTO_TCP, tot_len);
+ t1, tot_len);
}
#endif
@@ -1193,16 +1104,17 @@
struct inet_timewait_sock *tw = inet_twsk(sk);
struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
- tcp_v6_send_ack(tcptw, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
+ tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
- tcptw->tw_ts_recent);
+ tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw));
inet_twsk_put(tw);
}
static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req)
{
- tcp_v6_send_ack(NULL, skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent);
+ tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent,
+ tcp_v6_md5_do_lookup(skb->sk, &ipv6_hdr(skb)->daddr));
}
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index dd30962..e0693ff 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -7,8 +7,6 @@
*
* Based on linux/ipv4/udp.c
*
- * $Id: udp.c,v 1.65 2002/02/01 22:01:04 davem Exp $
- *
* Fixes:
* Hideaki YOSHIFUJI : sin6_scope_id support
* YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which
diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c
index 491efd0..f6cdcb3 100644
--- a/net/ipv6/udplite.c
+++ b/net/ipv6/udplite.c
@@ -2,8 +2,6 @@
* UDPLITEv6 An implementation of the UDP-Lite protocol over IPv6.
* See also net/ipv4/udplite.c
*
- * Version: $Id: udplite.c,v 1.9 2006/10/19 08:28:10 gerrit Exp $
- *
* Authors: Gerrit Renker <gerrit@erg.abdn.ac.uk>
*
* Changes:
diff --git a/net/irda/irnet/irnet_ppp.c b/net/irda/irnet/irnet_ppp.c
index e0eab59..f6e54fa 100644
--- a/net/irda/irnet/irnet_ppp.c
+++ b/net/irda/irnet/irnet_ppp.c
@@ -628,8 +628,8 @@
* This is the way pppd configure us and control us while the PPP
* instance is active.
*/
-static int
-dev_irnet_ioctl(struct inode * inode,
+static long
+dev_irnet_ioctl(
struct file * file,
unsigned int cmd,
unsigned long arg)
@@ -660,6 +660,7 @@
{
DEBUG(FS_INFO, "Entering PPP discipline.\n");
/* PPP channel setup (ap->chan in configued in dev_irnet_open())*/
+ lock_kernel();
err = ppp_register_channel(&ap->chan);
if(err == 0)
{
@@ -672,12 +673,14 @@
}
else
DERROR(FS_ERROR, "Can't setup PPP channel...\n");
+ unlock_kernel();
}
else
{
/* In theory, should be N_TTY */
DEBUG(FS_INFO, "Exiting PPP discipline.\n");
/* Disconnect from the generic PPP layer */
+ lock_kernel();
if(ap->ppp_open)
{
ap->ppp_open = 0;
@@ -686,24 +689,20 @@
else
DERROR(FS_ERROR, "Channel not registered !\n");
err = 0;
+ unlock_kernel();
}
break;
/* Query PPP channel and unit number */
case PPPIOCGCHAN:
- if(!ap->ppp_open)
- break;
- if(put_user(ppp_channel_index(&ap->chan), (int __user *)argp))
- break;
- DEBUG(FS_INFO, "Query channel.\n");
- err = 0;
+ if(ap->ppp_open && !put_user(ppp_channel_index(&ap->chan),
+ (int __user *)argp))
+ err = 0;
break;
case PPPIOCGUNIT:
- if(!ap->ppp_open)
- break;
- if(put_user(ppp_unit_number(&ap->chan), (int __user *)argp))
- break;
- DEBUG(FS_INFO, "Query unit number.\n");
+ lock_kernel();
+ if(ap->ppp_open && !put_user(ppp_unit_number(&ap->chan),
+ (int __user *)argp))
err = 0;
break;
@@ -723,34 +722,39 @@
DEBUG(FS_INFO, "Standard PPP ioctl.\n");
if(!capable(CAP_NET_ADMIN))
err = -EPERM;
- else
+ else {
+ lock_kernel();
err = ppp_irnet_ioctl(&ap->chan, cmd, arg);
+ unlock_kernel();
+ }
break;
/* TTY IOCTLs : Pretend that we are a tty, to keep pppd happy */
/* Get termios */
case TCGETS:
DEBUG(FS_INFO, "Get termios.\n");
+ lock_kernel();
#ifndef TCGETS2
- if(kernel_termios_to_user_termios((struct termios __user *)argp, &ap->termios))
- break;
+ if(!kernel_termios_to_user_termios((struct termios __user *)argp, &ap->termios))
+ err = 0;
#else
if(kernel_termios_to_user_termios_1((struct termios __user *)argp, &ap->termios))
- break;
+ err = 0;
#endif
- err = 0;
+ unlock_kernel();
break;
/* Set termios */
case TCSETSF:
DEBUG(FS_INFO, "Set termios.\n");
+ lock_kernel();
#ifndef TCGETS2
- if(user_termios_to_kernel_termios(&ap->termios, (struct termios __user *)argp))
- break;
+ if(!user_termios_to_kernel_termios(&ap->termios, (struct termios __user *)argp))
+ err = 0;
#else
- if(user_termios_to_kernel_termios_1(&ap->termios, (struct termios __user *)argp))
- break;
+ if(!user_termios_to_kernel_termios_1(&ap->termios, (struct termios __user *)argp))
+ err = 0;
#endif
- err = 0;
+ unlock_kernel();
break;
/* Set DTR/RTS */
@@ -773,7 +777,9 @@
* We should also worry that we don't accept junk here and that
* we get rid of our own buffers */
#ifdef FLUSH_TO_PPP
+ lock_kernel();
ppp_output_wakeup(&ap->chan);
+ unlock_kernel();
#endif /* FLUSH_TO_PPP */
err = 0;
break;
@@ -788,7 +794,7 @@
default:
DERROR(FS_ERROR, "Unsupported ioctl (0x%X)\n", cmd);
- err = -ENOIOCTLCMD;
+ err = -ENOTTY;
}
DEXIT(FS_TRACE, " - err = 0x%X\n", err);
diff --git a/net/irda/irnet/irnet_ppp.h b/net/irda/irnet/irnet_ppp.h
index d2beb7d..d9f8bd4 100644
--- a/net/irda/irnet/irnet_ppp.h
+++ b/net/irda/irnet/irnet_ppp.h
@@ -76,9 +76,8 @@
static unsigned int
dev_irnet_poll(struct file *,
poll_table *);
-static int
- dev_irnet_ioctl(struct inode *,
- struct file *,
+static long
+ dev_irnet_ioctl(struct file *,
unsigned int,
unsigned long);
/* ------------------------ PPP INTERFACE ------------------------ */
@@ -102,7 +101,7 @@
.read = dev_irnet_read,
.write = dev_irnet_write,
.poll = dev_irnet_poll,
- .ioctl = dev_irnet_ioctl,
+ .unlocked_ioctl = dev_irnet_ioctl,
.open = dev_irnet_open,
.release = dev_irnet_close
/* Also : llseek, readdir, mmap, flush, fsync, fasync, lock, readv, writev */
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index 7b0038f..58e4aee3 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -644,6 +644,7 @@
}
txmsg.class = 0;
+ memcpy(&txmsg.class, skb->data, skb->len >= 4 ? 4 : skb->len);
txmsg.tag = iucv->send_tag++;
memcpy(skb->cb, &txmsg.tag, 4);
skb_queue_tail(&iucv->send_skb_q, skb);
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c
index 9189707..531a206 100644
--- a/net/iucv/iucv.c
+++ b/net/iucv/iucv.c
@@ -474,14 +474,14 @@
{
int cpu;
- preempt_disable();
+ get_online_cpus();
for_each_online_cpu(cpu)
/* Enable all cpus with a declared buffer. */
if (cpu_isset(cpu, iucv_buffer_cpumask) &&
!cpu_isset(cpu, iucv_irq_cpumask))
smp_call_function_single(cpu, iucv_allow_cpu,
NULL, 0, 1);
- preempt_enable();
+ put_online_cpus();
}
/**
@@ -521,16 +521,17 @@
goto out;
/* Declare per cpu buffers. */
rc = -EIO;
- preempt_disable();
+ get_online_cpus();
for_each_online_cpu(cpu)
smp_call_function_single(cpu, iucv_declare_cpu, NULL, 0, 1);
- preempt_enable();
if (cpus_empty(iucv_buffer_cpumask))
/* No cpu could declare an iucv buffer. */
goto out_path;
+ put_online_cpus();
return 0;
out_path:
+ put_online_cpus();
kfree(iucv_path_table);
out:
return rc;
@@ -545,7 +546,9 @@
*/
static void iucv_disable(void)
{
+ get_online_cpus();
on_each_cpu(iucv_retrieve_cpu, NULL, 0, 1);
+ put_online_cpus();
kfree(iucv_path_table);
}
@@ -598,7 +601,7 @@
return NOTIFY_OK;
}
-static struct notifier_block __cpuinitdata iucv_cpu_notifier = {
+static struct notifier_block __refdata iucv_cpu_notifier = {
.notifier_call = iucv_cpu_notify,
};
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 7470e36..f0fc46c 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -579,25 +579,43 @@
return (proto ? proto : IPSEC_PROTO_ANY);
}
-static int pfkey_sadb_addr2xfrm_addr(struct sadb_address *addr,
- xfrm_address_t *xaddr)
+static inline int pfkey_sockaddr_len(sa_family_t family)
{
- switch (((struct sockaddr*)(addr + 1))->sa_family) {
+ switch (family) {
+ case AF_INET:
+ return sizeof(struct sockaddr_in);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ case AF_INET6:
+ return sizeof(struct sockaddr_in6);
+#endif
+ }
+ return 0;
+}
+
+static
+int pfkey_sockaddr_extract(const struct sockaddr *sa, xfrm_address_t *xaddr)
+{
+ switch (sa->sa_family) {
case AF_INET:
xaddr->a4 =
- ((struct sockaddr_in *)(addr + 1))->sin_addr.s_addr;
+ ((struct sockaddr_in *)sa)->sin_addr.s_addr;
return AF_INET;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
case AF_INET6:
memcpy(xaddr->a6,
- &((struct sockaddr_in6 *)(addr + 1))->sin6_addr,
+ &((struct sockaddr_in6 *)sa)->sin6_addr,
sizeof(struct in6_addr));
return AF_INET6;
#endif
- default:
- return 0;
}
- /* NOTREACHED */
+ return 0;
+}
+
+static
+int pfkey_sadb_addr2xfrm_addr(struct sadb_address *addr, xfrm_address_t *xaddr)
+{
+ return pfkey_sockaddr_extract((struct sockaddr *)(addr + 1),
+ xaddr);
}
static struct xfrm_state *pfkey_xfrm_state_lookup(struct sadb_msg *hdr, void **ext_hdrs)
@@ -642,20 +660,11 @@
}
#define PFKEY_ALIGN8(a) (1 + (((a) - 1) | (8 - 1)))
+
static int
pfkey_sockaddr_size(sa_family_t family)
{
- switch (family) {
- case AF_INET:
- return PFKEY_ALIGN8(sizeof(struct sockaddr_in));
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- case AF_INET6:
- return PFKEY_ALIGN8(sizeof(struct sockaddr_in6));
-#endif
- default:
- return 0;
- }
- /* NOTREACHED */
+ return PFKEY_ALIGN8(pfkey_sockaddr_len(family));
}
static inline int pfkey_mode_from_xfrm(int mode)
@@ -687,6 +696,36 @@
}
}
+static unsigned int pfkey_sockaddr_fill(xfrm_address_t *xaddr, __be16 port,
+ struct sockaddr *sa,
+ unsigned short family)
+{
+ switch (family) {
+ case AF_INET:
+ {
+ struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+ sin->sin_family = AF_INET;
+ sin->sin_port = port;
+ sin->sin_addr.s_addr = xaddr->a4;
+ memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+ return 32;
+ }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = port;
+ sin6->sin6_flowinfo = 0;
+ ipv6_addr_copy(&sin6->sin6_addr, (struct in6_addr *)xaddr->a6);
+ sin6->sin6_scope_id = 0;
+ return 128;
+ }
+#endif
+ }
+ return 0;
+}
+
static struct sk_buff *__pfkey_xfrm_state2msg(struct xfrm_state *x,
int add_keys, int hsc)
{
@@ -697,13 +736,9 @@
struct sadb_address *addr;
struct sadb_key *key;
struct sadb_x_sa2 *sa2;
- struct sockaddr_in *sin;
struct sadb_x_sec_ctx *sec_ctx;
struct xfrm_sec_ctx *xfrm_ctx;
int ctx_size = 0;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- struct sockaddr_in6 *sin6;
-#endif
int size;
int auth_key_size = 0;
int encrypt_key_size = 0;
@@ -732,14 +767,7 @@
}
/* identity & sensitivity */
-
- if ((x->props.family == AF_INET &&
- x->sel.saddr.a4 != x->props.saddr.a4)
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- || (x->props.family == AF_INET6 &&
- memcmp (x->sel.saddr.a6, x->props.saddr.a6, sizeof (struct in6_addr)))
-#endif
- )
+ if (xfrm_addr_cmp(&x->sel.saddr, &x->props.saddr, x->props.family))
size += sizeof(struct sadb_address) + sockaddr_size;
if (add_keys) {
@@ -861,29 +889,12 @@
protocol's number." - RFC2367 */
addr->sadb_address_proto = 0;
addr->sadb_address_reserved = 0;
- if (x->props.family == AF_INET) {
- addr->sadb_address_prefixlen = 32;
- sin = (struct sockaddr_in *) (addr + 1);
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = x->props.saddr.a4;
- sin->sin_port = 0;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- else if (x->props.family == AF_INET6) {
- addr->sadb_address_prefixlen = 128;
-
- sin6 = (struct sockaddr_in6 *) (addr + 1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- sin6->sin6_flowinfo = 0;
- memcpy(&sin6->sin6_addr, x->props.saddr.a6,
- sizeof(struct in6_addr));
- sin6->sin6_scope_id = 0;
- }
-#endif
- else
+ addr->sadb_address_prefixlen =
+ pfkey_sockaddr_fill(&x->props.saddr, 0,
+ (struct sockaddr *) (addr + 1),
+ x->props.family);
+ if (!addr->sadb_address_prefixlen)
BUG();
/* dst address */
@@ -894,71 +905,33 @@
sizeof(uint64_t);
addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
addr->sadb_address_proto = 0;
- addr->sadb_address_prefixlen = 32; /* XXX */
addr->sadb_address_reserved = 0;
- if (x->props.family == AF_INET) {
- sin = (struct sockaddr_in *) (addr + 1);
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = x->id.daddr.a4;
- sin->sin_port = 0;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- if (x->sel.saddr.a4 != x->props.saddr.a4) {
- addr = (struct sadb_address*) skb_put(skb,
- sizeof(struct sadb_address)+sockaddr_size);
- addr->sadb_address_len =
- (sizeof(struct sadb_address)+sockaddr_size)/
- sizeof(uint64_t);
- addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY;
- addr->sadb_address_proto =
- pfkey_proto_from_xfrm(x->sel.proto);
- addr->sadb_address_prefixlen = x->sel.prefixlen_s;
- addr->sadb_address_reserved = 0;
-
- sin = (struct sockaddr_in *) (addr + 1);
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = x->sel.saddr.a4;
- sin->sin_port = x->sel.sport;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- }
- }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- else if (x->props.family == AF_INET6) {
- addr->sadb_address_prefixlen = 128;
-
- sin6 = (struct sockaddr_in6 *) (addr + 1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- sin6->sin6_flowinfo = 0;
- memcpy(&sin6->sin6_addr, x->id.daddr.a6, sizeof(struct in6_addr));
- sin6->sin6_scope_id = 0;
-
- if (memcmp (x->sel.saddr.a6, x->props.saddr.a6,
- sizeof(struct in6_addr))) {
- addr = (struct sadb_address *) skb_put(skb,
- sizeof(struct sadb_address)+sockaddr_size);
- addr->sadb_address_len =
- (sizeof(struct sadb_address)+sockaddr_size)/
- sizeof(uint64_t);
- addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY;
- addr->sadb_address_proto =
- pfkey_proto_from_xfrm(x->sel.proto);
- addr->sadb_address_prefixlen = x->sel.prefixlen_s;
- addr->sadb_address_reserved = 0;
-
- sin6 = (struct sockaddr_in6 *) (addr + 1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = x->sel.sport;
- sin6->sin6_flowinfo = 0;
- memcpy(&sin6->sin6_addr, x->sel.saddr.a6,
- sizeof(struct in6_addr));
- sin6->sin6_scope_id = 0;
- }
- }
-#endif
- else
+ addr->sadb_address_prefixlen =
+ pfkey_sockaddr_fill(&x->id.daddr, 0,
+ (struct sockaddr *) (addr + 1),
+ x->props.family);
+ if (!addr->sadb_address_prefixlen)
BUG();
+ if (xfrm_addr_cmp(&x->sel.saddr, &x->props.saddr,
+ x->props.family)) {
+ addr = (struct sadb_address*) skb_put(skb,
+ sizeof(struct sadb_address)+sockaddr_size);
+ addr->sadb_address_len =
+ (sizeof(struct sadb_address)+sockaddr_size)/
+ sizeof(uint64_t);
+ addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY;
+ addr->sadb_address_proto =
+ pfkey_proto_from_xfrm(x->sel.proto);
+ addr->sadb_address_prefixlen = x->sel.prefixlen_s;
+ addr->sadb_address_reserved = 0;
+
+ pfkey_sockaddr_fill(&x->sel.saddr, x->sel.sport,
+ (struct sockaddr *) (addr + 1),
+ x->props.family);
+ }
+
/* auth key */
if (add_keys && auth_key_size) {
key = (struct sadb_key *) skb_put(skb,
@@ -1853,10 +1826,6 @@
parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
{
struct xfrm_tmpl *t = xp->xfrm_vec + xp->xfrm_nr;
- struct sockaddr_in *sin;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- struct sockaddr_in6 *sin6;
-#endif
int mode;
if (xp->xfrm_nr >= XFRM_MAX_DEPTH)
@@ -1881,31 +1850,19 @@
/* addresses present only in tunnel mode */
if (t->mode == XFRM_MODE_TUNNEL) {
- struct sockaddr *sa;
- sa = (struct sockaddr *)(rq+1);
- switch(sa->sa_family) {
- case AF_INET:
- sin = (struct sockaddr_in*)sa;
- t->saddr.a4 = sin->sin_addr.s_addr;
- sin++;
- if (sin->sin_family != AF_INET)
- return -EINVAL;
- t->id.daddr.a4 = sin->sin_addr.s_addr;
- break;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- case AF_INET6:
- sin6 = (struct sockaddr_in6*)sa;
- memcpy(t->saddr.a6, &sin6->sin6_addr, sizeof(struct in6_addr));
- sin6++;
- if (sin6->sin6_family != AF_INET6)
- return -EINVAL;
- memcpy(t->id.daddr.a6, &sin6->sin6_addr, sizeof(struct in6_addr));
- break;
-#endif
- default:
+ u8 *sa = (u8 *) (rq + 1);
+ int family, socklen;
+
+ family = pfkey_sockaddr_extract((struct sockaddr *)sa,
+ &t->saddr);
+ if (!family)
return -EINVAL;
- }
- t->encap_family = sa->sa_family;
+
+ socklen = pfkey_sockaddr_len(family);
+ if (pfkey_sockaddr_extract((struct sockaddr *)(sa + socklen),
+ &t->id.daddr) != family)
+ return -EINVAL;
+ t->encap_family = family;
} else
t->encap_family = xp->family;
@@ -1952,9 +1909,7 @@
for (i=0; i<xp->xfrm_nr; i++) {
t = xp->xfrm_vec + i;
- socklen += (t->encap_family == AF_INET ?
- sizeof(struct sockaddr_in) :
- sizeof(struct sockaddr_in6));
+ socklen += pfkey_sockaddr_len(t->encap_family);
}
return sizeof(struct sadb_msg) +
@@ -1987,18 +1942,12 @@
struct sadb_address *addr;
struct sadb_lifetime *lifetime;
struct sadb_x_policy *pol;
- struct sockaddr_in *sin;
struct sadb_x_sec_ctx *sec_ctx;
struct xfrm_sec_ctx *xfrm_ctx;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- struct sockaddr_in6 *sin6;
-#endif
int i;
int size;
int sockaddr_size = pfkey_sockaddr_size(xp->family);
- int socklen = (xp->family == AF_INET ?
- sizeof(struct sockaddr_in) :
- sizeof(struct sockaddr_in6));
+ int socklen = pfkey_sockaddr_len(xp->family);
size = pfkey_xfrm_policy2msg_size(xp);
@@ -2016,26 +1965,10 @@
addr->sadb_address_proto = pfkey_proto_from_xfrm(xp->selector.proto);
addr->sadb_address_prefixlen = xp->selector.prefixlen_s;
addr->sadb_address_reserved = 0;
- /* src address */
- if (xp->family == AF_INET) {
- sin = (struct sockaddr_in *) (addr + 1);
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = xp->selector.saddr.a4;
- sin->sin_port = xp->selector.sport;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- else if (xp->family == AF_INET6) {
- sin6 = (struct sockaddr_in6 *) (addr + 1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = xp->selector.sport;
- sin6->sin6_flowinfo = 0;
- memcpy(&sin6->sin6_addr, xp->selector.saddr.a6,
- sizeof(struct in6_addr));
- sin6->sin6_scope_id = 0;
- }
-#endif
- else
+ if (!pfkey_sockaddr_fill(&xp->selector.saddr,
+ xp->selector.sport,
+ (struct sockaddr *) (addr + 1),
+ xp->family))
BUG();
/* dst address */
@@ -2048,26 +1981,10 @@
addr->sadb_address_proto = pfkey_proto_from_xfrm(xp->selector.proto);
addr->sadb_address_prefixlen = xp->selector.prefixlen_d;
addr->sadb_address_reserved = 0;
- if (xp->family == AF_INET) {
- sin = (struct sockaddr_in *) (addr + 1);
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = xp->selector.daddr.a4;
- sin->sin_port = xp->selector.dport;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- else if (xp->family == AF_INET6) {
- sin6 = (struct sockaddr_in6 *) (addr + 1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = xp->selector.dport;
- sin6->sin6_flowinfo = 0;
- memcpy(&sin6->sin6_addr, xp->selector.daddr.a6,
- sizeof(struct in6_addr));
- sin6->sin6_scope_id = 0;
- }
-#endif
- else
- BUG();
+
+ pfkey_sockaddr_fill(&xp->selector.daddr, xp->selector.dport,
+ (struct sockaddr *) (addr + 1),
+ xp->family);
/* hard time */
lifetime = (struct sadb_lifetime *) skb_put(skb,
@@ -2121,12 +2038,13 @@
int mode;
req_size = sizeof(struct sadb_x_ipsecrequest);
- if (t->mode == XFRM_MODE_TUNNEL)
- req_size += ((t->encap_family == AF_INET ?
- sizeof(struct sockaddr_in) :
- sizeof(struct sockaddr_in6)) * 2);
- else
+ if (t->mode == XFRM_MODE_TUNNEL) {
+ socklen = pfkey_sockaddr_len(t->encap_family);
+ req_size += socklen * 2;
+ } else {
size -= 2*socklen;
+ socklen = 0;
+ }
rq = (void*)skb_put(skb, req_size);
pol->sadb_x_policy_len += req_size/8;
memset(rq, 0, sizeof(*rq));
@@ -2141,42 +2059,15 @@
if (t->optional)
rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_USE;
rq->sadb_x_ipsecrequest_reqid = t->reqid;
- if (t->mode == XFRM_MODE_TUNNEL) {
- switch (t->encap_family) {
- case AF_INET:
- sin = (void*)(rq+1);
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = t->saddr.a4;
- sin->sin_port = 0;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- sin++;
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = t->id.daddr.a4;
- sin->sin_port = 0;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- break;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- case AF_INET6:
- sin6 = (void*)(rq+1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- sin6->sin6_flowinfo = 0;
- memcpy(&sin6->sin6_addr, t->saddr.a6,
- sizeof(struct in6_addr));
- sin6->sin6_scope_id = 0;
- sin6++;
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- sin6->sin6_flowinfo = 0;
- memcpy(&sin6->sin6_addr, t->id.daddr.a6,
- sizeof(struct in6_addr));
- sin6->sin6_scope_id = 0;
- break;
-#endif
- default:
- break;
- }
+ if (t->mode == XFRM_MODE_TUNNEL) {
+ u8 *sa = (void *)(rq + 1);
+ pfkey_sockaddr_fill(&t->saddr, 0,
+ (struct sockaddr *)sa,
+ t->encap_family);
+ pfkey_sockaddr_fill(&t->id.daddr, 0,
+ (struct sockaddr *) (sa + socklen),
+ t->encap_family);
}
}
@@ -2459,61 +2350,31 @@
#ifdef CONFIG_NET_KEY_MIGRATE
static int pfkey_sockaddr_pair_size(sa_family_t family)
{
- switch (family) {
- case AF_INET:
- return PFKEY_ALIGN8(sizeof(struct sockaddr_in) * 2);
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- case AF_INET6:
- return PFKEY_ALIGN8(sizeof(struct sockaddr_in6) * 2);
-#endif
- default:
- return 0;
- }
- /* NOTREACHED */
+ return PFKEY_ALIGN8(pfkey_sockaddr_len(family) * 2);
}
static int parse_sockaddr_pair(struct sadb_x_ipsecrequest *rq,
xfrm_address_t *saddr, xfrm_address_t *daddr,
u16 *family)
{
- struct sockaddr *sa = (struct sockaddr *)(rq + 1);
+ u8 *sa = (u8 *) (rq + 1);
+ int af, socklen;
+
if (rq->sadb_x_ipsecrequest_len <
- pfkey_sockaddr_pair_size(sa->sa_family))
+ pfkey_sockaddr_pair_size(((struct sockaddr *)sa)->sa_family))
return -EINVAL;
- switch (sa->sa_family) {
- case AF_INET:
- {
- struct sockaddr_in *sin;
- sin = (struct sockaddr_in *)sa;
- if ((sin+1)->sin_family != AF_INET)
- return -EINVAL;
- memcpy(&saddr->a4, &sin->sin_addr, sizeof(saddr->a4));
- sin++;
- memcpy(&daddr->a4, &sin->sin_addr, sizeof(daddr->a4));
- *family = AF_INET;
- break;
- }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- case AF_INET6:
- {
- struct sockaddr_in6 *sin6;
- sin6 = (struct sockaddr_in6 *)sa;
- if ((sin6+1)->sin6_family != AF_INET6)
- return -EINVAL;
- memcpy(&saddr->a6, &sin6->sin6_addr,
- sizeof(saddr->a6));
- sin6++;
- memcpy(&daddr->a6, &sin6->sin6_addr,
- sizeof(daddr->a6));
- *family = AF_INET6;
- break;
- }
-#endif
- default:
+ af = pfkey_sockaddr_extract((struct sockaddr *) sa,
+ saddr);
+ if (!af)
return -EINVAL;
- }
+ socklen = pfkey_sockaddr_len(af);
+ if (pfkey_sockaddr_extract((struct sockaddr *) (sa + socklen),
+ daddr) != af)
+ return -EINVAL;
+
+ *family = af;
return 0;
}
@@ -3094,10 +2955,6 @@
struct sadb_msg *hdr;
struct sadb_address *addr;
struct sadb_x_policy *pol;
- struct sockaddr_in *sin;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- struct sockaddr_in6 *sin6;
-#endif
int sockaddr_size;
int size;
struct sadb_x_sec_ctx *sec_ctx;
@@ -3146,29 +3003,11 @@
addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
addr->sadb_address_proto = 0;
addr->sadb_address_reserved = 0;
- if (x->props.family == AF_INET) {
- addr->sadb_address_prefixlen = 32;
-
- sin = (struct sockaddr_in *) (addr + 1);
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = x->props.saddr.a4;
- sin->sin_port = 0;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- else if (x->props.family == AF_INET6) {
- addr->sadb_address_prefixlen = 128;
-
- sin6 = (struct sockaddr_in6 *) (addr + 1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- sin6->sin6_flowinfo = 0;
- memcpy(&sin6->sin6_addr,
- x->props.saddr.a6, sizeof(struct in6_addr));
- sin6->sin6_scope_id = 0;
- }
-#endif
- else
+ addr->sadb_address_prefixlen =
+ pfkey_sockaddr_fill(&x->props.saddr, 0,
+ (struct sockaddr *) (addr + 1),
+ x->props.family);
+ if (!addr->sadb_address_prefixlen)
BUG();
/* dst address */
@@ -3180,29 +3019,11 @@
addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
addr->sadb_address_proto = 0;
addr->sadb_address_reserved = 0;
- if (x->props.family == AF_INET) {
- addr->sadb_address_prefixlen = 32;
-
- sin = (struct sockaddr_in *) (addr + 1);
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = x->id.daddr.a4;
- sin->sin_port = 0;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- else if (x->props.family == AF_INET6) {
- addr->sadb_address_prefixlen = 128;
-
- sin6 = (struct sockaddr_in6 *) (addr + 1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- sin6->sin6_flowinfo = 0;
- memcpy(&sin6->sin6_addr,
- x->id.daddr.a6, sizeof(struct in6_addr));
- sin6->sin6_scope_id = 0;
- }
-#endif
- else
+ addr->sadb_address_prefixlen =
+ pfkey_sockaddr_fill(&x->id.daddr, 0,
+ (struct sockaddr *) (addr + 1),
+ x->props.family);
+ if (!addr->sadb_address_prefixlen)
BUG();
pol = (struct sadb_x_policy *) skb_put(skb, sizeof(struct sadb_x_policy));
@@ -3328,10 +3149,6 @@
struct sadb_sa *sa;
struct sadb_address *addr;
struct sadb_x_nat_t_port *n_port;
- struct sockaddr_in *sin;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- struct sockaddr_in6 *sin6;
-#endif
int sockaddr_size;
int size;
__u8 satype = (x->id.proto == IPPROTO_ESP ? SADB_SATYPE_ESP : 0);
@@ -3395,29 +3212,11 @@
addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
addr->sadb_address_proto = 0;
addr->sadb_address_reserved = 0;
- if (x->props.family == AF_INET) {
- addr->sadb_address_prefixlen = 32;
-
- sin = (struct sockaddr_in *) (addr + 1);
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = x->props.saddr.a4;
- sin->sin_port = 0;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- else if (x->props.family == AF_INET6) {
- addr->sadb_address_prefixlen = 128;
-
- sin6 = (struct sockaddr_in6 *) (addr + 1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- sin6->sin6_flowinfo = 0;
- memcpy(&sin6->sin6_addr,
- x->props.saddr.a6, sizeof(struct in6_addr));
- sin6->sin6_scope_id = 0;
- }
-#endif
- else
+ addr->sadb_address_prefixlen =
+ pfkey_sockaddr_fill(&x->props.saddr, 0,
+ (struct sockaddr *) (addr + 1),
+ x->props.family);
+ if (!addr->sadb_address_prefixlen)
BUG();
/* NAT_T_SPORT (old port) */
@@ -3436,28 +3235,11 @@
addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
addr->sadb_address_proto = 0;
addr->sadb_address_reserved = 0;
- if (x->props.family == AF_INET) {
- addr->sadb_address_prefixlen = 32;
-
- sin = (struct sockaddr_in *) (addr + 1);
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = ipaddr->a4;
- sin->sin_port = 0;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- else if (x->props.family == AF_INET6) {
- addr->sadb_address_prefixlen = 128;
-
- sin6 = (struct sockaddr_in6 *) (addr + 1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- sin6->sin6_flowinfo = 0;
- memcpy(&sin6->sin6_addr, &ipaddr->a6, sizeof(struct in6_addr));
- sin6->sin6_scope_id = 0;
- }
-#endif
- else
+ addr->sadb_address_prefixlen =
+ pfkey_sockaddr_fill(ipaddr, 0,
+ (struct sockaddr *) (addr + 1),
+ x->props.family);
+ if (!addr->sadb_address_prefixlen)
BUG();
/* NAT_T_DPORT (new port) */
@@ -3475,10 +3257,6 @@
struct xfrm_selector *sel)
{
struct sadb_address *addr;
- struct sockaddr_in *sin;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- struct sockaddr_in6 *sin6;
-#endif
addr = (struct sadb_address *)skb_put(skb, sizeof(struct sadb_address) + sasize);
addr->sadb_address_len = (sizeof(struct sadb_address) + sasize)/8;
addr->sadb_address_exttype = type;
@@ -3487,50 +3265,16 @@
switch (type) {
case SADB_EXT_ADDRESS_SRC:
- if (sel->family == AF_INET) {
- addr->sadb_address_prefixlen = sel->prefixlen_s;
- sin = (struct sockaddr_in *)(addr + 1);
- sin->sin_family = AF_INET;
- memcpy(&sin->sin_addr.s_addr, &sel->saddr,
- sizeof(sin->sin_addr.s_addr));
- sin->sin_port = 0;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- else if (sel->family == AF_INET6) {
- addr->sadb_address_prefixlen = sel->prefixlen_s;
- sin6 = (struct sockaddr_in6 *)(addr + 1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- sin6->sin6_flowinfo = 0;
- sin6->sin6_scope_id = 0;
- memcpy(&sin6->sin6_addr.s6_addr, &sel->saddr,
- sizeof(sin6->sin6_addr.s6_addr));
- }
-#endif
+ addr->sadb_address_prefixlen = sel->prefixlen_s;
+ pfkey_sockaddr_fill(&sel->saddr, 0,
+ (struct sockaddr *)(addr + 1),
+ sel->family);
break;
case SADB_EXT_ADDRESS_DST:
- if (sel->family == AF_INET) {
- addr->sadb_address_prefixlen = sel->prefixlen_d;
- sin = (struct sockaddr_in *)(addr + 1);
- sin->sin_family = AF_INET;
- memcpy(&sin->sin_addr.s_addr, &sel->daddr,
- sizeof(sin->sin_addr.s_addr));
- sin->sin_port = 0;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- else if (sel->family == AF_INET6) {
- addr->sadb_address_prefixlen = sel->prefixlen_d;
- sin6 = (struct sockaddr_in6 *)(addr + 1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- sin6->sin6_flowinfo = 0;
- sin6->sin6_scope_id = 0;
- memcpy(&sin6->sin6_addr.s6_addr, &sel->daddr,
- sizeof(sin6->sin6_addr.s6_addr));
- }
-#endif
+ addr->sadb_address_prefixlen = sel->prefixlen_d;
+ pfkey_sockaddr_fill(&sel->daddr, 0,
+ (struct sockaddr *)(addr + 1),
+ sel->family);
break;
default:
return -EINVAL;
@@ -3545,10 +3289,8 @@
xfrm_address_t *src, xfrm_address_t *dst)
{
struct sadb_x_ipsecrequest *rq;
- struct sockaddr_in *sin;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- struct sockaddr_in6 *sin6;
-#endif
+ u8 *sa;
+ int socklen = pfkey_sockaddr_len(family);
int size_req;
size_req = sizeof(struct sadb_x_ipsecrequest) +
@@ -3562,38 +3304,10 @@
rq->sadb_x_ipsecrequest_level = level;
rq->sadb_x_ipsecrequest_reqid = reqid;
- switch (family) {
- case AF_INET:
- sin = (struct sockaddr_in *)(rq + 1);
- sin->sin_family = AF_INET;
- memcpy(&sin->sin_addr.s_addr, src,
- sizeof(sin->sin_addr.s_addr));
- sin++;
- sin->sin_family = AF_INET;
- memcpy(&sin->sin_addr.s_addr, dst,
- sizeof(sin->sin_addr.s_addr));
- break;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- case AF_INET6:
- sin6 = (struct sockaddr_in6 *)(rq + 1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- sin6->sin6_flowinfo = 0;
- sin6->sin6_scope_id = 0;
- memcpy(&sin6->sin6_addr.s6_addr, src,
- sizeof(sin6->sin6_addr.s6_addr));
- sin6++;
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- sin6->sin6_flowinfo = 0;
- sin6->sin6_scope_id = 0;
- memcpy(&sin6->sin6_addr.s6_addr, dst,
- sizeof(sin6->sin6_addr.s6_addr));
- break;
-#endif
- default:
+ sa = (u8 *) (rq + 1);
+ if (!pfkey_sockaddr_fill(src, 0, (struct sockaddr *)sa, family) ||
+ !pfkey_sockaddr_fill(dst, 0, (struct sockaddr *)(sa + socklen), family))
return -EINVAL;
- }
return 0;
}
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index a24b459..590e00b 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -7,11 +7,23 @@
select CRC32
select WIRELESS_EXT
select CFG80211
- select NET_SCH_FIFO
---help---
This option enables the hardware independent IEEE 802.11
networking stack.
+config MAC80211_QOS
+ def_bool y
+ depends on MAC80211
+ depends on NET_SCHED
+ depends on NETDEVICES_MULTIQUEUE
+
+comment "QoS/HT support disabled"
+ depends on MAC80211 && !MAC80211_QOS
+comment "QoS/HT support needs CONFIG_NET_SCHED"
+ depends on MAC80211 && !NET_SCHED
+comment "QoS/HT support needs CONFIG_NETDEVICES_MULTIQUEUE"
+ depends on MAC80211 && !NETDEVICES_MULTIQUEUE
+
menu "Rate control algorithm selection"
depends on MAC80211 != n
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index 4e5847f..1d2a4e0 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -29,7 +29,7 @@
event.o
mac80211-$(CONFIG_MAC80211_LEDS) += led.o
-mac80211-$(CONFIG_NET_SCHED) += wme.o
+mac80211-$(CONFIG_MAC80211_QOS) += wme.o
mac80211-$(CONFIG_MAC80211_DEBUGFS) += \
debugfs.o \
debugfs_sta.o \
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/cfg.c b/net/mac80211/cfg.c
index a9fce4a..8108728 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -256,8 +256,8 @@
case ALG_TKIP:
params.cipher = WLAN_CIPHER_SUITE_TKIP;
- iv32 = key->u.tkip.iv32;
- iv16 = key->u.tkip.iv16;
+ iv32 = key->u.tkip.tx.iv32;
+ iv16 = key->u.tkip.tx.iv16;
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
sdata->local->ops->get_tkip_seq)
@@ -602,6 +602,7 @@
*/
if (params->station_flags & STATION_FLAG_CHANGED) {
+ spin_lock_bh(&sta->lock);
sta->flags &= ~WLAN_STA_AUTHORIZED;
if (params->station_flags & STATION_FLAG_AUTHORIZED)
sta->flags |= WLAN_STA_AUTHORIZED;
@@ -613,6 +614,7 @@
sta->flags &= ~WLAN_STA_WME;
if (params->station_flags & STATION_FLAG_WME)
sta->flags |= WLAN_STA_WME;
+ spin_unlock_bh(&sta->lock);
}
/*
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_key.c b/net/mac80211/debugfs_key.c
index 19efc3a..7439b63 100644
--- a/net/mac80211/debugfs_key.c
+++ b/net/mac80211/debugfs_key.c
@@ -97,8 +97,8 @@
break;
case ALG_TKIP:
len = scnprintf(buf, sizeof(buf), "%08x %04x\n",
- key->u.tkip.iv32,
- key->u.tkip.iv16);
+ key->u.tkip.tx.iv32,
+ key->u.tkip.tx.iv16);
break;
case ALG_CCMP:
tpn = key->u.ccmp.tx_pn;
@@ -128,8 +128,8 @@
for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
p += scnprintf(p, sizeof(buf)+buf-p,
"%08x %04x\n",
- key->u.tkip.iv32_rx[i],
- key->u.tkip.iv16_rx[i]);
+ key->u.tkip.rx[i].iv32,
+ key->u.tkip.rx[i].iv16);
len = p - buf;
break;
case ALG_CCMP:
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index e3326d0..b2089b2 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -155,7 +155,6 @@
__IEEE80211_IF_WFILE(name)
/* common attributes */
-IEEE80211_IF_FILE(channel_use, channel_use, DEC);
IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
/* STA/IBSS attributes */
@@ -248,7 +247,6 @@
static void add_sta_files(struct ieee80211_sub_if_data *sdata)
{
- DEBUGFS_ADD(channel_use, sta);
DEBUGFS_ADD(drop_unencrypted, sta);
DEBUGFS_ADD(state, sta);
DEBUGFS_ADD(bssid, sta);
@@ -269,7 +267,6 @@
static void add_ap_files(struct ieee80211_sub_if_data *sdata)
{
- DEBUGFS_ADD(channel_use, ap);
DEBUGFS_ADD(drop_unencrypted, ap);
DEBUGFS_ADD(num_sta_ps, ap);
DEBUGFS_ADD(dtim_count, ap);
@@ -281,14 +278,12 @@
static void add_wds_files(struct ieee80211_sub_if_data *sdata)
{
- DEBUGFS_ADD(channel_use, wds);
DEBUGFS_ADD(drop_unencrypted, wds);
DEBUGFS_ADD(peer, wds);
}
static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
{
- DEBUGFS_ADD(channel_use, vlan);
DEBUGFS_ADD(drop_unencrypted, vlan);
}
@@ -376,7 +371,6 @@
static void del_sta_files(struct ieee80211_sub_if_data *sdata)
{
- DEBUGFS_DEL(channel_use, sta);
DEBUGFS_DEL(drop_unencrypted, sta);
DEBUGFS_DEL(state, sta);
DEBUGFS_DEL(bssid, sta);
@@ -397,7 +391,6 @@
static void del_ap_files(struct ieee80211_sub_if_data *sdata)
{
- DEBUGFS_DEL(channel_use, ap);
DEBUGFS_DEL(drop_unencrypted, ap);
DEBUGFS_DEL(num_sta_ps, ap);
DEBUGFS_DEL(dtim_count, ap);
@@ -409,14 +402,12 @@
static void del_wds_files(struct ieee80211_sub_if_data *sdata)
{
- DEBUGFS_DEL(channel_use, wds);
DEBUGFS_DEL(drop_unencrypted, wds);
DEBUGFS_DEL(peer, wds);
}
static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
{
- DEBUGFS_DEL(channel_use, vlan);
DEBUGFS_DEL(drop_unencrypted, vlan);
}
@@ -528,7 +519,7 @@
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..79a0627 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -63,10 +63,9 @@
STA_FILE(tx_filtered, tx_filtered_count, LU);
STA_FILE(tx_retry_failed, tx_retry_failed, LU);
STA_FILE(tx_retry_count, tx_retry_count, LU);
-STA_FILE(last_rssi, last_rssi, D);
STA_FILE(last_signal, last_signal, D);
+STA_FILE(last_qual, last_qual, D);
STA_FILE(last_noise, last_noise, D);
-STA_FILE(channel_use, channel_use, D);
STA_FILE(wep_weak_iv_count, wep_weak_iv_count, LU);
static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
@@ -74,14 +73,15 @@
{
char buf[100];
struct sta_info *sta = file->private_data;
+ u32 staflags = get_sta_flags(sta);
int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s",
- sta->flags & WLAN_STA_AUTH ? "AUTH\n" : "",
- sta->flags & WLAN_STA_ASSOC ? "ASSOC\n" : "",
- sta->flags & WLAN_STA_PS ? "PS\n" : "",
- sta->flags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "",
- sta->flags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "",
- sta->flags & WLAN_STA_WME ? "WME\n" : "",
- sta->flags & WLAN_STA_WDS ? "WDS\n" : "");
+ staflags & WLAN_STA_AUTH ? "AUTH\n" : "",
+ staflags & WLAN_STA_ASSOC ? "ASSOC\n" : "",
+ staflags & WLAN_STA_PS ? "PS\n" : "",
+ staflags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "",
+ staflags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "",
+ staflags & WLAN_STA_WME ? "WME\n" : "",
+ staflags & WLAN_STA_WDS ? "WDS\n" : "");
return simple_read_from_buffer(userbuf, count, ppos, buf, res);
}
STA_OPS(flags);
@@ -123,36 +123,6 @@
}
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 006486b..b19bd16 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2,6 +2,7 @@
* Copyright 2002-2005, Instant802 Networks, Inc.
* Copyright 2005, Devicescape Software, Inc.
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007-2008 Johannes Berg <johannes@sipsolutions.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -82,7 +83,7 @@
u16 capability; /* host byte order */
enum ieee80211_band band;
int freq;
- int rssi, signal, noise;
+ int signal, noise, qual;
u8 *wpa_ie;
size_t wpa_ie_len;
u8 *rsn_ie;
@@ -91,6 +92,8 @@
size_t wmm_ie_len;
u8 *ht_ie;
size_t ht_ie_len;
+ u8 *ht_add_ie;
+ size_t ht_add_ie_len;
#ifdef CONFIG_MAC80211_MESH
u8 *mesh_id;
size_t mesh_id_len;
@@ -147,7 +150,6 @@
#define IEEE80211_TX_UNICAST BIT(1)
#define IEEE80211_TX_PS_BUFFERED BIT(2)
#define IEEE80211_TX_PROBE_LAST_FRAG BIT(3)
-#define IEEE80211_TX_INJECTED BIT(4)
struct ieee80211_tx_data {
struct sk_buff *skb;
@@ -157,13 +159,12 @@
struct sta_info *sta;
struct ieee80211_key *key;
- struct ieee80211_tx_control *control;
struct ieee80211_channel *channel;
- struct ieee80211_rate *rate;
+ s8 rate_idx;
/* use this rate (if set) for last fragment; rate can
* be set to lower rate for the first fragments, e.g.,
* when using CTS protection with IEEE 802.11g. */
- struct ieee80211_rate *last_frag_rate;
+ s8 last_frag_rate_idx;
/* Extra fragments (in addition to the first fragment
* in skb) */
@@ -202,32 +203,16 @@
unsigned int flags;
int sent_ps_buffered;
int queue;
- int load;
u32 tkip_iv32;
u16 tkip_iv16;
};
-/* flags used in struct ieee80211_tx_packet_data.flags */
-#define IEEE80211_TXPD_REQ_TX_STATUS BIT(0)
-#define IEEE80211_TXPD_DO_NOT_ENCRYPT BIT(1)
-#define IEEE80211_TXPD_REQUEUE BIT(2)
-#define IEEE80211_TXPD_EAPOL_FRAME BIT(3)
-#define IEEE80211_TXPD_AMPDU BIT(4)
-/* Stored in sk_buff->cb */
-struct ieee80211_tx_packet_data {
- int ifindex;
- unsigned long jiffies;
- unsigned int flags;
- u8 queue;
-};
-
struct ieee80211_tx_stored_packet {
- struct ieee80211_tx_control control;
struct sk_buff *skb;
struct sk_buff **extra_frag;
- struct ieee80211_rate *last_frag_rate;
+ s8 last_frag_rate_idx;
int num_extra_frag;
- unsigned int last_frag_rate_ctrl_probe;
+ bool last_frag_rate_ctrl_probe;
};
struct beacon_data {
@@ -464,14 +449,11 @@
struct ieee80211_if_sta sta;
u32 mntr_flags;
} u;
- int channel_use;
- int channel_use_raw;
#ifdef CONFIG_MAC80211_DEBUGFS
struct dentry *debugfsdir;
union {
struct {
- struct dentry *channel_use;
struct dentry *drop_unencrypted;
struct dentry *state;
struct dentry *bssid;
@@ -490,7 +472,6 @@
struct dentry *num_beacons_sta;
} sta;
struct {
- struct dentry *channel_use;
struct dentry *drop_unencrypted;
struct dentry *num_sta_ps;
struct dentry *dtim_count;
@@ -500,12 +481,10 @@
struct dentry *num_buffered_multicast;
} ap;
struct {
- struct dentry *channel_use;
struct dentry *drop_unencrypted;
struct dentry *peer;
} wds;
struct {
- struct dentry *channel_use;
struct dentry *drop_unencrypted;
} vlan;
struct {
@@ -610,8 +589,8 @@
struct sta_info *sta_hash[STA_HASH_SIZE];
struct timer_list sta_cleanup;
- unsigned long state[NUM_TX_DATA_QUEUES_AMPDU];
- struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES_AMPDU];
+ unsigned long queues_pending[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)];
+ struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_QUEUES];
struct tasklet_struct tx_pending_tasklet;
/* number of interfaces with corresponding IFF_ flags */
@@ -677,9 +656,6 @@
assoc_led_name[32], radio_led_name[32];
#endif
- u32 channel_use;
- u32 channel_use_raw;
-
#ifdef CONFIG_MAC80211_DEBUGFS
struct work_struct sta_debugfs_add;
#endif
@@ -705,8 +681,6 @@
unsigned int rx_expand_skb_head2;
unsigned int rx_handlers_fragments;
unsigned int tx_status_drop;
- unsigned int wme_rx_queue[NUM_RX_DATA_QUEUES];
- unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES];
#define I802_DEBUG_INC(c) (c)++
#else /* CONFIG_MAC80211_DEBUG_COUNTERS */
#define I802_DEBUG_INC(c) do { } while (0)
@@ -764,8 +738,6 @@
struct dentry *rx_expand_skb_head2;
struct dentry *rx_handlers_fragments;
struct dentry *tx_status_drop;
- struct dentry *wme_tx_queue;
- struct dentry *wme_rx_queue;
#endif
struct dentry *dot11ACKFailureCount;
struct dentry *dot11RTSFailureCount;
@@ -778,6 +750,15 @@
#endif
};
+static inline int ieee80211_is_multiqueue(struct ieee80211_local *local)
+{
+#ifdef CONFIG_MAC80211_QOS
+ return netif_is_multiqueue(local->mdev);
+#else
+ return 0;
+#endif
+}
+
/* this struct represents 802.11n's RA/TID combination */
struct ieee80211_ra_tid {
u8 ra[ETH_ALEN];
@@ -847,11 +828,6 @@
return &local->hw;
}
-enum ieee80211_link_state_t {
- IEEE80211_LINK_STATE_XOFF = 0,
- IEEE80211_LINK_STATE_PENDING,
-};
-
struct sta_attribute {
struct attribute attr;
ssize_t (*show)(const struct sta_info *, char *buf);
@@ -877,29 +853,8 @@
/* ieee80211_ioctl.c */
extern const struct iw_handler_def ieee80211_iw_handler_def;
-
-
-/* Least common multiple of the used rates (in 100 kbps). This is used to
- * calculate rate_inv values for each rate so that only integers are needed. */
-#define CHAN_UTIL_RATE_LCM 95040
-/* 1 usec is 1/8 * (95040/10) = 1188 */
-#define CHAN_UTIL_PER_USEC 1188
-/* Amount of bits to shift the result right to scale the total utilization
- * to values that will not wrap around 32-bit integers. */
-#define CHAN_UTIL_SHIFT 9
-/* Theoretical maximum of channel utilization counter in 10 ms (stat_time=1):
- * (CHAN_UTIL_PER_USEC * 10000) >> CHAN_UTIL_SHIFT = 23203. So dividing the
- * raw value with about 23 should give utilization in 10th of a percentage
- * (1/1000). However, utilization is only estimated and not all intervals
- * between frames etc. are calculated. 18 seems to give numbers that are closer
- * to the real maximum. */
-#define CHAN_UTIL_PER_10MS 18
-#define CHAN_UTIL_HDR_LONG (202 * CHAN_UTIL_PER_USEC)
-#define CHAN_UTIL_HDR_SHORT (40 * CHAN_UTIL_PER_USEC)
-
-
-/* ieee80211_ioctl.c */
int ieee80211_set_freq(struct net_device *dev, int freq);
+
/* ieee80211_sta.c */
void ieee80211_sta_timer(unsigned long data);
void ieee80211_sta_work(struct work_struct *work);
@@ -919,9 +874,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 +895,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..9844727 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. */
@@ -167,9 +166,10 @@
ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |
IEEE80211_AUTH_ALG_SHARED_KEY;
ifsta->flags |= IEEE80211_STA_CREATE_IBSS |
- IEEE80211_STA_WMM_ENABLED |
IEEE80211_STA_AUTO_BSSID_SEL |
IEEE80211_STA_AUTO_CHANNEL_SEL;
+ if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4)
+ ifsta->flags |= IEEE80211_STA_WMM_ENABLED;
msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev);
sdata->bss = &msdata->u.ap;
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 150d66d..d4893bd 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -321,8 +321,15 @@
* some hardware cannot handle TKIP with QoS, so
* we indicate whether QoS could be in use.
*/
- if (sta->flags & WLAN_STA_WME)
+ if (test_sta_flags(sta, WLAN_STA_WME))
key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA;
+
+ /*
+ * This key is for a specific sta interface,
+ * inform the driver that it should try to store
+ * this key as pairwise key.
+ */
+ key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
} else {
if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
struct sta_info *ap;
@@ -335,7 +342,7 @@
/* same here, the AP could be using QoS */
ap = sta_info_get(key->local, key->sdata->u.sta.bssid);
if (ap) {
- if (ap->flags & WLAN_STA_WME)
+ if (test_sta_flags(ap, WLAN_STA_WME))
key->conf.flags |=
IEEE80211_KEY_FLAG_WMM_STA;
}
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index f52c3df..a0f774a 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -69,6 +69,13 @@
KEY_FLAG_TODO_ADD_DEBUGFS = BIT(5),
};
+struct tkip_ctx {
+ u32 iv32;
+ u16 iv16;
+ u16 p1k[5];
+ int initialized;
+};
+
struct ieee80211_key {
struct ieee80211_local *local;
struct ieee80211_sub_if_data *sdata;
@@ -85,16 +92,10 @@
union {
struct {
/* last used TSC */
- u32 iv32;
- u16 iv16;
- u16 p1k[5];
- int tx_initialized;
+ struct tkip_ctx tx;
/* last received RSC */
- u32 iv32_rx[NUM_RX_DATA_QUEUES];
- u16 iv16_rx[NUM_RX_DATA_QUEUES];
- u16 p1k_rx[NUM_RX_DATA_QUEUES][5];
- int rx_initialized[NUM_RX_DATA_QUEUES];
+ struct tkip_ctx rx[NUM_RX_DATA_QUEUES];
} tkip;
struct {
u8 tx_pn[6];
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 98c0b5e..b182f01 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -35,8 +35,6 @@
#include "debugfs.h"
#include "debugfs_netdev.h"
-#define SUPP_MCS_SET_LEN 16
-
/*
* For seeing transmitted packets on monitor interfaces
* we have a radiotap header too.
@@ -112,7 +110,13 @@
break;
}
}
- return res;
+
+ if (res)
+ return res;
+
+ netif_start_queue(local->mdev);
+
+ return 0;
}
static int ieee80211_master_stop(struct net_device *dev)
@@ -346,6 +350,7 @@
goto err_del_interface;
}
+ /* no locking required since STA is not live yet */
sta->flags |= WLAN_STA_AUTHORIZED;
res = sta_info_insert(sta);
@@ -385,8 +390,8 @@
* yet be effective. Trigger execution of ieee80211_sta_work
* to fix this.
*/
- if(sdata->vif.type == IEEE80211_IF_TYPE_STA ||
- sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+ if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+ sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
queue_work(local->hw.workqueue, &ifsta->work);
}
@@ -585,16 +590,16 @@
sta = sta_info_get(local, ra);
if (!sta) {
printk(KERN_DEBUG "Could not find the station\n");
- rcu_read_unlock();
- return -ENOENT;
+ ret = -ENOENT;
+ goto exit;
}
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_lock_bh(&sta->lock);
/* we have tried too many times, receiver does not want A-MPDU */
if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
ret = -EBUSY;
- goto start_ba_exit;
+ goto err_unlock_sta;
}
state = &sta->ampdu_mlme.tid_state_tx[tid];
@@ -605,7 +610,7 @@
"idle on tid %u\n", tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
ret = -EAGAIN;
- goto start_ba_exit;
+ goto err_unlock_sta;
}
/* prepare A-MPDU MLME for Tx aggregation */
@@ -616,7 +621,7 @@
printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
tid);
ret = -ENOMEM;
- goto start_ba_exit;
+ goto err_unlock_sta;
}
/* Tx timer */
sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
@@ -639,7 +644,7 @@
printk(KERN_DEBUG "BA request denied - queue unavailable for"
" tid %d\n", tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
- goto start_ba_err;
+ goto err_unlock_queue;
}
sdata = sta->sdata;
@@ -661,12 +666,13 @@
" tid %d\n", tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
*state = HT_AGG_STATE_IDLE;
- goto start_ba_err;
+ goto err_unlock_queue;
}
/* Will put all the packets in the new SW queue */
ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
spin_unlock_bh(&local->mdev->queue_lock);
+ spin_unlock_bh(&sta->lock);
/* send an addBA request */
sta->ampdu_mlme.dialog_token_allocator++;
@@ -674,25 +680,26 @@
sta->ampdu_mlme.dialog_token_allocator;
sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
+
ieee80211_send_addba_request(sta->sdata->dev, ra, tid,
sta->ampdu_mlme.tid_tx[tid]->dialog_token,
sta->ampdu_mlme.tid_tx[tid]->ssn,
0x40, 5000);
-
/* activate the timer for the recipient's addBA response */
sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
jiffies + ADDBA_RESP_INTERVAL;
add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
- goto start_ba_exit;
+ goto exit;
-start_ba_err:
+err_unlock_queue:
kfree(sta->ampdu_mlme.tid_tx[tid]);
sta->ampdu_mlme.tid_tx[tid] = NULL;
spin_unlock_bh(&local->mdev->queue_lock);
ret = -EBUSY;
-start_ba_exit:
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+err_unlock_sta:
+ spin_unlock_bh(&sta->lock);
+exit:
rcu_read_unlock();
return ret;
}
@@ -720,7 +727,7 @@
/* check if the TID is in aggregation */
state = &sta->ampdu_mlme.tid_state_tx[tid];
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_lock_bh(&sta->lock);
if (*state != HT_AGG_STATE_OPERATIONAL) {
ret = -ENOENT;
@@ -750,7 +757,7 @@
}
stop_BA_exit:
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
rcu_read_unlock();
return ret;
}
@@ -779,12 +786,12 @@
}
state = &sta->ampdu_mlme.tid_state_tx[tid];
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_lock_bh(&sta->lock);
if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
*state);
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
rcu_read_unlock();
return;
}
@@ -797,7 +804,7 @@
printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
}
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
rcu_read_unlock();
}
EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
@@ -831,10 +838,11 @@
}
state = &sta->ampdu_mlme.tid_state_tx[tid];
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ /* NOTE: no need to use sta->lock in this state check, as
+ * ieee80211_stop_tx_ba_session will let only
+ * one stop call to pass through per sta/tid */
if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
rcu_read_unlock();
return;
}
@@ -857,11 +865,12 @@
* ieee80211_wake_queue is not used here as this queue is not
* necessarily stopped */
netif_schedule(local->mdev);
+ spin_lock_bh(&sta->lock);
*state = HT_AGG_STATE_IDLE;
sta->ampdu_mlme.addba_req_num[tid] = 0;
kfree(sta->ampdu_mlme.tid_tx[tid]);
sta->ampdu_mlme.tid_tx[tid] = NULL;
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
rcu_read_unlock();
}
@@ -967,8 +976,7 @@
/* everything else */
static int __ieee80211_if_config(struct net_device *dev,
- struct sk_buff *beacon,
- struct ieee80211_tx_control *control)
+ struct sk_buff *beacon)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
@@ -986,13 +994,11 @@
conf.ssid_len = sdata->u.sta.ssid_len;
} else if (ieee80211_vif_is_mesh(&sdata->vif)) {
conf.beacon = beacon;
- conf.beacon_control = control;
ieee80211_start_mesh(dev);
} else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
conf.ssid = sdata->u.ap.ssid;
conf.ssid_len = sdata->u.ap.ssid_len;
conf.beacon = beacon;
- conf.beacon_control = control;
}
return local->ops->config_interface(local_to_hw(local),
&sdata->vif, &conf);
@@ -1005,23 +1011,21 @@
if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT &&
(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
return ieee80211_if_config_beacon(dev);
- return __ieee80211_if_config(dev, NULL, NULL);
+ return __ieee80211_if_config(dev, NULL);
}
int ieee80211_if_config_beacon(struct net_device *dev)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_tx_control control;
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct sk_buff *skb;
if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
return 0;
- skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif,
- &control);
+ skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif);
if (!skb)
return -ENOMEM;
- return __ieee80211_if_config(dev, skb, &control);
+ return __ieee80211_if_config(dev, skb);
}
int ieee80211_hw_config(struct ieee80211_local *local)
@@ -1068,56 +1072,84 @@
struct ieee80211_supported_band *sband;
struct ieee80211_ht_info ht_conf;
struct ieee80211_ht_bss_info ht_bss_conf;
- int i;
u32 changed = 0;
+ int i;
+ u8 max_tx_streams = IEEE80211_HT_CAP_MAX_STREAMS;
+ u8 tx_mcs_set_cap;
sband = local->hw.wiphy->bands[conf->channel->band];
- /* HT is not supported */
- if (!sband->ht_info.ht_supported) {
- conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
- return 0;
- }
-
memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info));
memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info));
- if (enable_ht) {
- if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
- changed |= BSS_CHANGED_HT;
+ /* HT is not supported */
+ if (!sband->ht_info.ht_supported) {
+ conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
+ goto out;
+ }
- conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
- ht_conf.ht_supported = 1;
-
- ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
- ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS);
- ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
-
- for (i = 0; i < SUPP_MCS_SET_LEN; i++)
- ht_conf.supp_mcs_set[i] =
- sband->ht_info.supp_mcs_set[i] &
- req_ht_cap->supp_mcs_set[i];
-
- ht_bss_conf.primary_channel = req_bss_cap->primary_channel;
- ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
- ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
-
- ht_conf.ampdu_factor = req_ht_cap->ampdu_factor;
- ht_conf.ampdu_density = req_ht_cap->ampdu_density;
-
- /* if bss configuration changed store the new one */
- if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) ||
- memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
- changed |= BSS_CHANGED_HT;
- memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf));
- memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
- }
- } else {
+ /* disable HT */
+ if (!enable_ht) {
if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)
changed |= BSS_CHANGED_HT;
conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
+ conf->ht_conf.ht_supported = 0;
+ goto out;
}
+
+ if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
+ changed |= BSS_CHANGED_HT;
+
+ conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
+ ht_conf.ht_supported = 1;
+
+ ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
+ ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS);
+ ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
+ ht_bss_conf.primary_channel = req_bss_cap->primary_channel;
+ ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
+ ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
+
+ ht_conf.ampdu_factor = req_ht_cap->ampdu_factor;
+ ht_conf.ampdu_density = req_ht_cap->ampdu_density;
+
+ /* Bits 96-100 */
+ tx_mcs_set_cap = sband->ht_info.supp_mcs_set[12];
+
+ /* configure suppoerted Tx MCS according to requested MCS
+ * (based in most cases on Rx capabilities of peer) and self
+ * Tx MCS capabilities (as defined by low level driver HW
+ * Tx capabilities) */
+ if (!(tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_DEFINED))
+ goto check_changed;
+
+ /* Counting from 0 therfore + 1 */
+ if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_RX_DIFF)
+ max_tx_streams = ((tx_mcs_set_cap &
+ IEEE80211_HT_CAP_MCS_TX_STREAMS) >> 2) + 1;
+
+ for (i = 0; i < max_tx_streams; i++)
+ ht_conf.supp_mcs_set[i] =
+ sband->ht_info.supp_mcs_set[i] &
+ req_ht_cap->supp_mcs_set[i];
+
+ if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_UEQM)
+ for (i = IEEE80211_SUPP_MCS_SET_UEQM;
+ i < IEEE80211_SUPP_MCS_SET_LEN; i++)
+ ht_conf.supp_mcs_set[i] =
+ sband->ht_info.supp_mcs_set[i] &
+ req_ht_cap->supp_mcs_set[i];
+
+check_changed:
+ /* if bss configuration changed store the new one */
+ if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) ||
+ memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
+ changed |= BSS_CHANGED_HT;
+ memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf));
+ memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
+ }
+out:
return changed;
}
@@ -1148,38 +1180,20 @@
}
void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
- struct sk_buff *skb,
- struct ieee80211_tx_status *status)
+ struct sk_buff *skb)
{
struct ieee80211_local *local = hw_to_local(hw);
- struct ieee80211_tx_status *saved;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int tmp;
skb->dev = local->mdev;
- saved = kmalloc(sizeof(struct ieee80211_tx_status), GFP_ATOMIC);
- if (unlikely(!saved)) {
- if (net_ratelimit())
- printk(KERN_WARNING "%s: Not enough memory, "
- "dropping tx status", skb->dev->name);
- /* should be dev_kfree_skb_irq, but due to this function being
- * named _irqsafe instead of just _irq we can't be sure that
- * people won't call it from non-irq contexts */
- dev_kfree_skb_any(skb);
- return;
- }
- memcpy(saved, status, sizeof(struct ieee80211_tx_status));
- /* copy pointer to saved status into skb->cb for use by tasklet */
- memcpy(skb->cb, &saved, sizeof(saved));
-
skb->pkt_type = IEEE80211_TX_STATUS_MSG;
- skb_queue_tail(status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS ?
+ skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ?
&local->skb_queue : &local->skb_queue_unreliable, skb);
tmp = skb_queue_len(&local->skb_queue) +
skb_queue_len(&local->skb_queue_unreliable);
while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT &&
(skb = skb_dequeue(&local->skb_queue_unreliable))) {
- memcpy(&saved, skb->cb, sizeof(saved));
- kfree(saved);
dev_kfree_skb_irq(skb);
tmp--;
I802_DEBUG_INC(local->tx_status_drop);
@@ -1193,7 +1207,6 @@
struct ieee80211_local *local = (struct ieee80211_local *) data;
struct sk_buff *skb;
struct ieee80211_rx_status rx_status;
- struct ieee80211_tx_status *tx_status;
struct ieee80211_ra_tid *ra_tid;
while ((skb = skb_dequeue(&local->skb_queue)) ||
@@ -1208,12 +1221,8 @@
__ieee80211_rx(local_to_hw(local), skb, &rx_status);
break;
case IEEE80211_TX_STATUS_MSG:
- /* get pointer to saved status out of skb->cb */
- memcpy(&tx_status, skb->cb, sizeof(tx_status));
skb->pkt_type = 0;
- ieee80211_tx_status(local_to_hw(local),
- skb, tx_status);
- kfree(tx_status);
+ ieee80211_tx_status(local_to_hw(local), skb);
break;
case IEEE80211_DELBA_MSG:
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
@@ -1242,24 +1251,15 @@
* Also, tx_packet_data in cb is restored from tx_control. */
static void ieee80211_remove_tx_extra(struct ieee80211_local *local,
struct ieee80211_key *key,
- struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+ struct sk_buff *skb)
{
int hdrlen, iv_len, mic_len;
- struct ieee80211_tx_packet_data *pkt_data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
- pkt_data->ifindex = vif_to_sdata(control->vif)->dev->ifindex;
- pkt_data->flags = 0;
- if (control->flags & IEEE80211_TXCTL_REQ_TX_STATUS)
- pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS;
- if (control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)
- pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
- if (control->flags & IEEE80211_TXCTL_REQUEUE)
- pkt_data->flags |= IEEE80211_TXPD_REQUEUE;
- if (control->flags & IEEE80211_TXCTL_EAPOL_FRAME)
- pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME;
- pkt_data->queue = control->queue;
+ info->flags &= IEEE80211_TX_CTL_REQ_TX_STATUS |
+ IEEE80211_TX_CTL_DO_NOT_ENCRYPT |
+ IEEE80211_TX_CTL_REQUEUE |
+ IEEE80211_TX_CTL_EAPOL_FRAME;
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
@@ -1306,9 +1306,10 @@
static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
struct sta_info *sta,
- struct sk_buff *skb,
- struct ieee80211_tx_status *status)
+ struct sk_buff *skb)
{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
sta->tx_filtered_count++;
/*
@@ -1316,7 +1317,7 @@
* packet. If the STA went to power save mode, this will happen
* when it wakes up for the next time.
*/
- sta->flags |= WLAN_STA_CLEAR_PS_FILT;
+ set_sta_flags(sta, WLAN_STA_CLEAR_PS_FILT);
/*
* This code races in the following way:
@@ -1348,20 +1349,18 @@
* can be unknown, for example with different interrupt status
* bits.
*/
- if (sta->flags & WLAN_STA_PS &&
+ if (test_sta_flags(sta, WLAN_STA_PS) &&
skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
- ieee80211_remove_tx_extra(local, sta->key, skb,
- &status->control);
+ ieee80211_remove_tx_extra(local, sta->key, skb);
skb_queue_tail(&sta->tx_filtered, skb);
return;
}
- if (!(sta->flags & WLAN_STA_PS) &&
- !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) {
+ if (!test_sta_flags(sta, WLAN_STA_PS) &&
+ !(info->flags & IEEE80211_TX_CTL_REQUEUE)) {
/* Software retry the packet once */
- status->control.flags |= IEEE80211_TXCTL_REQUEUE;
- ieee80211_remove_tx_extra(local, sta->key, skb,
- &status->control);
+ info->flags |= IEEE80211_TX_CTL_REQUEUE;
+ ieee80211_remove_tx_extra(local, sta->key, skb);
dev_queue_xmit(skb);
return;
}
@@ -1371,61 +1370,49 @@
"queue_len=%d PS=%d @%lu\n",
wiphy_name(local->hw.wiphy),
skb_queue_len(&sta->tx_filtered),
- !!(sta->flags & WLAN_STA_PS), jiffies);
+ !!test_sta_flags(sta, WLAN_STA_PS), jiffies);
dev_kfree_skb(skb);
}
-void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_status *status)
+void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct sk_buff *skb2;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
u16 frag, type;
struct ieee80211_tx_status_rtap_hdr *rthdr;
struct ieee80211_sub_if_data *sdata;
struct net_device *prev_dev = NULL;
- if (!status) {
- printk(KERN_ERR
- "%s: ieee80211_tx_status called with NULL status\n",
- wiphy_name(local->hw.wiphy));
- dev_kfree_skb(skb);
- return;
- }
-
rcu_read_lock();
- if (status->excessive_retries) {
+ if (info->status.excessive_retries) {
struct sta_info *sta;
sta = sta_info_get(local, hdr->addr1);
if (sta) {
- if (sta->flags & WLAN_STA_PS) {
+ if (test_sta_flags(sta, WLAN_STA_PS)) {
/*
* The STA is in power save mode, so assume
* that this TX packet failed because of that.
*/
- status->excessive_retries = 0;
- status->flags |= IEEE80211_TX_STATUS_TX_FILTERED;
- ieee80211_handle_filtered_frame(local, sta,
- skb, status);
+ ieee80211_handle_filtered_frame(local, sta, skb);
rcu_read_unlock();
return;
}
}
}
- if (status->flags & IEEE80211_TX_STATUS_TX_FILTERED) {
+ if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
struct sta_info *sta;
sta = sta_info_get(local, hdr->addr1);
if (sta) {
- ieee80211_handle_filtered_frame(local, sta, skb,
- status);
+ ieee80211_handle_filtered_frame(local, sta, skb);
rcu_read_unlock();
return;
}
} else
- rate_control_tx_status(local->mdev, skb, status);
+ rate_control_tx_status(local->mdev, skb);
rcu_read_unlock();
@@ -1439,14 +1426,14 @@
frag = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE;
- if (status->flags & IEEE80211_TX_STATUS_ACK) {
+ if (info->flags & IEEE80211_TX_STAT_ACK) {
if (frag == 0) {
local->dot11TransmittedFrameCount++;
if (is_multicast_ether_addr(hdr->addr1))
local->dot11MulticastTransmittedFrameCount++;
- if (status->retry_count > 0)
+ if (info->status.retry_count > 0)
local->dot11RetryCount++;
- if (status->retry_count > 1)
+ if (info->status.retry_count > 1)
local->dot11MultipleRetryCount++;
}
@@ -1483,7 +1470,7 @@
return;
}
- rthdr = (struct ieee80211_tx_status_rtap_hdr*)
+ rthdr = (struct ieee80211_tx_status_rtap_hdr *)
skb_push(skb, sizeof(*rthdr));
memset(rthdr, 0, sizeof(*rthdr));
@@ -1492,17 +1479,17 @@
cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
(1 << IEEE80211_RADIOTAP_DATA_RETRIES));
- if (!(status->flags & IEEE80211_TX_STATUS_ACK) &&
+ if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
!is_multicast_ether_addr(hdr->addr1))
rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
- if ((status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) &&
- (status->control.flags & IEEE80211_TXCTL_USE_CTS_PROTECT))
+ if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) &&
+ (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT))
rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
- else if (status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS)
+ else if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
- rthdr->data_retries = status->retry_count;
+ rthdr->data_retries = info->status.retry_count;
/* XXX: is this sufficient for BPF? */
skb_set_mac_header(skb, 0);
@@ -1652,12 +1639,32 @@
if (result < 0)
return result;
+ /*
+ * We use the number of queues for feature tests (QoS, HT) internally
+ * so restrict them appropriately.
+ */
+#ifdef CONFIG_MAC80211_QOS
+ if (hw->queues > IEEE80211_MAX_QUEUES)
+ hw->queues = IEEE80211_MAX_QUEUES;
+ if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES)
+ hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES;
+ if (hw->queues < 4)
+ hw->ampdu_queues = 0;
+#else
+ hw->queues = 1;
+ hw->ampdu_queues = 0;
+#endif
+
/* for now, mdev needs sub_if_data :/ */
- mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data),
- "wmaster%d", ether_setup);
+ mdev = alloc_netdev_mq(sizeof(struct ieee80211_sub_if_data),
+ "wmaster%d", ether_setup,
+ ieee80211_num_queues(hw));
if (!mdev)
goto fail_mdev_alloc;
+ if (ieee80211_num_queues(hw) > 1)
+ mdev->features |= NETIF_F_MULTI_QUEUE;
+
sdata = IEEE80211_DEV_TO_SUB_IF(mdev);
mdev->ieee80211_ptr = &sdata->wdev;
sdata->wdev.wiphy = local->hw.wiphy;
@@ -1702,13 +1709,13 @@
local->hw.conf.beacon_int = 1000;
- local->wstats_flags |= local->hw.max_rssi ?
- IW_QUAL_LEVEL_UPDATED : IW_QUAL_LEVEL_INVALID;
- local->wstats_flags |= local->hw.max_signal ?
+ local->wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC |
+ IEEE80211_HW_SIGNAL_DB |
+ IEEE80211_HW_SIGNAL_DBM) ?
IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID;
- local->wstats_flags |= local->hw.max_noise ?
+ local->wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ?
IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID;
- if (local->hw.max_rssi < 0 || local->hw.max_noise < 0)
+ if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
local->wstats_flags |= IW_QUAL_DBM;
result = sta_info_start(local);
@@ -1858,7 +1865,9 @@
struct sk_buff *skb;
int ret;
- BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb));
+ BUILD_BUG_ON(sizeof(struct ieee80211_tx_info) > sizeof(skb->cb));
+ BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, driver_data) +
+ IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb));
ret = rc80211_pid_init();
if (ret)
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 697ef67..b5933b2 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -315,6 +315,13 @@
return newtbl;
}
+static void __mesh_table_free(struct mesh_table *tbl)
+{
+ kfree(tbl->hash_buckets);
+ kfree(tbl->hashwlock);
+ kfree(tbl);
+}
+
void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
{
struct hlist_head *mesh_hash;
@@ -330,9 +337,7 @@
}
spin_unlock(&tbl->hashwlock[i]);
}
- kfree(tbl->hash_buckets);
- kfree(tbl->hashwlock);
- kfree(tbl);
+ __mesh_table_free(tbl);
}
static void ieee80211_mesh_path_timer(unsigned long data)
@@ -349,21 +354,16 @@
{
struct mesh_table *newtbl;
struct hlist_head *oldhash;
- struct hlist_node *p;
- int err = 0;
+ struct hlist_node *p, *q;
int i;
if (atomic_read(&tbl->entries)
- < tbl->mean_chain_len * (tbl->hash_mask + 1)) {
- err = -EPERM;
+ < tbl->mean_chain_len * (tbl->hash_mask + 1))
goto endgrow;
- }
newtbl = mesh_table_alloc(tbl->size_order + 1);
- if (!newtbl) {
- err = -ENOMEM;
+ if (!newtbl)
goto endgrow;
- }
newtbl->free_node = tbl->free_node;
newtbl->mean_chain_len = tbl->mean_chain_len;
@@ -373,13 +373,19 @@
oldhash = tbl->hash_buckets;
for (i = 0; i <= tbl->hash_mask; i++)
hlist_for_each(p, &oldhash[i])
- tbl->copy_node(p, newtbl);
+ if (tbl->copy_node(p, newtbl) < 0)
+ goto errcopy;
+ return newtbl;
+
+errcopy:
+ for (i = 0; i <= newtbl->hash_mask; i++) {
+ hlist_for_each_safe(p, q, &newtbl->hash_buckets[i])
+ tbl->free_node(p, 0);
+ }
+ __mesh_table_free(tbl);
endgrow:
- if (err)
- return NULL;
- else
- return newtbl;
+ return NULL;
}
/**
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 2e161f6..669eafa 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -109,7 +109,7 @@
__u32 hash_rnd; /* Used for hash generation */
atomic_t entries; /* Up to MAX_MESH_NEIGHBOURS */
void (*free_node) (struct hlist_node *p, bool free_leafs);
- void (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl);
+ int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl);
int size_order;
int mean_chain_len;
};
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index af0cd1e..7fa149e 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -26,7 +26,7 @@
{
if (ae)
offset += 6;
- return le32_to_cpu(get_unaligned((__le32 *) (preq_elem + offset)));
+ return get_unaligned_le32(preq_elem + offset);
}
/* HWMP IE processing macros */
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 99c2d36..947b13b4 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -158,19 +158,14 @@
if (atomic_add_unless(&sdata->u.sta.mpaths, 1, MESH_MAX_MPATHS) == 0)
return -ENOSPC;
+ err = -ENOMEM;
new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL);
- if (!new_mpath) {
- atomic_dec(&sdata->u.sta.mpaths);
- err = -ENOMEM;
- goto endadd2;
- }
+ if (!new_mpath)
+ goto err_path_alloc;
+
new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL);
- if (!new_node) {
- kfree(new_mpath);
- atomic_dec(&sdata->u.sta.mpaths);
- err = -ENOMEM;
- goto endadd2;
- }
+ if (!new_node)
+ goto err_node_alloc;
read_lock(&pathtbl_resize_lock);
memcpy(new_mpath->dst, dst, ETH_ALEN);
@@ -189,16 +184,11 @@
spin_lock(&mesh_paths->hashwlock[hash_idx]);
+ err = -EEXIST;
hlist_for_each_entry(node, n, bucket, list) {
mpath = node->mpath;
- if (mpath->dev == dev && memcmp(dst, mpath->dst, ETH_ALEN)
- == 0) {
- err = -EEXIST;
- atomic_dec(&sdata->u.sta.mpaths);
- kfree(new_node);
- kfree(new_mpath);
- goto endadd;
- }
+ if (mpath->dev == dev && memcmp(dst, mpath->dst, ETH_ALEN) == 0)
+ goto err_exists;
}
hlist_add_head_rcu(&new_node->list, bucket);
@@ -206,10 +196,9 @@
mesh_paths->mean_chain_len * (mesh_paths->hash_mask + 1))
grow = 1;
-endadd:
spin_unlock(&mesh_paths->hashwlock[hash_idx]);
read_unlock(&pathtbl_resize_lock);
- if (!err && grow) {
+ if (grow) {
struct mesh_table *oldtbl, *newtbl;
write_lock(&pathtbl_resize_lock);
@@ -217,7 +206,7 @@
newtbl = mesh_table_grow(mesh_paths);
if (!newtbl) {
write_unlock(&pathtbl_resize_lock);
- return -ENOMEM;
+ return 0;
}
rcu_assign_pointer(mesh_paths, newtbl);
write_unlock(&pathtbl_resize_lock);
@@ -225,7 +214,16 @@
synchronize_rcu();
mesh_table_free(oldtbl, false);
}
-endadd2:
+ return 0;
+
+err_exists:
+ spin_unlock(&mesh_paths->hashwlock[hash_idx]);
+ read_unlock(&pathtbl_resize_lock);
+ kfree(new_node);
+err_node_alloc:
+ kfree(new_mpath);
+err_path_alloc:
+ atomic_dec(&sdata->u.sta.mpaths);
return err;
}
@@ -460,25 +458,28 @@
struct mpath_node *node = hlist_entry(p, struct mpath_node, list);
mpath = node->mpath;
hlist_del_rcu(p);
- synchronize_rcu();
if (free_leafs)
kfree(mpath);
kfree(node);
}
-static void mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl)
+static int mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl)
{
struct mesh_path *mpath;
struct mpath_node *node, *new_node;
u32 hash_idx;
+ new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC);
+ if (new_node == NULL)
+ return -ENOMEM;
+
node = hlist_entry(p, struct mpath_node, list);
mpath = node->mpath;
- new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL);
new_node->mpath = mpath;
hash_idx = mesh_table_hash(mpath->dst, mpath->dev, newtbl);
hlist_add_head(&new_node->list,
&newtbl->hash_buckets[hash_idx]);
+ return 0;
}
int mesh_pathtbl_init(void)
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 37f0c2b..9efeb1f 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -79,7 +79,7 @@
*
* @sta: mes peer link to restart
*
- * Locking: this function must be called holding sta->plink_lock
+ * Locking: this function must be called holding sta->lock
*/
static inline void mesh_plink_fsm_restart(struct sta_info *sta)
{
@@ -105,7 +105,7 @@
if (!sta)
return NULL;
- sta->flags |= WLAN_STA_AUTHORIZED;
+ sta->flags = WLAN_STA_AUTHORIZED;
sta->supp_rates[local->hw.conf.channel->band] = rates;
return sta;
@@ -118,7 +118,7 @@
*
* All mesh paths with this peer as next hop will be flushed
*
- * Locking: the caller must hold sta->plink_lock
+ * Locking: the caller must hold sta->lock
*/
static void __mesh_plink_deactivate(struct sta_info *sta)
{
@@ -139,9 +139,9 @@
*/
void mesh_plink_deactivate(struct sta_info *sta)
{
- spin_lock_bh(&sta->plink_lock);
+ spin_lock_bh(&sta->lock);
__mesh_plink_deactivate(sta);
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
}
static int mesh_plink_frame_tx(struct net_device *dev,
@@ -270,10 +270,10 @@
*/
sta = (struct sta_info *) data;
- spin_lock_bh(&sta->plink_lock);
+ spin_lock_bh(&sta->lock);
if (sta->ignore_plink_timer) {
sta->ignore_plink_timer = false;
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
return;
}
mpl_dbg("Mesh plink timer for %s fired on state %d\n",
@@ -298,7 +298,7 @@
rand % sta->plink_timeout;
++sta->plink_retries;
mod_plink_timer(sta, sta->plink_timeout);
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid,
0, 0);
break;
@@ -311,7 +311,7 @@
reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT);
sta->plink_state = PLINK_HOLDING;
mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid,
reason);
break;
@@ -319,10 +319,10 @@
/* holding timer */
del_timer(&sta->plink_timer);
mesh_plink_fsm_restart(sta);
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
break;
default:
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
break;
}
}
@@ -344,16 +344,16 @@
DECLARE_MAC_BUF(mac);
#endif
- spin_lock_bh(&sta->plink_lock);
+ spin_lock_bh(&sta->lock);
get_random_bytes(&llid, 2);
sta->llid = llid;
if (sta->plink_state != PLINK_LISTEN) {
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
return -EBUSY;
}
sta->plink_state = PLINK_OPN_SNT;
mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mpl_dbg("Mesh plink: starting establishment with %s\n",
print_mac(mac, sta->addr));
@@ -367,10 +367,10 @@
DECLARE_MAC_BUF(mac);
#endif
- spin_lock_bh(&sta->plink_lock);
+ spin_lock_bh(&sta->lock);
__mesh_plink_deactivate(sta);
sta->plink_state = PLINK_BLOCKED;
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
}
int mesh_plink_close(struct sta_info *sta)
@@ -383,14 +383,14 @@
mpl_dbg("Mesh plink: closing link with %s\n",
print_mac(mac, sta->addr));
- spin_lock_bh(&sta->plink_lock);
+ spin_lock_bh(&sta->lock);
sta->reason = cpu_to_le16(MESH_LINK_CANCELLED);
reason = sta->reason;
if (sta->plink_state == PLINK_LISTEN ||
sta->plink_state == PLINK_BLOCKED) {
mesh_plink_fsm_restart(sta);
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
return 0;
} else if (sta->plink_state == PLINK_ESTAB) {
__mesh_plink_deactivate(sta);
@@ -402,7 +402,7 @@
sta->plink_state = PLINK_HOLDING;
llid = sta->llid;
plid = sta->plid;
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(sta->sdata->dev, PLINK_CLOSE, sta->addr, llid,
plid, reason);
return 0;
@@ -490,7 +490,7 @@
/* avoid warning */
break;
}
- spin_lock_bh(&sta->plink_lock);
+ spin_lock_bh(&sta->lock);
} else if (!sta) {
/* ftype == PLINK_OPEN */
u64 rates;
@@ -512,9 +512,9 @@
return;
}
event = OPN_ACPT;
- spin_lock_bh(&sta->plink_lock);
+ spin_lock_bh(&sta->lock);
} else {
- spin_lock_bh(&sta->plink_lock);
+ spin_lock_bh(&sta->lock);
switch (ftype) {
case PLINK_OPEN:
if (!mesh_plink_free_count(sdata) ||
@@ -551,7 +551,7 @@
break;
default:
mpl_dbg("Mesh plink: unknown frame subtype\n");
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
rcu_read_unlock();
return;
}
@@ -568,7 +568,7 @@
switch (event) {
case CLS_ACPT:
mesh_plink_fsm_restart(sta);
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
break;
case OPN_ACPT:
sta->plink_state = PLINK_OPN_RCVD;
@@ -576,14 +576,14 @@
get_random_bytes(&llid, 2);
sta->llid = llid;
mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid,
0, 0);
mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr,
llid, plid, 0);
break;
default:
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
break;
}
break;
@@ -603,7 +603,7 @@
sta->ignore_plink_timer = true;
llid = sta->llid;
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
plid, reason);
break;
@@ -612,7 +612,7 @@
sta->plink_state = PLINK_OPN_RCVD;
sta->plid = plid;
llid = sta->llid;
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
plid, 0);
break;
@@ -622,10 +622,10 @@
dot11MeshConfirmTimeout(sdata)))
sta->ignore_plink_timer = true;
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
break;
default:
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
break;
}
break;
@@ -645,13 +645,13 @@
sta->ignore_plink_timer = true;
llid = sta->llid;
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
plid, reason);
break;
case OPN_ACPT:
llid = sta->llid;
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
plid, 0);
break;
@@ -659,12 +659,12 @@
del_timer(&sta->plink_timer);
sta->plink_state = PLINK_ESTAB;
mesh_plink_inc_estab_count(sdata);
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mpl_dbg("Mesh plink with %s ESTABLISHED\n",
print_mac(mac, sta->addr));
break;
default:
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
break;
}
break;
@@ -684,7 +684,7 @@
sta->ignore_plink_timer = true;
llid = sta->llid;
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
plid, reason);
break;
@@ -692,14 +692,14 @@
del_timer(&sta->plink_timer);
sta->plink_state = PLINK_ESTAB;
mesh_plink_inc_estab_count(sdata);
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mpl_dbg("Mesh plink with %s ESTABLISHED\n",
print_mac(mac, sta->addr));
mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
plid, 0);
break;
default:
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
break;
}
break;
@@ -713,18 +713,18 @@
sta->plink_state = PLINK_HOLDING;
llid = sta->llid;
mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
plid, reason);
break;
case OPN_ACPT:
llid = sta->llid;
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
plid, 0);
break;
default:
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
break;
}
break;
@@ -734,7 +734,7 @@
if (del_timer(&sta->plink_timer))
sta->ignore_plink_timer = 1;
mesh_plink_fsm_restart(sta);
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
break;
case OPN_ACPT:
case CNF_ACPT:
@@ -742,19 +742,19 @@
case CNF_RJCT:
llid = sta->llid;
reason = sta->reason;
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
plid, reason);
break;
default:
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
}
break;
default:
/* should not get here, PLINK_BLOCKED is dealt with at the
* beggining of the function
*/
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
break;
}
diff --git a/net/mac80211/michael.c b/net/mac80211/michael.c
index 0f844f7..1fcdf38 100644
--- a/net/mac80211/michael.c
+++ b/net/mac80211/michael.c
@@ -6,85 +6,58 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-
#include <linux/types.h>
+#include <linux/bitops.h>
+#include <asm/unaligned.h>
#include "michael.h"
-static inline u32 rotr(u32 val, int bits)
+static void michael_block(struct michael_mic_ctx *mctx, u32 val)
{
- return (val >> bits) | (val << (32 - bits));
+ mctx->l ^= val;
+ mctx->r ^= rol32(mctx->l, 17);
+ mctx->l += mctx->r;
+ mctx->r ^= ((mctx->l & 0xff00ff00) >> 8) |
+ ((mctx->l & 0x00ff00ff) << 8);
+ mctx->l += mctx->r;
+ mctx->r ^= rol32(mctx->l, 3);
+ mctx->l += mctx->r;
+ mctx->r ^= ror32(mctx->l, 2);
+ mctx->l += mctx->r;
}
-
-static inline u32 rotl(u32 val, int bits)
+static void michael_mic_hdr(struct michael_mic_ctx *mctx,
+ const u8 *key, const u8 *da, const u8 *sa, u8 priority)
{
- return (val << bits) | (val >> (32 - bits));
+ mctx->l = get_unaligned_le32(key);
+ mctx->r = get_unaligned_le32(key + 4);
+
+ /*
+ * A pseudo header (DA, SA, Priority, 0, 0, 0) is used in Michael MIC
+ * calculation, but it is _not_ transmitted
+ */
+ michael_block(mctx, get_unaligned_le32(da));
+ michael_block(mctx, get_unaligned_le16(&da[4]) |
+ (get_unaligned_le16(sa) << 16));
+ michael_block(mctx, get_unaligned_le32(&sa[2]));
+ michael_block(mctx, priority);
}
-
-static inline u32 xswap(u32 val)
+void michael_mic(const u8 *key, const u8 *da, const u8 *sa, u8 priority,
+ const u8 *data, size_t data_len, u8 *mic)
{
- return ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8);
-}
-
-
-#define michael_block(l, r) \
-do { \
- r ^= rotl(l, 17); \
- l += r; \
- r ^= xswap(l); \
- l += r; \
- r ^= rotl(l, 3); \
- l += r; \
- r ^= rotr(l, 2); \
- l += r; \
-} while (0)
-
-
-static inline u32 michael_get32(u8 *data)
-{
- return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
-}
-
-
-static inline void michael_put32(u32 val, u8 *data)
-{
- data[0] = val & 0xff;
- data[1] = (val >> 8) & 0xff;
- data[2] = (val >> 16) & 0xff;
- data[3] = (val >> 24) & 0xff;
-}
-
-
-void michael_mic(u8 *key, u8 *da, u8 *sa, u8 priority,
- u8 *data, size_t data_len, u8 *mic)
-{
- u32 l, r, val;
+ u32 val;
size_t block, blocks, left;
+ struct michael_mic_ctx mctx;
- l = michael_get32(key);
- r = michael_get32(key + 4);
-
- /* A pseudo header (DA, SA, Priority, 0, 0, 0) is used in Michael MIC
- * calculation, but it is _not_ transmitted */
- l ^= michael_get32(da);
- michael_block(l, r);
- l ^= da[4] | (da[5] << 8) | (sa[0] << 16) | (sa[1] << 24);
- michael_block(l, r);
- l ^= michael_get32(&sa[2]);
- michael_block(l, r);
- l ^= priority;
- michael_block(l, r);
+ michael_mic_hdr(&mctx, key, da, sa, priority);
/* Real data */
blocks = data_len / 4;
left = data_len % 4;
- for (block = 0; block < blocks; block++) {
- l ^= michael_get32(&data[block * 4]);
- michael_block(l, r);
- }
+ for (block = 0; block < blocks; block++)
+ michael_block(&mctx, get_unaligned_le32(&data[block * 4]));
/* Partial block of 0..3 bytes and padding: 0x5a + 4..7 zeros to make
* total length a multiple of 4. */
@@ -94,11 +67,10 @@
left--;
val |= data[blocks * 4 + left];
}
- l ^= val;
- michael_block(l, r);
- /* last block is zero, so l ^ 0 = l */
- michael_block(l, r);
- michael_put32(l, mic);
- michael_put32(r, mic + 4);
+ michael_block(&mctx, val);
+ michael_block(&mctx, 0);
+
+ put_unaligned_le32(mctx.l, mic);
+ put_unaligned_le32(mctx.r, mic + 4);
}
diff --git a/net/mac80211/michael.h b/net/mac80211/michael.h
index 2e6aeba..69b4501 100644
--- a/net/mac80211/michael.h
+++ b/net/mac80211/michael.h
@@ -14,7 +14,11 @@
#define MICHAEL_MIC_LEN 8
-void michael_mic(u8 *key, u8 *da, u8 *sa, u8 priority,
- u8 *data, size_t data_len, u8 *mic);
+struct michael_mic_ctx {
+ u32 l, r;
+};
+
+void michael_mic(const u8 *key, const u8 *da, const u8 *sa, u8 priority,
+ const u8 *data, size_t data_len, u8 *mic);
#endif /* MICHAEL_H */
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 4d2b582..7f05820 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);
}
}
@@ -282,6 +272,12 @@
int count;
u8 *pos;
+ if (!(ifsta->flags & IEEE80211_STA_WMM_ENABLED))
+ return;
+
+ if (!wmm_param)
+ return;
+
if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
return;
count = wmm_param[6] & 0x0f;
@@ -305,29 +301,25 @@
switch (aci) {
case 1:
- queue = IEEE80211_TX_QUEUE_DATA3;
- if (acm) {
+ queue = 3;
+ if (acm)
local->wmm_acm |= BIT(0) | BIT(3);
- }
break;
case 2:
- queue = IEEE80211_TX_QUEUE_DATA1;
- if (acm) {
+ queue = 1;
+ if (acm)
local->wmm_acm |= BIT(4) | BIT(5);
- }
break;
case 3:
- queue = IEEE80211_TX_QUEUE_DATA0;
- if (acm) {
+ queue = 0;
+ if (acm)
local->wmm_acm |= BIT(6) | BIT(7);
- }
break;
case 0:
default:
- queue = IEEE80211_TX_QUEUE_DATA2;
- if (acm) {
+ queue = 2;
+ if (acm)
local->wmm_acm |= BIT(1) | BIT(2);
- }
break;
}
@@ -586,7 +578,7 @@
int encrypt)
{
struct ieee80211_sub_if_data *sdata;
- struct ieee80211_tx_packet_data *pkt_data;
+ struct ieee80211_tx_info *info;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
skb->dev = sdata->local->mdev;
@@ -594,11 +586,11 @@
skb_set_network_header(skb, 0);
skb_set_transport_header(skb, 0);
- pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
- memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
- pkt_data->ifindex = sdata->dev->ifindex;
+ info = IEEE80211_SKB_CB(skb);
+ memset(info, 0, sizeof(struct ieee80211_tx_info));
+ info->control.ifindex = sdata->dev->ifindex;
if (!encrypt)
- pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
+ info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
dev_queue_xmit(skb);
}
@@ -727,9 +719,8 @@
if (bss) {
if (bss->capability & WLAN_CAPABILITY_PRIVACY)
capab |= WLAN_CAPABILITY_PRIVACY;
- if (bss->wmm_ie) {
+ if (bss->wmm_ie)
wmm = 1;
- }
/* get all rates supported by the device and the AP as
* some APs don't like getting a superset of their rates
@@ -821,9 +812,32 @@
*pos++ = 1; /* WME ver */
*pos++ = 0;
}
+
/* wmm support is a must to HT */
- if (wmm && sband->ht_info.ht_supported) {
- __le16 tmp = cpu_to_le16(sband->ht_info.cap);
+ if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) &&
+ sband->ht_info.ht_supported && bss->ht_add_ie) {
+ struct ieee80211_ht_addt_info *ht_add_info =
+ (struct ieee80211_ht_addt_info *)bss->ht_add_ie;
+ u16 cap = sband->ht_info.cap;
+ __le16 tmp;
+ u32 flags = local->hw.conf.channel->flags;
+
+ switch (ht_add_info->ht_param & IEEE80211_HT_IE_CHA_SEC_OFFSET) {
+ case IEEE80211_HT_IE_CHA_SEC_ABOVE:
+ if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) {
+ cap &= ~IEEE80211_HT_CAP_SUP_WIDTH;
+ cap &= ~IEEE80211_HT_CAP_SGI_40;
+ }
+ break;
+ case IEEE80211_HT_IE_CHA_SEC_BELOW:
+ if (flags & IEEE80211_CHAN_NO_FAT_BELOW) {
+ cap &= ~IEEE80211_HT_CAP_SUP_WIDTH;
+ cap &= ~IEEE80211_HT_CAP_SGI_40;
+ }
+ break;
+ }
+
+ tmp = cpu_to_le16(cap);
pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2);
*pos++ = WLAN_EID_HT_CAPABILITY;
*pos++ = sizeof(struct ieee80211_ht_cap);
@@ -1141,8 +1155,8 @@
struct ieee80211_mgmt *mgmt;
u16 capab;
- skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
- sizeof(mgmt->u.action.u.addba_resp));
+ skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
+
if (!skb) {
printk(KERN_DEBUG "%s: failed to allocate buffer "
"for addba resp frame\n", dev->name);
@@ -1190,9 +1204,7 @@
struct ieee80211_mgmt *mgmt;
u16 capab;
- skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
- sizeof(mgmt->u.action.u.addba_req));
-
+ skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
if (!skb) {
printk(KERN_ERR "%s: failed to allocate buffer "
@@ -1293,7 +1305,7 @@
/* examine state machine */
- spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
+ spin_lock_bh(&sta->lock);
if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) {
#ifdef CONFIG_MAC80211_HT_DEBUG
@@ -1360,7 +1372,7 @@
tid_agg_rx->stored_mpdu_num = 0;
status = WLAN_STATUS_SUCCESS;
end:
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
+ spin_unlock_bh(&sta->lock);
end_no_lock:
ieee80211_send_addba_resp(sta->sdata->dev, sta->addr, tid,
@@ -1392,10 +1404,10 @@
state = &sta->ampdu_mlme.tid_state_tx[tid];
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_lock_bh(&sta->lock);
if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:"
"%d\n", *state);
goto addba_resp_exit;
@@ -1403,7 +1415,7 @@
if (mgmt->u.action.u.addba_resp.dialog_token !=
sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
@@ -1427,7 +1439,7 @@
ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
}
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
printk(KERN_DEBUG "recipient accepted agg: tid %d \n", tid);
} else {
printk(KERN_DEBUG "recipient rejected agg: tid %d \n", tid);
@@ -1435,7 +1447,7 @@
sta->ampdu_mlme.addba_req_num[tid]++;
/* this will allow the state check in stop_BA_session */
*state = HT_AGG_STATE_OPERATIONAL;
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
ieee80211_stop_tx_ba_session(hw, sta->addr, tid,
WLAN_BACK_INITIATOR);
}
@@ -1454,8 +1466,7 @@
struct ieee80211_mgmt *mgmt;
u16 params;
- skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
- sizeof(mgmt->u.action.u.delba));
+ skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
if (!skb) {
printk(KERN_ERR "%s: failed to allocate buffer "
@@ -1506,17 +1517,17 @@
}
/* check if TID is in operational state */
- spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
+ spin_lock_bh(&sta->lock);
if (sta->ampdu_mlme.tid_state_rx[tid]
!= HT_AGG_STATE_OPERATIONAL) {
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
+ spin_unlock_bh(&sta->lock);
rcu_read_unlock();
return;
}
sta->ampdu_mlme.tid_state_rx[tid] =
HT_AGG_STATE_REQ_STOP_BA_MSK |
(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
+ spin_unlock_bh(&sta->lock);
/* stop HW Rx aggregation. ampdu_action existence
* already verified in session init so we add the BUG_ON */
@@ -1593,10 +1604,10 @@
ieee80211_sta_stop_rx_ba_session(dev, sta->addr, tid,
WLAN_BACK_INITIATOR, 0);
else { /* WLAN_BACK_RECIPIENT */
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_lock_bh(&sta->lock);
sta->ampdu_mlme.tid_state_tx[tid] =
HT_AGG_STATE_OPERATIONAL;
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid,
WLAN_BACK_RECIPIENT);
}
@@ -1633,9 +1644,9 @@
state = &sta->ampdu_mlme.tid_state_tx[tid];
/* check if the TID waits for addBA response */
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_lock_bh(&sta->lock);
if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
*state = HT_AGG_STATE_IDLE;
printk(KERN_DEBUG "timer expired on tid %d but we are not "
"expecting addBA response there", tid);
@@ -1646,7 +1657,7 @@
/* go through the state check in stop_BA_session */
*state = HT_AGG_STATE_OPERATIONAL;
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid,
WLAN_BACK_INITIATOR);
@@ -1659,7 +1670,7 @@
* resetting it after each frame that arrives from the originator.
* if this timer expires ieee80211_sta_stop_rx_ba_session will be executed.
*/
-void sta_rx_agg_session_timer_expired(unsigned long data)
+static void sta_rx_agg_session_timer_expired(unsigned long data)
{
/* not an elegant detour, but there is no choice as the timer passes
* only one argument, and various sta_info are needed here, so init
@@ -1848,9 +1859,8 @@
" (reason=%d)\n",
dev->name, print_mac(mac, mgmt->sa), reason_code);
- if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) {
+ if (ifsta->flags & IEEE80211_STA_AUTHENTICATED)
printk(KERN_DEBUG "%s: deauthenticated\n", dev->name);
- }
if (ifsta->state == IEEE80211_AUTHENTICATE ||
ifsta->state == IEEE80211_ASSOCIATE ||
@@ -2013,8 +2023,8 @@
local->hw.conf.channel->center_freq,
ifsta->ssid, ifsta->ssid_len);
if (bss) {
- sta->last_rssi = bss->rssi;
sta->last_signal = bss->signal;
+ sta->last_qual = bss->qual;
sta->last_noise = bss->noise;
ieee80211_rx_bss_put(dev, bss);
}
@@ -2038,8 +2048,8 @@
* to between the sta_info_alloc() and sta_info_insert() above.
*/
- sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP |
- WLAN_STA_AUTHORIZED;
+ set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP |
+ WLAN_STA_AUTHORIZED);
rates = 0;
basic_rates = 0;
@@ -2083,7 +2093,8 @@
else
sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
- if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param) {
+ if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param &&
+ (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
struct ieee80211_ht_bss_info bss_info;
ieee80211_ht_cap_ie_to_ht_info(
(struct ieee80211_ht_cap *)
@@ -2096,8 +2107,8 @@
rate_control_rate_init(sta, local);
- if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
- sta->flags |= WLAN_STA_WME;
+ if (elems.wmm_param) {
+ set_sta_flags(sta, WLAN_STA_WME);
rcu_read_unlock();
ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
elems.wmm_param_len);
@@ -2281,6 +2292,7 @@
kfree(bss->rsn_ie);
kfree(bss->wmm_ie);
kfree(bss->ht_ie);
+ kfree(bss->ht_add_ie);
kfree(bss_mesh_id(bss));
kfree(bss_mesh_cfg(bss));
kfree(bss);
@@ -2331,7 +2343,7 @@
int res, rates, i, j;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
- struct ieee80211_tx_control control;
+ struct ieee80211_tx_info *control;
struct rate_selection ratesel;
u8 *pos;
struct ieee80211_sub_if_data *sdata;
@@ -2419,21 +2431,22 @@
memcpy(pos, &bss->supp_rates[8], rates);
}
- memset(&control, 0, sizeof(control));
+ control = IEEE80211_SKB_CB(skb);
+
rate_control_get_rate(dev, sband, skb, &ratesel);
- if (!ratesel.rate) {
+ if (ratesel.rate_idx < 0) {
printk(KERN_DEBUG "%s: Failed to determine TX rate "
"for IBSS beacon\n", dev->name);
break;
}
- control.vif = &sdata->vif;
- control.tx_rate = ratesel.rate;
+ control->control.vif = &sdata->vif;
+ control->tx_rate_idx = ratesel.rate_idx;
if (sdata->bss_conf.use_short_preamble &&
- ratesel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
- control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
- control.antenna_sel_tx = local->hw.conf.antenna_sel_tx;
- control.flags |= IEEE80211_TXCTL_NO_ACK;
- control.retry_limit = 1;
+ sband->bitrates[ratesel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE)
+ control->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
+ control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
+ control->flags |= IEEE80211_TX_CTL_NO_ACK;
+ control->control.retry_limit = 1;
ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC);
if (ifsta->probe_resp) {
@@ -2448,8 +2461,7 @@
}
if (local->ops->beacon_update &&
- local->ops->beacon_update(local_to_hw(local),
- skb, &control) == 0) {
+ local->ops->beacon_update(local_to_hw(local), skb) == 0) {
printk(KERN_DEBUG "%s: Configured IBSS beacon "
"template\n", dev->name);
skb = NULL;
@@ -2657,6 +2669,26 @@
bss->ht_ie_len = 0;
}
+ if (elems.ht_info_elem &&
+ (!bss->ht_add_ie ||
+ bss->ht_add_ie_len != elems.ht_info_elem_len ||
+ memcmp(bss->ht_add_ie, elems.ht_info_elem,
+ elems.ht_info_elem_len))) {
+ kfree(bss->ht_add_ie);
+ bss->ht_add_ie =
+ kmalloc(elems.ht_info_elem_len + 2, GFP_ATOMIC);
+ if (bss->ht_add_ie) {
+ memcpy(bss->ht_add_ie, elems.ht_info_elem - 2,
+ elems.ht_info_elem_len + 2);
+ bss->ht_add_ie_len = elems.ht_info_elem_len + 2;
+ } else
+ bss->ht_add_ie_len = 0;
+ } else if (!elems.ht_info_elem && bss->ht_add_ie) {
+ kfree(bss->ht_add_ie);
+ bss->ht_add_ie = NULL;
+ bss->ht_add_ie_len = 0;
+ }
+
bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int);
bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);
@@ -2682,9 +2714,9 @@
bss->timestamp = beacon_timestamp;
bss->last_update = jiffies;
- bss->rssi = rx_status->ssi;
bss->signal = rx_status->signal;
bss->noise = rx_status->noise;
+ bss->qual = rx_status->qual;
if (!beacon && !bss->probe_resp)
bss->probe_resp = true;
@@ -2879,10 +2911,8 @@
ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
- if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
- ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
- elems.wmm_param_len);
- }
+ ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
+ elems.wmm_param_len);
/* Do not send changes to driver if we are scanning. This removes
* requirement that driver's bss_info_changed function needs to be
@@ -3478,9 +3508,9 @@
!ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len))
continue;
- if (!selected || top_rssi < bss->rssi) {
+ if (!selected || top_rssi < bss->signal) {
selected = bss;
- top_rssi = bss->rssi;
+ top_rssi = bss->signal;
}
}
if (selected)
@@ -3557,10 +3587,12 @@
bss->beacon_int = local->hw.conf.beacon_int;
bss->last_update = jiffies;
bss->capability = WLAN_CAPABILITY_IBSS;
- if (sdata->default_key) {
+
+ if (sdata->default_key)
bss->capability |= WLAN_CAPABILITY_PRIVACY;
- } else
+ else
sdata->drop_unencrypted = 0;
+
bss->supp_rates_len = sband->n_bitrates;
pos = bss->supp_rates;
for (i = 0; i < sband->n_bitrates; i++) {
@@ -4114,8 +4146,8 @@
IW_EV_FREQ_LEN);
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVQUAL;
- iwe.u.qual.qual = bss->signal;
- iwe.u.qual.level = bss->rssi;
+ iwe.u.qual.qual = bss->qual;
+ iwe.u.qual.level = bss->signal;
iwe.u.qual.noise = bss->noise;
iwe.u.qual.updated = local->wstats_flags;
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
@@ -4146,6 +4178,14 @@
bss->rsn_ie);
}
+ if (bss && bss->ht_ie) {
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = bss->ht_ie_len;
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+ bss->ht_ie);
+ }
+
if (bss && bss->supp_rates_len > 0) {
/* display all supported rates in readable format */
char *p = current_ev + IW_EV_LCP_LEN;
@@ -4247,6 +4287,7 @@
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+
kfree(ifsta->extra_ie);
if (len == 0) {
ifsta->extra_ie = NULL;
@@ -4264,9 +4305,9 @@
}
-struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev,
- struct sk_buff *skb, u8 *bssid,
- u8 *addr)
+struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev,
+ struct sk_buff *skb, u8 *bssid,
+ u8 *addr)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
@@ -4290,7 +4331,7 @@
if (!sta)
return NULL;
- sta->flags |= WLAN_STA_AUTHORIZED;
+ set_sta_flags(sta, WLAN_STA_AUTHORIZED);
sta->supp_rates[local->hw.conf.channel->band] =
sdata->u.sta.supp_rates_bits[local->hw.conf.channel->band];
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index 841df93..0388c09 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -176,20 +176,24 @@
rcu_read_lock();
sta = sta_info_get(local, hdr->addr1);
- memset(sel, 0, sizeof(struct rate_selection));
+ sel->rate_idx = -1;
+ sel->nonerp_idx = -1;
+ sel->probe_idx = -1;
ref->ops->get_rate(ref->priv, dev, sband, skb, sel);
+ BUG_ON(sel->rate_idx < 0);
+
/* Select a non-ERP backup rate. */
- if (!sel->nonerp) {
+ if (sel->nonerp_idx < 0) {
for (i = 0; i < sband->n_bitrates; i++) {
struct ieee80211_rate *rate = &sband->bitrates[i];
- if (sel->rate->bitrate < rate->bitrate)
+ if (sband->bitrates[sel->rate_idx].bitrate < rate->bitrate)
break;
if (rate_supported(sta, sband->band, i) &&
!(rate->flags & IEEE80211_RATE_ERP_G))
- sel->nonerp = rate;
+ sel->nonerp_idx = i;
}
}
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h
index 5b45f33..0ed9c8a 100644
--- a/net/mac80211/rate.h
+++ b/net/mac80211/rate.h
@@ -19,22 +19,22 @@
#include "ieee80211_i.h"
#include "sta_info.h"
-/* TODO: kdoc */
+/**
+ * struct rate_selection - rate selection for rate control algos
+ * @rate: selected transmission rate index
+ * @nonerp: Non-ERP rate to use instead if ERP cannot be used
+ * @probe: rate for probing (or -1)
+ *
+ */
struct rate_selection {
- /* Selected transmission rate */
- struct ieee80211_rate *rate;
- /* Non-ERP rate to use if mac80211 decides it cannot use an ERP rate */
- struct ieee80211_rate *nonerp;
- /* probe with this rate, or NULL for no probing */
- struct ieee80211_rate *probe;
+ s8 rate_idx, nonerp_idx, probe_idx;
};
struct rate_control_ops {
struct module *module;
const char *name;
void (*tx_status)(void *priv, struct net_device *dev,
- struct sk_buff *skb,
- struct ieee80211_tx_status *status);
+ struct sk_buff *skb);
void (*get_rate)(void *priv, struct net_device *dev,
struct ieee80211_supported_band *band,
struct sk_buff *skb,
@@ -76,13 +76,12 @@
void rate_control_put(struct rate_control_ref *ref);
static inline void rate_control_tx_status(struct net_device *dev,
- struct sk_buff *skb,
- struct ieee80211_tx_status *status)
+ struct sk_buff *skb)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct rate_control_ref *ref = local->rate_ctrl;
- ref->ops->tx_status(ref->priv, dev, skb, status);
+ ref->ops->tx_status(ref->priv, dev, skb);
}
@@ -138,7 +137,7 @@
return (sta == NULL || sta->supp_rates[band] & BIT(index));
}
-static inline int
+static inline s8
rate_lowest_index(struct ieee80211_local *local,
struct ieee80211_supported_band *sband,
struct sta_info *sta)
@@ -155,14 +154,6 @@
return 0;
}
-static inline struct ieee80211_rate *
-rate_lowest(struct ieee80211_local *local,
- struct ieee80211_supported_band *sband,
- struct sta_info *sta)
-{
- return &sband->bitrates[rate_lowest_index(local, sband, sta)];
-}
-
/* functions for rate control related to a device */
int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
diff --git a/net/mac80211/rc80211_pid.h b/net/mac80211/rc80211_pid.h
index 04afc13..2078803 100644
--- a/net/mac80211/rc80211_pid.h
+++ b/net/mac80211/rc80211_pid.h
@@ -61,7 +61,7 @@
union rc_pid_event_data {
/* RC_PID_EVENT_TX_STATUS */
struct {
- struct ieee80211_tx_status tx_status;
+ struct ieee80211_tx_info tx_status;
};
/* RC_PID_EVENT_TYPE_RATE_CHANGE */
/* RC_PID_EVENT_TYPE_TX_RATE */
@@ -158,7 +158,7 @@
};
void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf,
- struct ieee80211_tx_status *stat);
+ struct ieee80211_tx_info *stat);
void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf,
int index, int rate);
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c
index a849b74..e894541 100644
--- a/net/mac80211/rc80211_pid_algo.c
+++ b/net/mac80211/rc80211_pid_algo.c
@@ -237,8 +237,7 @@
}
static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
- struct sk_buff *skb,
- struct ieee80211_tx_status *status)
+ struct sk_buff *skb)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@@ -248,6 +247,7 @@
struct rc_pid_sta_info *spinfo;
unsigned long period;
struct ieee80211_supported_band *sband;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
rcu_read_lock();
@@ -266,28 +266,28 @@
/* Ignore all frames that were sent with a different rate than the rate
* we currently advise mac80211 to use. */
- if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx])
+ if (info->tx_rate_idx != sta->txrate_idx)
goto unlock;
spinfo = sta->rate_ctrl_priv;
spinfo->tx_num_xmit++;
#ifdef CONFIG_MAC80211_DEBUGFS
- rate_control_pid_event_tx_status(&spinfo->events, status);
+ rate_control_pid_event_tx_status(&spinfo->events, info);
#endif
/* We count frames that totally failed to be transmitted as two bad
* frames, those that made it out but had some retries as one good and
* one bad frame. */
- if (status->excessive_retries) {
+ if (info->status.excessive_retries) {
spinfo->tx_num_failed += 2;
spinfo->tx_num_xmit++;
- } else if (status->retry_count) {
+ } else if (info->status.retry_count) {
spinfo->tx_num_failed++;
spinfo->tx_num_xmit++;
}
- if (status->excessive_retries) {
+ if (info->status.excessive_retries) {
sta->tx_retry_failed++;
sta->tx_num_consecutive_failures++;
sta->tx_num_mpdu_fail++;
@@ -295,8 +295,8 @@
sta->tx_num_consecutive_failures = 0;
sta->tx_num_mpdu_ok++;
}
- sta->tx_retry_count += status->retry_count;
- sta->tx_num_mpdu_fail += status->retry_count;
+ sta->tx_retry_count += info->status.retry_count;
+ sta->tx_num_mpdu_fail += info->status.retry_count;
/* Update PID controller state. */
period = (HZ * pinfo->sampling_period + 500) / 1000;
@@ -330,7 +330,7 @@
fc = le16_to_cpu(hdr->frame_control);
if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
is_multicast_ether_addr(hdr->addr1) || !sta) {
- sel->rate = rate_lowest(local, sband, sta);
+ sel->rate_idx = rate_lowest_index(local, sband, sta);
rcu_read_unlock();
return;
}
@@ -349,7 +349,7 @@
rcu_read_unlock();
- sel->rate = &sband->bitrates[rateidx];
+ sel->rate_idx = rateidx;
#ifdef CONFIG_MAC80211_DEBUGFS
rate_control_pid_event_tx_rate(
diff --git a/net/mac80211/rc80211_pid_debugfs.c b/net/mac80211/rc80211_pid_debugfs.c
index ff5c380f..8121d3b 100644
--- a/net/mac80211/rc80211_pid_debugfs.c
+++ b/net/mac80211/rc80211_pid_debugfs.c
@@ -39,11 +39,11 @@
}
void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf,
- struct ieee80211_tx_status *stat)
+ struct ieee80211_tx_info *stat)
{
union rc_pid_event_data evd;
- memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_status));
+ memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_info));
rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_STATUS, &evd);
}
@@ -167,8 +167,8 @@
switch (ev->type) {
case RC_PID_EVENT_TYPE_TX_STATUS:
p += snprintf(pb + p, length - p, "tx_status %u %u",
- ev->data.tx_status.excessive_retries,
- ev->data.tx_status.retry_count);
+ ev->data.tx_status.status.excessive_retries,
+ ev->data.tx_status.status.retry_count);
break;
case RC_PID_EVENT_TYPE_RATE_CHANGE:
p += snprintf(pb + p, length - p, "rate_change %d %d",
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 0941e5d..a3643fd 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -77,6 +77,134 @@
return 0;
}
+static int
+ieee80211_rx_radiotap_len(struct ieee80211_local *local,
+ struct ieee80211_rx_status *status)
+{
+ int len;
+
+ /* always present fields */
+ len = sizeof(struct ieee80211_radiotap_header) + 9;
+
+ if (status->flag & RX_FLAG_TSFT)
+ len += 8;
+ if (local->hw.flags & IEEE80211_HW_SIGNAL_DB ||
+ local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
+ len += 1;
+ if (local->hw.flags & IEEE80211_HW_NOISE_DBM)
+ len += 1;
+
+ if (len & 1) /* padding for RX_FLAGS if necessary */
+ len++;
+
+ /* make sure radiotap starts at a naturally aligned address */
+ if (len % 8)
+ len = roundup(len, 8);
+
+ return len;
+}
+
+/**
+ * ieee80211_add_rx_radiotap_header - add radiotap header
+ *
+ * add a radiotap header containing all the fields which the hardware provided.
+ */
+static void
+ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
+ struct sk_buff *skb,
+ struct ieee80211_rx_status *status,
+ struct ieee80211_rate *rate,
+ int rtap_len)
+{
+ struct ieee80211_radiotap_header *rthdr;
+ unsigned char *pos;
+
+ rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len);
+ memset(rthdr, 0, rtap_len);
+
+ /* radiotap header, set always present flags */
+ rthdr->it_present =
+ cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
+ (1 << IEEE80211_RADIOTAP_RATE) |
+ (1 << IEEE80211_RADIOTAP_CHANNEL) |
+ (1 << IEEE80211_RADIOTAP_ANTENNA) |
+ (1 << IEEE80211_RADIOTAP_RX_FLAGS));
+ rthdr->it_len = cpu_to_le16(rtap_len);
+
+ pos = (unsigned char *)(rthdr+1);
+
+ /* the order of the following fields is important */
+
+ /* IEEE80211_RADIOTAP_TSFT */
+ if (status->flag & RX_FLAG_TSFT) {
+ *(__le64 *)pos = cpu_to_le64(status->mactime);
+ rthdr->it_present |=
+ cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT);
+ pos += 8;
+ }
+
+ /* IEEE80211_RADIOTAP_FLAGS */
+ if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
+ *pos |= IEEE80211_RADIOTAP_F_FCS;
+ pos++;
+
+ /* IEEE80211_RADIOTAP_RATE */
+ *pos = rate->bitrate / 5;
+ pos++;
+
+ /* IEEE80211_RADIOTAP_CHANNEL */
+ *(__le16 *)pos = cpu_to_le16(status->freq);
+ pos += 2;
+ if (status->band == IEEE80211_BAND_5GHZ)
+ *(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_OFDM |
+ IEEE80211_CHAN_5GHZ);
+ else
+ *(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_DYN |
+ IEEE80211_CHAN_2GHZ);
+ pos += 2;
+
+ /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */
+ if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
+ *pos = status->signal;
+ rthdr->it_present |=
+ cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
+ pos++;
+ }
+
+ /* IEEE80211_RADIOTAP_DBM_ANTNOISE */
+ if (local->hw.flags & IEEE80211_HW_NOISE_DBM) {
+ *pos = status->noise;
+ rthdr->it_present |=
+ cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE);
+ pos++;
+ }
+
+ /* IEEE80211_RADIOTAP_LOCK_QUALITY is missing */
+
+ /* IEEE80211_RADIOTAP_ANTENNA */
+ *pos = status->antenna;
+ pos++;
+
+ /* IEEE80211_RADIOTAP_DB_ANTSIGNAL */
+ if (local->hw.flags & IEEE80211_HW_SIGNAL_DB) {
+ *pos = status->signal;
+ rthdr->it_present |=
+ cpu_to_le32(1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL);
+ pos++;
+ }
+
+ /* IEEE80211_RADIOTAP_DB_ANTNOISE is not used */
+
+ /* IEEE80211_RADIOTAP_RX_FLAGS */
+ /* ensure 2 byte alignment for the 2 byte field as required */
+ if ((pos - (unsigned char *)rthdr) & 1)
+ pos++;
+ /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */
+ if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
+ *(__le16 *)pos |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS);
+ pos += 2;
+}
+
/*
* This function copies a received frame to all monitor interfaces and
* returns a cleaned-up SKB that no longer includes the FCS nor the
@@ -89,17 +217,6 @@
{
struct ieee80211_sub_if_data *sdata;
int needed_headroom = 0;
- struct ieee80211_radiotap_header *rthdr;
- __le64 *rttsft = NULL;
- struct ieee80211_rtap_fixed_data {
- u8 flags;
- u8 rate;
- __le16 chan_freq;
- __le16 chan_flags;
- u8 antsignal;
- u8 padding_for_rxflags;
- __le16 rx_flags;
- } __attribute__ ((packed)) *rtfixed;
struct sk_buff *skb, *skb2;
struct net_device *prev_dev = NULL;
int present_fcs_len = 0;
@@ -116,8 +233,8 @@
if (status->flag & RX_FLAG_RADIOTAP)
rtap_len = ieee80211_get_radiotap_len(origskb->data);
else
- /* room for radiotap header, always present fields and TSFT */
- needed_headroom = sizeof(*rthdr) + sizeof(*rtfixed) + 8;
+ /* room for the radiotap header based on driver features */
+ needed_headroom = ieee80211_rx_radiotap_len(local, status);
if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
present_fcs_len = FCS_LEN;
@@ -163,55 +280,9 @@
}
/* if necessary, prepend radiotap information */
- if (!(status->flag & RX_FLAG_RADIOTAP)) {
- rtfixed = (void *) skb_push(skb, sizeof(*rtfixed));
- rtap_len = sizeof(*rthdr) + sizeof(*rtfixed);
- if (status->flag & RX_FLAG_TSFT) {
- rttsft = (void *) skb_push(skb, sizeof(*rttsft));
- rtap_len += 8;
- }
- rthdr = (void *) skb_push(skb, sizeof(*rthdr));
- memset(rthdr, 0, sizeof(*rthdr));
- memset(rtfixed, 0, sizeof(*rtfixed));
- rthdr->it_present =
- cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
- (1 << IEEE80211_RADIOTAP_RATE) |
- (1 << IEEE80211_RADIOTAP_CHANNEL) |
- (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |
- (1 << IEEE80211_RADIOTAP_RX_FLAGS));
- rtfixed->flags = 0;
- if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
- rtfixed->flags |= IEEE80211_RADIOTAP_F_FCS;
-
- if (rttsft) {
- *rttsft = cpu_to_le64(status->mactime);
- rthdr->it_present |=
- cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT);
- }
-
- /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */
- rtfixed->rx_flags = 0;
- if (status->flag &
- (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
- rtfixed->rx_flags |=
- cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS);
-
- rtfixed->rate = rate->bitrate / 5;
-
- rtfixed->chan_freq = cpu_to_le16(status->freq);
-
- if (status->band == IEEE80211_BAND_5GHZ)
- rtfixed->chan_flags =
- cpu_to_le16(IEEE80211_CHAN_OFDM |
- IEEE80211_CHAN_5GHZ);
- else
- rtfixed->chan_flags =
- cpu_to_le16(IEEE80211_CHAN_DYN |
- IEEE80211_CHAN_2GHZ);
-
- rtfixed->antsignal = status->ssi;
- rthdr->it_len = cpu_to_le16(rtap_len);
- }
+ if (!(status->flag & RX_FLAG_RADIOTAP))
+ ieee80211_add_rx_radiotap_header(local, skb, status, rate,
+ needed_headroom);
skb_reset_mac_header(skb);
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -275,11 +346,6 @@
}
}
- I802_DEBUG_INC(rx->local->wme_rx_queue[tid]);
- /* only a debug counter, sta might not be assigned properly yet */
- if (rx->sta)
- I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]);
-
rx->queue = tid;
/* Set skb->priority to 1d tag if highest order bit of TID is not set.
* For now, set skb->priority to 0 for other cases. */
@@ -321,51 +387,9 @@
}
-static u32 ieee80211_rx_load_stats(struct ieee80211_local *local,
- struct sk_buff *skb,
- struct ieee80211_rx_status *status,
- struct ieee80211_rate *rate)
-{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- u32 load = 0, hdrtime;
-
- /* Estimate total channel use caused by this frame */
-
- /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
- * 1 usec = 1/8 * (1080 / 10) = 13.5 */
-
- if (status->band == IEEE80211_BAND_5GHZ ||
- (status->band == IEEE80211_BAND_5GHZ &&
- rate->flags & IEEE80211_RATE_ERP_G))
- hdrtime = CHAN_UTIL_HDR_SHORT;
- else
- hdrtime = CHAN_UTIL_HDR_LONG;
-
- load = hdrtime;
- if (!is_multicast_ether_addr(hdr->addr1))
- load += hdrtime;
-
- /* TODO: optimise again */
- load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate;
-
- /* Divide channel_use by 8 to avoid wrapping around the counter */
- load >>= CHAN_UTIL_SHIFT;
-
- return load;
-}
-
/* rx handlers */
static ieee80211_rx_result
-ieee80211_rx_h_if_stats(struct ieee80211_rx_data *rx)
-{
- if (rx->sta)
- rx->sta->channel_use_raw += rx->load;
- rx->sdata->channel_use_raw += rx->load;
- return RX_CONTINUE;
-}
-
-static ieee80211_rx_result
ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
{
struct ieee80211_local *local = rx->local;
@@ -484,7 +508,7 @@
((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL &&
(rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) &&
rx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
- (!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) {
+ (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) {
if ((!(rx->fc & IEEE80211_FCTL_FROMDS) &&
!(rx->fc & IEEE80211_FCTL_TODS) &&
(rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)
@@ -635,8 +659,7 @@
if (sdata->bss)
atomic_inc(&sdata->bss->num_sta_ps);
- sta->flags |= WLAN_STA_PS;
- sta->flags &= ~WLAN_STA_PSPOLL;
+ set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL);
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n",
dev->name, print_mac(mac, sta->addr), sta->aid);
@@ -649,7 +672,7 @@
struct sk_buff *skb;
int sent = 0;
struct ieee80211_sub_if_data *sdata;
- struct ieee80211_tx_packet_data *pkt_data;
+ struct ieee80211_tx_info *info;
DECLARE_MAC_BUF(mac);
sdata = sta->sdata;
@@ -657,7 +680,7 @@
if (sdata->bss)
atomic_dec(&sdata->bss->num_sta_ps);
- sta->flags &= ~(WLAN_STA_PS | WLAN_STA_PSPOLL);
+ clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL);
if (!skb_queue_empty(&sta->ps_tx_buf))
sta_info_clear_tim_bit(sta);
@@ -669,13 +692,13 @@
/* Send all buffered frames to the station */
while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
- pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+ info = IEEE80211_SKB_CB(skb);
sent++;
- pkt_data->flags |= IEEE80211_TXPD_REQUEUE;
+ info->flags |= IEEE80211_TX_CTL_REQUEUE;
dev_queue_xmit(skb);
}
while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
- pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+ info = IEEE80211_SKB_CB(skb);
local->total_ps_buffered--;
sent++;
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
@@ -683,7 +706,7 @@
"since STA not sleeping anymore\n", dev->name,
print_mac(mac, sta->addr), sta->aid);
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
- pkt_data->flags |= IEEE80211_TXPD_REQUEUE;
+ info->flags |= IEEE80211_TX_CTL_REQUEUE;
dev_queue_xmit(skb);
}
@@ -725,16 +748,17 @@
sta->rx_fragments++;
sta->rx_bytes += rx->skb->len;
- sta->last_rssi = rx->status->ssi;
sta->last_signal = rx->status->signal;
+ sta->last_qual = rx->status->qual;
sta->last_noise = rx->status->noise;
if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) {
/* Change STA power saving mode only in the end of a frame
* exchange sequence */
- if ((sta->flags & WLAN_STA_PS) && !(rx->fc & IEEE80211_FCTL_PM))
+ if (test_sta_flags(sta, WLAN_STA_PS) &&
+ !(rx->fc & IEEE80211_FCTL_PM))
rx->sent_ps_buffered += ap_sta_ps_end(dev, sta);
- else if (!(sta->flags & WLAN_STA_PS) &&
+ else if (!test_sta_flags(sta, WLAN_STA_PS) &&
(rx->fc & IEEE80211_FCTL_PM))
ap_sta_ps_start(dev, sta);
}
@@ -988,7 +1012,7 @@
* Tell TX path to send one frame even though the STA may
* still remain is PS mode after this frame exchange.
*/
- rx->sta->flags |= WLAN_STA_PSPOLL;
+ set_sta_flags(rx->sta, WLAN_STA_PSPOLL);
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n",
@@ -1051,7 +1075,8 @@
static int
ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)
{
- if (unlikely(!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED))) {
+ if (unlikely(!rx->sta ||
+ !test_sta_flags(rx->sta, WLAN_STA_AUTHORIZED))) {
#ifdef CONFIG_MAC80211_DEBUG
if (net_ratelimit())
printk(KERN_DEBUG "%s: dropped frame "
@@ -1713,7 +1738,6 @@
typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_rx_data *);
static ieee80211_rx_handler ieee80211_rx_handlers[] =
{
- ieee80211_rx_h_if_stats,
ieee80211_rx_h_passive_scan,
ieee80211_rx_h_check,
ieee80211_rx_h_decrypt,
@@ -1872,7 +1896,6 @@
static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
struct sk_buff *skb,
struct ieee80211_rx_status *status,
- u32 load,
struct ieee80211_rate *rate)
{
struct ieee80211_local *local = hw_to_local(hw);
@@ -1891,7 +1914,6 @@
rx.local = local;
rx.status = status;
- rx.load = load;
rx.rate = rate;
rx.fc = le16_to_cpu(hdr->frame_control);
type = rx.fc & IEEE80211_FCTL_FTYPE;
@@ -2000,7 +2022,6 @@
struct ieee80211_rx_status status;
u16 head_seq_num, buf_size;
int index;
- u32 pkt_load;
struct ieee80211_supported_band *sband;
struct ieee80211_rate *rate;
@@ -2035,12 +2056,9 @@
sizeof(status));
sband = local->hw.wiphy->bands[status.band];
rate = &sband->bitrates[status.rate_idx];
- pkt_load = ieee80211_rx_load_stats(local,
- tid_agg_rx->reorder_buf[index],
- &status, rate);
__ieee80211_rx_handle_packet(hw,
tid_agg_rx->reorder_buf[index],
- &status, pkt_load, rate);
+ &status, rate);
tid_agg_rx->stored_mpdu_num--;
tid_agg_rx->reorder_buf[index] = NULL;
}
@@ -2082,11 +2100,8 @@
sizeof(status));
sband = local->hw.wiphy->bands[status.band];
rate = &sband->bitrates[status.rate_idx];
- pkt_load = ieee80211_rx_load_stats(local,
- tid_agg_rx->reorder_buf[index],
- &status, rate);
__ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index],
- &status, pkt_load, rate);
+ &status, rate);
tid_agg_rx->stored_mpdu_num--;
tid_agg_rx->reorder_buf[index] = NULL;
tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
@@ -2165,7 +2180,6 @@
struct ieee80211_rx_status *status)
{
struct ieee80211_local *local = hw_to_local(hw);
- u32 pkt_load;
struct ieee80211_rate *rate = NULL;
struct ieee80211_supported_band *sband;
@@ -2205,11 +2219,8 @@
return;
}
- pkt_load = ieee80211_rx_load_stats(local, skb, status, rate);
- local->channel_use_raw += pkt_load;
-
if (!ieee80211_rx_reorder_ampdu(local, skb))
- __ieee80211_rx_handle_packet(hw, skb, status, pkt_load, rate);
+ __ieee80211_rx_handle_packet(hw, skb, status, rate);
rcu_read_unlock();
}
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 7d4fe4a..c24770c 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -202,14 +202,12 @@
dev_kfree_skb_any(skb);
for (i = 0; i < STA_TID_NUM; i++) {
- spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
+ spin_lock_bh(&sta->lock);
if (sta->ampdu_mlme.tid_rx[i])
del_timer_sync(&sta->ampdu_mlme.tid_rx[i]->session_timer);
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
if (sta->ampdu_mlme.tid_tx[i])
del_timer_sync(&sta->ampdu_mlme.tid_tx[i]->addba_resp_timer);
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
}
__sta_info_free(local, sta);
@@ -236,6 +234,8 @@
if (!sta)
return NULL;
+ spin_lock_init(&sta->lock);
+
memcpy(sta->addr, addr, ETH_ALEN);
sta->local = local;
sta->sdata = sdata;
@@ -249,15 +249,13 @@
return NULL;
}
- spin_lock_init(&sta->ampdu_mlme.ampdu_rx);
- spin_lock_init(&sta->ampdu_mlme.ampdu_tx);
for (i = 0; i < STA_TID_NUM; i++) {
/* timer_to_tid must be initialized with identity mapping to
* enable session_timer's data differentiation. refer to
* sta_rx_agg_session_timer_expired for useage */
sta->timer_to_tid[i] = i;
/* tid to tx queue: initialize according to HW (0 is valid) */
- sta->tid_to_tx_q[i] = local->hw.queues;
+ sta->tid_to_tx_q[i] = ieee80211_num_queues(&local->hw);
/* rx */
sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE;
sta->ampdu_mlme.tid_rx[i] = NULL;
@@ -276,7 +274,6 @@
#ifdef CONFIG_MAC80211_MESH
sta->plink_state = PLINK_LISTEN;
- spin_lock_init(&sta->plink_lock);
init_timer(&sta->plink_timer);
#endif
@@ -437,8 +434,7 @@
list_del(&(*sta)->list);
- if ((*sta)->flags & WLAN_STA_PS) {
- (*sta)->flags &= ~WLAN_STA_PS;
+ if (test_and_clear_sta_flags(*sta, WLAN_STA_PS)) {
if (sdata->bss)
atomic_dec(&sdata->bss->num_sta_ps);
__sta_info_clear_tim_bit(sdata->bss, *sta);
@@ -515,20 +511,20 @@
struct sta_info *sta,
struct sk_buff *skb)
{
- struct ieee80211_tx_packet_data *pkt_data;
+ struct ieee80211_tx_info *info;
int timeout;
if (!skb)
return 0;
- pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+ info = IEEE80211_SKB_CB(skb);
/* Timeout: (2 * listen_interval * beacon_int * 1024 / 1000000) sec */
timeout = (sta->listen_interval * local->hw.conf.beacon_int * 32 /
15625) * HZ;
if (timeout < STA_TX_BUFFER_EXPIRE)
timeout = STA_TX_BUFFER_EXPIRE;
- return time_after(jiffies, pkt_data->jiffies + timeout);
+ return time_after(jiffies, info->control.jiffies + timeout);
}
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index f8c95bc..95753f8 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -32,7 +32,7 @@
* @WLAN_STA_WDS: Station is one of our WDS peers.
* @WLAN_STA_PSPOLL: Station has just PS-polled us.
* @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the
- * IEEE80211_TXCTL_CLEAR_PS_FILT control flag) when the next
+ * IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next
* frame to this station is transmitted.
*/
enum ieee80211_sta_info_flags {
@@ -129,23 +129,19 @@
*
* @tid_state_rx: TID's state in Rx session state machine.
* @tid_rx: aggregation info for Rx per TID
- * @ampdu_rx: for locking sections in aggregation Rx flow
* @tid_state_tx: TID's state in Tx session state machine.
* @tid_tx: aggregation info for Tx per TID
* @addba_req_num: number of times addBA request has been sent.
- * @ampdu_tx: for locking sectionsi in aggregation Tx flow
* @dialog_token_allocator: dialog token enumerator for each new session;
*/
struct sta_ampdu_mlme {
/* rx */
u8 tid_state_rx[STA_TID_NUM];
struct tid_ampdu_rx *tid_rx[STA_TID_NUM];
- spinlock_t ampdu_rx;
/* tx */
u8 tid_state_tx[STA_TID_NUM];
struct tid_ampdu_tx *tid_tx[STA_TID_NUM];
u8 addba_req_num[STA_TID_NUM];
- spinlock_t ampdu_tx;
u8 dialog_token_allocator;
};
@@ -177,6 +173,8 @@
* @rx_bytes: Number of bytes received from this STA
* @supp_rates: Bitmap of supported rates (per band)
* @ht_info: HT capabilities of this STA
+ * @lock: used for locking all fields that require locking, see comments
+ * in the header file.
*/
struct sta_info {
/* General information, mostly static */
@@ -187,6 +185,7 @@
struct ieee80211_key *key;
struct rate_control_ref *rate_ctrl;
void *rate_ctrl_priv;
+ spinlock_t lock;
struct ieee80211_ht_info ht_info;
u64 supp_rates[IEEE80211_NUM_BANDS];
u8 addr[ETH_ALEN];
@@ -199,7 +198,7 @@
*/
u8 pin_status;
- /* frequently updated information, needs locking? */
+ /* frequently updated information, locked with lock spinlock */
u32 flags;
/*
@@ -217,8 +216,8 @@
* from this STA */
unsigned long rx_fragments; /* number of received MPDUs */
unsigned long rx_dropped; /* number of dropped MPDUs from this STA */
- int last_rssi; /* RSSI of last received frame from this STA */
int last_signal; /* signal of last received frame from this STA */
+ int last_qual; /* qual of last received frame from this STA */
int last_noise; /* noise of last received frame from this STA */
/* last received seq/frag number from this STA (per RX queue) */
__le16 last_seq_ctrl[NUM_RX_DATA_QUEUES];
@@ -246,12 +245,8 @@
unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES];
#endif
- /* Debug counters, no locking doesn't matter */
- int channel_use;
- int channel_use_raw;
-
/*
- * Aggregation information, comes with own locking.
+ * Aggregation information, locked with lock.
*/
struct sta_ampdu_mlme ampdu_mlme;
u8 timer_to_tid[STA_TID_NUM]; /* identity mapping to ID timers */
@@ -270,9 +265,6 @@
enum plink_state plink_state;
u32 plink_timeout;
struct timer_list plink_timer;
- spinlock_t plink_lock; /* For peer_state reads / updates and other
- updates in the structure. Ensures robust
- transitions for the peerlink FSM */
#endif
#ifdef CONFIG_MAC80211_DEBUGFS
@@ -299,6 +291,64 @@
return PLINK_LISTEN;
}
+static inline void set_sta_flags(struct sta_info *sta, const u32 flags)
+{
+ spin_lock_bh(&sta->lock);
+ sta->flags |= flags;
+ spin_unlock_bh(&sta->lock);
+}
+
+static inline void clear_sta_flags(struct sta_info *sta, const u32 flags)
+{
+ spin_lock_bh(&sta->lock);
+ sta->flags &= ~flags;
+ spin_unlock_bh(&sta->lock);
+}
+
+static inline void set_and_clear_sta_flags(struct sta_info *sta,
+ const u32 set, const u32 clear)
+{
+ spin_lock_bh(&sta->lock);
+ sta->flags |= set;
+ sta->flags &= ~clear;
+ spin_unlock_bh(&sta->lock);
+}
+
+static inline u32 test_sta_flags(struct sta_info *sta, const u32 flags)
+{
+ u32 ret;
+
+ spin_lock_bh(&sta->lock);
+ ret = sta->flags & flags;
+ spin_unlock_bh(&sta->lock);
+
+ return ret;
+}
+
+static inline u32 test_and_clear_sta_flags(struct sta_info *sta,
+ const u32 flags)
+{
+ u32 ret;
+
+ spin_lock_bh(&sta->lock);
+ ret = sta->flags & flags;
+ sta->flags &= ~flags;
+ spin_unlock_bh(&sta->lock);
+
+ return ret;
+}
+
+static inline u32 get_sta_flags(struct sta_info *sta)
+{
+ u32 ret;
+
+ spin_lock_bh(&sta->lock);
+ ret = sta->flags;
+ spin_unlock_bh(&sta->lock);
+
+ return ret;
+}
+
/* Maximum number of concurrently registered stations */
#define MAX_STA_COUNT 2007
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c
index 09093da..a00cf1ea 100644
--- a/net/mac80211/tkip.c
+++ b/net/mac80211/tkip.c
@@ -6,25 +6,23 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-
#include <linux/kernel.h>
+#include <linux/bitops.h>
#include <linux/types.h>
#include <linux/netdevice.h>
+#include <asm/unaligned.h>
#include <net/mac80211.h>
#include "key.h"
#include "tkip.h"
#include "wep.h"
-
-/* TKIP key mixing functions */
-
-
#define PHASE1_LOOP_COUNT 8
-
-/* 2-byte by 2-byte subset of the full AES S-box table; second part of this
- * table is identical to first part but byte-swapped */
+/*
+ * 2-byte by 2-byte subset of the full AES S-box table; second part of this
+ * table is identical to first part but byte-swapped
+ */
static const u16 tkip_sbox[256] =
{
0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
@@ -61,84 +59,48 @@
0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
};
-
-static inline u16 Mk16(u8 x, u8 y)
+static u16 tkipS(u16 val)
{
- return ((u16) x << 8) | (u16) y;
+ return tkip_sbox[val & 0xff] ^ swab16(tkip_sbox[val >> 8]);
}
-
-static inline u8 Hi8(u16 v)
-{
- return v >> 8;
-}
-
-
-static inline u8 Lo8(u16 v)
-{
- return v & 0xff;
-}
-
-
-static inline u16 Hi16(u32 v)
-{
- return v >> 16;
-}
-
-
-static inline u16 Lo16(u32 v)
-{
- return v & 0xffff;
-}
-
-
-static inline u16 RotR1(u16 v)
-{
- return (v >> 1) | ((v & 0x0001) << 15);
-}
-
-
-static inline u16 tkip_S(u16 val)
-{
- u16 a = tkip_sbox[Hi8(val)];
-
- return tkip_sbox[Lo8(val)] ^ Hi8(a) ^ (Lo8(a) << 8);
-}
-
-
-
-/* P1K := Phase1(TA, TK, TSC)
+/*
+ * P1K := Phase1(TA, TK, TSC)
* TA = transmitter address (48 bits)
* TK = dot11DefaultKeyValue or dot11KeyMappingValue (128 bits)
* TSC = TKIP sequence counter (48 bits, only 32 msb bits used)
* P1K: 80 bits
*/
-static void tkip_mixing_phase1(const u8 *ta, const u8 *tk, u32 tsc_IV32,
- u16 *p1k)
+static void tkip_mixing_phase1(struct ieee80211_key *key, const u8 *ta,
+ struct tkip_ctx *ctx, u32 tsc_IV32)
{
int i, j;
+ const u8 *tk = &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY];
+ u16 *p1k = ctx->p1k;
- p1k[0] = Lo16(tsc_IV32);
- p1k[1] = Hi16(tsc_IV32);
- p1k[2] = Mk16(ta[1], ta[0]);
- p1k[3] = Mk16(ta[3], ta[2]);
- p1k[4] = Mk16(ta[5], ta[4]);
+ p1k[0] = tsc_IV32 & 0xFFFF;
+ p1k[1] = tsc_IV32 >> 16;
+ p1k[2] = get_unaligned_le16(ta + 0);
+ p1k[3] = get_unaligned_le16(ta + 2);
+ p1k[4] = get_unaligned_le16(ta + 4);
for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
j = 2 * (i & 1);
- p1k[0] += tkip_S(p1k[4] ^ Mk16(tk[ 1 + j], tk[ 0 + j]));
- p1k[1] += tkip_S(p1k[0] ^ Mk16(tk[ 5 + j], tk[ 4 + j]));
- p1k[2] += tkip_S(p1k[1] ^ Mk16(tk[ 9 + j], tk[ 8 + j]));
- p1k[3] += tkip_S(p1k[2] ^ Mk16(tk[13 + j], tk[12 + j]));
- p1k[4] += tkip_S(p1k[3] ^ Mk16(tk[ 1 + j], tk[ 0 + j])) + i;
+ p1k[0] += tkipS(p1k[4] ^ get_unaligned_le16(tk + 0 + j));
+ p1k[1] += tkipS(p1k[0] ^ get_unaligned_le16(tk + 4 + j));
+ p1k[2] += tkipS(p1k[1] ^ get_unaligned_le16(tk + 8 + j));
+ p1k[3] += tkipS(p1k[2] ^ get_unaligned_le16(tk + 12 + j));
+ p1k[4] += tkipS(p1k[3] ^ get_unaligned_le16(tk + 0 + j)) + i;
}
+ ctx->initialized = 1;
}
-
-static void tkip_mixing_phase2(const u16 *p1k, const u8 *tk, u16 tsc_IV16,
- u8 *rc4key)
+static void tkip_mixing_phase2(struct ieee80211_key *key, struct tkip_ctx *ctx,
+ u16 tsc_IV16, u8 *rc4key)
{
u16 ppk[6];
+ const u16 *p1k = ctx->p1k;
+ const u8 *tk = &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY];
int i;
ppk[0] = p1k[0];
@@ -148,70 +110,51 @@
ppk[4] = p1k[4];
ppk[5] = p1k[4] + tsc_IV16;
- ppk[0] += tkip_S(ppk[5] ^ Mk16(tk[ 1], tk[ 0]));
- ppk[1] += tkip_S(ppk[0] ^ Mk16(tk[ 3], tk[ 2]));
- ppk[2] += tkip_S(ppk[1] ^ Mk16(tk[ 5], tk[ 4]));
- ppk[3] += tkip_S(ppk[2] ^ Mk16(tk[ 7], tk[ 6]));
- ppk[4] += tkip_S(ppk[3] ^ Mk16(tk[ 9], tk[ 8]));
- ppk[5] += tkip_S(ppk[4] ^ Mk16(tk[11], tk[10]));
- ppk[0] += RotR1(ppk[5] ^ Mk16(tk[13], tk[12]));
- ppk[1] += RotR1(ppk[0] ^ Mk16(tk[15], tk[14]));
- ppk[2] += RotR1(ppk[1]);
- ppk[3] += RotR1(ppk[2]);
- ppk[4] += RotR1(ppk[3]);
- ppk[5] += RotR1(ppk[4]);
+ ppk[0] += tkipS(ppk[5] ^ get_unaligned_le16(tk + 0));
+ ppk[1] += tkipS(ppk[0] ^ get_unaligned_le16(tk + 2));
+ ppk[2] += tkipS(ppk[1] ^ get_unaligned_le16(tk + 4));
+ ppk[3] += tkipS(ppk[2] ^ get_unaligned_le16(tk + 6));
+ ppk[4] += tkipS(ppk[3] ^ get_unaligned_le16(tk + 8));
+ ppk[5] += tkipS(ppk[4] ^ get_unaligned_le16(tk + 10));
+ ppk[0] += ror16(ppk[5] ^ get_unaligned_le16(tk + 12), 1);
+ ppk[1] += ror16(ppk[0] ^ get_unaligned_le16(tk + 14), 1);
+ ppk[2] += ror16(ppk[1], 1);
+ ppk[3] += ror16(ppk[2], 1);
+ ppk[4] += ror16(ppk[3], 1);
+ ppk[5] += ror16(ppk[4], 1);
- rc4key[0] = Hi8(tsc_IV16);
- rc4key[1] = (Hi8(tsc_IV16) | 0x20) & 0x7f;
- rc4key[2] = Lo8(tsc_IV16);
- rc4key[3] = Lo8((ppk[5] ^ Mk16(tk[1], tk[0])) >> 1);
+ rc4key[0] = tsc_IV16 >> 8;
+ rc4key[1] = ((tsc_IV16 >> 8) | 0x20) & 0x7f;
+ rc4key[2] = tsc_IV16 & 0xFF;
+ rc4key[3] = ((ppk[5] ^ get_unaligned_le16(tk)) >> 1) & 0xFF;
- for (i = 0; i < 6; i++) {
- rc4key[4 + 2 * i] = Lo8(ppk[i]);
- rc4key[5 + 2 * i] = Hi8(ppk[i]);
- }
+ rc4key += 4;
+ for (i = 0; i < 6; i++)
+ put_unaligned_le16(ppk[i], rc4key + 2 * i);
}
-
/* Add TKIP IV and Ext. IV at @pos. @iv0, @iv1, and @iv2 are the first octets
* of the IV. Returns pointer to the octet following IVs (i.e., beginning of
* the packet payload). */
-u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key,
+u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key,
u8 iv0, u8 iv1, u8 iv2)
{
*pos++ = iv0;
*pos++ = iv1;
*pos++ = iv2;
*pos++ = (key->conf.keyidx << 6) | (1 << 5) /* Ext IV */;
- *pos++ = key->u.tkip.iv32 & 0xff;
- *pos++ = (key->u.tkip.iv32 >> 8) & 0xff;
- *pos++ = (key->u.tkip.iv32 >> 16) & 0xff;
- *pos++ = (key->u.tkip.iv32 >> 24) & 0xff;
- return pos;
+ put_unaligned_le32(key->u.tkip.tx.iv32, pos);
+ return pos + 4;
}
-
-void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta,
- u16 *phase1key)
-{
- tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
- key->u.tkip.iv32, phase1key);
-}
-
-void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta,
+static void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta,
u8 *rc4key)
{
/* Calculate per-packet key */
- if (key->u.tkip.iv16 == 0 || !key->u.tkip.tx_initialized) {
- /* IV16 wrapped around - perform TKIP phase 1 */
- tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
- key->u.tkip.iv32, key->u.tkip.p1k);
- key->u.tkip.tx_initialized = 1;
- }
+ if (key->u.tkip.tx.iv16 == 0 || !key->u.tkip.tx.initialized)
+ tkip_mixing_phase1(key, ta, &key->u.tkip.tx, key->u.tkip.tx.iv32);
- tkip_mixing_phase2(key->u.tkip.p1k,
- &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
- key->u.tkip.iv16, rc4key);
+ tkip_mixing_phase2(key, &key->u.tkip.tx, key->u.tkip.tx.iv16, rc4key);
}
void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
@@ -228,18 +171,16 @@
u16 iv16;
u32 iv32;
- iv16 = data[hdr_len] << 8;
- iv16 += data[hdr_len + 2];
- iv32 = data[hdr_len + 4] | (data[hdr_len + 5] << 8) |
- (data[hdr_len + 6] << 16) | (data[hdr_len + 7] << 24);
+ iv16 = data[hdr_len + 2] | (data[hdr_len] << 8);
+ iv32 = get_unaligned_le32(data + hdr_len + 4);
#ifdef CONFIG_TKIP_DEBUG
printk(KERN_DEBUG "TKIP encrypt: iv16 = 0x%04x, iv32 = 0x%08x\n",
iv16, iv32);
- if (iv32 != key->u.tkip.iv32) {
+ if (iv32 != key->u.tkip.tx.iv32) {
printk(KERN_DEBUG "skb: iv32 = 0x%08x key: iv32 = 0x%08x\n",
- iv32, key->u.tkip.iv32);
+ iv32, key->u.tkip.tx.iv32);
printk(KERN_DEBUG "Wrap around of iv16 in the middle of a "
"fragmented packet\n");
}
@@ -248,20 +189,15 @@
/* Update the p1k only when the iv16 in the packet wraps around, this
* might occur after the wrap around of iv16 in the key in case of
* fragmented packets. */
- if (iv16 == 0 || !key->u.tkip.tx_initialized) {
- /* IV16 wrapped around - perform TKIP phase 1 */
- tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
- iv32, key->u.tkip.p1k);
- key->u.tkip.tx_initialized = 1;
- }
+ if (iv16 == 0 || !key->u.tkip.tx.initialized)
+ tkip_mixing_phase1(key, ta, &key->u.tkip.tx, iv32);
if (type == IEEE80211_TKIP_P1_KEY) {
- memcpy(outkey, key->u.tkip.p1k, sizeof(u16) * 5);
+ memcpy(outkey, key->u.tkip.tx.p1k, sizeof(u16) * 5);
return;
}
- tkip_mixing_phase2(key->u.tkip.p1k,
- &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], iv16, outkey);
+ tkip_mixing_phase2(key, &key->u.tkip.tx, iv16, outkey);
}
EXPORT_SYMBOL(ieee80211_get_tkip_key);
@@ -281,7 +217,6 @@
ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len);
}
-
/* Decrypt packet payload with TKIP using @key. @pos is a pointer to the
* beginning of the buffer containing IEEE 802.11 header payload, i.e.,
* including IV, Ext. IV, real data, Michael MIC, ICV. @payload_len is the
@@ -302,7 +237,7 @@
iv16 = (pos[0] << 8) | pos[2];
keyid = pos[3];
- iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
+ iv32 = get_unaligned_le32(pos + 4);
pos += 8;
#ifdef CONFIG_TKIP_DEBUG
{
@@ -322,33 +257,31 @@
if ((keyid >> 6) != key->conf.keyidx)
return TKIP_DECRYPT_INVALID_KEYIDX;
- if (key->u.tkip.rx_initialized[queue] &&
- (iv32 < key->u.tkip.iv32_rx[queue] ||
- (iv32 == key->u.tkip.iv32_rx[queue] &&
- iv16 <= key->u.tkip.iv16_rx[queue]))) {
+ if (key->u.tkip.rx[queue].initialized &&
+ (iv32 < key->u.tkip.rx[queue].iv32 ||
+ (iv32 == key->u.tkip.rx[queue].iv32 &&
+ iv16 <= key->u.tkip.rx[queue].iv16))) {
#ifdef CONFIG_TKIP_DEBUG
DECLARE_MAC_BUF(mac);
printk(KERN_DEBUG "TKIP replay detected for RX frame from "
"%s (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n",
print_mac(mac, ta),
- iv32, iv16, key->u.tkip.iv32_rx[queue],
- key->u.tkip.iv16_rx[queue]);
+ iv32, iv16, key->u.tkip.rx[queue].iv32,
+ key->u.tkip.rx[queue].iv16);
#endif /* CONFIG_TKIP_DEBUG */
return TKIP_DECRYPT_REPLAY;
}
if (only_iv) {
res = TKIP_DECRYPT_OK;
- key->u.tkip.rx_initialized[queue] = 1;
+ key->u.tkip.rx[queue].initialized = 1;
goto done;
}
- if (!key->u.tkip.rx_initialized[queue] ||
- key->u.tkip.iv32_rx[queue] != iv32) {
- key->u.tkip.rx_initialized[queue] = 1;
+ if (!key->u.tkip.rx[queue].initialized ||
+ key->u.tkip.rx[queue].iv32 != iv32) {
/* IV16 wrapped around - perform TKIP phase 1 */
- tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
- iv32, key->u.tkip.p1k_rx[queue]);
+ tkip_mixing_phase1(key, ta, &key->u.tkip.rx[queue], iv32);
#ifdef CONFIG_TKIP_DEBUG
{
int i;
@@ -362,7 +295,7 @@
printk("\n");
printk(KERN_DEBUG "TKIP decrypt: P1K=");
for (i = 0; i < 5; i++)
- printk("%04x ", key->u.tkip.p1k_rx[queue][i]);
+ printk("%04x ", key->u.tkip.rx[queue].p1k[i]);
printk("\n");
}
#endif /* CONFIG_TKIP_DEBUG */
@@ -377,13 +310,11 @@
key->local->ops->update_tkip_key(
local_to_hw(key->local), &key->conf,
- sta_addr, iv32, key->u.tkip.p1k_rx[queue]);
+ sta_addr, iv32, key->u.tkip.rx[queue].p1k);
}
}
- tkip_mixing_phase2(key->u.tkip.p1k_rx[queue],
- &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
- iv16, rc4key);
+ tkip_mixing_phase2(key, &key->u.tkip.rx[queue], iv16, rc4key);
#ifdef CONFIG_TKIP_DEBUG
{
int i;
@@ -409,5 +340,3 @@
return res;
}
-
-
diff --git a/net/mac80211/tkip.h b/net/mac80211/tkip.h
index b7c2ee7..b890427 100644
--- a/net/mac80211/tkip.h
+++ b/net/mac80211/tkip.h
@@ -13,12 +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);
-void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta,
- u16 *phase1key);
-void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta,
- u8 *rc4key);
+u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key,
+ u8 iv0, u8 iv1, u8 iv2);
void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
struct ieee80211_key *key,
u8 *pos, size_t payload_len, u8 *ta);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 1d7dd54..1ad9e66 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -91,11 +91,12 @@
int next_frag_len)
{
int rate, mrate, erp, dur, i;
- struct ieee80211_rate *txrate = tx->rate;
+ struct ieee80211_rate *txrate;
struct ieee80211_local *local = tx->local;
struct ieee80211_supported_band *sband;
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ sband = local->hw.wiphy->bands[tx->channel->band];
+ txrate = &sband->bitrates[tx->rate_idx];
erp = 0;
if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
@@ -212,18 +213,6 @@
return dur;
}
-static inline int __ieee80211_queue_stopped(const struct ieee80211_local *local,
- int queue)
-{
- return test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]);
-}
-
-static inline int __ieee80211_queue_pending(const struct ieee80211_local *local,
- int queue)
-{
- return test_bit(IEEE80211_LINK_STATE_PENDING, &local->state[queue]);
-}
-
static int inline is_ieee80211_device(struct net_device *dev,
struct net_device *master)
{
@@ -237,12 +226,12 @@
ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
{
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- struct sk_buff *skb = tx->skb;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
u32 sta_flags;
- if (unlikely(tx->flags & IEEE80211_TX_INJECTED))
+ if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED))
return TX_CONTINUE;
if (unlikely(tx->local->sta_sw_scanning) &&
@@ -256,7 +245,7 @@
if (tx->flags & IEEE80211_TX_PS_BUFFERED)
return TX_CONTINUE;
- sta_flags = tx->sta ? tx->sta->flags : 0;
+ sta_flags = tx->sta ? get_sta_flags(tx->sta) : 0;
if (likely(tx->flags & IEEE80211_TX_UNICAST)) {
if (unlikely(!(sta_flags & WLAN_STA_ASSOC) &&
@@ -347,6 +336,8 @@
static ieee80211_tx_result
ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+
/*
* broadcast/multicast frame
*
@@ -382,7 +373,7 @@
}
/* buffered in hardware */
- tx->control->flags |= IEEE80211_TXCTL_SEND_AFTER_DTIM;
+ info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM;
return TX_CONTINUE;
}
@@ -391,6 +382,8 @@
ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
{
struct sta_info *sta = tx->sta;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+ u32 staflags;
DECLARE_MAC_BUF(mac);
if (unlikely(!sta ||
@@ -398,9 +391,10 @@
(tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)))
return TX_CONTINUE;
- if (unlikely((sta->flags & WLAN_STA_PS) &&
- !(sta->flags & WLAN_STA_PSPOLL))) {
- struct ieee80211_tx_packet_data *pkt_data;
+ staflags = get_sta_flags(sta);
+
+ if (unlikely((staflags & WLAN_STA_PS) &&
+ !(staflags & WLAN_STA_PSPOLL))) {
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries "
"before %d)\n",
@@ -424,19 +418,18 @@
if (skb_queue_empty(&sta->ps_tx_buf))
sta_info_set_tim_bit(sta);
- pkt_data = (struct ieee80211_tx_packet_data *)tx->skb->cb;
- pkt_data->jiffies = jiffies;
+ info->control.jiffies = jiffies;
skb_queue_tail(&sta->ps_tx_buf, tx->skb);
return TX_QUEUED;
}
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
- else if (unlikely(sta->flags & WLAN_STA_PS)) {
+ else if (unlikely(test_sta_flags(sta, WLAN_STA_PS))) {
printk(KERN_DEBUG "%s: STA %s in PS mode, but pspoll "
"set -> send frame\n", tx->dev->name,
print_mac(mac, sta->addr));
}
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
- sta->flags &= ~WLAN_STA_PSPOLL;
+ clear_sta_flags(sta, WLAN_STA_PSPOLL);
return TX_CONTINUE;
}
@@ -457,17 +450,18 @@
ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
{
struct ieee80211_key *key;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
u16 fc = tx->fc;
- if (unlikely(tx->control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
+ if (unlikely(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT))
tx->key = NULL;
else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
tx->key = key;
else if ((key = rcu_dereference(tx->sdata->default_key)))
tx->key = key;
else if (tx->sdata->drop_unencrypted &&
- !(tx->control->flags & IEEE80211_TXCTL_EAPOL_FRAME) &&
- !(tx->flags & IEEE80211_TX_INJECTED)) {
+ !(info->flags & IEEE80211_TX_CTL_EAPOL_FRAME) &&
+ !(info->flags & IEEE80211_TX_CTL_INJECTED)) {
I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
return TX_DROP;
} else
@@ -496,7 +490,156 @@
}
if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
- tx->control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
+ info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
+
+ return TX_CONTINUE;
+}
+
+static ieee80211_tx_result
+ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
+{
+ struct rate_selection rsel;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+
+ sband = tx->local->hw.wiphy->bands[tx->channel->band];
+
+ if (likely(tx->rate_idx < 0)) {
+ rate_control_get_rate(tx->dev, sband, tx->skb, &rsel);
+ tx->rate_idx = rsel.rate_idx;
+ if (unlikely(rsel.probe_idx >= 0)) {
+ info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+ tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
+ info->control.alt_retry_rate_idx = tx->rate_idx;
+ tx->rate_idx = rsel.probe_idx;
+ } else
+ info->control.alt_retry_rate_idx = -1;
+
+ if (unlikely(tx->rate_idx < 0))
+ return TX_DROP;
+ } else
+ info->control.alt_retry_rate_idx = -1;
+
+ if (tx->sdata->bss_conf.use_cts_prot &&
+ (tx->flags & IEEE80211_TX_FRAGMENTED) && (rsel.nonerp_idx >= 0)) {
+ tx->last_frag_rate_idx = tx->rate_idx;
+ if (rsel.probe_idx >= 0)
+ tx->flags &= ~IEEE80211_TX_PROBE_LAST_FRAG;
+ else
+ tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
+ tx->rate_idx = rsel.nonerp_idx;
+ info->tx_rate_idx = rsel.nonerp_idx;
+ info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+ } else {
+ tx->last_frag_rate_idx = tx->rate_idx;
+ info->tx_rate_idx = tx->rate_idx;
+ }
+ info->tx_rate_idx = tx->rate_idx;
+
+ return TX_CONTINUE;
+}
+
+static ieee80211_tx_result
+ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
+ u16 fc = le16_to_cpu(hdr->frame_control);
+ u16 dur;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+ struct ieee80211_supported_band *sband;
+
+ sband = tx->local->hw.wiphy->bands[tx->channel->band];
+
+ if (tx->sta)
+ info->control.aid = tx->sta->aid;
+
+ if (!info->control.retry_limit) {
+ if (!is_multicast_ether_addr(hdr->addr1)) {
+ int len = min_t(int, tx->skb->len + FCS_LEN,
+ tx->local->fragmentation_threshold);
+ if (len > tx->local->rts_threshold
+ && tx->local->rts_threshold <
+ IEEE80211_MAX_RTS_THRESHOLD) {
+ info->flags |= IEEE80211_TX_CTL_USE_RTS_CTS;
+ info->flags |=
+ IEEE80211_TX_CTL_LONG_RETRY_LIMIT;
+ info->control.retry_limit =
+ tx->local->long_retry_limit;
+ } else {
+ info->control.retry_limit =
+ tx->local->short_retry_limit;
+ }
+ } else {
+ info->control.retry_limit = 1;
+ }
+ }
+
+ if (tx->flags & IEEE80211_TX_FRAGMENTED) {
+ /* Do not use multiple retry rates when sending fragmented
+ * frames.
+ * TODO: The last fragment could still use multiple retry
+ * rates. */
+ info->control.alt_retry_rate_idx = -1;
+ }
+
+ /* Use CTS protection for unicast frames sent using extended rates if
+ * there are associated non-ERP stations and RTS/CTS is not configured
+ * for the frame. */
+ if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) &&
+ (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_ERP_G) &&
+ (tx->flags & IEEE80211_TX_UNICAST) &&
+ tx->sdata->bss_conf.use_cts_prot &&
+ !(info->flags & IEEE80211_TX_CTL_USE_RTS_CTS))
+ info->flags |= IEEE80211_TX_CTL_USE_CTS_PROTECT;
+
+ /* Transmit data frames using short preambles if the driver supports
+ * short preambles at the selected rate and short preambles are
+ * available on the network at the current point in time. */
+ if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
+ (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
+ tx->sdata->bss_conf.use_short_preamble &&
+ (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) {
+ info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
+ }
+
+ /* Setup duration field for the first fragment of the frame. Duration
+ * for remaining fragments will be updated when they are being sent
+ * to low-level driver in ieee80211_tx(). */
+ dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1),
+ (tx->flags & IEEE80211_TX_FRAGMENTED) ?
+ tx->extra_frag[0]->len : 0);
+ hdr->duration_id = cpu_to_le16(dur);
+
+ if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
+ (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
+ struct ieee80211_rate *rate;
+ s8 baserate = -1;
+ int idx;
+
+ /* Do not use multiple retry rates when using RTS/CTS */
+ info->control.alt_retry_rate_idx = -1;
+
+ /* Use min(data rate, max base rate) as CTS/RTS rate */
+ rate = &sband->bitrates[tx->rate_idx];
+
+ for (idx = 0; idx < sband->n_bitrates; idx++) {
+ if (sband->bitrates[idx].bitrate > rate->bitrate)
+ continue;
+ if (tx->sdata->basic_rates & BIT(idx) &&
+ (baserate < 0 ||
+ (sband->bitrates[baserate].bitrate
+ < sband->bitrates[idx].bitrate)))
+ baserate = idx;
+ }
+
+ if (baserate >= 0)
+ info->control.rts_cts_rate_idx = baserate;
+ else
+ info->control.rts_cts_rate_idx = 0;
+ }
+
+ if (tx->sta)
+ info->control.aid = tx->sta->aid;
return TX_CONTINUE;
}
@@ -515,6 +658,17 @@
if (!(tx->flags & IEEE80211_TX_FRAGMENTED))
return TX_CONTINUE;
+ /*
+ * Warn when submitting a fragmented A-MPDU frame and drop it.
+ * This is an error and needs to be fixed elsewhere, but when
+ * done needs to take care of monitor interfaces (injection)
+ * etc.
+ */
+ if (WARN_ON(tx->flags & IEEE80211_TX_CTL_AMPDU ||
+ skb_get_queue_mapping(tx->skb) >=
+ ieee80211_num_regular_queues(&tx->local->hw)))
+ return TX_DROP;
+
first = tx->skb;
hdrlen = ieee80211_get_hdrlen(tx->fc);
@@ -602,215 +756,22 @@
}
static ieee80211_tx_result
-ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
+ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
{
- struct rate_selection rsel;
- struct ieee80211_supported_band *sband;
+ int i;
- sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band];
+ if (!tx->sta)
+ return TX_CONTINUE;
- if (likely(!tx->rate)) {
- rate_control_get_rate(tx->dev, sband, tx->skb, &rsel);
- tx->rate = rsel.rate;
- if (unlikely(rsel.probe)) {
- tx->control->flags |=
- IEEE80211_TXCTL_RATE_CTRL_PROBE;
- tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
- tx->control->alt_retry_rate = tx->rate;
- tx->rate = rsel.probe;
- } else
- tx->control->alt_retry_rate = NULL;
-
- if (!tx->rate)
- return TX_DROP;
- } else
- tx->control->alt_retry_rate = NULL;
-
- if (tx->sdata->bss_conf.use_cts_prot &&
- (tx->flags & IEEE80211_TX_FRAGMENTED) && rsel.nonerp) {
- tx->last_frag_rate = tx->rate;
- if (rsel.probe)
- tx->flags &= ~IEEE80211_TX_PROBE_LAST_FRAG;
- else
- tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
- tx->rate = rsel.nonerp;
- tx->control->tx_rate = rsel.nonerp;
- tx->control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE;
- } else {
- tx->last_frag_rate = tx->rate;
- tx->control->tx_rate = tx->rate;
- }
- tx->control->tx_rate = tx->rate;
-
- return TX_CONTINUE;
-}
-
-static ieee80211_tx_result
-ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
-{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
- u16 fc = le16_to_cpu(hdr->frame_control);
- u16 dur;
- struct ieee80211_tx_control *control = tx->control;
-
- if (!control->retry_limit) {
- if (!is_multicast_ether_addr(hdr->addr1)) {
- if (tx->skb->len + FCS_LEN > tx->local->rts_threshold
- && tx->local->rts_threshold <
- IEEE80211_MAX_RTS_THRESHOLD) {
- control->flags |=
- IEEE80211_TXCTL_USE_RTS_CTS;
- control->flags |=
- IEEE80211_TXCTL_LONG_RETRY_LIMIT;
- control->retry_limit =
- tx->local->long_retry_limit;
- } else {
- control->retry_limit =
- tx->local->short_retry_limit;
- }
- } else {
- control->retry_limit = 1;
- }
- }
-
- if (tx->flags & IEEE80211_TX_FRAGMENTED) {
- /* Do not use multiple retry rates when sending fragmented
- * frames.
- * TODO: The last fragment could still use multiple retry
- * rates. */
- control->alt_retry_rate = NULL;
- }
-
- /* Use CTS protection for unicast frames sent using extended rates if
- * there are associated non-ERP stations and RTS/CTS is not configured
- * for the frame. */
- if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) &&
- (tx->rate->flags & IEEE80211_RATE_ERP_G) &&
- (tx->flags & IEEE80211_TX_UNICAST) &&
- tx->sdata->bss_conf.use_cts_prot &&
- !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS))
- control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT;
-
- /* Transmit data frames using short preambles if the driver supports
- * short preambles at the selected rate and short preambles are
- * available on the network at the current point in time. */
- if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
- (tx->rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
- tx->sdata->bss_conf.use_short_preamble &&
- (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) {
- tx->control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
- }
-
- /* Setup duration field for the first fragment of the frame. Duration
- * for remaining fragments will be updated when they are being sent
- * to low-level driver in ieee80211_tx(). */
- dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1),
- (tx->flags & IEEE80211_TX_FRAGMENTED) ?
- tx->extra_frag[0]->len : 0);
- hdr->duration_id = cpu_to_le16(dur);
-
- if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
- (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
- struct ieee80211_supported_band *sband;
- struct ieee80211_rate *rate, *baserate;
- int idx;
-
- sband = tx->local->hw.wiphy->bands[
- tx->local->hw.conf.channel->band];
-
- /* Do not use multiple retry rates when using RTS/CTS */
- control->alt_retry_rate = NULL;
-
- /* Use min(data rate, max base rate) as CTS/RTS rate */
- rate = tx->rate;
- baserate = NULL;
-
- for (idx = 0; idx < sband->n_bitrates; idx++) {
- if (sband->bitrates[idx].bitrate > rate->bitrate)
- continue;
- if (tx->sdata->basic_rates & BIT(idx) &&
- (!baserate ||
- (baserate->bitrate < sband->bitrates[idx].bitrate)))
- baserate = &sband->bitrates[idx];
- }
-
- if (baserate)
- control->rts_cts_rate = baserate;
- else
- control->rts_cts_rate = &sband->bitrates[0];
- }
-
- if (tx->sta) {
- control->aid = tx->sta->aid;
- tx->sta->tx_packets++;
- tx->sta->tx_fragments++;
- tx->sta->tx_bytes += tx->skb->len;
- if (tx->extra_frag) {
- int i;
- tx->sta->tx_fragments += tx->num_extra_frag;
- for (i = 0; i < tx->num_extra_frag; i++) {
- tx->sta->tx_bytes +=
- tx->extra_frag[i]->len;
- }
- }
- }
-
- return TX_CONTINUE;
-}
-
-static ieee80211_tx_result
-ieee80211_tx_h_load_stats(struct ieee80211_tx_data *tx)
-{
- struct ieee80211_local *local = tx->local;
- struct sk_buff *skb = tx->skb;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- u32 load = 0, hdrtime;
- struct ieee80211_rate *rate = tx->rate;
-
- /* TODO: this could be part of tx_status handling, so that the number
- * of retries would be known; TX rate should in that case be stored
- * somewhere with the packet */
-
- /* Estimate total channel use caused by this frame */
-
- /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
- * 1 usec = 1/8 * (1080 / 10) = 13.5 */
-
- if (tx->channel->band == IEEE80211_BAND_5GHZ ||
- (tx->channel->band == IEEE80211_BAND_2GHZ &&
- rate->flags & IEEE80211_RATE_ERP_G))
- hdrtime = CHAN_UTIL_HDR_SHORT;
- else
- hdrtime = CHAN_UTIL_HDR_LONG;
-
- load = hdrtime;
- if (!is_multicast_ether_addr(hdr->addr1))
- load += hdrtime;
-
- if (tx->control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
- load += 2 * hdrtime;
- else if (tx->control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
- load += hdrtime;
-
- /* TODO: optimise again */
- load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate;
-
+ tx->sta->tx_packets++;
+ tx->sta->tx_fragments++;
+ tx->sta->tx_bytes += tx->skb->len;
if (tx->extra_frag) {
- int i;
- for (i = 0; i < tx->num_extra_frag; i++) {
- load += 2 * hdrtime;
- load += tx->extra_frag[i]->len *
- tx->rate->bitrate;
- }
+ tx->sta->tx_fragments += tx->num_extra_frag;
+ for (i = 0; i < tx->num_extra_frag; i++)
+ tx->sta->tx_bytes += tx->extra_frag[i]->len;
}
- /* Divide channel_use by 8 to avoid wrapping around the counter */
- load >>= CHAN_UTIL_SHIFT;
- local->channel_use_raw += load;
- if (tx->sta)
- tx->sta->channel_use_raw += load;
- tx->sdata->channel_use_raw += load;
-
return TX_CONTINUE;
}
@@ -823,11 +784,12 @@
ieee80211_tx_h_ps_buf,
ieee80211_tx_h_select_key,
ieee80211_tx_h_michael_mic_add,
- ieee80211_tx_h_fragment,
- ieee80211_tx_h_encrypt,
ieee80211_tx_h_rate_ctrl,
ieee80211_tx_h_misc,
- ieee80211_tx_h_load_stats,
+ ieee80211_tx_h_fragment,
+ /* handlers after fragment must be aware of tx info fragmentation! */
+ ieee80211_tx_h_encrypt,
+ ieee80211_tx_h_stats,
NULL
};
@@ -854,12 +816,12 @@
(struct ieee80211_radiotap_header *) skb->data;
struct ieee80211_supported_band *sband;
int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len);
- struct ieee80211_tx_control *control = tx->control;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band];
+ sband = tx->local->hw.wiphy->bands[tx->channel->band];
- control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
- tx->flags |= IEEE80211_TX_INJECTED;
+ info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
+ info->flags |= IEEE80211_TX_CTL_INJECTED;
tx->flags &= ~IEEE80211_TX_FRAGMENTED;
/*
@@ -896,7 +858,7 @@
r = &sband->bitrates[i];
if (r->bitrate == target_rate) {
- tx->rate = r;
+ tx->rate_idx = i;
break;
}
}
@@ -907,7 +869,7 @@
* radiotap uses 0 for 1st ant, mac80211 is 1 for
* 1st ant
*/
- control->antenna_sel_tx = (*iterator.this_arg) + 1;
+ info->antenna_sel_tx = (*iterator.this_arg) + 1;
break;
#if 0
@@ -931,8 +893,8 @@
skb_trim(skb, skb->len - FCS_LEN);
}
if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP)
- control->flags &=
- ~IEEE80211_TXCTL_DO_NOT_ENCRYPT;
+ info->flags &=
+ ~IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG)
tx->flags |= IEEE80211_TX_FRAGMENTED;
break;
@@ -967,12 +929,12 @@
static ieee80211_tx_result
__ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
struct sk_buff *skb,
- struct net_device *dev,
- struct ieee80211_tx_control *control)
+ struct net_device *dev)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_hdr *hdr;
struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int hdrlen;
@@ -981,7 +943,9 @@
tx->dev = dev; /* use original interface */
tx->local = local;
tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- tx->control = control;
+ tx->channel = local->hw.conf.channel;
+ tx->rate_idx = -1;
+ tx->last_frag_rate_idx = -1;
/*
* Set this flag (used below to indicate "automatic fragmentation"),
* it will be cleared/left by radiotap as desired.
@@ -1008,10 +972,10 @@
if (is_multicast_ether_addr(hdr->addr1)) {
tx->flags &= ~IEEE80211_TX_UNICAST;
- control->flags |= IEEE80211_TXCTL_NO_ACK;
+ info->flags |= IEEE80211_TX_CTL_NO_ACK;
} else {
tx->flags |= IEEE80211_TX_UNICAST;
- control->flags &= ~IEEE80211_TXCTL_NO_ACK;
+ info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
}
if (tx->flags & IEEE80211_TX_FRAGMENTED) {
@@ -1024,18 +988,16 @@
}
if (!tx->sta)
- control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT;
- else if (tx->sta->flags & WLAN_STA_CLEAR_PS_FILT) {
- control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT;
- tx->sta->flags &= ~WLAN_STA_CLEAR_PS_FILT;
- }
+ info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
+ else if (test_and_clear_sta_flags(tx->sta, WLAN_STA_CLEAR_PS_FILT))
+ info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
hdrlen = ieee80211_get_hdrlen(tx->fc);
if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) {
u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)];
tx->ethertype = (pos[0] << 8) | pos[1];
}
- control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT;
+ info->flags |= IEEE80211_TX_CTL_FIRST_FRAGMENT;
return TX_CONTINUE;
}
@@ -1045,14 +1007,12 @@
*/
static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
struct sk_buff *skb,
- struct net_device *mdev,
- struct ieee80211_tx_control *control)
+ struct net_device *mdev)
{
- struct ieee80211_tx_packet_data *pkt_data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct net_device *dev;
- pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
- dev = dev_get_by_index(&init_net, pkt_data->ifindex);
+ dev = dev_get_by_index(&init_net, info->control.ifindex);
if (unlikely(dev && !is_ieee80211_device(dev, mdev))) {
dev_put(dev);
dev = NULL;
@@ -1060,7 +1020,7 @@
if (unlikely(!dev))
return -ENODEV;
/* initialises tx with control */
- __ieee80211_tx_prepare(tx, skb, dev, control);
+ __ieee80211_tx_prepare(tx, skb, dev);
dev_put(dev);
return 0;
}
@@ -1068,50 +1028,49 @@
static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
struct ieee80211_tx_data *tx)
{
- struct ieee80211_tx_control *control = tx->control;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int ret, i;
- if (!ieee80211_qdisc_installed(local->mdev) &&
- __ieee80211_queue_stopped(local, 0)) {
- netif_stop_queue(local->mdev);
+ if (netif_subqueue_stopped(local->mdev, skb))
return IEEE80211_TX_AGAIN;
- }
+
if (skb) {
ieee80211_dump_frame(wiphy_name(local->hw.wiphy),
"TX to low-level driver", skb);
- ret = local->ops->tx(local_to_hw(local), skb, control);
+ ret = local->ops->tx(local_to_hw(local), skb);
if (ret)
return IEEE80211_TX_AGAIN;
local->mdev->trans_start = jiffies;
ieee80211_led_tx(local, 1);
}
if (tx->extra_frag) {
- control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS |
- IEEE80211_TXCTL_USE_CTS_PROTECT |
- IEEE80211_TXCTL_CLEAR_PS_FILT |
- IEEE80211_TXCTL_FIRST_FRAGMENT);
for (i = 0; i < tx->num_extra_frag; i++) {
if (!tx->extra_frag[i])
continue;
- if (__ieee80211_queue_stopped(local, control->queue))
+ info = IEEE80211_SKB_CB(tx->extra_frag[i]);
+ info->flags &= ~(IEEE80211_TX_CTL_USE_RTS_CTS |
+ IEEE80211_TX_CTL_USE_CTS_PROTECT |
+ IEEE80211_TX_CTL_CLEAR_PS_FILT |
+ IEEE80211_TX_CTL_FIRST_FRAGMENT);
+ if (netif_subqueue_stopped(local->mdev,
+ tx->extra_frag[i]))
return IEEE80211_TX_FRAG_AGAIN;
if (i == tx->num_extra_frag) {
- control->tx_rate = tx->last_frag_rate;
+ info->tx_rate_idx = tx->last_frag_rate_idx;
if (tx->flags & IEEE80211_TX_PROBE_LAST_FRAG)
- control->flags |=
- IEEE80211_TXCTL_RATE_CTRL_PROBE;
+ info->flags |=
+ IEEE80211_TX_CTL_RATE_CTRL_PROBE;
else
- control->flags &=
- ~IEEE80211_TXCTL_RATE_CTRL_PROBE;
+ info->flags &=
+ ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
}
ieee80211_dump_frame(wiphy_name(local->hw.wiphy),
"TX to low-level driver",
tx->extra_frag[i]);
ret = local->ops->tx(local_to_hw(local),
- tx->extra_frag[i],
- control);
+ tx->extra_frag[i]);
if (ret)
return IEEE80211_TX_FRAG_AGAIN;
local->mdev->trans_start = jiffies;
@@ -1124,17 +1083,20 @@
return IEEE80211_TX_OK;
}
-static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
ieee80211_tx_handler *handler;
struct ieee80211_tx_data tx;
ieee80211_tx_result res = TX_DROP, res_prepare;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int ret, i;
+ u16 queue;
- WARN_ON(__ieee80211_queue_pending(local, control->queue));
+ queue = skb_get_queue_mapping(skb);
+
+ WARN_ON(test_bit(queue, local->queues_pending));
if (unlikely(skb->len < 10)) {
dev_kfree_skb(skb);
@@ -1144,7 +1106,7 @@
rcu_read_lock();
/* initialises tx */
- res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control);
+ res_prepare = __ieee80211_tx_prepare(&tx, skb, dev);
if (res_prepare == TX_DROP) {
dev_kfree_skb(skb);
@@ -1154,6 +1116,7 @@
sta = tx.sta;
tx.channel = local->hw.conf.channel;
+ info->band = tx.channel->band;
for (handler = ieee80211_tx_handlers; *handler != NULL;
handler++) {
@@ -1162,7 +1125,8 @@
break;
}
- skb = tx.skb; /* handlers are allowed to change skb */
+ if (WARN_ON(tx.skb != skb))
+ goto drop;
if (unlikely(res == TX_DROP)) {
I802_DEBUG_INC(local->tx_handlers_drop);
@@ -1186,7 +1150,7 @@
next_len = tx.extra_frag[i + 1]->len;
} else {
next_len = 0;
- tx.rate = tx.last_frag_rate;
+ tx.rate_idx = tx.last_frag_rate_idx;
}
dur = ieee80211_duration(&tx, 0, next_len);
hdr->duration_id = cpu_to_le16(dur);
@@ -1196,34 +1160,41 @@
retry:
ret = __ieee80211_tx(local, skb, &tx);
if (ret) {
- struct ieee80211_tx_stored_packet *store =
- &local->pending_packet[control->queue];
+ struct ieee80211_tx_stored_packet *store;
+
+ /*
+ * Since there are no fragmented frames on A-MPDU
+ * queues, there's no reason for a driver to reject
+ * a frame there, warn and drop it.
+ */
+ if (WARN_ON(queue >= ieee80211_num_regular_queues(&local->hw)))
+ goto drop;
+
+ store = &local->pending_packet[queue];
if (ret == IEEE80211_TX_FRAG_AGAIN)
skb = NULL;
- set_bit(IEEE80211_LINK_STATE_PENDING,
- &local->state[control->queue]);
+ set_bit(queue, local->queues_pending);
smp_mb();
- /* When the driver gets out of buffers during sending of
- * fragments and calls ieee80211_stop_queue, there is
- * a small window between IEEE80211_LINK_STATE_XOFF and
- * IEEE80211_LINK_STATE_PENDING flags are set. If a buffer
+ /*
+ * When the driver gets out of buffers during sending of
+ * fragments and calls ieee80211_stop_queue, the netif
+ * subqueue is stopped. There is, however, a small window
+ * in which the PENDING bit is not yet set. If a buffer
* gets available in that window (i.e. driver calls
* ieee80211_wake_queue), we would end up with ieee80211_tx
- * called with IEEE80211_LINK_STATE_PENDING. Prevent this by
+ * called with the PENDING bit still set. Prevent this by
* continuing transmitting here when that situation is
- * possible to have happened. */
- if (!__ieee80211_queue_stopped(local, control->queue)) {
- clear_bit(IEEE80211_LINK_STATE_PENDING,
- &local->state[control->queue]);
+ * possible to have happened.
+ */
+ if (!__netif_subqueue_stopped(local->mdev, queue)) {
+ clear_bit(queue, local->queues_pending);
goto retry;
}
- memcpy(&store->control, control,
- sizeof(struct ieee80211_tx_control));
store->skb = skb;
store->extra_frag = tx.extra_frag;
store->num_extra_frag = tx.num_extra_frag;
- store->last_frag_rate = tx.last_frag_rate;
+ store->last_frag_rate_idx = tx.last_frag_rate_idx;
store->last_frag_rate_ctrl_probe =
!!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG);
}
@@ -1243,24 +1214,57 @@
/* device xmit handlers */
+static int ieee80211_skb_resize(struct ieee80211_local *local,
+ struct sk_buff *skb,
+ int head_need, bool may_encrypt)
+{
+ int tail_need = 0;
+
+ /*
+ * This could be optimised, devices that do full hardware
+ * crypto (including TKIP MMIC) need no tailroom... But we
+ * have no drivers for such devices currently.
+ */
+ if (may_encrypt) {
+ tail_need = IEEE80211_ENCRYPT_TAILROOM;
+ tail_need -= skb_tailroom(skb);
+ tail_need = max_t(int, tail_need, 0);
+ }
+
+ if (head_need || tail_need) {
+ /* Sorry. Can't account for this any more */
+ skb_orphan(skb);
+ }
+
+ if (skb_header_cloned(skb))
+ I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
+ else
+ I802_DEBUG_INC(local->tx_expand_skb_head);
+
+ if (pskb_expand_head(skb, head_need, tail_need, GFP_ATOMIC)) {
+ printk(KERN_DEBUG "%s: failed to reallocate TX buffer\n",
+ wiphy_name(local->hw.wiphy));
+ return -ENOMEM;
+ }
+
+ /* update truesize too */
+ skb->truesize += head_need + tail_need;
+
+ return 0;
+}
+
int ieee80211_master_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
- struct ieee80211_tx_control control;
- struct ieee80211_tx_packet_data *pkt_data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct net_device *odev = NULL;
struct ieee80211_sub_if_data *osdata;
int headroom;
+ bool may_encrypt;
int ret;
- /*
- * copy control out of the skb so other people can use skb->cb
- */
- pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
- memset(&control, 0, sizeof(struct ieee80211_tx_control));
-
- if (pkt_data->ifindex)
- odev = dev_get_by_index(&init_net, pkt_data->ifindex);
+ if (info->control.ifindex)
+ odev = dev_get_by_index(&init_net, info->control.ifindex);
if (unlikely(odev && !is_ieee80211_device(odev, dev))) {
dev_put(odev);
odev = NULL;
@@ -1273,32 +1277,25 @@
dev_kfree_skb(skb);
return 0;
}
+
osdata = IEEE80211_DEV_TO_SUB_IF(odev);
- headroom = osdata->local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM;
- if (skb_headroom(skb) < headroom) {
- if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) {
- dev_kfree_skb(skb);
- dev_put(odev);
- return 0;
- }
+ may_encrypt = !(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT);
+
+ headroom = osdata->local->tx_headroom;
+ if (may_encrypt)
+ headroom += IEEE80211_ENCRYPT_HEADROOM;
+ headroom -= skb_headroom(skb);
+ headroom = max_t(int, 0, headroom);
+
+ if (ieee80211_skb_resize(osdata->local, skb, headroom, may_encrypt)) {
+ dev_kfree_skb(skb);
+ dev_put(odev);
+ return 0;
}
- control.vif = &osdata->vif;
- control.type = osdata->vif.type;
- if (pkt_data->flags & IEEE80211_TXPD_REQ_TX_STATUS)
- control.flags |= IEEE80211_TXCTL_REQ_TX_STATUS;
- if (pkt_data->flags & IEEE80211_TXPD_DO_NOT_ENCRYPT)
- control.flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
- if (pkt_data->flags & IEEE80211_TXPD_REQUEUE)
- control.flags |= IEEE80211_TXCTL_REQUEUE;
- if (pkt_data->flags & IEEE80211_TXPD_EAPOL_FRAME)
- control.flags |= IEEE80211_TXCTL_EAPOL_FRAME;
- if (pkt_data->flags & IEEE80211_TXPD_AMPDU)
- control.flags |= IEEE80211_TXCTL_AMPDU;
- control.queue = pkt_data->queue;
-
- ret = ieee80211_tx(odev, skb, &control);
+ info->control.vif = &osdata->vif;
+ ret = ieee80211_tx(odev, skb);
dev_put(odev);
return ret;
@@ -1308,7 +1305,7 @@
struct net_device *dev)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_tx_packet_data *pkt_data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_radiotap_header *prthdr =
(struct ieee80211_radiotap_header *)skb->data;
u16 len_rthdr;
@@ -1330,12 +1327,12 @@
skb->dev = local->mdev;
- pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
- memset(pkt_data, 0, sizeof(*pkt_data));
/* needed because we set skb device to master */
- pkt_data->ifindex = dev->ifindex;
+ info->control.ifindex = dev->ifindex;
- pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
+ info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
+ /* Interfaces should always request a status report */
+ info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
/*
* fix up the pointers accounting for the radiotap
@@ -1379,7 +1376,7 @@
struct net_device *dev)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_tx_packet_data *pkt_data;
+ struct ieee80211_tx_info *info;
struct ieee80211_sub_if_data *sdata;
int ret = 1, head_need;
u16 ethertype, hdrlen, meshhdrlen = 0, fc;
@@ -1486,12 +1483,13 @@
rcu_read_lock();
sta = sta_info_get(local, hdr.addr1);
if (sta)
- sta_flags = sta->flags;
+ sta_flags = get_sta_flags(sta);
rcu_read_unlock();
}
- /* receiver is QoS enabled, use a QoS type frame */
- if (sta_flags & WLAN_STA_WME) {
+ /* receiver and we are QoS enabled, use a QoS type frame */
+ if (sta_flags & WLAN_STA_WME &&
+ ieee80211_num_regular_queues(&local->hw) >= 4) {
fc |= IEEE80211_STYPE_QOS_DATA;
hdrlen += 2;
}
@@ -1555,32 +1553,26 @@
* build in headroom in __dev_alloc_skb() (linux/skbuff.h) and
* alloc_skb() (net/core/skbuff.c)
*/
- head_need = hdrlen + encaps_len + meshhdrlen + local->tx_headroom;
- head_need -= skb_headroom(skb);
+ head_need = hdrlen + encaps_len + meshhdrlen - skb_headroom(skb);
- /* We are going to modify skb data, so make a copy of it if happens to
- * be cloned. This could happen, e.g., with Linux bridge code passing
- * us broadcast frames. */
+ /*
+ * So we need to modify the skb header and hence need a copy of
+ * that. The head_need variable above doesn't, so far, include
+ * the needed header space that we don't need right away. If we
+ * can, then we don't reallocate right now but only after the
+ * frame arrives at the master device (if it does...)
+ *
+ * If we cannot, however, then we will reallocate to include all
+ * the ever needed space. Also, if we need to reallocate it anyway,
+ * make it big enough for everything we may ever need.
+ */
if (head_need > 0 || skb_header_cloned(skb)) {
-#if 0
- printk(KERN_DEBUG "%s: need to reallocate buffer for %d bytes "
- "of headroom\n", dev->name, head_need);
-#endif
-
- if (skb_header_cloned(skb))
- I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
- else
- I802_DEBUG_INC(local->tx_expand_skb_head);
- /* Since we have to reallocate the buffer, make sure that there
- * is enough room for possible WEP IV/ICV and TKIP (8 bytes
- * before payload and 12 after). */
- if (pskb_expand_head(skb, (head_need > 0 ? head_need + 8 : 8),
- 12, GFP_ATOMIC)) {
- printk(KERN_DEBUG "%s: failed to reallocate TX buffer"
- "\n", dev->name);
+ head_need += IEEE80211_ENCRYPT_HEADROOM;
+ head_need += local->tx_headroom;
+ head_need = max_t(int, 0, head_need);
+ if (ieee80211_skb_resize(local, skb, head_need, true))
goto fail;
- }
}
if (encaps_data) {
@@ -1611,11 +1603,14 @@
nh_pos += hdrlen;
h_pos += hdrlen;
- pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
- memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
- pkt_data->ifindex = dev->ifindex;
+ info = IEEE80211_SKB_CB(skb);
+ memset(info, 0, sizeof(*info));
+ info->control.ifindex = dev->ifindex;
if (ethertype == ETH_P_PAE)
- pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME;
+ info->flags |= IEEE80211_TX_CTL_EAPOL_FRAME;
+
+ /* Interfaces should always request a status report */
+ info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
skb->dev = local->mdev;
dev->stats.tx_packets++;
@@ -1640,46 +1635,55 @@
return ret;
}
-/* helper functions for pending packets for when queues are stopped */
+/*
+ * ieee80211_clear_tx_pending may not be called in a context where
+ * it is possible that it packets could come in again.
+ */
void ieee80211_clear_tx_pending(struct ieee80211_local *local)
{
int i, j;
struct ieee80211_tx_stored_packet *store;
- for (i = 0; i < local->hw.queues; i++) {
- if (!__ieee80211_queue_pending(local, i))
+ for (i = 0; i < ieee80211_num_regular_queues(&local->hw); i++) {
+ if (!test_bit(i, local->queues_pending))
continue;
store = &local->pending_packet[i];
kfree_skb(store->skb);
for (j = 0; j < store->num_extra_frag; j++)
kfree_skb(store->extra_frag[j]);
kfree(store->extra_frag);
- clear_bit(IEEE80211_LINK_STATE_PENDING, &local->state[i]);
+ clear_bit(i, local->queues_pending);
}
}
+/*
+ * Transmit all pending packets. Called from tasklet, locks master device
+ * TX lock so that no new packets can come in.
+ */
void ieee80211_tx_pending(unsigned long data)
{
struct ieee80211_local *local = (struct ieee80211_local *)data;
struct net_device *dev = local->mdev;
struct ieee80211_tx_stored_packet *store;
struct ieee80211_tx_data tx;
- int i, ret, reschedule = 0;
+ int i, ret;
netif_tx_lock_bh(dev);
- for (i = 0; i < local->hw.queues; i++) {
- if (__ieee80211_queue_stopped(local, i))
+ for (i = 0; i < ieee80211_num_regular_queues(&local->hw); i++) {
+ /* Check that this queue is ok */
+ if (__netif_subqueue_stopped(local->mdev, i))
continue;
- if (!__ieee80211_queue_pending(local, i)) {
- reschedule = 1;
+
+ if (!test_bit(i, local->queues_pending)) {
+ ieee80211_wake_queue(&local->hw, i);
continue;
}
+
store = &local->pending_packet[i];
- tx.control = &store->control;
tx.extra_frag = store->extra_frag;
tx.num_extra_frag = store->num_extra_frag;
- tx.last_frag_rate = store->last_frag_rate;
+ tx.last_frag_rate_idx = store->last_frag_rate_idx;
tx.flags = 0;
if (store->last_frag_rate_ctrl_probe)
tx.flags |= IEEE80211_TX_PROBE_LAST_FRAG;
@@ -1688,19 +1692,11 @@
if (ret == IEEE80211_TX_FRAG_AGAIN)
store->skb = NULL;
} else {
- clear_bit(IEEE80211_LINK_STATE_PENDING,
- &local->state[i]);
- reschedule = 1;
+ clear_bit(i, local->queues_pending);
+ ieee80211_wake_queue(&local->hw, i);
}
}
netif_tx_unlock_bh(dev);
- if (reschedule) {
- if (!ieee80211_qdisc_installed(dev)) {
- if (!__ieee80211_queue_stopped(local, 0))
- netif_wake_queue(dev);
- } else
- netif_schedule(dev);
- }
}
/* functions for drivers to get certain frames */
@@ -1769,11 +1765,11 @@
}
struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_tx_control *control)
+ struct ieee80211_vif *vif)
{
struct ieee80211_local *local = hw_to_local(hw);
struct sk_buff *skb;
+ struct ieee80211_tx_info *info;
struct net_device *bdev;
struct ieee80211_sub_if_data *sdata = NULL;
struct ieee80211_if_ap *ap = NULL;
@@ -1783,9 +1779,10 @@
struct ieee80211_mgmt *mgmt;
int *num_beacons;
bool err = true;
+ enum ieee80211_band band = local->hw.conf.channel->band;
u8 *pos;
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ sband = local->hw.wiphy->bands[band];
rcu_read_lock();
@@ -1878,30 +1875,32 @@
goto out;
}
- if (control) {
- rate_control_get_rate(local->mdev, sband, skb, &rsel);
- if (!rsel.rate) {
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: ieee80211_beacon_get: "
- "no rate found\n",
- wiphy_name(local->hw.wiphy));
- }
- dev_kfree_skb(skb);
- skb = NULL;
- goto out;
- }
+ info = IEEE80211_SKB_CB(skb);
- control->vif = vif;
- control->tx_rate = rsel.rate;
- if (sdata->bss_conf.use_short_preamble &&
- rsel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
- control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
- control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
- control->flags |= IEEE80211_TXCTL_NO_ACK;
- control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
- control->retry_limit = 1;
- control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT;
+ info->band = band;
+ rate_control_get_rate(local->mdev, sband, skb, &rsel);
+
+ if (unlikely(rsel.rate_idx < 0)) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: ieee80211_beacon_get: "
+ "no rate found\n",
+ wiphy_name(local->hw.wiphy));
+ }
+ dev_kfree_skb(skb);
+ skb = NULL;
+ goto out;
}
+
+ info->control.vif = vif;
+ info->tx_rate_idx = rsel.rate_idx;
+ if (sdata->bss_conf.use_short_preamble &&
+ sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE)
+ info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
+ info->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
+ info->flags |= IEEE80211_TX_CTL_NO_ACK;
+ info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
+ info->control.retry_limit = 1;
+ info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
(*num_beacons)++;
out:
rcu_read_unlock();
@@ -1911,7 +1910,7 @@
void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
const void *frame, size_t frame_len,
- const struct ieee80211_tx_control *frame_txctl,
+ const struct ieee80211_tx_info *frame_txctl,
struct ieee80211_rts *rts)
{
const struct ieee80211_hdr *hdr = frame;
@@ -1928,7 +1927,7 @@
void ieee80211_ctstoself_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
const void *frame, size_t frame_len,
- const struct ieee80211_tx_control *frame_txctl,
+ const struct ieee80211_tx_info *frame_txctl,
struct ieee80211_cts *cts)
{
const struct ieee80211_hdr *hdr = frame;
@@ -1944,11 +1943,10 @@
struct sk_buff *
ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_tx_control *control)
+ struct ieee80211_vif *vif)
{
struct ieee80211_local *local = hw_to_local(hw);
- struct sk_buff *skb;
+ struct sk_buff *skb = NULL;
struct sta_info *sta;
ieee80211_tx_handler *handler;
struct ieee80211_tx_data tx;
@@ -1957,10 +1955,11 @@
struct ieee80211_sub_if_data *sdata;
struct ieee80211_if_ap *bss = NULL;
struct beacon_data *beacon;
+ struct ieee80211_tx_info *info;
sdata = vif_to_sdata(vif);
bdev = sdata->dev;
-
+ bss = &sdata->u.ap;
if (!bss)
return NULL;
@@ -1968,19 +1967,16 @@
rcu_read_lock();
beacon = rcu_dereference(bss->beacon);
- if (sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon ||
- !beacon->head) {
- rcu_read_unlock();
- return NULL;
- }
+ if (sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon || !beacon->head)
+ goto out;
if (bss->dtim_count != 0)
- return NULL; /* send buffered bc/mc only after DTIM beacon */
- memset(control, 0, sizeof(*control));
+ goto out; /* send buffered bc/mc only after DTIM beacon */
+
while (1) {
skb = skb_dequeue(&bss->ps_bc_buf);
if (!skb)
- return NULL;
+ goto out;
local->total_ps_buffered--;
if (!skb_queue_empty(&bss->ps_bc_buf) && skb->len >= 2) {
@@ -1993,20 +1989,26 @@
cpu_to_le16(IEEE80211_FCTL_MOREDATA);
}
- if (!ieee80211_tx_prepare(&tx, skb, local->mdev, control))
+ if (!ieee80211_tx_prepare(&tx, skb, local->mdev))
break;
dev_kfree_skb_any(skb);
}
+
+ info = IEEE80211_SKB_CB(skb);
+
sta = tx.sta;
tx.flags |= IEEE80211_TX_PS_BUFFERED;
tx.channel = local->hw.conf.channel;
+ info->band = tx.channel->band;
for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) {
res = (*handler)(&tx);
if (res == TX_DROP || res == TX_QUEUED)
break;
}
- skb = tx.skb; /* handlers are allowed to change skb */
+
+ if (WARN_ON(tx.skb != skb))
+ res = TX_DROP;
if (res == TX_DROP) {
I802_DEBUG_INC(local->tx_handlers_drop);
@@ -2017,6 +2019,7 @@
skb = NULL;
}
+out:
rcu_read_unlock();
return skb;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 4e97b26..6513bc2 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -258,7 +258,7 @@
__le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, size_t frame_len,
- const struct ieee80211_tx_control *frame_txctl)
+ const struct ieee80211_tx_info *frame_txctl)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_rate *rate;
@@ -266,10 +266,13 @@
bool short_preamble;
int erp;
u16 dur;
+ struct ieee80211_supported_band *sband;
+
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
short_preamble = sdata->bss_conf.use_short_preamble;
- rate = frame_txctl->rts_cts_rate;
+ rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx];
erp = 0;
if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
@@ -292,7 +295,7 @@
__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
size_t frame_len,
- const struct ieee80211_tx_control *frame_txctl)
+ const struct ieee80211_tx_info *frame_txctl)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_rate *rate;
@@ -300,10 +303,13 @@
bool short_preamble;
int erp;
u16 dur;
+ struct ieee80211_supported_band *sband;
+
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
short_preamble = sdata->bss_conf.use_short_preamble;
- rate = frame_txctl->rts_cts_rate;
+ rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx];
erp = 0;
if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
erp = rate->flags & IEEE80211_RATE_ERP_G;
@@ -311,7 +317,7 @@
/* Data frame duration */
dur = ieee80211_frame_duration(local, frame_len, rate->bitrate,
erp, short_preamble);
- if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) {
+ if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) {
/* ACK duration */
dur += ieee80211_frame_duration(local, 10, rate->bitrate,
erp, short_preamble);
@@ -325,17 +331,15 @@
{
struct ieee80211_local *local = hw_to_local(hw);
- if (test_and_clear_bit(IEEE80211_LINK_STATE_XOFF,
- &local->state[queue])) {
- if (test_bit(IEEE80211_LINK_STATE_PENDING,
- &local->state[queue]))
- tasklet_schedule(&local->tx_pending_tasklet);
- else
- if (!ieee80211_qdisc_installed(local->mdev)) {
- if (queue == 0)
- netif_wake_queue(local->mdev);
- } else
- __netif_schedule(local->mdev);
+ if (test_bit(queue, local->queues_pending)) {
+ tasklet_schedule(&local->tx_pending_tasklet);
+ } else {
+ if (ieee80211_is_multiqueue(local)) {
+ netif_wake_subqueue(local->mdev, queue);
+ } else {
+ WARN_ON(queue != 0);
+ netif_wake_queue(local->mdev);
+ }
}
}
EXPORT_SYMBOL(ieee80211_wake_queue);
@@ -344,29 +348,20 @@
{
struct ieee80211_local *local = hw_to_local(hw);
- if (!ieee80211_qdisc_installed(local->mdev) && queue == 0)
+ if (ieee80211_is_multiqueue(local)) {
+ netif_stop_subqueue(local->mdev, queue);
+ } else {
+ WARN_ON(queue != 0);
netif_stop_queue(local->mdev);
- set_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]);
+ }
}
EXPORT_SYMBOL(ieee80211_stop_queue);
-void ieee80211_start_queues(struct ieee80211_hw *hw)
-{
- struct ieee80211_local *local = hw_to_local(hw);
- int i;
-
- for (i = 0; i < local->hw.queues; i++)
- clear_bit(IEEE80211_LINK_STATE_XOFF, &local->state[i]);
- if (!ieee80211_qdisc_installed(local->mdev))
- netif_start_queue(local->mdev);
-}
-EXPORT_SYMBOL(ieee80211_start_queues);
-
void ieee80211_stop_queues(struct ieee80211_hw *hw)
{
int i;
- for (i = 0; i < hw->queues; i++)
+ for (i = 0; i < ieee80211_num_queues(hw); i++)
ieee80211_stop_queue(hw, i);
}
EXPORT_SYMBOL(ieee80211_stop_queues);
@@ -375,7 +370,7 @@
{
int i;
- for (i = 0; i < hw->queues; i++)
+ for (i = 0; i < hw->queues + hw->ampdu_queues; i++)
ieee80211_wake_queue(hw, i);
}
EXPORT_SYMBOL(ieee80211_wake_queues);
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c
index affcecd..e7b6344 100644
--- a/net/mac80211/wep.c
+++ b/net/mac80211/wep.c
@@ -93,13 +93,9 @@
fc |= IEEE80211_FCTL_PROTECTED;
hdr->frame_control = cpu_to_le16(fc);
- if ((skb_headroom(skb) < WEP_IV_LEN ||
- skb_tailroom(skb) < WEP_ICV_LEN)) {
- I802_DEBUG_INC(local->tx_expand_skb_head);
- if (unlikely(pskb_expand_head(skb, WEP_IV_LEN, WEP_ICV_LEN,
- GFP_ATOMIC)))
- return NULL;
- }
+ if (WARN_ON(skb_tailroom(skb) < WEP_ICV_LEN ||
+ skb_headroom(skb) < WEP_IV_LEN))
+ return NULL;
hdrlen = ieee80211_get_hdrlen(fc);
newhdr = skb_push(skb, WEP_IV_LEN);
@@ -333,11 +329,16 @@
static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+ info->control.iv_len = WEP_IV_LEN;
+ info->control.icv_len = WEP_ICV_LEN;
+
if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) {
if (ieee80211_wep_encrypt(tx->local, skb, tx->key))
return -1;
} else {
- tx->control->key_idx = tx->key->conf.hw_key_idx;
+ info->control.hw_key = &tx->key->conf;
if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) {
if (!ieee80211_wep_add_iv(tx->local, skb, tx->key))
return -1;
@@ -349,8 +350,6 @@
ieee80211_tx_result
ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx)
{
- tx->control->iv_len = WEP_IV_LEN;
- tx->control->icv_len = WEP_ICV_LEN;
ieee80211_tx_set_protected(tx);
if (wep_encrypt_skb(tx, tx->skb) < 0) {
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/wext.c b/net/mac80211/wext.c
index a8bb8e3..4806d96 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -169,14 +169,26 @@
range->num_encoding_sizes = 2;
range->max_encoding_tokens = NUM_DEFAULT_KEYS;
- range->max_qual.qual = local->hw.max_signal;
- range->max_qual.level = local->hw.max_rssi;
- range->max_qual.noise = local->hw.max_noise;
+ if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC ||
+ local->hw.flags & IEEE80211_HW_SIGNAL_DB)
+ range->max_qual.level = local->hw.max_signal;
+ else if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
+ range->max_qual.level = -110;
+ else
+ range->max_qual.level = 0;
+
+ if (local->hw.flags & IEEE80211_HW_NOISE_DBM)
+ range->max_qual.noise = -110;
+ else
+ range->max_qual.noise = 0;
+
+ range->max_qual.qual = 100;
range->max_qual.updated = local->wstats_flags;
- range->avg_qual.qual = local->hw.max_signal/2;
- range->avg_qual.level = 0;
- range->avg_qual.noise = 0;
+ range->avg_qual.qual = 50;
+ /* not always true but better than nothing */
+ range->avg_qual.level = range->max_qual.level / 2;
+ range->avg_qual.noise = range->max_qual.noise / 2;
range->avg_qual.updated = local->wstats_flags;
range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
@@ -1007,8 +1019,8 @@
wstats->qual.noise = 0;
wstats->qual.updated = IW_QUAL_ALL_INVALID;
} else {
- wstats->qual.level = sta->last_rssi;
- wstats->qual.qual = sta->last_signal;
+ wstats->qual.level = sta->last_signal;
+ wstats->qual.qual = sta->last_qual;
wstats->qual.noise = sta->last_noise;
wstats->qual.updated = local->wstats_flags;
}
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index dc1598b8..14a9ff1 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,29 +147,29 @@
static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
{
struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+ struct ieee80211_hw *hw = &local->hw;
struct ieee80211_sched_data *q = qdisc_priv(qd);
- struct ieee80211_tx_packet_data *pkt_data =
- (struct ieee80211_tx_packet_data *) skb->cb;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
unsigned short fc = le16_to_cpu(hdr->frame_control);
struct Qdisc *qdisc;
- int err, queue;
struct sta_info *sta;
+ int err, queue;
u8 tid;
- if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) {
- queue = pkt_data->queue;
+ if (info->flags & IEEE80211_TX_CTL_REQUEUE) {
+ queue = skb_get_queue_mapping(skb);
rcu_read_lock();
sta = sta_info_get(local, hdr->addr1);
tid = skb->priority & QOS_CONTROL_TAG1D_MASK;
if (sta) {
int ampdu_queue = sta->tid_to_tx_q[tid];
- if ((ampdu_queue < local->hw.queues) &&
+ if ((ampdu_queue < QD_NUM(hw)) &&
test_bit(ampdu_queue, q->qdisc_pool)) {
queue = ampdu_queue;
- pkt_data->flags |= IEEE80211_TXPD_AMPDU;
+ info->flags |= IEEE80211_TX_CTL_AMPDU;
} else {
- pkt_data->flags &= ~IEEE80211_TXPD_AMPDU;
+ info->flags &= ~IEEE80211_TX_CTL_AMPDU;
}
}
rcu_read_unlock();
@@ -174,6 +180,9 @@
queue = classify80211(skb, qd);
+ if (unlikely(queue >= local->hw.queues))
+ queue = local->hw.queues - 1;
+
/* now we know the 1d priority, fill in the QoS header if there is one
*/
if (WLAN_FC_IS_QOS_DATA(fc)) {
@@ -193,35 +202,24 @@
sta = sta_info_get(local, hdr->addr1);
if (sta) {
int ampdu_queue = sta->tid_to_tx_q[tid];
- if ((ampdu_queue < local->hw.queues) &&
- test_bit(ampdu_queue, q->qdisc_pool)) {
+ if ((ampdu_queue < QD_NUM(hw)) &&
+ test_bit(ampdu_queue, q->qdisc_pool)) {
queue = ampdu_queue;
- pkt_data->flags |= IEEE80211_TXPD_AMPDU;
+ info->flags |= IEEE80211_TX_CTL_AMPDU;
} else {
- pkt_data->flags &= ~IEEE80211_TXPD_AMPDU;
+ info->flags &= ~IEEE80211_TX_CTL_AMPDU;
}
}
rcu_read_unlock();
}
- if (unlikely(queue >= local->hw.queues)) {
-#if 0
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s - queue=%d (hw does not "
- "support) -> %d\n",
- __func__, queue, local->hw.queues - 1);
- }
-#endif
- queue = local->hw.queues - 1;
- }
-
if (unlikely(queue < 0)) {
kfree_skb(skb);
err = NET_XMIT_DROP;
} else {
tid = skb->priority & QOS_CONTROL_TAG1D_MASK;
- pkt_data->queue = (unsigned int) queue;
+ skb_set_queue_mapping(skb, queue);
qdisc = q->queues[queue];
err = qdisc->enqueue(skb, qdisc);
if (err == NET_XMIT_SUCCESS) {
@@ -242,13 +240,11 @@
static int wme_qdiscop_requeue(struct sk_buff *skb, struct Qdisc* qd)
{
struct ieee80211_sched_data *q = qdisc_priv(qd);
- struct ieee80211_tx_packet_data *pkt_data =
- (struct ieee80211_tx_packet_data *) skb->cb;
struct Qdisc *qdisc;
int err;
/* we recorded which queue to use earlier! */
- qdisc = q->queues[pkt_data->queue];
+ qdisc = q->queues[skb_get_queue_mapping(skb)];
if ((err = qdisc->ops->requeue(skb, qdisc)) == 0) {
qd->q.qlen++;
@@ -270,13 +266,10 @@
int queue;
/* check all the h/w queues in numeric/priority order */
- for (queue = 0; queue < hw->queues; queue++) {
+ for (queue = 0; queue < QD_NUM(hw); queue++) {
/* see if there is room in this hardware queue */
- if ((test_bit(IEEE80211_LINK_STATE_XOFF,
- &local->state[queue])) ||
- (test_bit(IEEE80211_LINK_STATE_PENDING,
- &local->state[queue])) ||
- (!test_bit(queue, q->qdisc_pool)))
+ if (__netif_subqueue_stopped(local->mdev, queue) ||
+ !test_bit(queue, q->qdisc_pool))
continue;
/* there is space - try and get a frame */
@@ -308,7 +301,7 @@
/* QUESTION: should we have some hardware flush functionality here? */
- for (queue = 0; queue < hw->queues; queue++) {
+ for (queue = 0; queue < QD_NUM(hw); queue++) {
skb_queue_purge(&q->requeued[queue]);
qdisc_reset(q->queues[queue]);
}
@@ -326,7 +319,7 @@
tcf_destroy_chain(q->filter_list);
q->filter_list = NULL;
- for (queue=0; queue < hw->queues; queue++) {
+ for (queue = 0; queue < QD_NUM(hw); queue++) {
skb_queue_purge(&q->requeued[queue]);
qdisc_destroy(q->queues[queue]);
q->queues[queue] = &noop_qdisc;
@@ -337,17 +330,6 @@
/* called whenever parameters are updated on existing qdisc */
static int wme_qdiscop_tune(struct Qdisc *qd, struct nlattr *opt)
{
-/* struct ieee80211_sched_data *q = qdisc_priv(qd);
-*/
- /* check our options block is the right size */
- /* copy any options to our local structure */
-/* Ignore options block for now - always use static mapping
- struct tc_ieee80211_qopt *qopt = nla_data(opt);
-
- if (opt->nla_len < nla_attr_size(sizeof(*qopt)))
- return -EINVAL;
- memcpy(q->tag2queue, qopt->tag2queue, sizeof(qopt->tag2queue));
-*/
return 0;
}
@@ -358,7 +340,7 @@
struct ieee80211_sched_data *q = qdisc_priv(qd);
struct net_device *dev = qd->dev;
struct ieee80211_local *local;
- int queues;
+ struct ieee80211_hw *hw;
int err = 0, i;
/* check that device is a mac80211 device */
@@ -366,29 +348,26 @@
dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
return -EINVAL;
- /* check this device is an ieee80211 master type device */
- if (dev->type != ARPHRD_IEEE80211)
+ local = wdev_priv(dev->ieee80211_ptr);
+ hw = &local->hw;
+
+ /* only allow on master dev */
+ if (dev != local->mdev)
return -EINVAL;
- /* check that there is no qdisc currently attached to device
- * this ensures that we will be the root qdisc. (I can't find a better
- * way to test this explicitly) */
- if (dev->qdisc_sleeping != &noop_qdisc)
+ /* ensure that we are root qdisc */
+ if (qd->parent != TC_H_ROOT)
return -EINVAL;
if (qd->flags & TCQ_F_INGRESS)
return -EINVAL;
- local = wdev_priv(dev->ieee80211_ptr);
- queues = local->hw.queues;
-
/* if options were passed in, set them */
- if (opt) {
+ if (opt)
err = wme_qdiscop_tune(qd, opt);
- }
/* create child queues */
- for (i = 0; i < queues; i++) {
+ for (i = 0; i < QD_NUM(hw); i++) {
skb_queue_head_init(&q->requeued[i]);
q->queues[i] = qdisc_create_dflt(qd->dev, &pfifo_qdisc_ops,
qd->handle);
@@ -399,8 +378,8 @@
}
}
- /* reserve all legacy QoS queues */
- for (i = 0; i < min(IEEE80211_TX_QUEUE_DATA4, queues); i++)
+ /* non-aggregation queues: reserve/mark as used */
+ for (i = 0; i < local->hw.queues; i++)
set_bit(i, q->qdisc_pool);
return err;
@@ -408,16 +387,6 @@
static int wme_qdiscop_dump(struct Qdisc *qd, struct sk_buff *skb)
{
-/* struct ieee80211_sched_data *q = qdisc_priv(qd);
- unsigned char *p = skb->tail;
- struct tc_ieee80211_qopt opt;
-
- memcpy(&opt.tag2queue, q->tag2queue, TC_80211_MAX_TAG + 1);
- NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
-*/ return skb->len;
-/*
-nla_put_failure:
- skb_trim(skb, p - skb->data);*/
return -1;
}
@@ -430,7 +399,7 @@
struct ieee80211_hw *hw = &local->hw;
unsigned long queue = arg - 1;
- if (queue >= hw->queues)
+ if (queue >= QD_NUM(hw))
return -EINVAL;
if (!new)
@@ -454,7 +423,7 @@
struct ieee80211_hw *hw = &local->hw;
unsigned long queue = arg - 1;
- if (queue >= hw->queues)
+ if (queue >= QD_NUM(hw))
return NULL;
return q->queues[queue];
@@ -467,7 +436,7 @@
struct ieee80211_hw *hw = &local->hw;
unsigned long queue = TC_H_MIN(classid);
- if (queue - 1 >= hw->queues)
+ if (queue - 1 >= QD_NUM(hw))
return 0;
return queue;
@@ -493,7 +462,7 @@
struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
struct ieee80211_hw *hw = &local->hw;
- if (cl - 1 > hw->queues)
+ if (cl - 1 > QD_NUM(hw))
return -ENOENT;
/* TODO: put code to program hardware queue parameters here,
@@ -510,7 +479,7 @@
struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
struct ieee80211_hw *hw = &local->hw;
- if (cl - 1 > hw->queues)
+ if (cl - 1 > QD_NUM(hw))
return -ENOENT;
return 0;
}
@@ -523,7 +492,7 @@
struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
struct ieee80211_hw *hw = &local->hw;
- if (cl - 1 > hw->queues)
+ if (cl - 1 > QD_NUM(hw))
return -ENOENT;
tcm->tcm_handle = TC_H_MIN(cl);
tcm->tcm_parent = qd->handle;
@@ -541,7 +510,7 @@
if (arg->stop)
return;
- for (queue = 0; queue < hw->queues; queue++) {
+ for (queue = 0; queue < QD_NUM(hw); queue++) {
if (arg->count < arg->skip) {
arg->count++;
continue;
@@ -658,10 +627,13 @@
DECLARE_MAC_BUF(mac);
/* prepare the filter and save it for the SW queue
- * matching the recieved HW queue */
+ * matching the received HW queue */
+
+ if (!local->hw.ampdu_queues)
+ return -EPERM;
/* try to get a Qdisc from the pool */
- for (i = IEEE80211_TX_QUEUE_BEACON; i < local->hw.queues; i++)
+ for (i = local->hw.queues; i < QD_NUM(&local->hw); i++)
if (!test_and_set_bit(i, q->qdisc_pool)) {
ieee80211_stop_queue(local_to_hw(local), i);
sta->tid_to_tx_q[tid] = i;
@@ -690,13 +662,14 @@
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/wme.h b/net/mac80211/wme.h
index fcc6b05..bbdb533 100644
--- a/net/mac80211/wme.h
+++ b/net/mac80211/wme.h
@@ -31,7 +31,7 @@
return (fc & 0x8C) == 0x88;
}
-#ifdef CONFIG_NET_SCHED
+#ifdef CONFIG_MAC80211_QOS
void ieee80211_install_qdisc(struct net_device *dev);
int ieee80211_qdisc_installed(struct net_device *dev);
int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 45709ad..9f6fd20 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -79,6 +79,7 @@
struct sk_buff *skb = tx->skb;
int authenticator;
int wpa_test = 0;
+ int tail;
fc = tx->fc;
@@ -98,16 +99,13 @@
return TX_CONTINUE;
}
- if (skb_tailroom(skb) < MICHAEL_MIC_LEN) {
- I802_DEBUG_INC(tx->local->tx_expand_skb_head);
- if (unlikely(pskb_expand_head(skb, TKIP_IV_LEN,
- MICHAEL_MIC_LEN + TKIP_ICV_LEN,
- GFP_ATOMIC))) {
- printk(KERN_DEBUG "%s: failed to allocate more memory "
- "for Michael MIC\n", tx->dev->name);
- return TX_DROP;
- }
- }
+ tail = MICHAEL_MIC_LEN;
+ if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
+ tail += TKIP_ICV_LEN;
+
+ if (WARN_ON(skb_tailroom(skb) < tail ||
+ skb_headroom(skb) < TKIP_IV_LEN))
+ return TX_DROP;
#if 0
authenticator = fc & IEEE80211_FCTL_FROMDS; /* FIX */
@@ -176,59 +174,65 @@
skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
/* update IV in key information to be able to detect replays */
- rx->key->u.tkip.iv32_rx[rx->queue] = rx->tkip_iv32;
- rx->key->u.tkip.iv16_rx[rx->queue] = rx->tkip_iv16;
+ rx->key->u.tkip.rx[rx->queue].iv32 = rx->tkip_iv32;
+ rx->key->u.tkip.rx[rx->queue].iv16 = rx->tkip_iv16;
return RX_CONTINUE;
}
-static int tkip_encrypt_skb(struct ieee80211_tx_data *tx,
- struct sk_buff *skb, int test)
+static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_key *key = tx->key;
- int hdrlen, len, tailneed;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ int hdrlen, len, tail;
u16 fc;
u8 *pos;
+ info->control.icv_len = TKIP_ICV_LEN;
+ info->control.iv_len = TKIP_IV_LEN;
+
+ if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
+ !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
+ /* hwaccel - with no need for preallocated room for IV/ICV */
+ info->control.hw_key = &tx->key->conf;
+ return 0;
+ }
+
fc = le16_to_cpu(hdr->frame_control);
hdrlen = ieee80211_get_hdrlen(fc);
len = skb->len - hdrlen;
if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
- tailneed = 0;
+ tail = 0;
else
- tailneed = TKIP_ICV_LEN;
+ tail = TKIP_ICV_LEN;
- if ((skb_headroom(skb) < TKIP_IV_LEN ||
- skb_tailroom(skb) < tailneed)) {
- I802_DEBUG_INC(tx->local->tx_expand_skb_head);
- if (unlikely(pskb_expand_head(skb, TKIP_IV_LEN, tailneed,
- GFP_ATOMIC)))
- return -1;
- }
+ if (WARN_ON(skb_tailroom(skb) < tail ||
+ skb_headroom(skb) < TKIP_IV_LEN))
+ return -1;
pos = skb_push(skb, TKIP_IV_LEN);
memmove(pos, pos + TKIP_IV_LEN, hdrlen);
pos += hdrlen;
/* Increase IV for the frame */
- key->u.tkip.iv16++;
- if (key->u.tkip.iv16 == 0)
- key->u.tkip.iv32++;
+ key->u.tkip.tx.iv16++;
+ if (key->u.tkip.tx.iv16 == 0)
+ key->u.tkip.tx.iv32++;
if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
hdr = (struct ieee80211_hdr *)skb->data;
/* hwaccel - with preallocated room for IV */
ieee80211_tkip_add_iv(pos, key,
- (u8) (key->u.tkip.iv16 >> 8),
- (u8) (((key->u.tkip.iv16 >> 8) | 0x20) &
+ (u8) (key->u.tkip.tx.iv16 >> 8),
+ (u8) (((key->u.tkip.tx.iv16 >> 8) | 0x20) &
0x7f),
- (u8) key->u.tkip.iv16);
+ (u8) key->u.tkip.tx.iv16);
- tx->control->key_idx = tx->key->conf.hw_key_idx;
+ info->control.hw_key = &tx->key->conf;
return 0;
}
@@ -246,28 +250,16 @@
ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx)
{
struct sk_buff *skb = tx->skb;
- int wpa_test = 0, test = 0;
- tx->control->icv_len = TKIP_ICV_LEN;
- tx->control->iv_len = TKIP_IV_LEN;
ieee80211_tx_set_protected(tx);
- if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
- !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) &&
- !wpa_test) {
- /* hwaccel - with no need for preallocated room for IV/ICV */
- tx->control->key_idx = tx->key->conf.hw_key_idx;
- return TX_CONTINUE;
- }
-
- if (tkip_encrypt_skb(tx, skb, test) < 0)
+ if (tkip_encrypt_skb(tx, skb) < 0)
return TX_DROP;
if (tx->extra_frag) {
int i;
for (i = 0; i < tx->num_extra_frag; i++) {
- if (tkip_encrypt_skb(tx, tx->extra_frag[i], test)
- < 0)
+ if (tkip_encrypt_skb(tx, tx->extra_frag[i]) < 0)
return TX_DROP;
}
}
@@ -429,16 +421,27 @@
}
-static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx,
- struct sk_buff *skb, int test)
+static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_key *key = tx->key;
- int hdrlen, len, tailneed;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ int hdrlen, len, tail;
u16 fc;
u8 *pos, *pn, *b_0, *aad, *scratch;
int i;
+ info->control.icv_len = CCMP_MIC_LEN;
+ info->control.iv_len = CCMP_HDR_LEN;
+
+ if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
+ !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
+ /* hwaccel - with no need for preallocated room for CCMP "
+ * header or MIC fields */
+ info->control.hw_key = &tx->key->conf;
+ return 0;
+ }
+
scratch = key->u.ccmp.tx_crypto_buf;
b_0 = scratch + 3 * AES_BLOCK_LEN;
aad = scratch + 4 * AES_BLOCK_LEN;
@@ -448,17 +451,13 @@
len = skb->len - hdrlen;
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
- tailneed = 0;
+ tail = 0;
else
- tailneed = CCMP_MIC_LEN;
+ tail = CCMP_MIC_LEN;
- if ((skb_headroom(skb) < CCMP_HDR_LEN ||
- skb_tailroom(skb) < tailneed)) {
- I802_DEBUG_INC(tx->local->tx_expand_skb_head);
- if (unlikely(pskb_expand_head(skb, CCMP_HDR_LEN, tailneed,
- GFP_ATOMIC)))
- return -1;
- }
+ if (WARN_ON(skb_tailroom(skb) < tail ||
+ skb_headroom(skb) < CCMP_HDR_LEN))
+ return -1;
pos = skb_push(skb, CCMP_HDR_LEN);
memmove(pos, pos + CCMP_HDR_LEN, hdrlen);
@@ -478,7 +477,7 @@
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
/* hwaccel - with preallocated room for CCMP header */
- tx->control->key_idx = key->conf.hw_key_idx;
+ info->control.hw_key = &tx->key->conf;
return 0;
}
@@ -495,28 +494,16 @@
ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx)
{
struct sk_buff *skb = tx->skb;
- int test = 0;
- tx->control->icv_len = CCMP_MIC_LEN;
- tx->control->iv_len = CCMP_HDR_LEN;
ieee80211_tx_set_protected(tx);
- if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
- !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
- /* hwaccel - with no need for preallocated room for CCMP "
- * header or MIC fields */
- tx->control->key_idx = tx->key->conf.hw_key_idx;
- return TX_CONTINUE;
- }
-
- if (ccmp_encrypt_skb(tx, skb, test) < 0)
+ if (ccmp_encrypt_skb(tx, skb) < 0)
return TX_DROP;
if (tx->extra_frag) {
int i;
for (i = 0; i < tx->num_extra_frag; i++) {
- if (ccmp_encrypt_skb(tx, tx->extra_frag[i], test)
- < 0)
+ if (ccmp_encrypt_skb(tx, tx->extra_frag[i]) < 0)
return TX_DROP;
}
}
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 662c1cc..f27c9924 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -847,6 +847,25 @@
}
EXPORT_SYMBOL_GPL(__nf_ct_refresh_acct);
+void __nf_ct_kill_acct(struct nf_conn *ct,
+ enum ip_conntrack_info ctinfo,
+ const struct sk_buff *skb,
+ int do_acct)
+{
+#ifdef CONFIG_NF_CT_ACCT
+ if (do_acct) {
+ spin_lock_bh(&nf_conntrack_lock);
+ ct->counters[CTINFO2DIR(ctinfo)].packets++;
+ ct->counters[CTINFO2DIR(ctinfo)].bytes +=
+ skb->len - skb_network_offset(skb);
+ spin_unlock_bh(&nf_conntrack_lock);
+ }
+#endif
+ if (del_timer(&ct->timeout))
+ ct->timeout.function((unsigned long)ct);
+}
+EXPORT_SYMBOL_GPL(__nf_ct_kill_acct);
+
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
#include <linux/netfilter/nfnetlink.h>
diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c
index bcc19fa..ba1c491 100644
--- a/net/netfilter/nf_conntrack_extend.c
+++ b/net/netfilter/nf_conntrack_extend.c
@@ -88,13 +88,11 @@
newlen = newoff + t->len;
rcu_read_unlock();
- if (newlen >= ksize(ct->ext)) {
- new = kmalloc(newlen, gfp);
- if (!new)
- return NULL;
+ new = krealloc(ct->ext, newlen, gfp);
+ if (!new)
+ return NULL;
- memcpy(new, ct->ext, ct->ext->len);
-
+ if (new != ct->ext) {
for (i = 0; i < NF_CT_EXT_NUM; i++) {
if (!nf_ct_ext_exist(ct, i))
continue;
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 0edefcf..63c4e1f 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -4,7 +4,7 @@
* (C) 2001 by Jay Schulist <jschlst@samba.org>
* (C) 2002-2006 by Harald Welte <laforge@gnumonks.org>
* (C) 2003 by Patrick Mchardy <kaber@trash.net>
- * (C) 2005-2007 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2005-2008 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* Initial connection tracking via netlink development funded and
* generally made possible by Network Robots, Inc. (www.networkrobots.com)
@@ -475,14 +475,14 @@
if (ctnetlink_dump_id(skb, ct) < 0)
goto nla_put_failure;
+ if (ctnetlink_dump_status(skb, ct) < 0)
+ goto nla_put_failure;
+
if (events & IPCT_DESTROY) {
if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)
goto nla_put_failure;
} else {
- if (ctnetlink_dump_status(skb, ct) < 0)
- goto nla_put_failure;
-
if (ctnetlink_dump_timeout(skb, ct) < 0)
goto nla_put_failure;
@@ -812,9 +812,8 @@
return -ENOENT;
}
}
- if (del_timer(&ct->timeout))
- ct->timeout.function((unsigned long)ct);
+ nf_ct_kill(ct);
nf_ct_put(ct);
return 0;
@@ -891,20 +890,19 @@
if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING))
/* unchangeable */
- return -EINVAL;
+ return -EBUSY;
if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY))
/* SEEN_REPLY bit can only be set */
- return -EINVAL;
-
+ return -EBUSY;
if (d & IPS_ASSURED && !(status & IPS_ASSURED))
/* ASSURED bit can only be set */
- return -EINVAL;
+ return -EBUSY;
if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
#ifndef CONFIG_NF_NAT_NEEDED
- return -EINVAL;
+ return -EOPNOTSUPP;
#else
struct nf_nat_range range;
@@ -945,7 +943,7 @@
/* don't change helper of sibling connections */
if (ct->master)
- return -EINVAL;
+ return -EBUSY;
err = ctnetlink_parse_help(cda[CTA_HELP], &helpname);
if (err < 0)
@@ -963,7 +961,7 @@
helper = __nf_conntrack_helper_find_byname(helpname);
if (helper == NULL)
- return -EINVAL;
+ return -EOPNOTSUPP;
if (help) {
if (help->helper == helper)
@@ -1258,12 +1256,12 @@
if (!(nlh->nlmsg_flags & NLM_F_EXCL)) {
/* we only allow nat config for new conntracks */
if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
- err = -EINVAL;
+ err = -EOPNOTSUPP;
goto out_unlock;
}
/* can't link an existing conntrack to a master */
if (cda[CTA_TUPLE_MASTER]) {
- err = -EINVAL;
+ err = -EOPNOTSUPP;
goto out_unlock;
}
err = ctnetlink_change_conntrack(nf_ct_tuplehash_to_ctrack(h),
@@ -1608,7 +1606,7 @@
h = __nf_conntrack_helper_find_byname(name);
if (!h) {
spin_unlock_bh(&nf_conntrack_lock);
- return -EINVAL;
+ return -EOPNOTSUPP;
}
for (i = 0; i < nf_ct_expect_hsize; i++) {
hlist_for_each_entry_safe(exp, n, next,
diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c
index afb4a18..e7866dd 100644
--- a/net/netfilter/nf_conntrack_proto_dccp.c
+++ b/net/netfilter/nf_conntrack_proto_dccp.c
@@ -475,8 +475,7 @@
if (type == DCCP_PKT_RESET &&
!test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
/* Tear down connection immediately if only reply is a RESET */
- if (del_timer(&ct->timeout))
- ct->timeout.function((unsigned long)ct);
+ nf_ct_kill_acct(ct, ctinfo, skb);
return NF_ACCEPT;
}
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c
index cbf2e27..41183a4 100644
--- a/net/netfilter/nf_conntrack_proto_sctp.c
+++ b/net/netfilter/nf_conntrack_proto_sctp.c
@@ -463,6 +463,82 @@
return true;
}
+#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
+
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_conntrack.h>
+
+static int sctp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
+ const struct nf_conn *ct)
+{
+ struct nlattr *nest_parms;
+
+ read_lock_bh(&sctp_lock);
+ nest_parms = nla_nest_start(skb, CTA_PROTOINFO_SCTP | NLA_F_NESTED);
+ if (!nest_parms)
+ goto nla_put_failure;
+
+ NLA_PUT_U8(skb, CTA_PROTOINFO_SCTP_STATE, ct->proto.sctp.state);
+
+ NLA_PUT_BE32(skb,
+ CTA_PROTOINFO_SCTP_VTAG_ORIGINAL,
+ htonl(ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL]));
+
+ NLA_PUT_BE32(skb,
+ CTA_PROTOINFO_SCTP_VTAG_REPLY,
+ htonl(ct->proto.sctp.vtag[IP_CT_DIR_REPLY]));
+
+ read_unlock_bh(&sctp_lock);
+
+ nla_nest_end(skb, nest_parms);
+
+ return 0;
+
+nla_put_failure:
+ read_unlock_bh(&sctp_lock);
+ return -1;
+}
+
+static const struct nla_policy sctp_nla_policy[CTA_PROTOINFO_SCTP_MAX+1] = {
+ [CTA_PROTOINFO_SCTP_STATE] = { .type = NLA_U8 },
+ [CTA_PROTOINFO_SCTP_VTAG_ORIGINAL] = { .type = NLA_U32 },
+ [CTA_PROTOINFO_SCTP_VTAG_REPLY] = { .type = NLA_U32 },
+};
+
+static int nlattr_to_sctp(struct nlattr *cda[], struct nf_conn *ct)
+{
+ struct nlattr *attr = cda[CTA_PROTOINFO_SCTP];
+ struct nlattr *tb[CTA_PROTOINFO_SCTP_MAX+1];
+ int err;
+
+ /* updates may not contain the internal protocol info, skip parsing */
+ if (!attr)
+ return 0;
+
+ err = nla_parse_nested(tb,
+ CTA_PROTOINFO_SCTP_MAX,
+ attr,
+ sctp_nla_policy);
+ if (err < 0)
+ return err;
+
+ if (!tb[CTA_PROTOINFO_SCTP_STATE] ||
+ !tb[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL] ||
+ !tb[CTA_PROTOINFO_SCTP_VTAG_REPLY])
+ return -EINVAL;
+
+ write_lock_bh(&sctp_lock);
+ ct->proto.sctp.state = nla_get_u8(tb[CTA_PROTOINFO_SCTP_STATE]);
+ ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL] =
+ ntohl(nla_get_be32(tb[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL]));
+ ct->proto.sctp.vtag[IP_CT_DIR_REPLY] =
+ ntohl(nla_get_be32(tb[CTA_PROTOINFO_SCTP_VTAG_REPLY]));
+ write_unlock_bh(&sctp_lock);
+
+ return 0;
+}
+#endif
+
#ifdef CONFIG_SYSCTL
static unsigned int sctp_sysctl_table_users;
static struct ctl_table_header *sctp_sysctl_header;
@@ -591,6 +667,8 @@
.new = sctp_new,
.me = THIS_MODULE,
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
+ .to_nlattr = sctp_to_nlattr,
+ .from_nlattr = nlattr_to_sctp,
.tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
.nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
.nla_policy = nf_ct_port_nla_policy,
@@ -617,6 +695,8 @@
.new = sctp_new,
.me = THIS_MODULE,
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
+ .to_nlattr = sctp_to_nlattr,
+ .from_nlattr = nlattr_to_sctp,
.tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
.nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
.nla_policy = nf_ct_port_nla_policy,
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index ba94004..8db13fb 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -843,8 +843,7 @@
/* Attempt to reopen a closed/aborted connection.
* Delete this connection and look up again. */
write_unlock_bh(&tcp_lock);
- if (del_timer(&ct->timeout))
- ct->timeout.function((unsigned long)ct);
+ nf_ct_kill(ct);
return -NF_REPEAT;
}
/* Fall through */
@@ -877,8 +876,7 @@
if (LOG_INVALID(IPPROTO_TCP))
nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
"nf_ct_tcp: killing out of sync session ");
- if (del_timer(&ct->timeout))
- ct->timeout.function((unsigned long)ct);
+ nf_ct_kill(ct);
return -NF_DROP;
}
ct->proto.tcp.last_index = index;
@@ -961,8 +959,7 @@
problem case, so we can delete the conntrack
immediately. --RR */
if (th->rst) {
- if (del_timer(&ct->timeout))
- ct->timeout.function((unsigned long)ct);
+ nf_ct_kill_acct(ct, ctinfo, skb);
return NF_ACCEPT;
}
} else if (!test_bit(IPS_ASSURED_BIT, &ct->status)
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 3447025..04e9c96 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -243,7 +243,6 @@
switch ((enum nfqnl_config_mode)queue->copy_mode) {
case NFQNL_COPY_META:
case NFQNL_COPY_NONE:
- data_len = 0;
break;
case NFQNL_COPY_PACKET:
diff --git a/net/netfilter/xt_CONNSECMARK.c b/net/netfilter/xt_CONNSECMARK.c
index 211189e..76ca1f2 100644
--- a/net/netfilter/xt_CONNSECMARK.c
+++ b/net/netfilter/xt_CONNSECMARK.c
@@ -8,7 +8,7 @@
* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
* by Henrik Nordstrom <hno@marasystems.com>
*
- * (C) 2006 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ * (C) 2006,2008 Red Hat, Inc., James Morris <jmorris@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -94,6 +94,12 @@
{
const struct xt_connsecmark_target_info *info = targinfo;
+ if (strcmp(tablename, "mangle") && strcmp(tablename, "security")) {
+ printk(KERN_INFO PFX "target only valid in the \'mangle\' "
+ "or \'security\' tables, not \'%s\'.\n", tablename);
+ return false;
+ }
+
switch (info->mode) {
case CONNSECMARK_SAVE:
case CONNSECMARK_RESTORE:
@@ -126,7 +132,6 @@
.destroy = connsecmark_tg_destroy,
.target = connsecmark_tg,
.targetsize = sizeof(struct xt_connsecmark_target_info),
- .table = "mangle",
.me = THIS_MODULE,
},
{
@@ -136,7 +141,6 @@
.destroy = connsecmark_tg_destroy,
.target = connsecmark_tg,
.targetsize = sizeof(struct xt_connsecmark_target_info),
- .table = "mangle",
.me = THIS_MODULE,
},
};
diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c
index c028485..94f87ee 100644
--- a/net/netfilter/xt_SECMARK.c
+++ b/net/netfilter/xt_SECMARK.c
@@ -5,7 +5,7 @@
* Based on the nfmark match by:
* (C) 1999-2001 Marc Boucher <marc@mbsi.ca>
*
- * (C) 2006 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ * (C) 2006,2008 Red Hat, Inc., James Morris <jmorris@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -89,6 +89,12 @@
{
struct xt_secmark_target_info *info = targinfo;
+ if (strcmp(tablename, "mangle") && strcmp(tablename, "security")) {
+ printk(KERN_INFO PFX "target only valid in the \'mangle\' "
+ "or \'security\' tables, not \'%s\'.\n", tablename);
+ return false;
+ }
+
if (mode && mode != info->mode) {
printk(KERN_INFO PFX "mode already set to %hu cannot mix with "
"rules for mode %hu\n", mode, info->mode);
@@ -127,7 +133,6 @@
.destroy = secmark_tg_destroy,
.target = secmark_tg,
.targetsize = sizeof(struct xt_secmark_target_info),
- .table = "mangle",
.me = THIS_MODULE,
},
{
@@ -137,7 +142,6 @@
.destroy = secmark_tg_destroy,
.target = secmark_tg,
.targetsize = sizeof(struct xt_secmark_target_info),
- .table = "mangle",
.me = THIS_MODULE,
},
};
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 9b97f80..6507c02 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -759,7 +759,7 @@
* 0: continue
* 1: repeat lookup - reference dropped while waiting for socket memory.
*/
-int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock,
+int netlink_attachskb(struct sock *sk, struct sk_buff *skb,
long *timeo, struct sock *ssk)
{
struct netlink_sock *nlk;
@@ -892,7 +892,7 @@
return err;
}
- err = netlink_attachskb(sk, skb, nonblock, &timeo, ssk);
+ err = netlink_attachskb(sk, skb, &timeo, ssk);
if (err == 1)
goto retry;
if (err)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 2cee87d..beca640 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -5,8 +5,6 @@
*
* PACKET - implements raw packet sockets.
*
- * Version: $Id: af_packet.c,v 1.61 2002/02/08 03:57:19 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Alan Cox, <gw4pts@gw4pts.ampr.org>
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 5bc1ed4..2130718 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -24,8 +24,6 @@
* Jiri Fojtasek
* fixed requeue routine
* and many others. thanks.
- *
- * $Id: sch_htb.c,v 1.25 2003/12/07 11:08:25 devik Exp devik $
*/
#include <linux/module.h>
#include <linux/types.h>
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 5326348..d5cc731 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 b435a19..d6af466 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..253e5ea 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_freq == 1) {
trans->param_flags =
(trans->param_flags & ~SPP_SACKDELAY) |
SPP_SACKDELAY_DISABLE;
+ } else if (params.sack_freq > 1) {
+ trans->sackfreq = params.sack_freq;
+ trans->param_flags =
+ (trans->param_flags & ~SPP_SACKDELAY) |
+ SPP_SACKDELAY_ENABLE;
}
}
}
@@ -3164,10 +3246,18 @@
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 = 2;
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/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index cc12d5f..019d4b4 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -33,8 +33,6 @@
* 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.
- *
- * $Id$
*/
diff --git a/net/sysctl_net.c b/net/sysctl_net.c
index b4f0525..007c1a6 100644
--- a/net/sysctl_net.c
+++ b/net/sysctl_net.c
@@ -4,7 +4,6 @@
* Begun April 1, 1996, Mike Shaver.
* Added /proc/sys/net directories for each protocol family. [MS]
*
- * $Log: sysctl_net.c,v $
* Revision 1.2 1996/05/08 20:24:40 shaver
* Added bits for NET_BRIDGE and the NET_IPV4_ARP stuff and
* NET_IPV4_IP_FORWARD.
@@ -40,6 +39,27 @@
.lookup = net_ctl_header_lookup,
};
+static LIST_HEAD(net_sysctl_ro_tables);
+static struct list_head *net_ctl_ro_header_lookup(struct ctl_table_root *root,
+ struct nsproxy *namespaces)
+{
+ return &net_sysctl_ro_tables;
+}
+
+static int net_ctl_ro_header_perms(struct ctl_table_root *root,
+ struct nsproxy *namespaces, struct ctl_table *table)
+{
+ if (namespaces->net_ns == &init_net)
+ return table->mode;
+ else
+ return table->mode & ~0222;
+}
+
+static struct ctl_table_root net_sysctl_ro_root = {
+ .lookup = net_ctl_ro_header_lookup,
+ .permissions = net_ctl_ro_header_perms,
+};
+
static int sysctl_net_init(struct net *net)
{
INIT_LIST_HEAD(&net->sysctl_table_headers);
@@ -64,6 +84,7 @@
if (ret)
goto out;
register_sysctl_root(&net_sysctl_root);
+ register_sysctl_root(&net_sysctl_ro_root);
out:
return ret;
}
@@ -80,6 +101,14 @@
}
EXPORT_SYMBOL_GPL(register_net_sysctl_table);
+struct ctl_table_header *register_net_sysctl_rotable(const
+ struct ctl_path *path, struct ctl_table *table)
+{
+ return __register_sysctl_paths(&net_sysctl_ro_root,
+ &init_nsproxy, path, table);
+}
+EXPORT_SYMBOL_GPL(register_net_sysctl_rotable);
+
void unregister_net_sysctl_table(struct ctl_table_header *header)
{
unregister_sysctl_table(header);
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index e788017..a5883b1 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -276,7 +276,7 @@
if (buf) {
msg = buf_msg(buf);
msg_init(msg, BCAST_PROTOCOL, STATE_MSG,
- TIPC_OK, INT_H_SIZE, n_ptr->addr);
+ INT_H_SIZE, n_ptr->addr);
msg_set_mc_netid(msg, tipc_net_id);
msg_set_bcast_ack(msg, mod(n_ptr->bclink.last_in));
msg_set_bcgap_after(msg, n_ptr->bclink.gap_after);
@@ -571,7 +571,7 @@
assert(tipc_cltr_bcast_nodes.count != 0);
bcbuf_set_acks(buf, tipc_cltr_bcast_nodes.count);
msg = buf_msg(buf);
- msg_set_non_seq(msg);
+ msg_set_non_seq(msg, 1);
msg_set_mc_netid(msg, tipc_net_id);
}
diff --git a/net/tipc/cluster.c b/net/tipc/cluster.c
index 4bb3404..bc1db47 100644
--- a/net/tipc/cluster.c
+++ b/net/tipc/cluster.c
@@ -238,7 +238,7 @@
if (buf) {
msg = buf_msg(buf);
memset((char *)msg, 0, size);
- msg_init(msg, ROUTE_DISTRIBUTOR, 0, TIPC_OK, INT_H_SIZE, dest);
+ msg_init(msg, ROUTE_DISTRIBUTOR, 0, INT_H_SIZE, dest);
}
return buf;
}
diff --git a/net/tipc/config.c b/net/tipc/config.c
index c71337a2..ca3544d 100644
--- a/net/tipc/config.c
+++ b/net/tipc/config.c
@@ -2,7 +2,7 @@
* net/tipc/config.c: TIPC configuration management code
*
* Copyright (c) 2002-2006, Ericsson AB
- * Copyright (c) 2004-2006, Wind River Systems
+ * Copyright (c) 2004-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -293,7 +293,6 @@
if (tipc_mode == TIPC_NET_MODE)
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (cannot change node address once assigned)");
- tipc_own_addr = addr;
/*
* Must release all spinlocks before calling start_net() because
@@ -306,7 +305,7 @@
*/
spin_unlock_bh(&config_lock);
- tipc_core_start_net();
+ tipc_core_start_net(addr);
spin_lock_bh(&config_lock);
return tipc_cfg_reply_none();
}
@@ -529,7 +528,7 @@
break;
#endif
case TIPC_CMD_SET_LOG_SIZE:
- rep_tlv_buf = tipc_log_resize(req_tlv_area, req_tlv_space);
+ rep_tlv_buf = tipc_log_resize_cmd(req_tlv_area, req_tlv_space);
break;
case TIPC_CMD_DUMP_LOG:
rep_tlv_buf = tipc_log_dump();
@@ -602,6 +601,10 @@
case TIPC_CMD_GET_NETID:
rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id);
break;
+ case TIPC_CMD_NOT_NET_ADMIN:
+ rep_tlv_buf =
+ tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN);
+ break;
default:
rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (unknown command)");
diff --git a/net/tipc/core.c b/net/tipc/core.c
index 740aac5..3256bd7 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
@@ -117,11 +117,11 @@
* start_net - start TIPC networking sub-systems
*/
-int tipc_core_start_net(void)
+int tipc_core_start_net(unsigned long addr)
{
int res;
- if ((res = tipc_net_start()) ||
+ if ((res = tipc_net_start(addr)) ||
(res = tipc_eth_media_start())) {
tipc_core_stop_net();
}
@@ -164,8 +164,7 @@
tipc_mode = TIPC_NODE_MODE;
if ((res = tipc_handler_start()) ||
- (res = tipc_ref_table_init(tipc_max_ports + tipc_max_subscriptions,
- tipc_random)) ||
+ (res = tipc_ref_table_init(tipc_max_ports, tipc_random)) ||
(res = tipc_reg_start()) ||
(res = tipc_nametbl_init()) ||
(res = tipc_k_signal((Handler)tipc_subscr_start, 0)) ||
@@ -182,7 +181,7 @@
{
int res;
- tipc_log_reinit(CONFIG_TIPC_LOG);
+ tipc_log_resize(CONFIG_TIPC_LOG);
info("Activated (version " TIPC_MOD_VER
" compiled " __DATE__ " " __TIME__ ")\n");
@@ -209,7 +208,7 @@
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..a881f92 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
@@ -178,7 +202,7 @@
extern int tipc_core_start(void);
extern void tipc_core_stop(void);
-extern int tipc_core_start_net(void);
+extern int tipc_core_start_net(unsigned long addr);
extern void tipc_core_stop_net(void);
extern int tipc_handler_start(void);
extern void tipc_handler_stop(void);
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/discover.c b/net/tipc/discover.c
index 5d643e5..1657f0e 100644
--- a/net/tipc/discover.c
+++ b/net/tipc/discover.c
@@ -120,9 +120,8 @@
if (buf) {
msg = buf_msg(buf);
- msg_init(msg, LINK_CONFIG, type, TIPC_OK, DSC_H_SIZE,
- dest_domain);
- msg_set_non_seq(msg);
+ msg_init(msg, LINK_CONFIG, type, DSC_H_SIZE, dest_domain);
+ msg_set_non_seq(msg, 1);
msg_set_req_links(msg, req_links);
msg_set_dest_domain(msg, dest_domain);
msg_set_bc_netid(msg, tipc_net_id);
@@ -156,11 +155,11 @@
/**
* tipc_disc_recv_msg - handle incoming link setup message (request or response)
* @buf: buffer containing message
+ * @b_ptr: bearer that message arrived on
*/
-void tipc_disc_recv_msg(struct sk_buff *buf)
+void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr)
{
- struct bearer *b_ptr = (struct bearer *)TIPC_SKB_CB(buf)->handle;
struct link *link;
struct tipc_media_addr media_addr;
struct tipc_msg *msg = buf_msg(buf);
@@ -200,9 +199,8 @@
dbg(" in own cluster\n");
if (n_ptr == NULL) {
n_ptr = tipc_node_create(orig);
- }
- if (n_ptr == NULL) {
- return;
+ if (!n_ptr)
+ return;
}
spin_lock_bh(&n_ptr->lock);
link = n_ptr->links[b_ptr->identity];
diff --git a/net/tipc/discover.h b/net/tipc/discover.h
index 9fd7587..c36eaeb 100644
--- a/net/tipc/discover.h
+++ b/net/tipc/discover.h
@@ -48,7 +48,7 @@
void tipc_disc_update_link_req(struct link_req *req);
void tipc_disc_stop_link_req(struct link_req *req);
-void tipc_disc_recv_msg(struct sk_buff *buf);
+void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr);
void tipc_disc_link_event(u32 addr, char *name, int up);
#if 0
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 2a26a16..9784a8e 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -51,6 +51,12 @@
/*
+ * Out-of-range value for link session numbers
+ */
+
+#define INVALID_SESSION 0x10000
+
+/*
* Limit for deferred reception queue:
*/
@@ -147,9 +153,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); \
@@ -450,9 +468,9 @@
l_ptr->pmsg = (struct tipc_msg *)&l_ptr->proto_msg;
msg = l_ptr->pmsg;
- msg_init(msg, LINK_PROTOCOL, RESET_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr);
+ msg_init(msg, LINK_PROTOCOL, RESET_MSG, INT_H_SIZE, l_ptr->addr);
msg_set_size(msg, sizeof(l_ptr->proto_msg));
- msg_set_session(msg, tipc_random);
+ msg_set_session(msg, (tipc_random & 0xffff));
msg_set_bearer_id(msg, b_ptr->identity);
strcpy((char *)msg_data(msg), if_name);
@@ -693,10 +711,10 @@
u32 checkpoint = l_ptr->next_in_no;
int was_active_link = tipc_link_is_active(l_ptr);
- msg_set_session(l_ptr->pmsg, msg_session(l_ptr->pmsg) + 1);
+ msg_set_session(l_ptr->pmsg, ((msg_session(l_ptr->pmsg) + 1) & 0xffff));
- /* Link is down, accept any session: */
- l_ptr->peer_session = 0;
+ /* Link is down, accept any session */
+ l_ptr->peer_session = INVALID_SESSION;
/* Prepare for max packet size negotiation */
link_init_max_pkt(l_ptr);
@@ -1110,7 +1128,7 @@
if (bundler) {
msg_init(&bundler_hdr, MSG_BUNDLER, OPEN_MSG,
- TIPC_OK, INT_H_SIZE, l_ptr->addr);
+ INT_H_SIZE, l_ptr->addr);
skb_copy_to_linear_data(bundler, &bundler_hdr,
INT_H_SIZE);
skb_trim(bundler, INT_H_SIZE);
@@ -1374,7 +1392,7 @@
msg_dbg(hdr, ">FRAGMENTING>");
msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
- TIPC_OK, INT_H_SIZE, msg_destnode(hdr));
+ INT_H_SIZE, msg_destnode(hdr));
msg_set_link_selector(&fragm_hdr, sender->publ.ref);
msg_set_size(&fragm_hdr, max_pkt);
msg_set_fragm_no(&fragm_hdr, 1);
@@ -1651,7 +1669,7 @@
struct tipc_msg *msg = buf_msg(buf);
warn("Retransmission failure on link <%s>\n", l_ptr->name);
- tipc_msg_print(TIPC_OUTPUT, msg, ">RETR-FAIL>");
+ tipc_msg_dbg(TIPC_OUTPUT, msg, ">RETR-FAIL>");
if (l_ptr->addr) {
@@ -1748,21 +1766,6 @@
l_ptr->retransm_queue_head = l_ptr->retransm_queue_size = 0;
}
-/*
- * link_recv_non_seq: Receive packets which are outside
- * the link sequence flow
- */
-
-static void link_recv_non_seq(struct sk_buff *buf)
-{
- struct tipc_msg *msg = buf_msg(buf);
-
- if (msg_user(msg) == LINK_CONFIG)
- tipc_disc_recv_msg(buf);
- else
- tipc_bclink_recv_pkt(buf);
-}
-
/**
* link_insert_deferred_queue - insert deferred messages back into receive chain
*/
@@ -1839,7 +1842,7 @@
{
read_lock_bh(&tipc_net_lock);
while (head) {
- struct bearer *b_ptr;
+ struct bearer *b_ptr = (struct bearer *)tb_ptr;
struct node *n_ptr;
struct link *l_ptr;
struct sk_buff *crs;
@@ -1850,9 +1853,6 @@
u32 released = 0;
int type;
- b_ptr = (struct bearer *)tb_ptr;
- TIPC_SKB_CB(buf)->handle = b_ptr;
-
head = head->next;
/* Ensure message is well-formed */
@@ -1871,7 +1871,10 @@
msg = buf_msg(buf);
if (unlikely(msg_non_seq(msg))) {
- link_recv_non_seq(buf);
+ if (msg_user(msg) == LINK_CONFIG)
+ tipc_disc_recv_msg(buf, b_ptr);
+ else
+ tipc_bclink_recv_pkt(buf);
continue;
}
@@ -1978,8 +1981,6 @@
if (link_recv_changeover_msg(&l_ptr, &buf)) {
msg = buf_msg(buf);
seq_no = msg_seqno(msg);
- TIPC_SKB_CB(buf)->handle
- = b_ptr;
if (type == ORIGINAL_MSG)
goto deliver;
goto protocol_check;
@@ -2263,7 +2264,8 @@
switch (msg_type(msg)) {
case RESET_MSG:
- if (!link_working_unknown(l_ptr) && l_ptr->peer_session) {
+ if (!link_working_unknown(l_ptr) &&
+ (l_ptr->peer_session != INVALID_SESSION)) {
if (msg_session(msg) == l_ptr->peer_session) {
dbg("Duplicate RESET: %u<->%u\n",
msg_session(msg), l_ptr->peer_session);
@@ -2424,7 +2426,7 @@
}
msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
- ORIGINAL_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr);
+ ORIGINAL_MSG, INT_H_SIZE, l_ptr->addr);
msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
msg_set_msgcnt(&tunnel_hdr, msgcount);
dbg("Link changeover requires %u tunnel messages\n", msgcount);
@@ -2479,7 +2481,7 @@
struct tipc_msg tunnel_hdr;
msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
- DUPLICATE_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr);
+ DUPLICATE_MSG, INT_H_SIZE, l_ptr->addr);
msg_set_msgcnt(&tunnel_hdr, l_ptr->out_queue_size);
msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
iter = l_ptr->first_out;
@@ -2672,10 +2674,12 @@
u32 pack_sz = link_max_pkt(l_ptr);
u32 fragm_sz = pack_sz - INT_H_SIZE;
u32 fragm_no = 1;
- u32 destaddr = msg_destnode(inmsg);
+ u32 destaddr;
if (msg_short(inmsg))
destaddr = l_ptr->addr;
+ else
+ destaddr = msg_destnode(inmsg);
if (msg_routed(inmsg))
msg_set_prevnode(inmsg, tipc_own_addr);
@@ -2683,7 +2687,7 @@
/* Prepare reusable fragment header: */
msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
- TIPC_OK, INT_H_SIZE, destaddr);
+ INT_H_SIZE, destaddr);
msg_set_link_selector(&fragm_hdr, msg_link_selector(inmsg));
msg_set_long_msgno(&fragm_hdr, mod(l_ptr->long_msg_seq_no++));
msg_set_fragm_no(&fragm_hdr, fragm_no);
diff --git a/net/tipc/msg.c b/net/tipc/msg.c
index 696a863..73dcd00 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);
@@ -228,13 +230,10 @@
switch (usr) {
case CONN_MANAGER:
- case NAME_DISTRIBUTOR:
case TIPC_LOW_IMPORTANCE:
case TIPC_MEDIUM_IMPORTANCE:
case TIPC_HIGH_IMPORTANCE:
case TIPC_CRITICAL_IMPORTANCE:
- if (msg_short(msg))
- break; /* No error */
switch (msg_errcode(msg)) {
case TIPC_OK:
break;
@@ -315,9 +314,11 @@
}
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/msg.h b/net/tipc/msg.h
index ad487e8..7ee6ae23 100644
--- a/net/tipc/msg.h
+++ b/net/tipc/msg.h
@@ -2,7 +2,7 @@
* net/tipc/msg.h: Include file for TIPC message header routines
*
* Copyright (c) 2000-2007, Ericsson AB
- * Copyright (c) 2005-2007, Wind River Systems
+ * Copyright (c) 2005-2008, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -75,6 +75,14 @@
m->hdr[w] |= htonl(val);
}
+static inline void msg_swap_words(struct tipc_msg *msg, u32 a, u32 b)
+{
+ u32 temp = msg->hdr[a];
+
+ msg->hdr[a] = msg->hdr[b];
+ msg->hdr[b] = temp;
+}
+
/*
* Word 0
*/
@@ -119,9 +127,9 @@
return msg_bits(m, 0, 20, 1);
}
-static inline void msg_set_non_seq(struct tipc_msg *m)
+static inline void msg_set_non_seq(struct tipc_msg *m, u32 n)
{
- msg_set_bits(m, 0, 20, 1, 1);
+ msg_set_bits(m, 0, 20, 1, n);
}
static inline int msg_dest_droppable(struct tipc_msg *m)
@@ -224,6 +232,25 @@
msg_set_bits(m, 2, 0, 0xffff, n);
}
+/*
+ * TIPC may utilize the "link ack #" and "link seq #" fields of a short
+ * message header to hold the destination node for the message, since the
+ * normal "dest node" field isn't present. This cache is only referenced
+ * when required, so populating the cache of a longer message header is
+ * harmless (as long as the header has the two link sequence fields present).
+ *
+ * Note: Host byte order is OK here, since the info never goes off-card.
+ */
+
+static inline u32 msg_destnode_cache(struct tipc_msg *m)
+{
+ return m->hdr[2];
+}
+
+static inline void msg_set_destnode_cache(struct tipc_msg *m, u32 dnode)
+{
+ m->hdr[2] = dnode;
+}
/*
* Words 3-10
@@ -325,7 +352,7 @@
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
w0:|vers |msg usr|hdr sz |n|resrv| packet size |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- w1:|m typ|rsv=0| sequence gap | broadcast ack no |
+ w1:|m typ| sequence gap | broadcast ack no |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
w2:| link level ack no/bc_gap_from | seq no / bcast_gap_to |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -388,12 +415,12 @@
static inline u32 msg_seq_gap(struct tipc_msg *m)
{
- return msg_bits(m, 1, 16, 0xff);
+ return msg_bits(m, 1, 16, 0x1fff);
}
static inline void msg_set_seq_gap(struct tipc_msg *m, u32 n)
{
- msg_set_bits(m, 1, 16, 0xff, n);
+ msg_set_bits(m, 1, 16, 0x1fff, n);
}
static inline u32 msg_req_links(struct tipc_msg *m)
@@ -696,7 +723,7 @@
static inline void msg_init(struct tipc_msg *m, u32 user, u32 type,
- u32 err, u32 hsize, u32 destnode)
+ u32 hsize, u32 destnode)
{
memset(m, 0, hsize);
msg_set_version(m);
@@ -705,7 +732,6 @@
msg_set_size(m, hsize);
msg_set_prevnode(m, tipc_own_addr);
msg_set_type(m, type);
- msg_set_errcode(m, err);
if (!msg_short(m)) {
msg_set_orignode(m, tipc_own_addr);
msg_set_destnode(m, destnode);
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
index 39fd161..10a6989 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)
/**
@@ -106,8 +103,7 @@
if (buf != NULL) {
msg = buf_msg(buf);
- msg_init(msg, NAME_DISTRIBUTOR, type, TIPC_OK,
- LONG_H_SIZE, dest);
+ msg_init(msg, NAME_DISTRIBUTOR, type, LONG_H_SIZE, dest);
msg_set_size(msg, LONG_H_SIZE + size);
}
return buf;
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index ac7dfdd..096f7bd 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -74,7 +74,7 @@
* @first_free: array index of first unused sub-sequence entry
* @ns_list: links to adjacent name sequences in hash chain
* @subscriptions: list of subscriptions for this 'type'
- * @lock: spinlock controlling access to name sequence structure
+ * @lock: spinlock controlling access to publication lists of all sub-sequences
*/
struct name_seq {
@@ -905,6 +905,9 @@
struct sub_seq *sseq;
char typearea[11];
+ if (seq->first_free == 0)
+ return;
+
sprintf(typearea, "%-10u", seq->type);
if (depth == 1) {
@@ -915,7 +918,9 @@
for (sseq = seq->sseqs; sseq != &seq->sseqs[seq->first_free]; sseq++) {
if ((lowbound <= sseq->upper) && (upbound >= sseq->lower)) {
tipc_printf(buf, "%s ", typearea);
+ spin_lock_bh(&seq->lock);
subseq_list(sseq, buf, depth, index);
+ spin_unlock_bh(&seq->lock);
sprintf(typearea, "%10s", " ");
}
}
@@ -1050,15 +1055,12 @@
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/net.c b/net/tipc/net.c
index c39c762..cc51fa48 100644
--- a/net/tipc/net.c
+++ b/net/tipc/net.c
@@ -266,7 +266,7 @@
tipc_link_send(buf, dnode, msg_link_selector(msg));
}
-int tipc_net_start(void)
+int tipc_net_start(u32 addr)
{
char addr_string[16];
int res;
@@ -274,6 +274,10 @@
if (tipc_mode != TIPC_NODE_MODE)
return -ENOPROTOOPT;
+ tipc_subscr_stop();
+ tipc_cfg_stop();
+
+ tipc_own_addr = addr;
tipc_mode = TIPC_NET_MODE;
tipc_named_reinit();
tipc_port_reinit();
@@ -284,10 +288,10 @@
(res = tipc_bclink_init())) {
return res;
}
- tipc_subscr_stop();
- tipc_cfg_stop();
+
tipc_k_signal((Handler)tipc_subscr_start, 0);
tipc_k_signal((Handler)tipc_cfg_init, 0);
+
info("Started in network mode\n");
info("Own node address %s, network identity %u\n",
addr_string_fill(addr_string, tipc_own_addr), tipc_net_id);
diff --git a/net/tipc/net.h b/net/tipc/net.h
index a6a0e99..d154ac2 100644
--- a/net/tipc/net.h
+++ b/net/tipc/net.h
@@ -58,7 +58,7 @@
struct node *tipc_net_select_remote_node(u32 addr, u32 ref);
u32 tipc_net_select_router(u32 addr, u32 ref);
-int tipc_net_start(void);
+int tipc_net_start(u32 addr);
void tipc_net_stop(void);
#endif
diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c
index 6a7f7b4..c387217 100644
--- a/net/tipc/netlink.c
+++ b/net/tipc/netlink.c
@@ -2,7 +2,7 @@
* net/tipc/netlink.c: TIPC configuration handling
*
* Copyright (c) 2005-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -45,15 +45,17 @@
struct nlmsghdr *req_nlh = info->nlhdr;
struct tipc_genlmsghdr *req_userhdr = info->userhdr;
int hdr_space = NLMSG_SPACE(GENL_HDRLEN + TIPC_GENL_HDRLEN);
+ u16 cmd;
if ((req_userhdr->cmd & 0xC000) && (!capable(CAP_NET_ADMIN)))
- rep_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN);
+ cmd = TIPC_CMD_NOT_NET_ADMIN;
else
- rep_buf = tipc_cfg_do_cmd(req_userhdr->dest,
- req_userhdr->cmd,
- NLMSG_DATA(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN,
- NLMSG_PAYLOAD(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN),
- hdr_space);
+ cmd = req_userhdr->cmd;
+
+ rep_buf = tipc_cfg_do_cmd(req_userhdr->dest, cmd,
+ NLMSG_DATA(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN,
+ NLMSG_PAYLOAD(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN),
+ hdr_space);
if (rep_buf) {
skb_push(rep_buf, hdr_space);
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 598f4d3..34e9a2b 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -52,16 +52,40 @@
struct node *tipc_nodes = NULL; /* sorted list of nodes within cluster */
+static DEFINE_SPINLOCK(node_create_lock);
+
u32 tipc_own_tag = 0;
+/**
+ * tipc_node_create - create neighboring node
+ *
+ * Currently, this routine is called by neighbor discovery code, which holds
+ * net_lock for reading only. We must take node_create_lock to ensure a node
+ * isn't created twice if two different bearers discover the node at the same
+ * time. (It would be preferable to switch to holding net_lock in write mode,
+ * but this is a non-trivial change.)
+ */
+
struct node *tipc_node_create(u32 addr)
{
struct cluster *c_ptr;
struct node *n_ptr;
struct node **curr_node;
+ spin_lock_bh(&node_create_lock);
+
+ for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) {
+ if (addr < n_ptr->addr)
+ break;
+ if (addr == n_ptr->addr) {
+ spin_unlock_bh(&node_create_lock);
+ return n_ptr;
+ }
+ }
+
n_ptr = kzalloc(sizeof(*n_ptr),GFP_ATOMIC);
if (!n_ptr) {
+ spin_unlock_bh(&node_create_lock);
warn("Node creation failed, no memory\n");
return NULL;
}
@@ -71,6 +95,7 @@
c_ptr = tipc_cltr_create(addr);
}
if (!c_ptr) {
+ spin_unlock_bh(&node_create_lock);
kfree(n_ptr);
return NULL;
}
@@ -91,6 +116,7 @@
}
}
(*curr_node) = n_ptr;
+ spin_unlock_bh(&node_create_lock);
return n_ptr;
}
diff --git a/net/tipc/port.c b/net/tipc/port.c
index 2f58064..2e0cff4 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,17 +240,12 @@
return 0;
}
- tipc_port_lock(ref);
p_ptr->publ.usr_handle = usr_handle;
p_ptr->publ.max_pkt = MAX_PKT_DEFAULT;
p_ptr->publ.ref = ref;
msg = &p_ptr->publ.phdr;
- msg_init(msg, TIPC_LOW_IMPORTANCE, TIPC_NAMED_MSG, TIPC_OK, LONG_H_SIZE,
- 0);
- msg_set_orignode(msg, tipc_own_addr);
- msg_set_prevnode(msg, tipc_own_addr);
+ msg_init(msg, importance, TIPC_NAMED_MSG, LONG_H_SIZE, 0);
msg_set_origport(msg, ref);
- msg_set_importance(msg,importance);
p_ptr->last_in_seqno = 41;
p_ptr->sent = 1;
INIT_LIST_HEAD(&p_ptr->wait_list);
@@ -262,7 +260,7 @@
INIT_LIST_HEAD(&p_ptr->port_list);
list_add_tail(&p_ptr->port_list, &ports);
spin_unlock_bh(&tipc_port_list_lock);
- tipc_port_unlock(p_ptr);
+ *tp_ptr = &p_ptr->publ;
return ref;
}
@@ -402,10 +400,10 @@
buf = buf_acquire(LONG_H_SIZE);
if (buf) {
msg = buf_msg(buf);
- msg_init(msg, usr, type, err, LONG_H_SIZE, destnode);
+ msg_init(msg, usr, type, LONG_H_SIZE, destnode);
+ msg_set_errcode(msg, err);
msg_set_destport(msg, destport);
msg_set_origport(msg, origport);
- msg_set_destnode(msg, destnode);
msg_set_orignode(msg, orignode);
msg_set_transp_seqno(msg, seqno);
msg_set_msgcnt(msg, ack);
@@ -446,17 +444,19 @@
return data_sz;
}
rmsg = buf_msg(rbuf);
- msg_init(rmsg, imp, msg_type(msg), err, hdr_sz, msg_orignode(msg));
+ msg_init(rmsg, imp, msg_type(msg), hdr_sz, msg_orignode(msg));
+ msg_set_errcode(rmsg, err);
msg_set_destport(rmsg, msg_origport(msg));
- msg_set_prevnode(rmsg, tipc_own_addr);
msg_set_origport(rmsg, msg_destport(msg));
- if (msg_short(msg))
+ if (msg_short(msg)) {
msg_set_orignode(rmsg, tipc_own_addr);
- else
+ /* leave name type & instance as zeroes */
+ } else {
msg_set_orignode(rmsg, msg_destnode(msg));
+ msg_set_nametype(rmsg, msg_nametype(msg));
+ msg_set_nameinst(rmsg, msg_nameinst(msg));
+ }
msg_set_size(rmsg, data_sz + hdr_sz);
- msg_set_nametype(rmsg, msg_nametype(msg));
- msg_set_nameinst(rmsg, msg_nameinst(msg));
skb_copy_to_linear_data_offset(rbuf, hdr_sz, msg_data(msg), data_sz);
/* send self-abort message when rejecting on a connected port */
@@ -778,6 +778,7 @@
msg = &p_ptr->publ.phdr;
if (msg_orignode(msg) == tipc_own_addr)
break;
+ msg_set_prevnode(msg, tipc_own_addr);
msg_set_orignode(msg, tipc_own_addr);
}
spin_unlock_bh(&tipc_port_list_lock);
@@ -838,17 +839,14 @@
u32 peer_node = port_peernode(p_ptr);
tipc_port_unlock(p_ptr);
- if (unlikely(!connected)) {
- if (unlikely(published))
- goto reject;
- tipc_connect2port(dref,&orig);
- }
- if (unlikely(msg_origport(msg) != peer_port))
- goto reject;
- if (unlikely(msg_orignode(msg) != peer_node))
- goto reject;
if (unlikely(!cb))
goto reject;
+ if (unlikely(!connected)) {
+ if (tipc_connect2port(dref, &orig))
+ goto reject;
+ } else if ((msg_origport(msg) != peer_port) ||
+ (msg_orignode(msg) != peer_node))
+ goto reject;
if (unlikely(++p_ptr->publ.conn_unacked >=
TIPC_FLOW_CONTROL_WIN))
tipc_acknowledge(dref,
@@ -862,9 +860,7 @@
tipc_msg_event cb = up_ptr->msg_cb;
tipc_port_unlock(p_ptr);
- if (unlikely(connected))
- goto reject;
- if (unlikely(!cb))
+ if (unlikely(!cb || connected))
goto reject;
skb_pull(buf, msg_hdr_sz(msg));
cb(usr_handle, dref, &buf, msg_data(msg),
@@ -877,11 +873,7 @@
tipc_named_msg_event cb = up_ptr->named_msg_cb;
tipc_port_unlock(p_ptr);
- if (unlikely(connected))
- goto reject;
- if (unlikely(!cb))
- goto reject;
- if (unlikely(!published))
+ if (unlikely(!cb || connected || !published))
goto reject;
dseq.type = msg_nametype(msg);
dseq.lower = msg_nameinst(msg);
@@ -908,11 +900,10 @@
u32 peer_node = port_peernode(p_ptr);
tipc_port_unlock(p_ptr);
- if (!connected || !cb)
+ if (!cb || !connected)
break;
- if (msg_origport(msg) != peer_port)
- break;
- if (msg_orignode(msg) != peer_node)
+ if ((msg_origport(msg) != peer_port) ||
+ (msg_orignode(msg) != peer_node))
break;
tipc_disconnect(dref);
skb_pull(buf, msg_hdr_sz(msg));
@@ -924,7 +915,7 @@
tipc_msg_err_event cb = up_ptr->err_cb;
tipc_port_unlock(p_ptr);
- if (connected || !cb)
+ if (!cb || connected)
break;
skb_pull(buf, msg_hdr_sz(msg));
cb(usr_handle, dref, &buf, msg_data(msg),
@@ -937,7 +928,7 @@
up_ptr->named_err_cb;
tipc_port_unlock(p_ptr);
- if (connected || !cb)
+ if (!cb || connected)
break;
dseq.type = msg_nametype(msg);
dseq.lower = msg_nameinst(msg);
@@ -1053,6 +1044,7 @@
{
struct user_port *up_ptr;
struct port *p_ptr;
+ struct tipc_port *tp_ptr;
u32 ref;
up_ptr = kmalloc(sizeof(*up_ptr), GFP_ATOMIC);
@@ -1060,12 +1052,13 @@
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..0326d30 100644
--- a/net/tipc/subscr.c
+++ b/net/tipc/subscr.c
@@ -1,8 +1,8 @@
/*
- * net/tipc/subscr.c: TIPC subscription service
+ * net/tipc/subscr.c: TIPC network topology service
*
* Copyright (c) 2000-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -36,27 +36,24 @@
#include "core.h"
#include "dbg.h"
-#include "subscr.h"
#include "name_table.h"
+#include "port.h"
#include "ref.h"
+#include "subscr.h"
/**
* struct subscriber - TIPC network topology subscriber
- * @ref: object reference to subscriber object itself
- * @lock: pointer to spinlock controlling access to subscriber object
+ * @port_ref: object reference to server port connecting to subscriber
+ * @lock: pointer to spinlock controlling access to subscriber's server port
* @subscriber_list: adjacent subscribers in top. server's list of subscribers
* @subscription_list: list of subscription objects for this subscriber
- * @port_ref: object reference to port used to communicate with subscriber
- * @swap: indicates if subscriber uses opposite endianness in its messages
*/
struct subscriber {
- u32 ref;
+ u32 port_ref;
spinlock_t *lock;
struct list_head subscriber_list;
struct list_head subscription_list;
- u32 port_ref;
- int swap;
};
/**
@@ -88,13 +85,14 @@
static u32 htohl(u32 in, int swap)
{
- char *c = (char *)∈
-
- return swap ? ((c[3] << 3) + (c[2] << 2) + (c[1] << 1) + c[0]) : in;
+ return swap ? (u32)___constant_swab32(in) : in;
}
/**
* subscr_send_event - send a message containing a tipc_event to the subscriber
+ *
+ * Note: Must not hold subscriber's server port lock, since tipc_send() will
+ * try to take the lock if the message is rejected and returned!
*/
static void subscr_send_event(struct subscription *sub,
@@ -109,12 +107,12 @@
msg_sect.iov_base = (void *)&sub->evt;
msg_sect.iov_len = sizeof(struct tipc_event);
- sub->evt.event = htohl(event, sub->owner->swap);
- sub->evt.found_lower = htohl(found_lower, sub->owner->swap);
- sub->evt.found_upper = htohl(found_upper, sub->owner->swap);
- sub->evt.port.ref = htohl(port_ref, sub->owner->swap);
- sub->evt.port.node = htohl(node, sub->owner->swap);
- tipc_send(sub->owner->port_ref, 1, &msg_sect);
+ sub->evt.event = htohl(event, sub->swap);
+ sub->evt.found_lower = htohl(found_lower, sub->swap);
+ sub->evt.found_upper = htohl(found_upper, sub->swap);
+ sub->evt.port.ref = htohl(port_ref, sub->swap);
+ sub->evt.port.node = htohl(node, sub->swap);
+ tipc_send(sub->server_ref, 1, &msg_sect);
}
/**
@@ -151,13 +149,12 @@
u32 node,
int must)
{
- dbg("Rep overlap %u:%u,%u<->%u,%u\n", sub->seq.type, sub->seq.lower,
- sub->seq.upper, found_lower, found_upper);
if (!tipc_subscr_overlap(sub, found_lower, found_upper))
return;
if (!must && !(sub->filter & TIPC_SUB_PORTS))
return;
- subscr_send_event(sub, found_lower, found_upper, event, port_ref, node);
+
+ sub->event_cb(sub, found_lower, found_upper, event, port_ref, node);
}
/**
@@ -166,20 +163,18 @@
static void subscr_timeout(struct subscription *sub)
{
- struct subscriber *subscriber;
- u32 subscriber_ref;
+ struct port *server_port;
- /* Validate subscriber reference (in case subscriber is terminating) */
+ /* Validate server port reference (in case subscriber is terminating) */
- subscriber_ref = sub->owner->ref;
- subscriber = (struct subscriber *)tipc_ref_lock(subscriber_ref);
- if (subscriber == NULL)
+ server_port = tipc_port_lock(sub->server_ref);
+ if (server_port == NULL)
return;
/* Validate timeout (in case subscription is being cancelled) */
if (sub->timeout == TIPC_WAIT_FOREVER) {
- tipc_ref_unlock(subscriber_ref);
+ tipc_port_unlock(server_port);
return;
}
@@ -187,19 +182,21 @@
tipc_nametbl_unsubscribe(sub);
- /* Notify subscriber of timeout, then unlink subscription */
+ /* Unlink subscription from subscriber */
- subscr_send_event(sub,
- sub->evt.s.seq.lower,
- sub->evt.s.seq.upper,
- TIPC_SUBSCR_TIMEOUT,
- 0,
- 0);
list_del(&sub->subscription_list);
+ /* Release subscriber's server port */
+
+ tipc_port_unlock(server_port);
+
+ /* Notify subscriber of timeout */
+
+ subscr_send_event(sub, sub->evt.s.seq.lower, sub->evt.s.seq.upper,
+ TIPC_SUBSCR_TIMEOUT, 0, 0);
+
/* Now destroy subscription */
- tipc_ref_unlock(subscriber_ref);
k_term_timer(&sub->timer);
kfree(sub);
atomic_dec(&topsrv.subscription_count);
@@ -208,7 +205,7 @@
/**
* subscr_del - delete a subscription within a subscription list
*
- * Called with subscriber locked.
+ * Called with subscriber port locked.
*/
static void subscr_del(struct subscription *sub)
@@ -222,7 +219,7 @@
/**
* subscr_terminate - terminate communication with a subscriber
*
- * Called with subscriber locked. Routine must temporarily release this lock
+ * Called with subscriber port locked. Routine must temporarily release lock
* to enable subscription timeout routine(s) to finish without deadlocking;
* the lock is then reclaimed to allow caller to release it upon return.
* (This should work even in the unlikely event some other thread creates
@@ -232,14 +229,21 @@
static void subscr_terminate(struct subscriber *subscriber)
{
+ u32 port_ref;
struct subscription *sub;
struct subscription *sub_temp;
/* Invalidate subscriber reference */
- tipc_ref_discard(subscriber->ref);
+ port_ref = subscriber->port_ref;
+ subscriber->port_ref = 0;
spin_unlock_bh(subscriber->lock);
+ /* Sever connection to subscriber */
+
+ tipc_shutdown(port_ref);
+ tipc_deleteport(port_ref);
+
/* Destroy any existing subscriptions for subscriber */
list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list,
@@ -253,27 +257,25 @@
subscr_del(sub);
}
- /* Sever connection to subscriber */
-
- tipc_shutdown(subscriber->port_ref);
- tipc_deleteport(subscriber->port_ref);
-
/* Remove subscriber from topology server's subscriber list */
spin_lock_bh(&topsrv.lock);
list_del(&subscriber->subscriber_list);
spin_unlock_bh(&topsrv.lock);
- /* Now destroy subscriber */
+ /* Reclaim subscriber lock */
spin_lock_bh(subscriber->lock);
+
+ /* Now destroy subscriber */
+
kfree(subscriber);
}
/**
* subscr_cancel - handle subscription cancellation request
*
- * Called with subscriber locked. Routine must temporarily release this lock
+ * Called with subscriber port locked. Routine must temporarily release lock
* to enable the subscription timeout routine to finish without deadlocking;
* the lock is then reclaimed to allow caller to release it upon return.
*
@@ -316,27 +318,25 @@
/**
* subscr_subscribe - create subscription for subscriber
*
- * Called with subscriber locked
+ * Called with subscriber port locked.
*/
-static void subscr_subscribe(struct tipc_subscr *s,
- struct subscriber *subscriber)
+static struct subscription *subscr_subscribe(struct tipc_subscr *s,
+ struct subscriber *subscriber)
{
struct subscription *sub;
+ int swap;
- /* Determine/update subscriber's endianness */
+ /* Determine subscriber's endianness */
- if (s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE))
- subscriber->swap = 0;
- else
- subscriber->swap = 1;
+ swap = !(s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE));
/* Detect & process a subscription cancellation request */
- if (s->filter & htohl(TIPC_SUB_CANCEL, subscriber->swap)) {
- s->filter &= ~htohl(TIPC_SUB_CANCEL, subscriber->swap);
+ if (s->filter & htohl(TIPC_SUB_CANCEL, swap)) {
+ s->filter &= ~htohl(TIPC_SUB_CANCEL, swap);
subscr_cancel(s, subscriber);
- return;
+ return NULL;
}
/* Refuse subscription if global limit exceeded */
@@ -345,63 +345,66 @@
warn("Subscription rejected, subscription limit reached (%u)\n",
tipc_max_subscriptions);
subscr_terminate(subscriber);
- return;
+ return NULL;
}
/* Allocate subscription object */
- sub = kzalloc(sizeof(*sub), GFP_ATOMIC);
+ sub = kmalloc(sizeof(*sub), GFP_ATOMIC);
if (!sub) {
warn("Subscription rejected, no memory\n");
subscr_terminate(subscriber);
- return;
+ return NULL;
}
/* Initialize subscription object */
- sub->seq.type = htohl(s->seq.type, subscriber->swap);
- sub->seq.lower = htohl(s->seq.lower, subscriber->swap);
- sub->seq.upper = htohl(s->seq.upper, subscriber->swap);
- sub->timeout = htohl(s->timeout, subscriber->swap);
- sub->filter = htohl(s->filter, subscriber->swap);
+ sub->seq.type = htohl(s->seq.type, swap);
+ sub->seq.lower = htohl(s->seq.lower, swap);
+ sub->seq.upper = htohl(s->seq.upper, swap);
+ sub->timeout = htohl(s->timeout, swap);
+ sub->filter = htohl(s->filter, swap);
if ((!(sub->filter & TIPC_SUB_PORTS)
== !(sub->filter & TIPC_SUB_SERVICE))
|| (sub->seq.lower > sub->seq.upper)) {
warn("Subscription rejected, illegal request\n");
kfree(sub);
subscr_terminate(subscriber);
- return;
+ return NULL;
}
- memcpy(&sub->evt.s, s, sizeof(struct tipc_subscr));
- INIT_LIST_HEAD(&sub->subscription_list);
+ sub->event_cb = subscr_send_event;
INIT_LIST_HEAD(&sub->nameseq_list);
list_add(&sub->subscription_list, &subscriber->subscription_list);
+ sub->server_ref = subscriber->port_ref;
+ sub->swap = swap;
+ memcpy(&sub->evt.s, s, sizeof(struct tipc_subscr));
atomic_inc(&topsrv.subscription_count);
if (sub->timeout != TIPC_WAIT_FOREVER) {
k_init_timer(&sub->timer,
(Handler)subscr_timeout, (unsigned long)sub);
k_start_timer(&sub->timer, sub->timeout);
}
- sub->owner = subscriber;
- tipc_nametbl_subscribe(sub);
+
+ return sub;
}
/**
* subscr_conn_shutdown_event - handle termination request from subscriber
+ *
+ * Called with subscriber's server port unlocked.
*/
static void subscr_conn_shutdown_event(void *usr_handle,
- u32 portref,
+ u32 port_ref,
struct sk_buff **buf,
unsigned char const *data,
unsigned int size,
int reason)
{
- struct subscriber *subscriber;
+ struct subscriber *subscriber = usr_handle;
spinlock_t *subscriber_lock;
- subscriber = tipc_ref_lock((u32)(unsigned long)usr_handle);
- if (subscriber == NULL)
+ if (tipc_port_lock(port_ref) == NULL)
return;
subscriber_lock = subscriber->lock;
@@ -411,6 +414,8 @@
/**
* subscr_conn_msg_event - handle new subscription request from subscriber
+ *
+ * Called with subscriber's server port unlocked.
*/
static void subscr_conn_msg_event(void *usr_handle,
@@ -419,20 +424,46 @@
const unchar *data,
u32 size)
{
- struct subscriber *subscriber;
+ struct subscriber *subscriber = usr_handle;
spinlock_t *subscriber_lock;
+ struct subscription *sub;
- subscriber = tipc_ref_lock((u32)(unsigned long)usr_handle);
- if (subscriber == NULL)
+ /*
+ * Lock subscriber's server port (& make a local copy of lock pointer,
+ * in case subscriber is deleted while processing subscription request)
+ */
+
+ if (tipc_port_lock(port_ref) == NULL)
return;
subscriber_lock = subscriber->lock;
- if (size != sizeof(struct tipc_subscr))
- subscr_terminate(subscriber);
- else
- subscr_subscribe((struct tipc_subscr *)data, subscriber);
- spin_unlock_bh(subscriber_lock);
+ if (size != sizeof(struct tipc_subscr)) {
+ subscr_terminate(subscriber);
+ spin_unlock_bh(subscriber_lock);
+ } else {
+ sub = subscr_subscribe((struct tipc_subscr *)data, subscriber);
+ spin_unlock_bh(subscriber_lock);
+ if (sub != NULL) {
+
+ /*
+ * We must release the server port lock before adding a
+ * subscription to the name table since TIPC needs to be
+ * able to (re)acquire the port lock if an event message
+ * issued by the subscription process is rejected and
+ * returned. The subscription cannot be deleted while
+ * it is being added to the name table because:
+ * a) the single-threading of the native API port code
+ * ensures the subscription cannot be cancelled and
+ * the subscriber connection cannot be broken, and
+ * b) the name table lock ensures the subscription
+ * timeout code cannot delete the subscription,
+ * so the subscription object is still protected.
+ */
+
+ tipc_nametbl_subscribe(sub);
+ }
+ }
}
/**
@@ -448,16 +479,10 @@
struct tipc_portid const *orig,
struct tipc_name_seq const *dest)
{
- struct subscriber *subscriber;
- struct iovec msg_sect = {NULL, 0};
- spinlock_t *subscriber_lock;
+ static struct iovec msg_sect = {NULL, 0};
- dbg("subscr_named_msg_event: orig = %x own = %x,\n",
- orig->node, tipc_own_addr);
- if (size && (size != sizeof(struct tipc_subscr))) {
- warn("Subscriber rejected, invalid subscription size\n");
- return;
- }
+ struct subscriber *subscriber;
+ u32 server_port_ref;
/* Create subscriber object */
@@ -468,17 +493,11 @@
}
INIT_LIST_HEAD(&subscriber->subscription_list);
INIT_LIST_HEAD(&subscriber->subscriber_list);
- subscriber->ref = tipc_ref_acquire(subscriber, &subscriber->lock);
- if (subscriber->ref == 0) {
- warn("Subscriber rejected, reference table exhausted\n");
- kfree(subscriber);
- return;
- }
- /* Establish a connection to subscriber */
+ /* Create server port & establish connection to subscriber */
tipc_createport(topsrv.user_ref,
- (void *)(unsigned long)subscriber->ref,
+ subscriber,
importance,
NULL,
NULL,
@@ -490,32 +509,36 @@
&subscriber->port_ref);
if (subscriber->port_ref == 0) {
warn("Subscriber rejected, unable to create port\n");
- tipc_ref_discard(subscriber->ref);
kfree(subscriber);
return;
}
tipc_connect2port(subscriber->port_ref, orig);
+ /* Lock server port (& save lock address for future use) */
+
+ subscriber->lock = tipc_port_lock(subscriber->port_ref)->publ.lock;
/* Add subscriber to topology server's subscriber list */
- tipc_ref_lock(subscriber->ref);
spin_lock_bh(&topsrv.lock);
list_add(&subscriber->subscriber_list, &topsrv.subscriber_list);
spin_unlock_bh(&topsrv.lock);
- /*
- * Subscribe now if message contains a subscription,
- * otherwise send an empty response to complete connection handshaking
- */
+ /* Unlock server port */
- subscriber_lock = subscriber->lock;
- if (size)
- subscr_subscribe((struct tipc_subscr *)data, subscriber);
- else
- tipc_send(subscriber->port_ref, 1, &msg_sect);
+ server_port_ref = subscriber->port_ref;
+ spin_unlock_bh(subscriber->lock);
- spin_unlock_bh(subscriber_lock);
+ /* Send an ACK- to complete connection handshaking */
+
+ tipc_send(server_port_ref, 1, &msg_sect);
+
+ /* Handle optional subscription request */
+
+ if (size != 0) {
+ subscr_conn_msg_event(subscriber, server_port_ref,
+ buf, data, size);
+ }
}
int tipc_subscr_start(void)
@@ -574,8 +597,8 @@
list_for_each_entry_safe(subscriber, subscriber_temp,
&topsrv.subscriber_list,
subscriber_list) {
- tipc_ref_lock(subscriber->ref);
subscriber_lock = subscriber->lock;
+ spin_lock_bh(subscriber_lock);
subscr_terminate(subscriber);
spin_unlock_bh(subscriber_lock);
}
diff --git a/net/tipc/subscr.h b/net/tipc/subscr.h
index 93a8e67..45d89bf 100644
--- a/net/tipc/subscr.h
+++ b/net/tipc/subscr.h
@@ -1,8 +1,8 @@
/*
- * net/tipc/subscr.h: Include file for TIPC subscription service
+ * net/tipc/subscr.h: Include file for TIPC network topology service
*
* Copyright (c) 2003-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -37,34 +37,44 @@
#ifndef _TIPC_SUBSCR_H
#define _TIPC_SUBSCR_H
+struct subscription;
+
+typedef void (*tipc_subscr_event) (struct subscription *sub,
+ u32 found_lower, u32 found_upper,
+ u32 event, u32 port_ref, u32 node);
+
/**
* struct subscription - TIPC network topology subscription object
* @seq: name sequence associated with subscription
* @timeout: duration of subscription (in ms)
* @filter: event filtering to be done for subscription
- * @evt: template for events generated by subscription
- * @subscription_list: adjacent subscriptions in subscriber's subscription list
+ * @event_cb: routine invoked when a subscription event is detected
+ * @timer: timer governing subscription duration (optional)
* @nameseq_list: adjacent subscriptions in name sequence's subscription list
- * @timer_ref: reference to timer governing subscription duration (may be NULL)
- * @owner: pointer to subscriber object associated with this subscription
+ * @subscription_list: adjacent subscriptions in subscriber's subscription list
+ * @server_ref: object reference of server port associated with subscription
+ * @swap: indicates if subscriber uses opposite endianness in its messages
+ * @evt: template for events generated by subscription
*/
struct subscription {
struct tipc_name_seq seq;
u32 timeout;
u32 filter;
- struct tipc_event evt;
- struct list_head subscription_list;
- struct list_head nameseq_list;
+ tipc_subscr_event event_cb;
struct timer_list timer;
- struct subscriber *owner;
+ struct list_head nameseq_list;
+ struct list_head subscription_list;
+ u32 server_ref;
+ int swap;
+ struct tipc_event evt;
};
-int tipc_subscr_overlap(struct subscription * sub,
+int tipc_subscr_overlap(struct subscription *sub,
u32 found_lower,
u32 found_upper);
-void tipc_subscr_report_overlap(struct subscription * sub,
+void tipc_subscr_report_overlap(struct subscription *sub,
u32 found_lower,
u32 found_upper,
u32 event,
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index e18cd36..392e80e 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -8,8 +8,6 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Version: $Id: af_unix.c,v 1.133 2002/02/08 03:57:19 davem Exp $
- *
* Fixes:
* Linus Torvalds : Assorted bug cures.
* Niibe Yutaka : async I/O support.
diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c
index 9ab31a3..b210a88 100644
--- a/net/wanrouter/wanmain.c
+++ b/net/wanrouter/wanmain.c
@@ -350,9 +350,9 @@
* o execute requested action or pass command to the device driver
*/
-int wanrouter_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+long wanrouter_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
+ struct inode *inode = file->f_path.dentry->d_inode;
int err = 0;
struct proc_dir_entry *dent;
struct wan_device *wandev;
@@ -372,6 +372,7 @@
if (wandev->magic != ROUTER_MAGIC)
return -EINVAL;
+ lock_kernel();
switch (cmd) {
case ROUTER_SETUP:
err = wanrouter_device_setup(wandev, data);
@@ -403,6 +404,7 @@
err = wandev->ioctl(wandev, cmd, arg);
else err = -EINVAL;
}
+ unlock_kernel();
return err;
}
diff --git a/net/wanrouter/wanproc.c b/net/wanrouter/wanproc.c
index 5bebe40..267f7ff 100644
--- a/net/wanrouter/wanproc.c
+++ b/net/wanrouter/wanproc.c
@@ -278,7 +278,7 @@
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
- .ioctl = wanrouter_ioctl,
+ .unlocked_ioctl = wanrouter_ioctl,
};
/*
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 80afacd..f1da0b9 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -143,8 +143,11 @@
int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
char *newname)
{
+ struct cfg80211_registered_device *drv;
int idx, taken = -1, result, digits;
+ mutex_lock(&cfg80211_drv_mutex);
+
/* prohibit calling the thing phy%d when %d is not its number */
sscanf(newname, PHY_NAME "%d%n", &idx, &taken);
if (taken == strlen(newname) && idx != rdev->idx) {
@@ -156,14 +159,30 @@
* deny the name if it is phy<idx> where <idx> is printed
* without leading zeroes. taken == strlen(newname) here
*/
+ result = -EINVAL;
if (taken == strlen(PHY_NAME) + digits)
- return -EINVAL;
+ goto out_unlock;
}
- /* this will check for collisions */
+
+ /* Ignore nop renames */
+ result = 0;
+ if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0)
+ goto out_unlock;
+
+ /* Ensure another device does not already have this name. */
+ list_for_each_entry(drv, &cfg80211_drv_list, list) {
+ result = -EINVAL;
+ if (strcmp(newname, dev_name(&drv->wiphy.dev)) == 0)
+ goto out_unlock;
+ }
+
+ /* this will only check for collisions in sysfs
+ * which is not even always compiled in.
+ */
result = device_rename(&rdev->wiphy.dev, newname);
if (result)
- return result;
+ goto out_unlock;
if (!debugfs_rename(rdev->wiphy.debugfsdir->d_parent,
rdev->wiphy.debugfsdir,
@@ -172,9 +191,13 @@
printk(KERN_ERR "cfg80211: failed to rename debugfs dir to %s!\n",
newname);
- nl80211_notify_dev_rename(rdev);
+ result = 0;
+out_unlock:
+ mutex_unlock(&cfg80211_drv_mutex);
+ if (result == 0)
+ nl80211_notify_dev_rename(rdev);
- return 0;
+ return result;
}
/* exported functions */
diff --git a/net/wireless/radiotap.c b/net/wireless/radiotap.c
index 28fbd0b..f591871 100644
--- a/net/wireless/radiotap.c
+++ b/net/wireless/radiotap.c
@@ -59,23 +59,21 @@
return -EINVAL;
/* sanity check for allowed length and radiotap length field */
- if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len)))
+ if (max_length < get_unaligned_le16(&radiotap_header->it_len))
return -EINVAL;
iterator->rtheader = radiotap_header;
- iterator->max_length = le16_to_cpu(get_unaligned(
- &radiotap_header->it_len));
+ iterator->max_length = get_unaligned_le16(&radiotap_header->it_len);
iterator->arg_index = 0;
- iterator->bitmap_shifter = le32_to_cpu(get_unaligned(
- &radiotap_header->it_present));
+ iterator->bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present);
iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header);
iterator->this_arg = NULL;
/* find payload start allowing for extended bitmap(s) */
if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) {
- while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) &
- (1<<IEEE80211_RADIOTAP_EXT)) {
+ while (get_unaligned_le32(iterator->arg) &
+ (1 << IEEE80211_RADIOTAP_EXT)) {
iterator->arg += sizeof(u32);
/*
@@ -241,8 +239,8 @@
if (iterator->bitmap_shifter & 1) {
/* b31 was set, there is more */
/* move to next u32 bitmap */
- iterator->bitmap_shifter = le32_to_cpu(
- get_unaligned(iterator->next_bitmap));
+ iterator->bitmap_shifter =
+ get_unaligned_le32(iterator->next_bitmap);
iterator->next_bitmap++;
} else
/* no more bitmaps: end */