diff options
author | Michael Buesch <mb@bu3sch.de> | 2008-03-05 15:18:49 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-03-07 16:02:59 -0500 |
commit | e6f5b934fba8c44c87c551e066aa7ca6fde2939e (patch) | |
tree | b3fabd1b35a044fe0f50d1ab16ca0dd697c3f59a /drivers/net/wireless/b43 | |
parent | e5f98f2df903af627a9b9ac55b9352fd54fc431a (diff) |
b43: Add QOS support
This adds QOS support to the b43 driver.
QOS can be disabled on driver level with a module parameter for debugging purposes.
Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/b43')
-rw-r--r-- | drivers/net/wireless/b43/b43.h | 37 | ||||
-rw-r--r-- | drivers/net/wireless/b43/dma.c | 90 | ||||
-rw-r--r-- | drivers/net/wireless/b43/dma.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/b43/main.c | 180 | ||||
-rw-r--r-- | drivers/net/wireless/b43/main.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/b43/xmit.c | 27 | ||||
-rw-r--r-- | drivers/net/wireless/b43/xmit.h | 12 |
7 files changed, 262 insertions, 91 deletions
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 33459d61a717..55031463c396 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h | |||
@@ -99,6 +99,8 @@ | |||
99 | #define B43_MMIO_TSF_2 0x636 /* core rev < 3 only */ | 99 | #define B43_MMIO_TSF_2 0x636 /* core rev < 3 only */ |
100 | #define B43_MMIO_TSF_3 0x638 /* core rev < 3 only */ | 100 | #define B43_MMIO_TSF_3 0x638 /* core rev < 3 only */ |
101 | #define B43_MMIO_RNG 0x65A | 101 | #define B43_MMIO_RNG 0x65A |
102 | #define B43_MMIO_IFSCTL 0x688 /* Interframe space control */ | ||
103 | #define B43_MMIO_IFSCTL_USE_EDCF 0x0004 | ||
102 | #define B43_MMIO_POWERUP_DELAY 0x6A8 | 104 | #define B43_MMIO_POWERUP_DELAY 0x6A8 |
103 | 105 | ||
104 | /* SPROM boardflags_lo values */ | 106 | /* SPROM boardflags_lo values */ |
@@ -621,6 +623,35 @@ struct b43_key { | |||
621 | u8 algorithm; | 623 | u8 algorithm; |
622 | }; | 624 | }; |
623 | 625 | ||
626 | /* SHM offsets to the QOS data structures for the 4 different queues. */ | ||
627 | #define B43_QOS_PARAMS(queue) (B43_SHM_SH_EDCFQ + \ | ||
628 | (B43_NR_QOSPARAMS * sizeof(u16) * (queue))) | ||
629 | #define B43_QOS_BACKGROUND B43_QOS_PARAMS(0) | ||
630 | #define B43_QOS_BESTEFFORT B43_QOS_PARAMS(1) | ||
631 | #define B43_QOS_VIDEO B43_QOS_PARAMS(2) | ||
632 | #define B43_QOS_VOICE B43_QOS_PARAMS(3) | ||
633 | |||
634 | /* QOS parameter hardware data structure offsets. */ | ||
635 | #define B43_NR_QOSPARAMS 22 | ||
636 | enum { | ||
637 | B43_QOSPARAM_TXOP = 0, | ||
638 | B43_QOSPARAM_CWMIN, | ||
639 | B43_QOSPARAM_CWMAX, | ||
640 | B43_QOSPARAM_CWCUR, | ||
641 | B43_QOSPARAM_AIFS, | ||
642 | B43_QOSPARAM_BSLOTS, | ||
643 | B43_QOSPARAM_REGGAP, | ||
644 | B43_QOSPARAM_STATUS, | ||
645 | }; | ||
646 | |||
647 | /* QOS parameters for a queue. */ | ||
648 | struct b43_qos_params { | ||
649 | /* The QOS parameters */ | ||
650 | struct ieee80211_tx_queue_params p; | ||
651 | /* Does this need to get uploaded to hardware? */ | ||
652 | bool need_hw_update; | ||
653 | }; | ||
654 | |||
624 | struct b43_wldev; | 655 | struct b43_wldev; |
625 | 656 | ||
626 | /* Data structure for the WLAN parts (802.11 cores) of the b43 chip. */ | 657 | /* Data structure for the WLAN parts (802.11 cores) of the b43 chip. */ |
@@ -673,6 +704,12 @@ struct b43_wl { | |||
673 | struct sk_buff *current_beacon; | 704 | struct sk_buff *current_beacon; |
674 | bool beacon0_uploaded; | 705 | bool beacon0_uploaded; |
675 | bool beacon1_uploaded; | 706 | bool beacon1_uploaded; |
707 | |||
708 | /* The current QOS parameters for the 4 queues. | ||
709 | * This is protected by the irq_lock. */ | ||
710 | struct b43_qos_params qos_params[4]; | ||
711 | /* Workqueue for updating QOS parameters in hardware. */ | ||
712 | struct work_struct qos_update_work; | ||
676 | }; | 713 | }; |
677 | 714 | ||
678 | /* In-memory representation of a cached microcode file. */ | 715 | /* In-memory representation of a cached microcode file. */ |
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 3dfb28a34be9..c8ead465497a 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c | |||
@@ -291,52 +291,6 @@ static inline int request_slot(struct b43_dmaring *ring) | |||
291 | return slot; | 291 | return slot; |
292 | } | 292 | } |
293 | 293 | ||
294 | /* Mac80211-queue to b43-ring mapping */ | ||
295 | static struct b43_dmaring *priority_to_txring(struct b43_wldev *dev, | ||
296 | int queue_priority) | ||
297 | { | ||
298 | struct b43_dmaring *ring; | ||
299 | |||
300 | /*FIXME: For now we always run on TX-ring-1 */ | ||
301 | return dev->dma.tx_ring1; | ||
302 | |||
303 | /* 0 = highest priority */ | ||
304 | switch (queue_priority) { | ||
305 | default: | ||
306 | B43_WARN_ON(1); | ||
307 | /* fallthrough */ | ||
308 | case 0: | ||
309 | ring = dev->dma.tx_ring3; | ||
310 | break; | ||
311 | case 1: | ||
312 | ring = dev->dma.tx_ring2; | ||
313 | break; | ||
314 | case 2: | ||
315 | ring = dev->dma.tx_ring1; | ||
316 | break; | ||
317 | case 3: | ||
318 | ring = dev->dma.tx_ring0; | ||
319 | break; | ||
320 | } | ||
321 | |||
322 | return ring; | ||
323 | } | ||
324 | |||
325 | /* b43-ring to mac80211-queue mapping */ | ||
326 | static inline int txring_to_priority(struct b43_dmaring *ring) | ||
327 | { | ||
328 | static const u8 idx_to_prio[] = { 3, 2, 1, 0, }; | ||
329 | unsigned int index; | ||
330 | |||
331 | /*FIXME: have only one queue, for now */ | ||
332 | return 0; | ||
333 | |||
334 | index = ring->index; | ||
335 | if (B43_WARN_ON(index >= ARRAY_SIZE(idx_to_prio))) | ||
336 | index = 0; | ||
337 | return idx_to_prio[index]; | ||
338 | } | ||
339 | |||
340 | static u16 b43_dmacontroller_base(enum b43_dmatype type, int controller_idx) | 294 | static u16 b43_dmacontroller_base(enum b43_dmatype type, int controller_idx) |
341 | { | 295 | { |
342 | static const u16 map64[] = { | 296 | static const u16 map64[] = { |
@@ -1272,6 +1226,37 @@ static inline int should_inject_overflow(struct b43_dmaring *ring) | |||
1272 | return 0; | 1226 | return 0; |
1273 | } | 1227 | } |
1274 | 1228 | ||
1229 | /* Static mapping of mac80211's queues (priorities) to b43 DMA rings. */ | ||
1230 | static struct b43_dmaring * select_ring_by_priority(struct b43_wldev *dev, | ||
1231 | u8 queue_prio) | ||
1232 | { | ||
1233 | struct b43_dmaring *ring; | ||
1234 | |||
1235 | if (b43_modparam_qos) { | ||
1236 | /* 0 = highest priority */ | ||
1237 | switch (queue_prio) { | ||
1238 | default: | ||
1239 | B43_WARN_ON(1); | ||
1240 | /* fallthrough */ | ||
1241 | case 0: | ||
1242 | ring = dev->dma.tx_ring3; /* AC_VO */ | ||
1243 | break; | ||
1244 | case 1: | ||
1245 | ring = dev->dma.tx_ring2; /* AC_VI */ | ||
1246 | break; | ||
1247 | case 2: | ||
1248 | ring = dev->dma.tx_ring1; /* AC_BE */ | ||
1249 | break; | ||
1250 | case 3: | ||
1251 | ring = dev->dma.tx_ring0; /* AC_BK */ | ||
1252 | break; | ||
1253 | } | ||
1254 | } else | ||
1255 | ring = dev->dma.tx_ring1; | ||
1256 | |||
1257 | return ring; | ||
1258 | } | ||
1259 | |||
1275 | int b43_dma_tx(struct b43_wldev *dev, | 1260 | int b43_dma_tx(struct b43_wldev *dev, |
1276 | struct sk_buff *skb, struct ieee80211_tx_control *ctl) | 1261 | struct sk_buff *skb, struct ieee80211_tx_control *ctl) |
1277 | { | 1262 | { |
@@ -1294,7 +1279,7 @@ int b43_dma_tx(struct b43_wldev *dev, | |||
1294 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); | 1279 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); |
1295 | } else { | 1280 | } else { |
1296 | /* Decide by priority where to put this frame. */ | 1281 | /* Decide by priority where to put this frame. */ |
1297 | ring = priority_to_txring(dev, ctl->queue); | 1282 | ring = select_ring_by_priority(dev, ctl->queue); |
1298 | } | 1283 | } |
1299 | 1284 | ||
1300 | spin_lock_irqsave(&ring->lock, flags); | 1285 | spin_lock_irqsave(&ring->lock, flags); |
@@ -1309,6 +1294,11 @@ int b43_dma_tx(struct b43_wldev *dev, | |||
1309 | * That would be a mac80211 bug. */ | 1294 | * That would be a mac80211 bug. */ |
1310 | B43_WARN_ON(ring->stopped); | 1295 | B43_WARN_ON(ring->stopped); |
1311 | 1296 | ||
1297 | /* Assign the queue number to the ring (if not already done before) | ||
1298 | * so TX status handling can use it. The queue to ring mapping is | ||
1299 | * static, so we don't need to store it per frame. */ | ||
1300 | ring->queue_prio = ctl->queue; | ||
1301 | |||
1312 | err = dma_tx_fragment(ring, skb, ctl); | 1302 | err = dma_tx_fragment(ring, skb, ctl); |
1313 | if (unlikely(err == -ENOKEY)) { | 1303 | if (unlikely(err == -ENOKEY)) { |
1314 | /* Drop this packet, as we don't have the encryption key | 1304 | /* Drop this packet, as we don't have the encryption key |
@@ -1325,7 +1315,7 @@ int b43_dma_tx(struct b43_wldev *dev, | |||
1325 | if ((free_slots(ring) < SLOTS_PER_PACKET) || | 1315 | if ((free_slots(ring) < SLOTS_PER_PACKET) || |
1326 | should_inject_overflow(ring)) { | 1316 | should_inject_overflow(ring)) { |
1327 | /* This TX ring is full. */ | 1317 | /* This TX ring is full. */ |
1328 | ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring)); | 1318 | ieee80211_stop_queue(dev->wl->hw, ctl->queue); |
1329 | ring->stopped = 1; | 1319 | ring->stopped = 1; |
1330 | if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { | 1320 | if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { |
1331 | b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); | 1321 | b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); |
@@ -1404,7 +1394,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, | |||
1404 | dev->stats.last_tx = jiffies; | 1394 | dev->stats.last_tx = jiffies; |
1405 | if (ring->stopped) { | 1395 | if (ring->stopped) { |
1406 | B43_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET); | 1396 | B43_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET); |
1407 | ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring)); | 1397 | ieee80211_wake_queue(dev->wl->hw, ring->queue_prio); |
1408 | ring->stopped = 0; | 1398 | ring->stopped = 0; |
1409 | if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { | 1399 | if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { |
1410 | b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index); | 1400 | b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index); |
@@ -1425,7 +1415,7 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev, | |||
1425 | 1415 | ||
1426 | for (i = 0; i < nr_queues; i++) { | 1416 | for (i = 0; i < nr_queues; i++) { |
1427 | data = &(stats->data[i]); | 1417 | data = &(stats->data[i]); |
1428 | ring = priority_to_txring(dev, i); | 1418 | ring = select_ring_by_priority(dev, i); |
1429 | 1419 | ||
1430 | spin_lock_irqsave(&ring->lock, flags); | 1420 | spin_lock_irqsave(&ring->lock, flags); |
1431 | data->len = ring->used_slots / SLOTS_PER_PACKET; | 1421 | data->len = ring->used_slots / SLOTS_PER_PACKET; |
diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h index c0d6b69e6501..9336286d97a7 100644 --- a/drivers/net/wireless/b43/dma.h +++ b/drivers/net/wireless/b43/dma.h | |||
@@ -245,6 +245,9 @@ struct b43_dmaring { | |||
245 | enum b43_dmatype type; | 245 | enum b43_dmatype type; |
246 | /* Boolean. Is this ring stopped at ieee80211 level? */ | 246 | /* Boolean. Is this ring stopped at ieee80211 level? */ |
247 | bool stopped; | 247 | bool stopped; |
248 | /* The QOS priority assigned to this ring. Only used for TX rings. | ||
249 | * This is the mac80211 "queue" value. */ | ||
250 | u8 queue_prio; | ||
248 | /* Lock, only used for TX. */ | 251 | /* Lock, only used for TX. */ |
249 | spinlock_t lock; | 252 | spinlock_t lock; |
250 | struct b43_wldev *dev; | 253 | struct b43_wldev *dev; |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index c93b62fb5f65..dbacb58d9527 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -78,6 +78,11 @@ static int modparam_nohwcrypt; | |||
78 | module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); | 78 | module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); |
79 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); | 79 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); |
80 | 80 | ||
81 | int b43_modparam_qos = 1; | ||
82 | module_param_named(qos, b43_modparam_qos, int, 0444); | ||
83 | MODULE_PARM_DESC(qos, "Enable QOS support (default on)"); | ||
84 | |||
85 | |||
81 | static const struct ssb_device_id b43_ssb_tbl[] = { | 86 | static const struct ssb_device_id b43_ssb_tbl[] = { |
82 | SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5), | 87 | SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5), |
83 | SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 6), | 88 | SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 6), |
@@ -2708,10 +2713,178 @@ out: | |||
2708 | return NETDEV_TX_OK; | 2713 | return NETDEV_TX_OK; |
2709 | } | 2714 | } |
2710 | 2715 | ||
2716 | /* Locking: wl->irq_lock */ | ||
2717 | static void b43_qos_params_upload(struct b43_wldev *dev, | ||
2718 | const struct ieee80211_tx_queue_params *p, | ||
2719 | u16 shm_offset) | ||
2720 | { | ||
2721 | u16 params[B43_NR_QOSPARAMS]; | ||
2722 | int cw_min, cw_max, aifs, bslots, tmp; | ||
2723 | unsigned int i; | ||
2724 | |||
2725 | const u16 aCWmin = 0x0001; | ||
2726 | const u16 aCWmax = 0x03FF; | ||
2727 | |||
2728 | /* Calculate the default values for the parameters, if needed. */ | ||
2729 | switch (shm_offset) { | ||
2730 | case B43_QOS_VOICE: | ||
2731 | aifs = (p->aifs == -1) ? 2 : p->aifs; | ||
2732 | cw_min = (p->cw_min == 0) ? ((aCWmin + 1) / 4 - 1) : p->cw_min; | ||
2733 | cw_max = (p->cw_max == 0) ? ((aCWmin + 1) / 2 - 1) : p->cw_max; | ||
2734 | break; | ||
2735 | case B43_QOS_VIDEO: | ||
2736 | aifs = (p->aifs == -1) ? 2 : p->aifs; | ||
2737 | cw_min = (p->cw_min == 0) ? ((aCWmin + 1) / 2 - 1) : p->cw_min; | ||
2738 | cw_max = (p->cw_max == 0) ? aCWmin : p->cw_max; | ||
2739 | break; | ||
2740 | case B43_QOS_BESTEFFORT: | ||
2741 | aifs = (p->aifs == -1) ? 3 : p->aifs; | ||
2742 | cw_min = (p->cw_min == 0) ? aCWmin : p->cw_min; | ||
2743 | cw_max = (p->cw_max == 0) ? aCWmax : p->cw_max; | ||
2744 | break; | ||
2745 | case B43_QOS_BACKGROUND: | ||
2746 | aifs = (p->aifs == -1) ? 7 : p->aifs; | ||
2747 | cw_min = (p->cw_min == 0) ? aCWmin : p->cw_min; | ||
2748 | cw_max = (p->cw_max == 0) ? aCWmax : p->cw_max; | ||
2749 | break; | ||
2750 | default: | ||
2751 | B43_WARN_ON(1); | ||
2752 | return; | ||
2753 | } | ||
2754 | if (cw_min <= 0) | ||
2755 | cw_min = aCWmin; | ||
2756 | if (cw_max <= 0) | ||
2757 | cw_max = aCWmin; | ||
2758 | bslots = b43_read16(dev, B43_MMIO_RNG) % cw_min; | ||
2759 | |||
2760 | memset(¶ms, 0, sizeof(params)); | ||
2761 | |||
2762 | params[B43_QOSPARAM_TXOP] = p->txop * 32; | ||
2763 | params[B43_QOSPARAM_CWMIN] = cw_min; | ||
2764 | params[B43_QOSPARAM_CWMAX] = cw_max; | ||
2765 | params[B43_QOSPARAM_CWCUR] = cw_min; | ||
2766 | params[B43_QOSPARAM_AIFS] = aifs; | ||
2767 | params[B43_QOSPARAM_BSLOTS] = bslots; | ||
2768 | params[B43_QOSPARAM_REGGAP] = bslots + aifs; | ||
2769 | |||
2770 | for (i = 0; i < ARRAY_SIZE(params); i++) { | ||
2771 | if (i == B43_QOSPARAM_STATUS) { | ||
2772 | tmp = b43_shm_read16(dev, B43_SHM_SHARED, | ||
2773 | shm_offset + (i * 2)); | ||
2774 | /* Mark the parameters as updated. */ | ||
2775 | tmp |= 0x100; | ||
2776 | b43_shm_write16(dev, B43_SHM_SHARED, | ||
2777 | shm_offset + (i * 2), | ||
2778 | tmp); | ||
2779 | } else { | ||
2780 | b43_shm_write16(dev, B43_SHM_SHARED, | ||
2781 | shm_offset + (i * 2), | ||
2782 | params[i]); | ||
2783 | } | ||
2784 | } | ||
2785 | } | ||
2786 | |||
2787 | /* Update the QOS parameters in hardware. */ | ||
2788 | static void b43_qos_update(struct b43_wldev *dev) | ||
2789 | { | ||
2790 | struct b43_wl *wl = dev->wl; | ||
2791 | struct b43_qos_params *params; | ||
2792 | unsigned long flags; | ||
2793 | unsigned int i; | ||
2794 | |||
2795 | /* Mapping of mac80211 queues to b43 SHM offsets. */ | ||
2796 | static const u16 qos_shm_offsets[] = { | ||
2797 | [0] = B43_QOS_VOICE, | ||
2798 | [1] = B43_QOS_VIDEO, | ||
2799 | [2] = B43_QOS_BESTEFFORT, | ||
2800 | [3] = B43_QOS_BACKGROUND, | ||
2801 | }; | ||
2802 | BUILD_BUG_ON(ARRAY_SIZE(qos_shm_offsets) != ARRAY_SIZE(wl->qos_params)); | ||
2803 | |||
2804 | b43_mac_suspend(dev); | ||
2805 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
2806 | |||
2807 | for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) { | ||
2808 | params = &(wl->qos_params[i]); | ||
2809 | if (params->need_hw_update) { | ||
2810 | b43_qos_params_upload(dev, &(params->p), | ||
2811 | qos_shm_offsets[i]); | ||
2812 | params->need_hw_update = 0; | ||
2813 | } | ||
2814 | } | ||
2815 | |||
2816 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
2817 | b43_mac_enable(dev); | ||
2818 | } | ||
2819 | |||
2820 | static void b43_qos_clear(struct b43_wl *wl) | ||
2821 | { | ||
2822 | struct b43_qos_params *params; | ||
2823 | unsigned int i; | ||
2824 | |||
2825 | for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) { | ||
2826 | params = &(wl->qos_params[i]); | ||
2827 | |||
2828 | memset(&(params->p), 0, sizeof(params->p)); | ||
2829 | params->p.aifs = -1; | ||
2830 | params->need_hw_update = 1; | ||
2831 | } | ||
2832 | } | ||
2833 | |||
2834 | /* Initialize the core's QOS capabilities */ | ||
2835 | static void b43_qos_init(struct b43_wldev *dev) | ||
2836 | { | ||
2837 | struct b43_wl *wl = dev->wl; | ||
2838 | unsigned int i; | ||
2839 | |||
2840 | /* Upload the current QOS parameters. */ | ||
2841 | for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) | ||
2842 | wl->qos_params[i].need_hw_update = 1; | ||
2843 | b43_qos_update(dev); | ||
2844 | |||
2845 | /* Enable QOS support. */ | ||
2846 | b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF); | ||
2847 | b43_write16(dev, B43_MMIO_IFSCTL, | ||
2848 | b43_read16(dev, B43_MMIO_IFSCTL) | ||
2849 | | B43_MMIO_IFSCTL_USE_EDCF); | ||
2850 | } | ||
2851 | |||
2852 | static void b43_qos_update_work(struct work_struct *work) | ||
2853 | { | ||
2854 | struct b43_wl *wl = container_of(work, struct b43_wl, qos_update_work); | ||
2855 | struct b43_wldev *dev; | ||
2856 | |||
2857 | mutex_lock(&wl->mutex); | ||
2858 | dev = wl->current_dev; | ||
2859 | if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) | ||
2860 | b43_qos_update(dev); | ||
2861 | mutex_unlock(&wl->mutex); | ||
2862 | } | ||
2863 | |||
2711 | static int b43_op_conf_tx(struct ieee80211_hw *hw, | 2864 | static int b43_op_conf_tx(struct ieee80211_hw *hw, |
2712 | int queue, | 2865 | int _queue, |
2713 | const struct ieee80211_tx_queue_params *params) | 2866 | const struct ieee80211_tx_queue_params *params) |
2714 | { | 2867 | { |
2868 | struct b43_wl *wl = hw_to_b43_wl(hw); | ||
2869 | unsigned long flags; | ||
2870 | unsigned int queue = (unsigned int)_queue; | ||
2871 | struct b43_qos_params *p; | ||
2872 | |||
2873 | if (queue >= ARRAY_SIZE(wl->qos_params)) { | ||
2874 | /* Queue not available or don't support setting | ||
2875 | * params on this queue. Return success to not | ||
2876 | * confuse mac80211. */ | ||
2877 | return 0; | ||
2878 | } | ||
2879 | |||
2880 | spin_lock_irqsave(&wl->irq_lock, flags); | ||
2881 | p = &(wl->qos_params[queue]); | ||
2882 | memcpy(&(p->p), params, sizeof(p->p)); | ||
2883 | p->need_hw_update = 1; | ||
2884 | spin_unlock_irqrestore(&wl->irq_lock, flags); | ||
2885 | |||
2886 | queue_work(hw->workqueue, &wl->qos_update_work); | ||
2887 | |||
2715 | return 0; | 2888 | return 0; |
2716 | } | 2889 | } |
2717 | 2890 | ||
@@ -3732,6 +3905,7 @@ static int b43_op_start(struct ieee80211_hw *hw) | |||
3732 | memset(wl->mac_addr, 0, ETH_ALEN); | 3905 | memset(wl->mac_addr, 0, ETH_ALEN); |
3733 | wl->filter_flags = 0; | 3906 | wl->filter_flags = 0; |
3734 | wl->radiotap_enabled = 0; | 3907 | wl->radiotap_enabled = 0; |
3908 | b43_qos_clear(wl); | ||
3735 | 3909 | ||
3736 | /* First register RFkill. | 3910 | /* First register RFkill. |
3737 | * LEDs that are registered later depend on it. */ | 3911 | * LEDs that are registered later depend on it. */ |
@@ -3773,6 +3947,7 @@ static void b43_op_stop(struct ieee80211_hw *hw) | |||
3773 | struct b43_wldev *dev = wl->current_dev; | 3947 | struct b43_wldev *dev = wl->current_dev; |
3774 | 3948 | ||
3775 | b43_rfkill_exit(dev); | 3949 | b43_rfkill_exit(dev); |
3950 | cancel_work_sync(&(wl->qos_update_work)); | ||
3776 | 3951 | ||
3777 | mutex_lock(&wl->mutex); | 3952 | mutex_lock(&wl->mutex); |
3778 | if (b43_status(dev) >= B43_STAT_STARTED) | 3953 | if (b43_status(dev) >= B43_STAT_STARTED) |
@@ -4133,7 +4308,7 @@ static int b43_wireless_init(struct ssb_device *dev) | |||
4133 | hw->max_signal = 100; | 4308 | hw->max_signal = 100; |
4134 | hw->max_rssi = -110; | 4309 | hw->max_rssi = -110; |
4135 | hw->max_noise = -110; | 4310 | hw->max_noise = -110; |
4136 | hw->queues = 1; /* FIXME: hardware has more queues */ | 4311 | hw->queues = b43_modparam_qos ? 4 : 1; |
4137 | SET_IEEE80211_DEV(hw, dev->dev); | 4312 | SET_IEEE80211_DEV(hw, dev->dev); |
4138 | if (is_valid_ether_addr(sprom->et1mac)) | 4313 | if (is_valid_ether_addr(sprom->et1mac)) |
4139 | SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac); | 4314 | SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac); |
@@ -4149,6 +4324,7 @@ static int b43_wireless_init(struct ssb_device *dev) | |||
4149 | spin_lock_init(&wl->shm_lock); | 4324 | spin_lock_init(&wl->shm_lock); |
4150 | mutex_init(&wl->mutex); | 4325 | mutex_init(&wl->mutex); |
4151 | INIT_LIST_HEAD(&wl->devlist); | 4326 | INIT_LIST_HEAD(&wl->devlist); |
4327 | INIT_WORK(&wl->qos_update_work, b43_qos_update_work); | ||
4152 | 4328 | ||
4153 | ssb_set_devtypedata(dev, wl); | 4329 | ssb_set_devtypedata(dev, wl); |
4154 | b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id); | 4330 | b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id); |
diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 24a79f5d6ff5..1197975f9207 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h | |||
@@ -38,6 +38,10 @@ | |||
38 | /* Magic helper macro to pad structures. Ignore those above. It's magic. */ | 38 | /* Magic helper macro to pad structures. Ignore those above. It's magic. */ |
39 | #define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes)) | 39 | #define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes)) |
40 | 40 | ||
41 | |||
42 | extern int b43_modparam_qos; | ||
43 | |||
44 | |||
41 | /* Lightweight function to convert a frequency (in Mhz) to a channel number. */ | 45 | /* Lightweight function to convert a frequency (in Mhz) to a channel number. */ |
42 | static inline u8 b43_freq_to_channel_5ghz(int freq) | 46 | static inline u8 b43_freq_to_channel_5ghz(int freq) |
43 | { | 47 | { |
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 187c11bee0f1..ec10a8e182f9 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c | |||
@@ -705,30 +705,3 @@ void b43_tx_resume(struct b43_wldev *dev) | |||
705 | { | 705 | { |
706 | b43_dma_tx_resume(dev); | 706 | b43_dma_tx_resume(dev); |
707 | } | 707 | } |
708 | |||
709 | #if 0 | ||
710 | static void upload_qos_parms(struct b43_wldev *dev, | ||
711 | const u16 * parms, u16 offset) | ||
712 | { | ||
713 | int i; | ||
714 | |||
715 | for (i = 0; i < B43_NR_QOSPARMS; i++) { | ||
716 | b43_shm_write16(dev, B43_SHM_SHARED, | ||
717 | offset + (i * 2), parms[i]); | ||
718 | } | ||
719 | } | ||
720 | #endif | ||
721 | |||
722 | /* Initialize the QoS parameters */ | ||
723 | void b43_qos_init(struct b43_wldev *dev) | ||
724 | { | ||
725 | /* FIXME: This function must probably be called from the mac80211 | ||
726 | * config callback. */ | ||
727 | return; | ||
728 | |||
729 | b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF); | ||
730 | //FIXME kill magic | ||
731 | b43_write16(dev, 0x688, b43_read16(dev, 0x688) | 0x4); | ||
732 | |||
733 | /*TODO: We might need some stack support here to get the values. */ | ||
734 | } | ||
diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h index 41765039552b..bf58a8a85258 100644 --- a/drivers/net/wireless/b43/xmit.h +++ b/drivers/net/wireless/b43/xmit.h | |||
@@ -302,18 +302,6 @@ void b43_handle_hwtxstatus(struct b43_wldev *dev, | |||
302 | void b43_tx_suspend(struct b43_wldev *dev); | 302 | void b43_tx_suspend(struct b43_wldev *dev); |
303 | void b43_tx_resume(struct b43_wldev *dev); | 303 | void b43_tx_resume(struct b43_wldev *dev); |
304 | 304 | ||
305 | #define B43_NR_QOSPARMS 22 | ||
306 | enum { | ||
307 | B43_QOSPARM_TXOP = 0, | ||
308 | B43_QOSPARM_CWMIN, | ||
309 | B43_QOSPARM_CWMAX, | ||
310 | B43_QOSPARM_CWCUR, | ||
311 | B43_QOSPARM_AIFS, | ||
312 | B43_QOSPARM_BSLOTS, | ||
313 | B43_QOSPARM_REGGAP, | ||
314 | B43_QOSPARM_STATUS, | ||
315 | }; | ||
316 | void b43_qos_init(struct b43_wldev *dev); | ||
317 | 305 | ||
318 | /* Helper functions for converting the key-table index from "firmware-format" | 306 | /* Helper functions for converting the key-table index from "firmware-format" |
319 | * to "raw-format" and back. The firmware API changed for this at some revision. | 307 | * to "raw-format" and back. The firmware API changed for this at some revision. |