Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6

This commit is contained in:
David S. Miller 2008-05-15 00:52:37 -07:00
commit f42a44494b
71 changed files with 2544 additions and 2141 deletions

View file

@ -445,9 +445,9 @@ static void adm8211_interrupt_rci(struct ieee80211_hw *dev)
struct ieee80211_rx_status rx_status = {0}; struct ieee80211_rx_status rx_status = {0};
if (priv->pdev->revision < ADM8211_REV_CA) if (priv->pdev->revision < ADM8211_REV_CA)
rx_status.ssi = rssi; rx_status.signal = rssi;
else else
rx_status.ssi = 100 - rssi; rx_status.signal = 100 - rssi;
rx_status.rate_idx = rate; rx_status.rate_idx = rate;
@ -1893,9 +1893,10 @@ static int __devinit adm8211_probe(struct pci_dev *pdev,
dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr); dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr);
/* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */ /* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */
dev->flags = IEEE80211_HW_SIGNAL_UNSPEC;
dev->channel_change_time = 1000; 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 */ dev->queues = 1; /* ADM8211C supports more, maybe ADM8211B too */

View file

@ -1148,7 +1148,6 @@ static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm);
static void airo_networks_free(struct airo_info *ai); static void airo_networks_free(struct airo_info *ai);
struct airo_info { struct airo_info {
struct net_device_stats stats;
struct net_device *dev; struct net_device *dev;
struct list_head dev_list; struct list_head dev_list;
/* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we /* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we
@ -1924,7 +1923,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
if (npacks >= MAXTXQ - 1) { if (npacks >= MAXTXQ - 1) {
netif_stop_queue (dev); netif_stop_queue (dev);
if (npacks > MAXTXQ) { if (npacks > MAXTXQ) {
ai->stats.tx_fifo_errors++; dev->stats.tx_fifo_errors++;
return 1; return 1;
} }
skb_queue_tail (&ai->txq, skb); skb_queue_tail (&ai->txq, skb);
@ -2044,13 +2043,13 @@ static void get_tx_error(struct airo_info *ai, s32 fid)
bap_read(ai, &status, 2, BAP0); bap_read(ai, &status, 2, BAP0);
} }
if (le16_to_cpu(status) & 2) /* Too many retries */ 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 */ 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) & 8) /* Aid fail */
{ } { }
if (le16_to_cpu(status) & 0x10) /* MAC disabled */ 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 */ if (le16_to_cpu(status) & 0x20) /* Association lost */
{ } { }
/* We produce a TXDROP event only for retry or lifetime /* We produce a TXDROP event only for retry or lifetime
@ -2102,7 +2101,7 @@ static void airo_end_xmit(struct net_device *dev) {
for (; i < MAX_FIDS / 2 && (priv->fids[i] & 0xffff0000); i++); for (; i < MAX_FIDS / 2 && (priv->fids[i] & 0xffff0000); i++);
} else { } else {
priv->fids[fid] &= 0xffff; priv->fids[fid] &= 0xffff;
priv->stats.tx_window_errors++; dev->stats.tx_window_errors++;
} }
if (i < MAX_FIDS / 2) if (i < MAX_FIDS / 2)
netif_wake_queue(dev); netif_wake_queue(dev);
@ -2128,7 +2127,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
netif_stop_queue(dev); netif_stop_queue(dev);
if (i == MAX_FIDS / 2) { if (i == MAX_FIDS / 2) {
priv->stats.tx_fifo_errors++; dev->stats.tx_fifo_errors++;
return 1; return 1;
} }
} }
@ -2167,7 +2166,7 @@ static void airo_end_xmit11(struct net_device *dev) {
for (; i < MAX_FIDS && (priv->fids[i] & 0xffff0000); i++); for (; i < MAX_FIDS && (priv->fids[i] & 0xffff0000); i++);
} else { } else {
priv->fids[fid] &= 0xffff; priv->fids[fid] &= 0xffff;
priv->stats.tx_window_errors++; dev->stats.tx_window_errors++;
} }
if (i < MAX_FIDS) if (i < MAX_FIDS)
netif_wake_queue(dev); netif_wake_queue(dev);
@ -2199,7 +2198,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
netif_stop_queue(dev); netif_stop_queue(dev);
if (i == MAX_FIDS) { if (i == MAX_FIDS) {
priv->stats.tx_fifo_errors++; dev->stats.tx_fifo_errors++;
return 1; return 1;
} }
} }
@ -2219,8 +2218,9 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
return 0; 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; StatsRid stats_rid;
__le32 *vals = stats_rid.vals; __le32 *vals = stats_rid.vals;
@ -2232,23 +2232,24 @@ static void airo_read_stats(struct airo_info *ai)
readStatsRid(ai, &stats_rid, RID_STATS, 0); readStatsRid(ai, &stats_rid, RID_STATS, 0);
up(&ai->sem); 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]); 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]); le32_to_cpu(vals[41]);
ai->stats.rx_bytes = le32_to_cpu(vals[92]); dev->stats.rx_bytes = le32_to_cpu(vals[92]);
ai->stats.tx_bytes = le32_to_cpu(vals[91]); dev->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_errors = le32_to_cpu(vals[0]) + le32_to_cpu(vals[2]) +
le32_to_cpu(vals[3]) + le32_to_cpu(vals[4]); le32_to_cpu(vals[3]) + le32_to_cpu(vals[4]);
ai->stats.tx_errors = le32_to_cpu(vals[42]) + ai->stats.tx_fifo_errors; dev->stats.tx_errors = le32_to_cpu(vals[42]) +
ai->stats.multicast = le32_to_cpu(vals[43]); dev->stats.tx_fifo_errors;
ai->stats.collisions = le32_to_cpu(vals[89]); dev->stats.multicast = le32_to_cpu(vals[43]);
dev->stats.collisions = le32_to_cpu(vals[89]);
/* detailed rx_errors: */ /* detailed rx_errors: */
ai->stats.rx_length_errors = le32_to_cpu(vals[3]); dev->stats.rx_length_errors = le32_to_cpu(vals[3]);
ai->stats.rx_crc_errors = le32_to_cpu(vals[4]); dev->stats.rx_crc_errors = le32_to_cpu(vals[4]);
ai->stats.rx_frame_errors = le32_to_cpu(vals[2]); dev->stats.rx_frame_errors = le32_to_cpu(vals[2]);
ai->stats.rx_fifo_errors = le32_to_cpu(vals[0]); dev->stats.rx_fifo_errors = le32_to_cpu(vals[0]);
} }
static struct net_device_stats *airo_get_stats(struct net_device *dev) static struct net_device_stats *airo_get_stats(struct net_device *dev)
@ -2261,10 +2262,10 @@ static struct net_device_stats *airo_get_stats(struct net_device *dev)
set_bit(JOB_STATS, &local->jobs); set_bit(JOB_STATS, &local->jobs);
wake_up_interruptible(&local->thr_wait); wake_up_interruptible(&local->thr_wait);
} else } else
airo_read_stats(local); airo_read_stats(dev);
} }
return &local->stats; return &dev->stats;
} }
static void airo_set_promisc(struct airo_info *ai) { static void airo_set_promisc(struct airo_info *ai) {
@ -3092,7 +3093,7 @@ static int airo_thread(void *data) {
else if (test_bit(JOB_XMIT11, &ai->jobs)) else if (test_bit(JOB_XMIT11, &ai->jobs))
airo_end_xmit11(dev); airo_end_xmit11(dev);
else if (test_bit(JOB_STATS, &ai->jobs)) else if (test_bit(JOB_STATS, &ai->jobs))
airo_read_stats(ai); airo_read_stats(dev);
else if (test_bit(JOB_WSTATS, &ai->jobs)) else if (test_bit(JOB_WSTATS, &ai->jobs))
airo_read_wireless_stats(ai); airo_read_wireless_stats(ai);
else if (test_bit(JOB_PROMISC, &ai->jobs)) else if (test_bit(JOB_PROMISC, &ai->jobs))
@ -3288,7 +3289,7 @@ static irqreturn_t airo_interrupt(int irq, void *dev_id)
skb = dev_alloc_skb( len + hdrlen + 2 + 2 ); skb = dev_alloc_skb( len + hdrlen + 2 + 2 );
if ( !skb ) { if ( !skb ) {
apriv->stats.rx_dropped++; dev->stats.rx_dropped++;
goto badrx; goto badrx;
} }
skb_reserve(skb, 2); /* This way the IP header is aligned */ skb_reserve(skb, 2); /* This way the IP header is aligned */
@ -3556,7 +3557,7 @@ static void mpi_receive_802_3(struct airo_info *ai)
skb = dev_alloc_skb(len); skb = dev_alloc_skb(len);
if (!skb) { if (!skb) {
ai->stats.rx_dropped++; ai->dev->stats.rx_dropped++;
goto badrx; goto badrx;
} }
buffer = skb_put(skb,len); buffer = skb_put(skb,len);
@ -3649,7 +3650,7 @@ void mpi_receive_802_11 (struct airo_info *ai)
skb = dev_alloc_skb( len + hdrlen + 2 ); skb = dev_alloc_skb( len + hdrlen + 2 );
if ( !skb ) { if ( !skb ) {
ai->stats.rx_dropped++; ai->dev->stats.rx_dropped++;
goto badrx; goto badrx;
} }
buffer = (u16*)skb_put (skb, len + hdrlen); buffer = (u16*)skb_put (skb, len + hdrlen);

View file

@ -125,7 +125,7 @@ static inline int arlan_drop_tx(struct net_device *dev)
{ {
struct arlan_private *priv = netdev_priv(dev); struct arlan_private *priv = netdev_priv(dev);
priv->stats.tx_errors++; dev->stats.tx_errors++;
if (priv->Conf->tx_delay_ms) if (priv->Conf->tx_delay_ms)
{ {
priv->tx_done_delayed = jiffies + priv->Conf->tx_delay_ms * HZ / 1000 + 1; priv->tx_done_delayed = jiffies + priv->Conf->tx_delay_ms * HZ / 1000 + 1;
@ -1269,7 +1269,7 @@ static void arlan_tx_done_interrupt(struct net_device *dev, int status)
{ {
IFDEBUG(ARLAN_DEBUG_TX_CHAIN) IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
printk("arlan intr: transmit OK\n"); printk("arlan intr: transmit OK\n");
priv->stats.tx_packets++; dev->stats.tx_packets++;
priv->bad = 0; priv->bad = 0;
priv->reset = 0; priv->reset = 0;
priv->retransmissions = 0; priv->retransmissions = 0;
@ -1496,7 +1496,7 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short
if (skb == NULL) if (skb == NULL)
{ {
printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name); printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name);
priv->stats.rx_dropped++; dev->stats.rx_dropped++;
break; break;
} }
skb_reserve(skb, 2); skb_reserve(skb, 2);
@ -1536,14 +1536,14 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short
} }
netif_rx(skb); netif_rx(skb);
dev->last_rx = jiffies; dev->last_rx = jiffies;
priv->stats.rx_packets++; dev->stats.rx_packets++;
priv->stats.rx_bytes += pkt_len; dev->stats.rx_bytes += pkt_len;
} }
break; break;
default: default:
printk(KERN_ERR "arlan intr: received unknown status\n"); printk(KERN_ERR "arlan intr: received unknown status\n");
priv->stats.rx_crc_errors++; dev->stats.rx_crc_errors++;
break; break;
} }
ARLAN_DEBUG_EXIT("arlan_rx_interrupt"); ARLAN_DEBUG_EXIT("arlan_rx_interrupt");
@ -1719,23 +1719,23 @@ static struct net_device_stats *arlan_statistics(struct net_device *dev)
/* Update the statistics from the device registers. */ /* Update the statistics from the device registers. */
READSHM(priv->stats.collisions, arlan->numReTransmissions, u_int); READSHM(dev->stats.collisions, arlan->numReTransmissions, u_int);
READSHM(priv->stats.rx_crc_errors, arlan->numCRCErrors, u_int); READSHM(dev->stats.rx_crc_errors, arlan->numCRCErrors, u_int);
READSHM(priv->stats.rx_dropped, arlan->numFramesDiscarded, u_int); READSHM(dev->stats.rx_dropped, arlan->numFramesDiscarded, u_int);
READSHM(priv->stats.rx_fifo_errors, arlan->numRXBufferOverflows, u_int); READSHM(dev->stats.rx_fifo_errors, arlan->numRXBufferOverflows, u_int);
READSHM(priv->stats.rx_frame_errors, arlan->numReceiveFramesLost, u_int); READSHM(dev->stats.rx_frame_errors, arlan->numReceiveFramesLost, u_int);
READSHM(priv->stats.rx_over_errors, arlan->numRXOverruns, u_int); READSHM(dev->stats.rx_over_errors, arlan->numRXOverruns, u_int);
READSHM(priv->stats.rx_packets, arlan->numDatagramsReceived, u_int); READSHM(dev->stats.rx_packets, arlan->numDatagramsReceived, u_int);
READSHM(priv->stats.tx_aborted_errors, arlan->numAbortErrors, u_int); READSHM(dev->stats.tx_aborted_errors, arlan->numAbortErrors, u_int);
READSHM(priv->stats.tx_carrier_errors, arlan->numStatusTimeouts, u_int); READSHM(dev->stats.tx_carrier_errors, arlan->numStatusTimeouts, u_int);
READSHM(priv->stats.tx_dropped, arlan->numDatagramsDiscarded, u_int); READSHM(dev->stats.tx_dropped, arlan->numDatagramsDiscarded, u_int);
READSHM(priv->stats.tx_fifo_errors, arlan->numTXUnderruns, u_int); READSHM(dev->stats.tx_fifo_errors, arlan->numTXUnderruns, u_int);
READSHM(priv->stats.tx_packets, arlan->numDatagramsTransmitted, u_int); READSHM(dev->stats.tx_packets, arlan->numDatagramsTransmitted, u_int);
READSHM(priv->stats.tx_window_errors, arlan->numHoldOffs, u_int); READSHM(dev->stats.tx_window_errors, arlan->numHoldOffs, u_int);
ARLAN_DEBUG_EXIT("arlan_statistics"); ARLAN_DEBUG_EXIT("arlan_statistics");
return &priv->stats; return &dev->stats;
} }

View file

@ -330,7 +330,6 @@ struct TxParam
#define TX_RING_SIZE 2 #define TX_RING_SIZE 2
/* Information that need to be kept for each board. */ /* Information that need to be kept for each board. */
struct arlan_private { struct arlan_private {
struct net_device_stats stats;
struct arlan_shmem __iomem * card; struct arlan_shmem __iomem * card;
struct arlan_shmem * conf; struct arlan_shmem * conf;

View file

@ -458,13 +458,11 @@ ath5k_pci_probe(struct pci_dev *pdev,
/* Initialize driver private data */ /* Initialize driver private data */
SET_IEEE80211_DEV(hw, &pdev->dev); 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->extra_tx_headroom = 2;
hw->channel_change_time = 5000; 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->priv;
sc->hw = hw; sc->hw = hw;
sc->pdev = pdev; sc->pdev = pdev;
@ -1787,6 +1785,8 @@ ath5k_tasklet_rx(unsigned long data)
spin_lock(&sc->rxbuflock); spin_lock(&sc->rxbuflock);
do { do {
rxs.flag = 0;
if (unlikely(list_empty(&sc->rxbuf))) { if (unlikely(list_empty(&sc->rxbuf))) {
ATH5K_WARN(sc, "empty rx buf pool\n"); ATH5K_WARN(sc, "empty rx buf pool\n");
break; break;
@ -1893,20 +1893,9 @@ accept:
rxs.freq = sc->curchan->center_freq; rxs.freq = sc->curchan->center_freq;
rxs.band = sc->curband->band; 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; rxs.noise = sc->ah->ah_noise_floor;
/* signal level in dBm */ rxs.signal = rxs.noise + rs.rs_rssi;
rxs.ssi = rxs.noise + rs.rs_rssi; rxs.qual = rs.rs_rssi * 100 / 64;
/*
* "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.antenna = rs.rs_antenna; rxs.antenna = rs.rs_antenna;
rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate); rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);

View file

@ -4119,6 +4119,7 @@ static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah,
rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); AR5K_5210_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
rs->rs_status = 0; rs->rs_status = 0;
rs->rs_phyerr = 0;
/* /*
* Key table status * Key table status
@ -4145,7 +4146,7 @@ static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah,
if (rx_status->rx_status_1 & if (rx_status->rx_status_1 &
AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) { AR5K_5210_RX_DESC_STATUS1_PHY_ERROR) {
rs->rs_status |= AR5K_RXERR_PHY; rs->rs_status |= AR5K_RXERR_PHY;
rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1, rs->rs_phyerr |= AR5K_REG_MS(rx_status->rx_status_1,
AR5K_5210_RX_DESC_STATUS1_PHY_ERROR); AR5K_5210_RX_DESC_STATUS1_PHY_ERROR);
} }
@ -4193,6 +4194,7 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
rs->rs_status = 0; rs->rs_status = 0;
rs->rs_phyerr = 0;
/* /*
* Key table status * Key table status
@ -4215,7 +4217,7 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
if (rx_status->rx_status_1 & if (rx_status->rx_status_1 &
AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) { AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) {
rs->rs_status |= AR5K_RXERR_PHY; rs->rs_status |= AR5K_RXERR_PHY;
rs->rs_phyerr = AR5K_REG_MS(rx_err->rx_error_1, rs->rs_phyerr |= AR5K_REG_MS(rx_err->rx_error_1,
AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE); AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE);
} }

View file

@ -433,7 +433,6 @@ struct atmel_private {
struct net_device *dev; struct net_device *dev;
struct device *sys_dev; struct device *sys_dev;
struct iw_statistics wstats; struct iw_statistics wstats;
struct net_device_stats stats; // device stats
spinlock_t irqlock, timerlock; // spinlocks spinlock_t irqlock, timerlock; // spinlocks
enum { BUS_TYPE_PCCARD, BUS_TYPE_PCI } bus_type; enum { BUS_TYPE_PCCARD, BUS_TYPE_PCI } bus_type;
enum { enum {
@ -694,9 +693,9 @@ static void tx_done_irq(struct atmel_private *priv)
if (type == TX_PACKET_TYPE_DATA) { if (type == TX_PACKET_TYPE_DATA) {
if (status == TX_STATUS_SUCCESS) if (status == TX_STATUS_SUCCESS)
priv->stats.tx_packets++; priv->dev->stats.tx_packets++;
else else
priv->stats.tx_errors++; priv->dev->stats.tx_errors++;
netif_wake_queue(priv->dev); netif_wake_queue(priv->dev);
} }
} }
@ -792,13 +791,13 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
if (priv->card && priv->present_callback && if (priv->card && priv->present_callback &&
!(*priv->present_callback)(priv->card)) { !(*priv->present_callback)(priv->card)) {
priv->stats.tx_errors++; dev->stats.tx_errors++;
dev_kfree_skb(skb); dev_kfree_skb(skb);
return 0; return 0;
} }
if (priv->station_state != STATION_STATE_READY) { if (priv->station_state != STATION_STATE_READY) {
priv->stats.tx_errors++; dev->stats.tx_errors++;
dev_kfree_skb(skb); dev_kfree_skb(skb);
return 0; return 0;
} }
@ -815,7 +814,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
initial + 18 (+30-12) */ initial + 18 (+30-12) */
if (!(buff = find_tx_buff(priv, len + 18))) { if (!(buff = find_tx_buff(priv, len + 18))) {
priv->stats.tx_dropped++; dev->stats.tx_dropped++;
spin_unlock_irqrestore(&priv->irqlock, flags); spin_unlock_irqrestore(&priv->irqlock, flags);
spin_unlock_bh(&priv->timerlock); spin_unlock_bh(&priv->timerlock);
netif_stop_queue(dev); netif_stop_queue(dev);
@ -851,7 +850,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
/* low bit of first byte of destination tells us if broadcast */ /* 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); tx_update_descriptor(priv, *(skb->data) & 0x01, len + 18, buff, TX_PACKET_TYPE_DATA);
dev->trans_start = jiffies; dev->trans_start = jiffies;
priv->stats.tx_bytes += len; dev->stats.tx_bytes += len;
spin_unlock_irqrestore(&priv->irqlock, flags); spin_unlock_irqrestore(&priv->irqlock, flags);
spin_unlock_bh(&priv->timerlock); spin_unlock_bh(&priv->timerlock);
@ -895,7 +894,7 @@ static void fast_rx_path(struct atmel_private *priv,
} }
if (!(skb = dev_alloc_skb(msdu_size + 14))) { if (!(skb = dev_alloc_skb(msdu_size + 14))) {
priv->stats.rx_dropped++; priv->dev->stats.rx_dropped++;
return; return;
} }
@ -908,7 +907,7 @@ static void fast_rx_path(struct atmel_private *priv,
crc = crc32_le(crc, skbp + 12, msdu_size); crc = crc32_le(crc, skbp + 12, msdu_size);
atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + 30 + msdu_size, 4); atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + 30 + msdu_size, 4);
if ((crc ^ 0xffffffff) != netcrc) { if ((crc ^ 0xffffffff) != netcrc) {
priv->stats.rx_crc_errors++; priv->dev->stats.rx_crc_errors++;
dev_kfree_skb(skb); dev_kfree_skb(skb);
return; return;
} }
@ -924,8 +923,8 @@ static void fast_rx_path(struct atmel_private *priv,
skb->protocol = eth_type_trans(skb, priv->dev); skb->protocol = eth_type_trans(skb, priv->dev);
skb->ip_summed = CHECKSUM_NONE; skb->ip_summed = CHECKSUM_NONE;
netif_rx(skb); netif_rx(skb);
priv->stats.rx_bytes += 12 + msdu_size; priv->dev->stats.rx_bytes += 12 + msdu_size;
priv->stats.rx_packets++; priv->dev->stats.rx_packets++;
} }
/* Test to see if the packet in card memory at packet_loc has a valid CRC /* Test to see if the packet in card memory at packet_loc has a valid CRC
@ -991,7 +990,7 @@ static void frag_rx_path(struct atmel_private *priv,
crc = crc32_le(crc, &priv->rx_buf[12], msdu_size); crc = crc32_le(crc, &priv->rx_buf[12], msdu_size);
atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4);
if ((crc ^ 0xffffffff) != netcrc) { if ((crc ^ 0xffffffff) != netcrc) {
priv->stats.rx_crc_errors++; priv->dev->stats.rx_crc_errors++;
memset(priv->frag_source, 0xff, 6); memset(priv->frag_source, 0xff, 6);
} }
} }
@ -1009,7 +1008,7 @@ static void frag_rx_path(struct atmel_private *priv,
msdu_size); msdu_size);
atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4);
if ((crc ^ 0xffffffff) != netcrc) { if ((crc ^ 0xffffffff) != netcrc) {
priv->stats.rx_crc_errors++; priv->dev->stats.rx_crc_errors++;
memset(priv->frag_source, 0xff, 6); memset(priv->frag_source, 0xff, 6);
more_frags = 1; /* don't send broken assembly */ more_frags = 1; /* don't send broken assembly */
} }
@ -1021,7 +1020,7 @@ static void frag_rx_path(struct atmel_private *priv,
if (!more_frags) { /* last one */ if (!more_frags) { /* last one */
memset(priv->frag_source, 0xff, 6); memset(priv->frag_source, 0xff, 6);
if (!(skb = dev_alloc_skb(priv->frag_len + 14))) { if (!(skb = dev_alloc_skb(priv->frag_len + 14))) {
priv->stats.rx_dropped++; priv->dev->stats.rx_dropped++;
} else { } else {
skb_reserve(skb, 2); skb_reserve(skb, 2);
memcpy(skb_put(skb, priv->frag_len + 12), memcpy(skb_put(skb, priv->frag_len + 12),
@ -1031,8 +1030,8 @@ static void frag_rx_path(struct atmel_private *priv,
skb->protocol = eth_type_trans(skb, priv->dev); skb->protocol = eth_type_trans(skb, priv->dev);
skb->ip_summed = CHECKSUM_NONE; skb->ip_summed = CHECKSUM_NONE;
netif_rx(skb); netif_rx(skb);
priv->stats.rx_bytes += priv->frag_len + 12; priv->dev->stats.rx_bytes += priv->frag_len + 12;
priv->stats.rx_packets++; priv->dev->stats.rx_packets++;
} }
} }
} else } else
@ -1057,7 +1056,7 @@ static void rx_done_irq(struct atmel_private *priv)
if (status == 0xc1) /* determined by experiment */ if (status == 0xc1) /* determined by experiment */
priv->wstats.discard.nwid++; priv->wstats.discard.nwid++;
else else
priv->stats.rx_errors++; priv->dev->stats.rx_errors++;
goto next; goto next;
} }
@ -1065,7 +1064,7 @@ static void rx_done_irq(struct atmel_private *priv)
rx_packet_loc = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_POS_OFFSET, priv->rx_desc_head)); rx_packet_loc = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_POS_OFFSET, priv->rx_desc_head));
if (msdu_size < 30) { if (msdu_size < 30) {
priv->stats.rx_errors++; priv->dev->stats.rx_errors++;
goto next; goto next;
} }
@ -1123,7 +1122,7 @@ static void rx_done_irq(struct atmel_private *priv)
msdu_size -= 4; msdu_size -= 4;
crc = crc32_le(crc, (unsigned char *)&priv->rx_buf, msdu_size); crc = crc32_le(crc, (unsigned char *)&priv->rx_buf, msdu_size);
if ((crc ^ 0xffffffff) != (*((u32 *)&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; goto next;
} }
} }
@ -1250,12 +1249,6 @@ static irqreturn_t service_interrupt(int irq, void *dev_id)
} }
} }
static struct net_device_stats *atmel_get_stats(struct net_device *dev)
{
struct atmel_private *priv = netdev_priv(dev);
return &priv->stats;
}
static struct iw_statistics *atmel_get_wireless_stats(struct net_device *dev) static struct iw_statistics *atmel_get_wireless_stats(struct net_device *dev)
{ {
struct atmel_private *priv = netdev_priv(dev); struct atmel_private *priv = netdev_priv(dev);
@ -1518,8 +1511,6 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
priv->crc_ok_cnt = priv->crc_ko_cnt = 0; priv->crc_ok_cnt = priv->crc_ko_cnt = 0;
} else } else
priv->probe_crc = 0; priv->probe_crc = 0;
memset(&priv->stats, 0, sizeof(priv->stats));
memset(&priv->wstats, 0, sizeof(priv->wstats));
priv->last_qual = jiffies; priv->last_qual = jiffies;
priv->last_beacon_timestamp = 0; priv->last_beacon_timestamp = 0;
memset(priv->frag_source, 0xff, sizeof(priv->frag_source)); memset(priv->frag_source, 0xff, sizeof(priv->frag_source));
@ -1568,7 +1559,6 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
dev->change_mtu = atmel_change_mtu; dev->change_mtu = atmel_change_mtu;
dev->set_mac_address = atmel_set_mac_address; dev->set_mac_address = atmel_set_mac_address;
dev->hard_start_xmit = start_tx; dev->hard_start_xmit = start_tx;
dev->get_stats = atmel_get_stats;
dev->wireless_handlers = (struct iw_handler_def *)&atmel_handler_def; dev->wireless_handlers = (struct iw_handler_def *)&atmel_handler_def;
dev->do_ioctl = atmel_ioctl; dev->do_ioctl = atmel_ioctl;
dev->irq = irq; dev->irq = irq;

View file

@ -939,22 +939,6 @@ static inline bool __b43_warn_on_dummy(bool x) { return x; }
# define B43_WARN_ON(x) __b43_warn_on_dummy(unlikely(!!(x))) # define B43_WARN_ON(x) __b43_warn_on_dummy(unlikely(!!(x)))
#endif #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 */ /* Convert an integer to a Q5.2 value */
#define INT_TO_Q52(i) ((i) << 2) #define INT_TO_Q52(i) ((i) << 2)
/* Convert a Q5.2 value to an integer (precision loss!) */ /* Convert a Q5.2 value to an integer (precision loss!) */

View file

