aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas
diff options
context:
space:
mode:
authorKiran Divekar <dkiran@marvell.com>2010-06-05 02:20:42 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-06-23 15:14:00 -0400
commit1047d5edd4838f27dc86f24676178f2249c446ea (patch)
tree2cf140cd7ae14590367b8dccda3c8adaee754e06 /drivers/net/wireless/libertas
parente4fe4eafa41cf951fb8fe2b9725ae84c599668d8 (diff)
Libertas: Added 11d support using cfg80211
Added 11d support for libertas driver using cfg80211. This is based on Holger Shurig's initial work to add cfg80211 support libertas. (https://patchwork.kernel.org/patch/64286/) Please let us know, if there are any improvements comments. Code is added to send 11d enable command to firmware while initialisation and pass 11d specific information to firmware when notifier handler is called by cfg80211. Signed-off-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: Kiran Divekar <dkiran@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/libertas')
-rw-r--r--drivers/net/wireless/libertas/cfg.c110
-rw-r--r--drivers/net/wireless/libertas/cfg.h5
-rw-r--r--drivers/net/wireless/libertas/cmd.c65
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c50
-rw-r--r--drivers/net/wireless/libertas/decl.h5
-rw-r--r--drivers/net/wireless/libertas/dev.h3
-rw-r--r--drivers/net/wireless/libertas/host.h28
-rw-r--r--drivers/net/wireless/libertas/main.c3
8 files changed, 268 insertions, 1 deletions
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 089f0722fa2..f36cc970ad1 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -8,6 +8,7 @@
8 8
9#include <linux/slab.h> 9#include <linux/slab.h>
10#include <linux/if_arp.h> 10#include <linux/if_arp.h>
11#include <linux/ieee80211.h>
11#include <net/cfg80211.h> 12#include <net/cfg80211.h>
12#include <asm/unaligned.h> 13#include <asm/unaligned.h>
13 14
@@ -2042,6 +2043,7 @@ int lbs_cfg_register(struct lbs_private *priv)
2042 */ 2043 */
2043 wdev->wiphy->cipher_suites = cipher_suites; 2044 wdev->wiphy->cipher_suites = cipher_suites;
2044 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); 2045 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
2046 wdev->wiphy->reg_notifier = lbs_reg_notifier;
2045 2047
2046 ret = wiphy_register(wdev->wiphy); 2048 ret = wiphy_register(wdev->wiphy);
2047 if (ret < 0) 2049 if (ret < 0)
@@ -2061,6 +2063,114 @@ int lbs_cfg_register(struct lbs_private *priv)
2061 return ret; 2063 return ret;
2062} 2064}
2063 2065
2066/**
2067 * @brief This function sets DOMAIN INFO to FW
2068 * @param priv pointer to struct lbs_private
2069 * @return 0; -1
2070*/
2071static int lbs_11d_set_domain_info(struct lbs_private *priv)
2072{
2073 int ret;
2074
2075 ret = lbs_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO,
2076 CMD_ACT_SET,
2077 CMD_OPTION_WAITFORRSP, 0, NULL);
2078 if (ret)
2079 lbs_deb_11d("fail to dnld domain info\n");
2080
2081 return ret;
2082}
2083
2084static void lbs_send_domain_info_cmd_fw(struct wiphy *wiphy,
2085 struct regulatory_request *request)
2086{
2087 u8 no_of_triplet = 0;
2088 u8 no_of_parsed_chan = 0;
2089 u8 first_channel = 0, next_chan = 0, max_pwr = 0;
2090 u8 i, flag = 0;
2091 enum ieee80211_band band;
2092 struct ieee80211_supported_band *sband;
2093 struct ieee80211_channel *ch;
2094 struct lbs_private *priv = wiphy_priv(wiphy);
2095 struct lbs_802_11d_domain_reg *domain_info = &priv->domain_reg;
2096 int ret = 0;
2097
2098 lbs_deb_enter(LBS_DEB_CFG80211);
2099
2100 /* Set country code */
2101 domain_info->country_code[0] = request->alpha2[0];
2102 domain_info->country_code[1] = request->alpha2[1];
2103 domain_info->country_code[2] = ' ';
2104
2105 for (band = 0; band < IEEE80211_NUM_BANDS ; band++) {
2106
2107 if (!wiphy->bands[band])
2108 continue;
2109
2110 sband = wiphy->bands[band];
2111
2112 for (i = 0; i < sband->n_channels ; i++) {
2113 ch = &sband->channels[i];
2114 if (ch->flags & IEEE80211_CHAN_DISABLED)
2115 continue;
2116
2117 if (!flag) {
2118 flag = 1;
2119 next_chan = first_channel = (u32) ch->hw_value;
2120 max_pwr = ch->max_power;
2121 no_of_parsed_chan = 1;
2122 continue;
2123 }
2124
2125 if (ch->hw_value == next_chan + 1 &&
2126 ch->max_power == max_pwr) {
2127 next_chan++;
2128 no_of_parsed_chan++;
2129 } else {
2130 domain_info->triplet[no_of_triplet]
2131 .chans.first_channel = first_channel;
2132 domain_info->triplet[no_of_triplet]
2133 .chans.num_channels = no_of_parsed_chan;
2134 domain_info->triplet[no_of_triplet]
2135 .chans.max_power = max_pwr;
2136 no_of_triplet++;
2137 flag = 0;
2138 }
2139 }
2140 if (flag) {
2141 domain_info->triplet[no_of_triplet]
2142 .chans.first_channel = first_channel;
2143 domain_info->triplet[no_of_triplet]
2144 .chans.num_channels = no_of_parsed_chan;
2145 domain_info->triplet[no_of_triplet]
2146 .chans.max_power = max_pwr;
2147 no_of_triplet++;
2148 }
2149 }
2150
2151 domain_info->no_triplet = no_of_triplet;
2152
2153 /* Set domain info */
2154 ret = lbs_11d_set_domain_info(priv);
2155 if (ret)
2156 lbs_pr_err("11D: error setting domain info in FW\n");
2157
2158 lbs_deb_leave(LBS_DEB_CFG80211);
2159}
2160
2161int lbs_reg_notifier(struct wiphy *wiphy,
2162 struct regulatory_request *request)
2163{
2164 lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain "
2165 "callback for domain %c%c\n", request->alpha2[0],
2166 request->alpha2[1]);
2167
2168 lbs_send_domain_info_cmd_fw(wiphy, request);
2169
2170 lbs_deb_leave(LBS_DEB_CFG80211);
2171
2172 return 0;
2173}
2064 2174
2065void lbs_scan_deinit(struct lbs_private *priv) 2175void lbs_scan_deinit(struct lbs_private *priv)
2066{ 2176{
diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h
index eae3fd911ab..756fb98f9f0 100644
--- a/drivers/net/wireless/libertas/cfg.h
+++ b/drivers/net/wireless/libertas/cfg.h
@@ -3,11 +3,16 @@
3 3
4struct device; 4struct device;
5struct lbs_private; 5struct lbs_private;
6struct regulatory_request;
7struct wiphy;
6 8
7struct wireless_dev *lbs_cfg_alloc(struct device *dev); 9struct wireless_dev *lbs_cfg_alloc(struct device *dev);
8int lbs_cfg_register(struct lbs_private *priv); 10int lbs_cfg_register(struct lbs_private *priv);
9void lbs_cfg_free(struct lbs_private *priv); 11void lbs_cfg_free(struct lbs_private *priv);
10 12
13int lbs_reg_notifier(struct wiphy *wiphy,
14 struct regulatory_request *request);
15
11/* All of those are TODOs: */ 16/* All of those are TODOs: */
12#define lbs_cmd_802_11_rssi(priv, cmdptr) (0) 17#define lbs_cmd_802_11_rssi(priv, cmdptr) (0)
13#define lbs_ret_802_11_rssi(priv, resp) (0) 18#define lbs_ret_802_11_rssi(priv, resp) (0)
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index d8838461e59..6c8a9d952a0 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -899,6 +899,66 @@ void lbs_set_mac_control(struct lbs_private *priv)
899} 899}
900 900
901/** 901/**
902 * @brief This function implements command CMD_802_11D_DOMAIN_INFO
903 * @param priv pointer to struct lbs_private
904 * @param cmd pointer to cmd buffer
905 * @param cmdno cmd ID
906 * @param cmdOption cmd action
907 * @return 0
908*/
909int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
910 struct cmd_ds_command *cmd,
911 u16 cmdoption)
912{
913 struct cmd_ds_802_11d_domain_info *pdomaininfo =
914 &cmd->params.domaininfo;
915 struct mrvl_ie_domain_param_set *domain = &pdomaininfo->domain;
916 u8 nr_triplet = priv->domain_reg.no_triplet;
917
918 lbs_deb_enter(LBS_DEB_11D);
919
920 lbs_deb_11d("nr_triplet=%x\n", nr_triplet);
921
922 pdomaininfo->action = cpu_to_le16(cmdoption);
923 if (cmdoption == CMD_ACT_GET) {
924 cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
925 sizeof(struct cmd_header));
926 lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
927 le16_to_cpu(cmd->size));
928 goto done;
929 }
930
931 domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
932 memcpy(domain->countrycode, priv->domain_reg.country_code,
933 sizeof(domain->countrycode));
934
935 domain->header.len = cpu_to_le16(nr_triplet
936 * sizeof(struct ieee80211_country_ie_triplet)
937 + sizeof(domain->countrycode));
938
939 if (nr_triplet) {
940 memcpy(domain->triplet, priv->domain_reg.triplet,
941 nr_triplet *
942 sizeof(struct ieee80211_country_ie_triplet));
943
944 cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
945 le16_to_cpu(domain->header.len) +
946 sizeof(struct mrvl_ie_header) +
947 sizeof(struct cmd_header));
948 } else {
949 cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
950 sizeof(struct cmd_header));
951 }
952
953 lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
954 le16_to_cpu(cmd->size));
955
956done:
957 lbs_deb_enter(LBS_DEB_11D);
958 return 0;
959}
960
961/**
902 * @brief This function prepare the command before send to firmware. 962 * @brief This function prepare the command before send to firmware.
903 * 963 *
904 * @param priv A pointer to struct lbs_private structure 964 * @param priv A pointer to struct lbs_private structure
@@ -996,6 +1056,11 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
996 ret = 0; 1056 ret = 0;
997 goto done; 1057 goto done;
998 1058
1059 case CMD_802_11D_DOMAIN_INFO:
1060 cmdptr->command = cpu_to_le16(cmd_no);
1061 ret = lbs_cmd_802_11d_domain_info(priv, cmdptr, cmd_action);
1062 break;
1063
999 case CMD_802_11_TPC_CFG: 1064 case CMD_802_11_TPC_CFG:
1000 cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG); 1065 cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
1001 cmdptr->size = 1066 cmdptr->size =
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 52b543c52a9..b4bc103d797 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -97,6 +97,52 @@ static int lbs_ret_reg_access(struct lbs_private *priv,
97 return ret; 97 return ret;
98} 98}
99 99
100/**
101 * @brief This function parses countryinfo from AP and download country info to FW
102 * @param priv pointer to struct lbs_private
103 * @param resp pointer to command response buffer
104 * @return 0; -1
105 */
106int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp)
107{
108 struct cmd_ds_802_11d_domain_info *domaininfo =
109 &resp->params.domaininforesp;
110 struct mrvl_ie_domain_param_set *domain = &domaininfo->domain;
111 u16 action = le16_to_cpu(domaininfo->action);
112 s16 ret = 0;
113 u8 nr_triplet = 0;
114
115 lbs_deb_enter(LBS_DEB_11D);
116
117 lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp,
118 (int)le16_to_cpu(resp->size));
119
120 nr_triplet = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
121 sizeof(struct ieee80211_country_ie_triplet);
122
123 lbs_deb_11d("domain info resp: nr_triplet %d\n", nr_triplet);
124
125 if (nr_triplet > MRVDRV_MAX_TRIPLET_802_11D) {
126 lbs_deb_11d("invalid number of triplets returned!!\n");
127 return -1;
128 }
129
130 switch (action) {
131 case CMD_ACT_SET: /*Proc set action */
132 break;
133
134 case CMD_ACT_GET:
135 break;
136 default:
137 lbs_deb_11d("invalid action:%d\n", domaininfo->action);
138 ret = -1;
139 break;
140 }
141
142 lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
143 return ret;
144}
145
100static inline int handle_cmd_response(struct lbs_private *priv, 146static inline int handle_cmd_response(struct lbs_private *priv,
101 struct cmd_header *cmd_response) 147 struct cmd_header *cmd_response)
102{ 148{
@@ -130,6 +176,10 @@ static inline int handle_cmd_response(struct lbs_private *priv,
130 ret = lbs_ret_802_11_rssi(priv, resp); 176 ret = lbs_ret_802_11_rssi(priv, resp);
131 break; 177 break;
132 178
179 case CMD_RET(CMD_802_11D_DOMAIN_INFO):
180 ret = lbs_ret_802_11d_domain_info(resp);
181 break;
182
133 case CMD_RET(CMD_802_11_TPC_CFG): 183 case CMD_RET(CMD_802_11_TPC_CFG):
134 spin_lock_irqsave(&priv->driver_lock, flags); 184 spin_lock_irqsave(&priv->driver_lock, flags);
135 memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg, 185 memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg,
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 85c97d3ed88..ba5438a7ba1 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -13,6 +13,7 @@
13struct lbs_private; 13struct lbs_private;
14struct sk_buff; 14struct sk_buff;
15struct net_device; 15struct net_device;
16struct cmd_ds_command;
16 17
17 18
18/* ethtool.c */ 19/* ethtool.c */
@@ -52,5 +53,9 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv);
52u32 lbs_fw_index_to_data_rate(u8 index); 53u32 lbs_fw_index_to_data_rate(u8 index);
53u8 lbs_data_rate_to_fw_index(u32 rate); 54u8 lbs_data_rate_to_fw_index(u32 rate);
54 55
56int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
57 struct cmd_ds_command *cmd, u16 cmdoption);
58
59int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp);
55 60
56#endif 61#endif
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index be263acf19c..4536d9c0ad8 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -60,6 +60,9 @@ struct lbs_private {
60 struct dentry *regs_dir; 60 struct dentry *regs_dir;
61 struct dentry *debugfs_regs_files[6]; 61 struct dentry *debugfs_regs_files[6];
62 62
63 /** 11D and domain regulatory data */
64 struct lbs_802_11d_domain_reg domain_reg;
65
63 /* Hardware debugging */ 66 /* Hardware debugging */
64 u32 mac_offset; 67 u32 mac_offset;
65 u32 bbp_offset; 68 u32 bbp_offset;
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index 3809c0b4946..112fbf167dc 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -389,6 +389,30 @@ struct lbs_offset_value {
389 u32 value; 389 u32 value;
390} __attribute__ ((packed)); 390} __attribute__ ((packed));
391 391
392#define MRVDRV_MAX_TRIPLET_802_11D 83
393
394#define COUNTRY_CODE_LEN 3
395
396struct mrvl_ie_domain_param_set {
397 struct mrvl_ie_header header;
398
399 u8 countrycode[COUNTRY_CODE_LEN];
400 struct ieee80211_country_ie_triplet triplet[1];
401} __attribute__ ((packed));
402
403struct cmd_ds_802_11d_domain_info {
404 __le16 action;
405 struct mrvl_ie_domain_param_set domain;
406} __attribute__ ((packed));
407
408struct lbs_802_11d_domain_reg {
409 /** Country code*/
410 u8 country_code[COUNTRY_CODE_LEN];
411 /** No. of triplet*/
412 u8 no_triplet;
413 struct ieee80211_country_ie_triplet triplet[MRVDRV_MAX_TRIPLET_802_11D];
414} __attribute__ ((packed));
415
392/* 416/*
393 * Define data structure for CMD_GET_HW_SPEC 417 * Define data structure for CMD_GET_HW_SPEC
394 * This structure defines the response for the GET_HW_SPEC command 418 * This structure defines the response for the GET_HW_SPEC command
@@ -949,6 +973,9 @@ struct cmd_ds_command {
949 struct cmd_ds_bbp_reg_access bbpreg; 973 struct cmd_ds_bbp_reg_access bbpreg;
950 struct cmd_ds_rf_reg_access rfreg; 974 struct cmd_ds_rf_reg_access rfreg;
951 975
976 struct cmd_ds_802_11d_domain_info domaininfo;
977 struct cmd_ds_802_11d_domain_info domaininforesp;
978
952 struct cmd_ds_802_11_tpc_cfg tpccfg; 979 struct cmd_ds_802_11_tpc_cfg tpccfg;
953 struct cmd_ds_802_11_afc afc; 980 struct cmd_ds_802_11_afc afc;
954 struct cmd_ds_802_11_led_ctrl ledgpio; 981 struct cmd_ds_802_11_led_ctrl ledgpio;
@@ -958,5 +985,4 @@ struct cmd_ds_command {
958 struct cmd_ds_802_11_beacon_control bcn_ctrl; 985 struct cmd_ds_802_11_beacon_control bcn_ctrl;
959 } params; 986 } params;
960} __attribute__ ((packed)); 987} __attribute__ ((packed));
961
962#endif 988#endif
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 58b031c5241..b519fc70f04 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -652,6 +652,9 @@ static int lbs_setup_firmware(struct lbs_private *priv)
652 priv->txpower_max = maxlevel; 652 priv->txpower_max = maxlevel;
653 } 653 }
654 654
655 /* Send cmd to FW to enable 11D function */
656 ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_11D_ENABLE, 1);
657
655 lbs_set_mac_control(priv); 658 lbs_set_mac_control(priv);
656done: 659done:
657 lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); 660 lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);