aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/b43/main.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-03-11 22:17:18 -0400
committerDavid S. Miller <davem@davemloft.net>2008-03-11 22:17:18 -0400
commitba73d4c84a7344f1b5635c2b4e96796e8c13a126 (patch)
treed4a3e2cfc5f3a046a2b9baa898f0c201c75ba898 /drivers/net/wireless/b43/main.c
parentb8ad0cbc58f703972e9e37c4e2a8081dd7e6a551 (diff)
parentdeedf504302ff747985db081352e045ff7087a11 (diff)
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/linville/wireless-2.6.26
Diffstat (limited to 'drivers/net/wireless/b43/main.c')
-rw-r--r--drivers/net/wireless/b43/main.c196
1 files changed, 191 insertions, 5 deletions
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index f745308faaad..694e29570e5d 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -78,6 +78,11 @@ static int modparam_nohwcrypt;
78module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); 78module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
79MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); 79MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
80 80
81int b43_modparam_qos = 1;
82module_param_named(qos, b43_modparam_qos, int, 0444);
83MODULE_PARM_DESC(qos, "Enable QOS support (default on)");
84
85
81static const struct ssb_device_id b43_ssb_tbl[] = { 86static 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),
@@ -1589,11 +1594,10 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev)
1589 1594
1590 /* Check the DMA reason registers for received data. */ 1595 /* Check the DMA reason registers for received data. */
1591 if (dma_reason[0] & B43_DMAIRQ_RX_DONE) 1596 if (dma_reason[0] & B43_DMAIRQ_RX_DONE)
1592 b43_dma_rx(dev->dma.rx_ring0); 1597 b43_dma_rx(dev->dma.rx_ring);
1593 if (dma_reason[3] & B43_DMAIRQ_RX_DONE)
1594 b43_dma_rx(dev->dma.rx_ring3);
1595 B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE); 1598 B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE);
1596 B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE); 1599 B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE);
1600 B43_WARN_ON(dma_reason[3] & B43_DMAIRQ_RX_DONE);
1597 B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE); 1601 B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE);
1598 B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE); 1602 B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE);
1599 1603
@@ -2708,10 +2712,178 @@ out:
2708 return NETDEV_TX_OK; 2712 return NETDEV_TX_OK;
2709} 2713}
2710 2714
2715/* Locking: wl->irq_lock */
2716static void b43_qos_params_upload(struct b43_wldev *dev,
2717 const struct ieee80211_tx_queue_params *p,
2718 u16 shm_offset)
2719{
2720 u16 params[B43_NR_QOSPARAMS];
2721 int cw_min, cw_max, aifs, bslots, tmp;
2722 unsigned int i;
2723
2724 const u16 aCWmin = 0x0001;
2725 const u16 aCWmax = 0x03FF;
2726
2727 /* Calculate the default values for the parameters, if needed. */
2728 switch (shm_offset) {
2729 case B43_QOS_VOICE:
2730 aifs = (p->aifs == -1) ? 2 : p->aifs;
2731 cw_min = (p->cw_min == 0) ? ((aCWmin + 1) / 4 - 1) : p->cw_min;
2732 cw_max = (p->cw_max == 0) ? ((aCWmin + 1) / 2 - 1) : p->cw_max;
2733 break;
2734 case B43_QOS_VIDEO:
2735 aifs = (p->aifs == -1) ? 2 : p->aifs;
2736 cw_min = (p->cw_min == 0) ? ((aCWmin + 1) / 2 - 1) : p->cw_min;
2737 cw_max = (p->cw_max == 0) ? aCWmin : p->cw_max;
2738 break;
2739 case B43_QOS_BESTEFFORT:
2740 aifs = (p->aifs == -1) ? 3 : p->aifs;
2741 cw_min = (p->cw_min == 0) ? aCWmin : p->cw_min;
2742 cw_max = (p->cw_max == 0) ? aCWmax : p->cw_max;
2743 break;
2744 case B43_QOS_BACKGROUND:
2745 aifs = (p->aifs == -1) ? 7 : p->aifs;
2746 cw_min = (p->cw_min == 0) ? aCWmin : p->cw_min;
2747 cw_max = (p->cw_max == 0) ? aCWmax : p->cw_max;
2748 break;
2749 default:
2750 B43_WARN_ON(1);
2751 return;
2752 }
2753 if (cw_min <= 0)
2754 cw_min = aCWmin;
2755 if (cw_max <= 0)
2756 cw_max = aCWmin;
2757 bslots = b43_read16(dev, B43_MMIO_RNG) % cw_min;
2758
2759 memset(&params, 0, sizeof(params));
2760
2761 params[B43_QOSPARAM_TXOP] = p->txop * 32;
2762 params[B43_QOSPARAM_CWMIN] = cw_min;
2763 params[B43_QOSPARAM_CWMAX] = cw_max;
2764 params[B43_QOSPARAM_CWCUR] = cw_min;
2765 params[B43_QOSPARAM_AIFS] = aifs;
2766 params[B43_QOSPARAM_BSLOTS] = bslots;
2767 params[B43_QOSPARAM_REGGAP] = bslots + aifs;
2768
2769 for (i = 0; i < ARRAY_SIZE(params); i++) {
2770 if (i == B43_QOSPARAM_STATUS) {
2771 tmp = b43_shm_read16(dev, B43_SHM_SHARED,
2772 shm_offset + (i * 2));
2773 /* Mark the parameters as updated. */
2774 tmp |= 0x100;
2775 b43_shm_write16(dev, B43_SHM_SHARED,
2776 shm_offset + (i * 2),
2777 tmp);
2778 } else {
2779 b43_shm_write16(dev, B43_SHM_SHARED,
2780 shm_offset + (i * 2),
2781 params[i]);
2782 }
2783 }
2784}
2785
2786/* Update the QOS parameters in hardware. */
2787static void b43_qos_update(struct b43_wldev *dev)
2788{
2789 struct b43_wl *wl = dev->wl;
2790 struct b43_qos_params *params;
2791 unsigned long flags;
2792 unsigned int i;
2793
2794 /* Mapping of mac80211 queues to b43 SHM offsets. */
2795 static const u16 qos_shm_offsets[] = {
2796 [0] = B43_QOS_VOICE,
2797 [1] = B43_QOS_VIDEO,
2798 [2] = B43_QOS_BESTEFFORT,
2799 [3] = B43_QOS_BACKGROUND,
2800 };
2801 BUILD_BUG_ON(ARRAY_SIZE(qos_shm_offsets) != ARRAY_SIZE(wl->qos_params));
2802
2803 b43_mac_suspend(dev);
2804 spin_lock_irqsave(&wl->irq_lock, flags);
2805
2806 for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) {
2807 params = &(wl->qos_params[i]);
2808 if (params->need_hw_update) {
2809 b43_qos_params_upload(dev, &(params->p),
2810 qos_shm_offsets[i]);
2811 params->need_hw_update = 0;
2812 }
2813 }
2814
2815 spin_unlock_irqrestore(&wl->irq_lock, flags);
2816 b43_mac_enable(dev);
2817}
2818
2819static void b43_qos_clear(struct b43_wl *wl)
2820{
2821 struct b43_qos_params *params;
2822 unsigned int i;
2823
2824 for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++) {
2825 params = &(wl->qos_params[i]);
2826
2827 memset(&(params->p), 0, sizeof(params->p));
2828 params->p.aifs = -1;
2829 params->need_hw_update = 1;
2830 }
2831}
2832
2833/* Initialize the core's QOS capabilities */
2834static void b43_qos_init(struct b43_wldev *dev)
2835{
2836 struct b43_wl *wl = dev->wl;
2837 unsigned int i;
2838
2839 /* Upload the current QOS parameters. */
2840 for (i = 0; i < ARRAY_SIZE(wl->qos_params); i++)
2841 wl->qos_params[i].need_hw_update = 1;
2842 b43_qos_update(dev);
2843
2844 /* Enable QOS support. */
2845 b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF);
2846 b43_write16(dev, B43_MMIO_IFSCTL,
2847 b43_read16(dev, B43_MMIO_IFSCTL)
2848 | B43_MMIO_IFSCTL_USE_EDCF);
2849}
2850
2851static void b43_qos_update_work(struct work_struct *work)
2852{
2853 struct b43_wl *wl = container_of(work, struct b43_wl, qos_update_work);
2854 struct b43_wldev *dev;
2855
2856 mutex_lock(&wl->mutex);
2857 dev = wl->current_dev;
2858 if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED)))
2859 b43_qos_update(dev);
2860 mutex_unlock(&wl->mutex);
2861}
2862
2711static int b43_op_conf_tx(struct ieee80211_hw *hw, 2863static int b43_op_conf_tx(struct ieee80211_hw *hw,
2712 int queue, 2864 int _queue,
2713 const struct ieee80211_tx_queue_params *params) 2865 const struct ieee80211_tx_queue_params *params)
2714{ 2866{
2867 struct b43_wl *wl = hw_to_b43_wl(hw);
2868 unsigned long flags;
2869 unsigned int queue = (unsigned int)_queue;
2870 struct b43_qos_params *p;
2871
2872 if (queue >= ARRAY_SIZE(wl->qos_params)) {
2873 /* Queue not available or don't support setting
2874 * params on this queue. Return success to not
2875 * confuse mac80211. */
2876 return 0;
2877 }
2878
2879 spin_lock_irqsave(&wl->irq_lock, flags);
2880 p = &(wl->qos_params[queue]);
2881 memcpy(&(p->p), params, sizeof(p->p));
2882 p->need_hw_update = 1;
2883 spin_unlock_irqrestore(&wl->irq_lock, flags);
2884
2885 queue_work(hw->workqueue, &wl->qos_update_work);
2886
2715 return 0; 2887 return 0;
2716} 2888}
2717 2889
@@ -3732,6 +3904,7 @@ static int b43_op_start(struct ieee80211_hw *hw)
3732 memset(wl->mac_addr, 0, ETH_ALEN); 3904 memset(wl->mac_addr, 0, ETH_ALEN);
3733 wl->filter_flags = 0; 3905 wl->filter_flags = 0;
3734 wl->radiotap_enabled = 0; 3906 wl->radiotap_enabled = 0;
3907 b43_qos_clear(wl);
3735 3908
3736 /* First register RFkill. 3909 /* First register RFkill.
3737 * LEDs that are registered later depend on it. */ 3910 * LEDs that are registered later depend on it. */
@@ -3773,6 +3946,7 @@ static void b43_op_stop(struct ieee80211_hw *hw)
3773 struct b43_wldev *dev = wl->current_dev; 3946 struct b43_wldev *dev = wl->current_dev;
3774 3947
3775 b43_rfkill_exit(dev); 3948 b43_rfkill_exit(dev);
3949 cancel_work_sync(&(wl->qos_update_work));
3776 3950
3777 mutex_lock(&wl->mutex); 3951 mutex_lock(&wl->mutex);
3778 if (b43_status(dev) >= B43_STAT_STARTED) 3952 if (b43_status(dev) >= B43_STAT_STARTED)
@@ -3835,6 +4009,16 @@ static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw,
3835 return 0; 4009 return 0;
3836} 4010}
3837 4011
4012static void b43_op_sta_notify(struct ieee80211_hw *hw,
4013 struct ieee80211_vif *vif,
4014 enum sta_notify_cmd notify_cmd,
4015 const u8 *addr)
4016{
4017 struct b43_wl *wl = hw_to_b43_wl(hw);
4018
4019 B43_WARN_ON(!vif || wl->vif != vif);
4020}
4021
3838static const struct ieee80211_ops b43_hw_ops = { 4022static const struct ieee80211_ops b43_hw_ops = {
3839 .tx = b43_op_tx, 4023 .tx = b43_op_tx,
3840 .conf_tx = b43_op_conf_tx, 4024 .conf_tx = b43_op_conf_tx,
@@ -3851,6 +4035,7 @@ static const struct ieee80211_ops b43_hw_ops = {
3851 .set_retry_limit = b43_op_set_retry_limit, 4035 .set_retry_limit = b43_op_set_retry_limit,
3852 .set_tim = b43_op_beacon_set_tim, 4036 .set_tim = b43_op_beacon_set_tim,
3853 .beacon_update = b43_op_ibss_beacon_update, 4037 .beacon_update = b43_op_ibss_beacon_update,
4038 .sta_notify = b43_op_sta_notify,
3854}; 4039};
3855 4040
3856/* Hard-reset the chip. Do not call this directly. 4041/* Hard-reset the chip. Do not call this directly.
@@ -4122,7 +4307,7 @@ static int b43_wireless_init(struct ssb_device *dev)
4122 hw->max_signal = 100; 4307 hw->max_signal = 100;
4123 hw->max_rssi = -110; 4308 hw->max_rssi = -110;
4124 hw->max_noise = -110; 4309 hw->max_noise = -110;
4125 hw->queues = 1; /* FIXME: hardware has more queues */ 4310 hw->queues = b43_modparam_qos ? 4 : 1;
4126 SET_IEEE80211_DEV(hw, dev->dev); 4311 SET_IEEE80211_DEV(hw, dev->dev);
4127 if (is_valid_ether_addr(sprom->et1mac)) 4312 if (is_valid_ether_addr(sprom->et1mac))
4128 SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac); 4313 SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
@@ -4138,6 +4323,7 @@ static int b43_wireless_init(struct ssb_device *dev)
4138 spin_lock_init(&wl->shm_lock); 4323 spin_lock_init(&wl->shm_lock);
4139 mutex_init(&wl->mutex); 4324 mutex_init(&wl->mutex);
4140 INIT_LIST_HEAD(&wl->devlist); 4325 INIT_LIST_HEAD(&wl->devlist);
4326 INIT_WORK(&wl->qos_update_work, b43_qos_update_work);
4141 4327
4142 ssb_set_devtypedata(dev, wl); 4328 ssb_set_devtypedata(dev, wl);
4143 b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id); 4329 b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id);