aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/mwl8k.c
diff options
context:
space:
mode:
authorLennert Buytenhek <buytenh@wantstofly.org>2010-01-08 12:31:39 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-01-12 14:02:10 -0500
commitb64fe619e371fc17d8d686d6d44aef1b41317880 (patch)
tree726411e61c6c80316c85e4a9273739eeeda51774 /drivers/net/wireless/mwl8k.c
parenta9e00b151ec2121b7ae09d84a2b5a68b6461e98a (diff)
mwl8k: basic AP interface support
Add support for creating AP interfaces, and enabling beaconing. This allows running a basic AP (11b/g mode only for now). 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.c171
1 files changed, 158 insertions, 13 deletions
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 428575beb8d0..759c94fb8e77 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -266,6 +266,7 @@ static const struct ieee80211_rate mwl8k_rates[] = {
266#define MWL8K_CMD_RADIO_CONTROL 0x001c 266#define MWL8K_CMD_RADIO_CONTROL 0x001c
267#define MWL8K_CMD_RF_TX_POWER 0x001e 267#define MWL8K_CMD_RF_TX_POWER 0x001e
268#define MWL8K_CMD_RF_ANTENNA 0x0020 268#define MWL8K_CMD_RF_ANTENNA 0x0020
269#define MWL8K_CMD_SET_BEACON 0x0100
269#define MWL8K_CMD_SET_PRE_SCAN 0x0107 270#define MWL8K_CMD_SET_PRE_SCAN 0x0107
270#define MWL8K_CMD_SET_POST_SCAN 0x0108 271#define MWL8K_CMD_SET_POST_SCAN 0x0108
271#define MWL8K_CMD_SET_RF_CHANNEL 0x010a 272#define MWL8K_CMD_SET_RF_CHANNEL 0x010a
@@ -281,6 +282,7 @@ static const struct ieee80211_rate mwl8k_rates[] = {
281#define MWL8K_CMD_ENABLE_SNIFFER 0x0150 282#define MWL8K_CMD_ENABLE_SNIFFER 0x0150
282#define MWL8K_CMD_SET_MAC_ADDR 0x0202 283#define MWL8K_CMD_SET_MAC_ADDR 0x0202
283#define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 284#define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203
285#define MWL8K_CMD_BSS_START 0x1100
284#define MWL8K_CMD_SET_NEW_STN 0x1111 286#define MWL8K_CMD_SET_NEW_STN 0x1111
285#define MWL8K_CMD_UPDATE_STADB 0x1123 287#define MWL8K_CMD_UPDATE_STADB 0x1123
286 288
@@ -299,6 +301,7 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize)
299 MWL8K_CMDNAME(RADIO_CONTROL); 301 MWL8K_CMDNAME(RADIO_CONTROL);
300 MWL8K_CMDNAME(RF_TX_POWER); 302 MWL8K_CMDNAME(RF_TX_POWER);
301 MWL8K_CMDNAME(RF_ANTENNA); 303 MWL8K_CMDNAME(RF_ANTENNA);
304 MWL8K_CMDNAME(SET_BEACON);
302 MWL8K_CMDNAME(SET_PRE_SCAN); 305 MWL8K_CMDNAME(SET_PRE_SCAN);
303 MWL8K_CMDNAME(SET_POST_SCAN); 306 MWL8K_CMDNAME(SET_POST_SCAN);
304 MWL8K_CMDNAME(SET_RF_CHANNEL); 307 MWL8K_CMDNAME(SET_RF_CHANNEL);
@@ -314,6 +317,7 @@ static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize)
314 MWL8K_CMDNAME(ENABLE_SNIFFER); 317 MWL8K_CMDNAME(ENABLE_SNIFFER);
315 MWL8K_CMDNAME(SET_MAC_ADDR); 318 MWL8K_CMDNAME(SET_MAC_ADDR);
316 MWL8K_CMDNAME(SET_RATEADAPT_MODE); 319 MWL8K_CMDNAME(SET_RATEADAPT_MODE);
320 MWL8K_CMDNAME(BSS_START);
317 MWL8K_CMDNAME(SET_NEW_STN); 321 MWL8K_CMDNAME(SET_NEW_STN);
318 MWL8K_CMDNAME(UPDATE_STADB); 322 MWL8K_CMDNAME(UPDATE_STADB);
319 default: 323 default:
@@ -1769,7 +1773,9 @@ struct mwl8k_cmd_set_hw_spec {
1769 __le32 total_rxd; 1773 __le32 total_rxd;
1770} __attribute__((packed)); 1774} __attribute__((packed));
1771 1775
1772#define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080 1776#define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080
1777#define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP 0x00000020
1778#define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON 0x00000010
1773 1779
1774static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) 1780static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw)
1775{ 1781{
@@ -1790,7 +1796,9 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw)
1790 cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES); 1796 cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES);
1791 for (i = 0; i < MWL8K_TX_QUEUES; i++) 1797 for (i = 0; i < MWL8K_TX_QUEUES; i++)
1792 cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma); 1798 cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma);
1793 cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT); 1799 cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT |
1800 MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP |
1801 MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON);
1794 cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); 1802 cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS);
1795 cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); 1803 cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS);
1796 1804
@@ -2028,6 +2036,35 @@ mwl8k_cmd_rf_antenna(struct ieee80211_hw *hw, int antenna, int mask)
2028} 2036}
2029 2037
2030/* 2038/*
2039 * CMD_SET_BEACON.
2040 */
2041struct mwl8k_cmd_set_beacon {
2042 struct mwl8k_cmd_pkt header;
2043 __le16 beacon_len;
2044 __u8 beacon[0];
2045};
2046
2047static int mwl8k_cmd_set_beacon(struct ieee80211_hw *hw, u8 *beacon, int len)
2048{
2049 struct mwl8k_cmd_set_beacon *cmd;
2050 int rc;
2051
2052 cmd = kzalloc(sizeof(*cmd) + len, GFP_KERNEL);
2053 if (cmd == NULL)
2054 return -ENOMEM;
2055
2056 cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_BEACON);
2057 cmd->header.length = cpu_to_le16(sizeof(*cmd) + len);
2058 cmd->beacon_len = cpu_to_le16(len);
2059 memcpy(cmd->beacon, beacon, len);
2060
2061 rc = mwl8k_post_cmd(hw, &cmd->header);
2062 kfree(cmd);
2063
2064 return rc;
2065}
2066
2067/*
2031 * CMD_SET_PRE_SCAN. 2068 * CMD_SET_PRE_SCAN.
2032 */ 2069 */
2033struct mwl8k_cmd_set_pre_scan { 2070struct mwl8k_cmd_set_pre_scan {
@@ -2665,6 +2702,33 @@ static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode)
2665} 2702}
2666 2703
2667/* 2704/*
2705 * CMD_BSS_START.
2706 */
2707struct mwl8k_cmd_bss_start {
2708 struct mwl8k_cmd_pkt header;
2709 __le32 enable;
2710} __attribute__((packed));
2711
2712static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw, int enable)
2713{
2714 struct mwl8k_cmd_bss_start *cmd;
2715 int rc;
2716
2717 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
2718 if (cmd == NULL)
2719 return -ENOMEM;
2720
2721 cmd->header.code = cpu_to_le16(MWL8K_CMD_BSS_START);
2722 cmd->header.length = cpu_to_le16(sizeof(*cmd));
2723 cmd->enable = cpu_to_le32(enable);
2724
2725 rc = mwl8k_post_cmd(hw, &cmd->header);
2726 kfree(cmd);
2727
2728 return rc;
2729}
2730
2731/*
2668 * CMD_SET_NEW_STN. 2732 * CMD_SET_NEW_STN.
2669 */ 2733 */
2670struct mwl8k_cmd_set_new_stn { 2734struct mwl8k_cmd_set_new_stn {
@@ -2727,6 +2791,26 @@ static int mwl8k_cmd_set_new_stn_add(struct ieee80211_hw *hw,
2727 return rc; 2791 return rc;
2728} 2792}
2729 2793
2794static int mwl8k_cmd_set_new_stn_add_self(struct ieee80211_hw *hw,
2795 struct ieee80211_vif *vif)
2796{
2797 struct mwl8k_cmd_set_new_stn *cmd;
2798 int rc;
2799
2800 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
2801 if (cmd == NULL)
2802 return -ENOMEM;
2803
2804 cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_NEW_STN);
2805 cmd->header.length = cpu_to_le16(sizeof(*cmd));
2806 memcpy(cmd->mac_addr, vif->addr, ETH_ALEN);
2807
2808 rc = mwl8k_post_cmd(hw, &cmd->header);
2809 kfree(cmd);
2810
2811 return rc;
2812}
2813
2730static int mwl8k_cmd_set_new_stn_del(struct ieee80211_hw *hw, 2814static int mwl8k_cmd_set_new_stn_del(struct ieee80211_hw *hw,
2731 struct ieee80211_vif *vif, u8 *addr) 2815 struct ieee80211_vif *vif, u8 *addr)
2732{ 2816{
@@ -3016,15 +3100,9 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw,
3016 return -EBUSY; 3100 return -EBUSY;
3017 3101
3018 /* 3102 /*
3019 * We only support managed interfaces for now.
3020 */
3021 if (vif->type != NL80211_IFTYPE_STATION)
3022 return -EINVAL;
3023
3024 /*
3025 * Reject interface creation if sniffer mode is active, as 3103 * Reject interface creation if sniffer mode is active, as
3026 * STA operation is mutually exclusive with hardware sniffer 3104 * STA operation is mutually exclusive with hardware sniffer
3027 * mode. 3105 * mode. (Sniffer mode is only used on STA firmware.)
3028 */ 3106 */
3029 if (priv->sniffer_enabled) { 3107 if (priv->sniffer_enabled) {
3030 printk(KERN_INFO "%s: unable to create STA " 3108 printk(KERN_INFO "%s: unable to create STA "
@@ -3036,6 +3114,9 @@ static int mwl8k_add_interface(struct ieee80211_hw *hw,
3036 /* Set the mac address. */ 3114 /* Set the mac address. */
3037 mwl8k_cmd_set_mac_addr(hw, vif->addr); 3115 mwl8k_cmd_set_mac_addr(hw, vif->addr);
3038 3116
3117 if (priv->ap_fw)
3118 mwl8k_cmd_set_new_stn_add_self(hw, vif);
3119
3039 /* Clean out driver private area */ 3120 /* Clean out driver private area */
3040 mwl8k_vif = MWL8K_VIF(vif); 3121 mwl8k_vif = MWL8K_VIF(vif);
3041 memset(mwl8k_vif, 0, sizeof(*mwl8k_vif)); 3122 memset(mwl8k_vif, 0, sizeof(*mwl8k_vif));
@@ -3054,6 +3135,9 @@ static void mwl8k_remove_interface(struct ieee80211_hw *hw,
3054{ 3135{
3055 struct mwl8k_priv *priv = hw->priv; 3136 struct mwl8k_priv *priv = hw->priv;
3056 3137
3138 if (priv->ap_fw)
3139 mwl8k_cmd_set_new_stn_del(hw, vif, vif->addr);
3140
3057 mwl8k_cmd_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00"); 3141 mwl8k_cmd_set_mac_addr(hw, "\x00\x00\x00\x00\x00\x00");
3058 3142
3059 priv->vif = NULL; 3143 priv->vif = NULL;
@@ -3105,10 +3189,9 @@ out:
3105 return rc; 3189 return rc;
3106} 3190}
3107 3191
3108static void mwl8k_bss_info_changed(struct ieee80211_hw *hw, 3192static void
3109 struct ieee80211_vif *vif, 3193mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
3110 struct ieee80211_bss_conf *info, 3194 struct ieee80211_bss_conf *info, u32 changed)
3111 u32 changed)
3112{ 3195{
3113 struct mwl8k_priv *priv = hw->priv; 3196 struct mwl8k_priv *priv = hw->priv;
3114 u32 ap_legacy_rates; 3197 u32 ap_legacy_rates;
@@ -3188,6 +3271,66 @@ out:
3188 mwl8k_fw_unlock(hw); 3271 mwl8k_fw_unlock(hw);
3189} 3272}
3190 3273
3274static void
3275mwl8k_bss_info_changed_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
3276 struct ieee80211_bss_conf *info, u32 changed)
3277{
3278 int rc;
3279
3280 if (mwl8k_fw_lock(hw))
3281 return;
3282
3283 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3284 rc = mwl8k_set_radio_preamble(hw,
3285 vif->bss_conf.use_short_preamble);
3286 if (rc)
3287 goto out;
3288 }
3289
3290 if (changed & BSS_CHANGED_BASIC_RATES) {
3291 int idx;
3292 int rate;
3293
3294 /*
3295 * Use lowest supported basic rate for multicasts
3296 * and management frames (such as probe responses --
3297 * beacons will always go out at 1 Mb/s).
3298 */
3299 idx = ffs(vif->bss_conf.basic_rates);
3300 rate = idx ? mwl8k_rates[idx - 1].hw_value : 2;
3301
3302 mwl8k_cmd_use_fixed_rate_ap(hw, rate, rate);
3303 }
3304
3305 if (changed & (BSS_CHANGED_BEACON_INT | BSS_CHANGED_BEACON)) {
3306 struct sk_buff *skb;
3307
3308 skb = ieee80211_beacon_get(hw, vif);
3309 if (skb != NULL) {
3310 mwl8k_cmd_set_beacon(hw, skb->data, skb->len);
3311 kfree_skb(skb);
3312 }
3313 }
3314
3315 if (changed & BSS_CHANGED_BEACON_ENABLED)
3316 mwl8k_cmd_bss_start(hw, info->enable_beacon);
3317
3318out:
3319 mwl8k_fw_unlock(hw);
3320}
3321
3322static void
3323mwl8k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
3324 struct ieee80211_bss_conf *info, u32 changed)
3325{
3326 struct mwl8k_priv *priv = hw->priv;
3327
3328 if (!priv->ap_fw)
3329 mwl8k_bss_info_changed_sta(hw, vif, info, changed);
3330 else
3331 mwl8k_bss_info_changed_ap(hw, vif, info, changed);
3332}
3333
3191static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw, 3334static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw,
3192 int mc_count, struct dev_addr_list *mclist) 3335 int mc_count, struct dev_addr_list *mclist)
3193{ 3336{
@@ -3766,6 +3909,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
3766 rc = mwl8k_cmd_get_hw_spec_ap(hw); 3909 rc = mwl8k_cmd_get_hw_spec_ap(hw);
3767 if (!rc) 3910 if (!rc)
3768 rc = mwl8k_cmd_set_hw_spec(hw); 3911 rc = mwl8k_cmd_set_hw_spec(hw);
3912
3913 hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_AP);
3769 } else { 3914 } else {
3770 rc = mwl8k_cmd_get_hw_spec_sta(hw); 3915 rc = mwl8k_cmd_get_hw_spec_sta(hw);
3771 3916