@ -199,7 +199,7 @@ static void lo_measure_txctl_values(struct b43_wldev *dev)
if (lb_gain > 10) { if (lb_gain > 10) {
radio_pctl_reg = 0; radio_pctl_reg = 0;
pga = abs(10 - lb_gain) / 6; pga = abs(10 - lb_gain) / 6;
pga = limit_value(pga, 0, 15); pga = clamp_val(pga, 0, 15);
} else { } else {
int cmp_val; int cmp_val;
int tmp; int tmp;
@ -321,7 +321,7 @@ static void lo_measure_gain_values(struct b43_wldev *dev,
phy->lna_lod_gain = 1; phy->lna_lod_gain = 1;
trsw_rx_gain -= 8; 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; phy->pga_gain = trsw_rx_gain / 3;
if (phy->pga_gain >= 5) { if (phy->pga_gain >= 5) {
phy->pga_gain -= 5; phy->pga_gain -= 5;

View file

@ -1182,10 +1182,10 @@ static void handle_irq_noise(struct b43_wldev *dev)
/* Get the noise samples. */ /* Get the noise samples. */
B43_WARN_ON(dev->noisecalc.nr_samples >= 8); B43_WARN_ON(dev->noisecalc.nr_samples >= 8);
i = dev->noisecalc.nr_samples; i = dev->noisecalc.nr_samples;
noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); noise[0] = clamp_val(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); noise[1] = clamp_val(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); noise[2] = clamp_val(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
noise[3] = limit_value(noise[3], 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][0] = phy->nrssi_lt[noise[0]];
dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]]; dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]];
dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]]; dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]];
@ -4466,10 +4466,10 @@ static int b43_wireless_init(struct ssb_device *dev)
/* fill hw info */ /* fill hw info */
hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
IEEE80211_HW_RX_INCLUDES_FCS; IEEE80211_HW_RX_INCLUDES_FCS |
hw->max_signal = 100; IEEE80211_HW_SIGNAL_DBM |
hw->max_rssi = -110; IEEE80211_HW_NOISE_DBM;
hw->max_noise = -110;
hw->queues = b43_modparam_qos ? 4 : 1; hw->queues = b43_modparam_qos ? 4 : 1;
SET_IEEE80211_DEV(hw, dev->dev); SET_IEEE80211_DEV(hw, dev->dev);
if (is_valid_ether_addr(sprom->et1mac)) if (is_valid_ether_addr(sprom->et1mac))

View file

@ -29,8 +29,6 @@
#include "nphy.h" #include "nphy.h"
#include "tables_nphy.h" #include "tables_nphy.h"
#include <linux/delay.h>
void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
{//TODO {//TODO

View file

@ -28,6 +28,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/bitrev.h>
#include "b43.h" #include "b43.h"
#include "phy.h" #include "phy.h"
@ -83,25 +84,9 @@ const u8 b43_radio_channel_codes_bg[] = {
72, 84, 72, 84,
}; };
#define bitrev4(tmp) (bitrev8(tmp) >> 4)
static void b43_phy_initg(struct b43_wldev *dev); 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, static void generate_rfatt_list(struct b43_wldev *dev,
struct b43_rfatt_list *list) struct b43_rfatt_list *list)
{ {
@ -1415,7 +1400,7 @@ static void b43_phy_initg(struct b43_wldev *dev)
* the value 0x7FFFFFFF here. I think that is some weird * the value 0x7FFFFFFF here. I think that is some weird
* compiler optimization in the original driver. * compiler optimization in the original driver.
* Essentially, what we do here is resetting all NRSSI LT * 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_nrssi_hw_update(dev, 0xFFFF); //FIXME?
b43_calc_nrssi_threshold(dev); b43_calc_nrssi_threshold(dev);
@ -1477,13 +1462,13 @@ static s8 b43_phy_estimate_power_out(struct b43_wldev *dev, s8 tssi)
switch (phy->type) { switch (phy->type) {
case B43_PHYTYPE_A: case B43_PHYTYPE_A:
tmp += 0x80; tmp += 0x80;
tmp = limit_value(tmp, 0x00, 0xFF); tmp = clamp_val(tmp, 0x00, 0xFF);
dbm = phy->tssi2dbm[tmp]; dbm = phy->tssi2dbm[tmp];
//TODO: There's a FIXME on the specs //TODO: There's a FIXME on the specs
break; break;
case B43_PHYTYPE_B: case B43_PHYTYPE_B:
case B43_PHYTYPE_G: case B43_PHYTYPE_G:
tmp = limit_value(tmp, 0x00, 0x3F); tmp = clamp_val(tmp, 0x00, 0x3F);
dbm = phy->tssi2dbm[tmp]; dbm = phy->tssi2dbm[tmp];
break; break;
default: default:
@ -1542,8 +1527,8 @@ void b43_put_attenuation_into_ranges(struct b43_wldev *dev,
break; break;
} }
*_rfatt = limit_value(rfatt, rf_min, rf_max); *_rfatt = clamp_val(rfatt, rf_min, rf_max);
*_bbatt = limit_value(bbatt, bb_min, bb_max); *_bbatt = clamp_val(bbatt, bb_min, bb_max);
} }
/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ /* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */
@ -1638,7 +1623,7 @@ void b43_phy_xmitpower(struct b43_wldev *dev)
/* Get desired power (in Q5.2) */ /* Get desired power (in Q5.2) */
desired_pwr = INT_TO_Q52(phy->power_level); desired_pwr = INT_TO_Q52(phy->power_level);
/* And limit it. max_pwr already is Q5.2 */ /* 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)) { if (b43_debug(dev, B43_DBG_XMITPOWER)) {
b43dbg(dev->wl, b43dbg(dev->wl,
"Current TX power output: " Q52_FMT "Current TX power output: " Q52_FMT
@ -1748,7 +1733,7 @@ static inline
f = q; f = q;
i++; i++;
} while (delta >= 2); } 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; return 0;
} }
@ -2274,7 +2259,7 @@ void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val)
for (i = 0; i < 64; i++) { for (i = 0; i < 64; i++) {
tmp = b43_nrssi_hw_read(dev, i); tmp = b43_nrssi_hw_read(dev, i);
tmp -= val; tmp -= val;
tmp = limit_value(tmp, -32, 31); tmp = clamp_val(tmp, -32, 31);
b43_nrssi_hw_write(dev, i, tmp); b43_nrssi_hw_write(dev, i, tmp);
} }
} }
@ -2291,7 +2276,7 @@ void b43_nrssi_mem_update(struct b43_wldev *dev)
tmp = (i - delta) * phy->nrssislope; tmp = (i - delta) * phy->nrssislope;
tmp /= 0x10000; tmp /= 0x10000;
tmp += 0x3A; tmp += 0x3A;
tmp = limit_value(tmp, 0, 0x3F); tmp = clamp_val(tmp, 0, 0x3F);
phy->nrssi_lt[i] = tmp; phy->nrssi_lt[i] = tmp;
} }
} }
@ -2728,7 +2713,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev)
} else } else
threshold = phy->nrssi[1] - 5; 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_read(dev, 0x0020); /* dummy read */
b43_phy_write(dev, 0x0020, b43_phy_write(dev, 0x0020,
(((u16) threshold) << 8) | 0x001C); (((u16) threshold) << 8) | 0x001C);
@ -2779,7 +2764,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev)
else else
a += 32; a += 32;
a = a >> 6; a = a >> 6;
a = limit_value(a, -31, 31); a = clamp_val(a, -31, 31);
b = b * (phy->nrssi[1] - phy->nrssi[0]); b = b * (phy->nrssi[1] - phy->nrssi[0]);
b += (phy->nrssi[0] << 6); b += (phy->nrssi[0] << 6);
@ -2788,7 +2773,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev)
else else
b += 32; b += 32;
b = b >> 6; 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 = b43_phy_read(dev, 0x048A) & 0xF000;
tmp_u16 |= ((u32) b & 0x0000003F); tmp_u16 |= ((u32) b & 0x0000003F);
@ -2891,13 +2876,13 @@ b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode)
} }
radio_stacksave(0x0078); radio_stacksave(0x0078);
tmp = (b43_radio_read16(dev, 0x0078) & 0x001E); tmp = (b43_radio_read16(dev, 0x0078) & 0x001E);
flipped = flip_4bit(tmp); B43_WARN_ON(tmp > 15);
flipped = bitrev4(tmp);
if (flipped < 10 && flipped >= 8) if (flipped < 10 && flipped >= 8)
flipped = 7; flipped = 7;
else if (flipped >= 10) else if (flipped >= 10)
flipped -= 3; flipped -= 3;
flipped = flip_4bit(flipped); flipped = (bitrev4(flipped) << 1) | 0x0020;
flipped = (flipped << 1) | 0x0020;
b43_radio_write16(dev, 0x0078, flipped); b43_radio_write16(dev, 0x0078, flipped);
b43_calc_nrssi_threshold(dev); b43_calc_nrssi_threshold(dev);
@ -3530,7 +3515,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
tmp1 >>= 9; tmp1 >>= 9;
for (i = 0; i < 16; i++) { for (i = 0; i < 16; i++) {
radio78 = ((flip_4bit(i) << 1) | 0x20); radio78 = (bitrev4(i) << 1) | 0x0020;
b43_radio_write16(dev, 0x78, radio78); b43_radio_write16(dev, 0x78, radio78);
udelay(10); udelay(10);
for (j = 0; j < 16; j++) { for (j = 0; j < 16; j++) {

View file

@ -581,12 +581,11 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
// and also find out what the maximum possible value is. // and also find out what the maximum possible value is.
// Fill status.ssi and status.signal fields. // Fill status.ssi and status.signal fields.
} else { } 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_OFDM),
(phystat0 & B43_RX_PHYST0_GAINCTL), (phystat0 & B43_RX_PHYST0_GAINCTL),
(phystat3 & B43_RX_PHYST3_TRSTATE)); (phystat3 & B43_RX_PHYST3_TRSTATE));
/* the next line looks wrong, but is what mac80211 wants */ status.qual = (rxhdr->jssi * 100) / B43_RX_MAX_SSI;
status.signal = (rxhdr->jssi * 100) / B43_RX_MAX_SSI;
} }
if (phystat0 & B43_RX_PHYST0_OFDM) if (phystat0 & B43_RX_PHYST0_OFDM)

View file

@ -823,23 +823,6 @@ void b43legacydbg(struct b43legacy_wl *wl, const char *fmt, ...)
# define b43legacydbg(wl, fmt...) do { /* nothing */ } while (0) # define b43legacydbg(wl, fmt...) do { /* nothing */ } while (0)
#endif /* DEBUG */ #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 */ /* Macros for printing a value in Q5.2 format */
#define Q52_FMT "%u.%u" #define Q52_FMT "%u.%u"
#define Q52_ARG(q52) ((q52) / 4), (((q52) & 3) * 100 / 4) #define Q52_ARG(q52) ((q52) / 4), (((q52) & 3) * 100 / 4)

View file

@ -846,10 +846,10 @@ static void handle_irq_noise(struct b43legacy_wldev *dev)
/* Get the noise samples. */ /* Get the noise samples. */
B43legacy_WARN_ON(dev->noisecalc.nr_samples >= 8); B43legacy_WARN_ON(dev->noisecalc.nr_samples >= 8);
i = dev->noisecalc.nr_samples; i = dev->noisecalc.nr_samples;
noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); noise[0] = clamp_val(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); noise[1] = clamp_val(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1); noise[2] = clamp_val(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
noise[3] = limit_value(noise[3], 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][0] = phy->nrssi_lt[noise[0]];
dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]]; dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]];
dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]]; dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]];
@ -3718,10 +3718,9 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
/* fill hw info */ /* fill hw info */
hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
IEEE80211_HW_RX_INCLUDES_FCS; IEEE80211_HW_RX_INCLUDES_FCS |
hw->max_signal = 100; IEEE80211_HW_SIGNAL_DBM |
hw->max_rssi = -110; IEEE80211_HW_NOISE_DBM;
hw->max_noise = -110;
hw->queues = 1; /* FIXME: hardware has more queues */ hw->queues = 1; /* FIXME: hardware has more queues */
SET_IEEE80211_DEV(hw, dev->dev); SET_IEEE80211_DEV(hw, dev->dev);
if (is_valid_ether_addr(sprom->et1mac)) if (is_valid_ether_addr(sprom->et1mac))

View file

@ -1088,7 +1088,7 @@ static void b43legacy_phy_initg(struct b43legacy_wldev *dev)
* the value 0x7FFFFFFF here. I think that is some weird * the value 0x7FFFFFFF here. I think that is some weird
* compiler optimization in the original driver. * compiler optimization in the original driver.
* Essentially, what we do here is resetting all NRSSI LT * 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_nrssi_hw_update(dev, 0xFFFF);
b43legacy_calc_nrssi_threshold(dev); b43legacy_calc_nrssi_threshold(dev);
@ -1756,7 +1756,7 @@ static s8 b43legacy_phy_estimate_power_out(struct b43legacy_wldev *dev, s8 tssi)
switch (phy->type) { switch (phy->type) {
case B43legacy_PHYTYPE_B: case B43legacy_PHYTYPE_B:
case B43legacy_PHYTYPE_G: case B43legacy_PHYTYPE_G:
tmp = limit_value(tmp, 0x00, 0x3F); tmp = clamp_val(tmp, 0x00, 0x3F);
dbm = phy->tssi2dbm[tmp]; dbm = phy->tssi2dbm[tmp];
break; break;
default: default:
@ -1859,7 +1859,7 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev)
/* find the desired power in Q5.2 - power_level is in dBm /* find the desired power in Q5.2 - power_level is in dBm
* and limit it - max_pwr is already in Q5.2 */ * 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)) if (b43legacy_debug(dev, B43legacy_DBG_XMITPOWER))
b43legacydbg(dev->wl, "Current TX power output: " Q52_FMT b43legacydbg(dev->wl, "Current TX power output: " Q52_FMT
" dBm, Desired TX power output: " Q52_FMT " dBm, Desired TX power output: " Q52_FMT
@ -1905,7 +1905,7 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev)
radio_attenuation++; radio_attenuation++;
} }
} }
baseband_attenuation = limit_value(baseband_attenuation, 0, 11); baseband_attenuation = clamp_val(baseband_attenuation, 0, 11);
txpower = phy->txctl1; txpower = phy->txctl1;
if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) { if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) {
@ -1933,8 +1933,8 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev)
} }
/* Save the control values */ /* Save the control values */
phy->txctl1 = txpower; phy->txctl1 = txpower;
baseband_attenuation = limit_value(baseband_attenuation, 0, 11); baseband_attenuation = clamp_val(baseband_attenuation, 0, 11);
radio_attenuation = limit_value(radio_attenuation, 0, 9); radio_attenuation = clamp_val(radio_attenuation, 0, 9);
phy->rfatt = radio_attenuation; phy->rfatt = radio_attenuation;
phy->bbatt = baseband_attenuation; phy->bbatt = baseband_attenuation;
@ -1979,7 +1979,7 @@ s8 b43legacy_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2)
f = q; f = q;
i++; i++;
} while (delta >= 2); } 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); -127, 128);
return 0; return 0;
} }

View file

@ -357,7 +357,7 @@ void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val)
for (i = 0; i < 64; i++) { for (i = 0; i < 64; i++) {
tmp = b43legacy_nrssi_hw_read(dev, i); tmp = b43legacy_nrssi_hw_read(dev, i);
tmp -= val; tmp -= val;
tmp = limit_value(tmp, -32, 31); tmp = clamp_val(tmp, -32, 31);
b43legacy_nrssi_hw_write(dev, i, tmp); b43legacy_nrssi_hw_write(dev, i, tmp);
} }
} }
@ -375,7 +375,7 @@ void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev)
tmp = (i - delta) * phy->nrssislope; tmp = (i - delta) * phy->nrssislope;
tmp /= 0x10000; tmp /= 0x10000;
tmp += 0x3A; tmp += 0x3A;
tmp = limit_value(tmp, 0, 0x3F); tmp = clamp_val(tmp, 0, 0x3F);
phy->nrssi_lt[i] = tmp; phy->nrssi_lt[i] = tmp;
} }
} }
@ -839,7 +839,7 @@ void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev)
} else } else
threshold = phy->nrssi[1] - 5; 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_read(dev, 0x0020); /* dummy read */
b43legacy_phy_write(dev, 0x0020, (((u16)threshold) << 8) b43legacy_phy_write(dev, 0x0020, (((u16)threshold) << 8)
| 0x001C); | 0x001C);
@ -892,7 +892,7 @@ void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev)
else else
a += 32; a += 32;
a = a >> 6; a = a >> 6;
a = limit_value(a, -31, 31); a = clamp_val(a, -31, 31);
b = b * (phy->nrssi[1] - phy->nrssi[0]); b = b * (phy->nrssi[1] - phy->nrssi[0]);
b += (phy->nrssi[0] << 6); b += (phy->nrssi[0] << 6);
@ -901,7 +901,7 @@ void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev)
else else
b += 32; b += 32;
b = b >> 6; 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 = b43legacy_phy_read(dev, 0x048A) & 0xF000;
tmp_u16 |= ((u32)b & 0x0000003F); tmp_u16 |= ((u32)b & 0x0000003F);
@ -1905,7 +1905,7 @@ void b43legacy_radio_set_txpower_a(struct b43legacy_wldev *dev, u16 txpower)
u16 dac; u16 dac;
u16 ilt; u16 ilt;
txpower = limit_value(txpower, 0, 63); txpower = clamp_val(txpower, 0, 63);
pamp = b43legacy_get_txgain_freq_power_amp(txpower); pamp = b43legacy_get_txgain_freq_power_amp(txpower);
pamp <<= 5; pamp <<= 5;

View file

@ -532,12 +532,12 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
} }
} }
status.ssi = b43legacy_rssi_postprocess(dev, jssi, status.signal = b43legacy_rssi_postprocess(dev, jssi,
(phystat0 & B43legacy_RX_PHYST0_OFDM), (phystat0 & B43legacy_RX_PHYST0_OFDM),
(phystat0 & B43legacy_RX_PHYST0_GAINCTL), (phystat0 & B43legacy_RX_PHYST0_GAINCTL),
(phystat3 & B43legacy_RX_PHYST3_TRSTATE)); (phystat3 & B43legacy_RX_PHYST3_TRSTATE));
status.noise = dev->stats.link_noise; 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 */ /* change to support A PHY */
if (phystat0 & B43legacy_RX_PHYST0_OFDM) if (phystat0 & B43legacy_RX_PHYST0_OFDM)
status.rate_idx = b43legacy_plcp_get_bitrate_idx_ofdm(plcp, false); status.rate_idx = b43legacy_plcp_get_bitrate_idx_ofdm(plcp, false);

View file

@ -96,13 +96,13 @@ config IWLWIFI_DEBUG
control which debug output is sent to the kernel log by setting the control which debug output is sent to the kernel log by setting the
value in 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. 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: 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: You can find the list of debug mask values in:
drivers/net/wireless/iwlwifi/iwl-4965-debug.h drivers/net/wireless/iwlwifi/iwl-4965-debug.h

View file

@ -1,5 +1,6 @@
obj-$(CONFIG_IWLCORE) += iwlcore.o obj-$(CONFIG_IWLCORE) += iwlcore.o
iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.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_DEBUGFS) += iwl-debugfs.o
iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o
iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o
@ -10,7 +11,7 @@ iwl3945-objs := iwl3945-base.o iwl-3945.o iwl-3945-rs.o
iwl3945-$(CONFIG_IWL3945_LEDS) += iwl-3945-led.o iwl3945-$(CONFIG_IWL3945_LEDS) += iwl-3945-led.o
obj-$(CONFIG_IWL4965) += iwl4965.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) ifeq ($(CONFIG_IWL5000),y)
iwl4965-objs += iwl-5000.o iwl4965-objs += iwl-5000.o

View file

@ -520,7 +520,7 @@ static void iwl3945_add_radiotap(struct iwl3945_priv *priv,
{ {
/* First cache any information we need before we overwrite /* First cache any information we need before we overwrite
* the information provided in the skb from the hardware */ * the information provided in the skb from the hardware */
s8 signal = stats->ssi; s8 signal = stats->signal;
s8 noise = 0; s8 noise = 0;
int rate = stats->rate_idx; int rate = stats->rate_idx;
u64 tsf = stats->mactime; u64 tsf = stats->mactime;
@ -693,7 +693,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
} }
/* Convert 3945's rssi indicator to dBm */ /* 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 */ /* Set default noise value to -127 */
if (priv->last_rx_noise == 0) if (priv->last_rx_noise == 0)
@ -712,21 +712,21 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
* Calculate rx_status.signal (quality indicator in %) based on SNR. */ * Calculate rx_status.signal (quality indicator in %) based on SNR. */
if (rx_stats_noise_diff) { if (rx_stats_noise_diff) {
snr = rx_stats_sig_avg / 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); 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); rx_status.noise);
/* If noise info not available, calculate signal quality indicator (%) /* If noise info not available, calculate signal quality indicator (%)
* using just the dBm signal level. */ * using just the dBm signal level. */
} else { } else {
rx_status.noise = priv->last_rx_noise; 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", 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); rx_stats_sig_avg, rx_stats_noise_diff);
header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
@ -736,8 +736,8 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
IWL_DEBUG_STATS_LIMIT("[%c] %d RSSI:%d Signal:%u, Noise:%u, Rate:%u\n", IWL_DEBUG_STATS_LIMIT("[%c] %d RSSI:%d Signal:%u, Noise:%u, Rate:%u\n",
network_packet ? '*' : ' ', network_packet ? '*' : ' ',
le16_to_cpu(rx_hdr->channel), le16_to_cpu(rx_hdr->channel),
rx_status.ssi, rx_status.ssi, rx_status.signal, rx_status.signal,
rx_status.ssi, rx_status.rate_idx); rx_status.noise, rx_status.rate_idx);
#ifdef CONFIG_IWL3945_DEBUG #ifdef CONFIG_IWL3945_DEBUG
if (iwl3945_debug_level & (IWL_DL_RX)) if (iwl3945_debug_level & (IWL_DL_RX))
@ -748,7 +748,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
if (network_packet) { if (network_packet) {
priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp); priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp);
priv->last_tsf = le64_to_cpu(rx_end->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; priv->last_rx_noise = rx_status.noise;
} }

View file

