diff options
author | Lennert Buytenhek <buytenh@wantstofly.org> | 2010-01-12 07:51:30 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-01-12 14:21:23 -0500 |
commit | ee0ddf1865954f44ee929d963e2c968eb377f447 (patch) | |
tree | 85cbe8d86dad8b53404db76aa78450460b1e258c /drivers/net/wireless/mwl8k.c | |
parent | aa21d0f69a5ca28d33f584b8952cca154115fd26 (diff) |
mwl8k: enable multi-BSS AP operation
As follows:
- GET_HW_SPEC is now responsible for setting
priv->{ap,sta}_macids_supported, which are bitmasks of supported
macids for AP and STA mode. (Typically, STA firmware images will
support only one macid, #0, in STA mode, and AP firmware images
will support macids #0-7, in AP mode.)
- Our wiphy ->interfaces_modes is now set based on the non-zero-ness
of these two bitmasks.
- We main priv->macids_used, a bitmask of which macids are currently
in use. ->add_interface() will assign the lowest free macid for
this interface type as it is created, or bail out if there are no
more free macids to assign. ->delete_interface() will mark the
macid as being free again.
This enables the multi-BSS code added in the previous commits.
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/mwl8k.c')
-rw-r--r-- | drivers/net/wireless/mwl8k.c | 70 |
1 files changed, 56 insertions, 14 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index d8cf43853de1..06dc7a0978a0 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c | |||
@@ -147,6 +147,8 @@ struct mwl8k_priv { | |||
147 | struct ieee80211_supported_band band_50; | 147 | struct ieee80211_supported_band band_50; |
148 | struct ieee80211_channel channels_50[4]; | 148 | struct ieee80211_channel channels_50[4]; |
149 | struct ieee80211_rate rates_50[9]; | 149 | struct ieee80211_rate rates_50[9]; |
150 | u32 ap_macids_supported; | ||
151 | u32 sta_macids_supported; | ||
150 | 152 | ||
151 | /* firmware access */ | 153 | /* firmware access */ |
152 | struct mutex fw_mutex; | 154 | struct mutex fw_mutex; |
@@ -161,6 +163,7 @@ struct mwl8k_priv { | |||
161 | struct completion *tx_wait; | 163 | struct completion *tx_wait; |
162 | 164 | ||
163 | /* List of interfaces. */ | 165 | /* List of interfaces. */ |
166 | u32 macids_used; | ||
164 | struct list_head vif_list; | 167 | struct list_head vif_list; |
165 | 168 | ||
166 | /* power management status cookie from firmware */ | 169 | /* power management status cookie from firmware */ |
@@ -1786,6 +1789,8 @@ static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw) | |||
1786 | priv->fw_rev = le32_to_cpu(cmd->fw_rev); | 1789 | priv->fw_rev = le32_to_cpu(cmd->fw_rev); |
1787 | priv->hw_rev = cmd->hw_rev; | 1790 | priv->hw_rev = cmd->hw_rev; |
1788 | mwl8k_set_caps(hw, le32_to_cpu(cmd->caps)); | 1791 | mwl8k_set_caps(hw, le32_to_cpu(cmd->caps)); |
1792 | priv->ap_macids_supported = 0x00000000; | ||
1793 | priv->sta_macids_supported = 0x00000001; | ||
1789 | } | 1794 | } |
1790 | 1795 | ||
1791 | kfree(cmd); | 1796 | kfree(cmd); |
@@ -1840,6 +1845,8 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw) | |||
1840 | priv->fw_rev = le32_to_cpu(cmd->fw_rev); | 1845 | priv->fw_rev = le32_to_cpu(cmd->fw_rev); |
1841 | priv->hw_rev = cmd->hw_rev; | 1846 | priv->hw_rev = cmd->hw_rev; |
1842 | mwl8k_setup_2ghz_band(hw); | 1847 | mwl8k_setup_2ghz_band(hw); |
1848 | priv->ap_macids_supported = 0x000000ff; | ||
1849 | priv->sta_macids_supported = 0x00000000; | ||
1843 | 1850 | ||
1844 | off = le32_to_cpu(cmd->wcbbase0) & 0xffff; | 1851 | off = le32_to_cpu(cmd->wcbbase0) & 0xffff; |
1845 | iowrite32(cpu_to_le32(priv->txq[0].txd_dma), priv->sram + off); | 1852 | iowrite32(cpu_to_le32(priv->txq[0].txd_dma), priv->sram + off); |
@@ -2759,16 +2766,33 @@ struct mwl8k_cmd_set_mac_addr { | |||
2759 | }; | 2766 | }; |
2760 | } __attribute__((packed)); | 2767 | } __attribute__((packed)); |
2761 | 2768 | ||
2762 | #define MWL8K_MAC_TYPE_PRIMARY_CLIENT 0 | 2769 | #define MWL8K_MAC_TYPE_PRIMARY_CLIENT 0 |
2763 | #define MWL8K_MAC_TYPE_PRIMARY_AP 2 | 2770 | #define MWL8K_MAC_TYPE_SECONDARY_CLIENT 1 |
2771 | #define MWL8K_MAC_TYPE_PRIMARY_AP 2 | ||
2772 | #define MWL8K_MAC_TYPE_SECONDARY_AP 3 | ||
2764 | 2773 | ||
2765 | static int mwl8k_cmd_set_mac_addr(struct ieee80211_hw *hw, | 2774 | static int mwl8k_cmd_set_mac_addr(struct ieee80211_hw *hw, |
2766 | struct ieee80211_vif *vif, u8 *mac) | 2775 | struct ieee80211_vif *vif, u8 *mac) |
2767 | { | 2776 | { |
2768 | struct mwl8k_priv *priv = hw->priv; | 2777 | struct mwl8k_priv *priv = hw->priv; |
2778 | struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); | ||
2769 | struct mwl8k_cmd_set_mac_addr *cmd; | 2779 | struct mwl8k_cmd_set_mac_addr *cmd; |
2780 | int mac_type; | ||
2770 | int rc; | 2781 | int rc; |
2771 | 2782 | ||
2783 | mac_type = MWL8K_MAC_TYPE_PRIMARY_AP; | ||
2784 | if (vif != NULL && vif->type == NL80211_IFTYPE_STATION) { | ||
2785 | if (mwl8k_vif->macid + 1 == ffs(priv->sta_macids_supported)) | ||
2786 | mac_type = MWL8K_MAC_TYPE_PRIMARY_CLIENT; | ||
2787 | else | ||
2788 | mac_type = MWL8K_MAC_TYPE_SECONDARY_CLIENT; | ||
2789 | } else if (vif != NULL && vif->type == NL80211_IFTYPE_AP) { | ||
2790 | if (mwl8k_vif->macid + 1 == ffs(priv->ap_macids_supported)) | ||
2791 | mac_type = MWL8K_MAC_TYPE_PRIMARY_AP; | ||
2792 | else | ||
2793 | mac_type = MWL8K_MAC_TYPE_SECONDARY_AP; | ||
2794 | } | ||
2795 | |||
2772 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | 2796 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); |
2773 | if (cmd == NULL) | 2797 | if (cmd == NULL) |
2774 | return -ENOMEM; | 2798 | return -ENOMEM; |
@@ -2776,7 +2800,7 @@ static int mwl8k_cmd_set_mac_addr(struct ieee80211_hw *hw, | |||
2776 | cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR); | 2800 | cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR); |
2777 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); | 2801 | cmd->header.length = cpu_to_le16(sizeof(*cmd)); |
2778 | if (priv->ap_fw) { | 2802 | if (priv->ap_fw) { |
2779 | cmd->mbss.mac_type = cpu_to_le16(MWL8K_MAC_TYPE_PRIMARY_AP); | 2803 | cmd->mbss.mac_type = cpu_to_le16(mac_type); |
2780 | memcpy(cmd->mbss.mac_addr, mac, ETH_ALEN); | 2804 | memcpy(cmd->mbss.mac_addr, mac, ETH_ALEN); |
2781 | } else { | 2805 | } else { |
2782 | memcpy(cmd->mac_addr, mac, ETH_ALEN); | 2806 | memcpy(cmd->mac_addr, mac, ETH_ALEN); |
@@ -3271,12 +3295,8 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, | |||
3271 | { | 3295 | { |
3272 | struct mwl8k_priv *priv = hw->priv; | 3296 | struct mwl8k_priv *priv = hw->priv; |
3273 | struct mwl8k_vif *mwl8k_vif; | 3297 | struct mwl8k_vif *mwl8k_vif; |
3274 | 3298 | u32 macids_supported; | |
3275 | /* | 3299 | int macid; |
3276 | * We only support one active interface at a time. | ||
3277 | */ | ||
3278 | if (!list_empty(&priv->vif_list)) | ||
3279 | return -EBUSY; | ||
3280 | 3300 | ||
3281 | /* | 3301 | /* |
3282 | * Reject interface creation if sniffer mode is active, as | 3302 | * Reject interface creation if sniffer mode is active, as |
@@ -3290,11 +3310,27 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, | |||
3290 | return -EINVAL; | 3310 | return -EINVAL; |
3291 | } | 3311 | } |
3292 | 3312 | ||
3313 | |||
3314 | switch (vif->type) { | ||
3315 | case NL80211_IFTYPE_AP: | ||
3316 | macids_supported = priv->ap_macids_supported; | ||
3317 | break; | ||
3318 | case NL80211_IFTYPE_STATION: | ||
3319 | macids_supported = priv->sta_macids_supported; | ||
3320 | break; | ||
3321 | default: | ||
3322 | return -EINVAL; | ||
3323 | } | ||
3324 | |||
3325 | macid = ffs(macids_supported & ~priv->macids_used); | ||
3326 | if (!macid--) | ||
3327 | return -EBUSY; | ||
3328 | |||
3293 | /* Setup driver private area. */ | 3329 | /* Setup driver private area. */ |
3294 | mwl8k_vif = MWL8K_VIF(vif); | 3330 | mwl8k_vif = MWL8K_VIF(vif); |
3295 | memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); | 3331 | memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); |
3296 | mwl8k_vif->vif = vif; | 3332 | mwl8k_vif->vif = vif; |
3297 | mwl8k_vif->macid = 0; | 3333 | mwl8k_vif->macid = macid; |
3298 | mwl8k_vif->seqno = 0; | 3334 | mwl8k_vif->seqno = 0; |
3299 | 3335 | ||
3300 | /* Set the mac address. */ | 3336 | /* Set the mac address. */ |
@@ -3303,6 +3339,7 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw, | |||
3303 | if (priv->ap_fw) | 3339 | if (priv->ap_fw) |
3304 | mwl8k_cmd_set_new_stn_add_self(hw, vif); | 3340 | mwl8k_cmd_set_new_stn_add_self(hw, vif); |
3305 | 3341 | ||
3342 | priv->macids_used |= 1 << mwl8k_vif->macid; | ||
3306 | list_add_tail(&mwl8k_vif->list, &priv->vif_list); | 3343 | list_add_tail(&mwl8k_vif->list, &priv->vif_list); |
3307 | 3344 | ||
3308 | return 0; | 3345 | return 0; |
@@ -3319,6 +3356,7 @@ static void mwl8k_remove_interface(struct ieee80211_hw *hw, | |||
3319 | 3356 | ||
3320 | mwl8k_cmd_set_mac_addr(hw, vif, "\x00\x00\x00\x00\x00\x00"); | 3357 | mwl8k_cmd_set_mac_addr(hw, vif, "\x00\x00\x00\x00\x00\x00"); |
3321 | 3358 | ||
3359 | priv->macids_used &= ~(1 << mwl8k_vif->macid); | ||
3322 | list_del(&mwl8k_vif->list); | 3360 | list_del(&mwl8k_vif->list); |
3323 | } | 3361 | } |
3324 | 3362 | ||
@@ -4023,6 +4061,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
4023 | hw->vif_data_size = sizeof(struct mwl8k_vif); | 4061 | hw->vif_data_size = sizeof(struct mwl8k_vif); |
4024 | hw->sta_data_size = sizeof(struct mwl8k_sta); | 4062 | hw->sta_data_size = sizeof(struct mwl8k_sta); |
4025 | 4063 | ||
4064 | priv->macids_used = 0; | ||
4026 | INIT_LIST_HEAD(&priv->vif_list); | 4065 | INIT_LIST_HEAD(&priv->vif_list); |
4027 | 4066 | ||
4028 | /* Set default radio state and preamble */ | 4067 | /* Set default radio state and preamble */ |
@@ -4094,12 +4133,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
4094 | rc = mwl8k_cmd_get_hw_spec_ap(hw); | 4133 | rc = mwl8k_cmd_get_hw_spec_ap(hw); |
4095 | if (!rc) | 4134 | if (!rc) |
4096 | rc = mwl8k_cmd_set_hw_spec(hw); | 4135 | rc = mwl8k_cmd_set_hw_spec(hw); |
4097 | |||
4098 | hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_AP); | ||
4099 | } else { | 4136 | } else { |
4100 | rc = mwl8k_cmd_get_hw_spec_sta(hw); | 4137 | rc = mwl8k_cmd_get_hw_spec_sta(hw); |
4101 | |||
4102 | hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | ||
4103 | } | 4138 | } |
4104 | if (rc) { | 4139 | if (rc) { |
4105 | printk(KERN_ERR "%s: Cannot initialise firmware\n", | 4140 | printk(KERN_ERR "%s: Cannot initialise firmware\n", |
@@ -4107,6 +4142,13 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev, | |||
4107 | goto err_free_irq; | 4142 | goto err_free_irq; |
4108 | } | 4143 | } |
4109 | 4144 | ||
4145 | hw->wiphy->interface_modes = 0; | ||
4146 | if (priv->ap_macids_supported) | ||
4147 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); | ||
4148 | if (priv->sta_macids_supported) | ||
4149 | hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION); | ||
4150 | |||
4151 | |||
4110 | /* Turn radio off */ | 4152 | /* Turn radio off */ |
4111 | rc = mwl8k_cmd_radio_disable(hw); | 4153 | rc = mwl8k_cmd_radio_disable(hw); |
4112 | if (rc) { | 4154 | if (rc) { |