diff options
author | David S. Miller <davem@davemloft.net> | 2008-03-11 22:17:18 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-03-11 22:17:18 -0400 |
commit | ba73d4c84a7344f1b5635c2b4e96796e8c13a126 (patch) | |
tree | d4a3e2cfc5f3a046a2b9baa898f0c201c75ba898 /drivers/net/wireless/b43/main.c | |
parent | b8ad0cbc58f703972e9e37c4e2a8081dd7e6a551 (diff) | |
parent | deedf504302ff747985db081352e045ff7087a11 (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.c | 196 |
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; | |||
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), |
@@ -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 */ | ||
2716 | static 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(¶ms, 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. */ | ||
2787 | static 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 | |||
2819 | static 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 */ | ||
2834 | static 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 | |||
2851 | static 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 | |||
2711 | static int b43_op_conf_tx(struct ieee80211_hw *hw, | 2863 | static 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 | ||
4012 | static 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 | |||
3838 | static const struct ieee80211_ops b43_hw_ops = { | 4022 | static 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); |