@ -886,6 +886,7 @@ struct iwl3945_priv {
struct work_struct report_work; struct work_struct report_work;
struct work_struct request_scan; struct work_struct request_scan;
struct work_struct beacon_update; struct work_struct beacon_update;
struct work_struct set_monitor;
struct tasklet_struct irq_tasklet; struct tasklet_struct irq_tasklet;

View file

@ -829,7 +829,7 @@ static inline __le32 iwl4965_hw_set_rate_n_flags(u8 rate, u16 flags)
#define IWL49_NUM_QUEUES 16 #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. * Describes up to 2 buffers containing (contiguous) portions of a Tx frame.
* Each buffer must be on dword boundary. * Each buffer must be on dword boundary.
@ -848,7 +848,7 @@ static inline __le32 iwl4965_hw_set_rate_n_flags(u8 rate, u16 flags)
* 31-20: Tx buffer 2 length (bytes) * 31-20: Tx buffer 2 length (bytes)
* 19- 0: Tx buffer 2 address bits [35:16] * 19- 0: Tx buffer 2 address bits [35:16]
*/ */
struct iwl4965_tfd_frame_data { struct iwl_tfd_frame_data {
__le32 tb1_addr; __le32 tb1_addr;
__le32 val1; __le32 val1;
@ -878,7 +878,7 @@ struct iwl4965_tfd_frame_data {
/** /**
* struct iwl4965_tfd_frame * struct iwl_tfd_frame
* *
* Transmit Frame Descriptor (TFD) * Transmit Frame Descriptor (TFD)
* *
@ -905,7 +905,7 @@ struct iwl4965_tfd_frame_data {
* *
* A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx. * 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 val0;
/* __le32 rsvd1:24; */ /* __le32 rsvd1:24; */
/* __le32 num_tbs:5; */ /* __le32 num_tbs:5; */
@ -914,7 +914,7 @@ struct iwl4965_tfd_frame {
#define IWL_num_tbs_SYM val0 #define IWL_num_tbs_SYM val0
/* __le32 rsvd2:1; */ /* __le32 rsvd2:1; */
/* __le32 padding:2; */ /* __le32 padding:2; */
struct iwl4965_tfd_frame_data pa[10]; struct iwl_tfd_frame_data pa[10];
__le32 reserved; __le32 reserved;
} __attribute__ ((packed)); } __attribute__ ((packed));

View file

@ -360,9 +360,9 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
unsigned long state; unsigned long state;
DECLARE_MAC_BUF(mac); 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]; 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 && if (state == HT_AGG_STATE_IDLE &&
rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) { rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) {
@ -662,7 +662,8 @@ static u16 rs_get_supported_rates(struct iwl4965_lq_sta *lq_sta,
} }
} }
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 high = IWL_RATE_INVALID;
u8 low = IWL_RATE_INVALID; u8 low = IWL_RATE_INVALID;
@ -763,7 +764,8 @@ static u32 rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta,
goto out; 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; low = high_low & 0xff;
if (low == IWL_RATE_INVALID) if (low == IWL_RATE_INVALID)
@ -990,7 +992,7 @@ out:
* These control how long we stay using same modulation mode before * These control how long we stay using same modulation mode before
* searching for a new mode. * 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) struct iwl4965_lq_sta *lq_sta)
{ {
IWL_DEBUG_RATE("we are staying in the same table\n"); IWL_DEBUG_RATE("we are staying in the same table\n");
@ -1079,7 +1081,8 @@ static s32 rs_get_best_rate(struct iwl_priv *priv,
new_rate = high = low = start_hi = IWL_RATE_INVALID; new_rate = high = low = start_hi = IWL_RATE_INVALID;
for (; ;) { 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; low = high_low & 0xff;
high = (high_low >> 8) & 0xff; high = (high_low >> 8) & 0xff;
@ -1565,7 +1568,9 @@ static void rs_stay_in_table(struct iwl4965_lq_sta *lq_sta)
int i; int i;
int active_tbl; int active_tbl;
int flush_interval_passed = 0; int flush_interval_passed = 0;
struct iwl_priv *priv;
priv = lq_sta->drv;
active_tbl = lq_sta->active_tbl; active_tbl = lq_sta->active_tbl;
tbl = &(lq_sta->lq_info[active_tbl]); tbl = &(lq_sta->lq_info[active_tbl]);
@ -1838,7 +1843,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
/* (Else) not in search of better modulation mode, try for better /* (Else) not in search of better modulation mode, try for better
* starting rate, while staying in this mode. */ * 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); tbl->lq_type);
low = high_low & 0xff; low = high_low & 0xff;
high = (high_low >> 8) & 0xff; high = (high_low >> 8) & 0xff;
@ -1998,7 +2003,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
(lq_sta->action_counter >= 1)) { (lq_sta->action_counter >= 1)) {
lq_sta->action_counter = 0; lq_sta->action_counter = 0;
IWL_DEBUG_RATE("LQ: STAY in legacy table\n"); IWL_DEBUG_RATE("LQ: STAY in legacy table\n");
rs_set_stay_in_table(1, lq_sta); rs_set_stay_in_table(priv, 1, lq_sta);
} }
/* If we're in an HT mode, and all 3 mode switch actions /* If we're in an HT mode, and all 3 mode switch actions
@ -2015,7 +2020,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
} }
#endif /*CONFIG_IWL4965_HT */ #endif /*CONFIG_IWL4965_HT */
lq_sta->action_counter = 0; lq_sta->action_counter = 0;
rs_set_stay_in_table(0, lq_sta); rs_set_stay_in_table(priv, 0, lq_sta);
} }
/* /*
@ -2169,11 +2174,13 @@ out:
rcu_read_unlock(); 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 iwl4965_lq_sta *lq_sta;
struct iwl_priv *priv;
int i, j; int i, j;
priv = (struct iwl_priv *)priv_rate;
IWL_DEBUG_RATE("create station rate scale window\n"); IWL_DEBUG_RATE("create station rate scale window\n");
lq_sta = kzalloc(sizeof(struct iwl4965_lq_sta), gfp); lq_sta = kzalloc(sizeof(struct iwl4965_lq_sta), gfp);
@ -2443,10 +2450,12 @@ static void rs_clear(void *priv_rate)
IWL_DEBUG_RATE("leave\n"); 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 iwl4965_lq_sta *lq_sta = priv_sta;
struct iwl_priv *priv;
priv = (struct iwl_priv *)priv_rate;
IWL_DEBUG_RATE("enter\n"); IWL_DEBUG_RATE("enter\n");
kfree(lq_sta); kfree(lq_sta);
IWL_DEBUG_RATE("leave\n"); IWL_DEBUG_RATE("leave\n");
@ -2462,6 +2471,9 @@ static int open_file_generic(struct inode *inode, struct file *file)
static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta, static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta,
u32 *rate_n_flags, int index) u32 *rate_n_flags, int index)
{ {
struct iwl_priv *priv;
priv = lq_sta->drv;
if (lq_sta->dbg_fixed_rate) { if (lq_sta->dbg_fixed_rate) {
if (index < 12) { if (index < 12) {
*rate_n_flags = lq_sta->dbg_fixed_rate; *rate_n_flags = lq_sta->dbg_fixed_rate;
@ -2481,10 +2493,12 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
const char __user *user_buf, size_t count, loff_t *ppos) const char __user *user_buf, size_t count, loff_t *ppos)
{ {
struct iwl4965_lq_sta *lq_sta = file->private_data; struct iwl4965_lq_sta *lq_sta = file->private_data;
struct iwl_priv *priv;
char buf[64]; char buf[64];
int buf_size; int buf_size;
u32 parsed_rate; u32 parsed_rate;
priv = lq_sta->drv;
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
buf_size = min(count, sizeof(buf) - 1); buf_size = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, buf_size)) if (copy_from_user(buf, user_buf, buf_size))

View file

@ -50,11 +50,10 @@ static struct iwl_mod_params iwl4965_mod_params = {
.num_of_queues = IWL49_NUM_QUEUES, .num_of_queues = IWL49_NUM_QUEUES,
.enable_qos = 1, .enable_qos = 1,
.amsdu_size_8K = 1, .amsdu_size_8K = 1,
.restart_fw = 1,
/* the rest are 0 by default */ /* the rest are 0 by default */
}; };
static void iwl4965_hw_card_show_info(struct iwl_priv *priv);
#ifdef CONFIG_IWL4965_HT #ifdef CONFIG_IWL4965_HT
static const u16 default_tid_to_tx_fifo[] = { static const u16 default_tid_to_tx_fifo[] = {
@ -224,6 +223,102 @@ static int iwl4965_load_bsm(struct iwl_priv *priv)
return 0; return 0;
} }
/**
* 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;
unsigned long flags;
int ret = 0;
/* 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);
ret = iwl_grab_nic_access(priv);
if (ret) {
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}
/* 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 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) static int is_fat_channel(__le32 rxon_flags)
{ {
return (rxon_flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) || return (rxon_flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) ||
@ -372,178 +467,31 @@ int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
return ret; return ret;
} }
static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq) static int iwl4965_disable_tx_fifo(struct iwl_priv *priv)
{ {
int ret;
unsigned long flags; unsigned long flags;
unsigned int rb_size; int ret;
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv); ret = iwl_grab_nic_access(priv);
if (ret) { if (unlikely(ret)) {
IWL_ERROR("Tx fifo reset failed");
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
return ret; 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, FH_KW_MEM_ADDR_REG,
priv->kw.dma_addr >> 4);
iwl_release_nic_access(priv);
out:
spin_unlock_irqrestore(&priv->lock, flags);
return rc;
}
static int iwl4965_kw_alloc(struct iwl_priv *priv)
{
struct pci_dev *dev = priv->pci_dev;
struct iwl4965_kw *kw = &priv->kw;
kw->size = IWL4965_KW_SIZE; /* TBW need set somewhere else */
kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr);
if (!kw->v_addr)
return -ENOMEM;
return 0;
}
/**
* iwl4965_kw_free - Free the "keep warm" buffer
*/
static void iwl4965_kw_free(struct iwl_priv *priv)
{
struct pci_dev *dev = priv->pci_dev;
struct iwl4965_kw *kw = &priv->kw;
if (kw->v_addr) {
pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr);
memset(kw, 0, sizeof(*kw));
}
}
/**
* iwl4965_txq_ctx_reset - Reset TX queue context
* Destroys all DMA structures and initialise them again
*
* @param priv
* @return error code
*/
static int iwl4965_txq_ctx_reset(struct iwl_priv *priv)
{
int rc = 0;
int txq_id, slots_num;
unsigned long flags;
iwl4965_kw_free(priv);
/* Free all tx/cmd queues and keep-warm buffer */
iwl4965_hw_txq_ctx_free(priv);
/* Alloc keep-warm buffer */
rc = iwl4965_kw_alloc(priv);
if (rc) {
IWL_ERROR("Keep Warm allocation failed");
goto error_kw;
}
spin_lock_irqsave(&priv->lock, flags);
rc = iwl_grab_nic_access(priv);
if (unlikely(rc)) {
IWL_ERROR("TX reset failed");
spin_unlock_irqrestore(&priv->lock, flags);
goto error_reset;
}
/* Turn off all Tx DMA channels */
iwl_write_prph(priv, IWL49_SCD_TXFACT, 0); iwl_write_prph(priv, IWL49_SCD_TXFACT, 0);
iwl_release_nic_access(priv); iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
/* Tell 4965 where to find the keep-warm buffer */ return 0;
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;
} }
static int iwl4965_apm_init(struct iwl_priv *priv) static int iwl4965_apm_init(struct iwl_priv *priv)
{ {
unsigned long flags;
int ret = 0; int ret = 0;
spin_lock_irqsave(&priv->lock, flags);
iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, 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);
@ -575,7 +523,6 @@ static int iwl4965_apm_init(struct iwl_priv *priv)
iwl_release_nic_access(priv); iwl_release_nic_access(priv);
out: out:
spin_unlock_irqrestore(&priv->lock, flags);
return ret; return ret;
} }
@ -621,59 +568,6 @@ static void iwl4965_nic_config(struct iwl_priv *priv)
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
} }
int iwl4965_hw_nic_init(struct iwl_priv *priv)
{
unsigned long flags;
struct iwl4965_rx_queue *rxq = &priv->rxq;
int ret;
/* nic_init */
priv->cfg->ops->lib->apm_ops.init(priv);
spin_lock_irqsave(&priv->lock, flags);
iwl_write32(priv, CSR_INT_COALESCING, 512 / 32);
spin_unlock_irqrestore(&priv->lock, flags);
ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN);
priv->cfg->ops->lib->apm_ops.config(priv);
iwl4965_hw_card_show_info(priv);
/* end nic_init */
/* Allocate the RX queue, or reset if it is already allocated */
if (!rxq->bd) {
ret = iwl4965_rx_queue_alloc(priv);
if (ret) {
IWL_ERROR("Unable to initialize Rx queue\n");
return -ENOMEM;
}
} else
iwl4965_rx_queue_reset(priv, rxq);
iwl4965_rx_replenish(priv);
iwl4965_rx_init(priv, rxq);
spin_lock_irqsave(&priv->lock, flags);
rxq->need_update = 1;
iwl4965_rx_queue_update_write_ptr(priv, rxq);
spin_unlock_irqrestore(&priv->lock, flags);
/* Allocate and init all Tx and Command queues */
ret = iwl4965_txq_ctx_reset(priv);
if (ret)
return ret;
set_bit(STATUS_INIT, &priv->status);
return 0;
}
int iwl4965_hw_nic_stop_master(struct iwl_priv *priv) int iwl4965_hw_nic_stop_master(struct iwl_priv *priv)
{ {
int rc = 0; int rc = 0;
@ -734,7 +628,7 @@ void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv)
} }
/* Deallocate memory for all Tx queues */ /* Deallocate memory for all Tx queues */
iwl4965_hw_txq_ctx_free(priv); iwl_hw_txq_ctx_free(priv);
} }
int iwl4965_hw_nic_reset(struct iwl_priv *priv) int iwl4965_hw_nic_reset(struct iwl_priv *priv)
@ -984,7 +878,7 @@ static void iwl4965_set_wr_ptrs(struct iwl_priv *priv, int txq_id, u32 index)
* NOTE: Acquire priv->lock before calling this function ! * NOTE: Acquire priv->lock before calling this function !
*/ */
static void iwl4965_tx_queue_set_status(struct iwl_priv *priv, 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 tx_fifo_id, int scd_retry)
{ {
int txq_id = txq->q.id; int txq_id = txq->q.id;
@ -1188,82 +1082,6 @@ int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
return 0; return 0;
} }
/**
* iwl4965_hw_txq_ctx_free - Free TXQ Context
*
* Destroy all TX DMA queues and structures
*/
void iwl4965_hw_txq_ctx_free(struct iwl_priv *priv)
{
int txq_id;
/* 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);
}
/**
* 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;
}
/* set card power command */ /* set card power command */
static int iwl4965_set_power(struct iwl_priv *priv, static int iwl4965_set_power(struct iwl_priv *priv,
void *cmd) void *cmd)
@ -2186,7 +2004,7 @@ void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv,
tx->rate_n_flags = iwl4965_hw_set_rate_n_flags(rate_plcp, rate_flags); 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; struct iwl4965_shared *s = priv->shared_virt;
return le32_to_cpu(s->rb_closed) & 0xFFF; return le32_to_cpu(s->rb_closed) & 0xFFF;
@ -2229,46 +2047,11 @@ unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
return (sizeof(*tx_beacon_cmd) + frame_size); return (sizeof(*tx_beacon_cmd) + frame_size);
} }
/*
* Tell 4965 where to find circular buffer of Tx Frame Descriptors for
* given Tx queue, and enable the DMA channel used for that queue.
*
* 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA
* channels supported in hardware.
*/
int iwl4965_hw_tx_queue_init(struct iwl_priv *priv, struct iwl4965_tx_queue *txq)
{
int rc;
unsigned long flags;
int txq_id = txq->q.id;
spin_lock_irqsave(&priv->lock, flags);
rc = iwl_grab_nic_access(priv);
if (rc) {
spin_unlock_irqrestore(&priv->lock, flags);
return rc;
}
/* Circular buffer (TFD queue in DRAM) physical base address */
iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
txq->q.dma_addr >> 8);
/* Enable DMA channel, using same id as for TFD queue */
iwl_write_direct32(
priv, 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;
}
int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,
dma_addr_t addr, u16 len) dma_addr_t addr, u16 len)
{ {
int index, is_odd; int index, is_odd;
struct iwl4965_tfd_frame *tfd = ptr; struct iwl_tfd_frame *tfd = ptr;
u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs); u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs);
/* Each TFD can point to a maximum 20 Tx buffers */ /* Each TFD can point to a maximum 20 Tx buffers */
@ -2298,18 +2081,6 @@ int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,
return 0; return 0;
} }
static void iwl4965_hw_card_show_info(struct iwl_priv *priv)
{
u16 hw_version = iwl_eeprom_query16(priv, EEPROM_4965_BOARD_REVISION);
IWL_DEBUG_INFO("4965ABGN HW Version %u.%u.%u\n",
((hw_version >> 8) & 0x0F),
((hw_version >> 8) >> 4), (hw_version & 0x00FF));
IWL_DEBUG_INFO("4965ABGN PBA Number %.16s\n",
&priv->eeprom[EEPROM_4965_BOARD_PBA]);
}
static int iwl4965_alloc_shared_mem(struct iwl_priv *priv) static int iwl4965_alloc_shared_mem(struct iwl_priv *priv)
{ {
priv->shared_virt = pci_alloc_consistent(priv->pci_dev, priv->shared_virt = pci_alloc_consistent(priv->pci_dev,
@ -2320,6 +2091,8 @@ static int iwl4965_alloc_shared_mem(struct iwl_priv *priv)
memset(priv->shared_virt, 0, sizeof(struct iwl4965_shared)); memset(priv->shared_virt, 0, sizeof(struct iwl4965_shared));
priv->rb_closed_offset = offsetof(struct iwl4965_shared, rb_closed);
return 0; return 0;
} }
@ -2336,7 +2109,7 @@ static void iwl4965_free_shared_mem(struct iwl_priv *priv)
* iwl4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array * 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, 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) u16 byte_cnt)
{ {
int len; int len;
@ -2516,9 +2289,10 @@ static void iwl4965_rx_calc_noise(struct iwl_priv *priv)
priv->last_rx_noise); 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; int change;
s32 temp; s32 temp;
@ -2588,7 +2362,7 @@ static void iwl4965_add_radiotap(struct iwl_priv *priv,
struct ieee80211_rx_status *stats, struct ieee80211_rx_status *stats,
u32 ampdu_status) u32 ampdu_status)
{ {
s8 signal = stats->ssi; s8 signal = stats->signal;
s8 noise = 0; s8 noise = 0;
int rate = stats->rate_idx; int rate = stats->rate_idx;
u64 tsf = stats->mactime; u64 tsf = stats->mactime;
@ -2742,7 +2516,7 @@ static int iwl4965_set_decrypted_flag(struct iwl_priv *priv,
return 0; return 0;
} }
static u32 iwl4965_translate_rx_status(u32 decrypt_in) static u32 iwl4965_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
{ {
u32 decrypt_out = 0; u32 decrypt_out = 0;
@ -2803,10 +2577,10 @@ static u32 iwl4965_translate_rx_status(u32 decrypt_in)
static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data, static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
int include_phy, int include_phy,
struct iwl4965_rx_mem_buffer *rxb, struct iwl_rx_mem_buffer *rxb,
struct ieee80211_rx_status *stats) 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 *rx_start = (include_phy) ?
(struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : NULL; (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : NULL;
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
@ -2843,7 +2617,9 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
rx_start->byte_count = amsdu->byte_count; rx_start->byte_count = amsdu->byte_count;
rx_end = (__le32 *) (((u8 *) hdr) + len); 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); IWL_WARNING("byte count out of range [16,4K] : %d\n", len);
return; return;
} }
@ -2854,7 +2630,7 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
if (!include_phy) { if (!include_phy) {
/* New status scheme, need to translate */ /* New status scheme, need to translate */
ampdu_status_legacy = ampdu_status; 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 */ /* start from MAC */
@ -2886,7 +2662,8 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
} }
/* Calc max signal level (dBm) among 3 possible receivers */ /* 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., /* data from PHY/DSP regarding signal strength, etc.,
* contents are always there, not configurable by host. */ * contents are always there, not configurable by host. */
@ -2930,7 +2707,7 @@ static void iwl4965_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
spin_unlock_irqrestore(&priv->sta_lock, flags); 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) static void iwl4965_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
@ -2963,7 +2740,7 @@ static void iwl4965_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
* proper operation with 4965. * proper operation with 4965.
*/ */
static void iwl4965_dbg_report_frame(struct iwl_priv *priv, 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) struct ieee80211_hdr *header, int group100)
{ {
u32 to_us; u32 to_us;
@ -2990,7 +2767,7 @@ static void iwl4965_dbg_report_frame(struct iwl_priv *priv,
struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt); struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt);
u8 *data = IWL_RX_DATA(pkt); u8 *data = IWL_RX_DATA(pkt);
if (likely(!(iwl_debug_level & IWL_DL_RX))) if (likely(!(priv->debug_level & IWL_DL_RX)))
return; return;
/* MAC header */ /* MAC header */
@ -3093,11 +2870,11 @@ static void iwl4965_dbg_report_frame(struct iwl_priv *priv,
} }
} }
if (print_dump) if (print_dump)
iwl_print_hex_dump(IWL_DL_RX, data, length); iwl_print_hex_dump(priv, IWL_DL_RX, data, length);
} }
#else #else
static inline void iwl4965_dbg_report_frame(struct iwl_priv *priv, 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, struct ieee80211_hdr *header,
int group100) int group100)
{ {
@ -3109,11 +2886,11 @@ static inline void iwl4965_dbg_report_frame(struct iwl_priv *priv,
/* Called for REPLY_RX (legacy ABG frames), or /* Called for REPLY_RX (legacy ABG frames), or
* REPLY_RX_MPDU_CMD (HT high-throughput N frames). */ * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */
static void iwl4965_rx_reply_rx(struct iwl_priv *priv, static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
struct iwl4965_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
struct ieee80211_hdr *header; struct ieee80211_hdr *header;
struct ieee80211_rx_status rx_status; 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 /* Use phy data (Rx signal strength, etc.) contained within
* this rx packet for legacy frames, * this rx packet for legacy frames,
* or phy data cached from REPLY_RX_PHY_CMD for HT frames. */ * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */
@ -3186,7 +2963,7 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp); priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp);
/* Find max signal strength (dBm) among 3 antenna/receiver chains */ /* 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, /* Meaningful noise values are available only from beacon statistics,
* which are gathered only when associated, and indicate noise * which are gathered only when associated, and indicate noise
@ -3195,11 +2972,11 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
if (iwl_is_associated(priv) && if (iwl_is_associated(priv) &&
!test_bit(STATUS_SCANNING, &priv->status)) { !test_bit(STATUS_SCANNING, &priv->status)) {
rx_status.noise = priv->last_rx_noise; 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); rx_status.noise);
} else { } else {
rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; 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. */ /* Reset beacon noise level if not associated. */
@ -3211,12 +2988,19 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
iwl4965_dbg_report_frame(priv, pkt, header, 1); iwl4965_dbg_report_frame(priv, pkt, header, 1);
IWL_DEBUG_STATS_LIMIT("Rssi %d, noise %d, qual %d, TSF %llu\n", 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); (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); network_packet = iwl4965_is_network_packet(priv, header);
if (network_packet) { 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_beacon_time = priv->ucode_beacon_time;
priv->last_tsf = le64_to_cpu(rx_start->timestamp); priv->last_tsf = le64_to_cpu(rx_start->timestamp);
} }
@ -3278,19 +3062,19 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). /* 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. */ * 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, static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv,
struct iwl4965_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
priv->last_phy_res[0] = 1; priv->last_phy_res[0] = 1;
memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]), memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]),
sizeof(struct iwl4965_rx_phy_res)); sizeof(struct iwl4965_rx_phy_res));
} }
static void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv, static void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv,
struct iwl4965_rx_mem_buffer *rxb) struct iwl_rx_mem_buffer *rxb)
{ {
#ifdef CONFIG_IWL4965_RUN_TIME_CALIB #ifdef CONFIG_IWL4965_RUN_TIME_CALIB
struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
struct iwl4965_missed_beacon_notif *missed_beacon; struct iwl4965_missed_beacon_notif *missed_beacon;
missed_beacon = &pkt->u.missed_beacon; missed_beacon = &pkt->u.missed_beacon;
@ -3322,7 +3106,7 @@ static void iwl4965_sta_modify_enable_tid_tx(struct iwl_priv *priv,
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
spin_unlock_irqrestore(&priv->sta_lock, flags); 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);
} }
/** /**
@ -3332,7 +3116,7 @@ static void iwl4965_sta_modify_enable_tid_tx(struct iwl_priv *priv,
* ACK vs. not. This gets sent to mac80211, then to rate scaling algo. * 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, 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* struct iwl4965_compressed_ba_resp*
ba_resp) ba_resp)
@ -3449,7 +3233,7 @@ int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id,
{ {
struct iwl4965_queue *q = &priv->txq[txq_id].q; struct iwl4965_queue *q = &priv->txq[txq_id].q;
u8 *addr = priv->stations[sta_id].sta.sta.addr; u8 *addr = priv->stations[sta_id].sta.sta.addr;
struct iwl4965_tid_data *tid_data = &priv->stations[sta_id].tid[tid]; struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid];
switch (priv->stations[sta_id].tid[tid].agg.state) { switch (priv->stations[sta_id].tid[tid].agg.state) {
case IWL_EMPTYING_HW_QUEUE_DELBA: case IWL_EMPTYING_HW_QUEUE_DELBA:
@ -3495,13 +3279,13 @@ static inline int iwl4965_queue_dec_wrap(int index, int n_bd)
* of frames sent via aggregation. * of frames sent via aggregation.
*/ */
static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, 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; struct iwl4965_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba;
int index; int index;
struct iwl4965_tx_queue *txq = NULL; struct iwl_tx_queue *txq = NULL;
struct iwl4965_ht_agg *agg; struct iwl_ht_agg *agg;
DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac);
/* "flow" corresponds to Tx queue */ /* "flow" corresponds to Tx queue */
@ -3547,13 +3331,16 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv,
* block-ack window (we assume that they've been successfully * block-ack window (we assume that they've been successfully
* transmitted ... if not, it's too late anyway). */ * transmitted ... if not, it's too late anyway). */
if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) { if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) {
/* calculate mac80211 ampdu sw queue to wake */
int ampdu_q =
scd_flow - IWL_BACK_QUEUE_FIRST_ID + priv->hw->queues;
int freed = iwl4965_tx_queue_reclaim(priv, scd_flow, index); int freed = iwl4965_tx_queue_reclaim(priv, scd_flow, index);
priv->stations[ba_resp->sta_id]. priv->stations[ba_resp->sta_id].
tid[ba_resp->tid].tfds_in_queue -= freed; tid[ba_resp->tid].tfds_in_queue -= freed;
if (iwl4965_queue_space(&txq->q) > txq->q.low_mark && if (iwl4965_queue_space(&txq->q) > txq->q.low_mark &&
priv->mac80211_registered && priv->mac80211_registered &&
agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)
ieee80211_wake_queue(priv->hw, scd_flow); ieee80211_wake_queue(priv->hw, ampdu_q);
iwl4965_check_empty_hw_queue(priv, ba_resp->sta_id, iwl4965_check_empty_hw_queue(priv, ba_resp->sta_id,
ba_resp->tid, scd_flow); ba_resp->tid, scd_flow);
} }
@ -3714,103 +3501,6 @@ void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
#ifdef CONFIG_IWL4965_HT #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);
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;
}
void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index, void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index,
struct ieee80211_ht_info *sta_ht_inf) struct ieee80211_ht_info *sta_ht_inf)
{ {
@ -3846,7 +3536,7 @@ void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index,
sta_flags |= cpu_to_le32( sta_flags |= cpu_to_le32(
(u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
if (iwl4965_is_fat_tx_allowed(priv, sta_ht_inf)) if (iwl_is_fat_tx_allowed(priv, sta_ht_inf))
sta_flags |= STA_FLG_FAT_EN_MSK; sta_flags |= STA_FLG_FAT_EN_MSK;
else else
sta_flags &= ~STA_FLG_FAT_EN_MSK; sta_flags &= ~STA_FLG_FAT_EN_MSK;
@ -3874,7 +3564,7 @@ static int iwl4965_rx_agg_start(struct iwl_priv *priv,
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
spin_unlock_irqrestore(&priv->sta_lock, flags); spin_unlock_irqrestore(&priv->sta_lock, flags);
return iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
CMD_ASYNC); CMD_ASYNC);
} }
@ -3895,7 +3585,7 @@ static int iwl4965_rx_agg_stop(struct iwl_priv *priv,
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
spin_unlock_irqrestore(&priv->sta_lock, flags); spin_unlock_irqrestore(&priv->sta_lock, flags);
return iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
CMD_ASYNC); CMD_ASYNC);
} }
@ -3925,7 +3615,7 @@ static int iwl4965_tx_agg_start(struct ieee80211_hw *hw, const u8 *ra,
int ssn = -1; int ssn = -1;
int ret = 0; int ret = 0;
unsigned long flags; unsigned long flags;
struct iwl4965_tid_data *tid_data; struct iwl_tid_data *tid_data;
DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac);
if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
@ -3978,7 +3668,7 @@ static int iwl4965_tx_agg_stop(struct ieee80211_hw *hw, const u8 *ra, u16 tid)
{ {
struct iwl_priv *priv = hw->priv; struct iwl_priv *priv = hw->priv;
int tx_fifo_id, txq_id, sta_id, ssn = -1; int tx_fifo_id, txq_id, sta_id, ssn = -1;
struct iwl4965_tid_data *tid_data; struct iwl_tid_data *tid_data;
int ret, write_ptr, read_ptr; int ret, write_ptr, read_ptr;
unsigned long flags; unsigned long flags;
DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac);
@ -4060,9 +3750,26 @@ int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
} }
return 0; return 0;
} }
#endif /* CONFIG_IWL4965_HT */ #endif /* CONFIG_IWL4965_HT */
static u16 iwl4965_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
{
struct iwl4965_addsta_cmd *addsta = (struct iwl4965_addsta_cmd *)data;
addsta->mode = cmd->mode;
memcpy(&addsta->sta, &cmd->sta, sizeof(struct sta_id_modify));
memcpy(&addsta->key, &cmd->key, sizeof(struct iwl4965_keyinfo));
addsta->station_flags = cmd->station_flags;
addsta->station_flags_msk = cmd->station_flags_msk;
addsta->tid_disable_tx = cmd->tid_disable_tx;
addsta->add_immediate_ba_tid = cmd->add_immediate_ba_tid;
addsta->remove_immediate_ba_tid = cmd->remove_immediate_ba_tid;
addsta->add_immediate_ba_ssn = cmd->add_immediate_ba_ssn;
addsta->reserved1 = __constant_cpu_to_le16(0);
addsta->reserved2 = __constant_cpu_to_le32(0);
return (u16)sizeof(struct iwl4965_addsta_cmd);
}
/* Set up 4965-specific Rx frame reply handlers */ /* Set up 4965-specific Rx frame reply handlers */
static void iwl4965_rx_handler_setup(struct iwl_priv *priv) static void iwl4965_rx_handler_setup(struct iwl_priv *priv)
{ {
@ -4106,6 +3813,7 @@ static struct iwl_hcmd_ops iwl4965_hcmd = {
static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
.enqueue_hcmd = iwl4965_enqueue_hcmd, .enqueue_hcmd = iwl4965_enqueue_hcmd,
.build_addsta_hcmd = iwl4965_build_addsta_hcmd,
#ifdef CONFIG_IWL4965_RUN_TIME_CALIB #ifdef CONFIG_IWL4965_RUN_TIME_CALIB
.chain_noise_reset = iwl4965_chain_noise_reset, .chain_noise_reset = iwl4965_chain_noise_reset,
.gain_computation = iwl4965_gain_computation, .gain_computation = iwl4965_gain_computation,
@ -4116,11 +3824,13 @@ static struct iwl_lib_ops iwl4965_lib = {
.set_hw_params = iwl4965_hw_set_hw_params, .set_hw_params = iwl4965_hw_set_hw_params,
.alloc_shared_mem = iwl4965_alloc_shared_mem, .alloc_shared_mem = iwl4965_alloc_shared_mem,
.free_shared_mem = iwl4965_free_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, .txq_update_byte_cnt_tbl = iwl4965_txq_update_byte_cnt_tbl,
.hw_nic_init = iwl4965_hw_nic_init, .disable_tx_fifo = iwl4965_disable_tx_fifo,
.rx_handler_setup = iwl4965_rx_handler_setup, .rx_handler_setup = iwl4965_rx_handler_setup,
.is_valid_rtc_data_addr = iwl4965_hw_valid_rtc_data_addr, .is_valid_rtc_data_addr = iwl4965_hw_valid_rtc_data_addr,
.alive_notify = iwl4965_alive_notify, .alive_notify = iwl4965_alive_notify,
.init_alive_start = iwl4965_init_alive_start,
.load_ucode = iwl4965_load_bsm, .load_ucode = iwl4965_load_bsm,
.apm_ops = { .apm_ops = {
.init = iwl4965_apm_init, .init = iwl4965_apm_init,
@ -4183,4 +3893,5 @@ module_param_named(qos_enable, iwl4965_mod_params.enable_qos, int, 0444);
MODULE_PARM_DESC(qos_enable, "enable all QoS functionality"); MODULE_PARM_DESC(qos_enable, "enable all QoS functionality");
module_param_named(amsdu_size_8K, iwl4965_mod_params.amsdu_size_8K, int, 0444); 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_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");

View file

@ -86,7 +86,7 @@ static int iwl5000_apm_init(struct iwl_priv *priv)
return ret; return ret;
} }
static void iwl5000_nic_init(struct iwl_priv *priv) static void iwl5000_nic_config(struct iwl_priv *priv)
{ {
unsigned long flags; unsigned long flags;
u16 radio_cfg; u16 radio_cfg;
@ -362,6 +362,8 @@ static int iwl5000_alloc_shared_mem(struct iwl_priv *priv)
memset(priv->shared_virt, 0, sizeof(struct iwl5000_shared)); memset(priv->shared_virt, 0, sizeof(struct iwl5000_shared));
priv->rb_closed_offset = offsetof(struct iwl5000_shared, rb_closed);
return 0; return 0;
} }
@ -374,11 +376,17 @@ static void iwl5000_free_shared_mem(struct iwl_priv *priv)
priv->shared_phys); 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 * 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, static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
struct iwl4965_tx_queue *txq, struct iwl_tx_queue *txq,
u16 byte_cnt) u16 byte_cnt)
{ {
struct iwl5000_shared *shared_data = priv->shared_virt; struct iwl5000_shared *shared_data = priv->shared_virt;
@ -422,10 +430,40 @@ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
} }
} }
static u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
{
u16 size = (u16)sizeof(struct iwl_addsta_cmd);
memcpy(data, cmd, size);
return size;
}
static int iwl5000_disable_tx_fifo(struct iwl_priv *priv)
{
unsigned long flags;
int ret;
spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv);
if (unlikely(ret)) {
IWL_ERROR("Tx fifo reset failed");
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}
iwl_write_prph(priv, IWL50_SCD_TXFACT, 0);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
static struct iwl_hcmd_ops iwl5000_hcmd = { static struct iwl_hcmd_ops iwl5000_hcmd = {
}; };
static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
.build_addsta_hcmd = iwl5000_build_addsta_hcmd,
#ifdef CONFIG_IWL5000_RUN_TIME_CALIB #ifdef CONFIG_IWL5000_RUN_TIME_CALIB
.gain_computation = iwl5000_gain_computation, .gain_computation = iwl5000_gain_computation,
.chain_noise_reset = iwl5000_chain_noise_reset, .chain_noise_reset = iwl5000_chain_noise_reset,
@ -436,10 +474,12 @@ static struct iwl_lib_ops iwl5000_lib = {
.set_hw_params = iwl5000_hw_set_hw_params, .set_hw_params = iwl5000_hw_set_hw_params,
.alloc_shared_mem = iwl5000_alloc_shared_mem, .alloc_shared_mem = iwl5000_alloc_shared_mem,
.free_shared_mem = iwl5000_free_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_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
.disable_tx_fifo = iwl5000_disable_tx_fifo,
.apm_ops = { .apm_ops = {
.init = iwl5000_apm_init, .init = iwl5000_apm_init,
.config = iwl5000_nic_init, .config = iwl5000_nic_config,
.set_pwr_src = iwl4965_set_pwr_src, .set_pwr_src = iwl4965_set_pwr_src,
}, },
.eeprom_ops = { .eeprom_ops = {
@ -470,6 +510,7 @@ static struct iwl_mod_params iwl50_mod_params = {
.num_of_queues = IWL50_NUM_QUEUES, .num_of_queues = IWL50_NUM_QUEUES,
.enable_qos = 1, .enable_qos = 1,
.amsdu_size_8K = 1, .amsdu_size_8K = 1,
.restart_fw = 1,
/* the rest are 0 by default */ /* the rest are 0 by default */
}; };
@ -515,5 +556,5 @@ module_param_named(qos_enable50, iwl50_mod_params.enable_qos, int, 0444);
MODULE_PARM_DESC(qos_enable50, "enable all 50XX QoS functionality"); 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_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_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");

View file

@ -769,6 +769,20 @@ struct iwl4965_keyinfo {
u8 key[16]; /* 16-byte unicast decryption key */ u8 key[16]; /* 16-byte unicast decryption key */
} __attribute__ ((packed)); } __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 * struct sta_id_modify
* @addr[ETH_ALEN]: station's MAC address * @addr[ETH_ALEN]: station's MAC address
@ -844,6 +858,38 @@ struct iwl4965_addsta_cmd {
__le32 reserved2; __le32 reserved2;
} __attribute__ ((packed)); } __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_SUCCESS_MSK 0x1
#define ADD_STA_NO_ROOM_IN_TABLE 0x2 #define ADD_STA_NO_ROOM_IN_TABLE 0x2
#define ADD_STA_NO_BLOCK_ACK_RESOURCE 0x4 #define ADD_STA_NO_BLOCK_ACK_RESOURCE 0x4
@ -2731,7 +2777,7 @@ struct iwl4965_led_cmd {
* *
*****************************************************************************/ *****************************************************************************/
struct iwl4965_rx_packet { struct iwl_rx_packet {
__le32 len; __le32 len;
struct iwl_cmd_header hdr; struct iwl_cmd_header hdr;
union { union {

View file

@ -46,11 +46,6 @@ MODULE_VERSION(IWLWIFI_VERSION);
MODULE_AUTHOR(DRV_COPYRIGHT); MODULE_AUTHOR(DRV_COPYRIGHT);
MODULE_LICENSE("GPL"); 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) \ #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_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \
IWL_RATE_SISO_##s##M_PLCP, \ IWL_RATE_SISO_##s##M_PLCP, \
@ -121,6 +116,100 @@ void iwl_hw_detect(struct iwl_priv *priv)
} }
EXPORT_SYMBOL(iwl_hw_detect); 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 * iwlcore_clear_stations_table - Clear the driver's station table
* *
@ -259,6 +348,12 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
if (priv->hw_params.tx_chains_num >= 3) if (priv->hw_params.tx_chains_num >= 3)
ht_info->supp_mcs_set[2] = 0xFF; ht_info->supp_mcs_set[2] = 0xFF;
} }
#else
static inline void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
struct ieee80211_ht_info *ht_info,
enum ieee80211_band band)
{
}
#endif /* CONFIG_IWL4965_HT */ #endif /* CONFIG_IWL4965_HT */
static void iwlcore_init_hw_rates(struct iwl_priv *priv, static void iwlcore_init_hw_rates(struct iwl_priv *priv,
@ -428,6 +523,105 @@ static u8 is_single_rx_stream(struct iwl_priv *priv)
(priv->current_ht_config.supp_mcs_set[2] == 0)) || (priv->current_ht_config.supp_mcs_set[2] == 0)) ||
priv->ps_mode == IWL_MIMO_PS_STATIC; priv->ps_mode == IWL_MIMO_PS_STATIC;
} }
static u8 iwl_is_channel_extension(struct iwl_priv *priv,
enum ieee80211_band band,
u16 channel, u8 extension_chan_offset)
{
const struct iwl_channel_info *ch_info;
ch_info = iwl_get_channel_info(priv, band, channel);
if (!is_channel_valid(ch_info))
return 0;
if (extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_NONE)
return 0;
if ((ch_info->fat_extension_channel == extension_chan_offset) ||
(ch_info->fat_extension_channel == HT_IE_EXT_CHANNEL_MAX))
return 1;
return 0;
}
u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
struct ieee80211_ht_info *sta_ht_inf)
{
struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config;
if ((!iwl_ht_conf->is_ht) ||
(iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) ||
(iwl_ht_conf->extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_NONE))
return 0;
if (sta_ht_inf) {
if ((!sta_ht_inf->ht_supported) ||
(!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH)))
return 0;
}
return iwl_is_channel_extension(priv, priv->band,
iwl_ht_conf->control_channel,
iwl_ht_conf->extension_chan_offset);
}
EXPORT_SYMBOL(iwl_is_fat_tx_allowed);
void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
{
struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon;
u32 val;
if (!ht_info->is_ht)
return;
/* Set up channel bandwidth: 20 MHz only, or 20/40 mixed if fat ok */
if (iwl_is_fat_tx_allowed(priv, NULL))
rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK;
else
rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
RXON_FLG_CHANNEL_MODE_PURE_40_MSK);
if (le16_to_cpu(rxon->channel) != ht_info->control_channel) {
IWL_DEBUG_ASSOC("control diff than current %d %d\n",
le16_to_cpu(rxon->channel),
ht_info->control_channel);
rxon->channel = cpu_to_le16(ht_info->control_channel);
return;
}
/* Note: control channel is opposite of extension channel */
switch (ht_info->extension_chan_offset) {
case IWL_EXT_CHANNEL_OFFSET_ABOVE:
rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
break;
case IWL_EXT_CHANNEL_OFFSET_BELOW:
rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
break;
case IWL_EXT_CHANNEL_OFFSET_NONE:
default:
rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK;
break;
}
val = ht_info->ht_protection;
rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS);
iwl_set_rxon_chain(priv);
IWL_DEBUG_ASSOC("supported HT rate 0x%X 0x%X 0x%X "
"rxon flags 0x%X operation mode :0x%X "
"extension channel offset 0x%x "
"control chan %d\n",
ht_info->supp_mcs_set[0],
ht_info->supp_mcs_set[1],
ht_info->supp_mcs_set[2],
le32_to_cpu(rxon->flags), ht_info->ht_protection,
ht_info->extension_chan_offset,
ht_info->control_channel);
return;
}
EXPORT_SYMBOL(iwl_set_rxon_ht);
#else #else
static inline u8 is_single_rx_stream(struct iwl_priv *priv) static inline u8 is_single_rx_stream(struct iwl_priv *priv)
{ {
@ -552,18 +746,10 @@ static void iwlcore_init_hw(struct iwl_priv *priv)
struct ieee80211_hw *hw = priv->hw; struct ieee80211_hw *hw = priv->hw;
hw->rate_control_algorithm = "iwl-4965-rs"; hw->rate_control_algorithm = "iwl-4965-rs";
/* Tell mac80211 and its clients (e.g. Wireless Extensions) /* Tell mac80211 our characteristics */
* the range of signal quality values that we'll provide. hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
* Negative values for level/noise indicate that we'll provide dBm. IEEE80211_HW_SIGNAL_DBM |
* For WE, at least, non-0 values here *enable* display of values IEEE80211_HW_NOISE_DBM;
* 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;
/* Default value; 4 EDCA QOS priorities */ /* Default value; 4 EDCA QOS priorities */
hw->queues = 4; hw->queues = 4;
#ifdef CONFIG_IWL4965_HT #ifdef CONFIG_IWL4965_HT

View file

@ -87,6 +87,7 @@ struct iwl_hcmd_ops {
}; };
struct iwl_hcmd_utils_ops { struct iwl_hcmd_utils_ops {
int (*enqueue_hcmd)(struct iwl_priv *priv, struct iwl_host_cmd *cmd); int (*enqueue_hcmd)(struct iwl_priv *priv, struct iwl_host_cmd *cmd);
u16 (*build_addsta_hcmd)(const struct iwl_addsta_cmd *cmd, u8 *data);
#ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB #ifdef CONFIG_IWLWIFI_RUN_TIME_CALIB
void (*gain_computation)(struct iwl_priv *priv, void (*gain_computation)(struct iwl_priv *priv,
u32 *average_noise, u32 *average_noise,
@ -102,13 +103,16 @@ struct iwl_lib_ops {
/* ucode shared memory */ /* ucode shared memory */
int (*alloc_shared_mem)(struct iwl_priv *priv); int (*alloc_shared_mem)(struct iwl_priv *priv);
void (*free_shared_mem)(struct iwl_priv *priv); void (*free_shared_mem)(struct iwl_priv *priv);
int (*shared_mem_rx_idx)(struct iwl_priv *priv);
void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv, void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv,
struct iwl4965_tx_queue *txq, struct iwl_tx_queue *txq,
u16 byte_cnt); u16 byte_cnt);
/* setup Rx handler */ /* setup Rx handler */
void (*rx_handler_setup)(struct iwl_priv *priv); void (*rx_handler_setup)(struct iwl_priv *priv);
/* nic init */ /* nic Tx fifo handling */
int (*hw_nic_init)(struct iwl_priv *priv); int (*disable_tx_fifo)(struct iwl_priv *priv);
/* alive notification after init uCode load */
void (*init_alive_start)(struct iwl_priv *priv);
/* alive notification */ /* alive notification */
int (*alive_notify)(struct iwl_priv *priv); int (*alive_notify)(struct iwl_priv *priv);
/* check validity of rtc data address */ /* check validity of rtc data address */
@ -145,6 +149,7 @@ struct iwl_mod_params {
int enable_qos; /* def: 1 = use quality of service */ int enable_qos; /* def: 1 = use quality of service */
int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */ int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */
int antenna; /* def: 0 = both antennas (use diversity) */ int antenna; /* def: 0 = both antennas (use diversity) */
int restart_fw; /* def: 1 = restart firmware */
}; };
struct iwl_cfg { struct iwl_cfg {
@ -172,6 +177,39 @@ int iwl_set_rxon_channel(struct iwl_priv *priv,
u16 channel); u16 channel);
void iwlcore_free_geos(struct iwl_priv *priv); void iwlcore_free_geos(struct iwl_priv *priv);
int iwl_setup(struct iwl_priv *priv); int iwl_setup(struct iwl_priv *priv);
void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info);
u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
struct ieee80211_ht_info *sta_ht_inf);
int iwl_hw_nic_init(struct iwl_priv *priv);
/* "keep warm" functions */
int iwl_kw_init(struct iwl_priv *priv);
int iwl_kw_alloc(struct iwl_priv *priv);
void iwl_kw_free(struct iwl_priv *priv);
/*****************************************************
* RX
******************************************************/
void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
int iwl_rx_queue_alloc(struct iwl_priv *priv);
void iwl_rx_handle(struct iwl_priv *priv);
int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
struct iwl_rx_queue *q);
void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
void iwl_rx_replenish(struct iwl_priv *priv);
int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
/* FIXME: remove when TX is moved to iwl core */
int iwl_rx_queue_restock(struct iwl_priv *priv);
int iwl_rx_queue_space(const struct iwl_rx_queue *q);
void iwl_rx_allocate(struct iwl_priv *priv);
/*****************************************************
* TX
******************************************************/
int iwl_txq_ctx_reset(struct iwl_priv *priv);
/* FIXME: remove when free Tx is fully merged into iwlcore */
int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
void iwl_hw_txq_ctx_free(struct iwl_priv *priv);
/***************************************************** /*****************************************************
* S e n d i n g H o s t C o m m a n d s * * S e n d i n g H o s t C o m m a n d s *
@ -265,4 +303,5 @@ static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
return priv->cfg->ops->hcmd->rxon_assoc(priv); return priv->cfg->ops->hcmd->rxon_assoc(priv);
} }
#endif /* __iwl_core_h__ */ #endif /* __iwl_core_h__ */

View file

@ -30,26 +30,16 @@
#define __iwl_debug_h__ #define __iwl_debug_h__
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
extern u32 iwl_debug_level;
#define IWL_DEBUG(level, fmt, args...) \ #define IWL_DEBUG(level, fmt, args...) \
do { if (iwl_debug_level & (level)) \ do { if (priv->debug_level & (level)) \
printk(KERN_ERR DRV_NAME": %c %s " fmt, \ dev_printk(KERN_ERR, &(priv->hw->wiphy->dev), "%c %s " fmt, \
in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
#define IWL_DEBUG_LIMIT(level, fmt, args...) \ #define IWL_DEBUG_LIMIT(level, fmt, args...) \
do { if ((iwl_debug_level & (level)) && net_ratelimit()) \ do { if ((priv->debug_level & (level)) && net_ratelimit()) \
printk(KERN_ERR DRV_NAME": %c %s " fmt, \ dev_printk(KERN_ERR, &(priv->hw->wiphy->dev), "%c %s " fmt, \
in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) 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 #ifdef CONFIG_IWLWIFI_DEBUGFS
struct iwl_debugfs { struct iwl_debugfs {
const char *name; const char *name;
@ -57,6 +47,7 @@ struct iwl_debugfs {
struct dentry *dir_data; struct dentry *dir_data;
struct dir_data_files{ struct dir_data_files{
struct dentry *file_sram; struct dentry *file_sram;
struct dentry *file_eeprom;
struct dentry *file_stations; struct dentry *file_stations;
struct dentry *file_rx_statistics; struct dentry *file_rx_statistics;
struct dentry *file_tx_statistics; struct dentry *file_tx_statistics;
@ -76,9 +67,6 @@ static inline void IWL_DEBUG(int level, const char *fmt, ...)
static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...) static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...)
{ {
} }
static inline void iwl_print_hex_dump(int level, void *p, u32 len)
{
}
#endif /* CONFIG_IWLWIFI_DEBUG */ #endif /* CONFIG_IWLWIFI_DEBUG */

View file

@ -206,7 +206,7 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct iwl_priv *priv = (struct iwl_priv *)file->private_data; 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; int max_sta = priv->hw_params.max_stations;
char *buf; char *buf;
int i, j, pos = 0; int i, j, pos = 0;
@ -277,8 +277,48 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
return ret; return ret;
} }
static ssize_t iwl_dbgfs_eeprom_read(struct file *file,
char __user *user_buf,
size_t count,
loff_t *ppos)
{
ssize_t ret;
struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
int pos = 0, ofs = 0, buf_size = 0;
const u8 *ptr;
char *buf;
size_t eeprom_len = priv->cfg->eeprom_size;
buf_size = 4 * eeprom_len + 256;
if (eeprom_len % 16) {
IWL_ERROR("EEPROM size is not multiple of 16.\n");
return -ENODATA;
}
/* 4 characters for byte 0xYY */
buf = kzalloc(buf_size, GFP_KERNEL);
if (!buf) {
IWL_ERROR("Can not allocate Buffer\n");
return -ENOMEM;
}
ptr = priv->eeprom;
for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) {
pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs);
hex_dump_to_buffer(ptr + ofs, 16 , 16, 2, buf + pos,
buf_size - pos, 0);
pos += strlen(buf);
if (buf_size - pos > 0)
buf[pos++] = '\n';
}
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
kfree(buf);
return ret;
}
DEBUGFS_READ_WRITE_FILE_OPS(sram); DEBUGFS_READ_WRITE_FILE_OPS(sram);
DEBUGFS_READ_FILE_OPS(eeprom);
DEBUGFS_READ_FILE_OPS(stations); DEBUGFS_READ_FILE_OPS(stations);
DEBUGFS_READ_FILE_OPS(rx_statistics); DEBUGFS_READ_FILE_OPS(rx_statistics);
DEBUGFS_READ_FILE_OPS(tx_statistics); DEBUGFS_READ_FILE_OPS(tx_statistics);
@ -304,6 +344,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
} }
DEBUGFS_ADD_DIR(data, dbgfs->dir_drv); DEBUGFS_ADD_DIR(data, dbgfs->dir_drv);
DEBUGFS_ADD_FILE(eeprom, data);
DEBUGFS_ADD_FILE(sram, data); DEBUGFS_ADD_FILE(sram, data);
DEBUGFS_ADD_FILE(stations, data); DEBUGFS_ADD_FILE(stations, data);
DEBUGFS_ADD_FILE(rx_statistics, data); DEBUGFS_ADD_FILE(rx_statistics, data);
@ -327,6 +368,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
if (!(priv->dbgfs)) if (!(priv->dbgfs))
return; 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_rx_statistics);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_tx_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_sram);

View file

@ -91,7 +91,7 @@ extern struct iwl_cfg iwl5350_agn_cfg;
#define DEFAULT_SHORT_RETRY_LIMIT 7U #define DEFAULT_SHORT_RETRY_LIMIT 7U
#define DEFAULT_LONG_RETRY_LIMIT 4U #define DEFAULT_LONG_RETRY_LIMIT 4U
struct iwl4965_rx_mem_buffer { struct iwl_rx_mem_buffer {
dma_addr_t dma_addr; dma_addr_t dma_addr;
struct sk_buff *skb; struct sk_buff *skb;
struct list_head list; struct list_head list;
@ -124,7 +124,7 @@ struct iwl4965_tx_info {
}; };
/** /**
* struct iwl4965_tx_queue - Tx Queue for DMA * struct iwl_tx_queue - Tx Queue for DMA
* @q: generic Rx/Tx queue descriptor * @q: generic Rx/Tx queue descriptor
* @bd: base of circular buffer of TFDs * @bd: base of circular buffer of TFDs
* @cmd: array of command/Tx buffers * @cmd: array of command/Tx buffers
@ -136,9 +136,9 @@ struct iwl4965_tx_info {
* A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame
* descriptors) and required locking structures. * descriptors) and required locking structures.
*/ */
struct iwl4965_tx_queue { struct iwl_tx_queue {
struct iwl4965_queue q; struct iwl4965_queue q;
struct iwl4965_tfd_frame *bd; struct iwl_tfd_frame *bd;
struct iwl_cmd *cmd; struct iwl_cmd *cmd;
dma_addr_t dma_addr_cmd; dma_addr_t dma_addr_cmd;
struct iwl4965_tx_info *txb; struct iwl4965_tx_info *txb;
@ -319,7 +319,7 @@ struct iwl_cmd {
struct iwl_cmd_meta meta; /* driver data */ struct iwl_cmd_meta meta; /* driver data */
struct iwl_cmd_header hdr; /* uCode API */ struct iwl_cmd_header hdr; /* uCode API */
union { union {
struct iwl4965_addsta_cmd addsta; struct iwl_addsta_cmd addsta;
struct iwl4965_led_cmd led; struct iwl4965_led_cmd led;
u32 flags; u32 flags;
u8 val8; u8 val8;
@ -358,7 +358,7 @@ struct iwl_host_cmd {
#define SUP_RATE_11G_MAX_NUM_CHANNELS 12 #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 * @processed: Internal index to last handled Rx packet
* @read: Shared index to newest available Rx buffer * @read: Shared index to newest available Rx buffer
* @write: Shared index to oldest written Rx packet * @write: Shared index to oldest written Rx packet
@ -367,13 +367,13 @@ struct iwl_host_cmd {
* @rx_used: List of Rx buffers with no SKB * @rx_used: List of Rx buffers with no SKB
* @need_update: flag to indicate we need to update read/write index * @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; __le32 *bd;
dma_addr_t dma_addr; dma_addr_t dma_addr;
struct iwl4965_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
struct iwl4965_rx_mem_buffer *queue[RX_QUEUE_SIZE]; struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
u32 processed; u32 processed;
u32 read; u32 read;
u32 write; u32 write;
@ -401,7 +401,7 @@ struct iwl4965_rx_queue {
#ifdef CONFIG_IWL4965_HT #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 * @txq_id: Tx queue used for Tx attempt
* @frame_count: # frames attempted by Tx command * @frame_count: # frames attempted by Tx command
* @wait_for_ba: Expect block-ack before next Tx reply * @wait_for_ba: Expect block-ack before next Tx reply
@ -414,7 +414,7 @@ struct iwl4965_rx_queue {
* for block ack (REPLY_COMPRESSED_BA). This struct stores tx reply info * for block ack (REPLY_COMPRESSED_BA). This struct stores tx reply info
* until block ack arrives. * until block ack arrives.
*/ */
struct iwl4965_ht_agg { struct iwl_ht_agg {
u16 txq_id; u16 txq_id;
u16 frame_count; u16 frame_count;
u16 wait_for_ba; u16 wait_for_ba;
@ -430,15 +430,15 @@ struct iwl4965_ht_agg {
#endif /* CONFIG_IWL4965_HT */ #endif /* CONFIG_IWL4965_HT */
struct iwl4965_tid_data { struct iwl_tid_data {
u16 seq_number; u16 seq_number;
u16 tfds_in_queue; u16 tfds_in_queue;
#ifdef CONFIG_IWL4965_HT #ifdef CONFIG_IWL4965_HT
struct iwl4965_ht_agg agg; struct iwl_ht_agg agg;
#endif /* CONFIG_IWL4965_HT */ #endif /* CONFIG_IWL4965_HT */
}; };
struct iwl4965_hw_key { struct iwl_hw_key {
enum ieee80211_key_alg alg; enum ieee80211_key_alg alg;
int keylen; int keylen;
u8 keyidx; u8 keyidx;
@ -454,7 +454,6 @@ union iwl4965_ht_rate_supp {
}; };
}; };
#ifdef CONFIG_IWL4965_HT
#define CFG_HT_RX_AMPDU_FACTOR_DEF (0x3) #define CFG_HT_RX_AMPDU_FACTOR_DEF (0x3)
#define CFG_HT_MPDU_DENSITY_2USEC (0x5) #define CFG_HT_MPDU_DENSITY_2USEC (0x5)
#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC #define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC
@ -477,7 +476,6 @@ struct iwl_ht_info {
u8 ht_protection; u8 ht_protection;
u8 non_GF_STA_present; u8 non_GF_STA_present;
}; };
#endif /*CONFIG_IWL4965_HT */
union iwl4965_qos_capabity { union iwl4965_qos_capabity {
struct { struct {
@ -510,12 +508,12 @@ struct iwl4965_qos_info {
#define STA_PS_STATUS_WAKE 0 #define STA_PS_STATUS_WAKE 0
#define STA_PS_STATUS_SLEEP 1 #define STA_PS_STATUS_SLEEP 1
struct iwl4965_station_entry { struct iwl_station_entry {
struct iwl4965_addsta_cmd sta; struct iwl_addsta_cmd sta;
struct iwl4965_tid_data tid[MAX_TID_COUNT]; struct iwl_tid_data tid[MAX_TID_COUNT];
u8 used; u8 used;
u8 ps_status; u8 ps_status;
struct iwl4965_hw_key keyinfo; struct iwl_hw_key keyinfo;
}; };
/* one for each uCode image (inst/data, boot/init/runtime) */ /* one for each uCode image (inst/data, boot/init/runtime) */
@ -634,35 +632,26 @@ struct iwl_hw_params {
* for use by iwl-*.c * for use by iwl-*.c
* *
*****************************************************************************/ *****************************************************************************/
struct iwl4965_addsta_cmd; struct iwl_addsta_cmd;
extern int iwl4965_send_add_station(struct iwl_priv *priv, extern int iwl_send_add_sta(struct iwl_priv *priv,
struct iwl4965_addsta_cmd *sta, u8 flags); struct iwl_addsta_cmd *sta, u8 flags);
extern u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr, extern u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr,
int is_ap, u8 flags, void *ht_data); int is_ap, u8 flags, void *ht_data);
extern int iwl4965_is_network_packet(struct iwl_priv *priv, extern int iwl4965_is_network_packet(struct iwl_priv *priv,
struct ieee80211_hdr *header); struct ieee80211_hdr *header);
extern int iwl4965_power_init_handle(struct iwl_priv *priv); extern int iwl4965_power_init_handle(struct iwl_priv *priv);
extern void iwl4965_handle_data_packet_monitor(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, void *data, short len,
struct ieee80211_rx_status *stats, struct ieee80211_rx_status *stats,
u16 phy_flags); u16 phy_flags);
extern int iwl4965_is_duplicate_packet(struct iwl_priv *priv, extern int iwl4965_is_duplicate_packet(struct iwl_priv *priv,
struct ieee80211_hdr *header); 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_db_from_ratio(int sig_ratio);
extern int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm); 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, extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv,
struct ieee80211_hdr *hdr, struct ieee80211_hdr *hdr,
const u8 *dest, int left); const u8 *dest, int left);
extern int iwl4965_rx_queue_update_write_ptr(struct iwl_priv *priv,
struct iwl4965_rx_queue *q);
extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr); extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr);
extern void iwl4965_update_chain_flags(struct iwl_priv *priv); 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_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src);
@ -700,20 +689,14 @@ extern void iwl4965_hw_setup_deferred_work(struct iwl_priv *priv);
extern void iwl4965_hw_cancel_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_rxq_stop(struct iwl_priv *priv);
extern int iwl4965_hw_set_hw_params(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 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 void iwl4965_hw_txq_ctx_stop(struct iwl_priv *priv);
extern int iwl4965_hw_nic_reset(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, extern int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd,
dma_addr_t addr, u16 len); dma_addr_t addr, u16 len);
extern int iwl4965_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl4965_tx_queue *txq);
extern int iwl4965_hw_get_temperature(struct iwl_priv *priv); extern int iwl4965_hw_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, extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
struct iwl4965_frame *frame, u8 rate); struct iwl4965_frame *frame, u8 rate);
extern int iwl4965_hw_get_rx_read(struct iwl_priv *priv);
extern void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv, extern void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv,
struct iwl_cmd *cmd, struct iwl_cmd *cmd,
struct ieee80211_tx_control *ctrl, struct ieee80211_tx_control *ctrl,
@ -722,7 +705,7 @@ extern void iwl4965_hw_build_tx_cmd_rate(struct iwl_priv *priv,
extern int iwl4965_hw_reg_send_txpower(struct iwl_priv *priv); 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 int iwl4965_hw_reg_set_txpower(struct iwl_priv *priv, s8 power);
extern void iwl4965_hw_rx_statistics(struct iwl_priv *priv, 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 void iwl4965_disable_events(struct iwl_priv *priv);
extern int iwl4965_get_temperature(const struct iwl_priv *priv); extern int iwl4965_get_temperature(const struct iwl_priv *priv);
@ -746,7 +729,7 @@ extern void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio);
* Forward declare iwl-4965.c functions for iwl-base.c * Forward declare iwl-4965.c functions for iwl-base.c
*/ */
extern int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv, 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); u16 byte_cnt);
extern void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, extern void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr,
int is_ap); int is_ap);
@ -778,9 +761,9 @@ static inline void iwl4965_init_ht_hw_capab(const struct iwl_priv *priv,
#endif /*CONFIG_IWL4965_HT */ #endif /*CONFIG_IWL4965_HT */
/* Structures, enum, and defines specific to the 4965 */ /* 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; dma_addr_t dma_addr;
void *v_addr; void *v_addr;
size_t size; size_t size;
@ -960,7 +943,7 @@ struct iwl_priv {
bool add_radiotap; bool add_radiotap;
void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, 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]; struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
@ -1077,10 +1060,10 @@ struct iwl_priv {
int activity_timer_active; int activity_timer_active;
/* Rx and Tx DMA processing queues */ /* Rx and Tx DMA processing queues */
struct iwl4965_rx_queue rxq; struct iwl_rx_queue rxq;
struct iwl4965_tx_queue txq[IWL_MAX_NUM_QUEUES]; struct iwl_tx_queue txq[IWL_MAX_NUM_QUEUES];
unsigned long txq_ctx_active_msk; 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 */ u32 scd_base_addr; /* scheduler sram base address */
unsigned long status; unsigned long status;
@ -1113,7 +1096,7 @@ struct iwl_priv {
/*station table variables */ /*station table variables */
spinlock_t sta_lock; spinlock_t sta_lock;
int num_stations; 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]; struct iwl_wep_key wep_keys[WEP_KEYS_MAX];
u8 default_wep_key; u8 default_wep_key;
u8 key_mapping_key; u8 key_mapping_key;
@ -1154,6 +1137,7 @@ struct iwl_priv {
struct iwl_hw_params hw_params; struct iwl_hw_params hw_params;
/* driver/uCode shared Tx Byte Counts and Rx status */ /* driver/uCode shared Tx Byte Counts and Rx status */
void *shared_virt; void *shared_virt;
int rb_closed_offset;
/* Physical Pointer to Tx Byte Counts and Rx status */ /* Physical Pointer to Tx Byte Counts and Rx status */
dma_addr_t shared_phys; dma_addr_t shared_phys;
@ -1179,6 +1163,7 @@ struct iwl_priv {
struct work_struct report_work; struct work_struct report_work;
struct work_struct request_scan; struct work_struct request_scan;
struct work_struct beacon_update; struct work_struct beacon_update;
struct work_struct set_monitor;
struct tasklet_struct irq_tasklet; struct tasklet_struct irq_tasklet;
@ -1200,6 +1185,7 @@ struct iwl_priv {
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
/* debugging info */ /* debugging info */
u32 debug_level;
u32 framecnt_to_us; u32 framecnt_to_us;
atomic_t restrict_refcnt; atomic_t restrict_refcnt;
#ifdef CONFIG_IWLWIFI_DEBUGFS #ifdef CONFIG_IWLWIFI_DEBUGFS
@ -1252,6 +1238,23 @@ static inline int is_channel_ibss(const struct iwl_channel_info *ch)
return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0; 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( extern const struct iwl_channel_info *iwl_get_channel_info(
const struct iwl_priv *priv, enum ieee80211_band band, u16 channel); const struct iwl_priv *priv, enum ieee80211_band band, u16 channel);

View file

@ -101,7 +101,7 @@ EXPORT_SYMBOL(get_cmd_string);
static int iwl_generic_cmd_callback(struct iwl_priv *priv, static int iwl_generic_cmd_callback(struct iwl_priv *priv,
struct iwl_cmd *cmd, struct sk_buff *skb) struct iwl_cmd *cmd, struct sk_buff *skb)
{ {
struct iwl4965_rx_packet *pkt = NULL; struct iwl_rx_packet *pkt = NULL;
if (!skb) { if (!skb) {
IWL_ERROR("Error: Response NULL in %s.\n", IWL_ERROR("Error: Response NULL in %s.\n",
@ -109,7 +109,7 @@ static int iwl_generic_cmd_callback(struct iwl_priv *priv,
return 1; return 1;
} }
pkt = (struct iwl4965_rx_packet *)skb->data; pkt = (struct iwl_rx_packet *)skb->data;
if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERROR("Bad return from %s (0x%08X)\n", IWL_ERROR("Bad return from %s (0x%08X)\n",
get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);

View file

@ -0,0 +1,422 @@
/******************************************************************************
*
* Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* James P. Ketrenos <ipw2100-admin@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
#include <net/mac80211.h>
#include "iwl-eeprom.h"
#include "iwl-dev.h"
#include "iwl-core.h"
#include "iwl-sta.h"
#include "iwl-io.h"
#include "iwl-helpers.h"
/************************** RX-FUNCTIONS ****************************/
/*
* Rx theory of operation
*
* Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs),
* each of which point to Receive Buffers to be filled by the NIC. These get
* used not only for Rx frames, but for any command response or notification
* from the NIC. The driver and NIC manage the Rx buffers by means
* of indexes into the circular buffer.
*
* Rx Queue Indexes
* The host/firmware share two index registers for managing the Rx buffers.
*
* The READ index maps to the first position that the firmware may be writing
* to -- the driver can read up to (but not including) this position and get
* good data.
* The READ index is managed by the firmware once the card is enabled.
*
* The WRITE index maps to the last position the driver has read from -- the
* position preceding WRITE is the last slot the firmware can place a packet.
*
* The queue is empty (no good data) if WRITE = READ - 1, and is full if
* WRITE = READ.
*
* During initialization, the host sets up the READ queue position to the first
* INDEX position, and WRITE to the last (READ - 1 wrapped)
*
* When the firmware places a packet in a buffer, it will advance the READ index
* and fire the RX interrupt. The driver can then query the READ index and
* process as many packets as possible, moving the WRITE index forward as it
* resets the Rx queue buffers with new memory.
*
* The management in the driver is as follows:
* + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When
* iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
* to replenish the iwl->rxq->rx_free.
* + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the
* iwl->rxq is replenished and the READ INDEX is updated (updating the
* 'processed' and 'read' driver indexes as well)
* + A received packet is processed and handed to the kernel network stack,
* detached from the iwl->rxq. The driver 'processed' index is updated.
* + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free
* list. If there are no allocated buffers in iwl->rxq->rx_free, the READ
* INDEX is not incremented and iwl->status(RX_STALLED) is set. If there
* were enough free buffers and RX_STALLED is set it is cleared.
*
*
* Driver sequence:
*
* iwl_rx_queue_alloc() Allocates rx_free
* iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls
* iwl_rx_queue_restock
* iwl_rx_queue_restock() Moves available buffers from rx_free into Rx
* queue, updates firmware pointers, and updates
* the WRITE index. If insufficient rx_free buffers
* are available, schedules iwl_rx_replenish
*
* -- enable interrupts --
* ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the
* READ INDEX, detaching the SKB from the pool.
* Moves the packet buffer from queue to rx_used.
* Calls iwl_rx_queue_restock to refill any empty
* slots.
* ...
*
*/
/**
* iwl_rx_queue_space - Return number of free slots available in queue.
*/
int iwl_rx_queue_space(const struct iwl_rx_queue *q)
{
int s = q->read - q->write;
if (s <= 0)
s += RX_QUEUE_SIZE;
/* keep some buffer to not confuse full and empty queue */
s -= 2;
if (s < 0)
s = 0;
return s;
}
EXPORT_SYMBOL(iwl_rx_queue_space);
/**
* iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
*/
int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
{
u32 reg = 0;
int ret = 0;
unsigned long flags;
spin_lock_irqsave(&q->lock, flags);
if (q->need_update == 0)
goto exit_unlock;
/* If power-saving is in use, make sure device is awake */
if (test_bit(STATUS_POWER_PMI, &priv->status)) {
reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
iwl_set_bit(priv, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
goto exit_unlock;
}
ret = iwl_grab_nic_access(priv);
if (ret)
goto exit_unlock;
/* Device expects a multiple of 8 */
iwl_write_direct32(priv, FH_RSCSR_CHNL0_WPTR,
q->write & ~0x7);
iwl_release_nic_access(priv);
/* Else device is assumed to be awake */
} else
/* Device expects a multiple of 8 */
iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7);
q->need_update = 0;
exit_unlock:
spin_unlock_irqrestore(&q->lock, flags);
return ret;
}
EXPORT_SYMBOL(iwl_rx_queue_update_write_ptr);
/**
* iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
*/
static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv,
dma_addr_t dma_addr)
{
return cpu_to_le32((u32)(dma_addr >> 8));
}
/**
* iwl_rx_queue_restock - refill RX queue from pre-allocated pool
*
* If there are slots in the RX queue that need to be restocked,
* and we have free pre-allocated buffers, fill the ranks as much
* as we can, pulling from rx_free.
*
* This moves the 'write' index forward to catch up with 'processed', and
* also updates the memory address in the firmware to reference the new
* target buffer.
*/
int iwl_rx_queue_restock(struct iwl_priv *priv)
{
struct iwl_rx_queue *rxq = &priv->rxq;
struct list_head *element;
struct iwl_rx_mem_buffer *rxb;
unsigned long flags;
int write;
int ret = 0;
spin_lock_irqsave(&rxq->lock, flags);
write = rxq->write & ~0x7;
while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
/* Get next free Rx buffer, remove from free list */
element = rxq->rx_free.next;
rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
list_del(element);
/* Point to Rx buffer via next RBD in circular buffer */
rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->dma_addr);
rxq->queue[rxq->write] = rxb;
rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
rxq->free_count--;
}
spin_unlock_irqrestore(&rxq->lock, flags);
/* If the pre-allocated buffer pool is dropping low, schedule to
* refill it */
if (rxq->free_count <= RX_LOW_WATERMARK)
queue_work(priv->workqueue, &priv->rx_replenish);
/* If we've added more space for the firmware to place data, tell it.
* Increment device's write pointer in multiples of 8. */
if ((write != (rxq->write & ~0x7))
|| (abs(rxq->write - rxq->read) > 7)) {
spin_lock_irqsave(&rxq->lock, flags);
rxq->need_update = 1;
spin_unlock_irqrestore(&rxq->lock, flags);
ret = iwl_rx_queue_update_write_ptr(priv, rxq);
}
return ret;
}
EXPORT_SYMBOL(iwl_rx_queue_restock);
/**
* iwl_rx_replenish - Move all used packet from rx_used to rx_free
*
* When moving to rx_free an SKB is allocated for the slot.
*
* Also restock the Rx queue via iwl_rx_queue_restock.
* This is called as a scheduled work item (except for during initialization)
*/
void iwl_rx_allocate(struct iwl_priv *priv)
{
struct iwl_rx_queue *rxq = &priv->rxq;
struct list_head *element;
struct iwl_rx_mem_buffer *rxb;
unsigned long flags;
spin_lock_irqsave(&rxq->lock, flags);
while (!list_empty(&rxq->rx_used)) {
element = rxq->rx_used.next;
rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
/* Alloc a new receive buffer */
rxb->skb = alloc_skb(priv->hw_params.rx_buf_size,
__GFP_NOWARN | GFP_ATOMIC);
if (!rxb->skb) {
if (net_ratelimit())
printk(KERN_CRIT DRV_NAME
": Can not allocate SKB buffers\n");
/* We don't reschedule replenish work here -- we will
* call the restock method and if it still needs
* more buffers it will schedule replenish */
break;
}
priv->alloc_rxb_skb++;
list_del(element);
/* Get physical address of RB/SKB */
rxb->dma_addr =
pci_map_single(priv->pci_dev, rxb->skb->data,
priv->hw_params.rx_buf_size, PCI_DMA_FROMDEVICE);
list_add_tail(&rxb->list, &rxq->rx_free);
rxq->free_count++;
}
spin_unlock_irqrestore(&rxq->lock, flags);
}
EXPORT_SYMBOL(iwl_rx_allocate);
void iwl_rx_replenish(struct iwl_priv *priv)
{
unsigned long flags;
iwl_rx_allocate(priv);
spin_lock_irqsave(&priv->lock, flags);
iwl_rx_queue_restock(priv);
spin_unlock_irqrestore(&priv->lock, flags);
}
EXPORT_SYMBOL(iwl_rx_replenish);
/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
* If an SKB has been detached, the POOL needs to have its SKB set to NULL
* This free routine walks the list of POOL entries and if SKB is set to
* non NULL it is unmapped and freed
*/
void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
{
int i;
for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
if (rxq->pool[i].skb != NULL) {
pci_unmap_single(priv->pci_dev,
rxq->pool[i].dma_addr,
priv->hw_params.rx_buf_size,
PCI_DMA_FROMDEVICE);
dev_kfree_skb(rxq->pool[i].skb);
}
}
pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
rxq->dma_addr);
rxq->bd = NULL;
}
EXPORT_SYMBOL(iwl_rx_queue_free);
int iwl_rx_queue_alloc(struct iwl_priv *priv)
{
struct iwl_rx_queue *rxq = &priv->rxq;
struct pci_dev *dev = priv->pci_dev;
int i;
spin_lock_init(&rxq->lock);
INIT_LIST_HEAD(&rxq->rx_free);
INIT_LIST_HEAD(&rxq->rx_used);
/* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */
rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr);
if (!rxq->bd)
return -ENOMEM;
/* Fill the rx_used queue with _all_ of the Rx buffers */
for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
/* Set us so that we have processed and used all buffers, but have
* not restocked the Rx queue with fresh buffers */
rxq->read = rxq->write = 0;
rxq->free_count = 0;
rxq->need_update = 0;
return 0;
}
EXPORT_SYMBOL(iwl_rx_queue_alloc);
void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
{
unsigned long flags;
int i;
spin_lock_irqsave(&rxq->lock, flags);
INIT_LIST_HEAD(&rxq->rx_free);
INIT_LIST_HEAD(&rxq->rx_used);
/* Fill the rx_used queue with _all_ of the Rx buffers */
for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
/* In the reset function, these buffers may have been allocated
* to an SKB, so we need to unmap and free potential storage */
if (rxq->pool[i].skb != NULL) {
pci_unmap_single(priv->pci_dev,
rxq->pool[i].dma_addr,
priv->hw_params.rx_buf_size,
PCI_DMA_FROMDEVICE);
priv->alloc_rxb_skb--;
dev_kfree_skb(rxq->pool[i].skb);
rxq->pool[i].skb = NULL;
}
list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
}
/* Set us so that we have processed and used all buffers, but have
* not restocked the Rx queue with fresh buffers */
rxq->read = rxq->write = 0;
rxq->free_count = 0;
spin_unlock_irqrestore(&rxq->lock, flags);
}
EXPORT_SYMBOL(iwl_rx_queue_reset);
int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
{
int ret;
unsigned long flags;
unsigned int rb_size;
spin_lock_irqsave(&priv->lock, flags);
ret = iwl_grab_nic_access(priv);
if (ret) {
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}
if (priv->cfg->mod_params->amsdu_size_8K)
rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
else
rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
/* Stop Rx DMA */
iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
/* Reset driver's Rx queue write index */
iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
/* Tell device where to find RBD circular buffer in DRAM */
iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
rxq->dma_addr >> 8);
/* Tell device where in DRAM to update its Rx status */
iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
(priv->shared_phys + priv->rb_closed_offset) >> 4);
/* Enable Rx DMA, enable host interrupt, Rx buffer size 4k, 256 RBDs */
iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG,
FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
rb_size |
/* 0x10 << 4 | */
(RX_QUEUE_SIZE_LOG <<
FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));
/*
* iwl_write32(priv,CSR_INT_COAL_REG,0);
*/
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}

View file

@ -70,6 +70,52 @@ u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr)
} }
EXPORT_SYMBOL(iwl_find_station); EXPORT_SYMBOL(iwl_find_station);
int iwl_send_add_sta(struct iwl_priv *priv,
struct iwl_addsta_cmd *sta, u8 flags)
{
struct iwl_rx_packet *res = NULL;
int ret = 0;
u8 data[sizeof(*sta)];
struct iwl_host_cmd cmd = {
.id = REPLY_ADD_STA,
.meta.flags = flags,
.data = data,
};
if (!(flags & CMD_ASYNC))
cmd.meta.flags |= CMD_WANT_SKB;
cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data);
ret = iwl_send_cmd(priv, &cmd);
if (ret || (flags & CMD_ASYNC))
return ret;
res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
res->hdr.flags);
ret = -EIO;
}
if (ret == 0) {
switch (res->u.add_sta.status) {
case ADD_STA_SUCCESS_MSK:
IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n");
break;
default:
ret = -EIO;
IWL_WARNING("REPLY_ADD_STA failed\n");
break;
}
}
priv->alloc_rxb_skb--;
dev_kfree_skb_any(cmd.meta.u.skb);
return ret;
}
EXPORT_SYMBOL(iwl_send_add_sta);
int iwl_get_free_ucode_key_index(struct iwl_priv *priv) int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
{ {
@ -124,6 +170,7 @@ int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
else else
return 0; return 0;
} }
EXPORT_SYMBOL(iwl_send_static_wepkey_cmd);
int iwl_remove_default_wep_key(struct iwl_priv *priv, int iwl_remove_default_wep_key(struct iwl_priv *priv,
struct ieee80211_key_conf *keyconf) struct ieee80211_key_conf *keyconf)
@ -144,6 +191,7 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
return ret; return ret;
} }
EXPORT_SYMBOL(iwl_remove_default_wep_key);
int iwl_set_default_wep_key(struct iwl_priv *priv, int iwl_set_default_wep_key(struct iwl_priv *priv,
struct ieee80211_key_conf *keyconf) struct ieee80211_key_conf *keyconf)
@ -171,6 +219,7 @@ int iwl_set_default_wep_key(struct iwl_priv *priv,
return ret; return ret;
} }
EXPORT_SYMBOL(iwl_set_default_wep_key);
static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv, static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
struct ieee80211_key_conf *keyconf, struct ieee80211_key_conf *keyconf,
@ -216,8 +265,7 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv,
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
ret = iwl4965_send_add_station(priv, ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
&priv->stations[sta_id].sta, CMD_ASYNC);
spin_unlock_irqrestore(&priv->sta_lock, flags); spin_unlock_irqrestore(&priv->sta_lock, flags);
@ -265,8 +313,7 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
spin_unlock_irqrestore(&priv->sta_lock, flags); spin_unlock_irqrestore(&priv->sta_lock, flags);
IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n"); IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
return iwl4965_send_add_station(priv, return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
&priv->stations[sta_id].sta, CMD_ASYNC);
} }
static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv, static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
@ -333,7 +380,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
IWL_ERROR("index %d not used in uCode key table.\n", IWL_ERROR("index %d not used in uCode key table.\n",
priv->stations[sta_id].sta.key.key_offset); priv->stations[sta_id].sta.key.key_offset);
memset(&priv->stations[sta_id].keyinfo, 0, 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, memset(&priv->stations[sta_id].sta.key, 0,
sizeof(struct iwl4965_keyinfo)); sizeof(struct iwl4965_keyinfo));
priv->stations[sta_id].sta.key.key_flags = priv->stations[sta_id].sta.key.key_flags =
@ -343,10 +390,11 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n"); IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n");
ret = iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0); ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, 0);
spin_unlock_irqrestore(&priv->sta_lock, flags); spin_unlock_irqrestore(&priv->sta_lock, flags);
return ret; return ret;
} }
EXPORT_SYMBOL(iwl_remove_dynamic_key);
int iwl_set_dynamic_key(struct iwl_priv *priv, int iwl_set_dynamic_key(struct iwl_priv *priv,
struct ieee80211_key_conf *key, u8 sta_id) struct ieee80211_key_conf *key, u8 sta_id)
@ -372,6 +420,7 @@ int iwl_set_dynamic_key(struct iwl_priv *priv,
return ret; return ret;
} }
EXPORT_SYMBOL(iwl_set_dynamic_key);
#ifdef CONFIG_IWLWIFI_DEBUG #ifdef CONFIG_IWLWIFI_DEBUG
static void iwl_dump_lq_cmd(struct iwl_priv *priv, static void iwl_dump_lq_cmd(struct iwl_priv *priv,

View file

@ -0,0 +1,373 @@
/******************************************************************************
*
* Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
* Contact Information:
* James P. Ketrenos <ipw2100-admin@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
*****************************************************************************/
#include <net/mac80211.h>
#include "iwl-eeprom.h"
#include "iwl-dev.h"
#include "iwl-core.h"
#include "iwl-sta.h"
#include "iwl-io.h"
#include "iwl-helpers.h"
/**
* iwl_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
*
* Does NOT advance any TFD circular buffer read/write indexes
* Does NOT free the TFD itself (which is within circular buffer)
*/
int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
{
struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0];
struct iwl_tfd_frame *bd = &bd_tmp[txq->q.read_ptr];
struct pci_dev *dev = priv->pci_dev;
int i;
int counter = 0;
int index, is_odd;
/* Host command buffers stay mapped in memory, nothing to clean */
if (txq->q.id == IWL_CMD_QUEUE_NUM)
return 0;
/* Sanity check on number of chunks */
counter = IWL_GET_BITS(*bd, num_tbs);
if (counter > MAX_NUM_OF_TBS) {
IWL_ERROR("Too many chunks: %i\n", counter);
/* @todo issue fatal error, it is quite serious situation */
return 0;
}
/* Unmap chunks, if any.
* TFD info for odd chunks is different format than for even chunks. */
for (i = 0; i < counter; i++) {
index = i / 2;
is_odd = i & 0x1;
if (is_odd)
pci_unmap_single(
dev,
IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) |
(IWL_GET_BITS(bd->pa[index],
tb2_addr_hi20) << 16),
IWL_GET_BITS(bd->pa[index], tb2_len),
PCI_DMA_TODEVICE);
else if (i > 0)
pci_unmap_single(dev,
le32_to_cpu(bd->pa[index].tb1_addr),
IWL_GET_BITS(bd->pa[index], tb1_len),
PCI_DMA_TODEVICE);
/* Free SKB, if any, for this chunk */
if (txq->txb[txq->q.read_ptr].skb[i]) {
struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[i];
dev_kfree_skb(skb);
txq->txb[txq->q.read_ptr].skb[i] = NULL;
}
}
return 0;
}
EXPORT_SYMBOL(iwl_hw_txq_free_tfd);
/**
* iwl_tx_queue_free - Deallocate DMA queue.
* @txq: Transmit queue to deallocate.
*
* Empty queue by removing and destroying all BD's.
* Free all buffers.
* 0-fill, but do not free "txq" descriptor structure.
*/
static void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq)
{
struct iwl4965_queue *q = &txq->q;
struct pci_dev *dev = priv->pci_dev;
int len;
if (q->n_bd == 0)
return;
/* first, empty all BD's */
for (; q->write_ptr != q->read_ptr;
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd))
iwl_hw_txq_free_tfd(priv, txq);
len = sizeof(struct iwl_cmd) * q->n_window;
if (q->id == IWL_CMD_QUEUE_NUM)
len += IWL_MAX_SCAN_SIZE;
/* De-alloc array of command/tx buffers */
pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
/* De-alloc circular buffer of TFDs */
if (txq->q.n_bd)
pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) *
txq->q.n_bd, txq->bd, txq->q.dma_addr);
/* De-alloc array of per-TFD driver data */
kfree(txq->txb);
txq->txb = NULL;
/* 0-fill queue descriptor structure */
memset(txq, 0, sizeof(*txq));
}
/**
* iwl_hw_txq_ctx_free - Free TXQ Context
*
* Destroy all TX DMA queues and structures
*/
void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
{
int txq_id;
/* Tx queues */
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
iwl_tx_queue_free(priv, &priv->txq[txq_id]);
/* Keep-warm buffer */
iwl_kw_free(priv);
}
EXPORT_SYMBOL(iwl_hw_txq_ctx_free);
/**
* iwl_queue_init - Initialize queue's high/low-water and read/write indexes
*/
static int iwl_queue_init(struct iwl_priv *priv, struct iwl4965_queue *q,
int count, int slots_num, u32 id)
{
q->n_bd = count;
q->n_window = slots_num;
q->id = id;
/* count must be power-of-two size, otherwise iwl_queue_inc_wrap
* and iwl_queue_dec_wrap are broken. */
BUG_ON(!is_power_of_2(count));
/* slots_num must be power-of-two size, otherwise
* get_cmd_index is broken. */
BUG_ON(!is_power_of_2(slots_num));
q->low_mark = q->n_window / 4;
if (q->low_mark < 4)
q->low_mark = 4;
q->high_mark = q->n_window / 8;
if (q->high_mark < 2)
q->high_mark = 2;
q->write_ptr = q->read_ptr = 0;
return 0;
}
/**
* iwl_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue
*/
static int iwl_tx_queue_alloc(struct iwl_priv *priv,
struct iwl_tx_queue *txq, u32 id)
{
struct pci_dev *dev = priv->pci_dev;
/* Driver private data, only for Tx (not command) queues,
* not shared with device. */
if (id != IWL_CMD_QUEUE_NUM) {
txq->txb = kmalloc(sizeof(txq->txb[0]) *
TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
if (!txq->txb) {
IWL_ERROR("kmalloc for auxiliary BD "
"structures failed\n");
goto error;
}
} else
txq->txb = NULL;
/* Circular buffer of transmit frame descriptors (TFDs),
* shared with device */
txq->bd = pci_alloc_consistent(dev,
sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX,
&txq->q.dma_addr);
if (!txq->bd) {
IWL_ERROR("pci_alloc_consistent(%zd) failed\n",
sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX);
goto error;
}
txq->q.id = id;
return 0;
error:
kfree(txq->txb);
txq->txb = NULL;
return -ENOMEM;
}
/*
* Tell nic where to find circular buffer of Tx Frame Descriptors for
* given Tx queue, and enable the DMA channel used for that queue.
*
* 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA
* channels supported in hardware.
*/
static int iwl_hw_tx_queue_init(struct iwl_priv *priv,
struct iwl_tx_queue *txq)
{
int rc;
unsigned long flags;
int txq_id = txq->q.id;
spin_lock_irqsave(&priv->lock, flags);
rc = iwl_grab_nic_access(priv);
if (rc) {
spin_unlock_irqrestore(&priv->lock, flags);
return rc;
}
/* Circular buffer (TFD queue in DRAM) physical base address */
iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
txq->q.dma_addr >> 8);
/* Enable DMA channel, using same id as for TFD queue */
iwl_write_direct32(
priv, FH_TCSR_CHNL_TX_CONFIG_REG(txq_id),
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL);
iwl_release_nic_access(priv);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
/**
* iwl_tx_queue_init - Allocate and initialize one tx/cmd queue
*/
static int iwl_tx_queue_init(struct iwl_priv *priv,
struct iwl_tx_queue *txq,
int slots_num, u32 txq_id)
{
struct pci_dev *dev = priv->pci_dev;
int len;
int rc = 0;
/*
* Alloc buffer array for commands (Tx or other types of commands).
* For the command queue (#4), allocate command space + one big
* command for scan, since scan command is very huge; the system will
* not have two scans at the same time, so only one is needed.
* For normal Tx queues (all other queues), no super-size command
* space is needed.
*/
len = sizeof(struct iwl_cmd) * slots_num;
if (txq_id == IWL_CMD_QUEUE_NUM)
len += IWL_MAX_SCAN_SIZE;
txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd);
if (!txq->cmd)
return -ENOMEM;
/* Alloc driver data array and TFD circular buffer */
rc = iwl_tx_queue_alloc(priv, txq, txq_id);
if (rc) {
pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
return -ENOMEM;
}
txq->need_update = 0;
/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
* iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
/* Initialize queue's high/low-water marks, and head/tail indexes */
iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
/* Tell device where to find queue */
iwl_hw_tx_queue_init(priv, txq);
return 0;
}
/**
* iwl_txq_ctx_reset - Reset TX queue context
* Destroys all DMA structures and initialise them again
*
* @param priv
* @return error code
*/
int iwl_txq_ctx_reset(struct iwl_priv *priv)
{
int ret = 0;
int txq_id, slots_num;
iwl_kw_free(priv);
/* Free all tx/cmd queues and keep-warm buffer */
iwl_hw_txq_ctx_free(priv);
/* Alloc keep-warm buffer */
ret = iwl_kw_alloc(priv);
if (ret) {
IWL_ERROR("Keep Warm allocation failed");
goto error_kw;
}
/* Turn off all Tx DMA fifos */
ret = priv->cfg->ops->lib->disable_tx_fifo(priv);
if (unlikely(ret))
goto error_reset;
/* Tell nic where to find the keep-warm buffer */
ret = iwl_kw_init(priv);
if (ret) {
IWL_ERROR("kw_init failed\n");
goto error_reset;
}
/* Alloc and init all (default 16) Tx queues,
* including the command queue (#4) */
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
ret = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
txq_id);
if (ret) {
IWL_ERROR("Tx %d queue init failed\n", txq_id);
goto error;
}
}
return ret;
error:
iwl_hw_txq_ctx_free(priv);
error_reset:
iwl_kw_free(priv);
error_kw:
return ret;
}

