mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-06 10:57:46 +00:00
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>
This commit is contained in:
parent
aa21d0f69a
commit
ee0ddf1865
1 changed files with 56 additions and 14 deletions
|
@ -147,6 +147,8 @@ struct mwl8k_priv {
|
||||||
struct ieee80211_supported_band band_50;
|
struct ieee80211_supported_band band_50;
|
||||||
struct ieee80211_channel channels_50[4];
|
struct ieee80211_channel channels_50[4];
|
||||||
struct ieee80211_rate rates_50[9];
|
struct ieee80211_rate rates_50[9];
|
||||||
|
u32 ap_macids_supported;
|
||||||
|
u32 sta_macids_supported;
|
||||||
|
|
||||||
/* firmware access */
|
/* firmware access */
|
||||||
struct mutex fw_mutex;
|
struct mutex fw_mutex;
|
||||||
|
@ -161,6 +163,7 @@ struct mwl8k_priv {
|
||||||
struct completion *tx_wait;
|
struct completion *tx_wait;
|
||||||
|
|
||||||
/* List of interfaces. */
|
/* List of interfaces. */
|
||||||
|
u32 macids_used;
|
||||||
struct list_head vif_list;
|
struct list_head vif_list;
|
||||||
|
|
||||||
/* power management status cookie from firmware */
|
/* power management status cookie from firmware */
|
||||||
|
@ -1786,6 +1789,8 @@ static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw)
|
||||||
priv->fw_rev = le32_to_cpu(cmd->fw_rev);
|
priv->fw_rev = le32_to_cpu(cmd->fw_rev);
|
||||||
priv->hw_rev = cmd->hw_rev;
|
priv->hw_rev = cmd->hw_rev;
|
||||||
mwl8k_set_caps(hw, le32_to_cpu(cmd->caps));
|
mwl8k_set_caps(hw, le32_to_cpu(cmd->caps));
|
||||||
|
priv->ap_macids_supported = 0x00000000;
|
||||||
|
priv->sta_macids_supported = 0x00000001;
|
||||||
}
|
}
|
||||||
|
|
||||||
kfree(cmd);
|
kfree(cmd);
|
||||||
|
@ -1840,6 +1845,8 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw)
|
||||||
priv->fw_rev = le32_to_cpu(cmd->fw_rev);
|
priv->fw_rev = le32_to_cpu(cmd->fw_rev);
|
||||||
priv->hw_rev = cmd->hw_rev;
|
priv->hw_rev = cmd->hw_rev;
|
||||||
mwl8k_setup_2ghz_band(hw);
|
mwl8k_setup_2ghz_band(hw);
|
||||||
|
priv->ap_macids_supported = 0x000000ff;
|
||||||
|
priv->sta_macids_supported = 0x00000000;
|
||||||
|
|
||||||
off = le32_to_cpu(cmd->wcbbase0) & 0xffff;
|
off = le32_to_cpu(cmd->wcbbase0) & 0xffff;
|
||||||
iowrite32(cpu_to_le32(priv->txq[0].txd_dma), priv->sram + off);
|
iowrite32(cpu_to_le32(priv->txq[0].txd_dma), priv->sram + off);
|
||||||
|
@ -2759,16 +2766,33 @@ struct mwl8k_cmd_set_mac_addr {
|
||||||
};
|
};
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
#define MWL8K_MAC_TYPE_PRIMARY_CLIENT 0
|
#define MWL8K_MAC_TYPE_PRIMARY_CLIENT 0
|
||||||
#define MWL8K_MAC_TYPE_PRIMARY_AP 2
|
#define MWL8K_MAC_TYPE_SECONDARY_CLIENT 1
|
||||||
|
#define MWL8K_MAC_TYPE_PRIMARY_AP 2
|
||||||
|
#define MWL8K_MAC_TYPE_SECONDARY_AP 3
|
||||||
|
|
||||||
static int mwl8k_cmd_set_mac_addr(struct ieee80211_hw *hw,
|
static int mwl8k_cmd_set_mac_addr(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif, u8 *mac)
|
struct ieee80211_vif *vif, u8 *mac)
|
||||||
{
|
{
|
||||||
struct mwl8k_priv *priv = hw->priv;
|
struct mwl8k_priv *priv = hw->priv;
|
||||||
|
struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
|
||||||
struct mwl8k_cmd_set_mac_addr *cmd;
|
struct mwl8k_cmd_set_mac_addr *cmd;
|
||||||
|
int mac_type;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
mac_type = MWL8K_MAC_TYPE_PRIMARY_AP;
|
||||||
|
if (vif != NULL && vif->type == NL80211_IFTYPE_STATION) {
|
||||||
|
if (mwl8k_vif->macid + 1 == ffs(priv->sta_macids_supported))
|
||||||
|
mac_type = MWL8K_MAC_TYPE_PRIMARY_CLIENT;
|
||||||
|
else
|
||||||
|
mac_type = MWL8K_MAC_TYPE_SECONDARY_CLIENT;
|
||||||
|
} else if (vif != NULL && vif->type == NL80211_IFTYPE_AP) {
|
||||||
|
if (mwl8k_vif->macid + 1 == ffs(priv->ap_macids_supported))
|
||||||
|
mac_type = MWL8K_MAC_TYPE_PRIMARY_AP;
|
||||||
|
else
|
||||||
|
mac_type = MWL8K_MAC_TYPE_SECONDARY_AP;
|
||||||
|
}
|
||||||
|
|
||||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||||
if (cmd == NULL)
|
if (cmd == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -2776,7 +2800,7 @@ static int mwl8k_cmd_set_mac_addr(struct ieee80211_hw *hw,
|
||||||
cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR);
|
cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_MAC_ADDR);
|
||||||
cmd->header.length = cpu_to_le16(sizeof(*cmd));
|
cmd->header.length = cpu_to_le16(sizeof(*cmd));
|
||||||
if (priv->ap_fw) {
|
if (priv->ap_fw) {
|
||||||
cmd->mbss.mac_type = cpu_to_le16(MWL8K_MAC_TYPE_PRIMARY_AP);
|
cmd->mbss.mac_type = cpu_to_le16(mac_type);
|
||||||
memcpy(cmd->mbss.mac_addr, mac, ETH_ALEN);
|
memcpy(cmd->mbss.mac_addr, mac, ETH_ALEN);
|
||||||
} else {
|
} else {
|
||||||
memcpy(cmd->mac_addr, mac, ETH_ALEN);
|
memcpy(cmd->mac_addr, mac, ETH_ALEN);
|
||||||
|
@ -3271,12 +3295,8 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw,
|
||||||
{
|
{
|
||||||
struct mwl8k_priv *priv = hw->priv;
|
struct mwl8k_priv *priv = hw->priv;
|
||||||
struct mwl8k_vif *mwl8k_vif;
|
struct mwl8k_vif *mwl8k_vif;
|
||||||
|
u32 macids_supported;
|
||||||
/*
|
int macid;
|
||||||
* We only support one active interface at a time.
|
|
||||||
*/
|
|
||||||
if (!list_empty(&priv->vif_list))
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reject interface creation if sniffer mode is active, as
|
* Reject interface creation if sniffer mode is active, as
|
||||||
|
@ -3290,11 +3310,27 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
switch (vif->type) {
|
||||||
|
case NL80211_IFTYPE_AP:
|
||||||
|
macids_supported = priv->ap_macids_supported;
|
||||||
|
break;
|
||||||
|
case NL80211_IFTYPE_STATION:
|
||||||
|
macids_supported = priv->sta_macids_supported;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
macid = ffs(macids_supported & ~priv->macids_used);
|
||||||
|
if (!macid--)
|
||||||
|
return -EBUSY;
|
||||||
|
|
||||||
/* Setup driver private area. */
|
/* Setup driver private area. */
|
||||||
mwl8k_vif = MWL8K_VIF(vif);
|
mwl8k_vif = MWL8K_VIF(vif);
|
||||||
memset(mwl8k_vif, 0, sizeof(*mwl8k_vif));
|
memset(mwl8k_vif, 0, sizeof(*mwl8k_vif));
|
||||||
mwl8k_vif->vif = vif;
|
mwl8k_vif->vif = vif;
|
||||||
mwl8k_vif->macid = 0;
|
mwl8k_vif->macid = macid;
|
||||||
mwl8k_vif->seqno = 0;
|
mwl8k_vif->seqno = 0;
|
||||||
|
|
||||||
/* Set the mac address. */
|
/* Set the mac address. */
|
||||||
|
@ -3303,6 +3339,7 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw,
|
||||||
if (priv->ap_fw)
|
if (priv->ap_fw)
|
||||||
mwl8k_cmd_set_new_stn_add_self(hw, vif);
|
mwl8k_cmd_set_new_stn_add_self(hw, vif);
|
||||||
|
|
||||||
|
priv->macids_used |= 1 << mwl8k_vif->macid;
|
||||||
list_add_tail(&mwl8k_vif->list, &priv->vif_list);
|
list_add_tail(&mwl8k_vif->list, &priv->vif_list);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -3319,6 +3356,7 @@ static void mwl8k_remove_interface(struct ieee80211_hw *hw,
|
||||||
|
|
||||||
mwl8k_cmd_set_mac_addr(hw, vif, "\x00\x00\x00\x00\x00\x00");
|
mwl8k_cmd_set_mac_addr(hw, vif, "\x00\x00\x00\x00\x00\x00");
|
||||||
|
|
||||||
|
priv->macids_used &= ~(1 << mwl8k_vif->macid);
|
||||||
list_del(&mwl8k_vif->list);
|
list_del(&mwl8k_vif->list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4023,6 +4061,7 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
|
||||||
hw->vif_data_size = sizeof(struct mwl8k_vif);
|
hw->vif_data_size = sizeof(struct mwl8k_vif);
|
||||||
hw->sta_data_size = sizeof(struct mwl8k_sta);
|
hw->sta_data_size = sizeof(struct mwl8k_sta);
|
||||||
|
|
||||||
|
priv->macids_used = 0;
|
||||||
INIT_LIST_HEAD(&priv->vif_list);
|
INIT_LIST_HEAD(&priv->vif_list);
|
||||||
|
|
||||||
/* Set default radio state and preamble */
|
/* Set default radio state and preamble */
|
||||||
|
@ -4094,12 +4133,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
|
||||||
rc = mwl8k_cmd_get_hw_spec_ap(hw);
|
rc = mwl8k_cmd_get_hw_spec_ap(hw);
|
||||||
if (!rc)
|
if (!rc)
|
||||||
rc = mwl8k_cmd_set_hw_spec(hw);
|
rc = mwl8k_cmd_set_hw_spec(hw);
|
||||||
|
|
||||||
hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_AP);
|
|
||||||
} else {
|
} else {
|
||||||
rc = mwl8k_cmd_get_hw_spec_sta(hw);
|
rc = mwl8k_cmd_get_hw_spec_sta(hw);
|
||||||
|
|
||||||
hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
|
|
||||||
}
|
}
|
||||||
if (rc) {
|
if (rc) {
|
||||||
printk(KERN_ERR "%s: Cannot initialise firmware\n",
|
printk(KERN_ERR "%s: Cannot initialise firmware\n",
|
||||||
|
@ -4107,6 +4142,13 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
|
||||||
goto err_free_irq;
|
goto err_free_irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hw->wiphy->interface_modes = 0;
|
||||||
|
if (priv->ap_macids_supported)
|
||||||
|
hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP);
|
||||||
|
if (priv->sta_macids_supported)
|
||||||
|
hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION);
|
||||||
|
|
||||||
|
|
||||||
/* Turn radio off */
|
/* Turn radio off */
|
||||||
rc = mwl8k_cmd_radio_disable(hw);
|
rc = mwl8k_cmd_radio_disable(hw);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
|
|
Loading…
Reference in a new issue