aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/b43legacy
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2012-01-05 10:12:45 -0500
committerJohn W. Linville <linville@tuxdriver.com>2012-01-05 10:13:24 -0500
commit1032c736e81cdf490ae62f86da7efe67c3c3e61d (patch)
treea0c3919849f97dbbc5ea7c6a9ac1d7a639e44a73 /drivers/net/wireless/b43legacy
parent117ff42fd43e92d24c6aa6f3e4f0f1e1edada140 (diff)
parentcb00ec382b57d35b955c085198cd54a0c1fcdc94 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Conflicts: drivers/net/wireless/b43legacy/dma.c
Diffstat (limited to 'drivers/net/wireless/b43legacy')
-rw-r--r--drivers/net/wireless/b43legacy/b43legacy.h20
-rw-r--r--drivers/net/wireless/b43legacy/dma.c65
-rw-r--r--drivers/net/wireless/b43legacy/dma.h5
-rw-r--r--drivers/net/wireless/b43legacy/main.c86
4 files changed, 126 insertions, 50 deletions
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h
index 1d4fc9db7f5e..98e3d44400c6 100644
--- a/drivers/net/wireless/b43legacy/b43legacy.h
+++ b/drivers/net/wireless/b43legacy/b43legacy.h
@@ -560,8 +560,16 @@ struct b43legacy_key {
560 u8 algorithm; 560 u8 algorithm;
561}; 561};
562 562
563#define B43legacy_QOS_QUEUE_NUM 4
564
563struct b43legacy_wldev; 565struct b43legacy_wldev;
564 566
567/* QOS parameters for a queue. */
568struct b43legacy_qos_params {
569 /* The QOS parameters */
570 struct ieee80211_tx_queue_params p;
571};
572
565/* Data structure for the WLAN parts (802.11 cores) of the b43legacy chip. */ 573/* Data structure for the WLAN parts (802.11 cores) of the b43legacy chip. */
566struct b43legacy_wl { 574struct b43legacy_wl {
567 /* Pointer to the active wireless device on this chip */ 575 /* Pointer to the active wireless device on this chip */
@@ -611,6 +619,18 @@ struct b43legacy_wl {
611 bool beacon1_uploaded; 619 bool beacon1_uploaded;
612 bool beacon_templates_virgin; /* Never wrote the templates? */ 620 bool beacon_templates_virgin; /* Never wrote the templates? */
613 struct work_struct beacon_update_trigger; 621 struct work_struct beacon_update_trigger;
622 /* The current QOS parameters for the 4 queues. */
623 struct b43legacy_qos_params qos_params[B43legacy_QOS_QUEUE_NUM];
624
625 /* Packet transmit work */
626 struct work_struct tx_work;
627
628 /* Queue of packets to be transmitted. */
629 struct sk_buff_head tx_queue[B43legacy_QOS_QUEUE_NUM];
630
631 /* Flag that implement the queues stopping. */
632 bool tx_queue_stopped[B43legacy_QOS_QUEUE_NUM];
633
614}; 634};
615 635
616/* Pointers to the firmware data and meta information about it. */ 636/* Pointers to the firmware data and meta information about it. */
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
index 1ee31c55c7ba..f1f8bd09bd87 100644
--- a/drivers/net/wireless/b43legacy/dma.c
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -727,7 +727,6 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
727 } else 727 } else
728 B43legacy_WARN_ON(1); 728 B43legacy_WARN_ON(1);
729 } 729 }
730 spin_lock_init(&ring->lock);
731#ifdef CONFIG_B43LEGACY_DEBUG 730#ifdef CONFIG_B43LEGACY_DEBUG
732 ring->last_injected_overflow = jiffies; 731 ring->last_injected_overflow = jiffies;
733#endif 732#endif
@@ -1144,10 +1143,8 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev,
1144{ 1143{
1145 struct b43legacy_dmaring *ring; 1144 struct b43legacy_dmaring *ring;
1146 int err = 0; 1145 int err = 0;
1147 unsigned long flags;
1148 1146
1149 ring = priority_to_txring(dev, skb_get_queue_mapping(skb)); 1147 ring = priority_to_txring(dev, skb_get_queue_mapping(skb));
1150 spin_lock_irqsave(&ring->lock, flags);
1151 B43legacy_WARN_ON(!ring->tx); 1148 B43legacy_WARN_ON(!ring->tx);
1152 1149
1153 if (unlikely(ring->stopped)) { 1150 if (unlikely(ring->stopped)) {
@@ -1157,16 +1154,14 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev,
1157 * For now, just refuse the transmit. */ 1154 * For now, just refuse the transmit. */
1158 if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE)) 1155 if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE))
1159 b43legacyerr(dev->wl, "Packet after queue stopped\n"); 1156 b43legacyerr(dev->wl, "Packet after queue stopped\n");
1160 err = -ENOSPC; 1157 return -ENOSPC;
1161 goto out_unlock;
1162 } 1158 }
1163 1159
1164 if (unlikely(WARN_ON(free_slots(ring) < SLOTS_PER_PACKET))) { 1160 if (unlikely(WARN_ON(free_slots(ring) < SLOTS_PER_PACKET))) {
1165 /* If we get here, we have a real error with the queue 1161 /* If we get here, we have a real error with the queue
1166 * full, but queues not stopped. */ 1162 * full, but queues not stopped. */
1167 b43legacyerr(dev->wl, "DMA queue overflow\n"); 1163 b43legacyerr(dev->wl, "DMA queue overflow\n");
1168 err = -ENOSPC; 1164 return -ENOSPC;
1169 goto out_unlock;
1170 } 1165 }
1171 1166
1172 /* dma_tx_fragment might reallocate the skb, so invalidate pointers pointing 1167 /* dma_tx_fragment might reallocate the skb, so invalidate pointers pointing
@@ -1176,25 +1171,23 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev,
1176 /* Drop this packet, as we don't have the encryption key 1171 /* Drop this packet, as we don't have the encryption key
1177 * anymore and must not transmit it unencrypted. */ 1172 * anymore and must not transmit it unencrypted. */
1178 dev_kfree_skb_any(skb); 1173 dev_kfree_skb_any(skb);
1179 err = 0; 1174 return 0;
1180 goto out_unlock;
1181 } 1175 }
1182 if (unlikely(err)) { 1176 if (unlikely(err)) {
1183 b43legacyerr(dev->wl, "DMA tx mapping failure\n"); 1177 b43legacyerr(dev->wl, "DMA tx mapping failure\n");
1184 goto out_unlock; 1178 return err;
1185 } 1179 }
1186 if ((free_slots(ring) < SLOTS_PER_PACKET) || 1180 if ((free_slots(ring) < SLOTS_PER_PACKET) ||
1187 should_inject_overflow(ring)) { 1181 should_inject_overflow(ring)) {
1188 /* This TX ring is full. */ 1182 /* This TX ring is full. */
1189 ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring)); 1183 unsigned int skb_mapping = skb_get_queue_mapping(skb);
1184 ieee80211_stop_queue(dev->wl->hw, skb_mapping);
1185 dev->wl->tx_queue_stopped[skb_mapping] = 1;
1190 ring->stopped = true; 1186 ring->stopped = true;
1191 if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE)) 1187 if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE))
1192 b43legacydbg(dev->wl, "Stopped TX ring %d\n", 1188 b43legacydbg(dev->wl, "Stopped TX ring %d\n",
1193 ring->index); 1189 ring->index);
1194 } 1190 }
1195out_unlock:
1196 spin_unlock_irqrestore(&ring->lock, flags);
1197
1198 return err; 1191 return err;
1199} 1192}
1200 1193
@@ -1205,14 +1198,29 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
1205 struct b43legacy_dmadesc_meta *meta; 1198 struct b43legacy_dmadesc_meta *meta;
1206 int retry_limit; 1199 int retry_limit;
1207 int slot; 1200 int slot;
1201 int firstused;
1208 1202
1209 ring = parse_cookie(dev, status->cookie, &slot); 1203 ring = parse_cookie(dev, status->cookie, &slot);
1210 if (unlikely(!ring)) 1204 if (unlikely(!ring))
1211 return; 1205 return;
1212 B43legacy_WARN_ON(!irqs_disabled());
1213 spin_lock(&ring->lock);
1214
1215 B43legacy_WARN_ON(!ring->tx); 1206 B43legacy_WARN_ON(!ring->tx);
1207
1208 /* Sanity check: TX packets are processed in-order on one ring.
1209 * Check if the slot deduced from the cookie really is the first
1210 * used slot. */
1211 firstused = ring->current_slot - ring->used_slots + 1;
1212 if (firstused < 0)
1213 firstused = ring->nr_slots + firstused;
1214 if (unlikely(slot != firstused)) {
1215 /* This possibly is a firmware bug and will result in
1216 * malfunction, memory leaks and/or stall of DMA functionality.
1217 */
1218 b43legacydbg(dev->wl, "Out of order TX status report on DMA "
1219 "ring %d. Expected %d, but got %d\n",
1220 ring->index, firstused, slot);
1221 return;
1222 }
1223
1216 while (1) { 1224 while (1) {
1217 B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); 1225 B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
1218 op32_idx2desc(ring, slot, &meta); 1226 op32_idx2desc(ring, slot, &meta);
@@ -1285,14 +1293,21 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
1285 dev->stats.last_tx = jiffies; 1293 dev->stats.last_tx = jiffies;
1286 if (ring->stopped) { 1294 if (ring->stopped) {
1287 B43legacy_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET); 1295 B43legacy_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET);
1288 ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring));
1289 ring->stopped = false; 1296 ring->stopped = false;
1297 }
1298
1299 if (dev->wl->tx_queue_stopped[ring->queue_prio]) {
1300 dev->wl->tx_queue_stopped[ring->queue_prio] = 0;
1301 } else {
1302 /* If the driver queue is running wake the corresponding
1303 * mac80211 queue. */
1304 ieee80211_wake_queue(dev->wl->hw, ring->queue_prio);
1290 if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE)) 1305 if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE))
1291 b43legacydbg(dev->wl, "Woke up TX ring %d\n", 1306 b43legacydbg(dev->wl, "Woke up TX ring %d\n",
1292 ring->index); 1307 ring->index);
1293 } 1308 }
1294 1309 /* Add work to the queue. */
1295 spin_unlock(&ring->lock); 1310 ieee80211_queue_work(dev->wl->hw, &dev->wl->tx_work);
1296} 1311}
1297 1312
1298static void dma_rx(struct b43legacy_dmaring *ring, 1313static void dma_rx(struct b43legacy_dmaring *ring,
@@ -1415,22 +1430,14 @@ void b43legacy_dma_rx(struct b43legacy_dmaring *ring)
1415 1430
1416static void b43legacy_dma_tx_suspend_ring(struct b43legacy_dmaring *ring) 1431static void b43legacy_dma_tx_suspend_ring(struct b43legacy_dmaring *ring)
1417{ 1432{
1418 unsigned long flags;
1419
1420 spin_lock_irqsave(&ring->lock, flags);
1421 B43legacy_WARN_ON(!ring->tx); 1433 B43legacy_WARN_ON(!ring->tx);
1422 op32_tx_suspend(ring); 1434 op32_tx_suspend(ring);
1423 spin_unlock_irqrestore(&ring->lock, flags);
1424} 1435}
1425 1436
1426static void b43legacy_dma_tx_resume_ring(struct b43legacy_dmaring *ring) 1437static void b43legacy_dma_tx_resume_ring(struct b43legacy_dmaring *ring)
1427{ 1438{
1428 unsigned long flags;
1429
1430 spin_lock_irqsave(&ring->lock, flags);
1431 B43legacy_WARN_ON(!ring->tx); 1439 B43legacy_WARN_ON(!ring->tx);
1432 op32_tx_resume(ring); 1440 op32_tx_resume(ring);
1433 spin_unlock_irqrestore(&ring->lock, flags);
1434} 1441}
1435 1442
1436void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev) 1443void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev)
diff --git a/drivers/net/wireless/b43legacy/dma.h b/drivers/net/wireless/b43legacy/dma.h
index 504a58767e95..c3282f906bc7 100644
--- a/drivers/net/wireless/b43legacy/dma.h
+++ b/drivers/net/wireless/b43legacy/dma.h
@@ -150,8 +150,9 @@ struct b43legacy_dmaring {
150 enum b43legacy_dmatype type; 150 enum b43legacy_dmatype type;
151 /* Boolean. Is this ring stopped at ieee80211 level? */ 151 /* Boolean. Is this ring stopped at ieee80211 level? */
152 bool stopped; 152 bool stopped;
153 /* Lock, only used for TX. */ 153 /* The QOS priority assigned to this ring. Only used for TX rings.
154 spinlock_t lock; 154 * This is the mac80211 "queue" value. */
155 u8 queue_prio;
155 struct b43legacy_wldev *dev; 156 struct b43legacy_wldev *dev;
156#ifdef CONFIG_B43LEGACY_DEBUG 157#ifdef CONFIG_B43LEGACY_DEBUG
157 /* Maximum number of used slots. */ 158 /* Maximum number of used slots. */
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 200138cdb030..75e70bce40f6 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -2440,30 +2440,64 @@ static int b43legacy_rng_init(struct b43legacy_wl *wl)
2440 return err; 2440 return err;
2441} 2441}
2442 2442
2443static void b43legacy_tx_work(struct work_struct *work)
2444{
2445 struct b43legacy_wl *wl = container_of(work, struct b43legacy_wl,
2446 tx_work);
2447 struct b43legacy_wldev *dev;
2448 struct sk_buff *skb;
2449 int queue_num;
2450 int err = 0;
2451
2452 mutex_lock(&wl->mutex);
2453 dev = wl->current_dev;
2454 if (unlikely(!dev || b43legacy_status(dev) < B43legacy_STAT_STARTED)) {
2455 mutex_unlock(&wl->mutex);
2456 return;
2457 }
2458
2459 for (queue_num = 0; queue_num < B43legacy_QOS_QUEUE_NUM; queue_num++) {
2460 while (skb_queue_len(&wl->tx_queue[queue_num])) {
2461 skb = skb_dequeue(&wl->tx_queue[queue_num]);
2462 if (b43legacy_using_pio(dev))
2463 err = b43legacy_pio_tx(dev, skb);
2464 else
2465 err = b43legacy_dma_tx(dev, skb);
2466 if (err == -ENOSPC) {
2467 wl->tx_queue_stopped[queue_num] = 1;
2468 ieee80211_stop_queue(wl->hw, queue_num);
2469 skb_queue_head(&wl->tx_queue[queue_num], skb);
2470 break;
2471 }
2472 if (unlikely(err))
2473 dev_kfree_skb(skb); /* Drop it */
2474 err = 0;
2475 }
2476
2477 if (!err)
2478 wl->tx_queue_stopped[queue_num] = 0;
2479 }
2480
2481 mutex_unlock(&wl->mutex);
2482}
2483
2443static void b43legacy_op_tx(struct ieee80211_hw *hw, 2484static void b43legacy_op_tx(struct ieee80211_hw *hw,
2444 struct sk_buff *skb) 2485 struct sk_buff *skb)
2445{ 2486{
2446 struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); 2487 struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
2447 struct b43legacy_wldev *dev = wl->current_dev;
2448 int err = -ENODEV;
2449 unsigned long flags;
2450 2488
2451 if (unlikely(!dev)) 2489 if (unlikely(skb->len < 2 + 2 + 6)) {
2452 goto out; 2490 /* Too short, this can't be a valid frame. */
2453 if (unlikely(b43legacy_status(dev) < B43legacy_STAT_STARTED))
2454 goto out;
2455 /* DMA-TX is done without a global lock. */
2456 if (b43legacy_using_pio(dev)) {
2457 spin_lock_irqsave(&wl->irq_lock, flags);
2458 err = b43legacy_pio_tx(dev, skb);
2459 spin_unlock_irqrestore(&wl->irq_lock, flags);
2460 } else
2461 err = b43legacy_dma_tx(dev, skb);
2462out:
2463 if (unlikely(err)) {
2464 /* Drop the packet. */
2465 dev_kfree_skb_any(skb); 2491 dev_kfree_skb_any(skb);
2492 return;
2466 } 2493 }
2494 B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags);
2495
2496 skb_queue_tail(&wl->tx_queue[skb->queue_mapping], skb);
2497 if (!wl->tx_queue_stopped[skb->queue_mapping])
2498 ieee80211_queue_work(wl->hw, &wl->tx_work);
2499 else
2500 ieee80211_stop_queue(wl->hw, skb->queue_mapping);
2467} 2501}
2468 2502
2469static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, 2503static int b43legacy_op_conf_tx(struct ieee80211_hw *hw,
@@ -2879,6 +2913,7 @@ static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev)
2879{ 2913{
2880 struct b43legacy_wl *wl = dev->wl; 2914 struct b43legacy_wl *wl = dev->wl;
2881 unsigned long flags; 2915 unsigned long flags;
2916 int queue_num;
2882 2917
2883 if (b43legacy_status(dev) < B43legacy_STAT_STARTED) 2918 if (b43legacy_status(dev) < B43legacy_STAT_STARTED)
2884 return; 2919 return;
@@ -2898,11 +2933,16 @@ static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev)
2898 /* Must unlock as it would otherwise deadlock. No races here. 2933 /* Must unlock as it would otherwise deadlock. No races here.
2899 * Cancel the possibly running self-rearming periodic work. */ 2934 * Cancel the possibly running self-rearming periodic work. */
2900 cancel_delayed_work_sync(&dev->periodic_work); 2935 cancel_delayed_work_sync(&dev->periodic_work);
2936 cancel_work_sync(&wl->tx_work);
2901 mutex_lock(&wl->mutex); 2937 mutex_lock(&wl->mutex);
2902 2938
2903 ieee80211_stop_queues(wl->hw); /* FIXME this could cause a deadlock */ 2939 /* Drain all TX queues. */
2940 for (queue_num = 0; queue_num < B43legacy_QOS_QUEUE_NUM; queue_num++) {
2941 while (skb_queue_len(&wl->tx_queue[queue_num]))
2942 dev_kfree_skb(skb_dequeue(&wl->tx_queue[queue_num]));
2943 }
2904 2944
2905 b43legacy_mac_suspend(dev); 2945b43legacy_mac_suspend(dev);
2906 free_irq(dev->dev->irq, dev); 2946 free_irq(dev->dev->irq, dev);
2907 b43legacydbg(wl, "Wireless interface stopped\n"); 2947 b43legacydbg(wl, "Wireless interface stopped\n");
2908} 2948}
@@ -3748,6 +3788,7 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
3748 struct ieee80211_hw *hw; 3788 struct ieee80211_hw *hw;
3749 struct b43legacy_wl *wl; 3789 struct b43legacy_wl *wl;
3750 int err = -ENOMEM; 3790 int err = -ENOMEM;
3791 int queue_num;
3751 3792
3752 b43legacy_sprom_fixup(dev->bus); 3793 b43legacy_sprom_fixup(dev->bus);
3753 3794
@@ -3782,6 +3823,13 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
3782 mutex_init(&wl->mutex); 3823 mutex_init(&wl->mutex);
3783 INIT_LIST_HEAD(&wl->devlist); 3824 INIT_LIST_HEAD(&wl->devlist);
3784 INIT_WORK(&wl->beacon_update_trigger, b43legacy_beacon_update_trigger_work); 3825 INIT_WORK(&wl->beacon_update_trigger, b43legacy_beacon_update_trigger_work);
3826 INIT_WORK(&wl->tx_work, b43legacy_tx_work);
3827
3828 /* Initialize queues and flags. */
3829 for (queue_num = 0; queue_num < B43legacy_QOS_QUEUE_NUM; queue_num++) {
3830 skb_queue_head_init(&wl->tx_queue[queue_num]);
3831 wl->tx_queue_stopped[queue_num] = 0;
3832 }
3785 3833
3786 ssb_set_devtypedata(dev, wl); 3834 ssb_set_devtypedata(dev, wl);
3787 b43legacyinfo(wl, "Broadcom %04X WLAN found (core revision %u)\n", 3835 b43legacyinfo(wl, "Broadcom %04X WLAN found (core revision %u)\n",