View file

@ -6144,6 +6144,24 @@ static void iwl3945_bg_rf_kill(struct work_struct *work)
mutex_unlock(&priv->mutex); 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) #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
static void iwl3945_bg_scan_check(struct work_struct *data) static void iwl3945_bg_scan_check(struct work_struct *data)
@ -6996,7 +7014,22 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw,
* XXX: dummy * XXX: dummy
* see also iwl3945_connection_init_rx_config * 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, static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw,
@ -7054,9 +7087,10 @@ static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
rc = -EAGAIN; rc = -EAGAIN;
goto out_unlock; goto out_unlock;
} }
/* if we just finished scan ask for delay */ /* if we just finished scan ask for delay for a broadcast scan */
if (priv->last_scan_jiffies && time_after(priv->last_scan_jiffies + if ((len == 0) && priv->last_scan_jiffies &&
IWL_DELAY_NEXT_SCAN, jiffies)) { time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN,
jiffies)) {
rc = -EAGAIN; rc = -EAGAIN;
goto out_unlock; goto out_unlock;
} }
@ -7872,6 +7906,7 @@ static void iwl3945_setup_deferred_work(struct iwl3945_priv *priv)
INIT_WORK(&priv->abort_scan, iwl3945_bg_abort_scan); INIT_WORK(&priv->abort_scan, iwl3945_bg_abort_scan);
INIT_WORK(&priv->rf_kill, iwl3945_bg_rf_kill); INIT_WORK(&priv->rf_kill, iwl3945_bg_rf_kill);
INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update); 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->post_associate, iwl3945_bg_post_associate);
INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start); INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start);
INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start);
@ -7994,17 +8029,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
priv->ibss_beacon = NULL; priv->ibss_beacon = NULL;
/* Tell mac80211 and its clients (e.g. Wireless Extensions) /* Tell mac80211 our characteristics */
* the range of signal quality values that we'll provide. hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
* Negative values for level/noise indicate that we'll provide dBm. IEEE80211_HW_SIGNAL_DBM |
* For WE, at least, non-0 values here *enable* display of values IEEE80211_HW_NOISE_DBM;
* 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;
/* 4 EDCA QOS priorities */ /* 4 EDCA QOS priorities */
hw->queues = 4; hw->queues = 4;

