aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/b43/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/b43/main.c')
-rw-r--r--drivers/net/wireless/b43/main.c180
1 files changed, 178 insertions, 2 deletions
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index c93b62fb5f6..dbacb58d952 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),
@@ -2708,10 +2713,178 @@ out:
2708 return NETDEV_TX_OK; 2713 return NETDEV_TX_OK;
2709} 2714}
2710 2715
2716/* Locking: wl->irq_lock */
2717static 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(&params, 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. */
2788static 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
2820static 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 */
2835static 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
2852static 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
2711static int b43_op_conf_tx(struct ieee80211_hw *hw, 2864static 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);