File diff suppressed because it is too large Load diff

View file

@ -696,38 +696,6 @@ static int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
return 0; return 0;
} }
/**
* @brief Get the current data rate
*
* @param priv A pointer to struct lbs_private structure
*
* @return The data rate on success, error on failure
*/
int lbs_get_data_rate(struct lbs_private *priv)
{
struct cmd_ds_802_11_data_rate cmd;
int ret = -1;
lbs_deb_enter(LBS_DEB_CMD);
memset(&cmd, 0, sizeof(cmd));
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
cmd.action = cpu_to_le16(CMD_ACT_GET_TX_RATE);
ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
if (ret)
goto out;
lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof (cmd));
ret = (int) lbs_fw_index_to_data_rate(cmd.rates[0]);
lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", ret);
out:
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
/** /**
* @brief Set the data rate * @brief Set the data rate
* *

View file

@ -34,7 +34,6 @@ int lbs_update_hw_spec(struct lbs_private *priv);
int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
struct cmd_ds_mesh_access *cmd); 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_set_data_rate(struct lbs_private *priv, u8 rate);
int lbs_get_channel(struct lbs_private *priv); int lbs_get_channel(struct lbs_private *priv);

View file

@ -927,20 +927,10 @@ static int lbs_setup_firmware(struct lbs_private *priv)
*/ */
memset(priv->current_addr, 0xff, ETH_ALEN); memset(priv->current_addr, 0xff, ETH_ALEN);
ret = lbs_update_hw_spec(priv); ret = lbs_update_hw_spec(priv);
if (ret) { if (ret)
ret = -1;
goto done; goto done;
}
lbs_set_mac_control(priv); lbs_set_mac_control(priv);
ret = lbs_get_data_rate(priv);
if (ret < 0) {
ret = -1;
goto done;
}
ret = 0;
done: done:
lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
return ret; return ret;

View file

@ -355,7 +355,7 @@ static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
struct ieee80211_rx_status rx_status = {0}; struct ieee80211_rx_status rx_status = {0};
u16 freq = le16_to_cpu(hdr->freq); u16 freq = le16_to_cpu(hdr->freq);
rx_status.ssi = hdr->rssi; rx_status.signal = hdr->rssi;
/* XX correct? */ /* XX correct? */
rx_status.rate_idx = hdr->rate & 0xf; rx_status.rate_idx = hdr->rate & 0xf;
rx_status.freq = freq; rx_status.freq = freq;
@ -1000,9 +1000,10 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
skb_queue_head_init(&priv->tx_queue); skb_queue_head_init(&priv->tx_queue);
dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz;
dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */ 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->channel_change_time = 1000; /* TODO: find actual value */
dev->max_rssi = 127; dev->max_signal = 127;
priv->tx_stats[0].limit = 5; priv->tx_stats[0].limit = 5;
dev->queues = 1; dev->queues = 1;

View file

@ -1361,10 +1361,9 @@ static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/* /*
* Initialize all hw fields. * 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->extra_tx_headroom = 0;
rt2x00dev->hw->max_signal = MAX_SIGNAL;
rt2x00dev->hw->max_rssi = MAX_RX_SSI;
rt2x00dev->hw->queues = 2; rt2x00dev->hw->queues = 2;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);

View file

@ -1680,10 +1680,10 @@ static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
/* /*
* Initialize all hw fields. * 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->extra_tx_headroom = 0;
rt2x00dev->hw->max_signal = MAX_SIGNAL;
rt2x00dev->hw->max_rssi = MAX_RX_SSI;
rt2x00dev->hw->queues = 2; rt2x00dev->hw->queues = 2;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);

View file

@ -1587,10 +1587,10 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
rt2x00dev->hw->flags = rt2x00dev->hw->flags =
IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
IEEE80211_HW_RX_INCLUDES_FCS | 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->extra_tx_headroom = TXD_DESC_SIZE;
rt2x00dev->hw->max_signal = MAX_SIGNAL;
rt2x00dev->hw->max_rssi = MAX_RX_SSI;
rt2x00dev->hw->queues = 2; rt2x00dev->hw->queues = 2;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev); SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);

View file

@ -600,9 +600,9 @@ void rt2x00lib_rxdone(struct queue_entry *entry,
rt2x00dev->link.qual.rx_success++; rt2x00dev->link.qual.rx_success++;
rx_status->rate_idx = idx; rx_status->rate_idx = idx;
rx_status->signal = rx_status->qual =
rt2x00lib_calculate_link_signal(rt2x00dev, rxdesc->rssi); rt2x00lib_calculate_link_signal(rt2x00dev, rxdesc->rssi);
rx_status->ssi = rxdesc->rssi; rx_status->signal = rxdesc->rssi;
rx_status->flag = rxdesc->flags; rx_status->flag = rxdesc->flags;
rx_status->antenna = rt2x00dev->link.ant.active.rx; rx_status->antenna = rt2x00dev->link.ant.active.rx;

View file

@ -2245,10 +2245,9 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
*/ */
rt2x00dev->hw->flags = rt2x00dev->hw->flags =
IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | 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->extra_tx_headroom = 0;
rt2x00dev->hw->max_signal = MAX_SIGNAL;
rt2x00dev->hw->max_rssi = MAX_RX_SSI;
rt2x00dev->hw->queues = 4; rt2x00dev->hw->queues = 4;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev); SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);

View file

@ -1830,10 +1830,9 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
*/ */
rt2x00dev->hw->flags = rt2x00dev->hw->flags =
IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | 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->extra_tx_headroom = TXD_DESC_SIZE;
rt2x00dev->hw->max_signal = MAX_SIGNAL;
rt2x00dev->hw->max_rssi = MAX_RX_SSI;
rt2x00dev->hw->queues = 4; rt2x00dev->hw->queues = 4;
SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev); SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);

View file

@ -132,8 +132,8 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
rx_status.antenna = (flags2 >> 15) & 1; rx_status.antenna = (flags2 >> 15) & 1;
/* TODO: improve signal/rssi reporting */ /* TODO: improve signal/rssi reporting */
rx_status.signal = flags2 & 0xFF; rx_status.qual = flags2 & 0xFF;
rx_status.ssi = (flags2 >> 8) & 0x7F; rx_status.signal = (flags2 >> 8) & 0x7F;
/* XXX: is this correct? */ /* XXX: is this correct? */
rx_status.rate_idx = (flags >> 20) & 0xF; rx_status.rate_idx = (flags >> 20) & 0xF;
rx_status.freq = dev->conf.channel->center_freq; rx_status.freq = dev->conf.channel->center_freq;
@ -894,9 +894,10 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev,
dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | 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->queues = 1;
dev->max_rssi = 65; dev->max_signal = 65;
reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
reg &= RTL818X_TX_CONF_HWVER_MASK; reg &= RTL818X_TX_CONF_HWVER_MASK;

View file

@ -261,8 +261,8 @@ static void rtl8187_rx_cb(struct urb *urb)
} }
rx_status.antenna = (hdr->signal >> 7) & 1; rx_status.antenna = (hdr->signal >> 7) & 1;
rx_status.signal = 64 - min(hdr->noise, (u8)64); rx_status.qual = 64 - min(hdr->noise, (u8)64);
rx_status.ssi = signal; rx_status.signal = signal;
rx_status.rate_idx = rate; rx_status.rate_idx = rate;
rx_status.freq = dev->conf.channel->center_freq; rx_status.freq = dev->conf.channel->center_freq;
rx_status.band = dev->conf.channel->band; rx_status.band = dev->conf.channel->band;
@ -740,11 +740,11 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
priv->mode = IEEE80211_IF_TYPE_MNTR; priv->mode = IEEE80211_IF_TYPE_MNTR;
dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | 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->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr);
dev->queues = 1; dev->queues = 1;
dev->max_rssi = 65; dev->max_signal = 65;
dev->max_signal = 64;
eeprom.data = dev; eeprom.data = dev;
eeprom.register_read = rtl8187_eeprom_register_read; eeprom.register_read = rtl8187_eeprom_register_read;

View file

@ -638,7 +638,7 @@ static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr,
memset(&status, 0, sizeof(status)); memset(&status, 0, sizeof(status));
status.flags = IEEE80211_TX_STATUS_ACK; status.flags = IEEE80211_TX_STATUS_ACK;
status.ack_signal = stats->ssi; status.ack_signal = stats->signal;
__skb_unlink(skb, q); __skb_unlink(skb, q);
tx_status(hw, skb, &status, 1); tx_status(hw, skb, &status, 1);
goto out; goto out;
@ -691,8 +691,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
stats.freq = zd_channels[_zd_chip_get_channel(&mac->chip) - 1].center_freq; stats.freq = zd_channels[_zd_chip_get_channel(&mac->chip) - 1].center_freq;
stats.band = IEEE80211_BAND_2GHZ; stats.band = IEEE80211_BAND_2GHZ;
stats.ssi = status->signal_strength; stats.signal = status->signal_strength;
stats.signal = zd_rx_qual_percent(buffer, stats.qual = zd_rx_qual_percent(buffer,
length - sizeof(struct rx_status), length - sizeof(struct rx_status),
status); status);
@ -751,6 +751,7 @@ static int zd_op_add_interface(struct ieee80211_hw *hw,
case IEEE80211_IF_TYPE_MNTR: case IEEE80211_IF_TYPE_MNTR:
case IEEE80211_IF_TYPE_MESH_POINT: case IEEE80211_IF_TYPE_MESH_POINT:
case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
mac->type = conf->type; mac->type = conf->type;
break; break;
default: default:
@ -781,7 +782,8 @@ static int zd_op_config_interface(struct ieee80211_hw *hw,
struct zd_mac *mac = zd_hw_mac(hw); struct zd_mac *mac = zd_hw_mac(hw);
int associated; 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; associated = true;
if (conf->beacon) { if (conf->beacon) {
zd_mac_config_beacon(hw, conf->beacon); zd_mac_config_beacon(hw, conf->beacon);
@ -941,6 +943,18 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw,
} }
} }
static int zd_op_beacon_update(struct ieee80211_hw *hw,
struct sk_buff *skb,
struct ieee80211_tx_control *ctl)
{
struct zd_mac *mac = zd_hw_mac(hw);
zd_mac_config_beacon(hw, skb);
kfree_skb(skb);
zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS |
hw->conf.beacon_int);
return 0;
}
static const struct ieee80211_ops zd_ops = { static const struct ieee80211_ops zd_ops = {
.tx = zd_op_tx, .tx = zd_op_tx,
.start = zd_op_start, .start = zd_op_start,
@ -951,6 +965,7 @@ static const struct ieee80211_ops zd_ops = {
.config_interface = zd_op_config_interface, .config_interface = zd_op_config_interface,
.configure_filter = zd_op_configure_filter, .configure_filter = zd_op_configure_filter,
.bss_info_changed = zd_op_bss_info_changed, .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) struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
@ -982,10 +997,10 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band; hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band;
hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
hw->max_rssi = 100; IEEE80211_HW_SIGNAL_DB;
hw->max_signal = 100;
hw->max_signal = 100;
hw->queues = 1; hw->queues = 1;
hw->extra_tx_headroom = sizeof(struct zd_ctrlset); hw->extra_tx_headroom = sizeof(struct zd_ctrlset);

View file

@ -552,16 +552,17 @@ enum ieee80211_back_parties {
*/ */
static inline u8 *ieee80211_get_SA(struct ieee80211_hdr *hdr) static inline u8 *ieee80211_get_SA(struct ieee80211_hdr *hdr)
{ {
u8 *raw = (u8 *) hdr; __le16 fc = hdr->frame_control;
u8 tofrom = (*(raw+1)) & 3; /* get the TODS and FROMDS bits */ fc &= cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS);
switch (tofrom) { switch (fc) {
case 2: case __constant_cpu_to_le16(IEEE80211_FCTL_FROMDS):
return hdr->addr3; return hdr->addr3;
case 3: case __constant_cpu_to_le16(IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS):
return hdr->addr4; return hdr->addr4;
default:
return hdr->addr2;
} }
return hdr->addr2;
} }
/** /**
@ -577,12 +578,13 @@ static inline u8 *ieee80211_get_SA(struct ieee80211_hdr *hdr)
*/ */
static inline u8 *ieee80211_get_DA(struct ieee80211_hdr *hdr) static inline u8 *ieee80211_get_DA(struct ieee80211_hdr *hdr)
{ {
u8 *raw = (u8 *) hdr; __le16 fc = hdr->frame_control;
u8 to_ds = (*(raw+1)) & 1; /* get the TODS bit */ fc &= cpu_to_le16(IEEE80211_FCTL_TODS);
if (to_ds) if (fc)
return hdr->addr3; return hdr->addr3;
return hdr->addr1; else
return hdr->addr1;
} }
/** /**
@ -595,8 +597,8 @@ static inline u8 *ieee80211_get_DA(struct ieee80211_hdr *hdr)
*/ */
static inline int ieee80211_get_morefrag(struct ieee80211_hdr *hdr) static inline int ieee80211_get_morefrag(struct ieee80211_hdr *hdr)
{ {
return (le16_to_cpu(hdr->frame_control) & __le16 fc = hdr->frame_control;
IEEE80211_FCTL_MOREFRAGS) != 0; return !!(fc & cpu_to_le16(IEEE80211_FCTL_MOREFRAGS));
} }
#endif /* IEEE80211_H */ #endif /* IEEE80211_H */

View file

@ -336,13 +336,16 @@ enum mac80211_rx_flags {
* The low-level driver should provide this information (the subset * The low-level driver should provide this information (the subset
* supported by hardware) to the 802.11 code with each received * supported by hardware) to the 802.11 code with each received
* frame. * frame.
*
* @mactime: value in microseconds of the 64-bit Time Synchronization Function * @mactime: value in microseconds of the 64-bit Time Synchronization Function
* (TSF) timer when the first data symbol (MPDU) arrived at the hardware. * (TSF) timer when the first data symbol (MPDU) arrived at the hardware.
* @band: the active band when this frame was received * @band: the active band when this frame was received
* @freq: frequency the radio was tuned to when receiving this frame, in MHz * @freq: frequency the radio was tuned to when receiving this frame, in MHz
* @ssi: signal strength when receiving this frame * @signal: signal strength when receiving this frame, either in dBm, in dB or
* @signal: used as 'qual' in statistics reporting * unspecified depending on the hardware capabilities flags
* @noise: PHY noise when receiving this frame * @IEEE80211_HW_SIGNAL_*
* @noise: noise when receiving this frame, in dBm.
* @qual: overall signal quality indication, in percent (0-100).
* @antenna: antenna used * @antenna: antenna used
* @rate_idx: index of data rate into band's supported rates * @rate_idx: index of data rate into band's supported rates
* @flag: %RX_FLAG_* * @flag: %RX_FLAG_*
@ -351,9 +354,9 @@ struct ieee80211_rx_status {
u64 mactime; u64 mactime;
enum ieee80211_band band; enum ieee80211_band band;
int freq; int freq;
int ssi;
int signal; int signal;
int noise; int noise;
int qual;
int antenna; int antenna;
int rate_idx; int rate_idx;
int flag; int flag;
@ -392,7 +395,8 @@ enum ieee80211_tx_status_flags {
* relevant only if IEEE80211_TX_STATUS_AMPDU was set. * relevant only if IEEE80211_TX_STATUS_AMPDU was set.
* @ampdu_ack_map: block ack bit map for the aggregation. * @ampdu_ack_map: block ack bit map for the aggregation.
* relevant only if IEEE80211_TX_STATUS_AMPDU was set. * relevant only if IEEE80211_TX_STATUS_AMPDU was set.
* @ack_signal: signal strength of the ACK frame * @ack_signal: signal strength of the ACK frame either in dBm, dB or unspec
* depending on hardware capabilites flags @IEEE80211_HW_SIGNAL_*
*/ */
struct ieee80211_tx_status { struct ieee80211_tx_status {
struct ieee80211_tx_control control; struct ieee80211_tx_control control;
@ -703,6 +707,25 @@ enum ieee80211_tkip_key_type {
* @IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE: * @IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE:
* Hardware is not capable of receiving frames with short preamble on * Hardware is not capable of receiving frames with short preamble on
* the 2.4 GHz band. * 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 { enum ieee80211_hw_flags {
IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE = 1<<0, IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE = 1<<0,
@ -710,6 +733,10 @@ enum ieee80211_hw_flags {
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING = 1<<2, IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING = 1<<2,
IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE = 1<<3, IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE = 1<<3,
IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE = 1<<4, 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,
}; };
/** /**
@ -740,12 +767,8 @@ enum ieee80211_hw_flags {
* *
* @channel_change_time: time (in microseconds) it takes to change channels. * @channel_change_time: time (in microseconds) it takes to change channels.
* *
* @max_rssi: Maximum value for ssi in RX information, use * @max_signal: Maximum value for signal (rssi) in RX information, used
* negative numbers for dBm and 0 to indicate no support. * only when @IEEE80211_HW_SIGNAL_UNSPEC or @IEEE80211_HW_SIGNAL_DB
*
* @max_signal: like @max_rssi, but for the signal value.
*
* @max_noise: like @max_rssi, but for the noise value.
* *
* @queues: number of available hardware transmit queues for * @queues: number of available hardware transmit queues for
* data packets. WMM/QoS requires at least four, these * data packets. WMM/QoS requires at least four, these
@ -775,9 +798,7 @@ struct ieee80211_hw {
int channel_change_time; int channel_change_time;
int vif_data_size; int vif_data_size;
u16 queues, ampdu_queues; u16 queues, ampdu_queues;
s8 max_rssi;
s8 max_signal; s8 max_signal;
s8 max_noise;
}; };
/** /**

View file

@ -391,7 +391,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
wstats.updated = 0; wstats.updated = 0;
if (rx_stats->mask & IEEE80211_STATMASK_RSSI) { if (rx_stats->mask & IEEE80211_STATMASK_RSSI) {
wstats.level = rx_stats->rssi; wstats.level = rx_stats->signal;
wstats.updated |= IW_QUAL_LEVEL_UPDATED; wstats.updated |= IW_QUAL_LEVEL_UPDATED;
} else } else
wstats.updated |= IW_QUAL_LEVEL_INVALID; wstats.updated |= IW_QUAL_LEVEL_INVALID;

View file

@ -602,6 +602,7 @@ static void sta_apply_parameters(struct ieee80211_local *local,
*/ */
if (params->station_flags & STATION_FLAG_CHANGED) { if (params->station_flags & STATION_FLAG_CHANGED) {
spin_lock_bh(&sta->lock);
sta->flags &= ~WLAN_STA_AUTHORIZED; sta->flags &= ~WLAN_STA_AUTHORIZED;
if (params->station_flags & STATION_FLAG_AUTHORIZED) if (params->station_flags & STATION_FLAG_AUTHORIZED)
sta->flags |= WLAN_STA_AUTHORIZED; sta->flags |= WLAN_STA_AUTHORIZED;
@ -613,6 +614,7 @@ static void sta_apply_parameters(struct ieee80211_local *local,
sta->flags &= ~WLAN_STA_WME; sta->flags &= ~WLAN_STA_WME;
if (params->station_flags & STATION_FLAG_WME) if (params->station_flags & STATION_FLAG_WME)
sta->flags |= WLAN_STA_WME; sta->flags |= WLAN_STA_WME;
spin_unlock_bh(&sta->lock);
} }
/* /*

View file

@ -63,8 +63,8 @@ STA_FILE(tx_fragments, tx_fragments, LU);
STA_FILE(tx_filtered, tx_filtered_count, LU); STA_FILE(tx_filtered, tx_filtered_count, LU);
STA_FILE(tx_retry_failed, tx_retry_failed, LU); STA_FILE(tx_retry_failed, tx_retry_failed, LU);
STA_FILE(tx_retry_count, tx_retry_count, 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_signal, last_signal, D);
STA_FILE(last_qual, last_qual, D);
STA_FILE(last_noise, last_noise, D); STA_FILE(last_noise, last_noise, D);
STA_FILE(channel_use, channel_use, D); STA_FILE(channel_use, channel_use, D);
STA_FILE(wep_weak_iv_count, wep_weak_iv_count, LU); STA_FILE(wep_weak_iv_count, wep_weak_iv_count, LU);
@ -74,14 +74,15 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
{ {
char buf[100]; char buf[100];
struct sta_info *sta = file->private_data; 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", int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s",
sta->flags & WLAN_STA_AUTH ? "AUTH\n" : "", staflags & WLAN_STA_AUTH ? "AUTH\n" : "",
sta->flags & WLAN_STA_ASSOC ? "ASSOC\n" : "", staflags & WLAN_STA_ASSOC ? "ASSOC\n" : "",
sta->flags & WLAN_STA_PS ? "PS\n" : "", staflags & WLAN_STA_PS ? "PS\n" : "",
sta->flags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "", staflags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "",
sta->flags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "", staflags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "",
sta->flags & WLAN_STA_WME ? "WME\n" : "", staflags & WLAN_STA_WME ? "WME\n" : "",
sta->flags & WLAN_STA_WDS ? "WDS\n" : ""); staflags & WLAN_STA_WDS ? "WDS\n" : "");
return simple_read_from_buffer(userbuf, count, ppos, buf, res); return simple_read_from_buffer(userbuf, count, ppos, buf, res);
} }
STA_OPS(flags); STA_OPS(flags);

View file

@ -82,7 +82,7 @@ struct ieee80211_sta_bss {
u16 capability; /* host byte order */ u16 capability; /* host byte order */
enum ieee80211_band band; enum ieee80211_band band;
int freq; int freq;
int rssi, signal, noise; int signal, noise, qual;
u8 *wpa_ie; u8 *wpa_ie;
size_t wpa_ie_len; size_t wpa_ie_len;
u8 *rsn_ie; u8 *rsn_ie;
@ -610,8 +610,8 @@ struct ieee80211_local {
struct sta_info *sta_hash[STA_HASH_SIZE]; struct sta_info *sta_hash[STA_HASH_SIZE];
struct timer_list sta_cleanup; struct timer_list sta_cleanup;
unsigned long state[IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_AMPDU_QUEUES]; unsigned long state[IEEE80211_MAX_QUEUES + IEEE80211_MAX_AMPDU_QUEUES];
struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_AMPDU_QUEUES]; struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_QUEUES + IEEE80211_MAX_AMPDU_QUEUES];
struct tasklet_struct tx_pending_tasklet; struct tasklet_struct tx_pending_tasklet;
/* number of interfaces with corresponding IFF_ flags */ /* number of interfaces with corresponding IFF_ flags */

View file

@ -166,9 +166,10 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN | ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |
IEEE80211_AUTH_ALG_SHARED_KEY; IEEE80211_AUTH_ALG_SHARED_KEY;
ifsta->flags |= IEEE80211_STA_CREATE_IBSS | ifsta->flags |= IEEE80211_STA_CREATE_IBSS |
IEEE80211_STA_WMM_ENABLED |
IEEE80211_STA_AUTO_BSSID_SEL | IEEE80211_STA_AUTO_BSSID_SEL |
IEEE80211_STA_AUTO_CHANNEL_SEL; IEEE80211_STA_AUTO_CHANNEL_SEL;
if (sdata->local->hw.queues >= 4)
ifsta->flags |= IEEE80211_STA_WMM_ENABLED;
msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev); msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev);
sdata->bss = &msdata->u.ap; sdata->bss = &msdata->u.ap;

View file

@ -321,7 +321,7 @@ void ieee80211_key_link(struct ieee80211_key *key,
* some hardware cannot handle TKIP with QoS, so * some hardware cannot handle TKIP with QoS, so
* we indicate whether QoS could be in use. * 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; key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA;
/* /*
@ -342,7 +342,7 @@ void ieee80211_key_link(struct ieee80211_key *key,
/* same here, the AP could be using QoS */ /* same here, the AP could be using QoS */
ap = sta_info_get(key->local, key->sdata->u.sta.bssid); ap = sta_info_get(key->local, key->sdata->u.sta.bssid);
if (ap) { if (ap) {
if (ap->flags & WLAN_STA_WME) if (test_sta_flags(ap, WLAN_STA_WME))
key->conf.flags |= key->conf.flags |=
IEEE80211_KEY_FLAG_WMM_STA; IEEE80211_KEY_FLAG_WMM_STA;
} }

View file

@ -346,6 +346,7 @@ static int ieee80211_open(struct net_device *dev)
goto err_del_interface; goto err_del_interface;
} }
/* no locking required since STA is not live yet */
sta->flags |= WLAN_STA_AUTHORIZED; sta->flags |= WLAN_STA_AUTHORIZED;
res = sta_info_insert(sta); res = sta_info_insert(sta);
@ -588,7 +589,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
return -ENOENT; return -ENOENT;
} }
spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); spin_lock_bh(&sta->lock);
/* we have tried too many times, receiver does not want A-MPDU */ /* we have tried too many times, receiver does not want A-MPDU */
if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
@ -691,7 +692,7 @@ start_ba_err:
spin_unlock_bh(&local->mdev->queue_lock); spin_unlock_bh(&local->mdev->queue_lock);
ret = -EBUSY; ret = -EBUSY;
start_ba_exit: start_ba_exit:
spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); spin_unlock_bh(&sta->lock);
rcu_read_unlock(); rcu_read_unlock();
return ret; return ret;
} }
@ -719,7 +720,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
/* check if the TID is in aggregation */ /* check if the TID is in aggregation */
state = &sta->ampdu_mlme.tid_state_tx[tid]; state = &sta->ampdu_mlme.tid_state_tx[tid];
spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); spin_lock_bh(&sta->lock);
if (*state != HT_AGG_STATE_OPERATIONAL) { if (*state != HT_AGG_STATE_OPERATIONAL) {
ret = -ENOENT; ret = -ENOENT;
@ -749,7 +750,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
} }
stop_BA_exit: stop_BA_exit:
spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); spin_unlock_bh(&sta->lock);
rcu_read_unlock(); rcu_read_unlock();
return ret; return ret;
} }
@ -778,12 +779,12 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
} }
state = &sta->ampdu_mlme.tid_state_tx[tid]; 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)) { if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
*state); *state);
spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); spin_unlock_bh(&sta->lock);
rcu_read_unlock(); rcu_read_unlock();
return; return;
} }
@ -796,7 +797,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
ieee80211_wake_queue(hw, sta->tid_to_tx_q[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(); rcu_read_unlock();
} }
EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
@ -830,10 +831,10 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
} }
state = &sta->ampdu_mlme.tid_state_tx[tid]; state = &sta->ampdu_mlme.tid_state_tx[tid];
spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); spin_lock_bh(&sta->lock);
if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); spin_unlock_bh(&sta->lock);
rcu_read_unlock(); rcu_read_unlock();
return; return;
} }
@ -860,7 +861,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
sta->ampdu_mlme.addba_req_num[tid] = 0; sta->ampdu_mlme.addba_req_num[tid] = 0;
kfree(sta->ampdu_mlme.tid_tx[tid]); kfree(sta->ampdu_mlme.tid_tx[tid]);
sta->ampdu_mlme.tid_tx[tid] = NULL; sta->ampdu_mlme.tid_tx[tid] = NULL;
spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); spin_unlock_bh(&sta->lock);
rcu_read_unlock(); rcu_read_unlock();
} }
@ -1315,7 +1316,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
* packet. If the STA went to power save mode, this will happen * packet. If the STA went to power save mode, this will happen
* happen when it wakes up for the next time. * 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: * This code races in the following way:
@ -1347,7 +1348,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
* can be unknown, for example with different interrupt status * can be unknown, for example with different interrupt status
* bits. * 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) { skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
ieee80211_remove_tx_extra(local, sta->key, skb, ieee80211_remove_tx_extra(local, sta->key, skb,
&status->control); &status->control);
@ -1355,7 +1356,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
return; return;
} }
if (!(sta->flags & WLAN_STA_PS) && if (!test_sta_flags(sta, WLAN_STA_PS) &&
!(status->control.flags & IEEE80211_TXCTL_REQUEUE)) { !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) {
/* Software retry the packet once */ /* Software retry the packet once */
status->control.flags |= IEEE80211_TXCTL_REQUEUE; status->control.flags |= IEEE80211_TXCTL_REQUEUE;
@ -1370,7 +1371,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
"queue_len=%d PS=%d @%lu\n", "queue_len=%d PS=%d @%lu\n",
wiphy_name(local->hw.wiphy), wiphy_name(local->hw.wiphy),
skb_queue_len(&sta->tx_filtered), skb_queue_len(&sta->tx_filtered),
!!(sta->flags & WLAN_STA_PS), jiffies); !!test_sta_flags(sta, WLAN_STA_PS), jiffies);
dev_kfree_skb(skb); dev_kfree_skb(skb);
} }
@ -1399,7 +1400,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
struct sta_info *sta; struct sta_info *sta;
sta = sta_info_get(local, hdr->addr1); sta = sta_info_get(local, hdr->addr1);
if (sta) { 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 * The STA is in power save mode, so assume
* that this TX packet failed because of that. * that this TX packet failed because of that.
@ -1701,13 +1702,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
local->hw.conf.beacon_int = 1000; local->hw.conf.beacon_int = 1000;
local->wstats_flags |= local->hw.max_rssi ? local->wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC |
IW_QUAL_LEVEL_UPDATED : IW_QUAL_LEVEL_INVALID; IEEE80211_HW_SIGNAL_DB |
local->wstats_flags |= local->hw.max_signal ? IEEE80211_HW_SIGNAL_DBM) ?
IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID; 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; 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; local->wstats_flags |= IW_QUAL_DBM;
result = sta_info_start(local); result = sta_info_start(local);

View file

@ -26,7 +26,7 @@ static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae)
{ {
if (ae) if (ae)
offset += 6; offset += 6;
return le32_to_cpu(get_unaligned((__le32 *) (preq_elem + offset))); return get_unaligned_le32(preq_elem + offset);
} }
/* HWMP IE processing macros */ /* HWMP IE processing macros */

View file

@ -79,7 +79,7 @@ void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
* *
* @sta: mes peer link to restart * @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) static inline void mesh_plink_fsm_restart(struct sta_info *sta)
{ {
@ -105,7 +105,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
if (!sta) if (!sta)
return NULL; return NULL;
sta->flags |= WLAN_STA_AUTHORIZED; sta->flags = WLAN_STA_AUTHORIZED;
sta->supp_rates[local->hw.conf.channel->band] = rates; sta->supp_rates[local->hw.conf.channel->band] = rates;
return sta; return sta;
@ -118,7 +118,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
* *
* All mesh paths with this peer as next hop will be flushed * 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) static void __mesh_plink_deactivate(struct sta_info *sta)
{ {
@ -139,9 +139,9 @@ static void __mesh_plink_deactivate(struct sta_info *sta)
*/ */
void mesh_plink_deactivate(struct sta_info *sta) void mesh_plink_deactivate(struct sta_info *sta)
{ {
spin_lock_bh(&sta->plink_lock); spin_lock_bh(&sta->lock);
__mesh_plink_deactivate(sta); __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, static int mesh_plink_frame_tx(struct net_device *dev,
@ -270,10 +270,10 @@ static void mesh_plink_timer(unsigned long data)
*/ */
sta = (struct sta_info *) data; sta = (struct sta_info *) data;
spin_lock_bh(&sta->plink_lock); spin_lock_bh(&sta->lock);
if (sta->ignore_plink_timer) { if (sta->ignore_plink_timer) {
sta->ignore_plink_timer = false; sta->ignore_plink_timer = false;
spin_unlock_bh(&sta->plink_lock); spin_unlock_bh(&sta->lock);
return; return;
} }
mpl_dbg("Mesh plink timer for %s fired on state %d\n", mpl_dbg("Mesh plink timer for %s fired on state %d\n",
@ -298,7 +298,7 @@ static void mesh_plink_timer(unsigned long data)
rand % sta->plink_timeout; rand % sta->plink_timeout;
++sta->plink_retries; ++sta->plink_retries;
mod_plink_timer(sta, sta->plink_timeout); 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, mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid,
0, 0); 0, 0);
break; break;
@ -311,7 +311,7 @@ static void mesh_plink_timer(unsigned long data)
reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT); reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT);
sta->plink_state = PLINK_HOLDING; sta->plink_state = PLINK_HOLDING;
mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); 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, mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid,
reason); reason);
break; break;
@ -319,10 +319,10 @@ static void mesh_plink_timer(unsigned long data)
/* holding timer */ /* holding timer */
del_timer(&sta->plink_timer); del_timer(&sta->plink_timer);
mesh_plink_fsm_restart(sta); mesh_plink_fsm_restart(sta);
spin_unlock_bh(&sta->plink_lock); spin_unlock_bh(&sta->lock);
break; break;
default: default:
spin_unlock_bh(&sta->plink_lock); spin_unlock_bh(&sta->lock);
break; break;
} }
} }
@ -344,16 +344,16 @@ int mesh_plink_open(struct sta_info *sta)
DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac);
#endif #endif
spin_lock_bh(&sta->plink_lock); spin_lock_bh(&sta->lock);
get_random_bytes(&llid, 2); get_random_bytes(&llid, 2);
sta->llid = llid; sta->llid = llid;
if (sta->plink_state != PLINK_LISTEN) { if (sta->plink_state != PLINK_LISTEN) {
spin_unlock_bh(&sta->plink_lock); spin_unlock_bh(&sta->lock);
return -EBUSY; return -EBUSY;
} }
sta->plink_state = PLINK_OPN_SNT; sta->plink_state = PLINK_OPN_SNT;
mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); 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", mpl_dbg("Mesh plink: starting establishment with %s\n",
print_mac(mac, sta->addr)); print_mac(mac, sta->addr));
@ -367,10 +367,10 @@ void mesh_plink_block(struct sta_info *sta)
DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac);
#endif #endif
spin_lock_bh(&sta->plink_lock); spin_lock_bh(&sta->lock);
__mesh_plink_deactivate(sta); __mesh_plink_deactivate(sta);
sta->plink_state = PLINK_BLOCKED; sta->plink_state = PLINK_BLOCKED;
spin_unlock_bh(&sta->plink_lock); spin_unlock_bh(&sta->lock);
} }
int mesh_plink_close(struct sta_info *sta) int mesh_plink_close(struct sta_info *sta)
@ -383,14 +383,14 @@ int mesh_plink_close(struct sta_info *sta)
mpl_dbg("Mesh plink: closing link with %s\n", mpl_dbg("Mesh plink: closing link with %s\n",
print_mac(mac, sta->addr)); print_mac(mac, sta->addr));
spin_lock_bh(&sta->plink_lock); spin_lock_bh(&sta->lock);
sta->reason = cpu_to_le16(MESH_LINK_CANCELLED); sta->reason = cpu_to_le16(MESH_LINK_CANCELLED);
reason = sta->reason; reason = sta->reason;
if (sta->plink_state == PLINK_LISTEN || if (sta->plink_state == PLINK_LISTEN ||
sta->plink_state == PLINK_BLOCKED) { sta->plink_state == PLINK_BLOCKED) {
mesh_plink_fsm_restart(sta); mesh_plink_fsm_restart(sta);
spin_unlock_bh(&sta->plink_lock); spin_unlock_bh(&sta->lock);
return 0; return 0;
} else if (sta->plink_state == PLINK_ESTAB) { } else if (sta->plink_state == PLINK_ESTAB) {
__mesh_plink_deactivate(sta); __mesh_plink_deactivate(sta);
@ -402,7 +402,7 @@ int mesh_plink_close(struct sta_info *sta)
sta->plink_state = PLINK_HOLDING; sta->plink_state = PLINK_HOLDING;
llid = sta->llid; llid = sta->llid;
plid = sta->plid; 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, mesh_plink_frame_tx(sta->sdata->dev, PLINK_CLOSE, sta->addr, llid,
plid, reason); plid, reason);
return 0; return 0;
@ -490,7 +490,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
/* avoid warning */ /* avoid warning */
break; break;
} }
spin_lock_bh(&sta->plink_lock); spin_lock_bh(&sta->lock);
} else if (!sta) { } else if (!sta) {
/* ftype == PLINK_OPEN */ /* ftype == PLINK_OPEN */
u64 rates; u64 rates;
@ -512,9 +512,9 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
return; return;
} }
event = OPN_ACPT; event = OPN_ACPT;
spin_lock_bh(&sta->plink_lock); spin_lock_bh(&sta->lock);
} else { } else {
spin_lock_bh(&sta->plink_lock); spin_lock_bh(&sta->lock);
switch (ftype) { switch (ftype) {
case PLINK_OPEN: case PLINK_OPEN:
if (!mesh_plink_free_count(sdata) || if (!mesh_plink_free_count(sdata) ||
@ -551,7 +551,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
break; break;
default: default:
mpl_dbg("Mesh plink: unknown frame subtype\n"); mpl_dbg("Mesh plink: unknown frame subtype\n");
spin_unlock_bh(&sta->plink_lock); spin_unlock_bh(&sta->lock);
rcu_read_unlock(); rcu_read_unlock();
return; return;
} }
@ -568,7 +568,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
switch (event) { switch (event) {
case CLS_ACPT: case CLS_ACPT:
mesh_plink_fsm_restart(sta); mesh_plink_fsm_restart(sta);
spin_unlock_bh(&sta->plink_lock); spin_unlock_bh(&sta->lock);
break; break;
case OPN_ACPT: case OPN_ACPT:
sta->plink_state = PLINK_OPN_RCVD; sta->plink_state = PLINK_OPN_RCVD;
@ -576,14 +576,14 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
get_random_bytes(&llid, 2); get_random_bytes(&llid, 2);
sta->llid = llid; sta->llid = llid;
mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); 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, mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid,
0, 0); 0, 0);
mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr,
llid, plid, 0); llid, plid, 0);
break; break;
default: default:
spin_unlock_bh(&sta->plink_lock); spin_unlock_bh(&sta->lock);
break; break;
} }
break; break;
@ -603,7 +603,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
sta->ignore_plink_timer = true; sta->ignore_plink_timer = true;
llid = sta->llid; llid = sta->llid;
spin_unlock_bh(&sta->plink_lock); spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
plid, reason); plid, reason);
break; break;
@ -612,7 +612,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
sta->plink_state = PLINK_OPN_RCVD; sta->plink_state = PLINK_OPN_RCVD;
sta->plid = plid; sta->plid = plid;
llid = sta->llid; llid = sta->llid;
spin_unlock_bh(&sta->plink_lock); spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
plid, 0); plid, 0);
break; break;
@ -622,10 +622,10 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
dot11MeshConfirmTimeout(sdata))) dot11MeshConfirmTimeout(sdata)))
sta->ignore_plink_timer = true; sta->ignore_plink_timer = true;
spin_unlock_bh(&sta->plink_lock); spin_unlock_bh(&sta->lock);
break; break;
default: default:
spin_unlock_bh(&sta->plink_lock); spin_unlock_bh(&sta->lock);
break; break;
} }
break; break;
@ -645,13 +645,13 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
sta->ignore_plink_timer = true; sta->ignore_plink_timer = true;
llid = sta->llid; llid = sta->llid;
spin_unlock_bh(&sta->plink_lock); spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
plid, reason); plid, reason);
break; break;
case OPN_ACPT: case OPN_ACPT:
llid = sta->llid; llid = sta->llid;
spin_unlock_bh(&sta->plink_lock); spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
plid, 0); plid, 0);
break; break;
@ -659,12 +659,12 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
del_timer(&sta->plink_timer); del_timer(&sta->plink_timer);
sta->plink_state = PLINK_ESTAB; sta->plink_state = PLINK_ESTAB;
mesh_plink_inc_estab_count(sdata); 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", mpl_dbg("Mesh plink with %s ESTABLISHED\n",
print_mac(mac, sta->addr)); print_mac(mac, sta->addr));
break; break;
default: default:
spin_unlock_bh(&sta->plink_lock); spin_unlock_bh(&sta->lock);
break; break;
} }
break; break;
@ -684,7 +684,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
sta->ignore_plink_timer = true; sta->ignore_plink_timer = true;
llid = sta->llid; llid = sta->llid;
spin_unlock_bh(&sta->plink_lock); spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
plid, reason); plid, reason);
break; break;
@ -692,14 +692,14 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
del_timer(&sta->plink_timer); del_timer(&sta->plink_timer);
sta->plink_state = PLINK_ESTAB; sta->plink_state = PLINK_ESTAB;
mesh_plink_inc_estab_count(sdata); 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", mpl_dbg("Mesh plink with %s ESTABLISHED\n",
print_mac(mac, sta->addr)); print_mac(mac, sta->addr));
mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
plid, 0); plid, 0);
break; break;
default: default:
spin_unlock_bh(&sta->plink_lock); spin_unlock_bh(&sta->lock);
break; break;
} }
break; break;
@ -713,18 +713,18 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
sta->plink_state = PLINK_HOLDING; sta->plink_state = PLINK_HOLDING;
llid = sta->llid; llid = sta->llid;
mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); 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, mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
plid, reason); plid, reason);
break; break;
case OPN_ACPT: case OPN_ACPT:
llid = sta->llid; llid = sta->llid;
spin_unlock_bh(&sta->plink_lock); spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
plid, 0); plid, 0);
break; break;
default: default:
spin_unlock_bh(&sta->plink_lock); spin_unlock_bh(&sta->lock);
break; break;
} }
break; break;
@ -734,7 +734,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
if (del_timer(&sta->plink_timer)) if (del_timer(&sta->plink_timer))
sta->ignore_plink_timer = 1; sta->ignore_plink_timer = 1;
mesh_plink_fsm_restart(sta); mesh_plink_fsm_restart(sta);
spin_unlock_bh(&sta->plink_lock); spin_unlock_bh(&sta->lock);
break; break;
case OPN_ACPT: case OPN_ACPT:
case CNF_ACPT: case CNF_ACPT:
@ -742,19 +742,19 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
case CNF_RJCT: case CNF_RJCT:
llid = sta->llid; llid = sta->llid;
reason = sta->reason; reason = sta->reason;
spin_unlock_bh(&sta->plink_lock); spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
plid, reason); plid, reason);
break; break;
default: default:
spin_unlock_bh(&sta->plink_lock); spin_unlock_bh(&sta->lock);
} }
break; break;
default: default:
/* should not get here, PLINK_BLOCKED is dealt with at the /* should not get here, PLINK_BLOCKED is dealt with at the
* beggining of the function * beggining of the function
*/ */
spin_unlock_bh(&sta->plink_lock); spin_unlock_bh(&sta->lock);
break; break;
} }

View file

@ -272,6 +272,12 @@ static void ieee80211_sta_wmm_params(struct net_device *dev,
int count; int count;
u8 *pos; u8 *pos;
if (!(ifsta->flags & IEEE80211_STA_WMM_ENABLED))
return;
if (!wmm_param)
return;
if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
return; return;
count = wmm_param[6] & 0x0f; count = wmm_param[6] & 0x0f;
@ -799,8 +805,10 @@ static void ieee80211_send_assoc(struct net_device *dev,
*pos++ = 1; /* WME ver */ *pos++ = 1; /* WME ver */
*pos++ = 0; *pos++ = 0;
} }
/* wmm support is a must to HT */ /* wmm support is a must to HT */
if (wmm && sband->ht_info.ht_supported) { if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) &&
sband->ht_info.ht_supported) {
__le16 tmp = cpu_to_le16(sband->ht_info.cap); __le16 tmp = cpu_to_le16(sband->ht_info.cap);
pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2); pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2);
*pos++ = WLAN_EID_HT_CAPABILITY; *pos++ = WLAN_EID_HT_CAPABILITY;
@ -1269,7 +1277,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev,
/* examine state machine */ /* 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) { if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) {
#ifdef CONFIG_MAC80211_HT_DEBUG #ifdef CONFIG_MAC80211_HT_DEBUG
@ -1336,7 +1344,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev,
tid_agg_rx->stored_mpdu_num = 0; tid_agg_rx->stored_mpdu_num = 0;
status = WLAN_STATUS_SUCCESS; status = WLAN_STATUS_SUCCESS;
end: end:
spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); spin_unlock_bh(&sta->lock);
end_no_lock: end_no_lock:
ieee80211_send_addba_resp(sta->sdata->dev, sta->addr, tid, ieee80211_send_addba_resp(sta->sdata->dev, sta->addr, tid,
@ -1368,10 +1376,10 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev,
state = &sta->ampdu_mlme.tid_state_tx[tid]; state = &sta->ampdu_mlme.tid_state_tx[tid];
spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); spin_lock_bh(&sta->lock);
if (!(*state & HT_ADDBA_REQUESTED_MSK)) { 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:" printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:"
"%d\n", *state); "%d\n", *state);
goto addba_resp_exit; goto addba_resp_exit;
@ -1379,7 +1387,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev,
if (mgmt->u.action.u.addba_resp.dialog_token != if (mgmt->u.action.u.addba_resp.dialog_token !=
sta->ampdu_mlme.tid_tx[tid]->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 #ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */ #endif /* CONFIG_MAC80211_HT_DEBUG */
@ -1403,7 +1411,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev,
ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); 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); printk(KERN_DEBUG "recipient accepted agg: tid %d \n", tid);
} else { } else {
printk(KERN_DEBUG "recipient rejected agg: tid %d \n", tid); printk(KERN_DEBUG "recipient rejected agg: tid %d \n", tid);
@ -1411,7 +1419,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev,
sta->ampdu_mlme.addba_req_num[tid]++; sta->ampdu_mlme.addba_req_num[tid]++;
/* this will allow the state check in stop_BA_session */ /* this will allow the state check in stop_BA_session */
*state = HT_AGG_STATE_OPERATIONAL; *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, ieee80211_stop_tx_ba_session(hw, sta->addr, tid,
WLAN_BACK_INITIATOR); WLAN_BACK_INITIATOR);
} }
@ -1481,17 +1489,17 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid,
} }
/* check if TID is in operational state */ /* 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] if (sta->ampdu_mlme.tid_state_rx[tid]
!= HT_AGG_STATE_OPERATIONAL) { != HT_AGG_STATE_OPERATIONAL) {
spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); spin_unlock_bh(&sta->lock);
rcu_read_unlock(); rcu_read_unlock();
return; return;
} }
sta->ampdu_mlme.tid_state_rx[tid] = sta->ampdu_mlme.tid_state_rx[tid] =
HT_AGG_STATE_REQ_STOP_BA_MSK | HT_AGG_STATE_REQ_STOP_BA_MSK |
(initiator << HT_AGG_STATE_INITIATOR_SHIFT); (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 /* stop HW Rx aggregation. ampdu_action existence
* already verified in session init so we add the BUG_ON */ * already verified in session init so we add the BUG_ON */
@ -1568,10 +1576,10 @@ static void ieee80211_sta_process_delba(struct net_device *dev,
ieee80211_sta_stop_rx_ba_session(dev, sta->addr, tid, ieee80211_sta_stop_rx_ba_session(dev, sta->addr, tid,
WLAN_BACK_INITIATOR, 0); WLAN_BACK_INITIATOR, 0);
else { /* WLAN_BACK_RECIPIENT */ else { /* WLAN_BACK_RECIPIENT */
spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); spin_lock_bh(&sta->lock);
sta->ampdu_mlme.tid_state_tx[tid] = sta->ampdu_mlme.tid_state_tx[tid] =
HT_AGG_STATE_OPERATIONAL; 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, ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid,
WLAN_BACK_RECIPIENT); WLAN_BACK_RECIPIENT);
} }
@ -1608,9 +1616,9 @@ void sta_addba_resp_timer_expired(unsigned long data)
state = &sta->ampdu_mlme.tid_state_tx[tid]; state = &sta->ampdu_mlme.tid_state_tx[tid];
/* check if the TID waits for addBA response */ /* 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)) { if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); spin_unlock_bh(&sta->lock);
*state = HT_AGG_STATE_IDLE; *state = HT_AGG_STATE_IDLE;
printk(KERN_DEBUG "timer expired on tid %d but we are not " printk(KERN_DEBUG "timer expired on tid %d but we are not "
"expecting addBA response there", tid); "expecting addBA response there", tid);
@ -1621,7 +1629,7 @@ void sta_addba_resp_timer_expired(unsigned long data)
/* go through the state check in stop_BA_session */ /* go through the state check in stop_BA_session */
*state = HT_AGG_STATE_OPERATIONAL; *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, ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid,
WLAN_BACK_INITIATOR); WLAN_BACK_INITIATOR);
@ -1987,8 +1995,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
local->hw.conf.channel->center_freq, local->hw.conf.channel->center_freq,
ifsta->ssid, ifsta->ssid_len); ifsta->ssid, ifsta->ssid_len);
if (bss) { if (bss) {
sta->last_rssi = bss->rssi;
sta->last_signal = bss->signal; sta->last_signal = bss->signal;
sta->last_qual = bss->qual;
sta->last_noise = bss->noise; sta->last_noise = bss->noise;
ieee80211_rx_bss_put(dev, bss); ieee80211_rx_bss_put(dev, bss);
} }
@ -2012,8 +2020,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
* to between the sta_info_alloc() and sta_info_insert() above. * to between the sta_info_alloc() and sta_info_insert() above.
*/ */
sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP | set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP |
WLAN_STA_AUTHORIZED; WLAN_STA_AUTHORIZED);
rates = 0; rates = 0;
basic_rates = 0; basic_rates = 0;
@ -2057,7 +2065,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
else else
sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; 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; struct ieee80211_ht_bss_info bss_info;
ieee80211_ht_cap_ie_to_ht_info( ieee80211_ht_cap_ie_to_ht_info(
(struct ieee80211_ht_cap *) (struct ieee80211_ht_cap *)
@ -2070,8 +2079,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
rate_control_rate_init(sta, local); rate_control_rate_init(sta, local);
if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { if (elems.wmm_param) {
sta->flags |= WLAN_STA_WME; set_sta_flags(sta, WLAN_STA_WME);
rcu_read_unlock(); rcu_read_unlock();
ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
elems.wmm_param_len); elems.wmm_param_len);
@ -2656,9 +2665,9 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
bss->timestamp = beacon_timestamp; bss->timestamp = beacon_timestamp;
bss->last_update = jiffies; bss->last_update = jiffies;
bss->rssi = rx_status->ssi;
bss->signal = rx_status->signal; bss->signal = rx_status->signal;
bss->noise = rx_status->noise; bss->noise = rx_status->noise;
bss->qual = rx_status->qual;
if (!beacon && !bss->probe_resp) if (!beacon && !bss->probe_resp)
bss->probe_resp = true; bss->probe_resp = true;
@ -2853,10 +2862,8 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); 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,
ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, elems.wmm_param_len);
elems.wmm_param_len);
}
/* Do not send changes to driver if we are scanning. This removes /* Do not send changes to driver if we are scanning. This removes
* requirement that driver's bss_info_changed function needs to be * requirement that driver's bss_info_changed function needs to be
@ -3456,9 +3463,9 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
!ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len)) !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len))
continue; continue;
if (!selected || top_rssi < bss->rssi) { if (!selected || top_rssi < bss->signal) {
selected = bss; selected = bss;
top_rssi = bss->rssi; top_rssi = bss->signal;
} }
} }
if (selected) if (selected)
@ -4089,8 +4096,8 @@ ieee80211_sta_scan_result(struct net_device *dev,
memset(&iwe, 0, sizeof(iwe)); memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVQUAL; iwe.cmd = IWEVQUAL;
iwe.u.qual.qual = bss->signal; iwe.u.qual.qual = bss->qual;
iwe.u.qual.level = bss->rssi; iwe.u.qual.level = bss->signal;
iwe.u.qual.noise = bss->noise; iwe.u.qual.noise = bss->noise;
iwe.u.qual.updated = local->wstats_flags; iwe.u.qual.updated = local->wstats_flags;
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
@ -4266,7 +4273,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev,
if (!sta) if (!sta)
return NULL; return NULL;
sta->flags |= WLAN_STA_AUTHORIZED; set_sta_flags(sta, WLAN_STA_AUTHORIZED);
sta->supp_rates[local->hw.conf.channel->band] = sta->supp_rates[local->hw.conf.channel->band] =
sdata->u.sta.supp_rates_bits[local->hw.conf.channel->band]; sdata->u.sta.supp_rates_bits[local->hw.conf.channel->band];

View file

@ -77,6 +77,134 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status,
return 0; 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 * This function copies a received frame to all monitor interfaces and
* returns a cleaned-up SKB that no longer includes the FCS nor the * returns a cleaned-up SKB that no longer includes the FCS nor the
@ -89,17 +217,6 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
{ {
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
int needed_headroom = 0; 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 sk_buff *skb, *skb2;
struct net_device *prev_dev = NULL; struct net_device *prev_dev = NULL;
int present_fcs_len = 0; int present_fcs_len = 0;
@ -116,8 +233,8 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
if (status->flag & RX_FLAG_RADIOTAP) if (status->flag & RX_FLAG_RADIOTAP)
rtap_len = ieee80211_get_radiotap_len(origskb->data); rtap_len = ieee80211_get_radiotap_len(origskb->data);
else else
/* room for radiotap header, always present fields and TSFT */ /* room for the radiotap header based on driver features */
needed_headroom = sizeof(*rthdr) + sizeof(*rtfixed) + 8; needed_headroom = ieee80211_rx_radiotap_len(local, status);
if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
present_fcs_len = FCS_LEN; present_fcs_len = FCS_LEN;
@ -163,55 +280,9 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
} }
/* if necessary, prepend radiotap information */ /* if necessary, prepend radiotap information */
if (!(status->flag & RX_FLAG_RADIOTAP)) { if (!(status->flag & RX_FLAG_RADIOTAP))
rtfixed = (void *) skb_push(skb, sizeof(*rtfixed)); ieee80211_add_rx_radiotap_header(local, skb, status, rate,
rtap_len = sizeof(*rthdr) + sizeof(*rtfixed); needed_headroom);
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);
}
skb_reset_mac_header(skb); skb_reset_mac_header(skb);
skb->ip_summed = CHECKSUM_UNNECESSARY; skb->ip_summed = CHECKSUM_UNNECESSARY;
@ -479,7 +550,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL && ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL &&
(rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) && (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) &&
rx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS && 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) && if ((!(rx->fc & IEEE80211_FCTL_FROMDS) &&
!(rx->fc & IEEE80211_FCTL_TODS) && !(rx->fc & IEEE80211_FCTL_TODS) &&
(rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)
@ -630,8 +701,7 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
if (sdata->bss) if (sdata->bss)
atomic_inc(&sdata->bss->num_sta_ps); atomic_inc(&sdata->bss->num_sta_ps);
sta->flags |= WLAN_STA_PS; set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL);
sta->flags &= ~WLAN_STA_PSPOLL;
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n", printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n",
dev->name, print_mac(mac, sta->addr), sta->aid); dev->name, print_mac(mac, sta->addr), sta->aid);
@ -652,7 +722,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
if (sdata->bss) if (sdata->bss)
atomic_dec(&sdata->bss->num_sta_ps); 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)) if (!skb_queue_empty(&sta->ps_tx_buf))
sta_info_clear_tim_bit(sta); sta_info_clear_tim_bit(sta);
@ -720,16 +790,17 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
sta->rx_fragments++; sta->rx_fragments++;
sta->rx_bytes += rx->skb->len; sta->rx_bytes += rx->skb->len;
sta->last_rssi = rx->status->ssi;
sta->last_signal = rx->status->signal; sta->last_signal = rx->status->signal;
sta->last_qual = rx->status->qual;
sta->last_noise = rx->status->noise; sta->last_noise = rx->status->noise;
if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) { if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) {
/* Change STA power saving mode only in the end of a frame /* Change STA power saving mode only in the end of a frame
* exchange sequence */ * 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); 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)) (rx->fc & IEEE80211_FCTL_PM))
ap_sta_ps_start(dev, sta); ap_sta_ps_start(dev, sta);
} }
@ -983,7 +1054,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
* Tell TX path to send one frame even though the STA may * Tell TX path to send one frame even though the STA may
* still remain is PS mode after this frame exchange. * 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 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n", printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n",
@ -1046,7 +1117,8 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx)
static int static int
ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx) 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 #ifdef CONFIG_MAC80211_DEBUG
if (net_ratelimit()) if (net_ratelimit())
printk(KERN_DEBUG "%s: dropped frame " printk(KERN_DEBUG "%s: dropped frame "

View file

@ -202,14 +202,12 @@ void sta_info_destroy(struct sta_info *sta)
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
for (i = 0; i < STA_TID_NUM; i++) { 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]) if (sta->ampdu_mlme.tid_rx[i])
del_timer_sync(&sta->ampdu_mlme.tid_rx[i]->session_timer); 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]) if (sta->ampdu_mlme.tid_tx[i])
del_timer_sync(&sta->ampdu_mlme.tid_tx[i]->addba_resp_timer); 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); __sta_info_free(local, sta);
@ -236,6 +234,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
if (!sta) if (!sta)
return NULL; return NULL;
spin_lock_init(&sta->lock);
memcpy(sta->addr, addr, ETH_ALEN); memcpy(sta->addr, addr, ETH_ALEN);
sta->local = local; sta->local = local;
sta->sdata = sdata; sta->sdata = sdata;
@ -249,8 +249,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
return NULL; 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++) { for (i = 0; i < STA_TID_NUM; i++) {
/* timer_to_tid must be initialized with identity mapping to /* timer_to_tid must be initialized with identity mapping to
* enable session_timer's data differentiation. refer to * enable session_timer's data differentiation. refer to
@ -276,7 +274,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
#ifdef CONFIG_MAC80211_MESH #ifdef CONFIG_MAC80211_MESH
sta->plink_state = PLINK_LISTEN; sta->plink_state = PLINK_LISTEN;
spin_lock_init(&sta->plink_lock);
init_timer(&sta->plink_timer); init_timer(&sta->plink_timer);
#endif #endif
@ -437,8 +434,7 @@ void __sta_info_unlink(struct sta_info **sta)
list_del(&(*sta)->list); list_del(&(*sta)->list);
if ((*sta)->flags & WLAN_STA_PS) { if (test_and_clear_sta_flags(*sta, WLAN_STA_PS)) {
(*sta)->flags &= ~WLAN_STA_PS;
if (sdata->bss) if (sdata->bss)
atomic_dec(&sdata->bss->num_sta_ps); atomic_dec(&sdata->bss->num_sta_ps);
__sta_info_clear_tim_bit(sdata->bss, *sta); __sta_info_clear_tim_bit(sdata->bss, *sta);

View file

@ -129,23 +129,19 @@ enum plink_state {
* *
* @tid_state_rx: TID's state in Rx session state machine. * @tid_state_rx: TID's state in Rx session state machine.
* @tid_rx: aggregation info for Rx per TID * @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_state_tx: TID's state in Tx session state machine.
* @tid_tx: aggregation info for Tx per TID * @tid_tx: aggregation info for Tx per TID
* @addba_req_num: number of times addBA request has been sent. * @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; * @dialog_token_allocator: dialog token enumerator for each new session;
*/ */
struct sta_ampdu_mlme { struct sta_ampdu_mlme {
/* rx */ /* rx */
u8 tid_state_rx[STA_TID_NUM]; u8 tid_state_rx[STA_TID_NUM];
struct tid_ampdu_rx *tid_rx[STA_TID_NUM]; struct tid_ampdu_rx *tid_rx[STA_TID_NUM];
spinlock_t ampdu_rx;
/* tx */ /* tx */
u8 tid_state_tx[STA_TID_NUM]; u8 tid_state_tx[STA_TID_NUM];
struct tid_ampdu_tx *tid_tx[STA_TID_NUM]; struct tid_ampdu_tx *tid_tx[STA_TID_NUM];
u8 addba_req_num[STA_TID_NUM]; u8 addba_req_num[STA_TID_NUM];
spinlock_t ampdu_tx;
u8 dialog_token_allocator; u8 dialog_token_allocator;
}; };
@ -177,6 +173,8 @@ struct sta_ampdu_mlme {
* @rx_bytes: Number of bytes received from this STA * @rx_bytes: Number of bytes received from this STA
* @supp_rates: Bitmap of supported rates (per band) * @supp_rates: Bitmap of supported rates (per band)
* @ht_info: HT capabilities of this STA * @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 { struct sta_info {
/* General information, mostly static */ /* General information, mostly static */
@ -187,6 +185,7 @@ struct sta_info {
struct ieee80211_key *key; struct ieee80211_key *key;
struct rate_control_ref *rate_ctrl; struct rate_control_ref *rate_ctrl;
void *rate_ctrl_priv; void *rate_ctrl_priv;
spinlock_t lock;
struct ieee80211_ht_info ht_info; struct ieee80211_ht_info ht_info;
u64 supp_rates[IEEE80211_NUM_BANDS]; u64 supp_rates[IEEE80211_NUM_BANDS];
u8 addr[ETH_ALEN]; u8 addr[ETH_ALEN];
@ -199,7 +198,7 @@ struct sta_info {
*/ */
u8 pin_status; u8 pin_status;
/* frequently updated information, needs locking? */ /* frequently updated information, locked with lock spinlock */
u32 flags; u32 flags;
/* /*
@ -217,8 +216,8 @@ struct sta_info {
* from this STA */ * from this STA */
unsigned long rx_fragments; /* number of received MPDUs */ unsigned long rx_fragments; /* number of received MPDUs */
unsigned long rx_dropped; /* number of dropped MPDUs from this STA */ 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_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 */ int last_noise; /* noise of last received frame from this STA */
/* last received seq/frag number from this STA (per RX queue) */ /* last received seq/frag number from this STA (per RX queue) */
__le16 last_seq_ctrl[NUM_RX_DATA_QUEUES]; __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES];
@ -251,7 +250,7 @@ struct sta_info {
int channel_use_raw; int channel_use_raw;
/* /*
* Aggregation information, comes with own locking. * Aggregation information, locked with lock.
*/ */
struct sta_ampdu_mlme ampdu_mlme; struct sta_ampdu_mlme ampdu_mlme;
u8 timer_to_tid[STA_TID_NUM]; /* identity mapping to ID timers */ u8 timer_to_tid[STA_TID_NUM]; /* identity mapping to ID timers */
@ -270,9 +269,6 @@ struct sta_info {
enum plink_state plink_state; enum plink_state plink_state;
u32 plink_timeout; u32 plink_timeout;
struct timer_list plink_timer; 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 #endif
#ifdef CONFIG_MAC80211_DEBUGFS #ifdef CONFIG_MAC80211_DEBUGFS
@ -299,6 +295,64 @@ static inline enum plink_state sta_plink_state(struct sta_info *sta)
return PLINK_LISTEN; 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 */ /* Maximum number of concurrently registered stations */
#define MAX_STA_COUNT 2007 #define MAX_STA_COUNT 2007

View file

@ -8,23 +8,22 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/bitops.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <asm/unaligned.h>
#include <net/mac80211.h> #include <net/mac80211.h>
#include "key.h" #include "key.h"
#include "tkip.h" #include "tkip.h"
#include "wep.h" #include "wep.h"
/* TKIP key mixing functions */
#define PHASE1_LOOP_COUNT 8 #define PHASE1_LOOP_COUNT 8
/*
/* 2-byte by 2-byte subset of the full AES S-box table; second part of this * 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 */ * table is identical to first part but byte-swapped
*/
static const u16 tkip_sbox[256] = static const u16 tkip_sbox[256] =
{ {
0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154, 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
@ -61,53 +60,13 @@ static const u16 tkip_sbox[256] =
0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A, 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
}; };
static u16 tkipS(u16 val)
static inline u16 Mk16(u8 x, u8 y)
{ {
return ((u16) x << 8) | (u16) y; return tkip_sbox[val & 0xff] ^ swab16(tkip_sbox[val >> 8]);
} }
/*
static inline u8 Hi8(u16 v) * P1K := Phase1(TA, TK, TSC)
{
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)
* TA = transmitter address (48 bits) * TA = transmitter address (48 bits)
* TK = dot11DefaultKeyValue or dot11KeyMappingValue (128 bits) * TK = dot11DefaultKeyValue or dot11KeyMappingValue (128 bits)
* TSC = TKIP sequence counter (48 bits, only 32 msb bits used) * TSC = TKIP sequence counter (48 bits, only 32 msb bits used)
@ -118,23 +77,22 @@ static void tkip_mixing_phase1(const u8 *ta, const u8 *tk, u32 tsc_IV32,
{ {
int i, j; int i, j;
p1k[0] = Lo16(tsc_IV32); p1k[0] = tsc_IV32 & 0xFFFF;
p1k[1] = Hi16(tsc_IV32); p1k[1] = tsc_IV32 >> 16;
p1k[2] = Mk16(ta[1], ta[0]); p1k[2] = get_unaligned_le16(ta + 0);
p1k[3] = Mk16(ta[3], ta[2]); p1k[3] = get_unaligned_le16(ta + 2);
p1k[4] = Mk16(ta[5], ta[4]); p1k[4] = get_unaligned_le16(ta + 4);
for (i = 0; i < PHASE1_LOOP_COUNT; i++) { for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
j = 2 * (i & 1); j = 2 * (i & 1);
p1k[0] += tkip_S(p1k[4] ^ Mk16(tk[ 1 + j], tk[ 0 + j])); p1k[0] += tkipS(p1k[4] ^ get_unaligned_le16(tk + 0 + j));
p1k[1] += tkip_S(p1k[0] ^ Mk16(tk[ 5 + j], tk[ 4 + j])); p1k[1] += tkipS(p1k[0] ^ get_unaligned_le16(tk + 4 + j));
p1k[2] += tkip_S(p1k[1] ^ Mk16(tk[ 9 + j], tk[ 8 + j])); p1k[2] += tkipS(p1k[1] ^ get_unaligned_le16(tk + 8 + j));
p1k[3] += tkip_S(p1k[2] ^ Mk16(tk[13 + j], tk[12 + j])); p1k[3] += tkipS(p1k[2] ^ get_unaligned_le16(tk + 12 + j));
p1k[4] += tkip_S(p1k[3] ^ Mk16(tk[ 1 + j], tk[ 0 + j])) + i; p1k[4] += tkipS(p1k[3] ^ get_unaligned_le16(tk + 0 + j)) + i;
} }
} }
static void tkip_mixing_phase2(const u16 *p1k, const u8 *tk, u16 tsc_IV16, static void tkip_mixing_phase2(const u16 *p1k, const u8 *tk, u16 tsc_IV16,
u8 *rc4key) u8 *rc4key)
{ {
@ -148,31 +106,29 @@ static void tkip_mixing_phase2(const u16 *p1k, const u8 *tk, u16 tsc_IV16,
ppk[4] = p1k[4]; ppk[4] = p1k[4];
ppk[5] = p1k[4] + tsc_IV16; ppk[5] = p1k[4] + tsc_IV16;
ppk[0] += tkip_S(ppk[5] ^ Mk16(tk[ 1], tk[ 0])); ppk[0] += tkipS(ppk[5] ^ get_unaligned_le16(tk + 0));
ppk[1] += tkip_S(ppk[0] ^ Mk16(tk[ 3], tk[ 2])); ppk[1] += tkipS(ppk[0] ^ get_unaligned_le16(tk + 2));
ppk[2] += tkip_S(ppk[1] ^ Mk16(tk[ 5], tk[ 4])); ppk[2] += tkipS(ppk[1] ^ get_unaligned_le16(tk + 4));
ppk[3] += tkip_S(ppk[2] ^ Mk16(tk[ 7], tk[ 6])); ppk[3] += tkipS(ppk[2] ^ get_unaligned_le16(tk + 6));
ppk[4] += tkip_S(ppk[3] ^ Mk16(tk[ 9], tk[ 8])); ppk[4] += tkipS(ppk[3] ^ get_unaligned_le16(tk + 8));
ppk[5] += tkip_S(ppk[4] ^ Mk16(tk[11], tk[10])); ppk[5] += tkipS(ppk[4] ^ get_unaligned_le16(tk + 10));
ppk[0] += RotR1(ppk[5] ^ Mk16(tk[13], tk[12])); ppk[0] += ror16(ppk[5] ^ get_unaligned_le16(tk + 12), 1);
ppk[1] += RotR1(ppk[0] ^ Mk16(tk[15], tk[14])); ppk[1] += ror16(ppk[0] ^ get_unaligned_le16(tk + 14), 1);
ppk[2] += RotR1(ppk[1]); ppk[2] += ror16(ppk[1], 1);
ppk[3] += RotR1(ppk[2]); ppk[3] += ror16(ppk[2], 1);
ppk[4] += RotR1(ppk[3]); ppk[4] += ror16(ppk[3], 1);
ppk[5] += RotR1(ppk[4]); ppk[5] += ror16(ppk[4], 1);
rc4key[0] = Hi8(tsc_IV16); rc4key[0] = tsc_IV16 >> 8;
rc4key[1] = (Hi8(tsc_IV16) | 0x20) & 0x7f; rc4key[1] = ((tsc_IV16 >> 8) | 0x20) & 0x7f;
rc4key[2] = Lo8(tsc_IV16); rc4key[2] = tsc_IV16 & 0xFF;
rc4key[3] = Lo8((ppk[5] ^ Mk16(tk[1], tk[0])) >> 1); rc4key[3] = ((ppk[5] ^ get_unaligned_le16(tk)) >> 1) & 0xFF;
for (i = 0; i < 6; i++) { rc4key += 4;
rc4key[4 + 2 * i] = Lo8(ppk[i]); for (i = 0; i < 6; i++)
rc4key[5 + 2 * i] = Hi8(ppk[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 /* 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 * of the IV. Returns pointer to the octet following IVs (i.e., beginning of
* the packet payload). */ * the packet payload). */
@ -183,14 +139,10 @@ u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key,
*pos++ = iv1; *pos++ = iv1;
*pos++ = iv2; *pos++ = iv2;
*pos++ = (key->conf.keyidx << 6) | (1 << 5) /* Ext IV */; *pos++ = (key->conf.keyidx << 6) | (1 << 5) /* Ext IV */;
*pos++ = key->u.tkip.iv32 & 0xff; put_unaligned_le32(key->u.tkip.iv32, pos);
*pos++ = (key->u.tkip.iv32 >> 8) & 0xff; return pos + 4;
*pos++ = (key->u.tkip.iv32 >> 16) & 0xff;
*pos++ = (key->u.tkip.iv32 >> 24) & 0xff;
return pos;
} }
void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta, void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta,
u16 *phase1key) u16 *phase1key)
{ {
@ -228,10 +180,8 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
u16 iv16; u16 iv16;
u32 iv32; u32 iv32;
iv16 = data[hdr_len] << 8; iv16 = data[hdr_len + 2] | (data[hdr_len] << 8);
iv16 += data[hdr_len + 2]; iv32 = get_unaligned_le32(data + hdr_len + 4);
iv32 = data[hdr_len + 4] | (data[hdr_len + 5] << 8) |
(data[hdr_len + 6] << 16) | (data[hdr_len + 7] << 24);
#ifdef CONFIG_TKIP_DEBUG #ifdef CONFIG_TKIP_DEBUG
printk(KERN_DEBUG "TKIP encrypt: iv16 = 0x%04x, iv32 = 0x%08x\n", printk(KERN_DEBUG "TKIP encrypt: iv16 = 0x%04x, iv32 = 0x%08x\n",
@ -281,7 +231,6 @@ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len); ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len);
} }
/* Decrypt packet payload with TKIP using @key. @pos is a pointer to the /* 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., * 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 * including IV, Ext. IV, real data, Michael MIC, ICV. @payload_len is the
@ -302,7 +251,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
iv16 = (pos[0] << 8) | pos[2]; iv16 = (pos[0] << 8) | pos[2];
keyid = pos[3]; keyid = pos[3];
iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24); iv32 = get_unaligned_le32(pos + 4);
pos += 8; pos += 8;
#ifdef CONFIG_TKIP_DEBUG #ifdef CONFIG_TKIP_DEBUG
{ {
@ -409,5 +358,3 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
return res; return res;
} }

View file

@ -256,7 +256,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
if (tx->flags & IEEE80211_TX_PS_BUFFERED) if (tx->flags & IEEE80211_TX_PS_BUFFERED)
return TX_CONTINUE; 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 (likely(tx->flags & IEEE80211_TX_UNICAST)) {
if (unlikely(!(sta_flags & WLAN_STA_ASSOC) && if (unlikely(!(sta_flags & WLAN_STA_ASSOC) &&
@ -391,6 +391,7 @@ static ieee80211_tx_result
ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
{ {
struct sta_info *sta = tx->sta; struct sta_info *sta = tx->sta;
u32 staflags;
DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac);
if (unlikely(!sta || if (unlikely(!sta ||
@ -398,8 +399,10 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
(tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP))) (tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)))
return TX_CONTINUE; return TX_CONTINUE;
if (unlikely((sta->flags & WLAN_STA_PS) && staflags = get_sta_flags(sta);
!(sta->flags & WLAN_STA_PSPOLL))) {
if (unlikely((staflags & WLAN_STA_PS) &&
!(staflags & WLAN_STA_PSPOLL))) {
struct ieee80211_tx_packet_data *pkt_data; struct ieee80211_tx_packet_data *pkt_data;
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries " printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries "
@ -430,13 +433,13 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
return TX_QUEUED; return TX_QUEUED;
} }
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG #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 " printk(KERN_DEBUG "%s: STA %s in PS mode, but pspoll "
"set -> send frame\n", tx->dev->name, "set -> send frame\n", tx->dev->name,
print_mac(mac, sta->addr)); print_mac(mac, sta->addr));
} }
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
sta->flags &= ~WLAN_STA_PSPOLL; clear_sta_flags(sta, WLAN_STA_PSPOLL);
return TX_CONTINUE; return TX_CONTINUE;
} }
@ -697,7 +700,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
(tx->rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) && (tx->rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
tx->sdata->bss_conf.use_short_preamble && tx->sdata->bss_conf.use_short_preamble &&
(!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) { (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) {
tx->control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; tx->control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
} }
@ -1025,10 +1028,8 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
if (!tx->sta) if (!tx->sta)
control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT;
else if (tx->sta->flags & WLAN_STA_CLEAR_PS_FILT) { else if (test_and_clear_sta_flags(tx->sta, WLAN_STA_CLEAR_PS_FILT))
control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT;
tx->sta->flags &= ~WLAN_STA_CLEAR_PS_FILT;
}
hdrlen = ieee80211_get_hdrlen(tx->fc); hdrlen = ieee80211_get_hdrlen(tx->fc);
if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) { if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) {
@ -1336,6 +1337,8 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
pkt_data->ifindex = dev->ifindex; pkt_data->ifindex = dev->ifindex;
pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
/* Interfaces should always request a status report */
pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS;
/* /*
* fix up the pointers accounting for the radiotap * fix up the pointers accounting for the radiotap
@ -1486,12 +1489,12 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
rcu_read_lock(); rcu_read_lock();
sta = sta_info_get(local, hdr.addr1); sta = sta_info_get(local, hdr.addr1);
if (sta) if (sta)
sta_flags = sta->flags; sta_flags = get_sta_flags(sta);
rcu_read_unlock(); rcu_read_unlock();
} }
/* receiver is QoS enabled, use a QoS type frame */ /* receiver and we are QoS enabled, use a QoS type frame */
if (sta_flags & WLAN_STA_WME) { if (sta_flags & WLAN_STA_WME && local->hw.queues >= 4) {
fc |= IEEE80211_STYPE_QOS_DATA; fc |= IEEE80211_STYPE_QOS_DATA;
hdrlen += 2; hdrlen += 2;
} }
@ -1617,6 +1620,9 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
if (ethertype == ETH_P_PAE) if (ethertype == ETH_P_PAE)
pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME; pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME;
/* Interfaces should always request a status report */
pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS;
skb->dev = local->mdev; skb->dev = local->mdev;
dev->stats.tx_packets++; dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len; dev->stats.tx_bytes += skb->len;

View file

@ -169,14 +169,26 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev,
range->num_encoding_sizes = 2; range->num_encoding_sizes = 2;
range->max_encoding_tokens = NUM_DEFAULT_KEYS; range->max_encoding_tokens = NUM_DEFAULT_KEYS;
range->max_qual.qual = local->hw.max_signal; if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC ||
range->max_qual.level = local->hw.max_rssi; local->hw.flags & IEEE80211_HW_SIGNAL_DB)
range->max_qual.noise = local->hw.max_noise; 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->max_qual.updated = local->wstats_flags;
range->avg_qual.qual = local->hw.max_signal/2; range->avg_qual.qual = 50;
range->avg_qual.level = 0; /* not always true but better than nothing */
range->avg_qual.noise = 0; 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->avg_qual.updated = local->wstats_flags;
range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
@ -996,8 +1008,8 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev
wstats->qual.noise = 0; wstats->qual.noise = 0;
wstats->qual.updated = IW_QUAL_ALL_INVALID; wstats->qual.updated = IW_QUAL_ALL_INVALID;
} else { } else {
wstats->qual.level = sta->last_rssi; wstats->qual.level = sta->last_signal;
wstats->qual.qual = sta->last_signal; wstats->qual.qual = sta->last_qual;
wstats->qual.noise = sta->last_noise; wstats->qual.noise = sta->last_noise;
wstats->qual.updated = local->wstats_flags; wstats->qual.updated = local->wstats_flags;
} }

View file

@ -143,8 +143,11 @@ void cfg80211_put_dev(struct cfg80211_registered_device *drv)
int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
char *newname) char *newname)
{ {
struct cfg80211_registered_device *drv;
int idx, taken = -1, result, digits; int idx, taken = -1, result, digits;
mutex_lock(&cfg80211_drv_mutex);
/* prohibit calling the thing phy%d when %d is not its number */ /* prohibit calling the thing phy%d when %d is not its number */
sscanf(newname, PHY_NAME "%d%n", &idx, &taken); sscanf(newname, PHY_NAME "%d%n", &idx, &taken);
if (taken == strlen(newname) && idx != rdev->idx) { if (taken == strlen(newname) && idx != rdev->idx) {
@ -156,14 +159,30 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
* deny the name if it is phy<idx> where <idx> is printed * deny the name if it is phy<idx> where <idx> is printed
* without leading zeroes. taken == strlen(newname) here * without leading zeroes. taken == strlen(newname) here
*/ */
result = -EINVAL;
if (taken == strlen(PHY_NAME) + digits) 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); result = device_rename(&rdev->wiphy.dev, newname);
if (result) if (result)
return result; goto out_unlock;
if (!debugfs_rename(rdev->wiphy.debugfsdir->d_parent, if (!debugfs_rename(rdev->wiphy.debugfsdir->d_parent,
rdev->wiphy.debugfsdir, rdev->wiphy.debugfsdir,
@ -172,9 +191,13 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
printk(KERN_ERR "cfg80211: failed to rename debugfs dir to %s!\n", printk(KERN_ERR "cfg80211: failed to rename debugfs dir to %s!\n",
newname); 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 */ /* exported functions */

View file

@ -59,23 +59,21 @@ int ieee80211_radiotap_iterator_init(
return -EINVAL; return -EINVAL;
/* sanity check for allowed length and radiotap length field */ /* 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; return -EINVAL;
iterator->rtheader = radiotap_header; iterator->rtheader = radiotap_header;
iterator->max_length = le16_to_cpu(get_unaligned( iterator->max_length = get_unaligned_le16(&radiotap_header->it_len);
&radiotap_header->it_len));
iterator->arg_index = 0; iterator->arg_index = 0;
iterator->bitmap_shifter = le32_to_cpu(get_unaligned( iterator->bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present);
&radiotap_header->it_present));
iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header); iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header);
iterator->this_arg = NULL; iterator->this_arg = NULL;
/* find payload start allowing for extended bitmap(s) */ /* find payload start allowing for extended bitmap(s) */
if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) { if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) {
while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) & while (get_unaligned_le32(iterator->arg) &
(1<<IEEE80211_RADIOTAP_EXT)) { (1 << IEEE80211_RADIOTAP_EXT)) {
iterator->arg += sizeof(u32); iterator->arg += sizeof(u32);
/* /*
@ -241,8 +239,8 @@ int ieee80211_radiotap_iterator_next(
if (iterator->bitmap_shifter & 1) { if (iterator->bitmap_shifter & 1) {
/* b31 was set, there is more */ /* b31 was set, there is more */
/* move to next u32 bitmap */ /* move to next u32 bitmap */
iterator->bitmap_shifter = le32_to_cpu( iterator->bitmap_shifter =
get_unaligned(iterator->next_bitmap)); get_unaligned_le32(iterator->next_bitmap);
iterator->next_bitmap++; iterator->next_bitmap++;
} else } else
/* no more bitmaps: end */ /* no more bitmaps: end */