diff options
author | Javier Cardona <javier@cozybit.com> | 2008-05-17 03:55:10 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-05-21 21:47:39 -0400 |
commit | edaea5ce05ca804cc55438c586ca2f947d49f56f (patch) | |
tree | be82d922cb908221d247e21d04ddf5517e7a4953 /drivers/net/wireless | |
parent | 75bf45a7b4ab81cfa5c5eab68b57bbfee8b8ede2 (diff) |
libertas: Extend MESH_CONFIG command to access non-volatile configuration
This patch is based on a patch from Shailendra Govardhan and Brian Cavagnolo.
It extends the MESH_CONFIG command to configure non-volatile parameters on
libertas devices that support them (e.g. OLPC Active Antenna).
This patch only implements the driver/firmware interface.
See http://dev.laptop.org/ticket/6823 for minimal testing results and known
issues.
Signed-off-by: Javier Cardona <javier@cozybit.com>
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/libertas/assoc.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/cmd.c | 68 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/cmd.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/defs.h | 10 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/host.h | 17 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/main.c | 13 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/types.h | 30 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/wext.c | 5 |
8 files changed, 132 insertions, 20 deletions
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index c9c3640ce9fb..953a44f750e1 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c | |||
@@ -603,7 +603,8 @@ static int assoc_helper_channel(struct lbs_private *priv, | |||
603 | /* Change mesh channel first; 21.p21 firmware won't let | 603 | /* Change mesh channel first; 21.p21 firmware won't let |
604 | you change channel otherwise (even though it'll return | 604 | you change channel otherwise (even though it'll return |
605 | an error to this */ | 605 | an error to this */ |
606 | lbs_mesh_config(priv, 0, assoc_req->channel); | 606 | lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, |
607 | assoc_req->channel); | ||
607 | } | 608 | } |
608 | 609 | ||
609 | lbs_deb_assoc("ASSOC: channel: %d -> %d\n", | 610 | lbs_deb_assoc("ASSOC: channel: %d -> %d\n", |
@@ -642,7 +643,8 @@ static int assoc_helper_channel(struct lbs_private *priv, | |||
642 | 643 | ||
643 | restore_mesh: | 644 | restore_mesh: |
644 | if (priv->mesh_dev) | 645 | if (priv->mesh_dev) |
645 | lbs_mesh_config(priv, 1, priv->curbssparams.channel); | 646 | lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, |
647 | priv->curbssparams.channel); | ||
646 | 648 | ||
647 | done: | 649 | done: |
648 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); | 650 | lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); |
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index b494aba869c5..7ccec987faaa 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c | |||
@@ -4,6 +4,7 @@ | |||
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <net/iw_handler.h> | 6 | #include <net/iw_handler.h> |
7 | #include <net/ieee80211.h> | ||
7 | #include <linux/kfifo.h> | 8 | #include <linux/kfifo.h> |
8 | #include "host.h" | 9 | #include "host.h" |
9 | #include "hostcmd.h" | 10 | #include "hostcmd.h" |
@@ -998,24 +999,69 @@ int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, | |||
998 | return ret; | 999 | return ret; |
999 | } | 1000 | } |
1000 | 1001 | ||
1001 | int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan) | 1002 | int lbs_mesh_config_send(struct lbs_private *priv, |
1003 | struct cmd_ds_mesh_config *cmd, | ||
1004 | uint16_t action, uint16_t type) | ||
1005 | { | ||
1006 | int ret; | ||
1007 | |||
1008 | lbs_deb_enter(LBS_DEB_CMD); | ||
1009 | |||
1010 | cmd->hdr.command = cpu_to_le16(CMD_MESH_CONFIG); | ||
1011 | cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config)); | ||
1012 | cmd->hdr.result = 0; | ||
1013 | |||
1014 | cmd->type = cpu_to_le16(type); | ||
1015 | cmd->action = cpu_to_le16(action); | ||
1016 | |||
1017 | ret = lbs_cmd_with_response(priv, CMD_MESH_CONFIG, cmd); | ||
1018 | |||
1019 | lbs_deb_leave(LBS_DEB_CMD); | ||
1020 | return ret; | ||
1021 | } | ||
1022 | |||
1023 | /* This function is the CMD_MESH_CONFIG legacy function. It only handles the | ||
1024 | * START and STOP actions. The extended actions supported by CMD_MESH_CONFIG | ||
1025 | * are all handled by preparing a struct cmd_ds_mesh_config and passing it to | ||
1026 | * lbs_mesh_config_send. | ||
1027 | */ | ||
1028 | int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan) | ||
1002 | { | 1029 | { |
1003 | struct cmd_ds_mesh_config cmd; | 1030 | struct cmd_ds_mesh_config cmd; |
1031 | struct mrvl_meshie *ie; | ||
1004 | 1032 | ||
1005 | memset(&cmd, 0, sizeof(cmd)); | 1033 | memset(&cmd, 0, sizeof(cmd)); |
1006 | cmd.action = cpu_to_le16(enable); | ||
1007 | cmd.channel = cpu_to_le16(chan); | 1034 | cmd.channel = cpu_to_le16(chan); |
1008 | cmd.type = cpu_to_le16(priv->mesh_tlv); | 1035 | ie = (struct mrvl_meshie *)cmd.data; |
1009 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); | 1036 | |
1010 | 1037 | switch (action) { | |
1011 | if (enable) { | 1038 | case CMD_ACT_MESH_CONFIG_START: |
1012 | cmd.length = cpu_to_le16(priv->mesh_ssid_len); | 1039 | ie->hdr.id = MFIE_TYPE_GENERIC; |
1013 | memcpy(cmd.data, priv->mesh_ssid, priv->mesh_ssid_len); | 1040 | ie->val.oui[0] = 0x00; |
1041 | ie->val.oui[1] = 0x50; | ||
1042 | ie->val.oui[2] = 0x43; | ||
1043 | ie->val.type = MARVELL_MESH_IE_TYPE; | ||
1044 | ie->val.subtype = MARVELL_MESH_IE_SUBTYPE; | ||
1045 | ie->val.version = MARVELL_MESH_IE_VERSION; | ||
1046 | ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP; | ||
1047 | ie->val.active_metric_id = MARVELL_MESH_METRIC_ID; | ||
1048 | ie->val.mesh_capability = MARVELL_MESH_CAPABILITY; | ||
1049 | ie->val.mesh_id_len = priv->mesh_ssid_len; | ||
1050 | memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len); | ||
1051 | ie->hdr.len = sizeof(struct mrvl_meshie_val) - | ||
1052 | IW_ESSID_MAX_SIZE + priv->mesh_ssid_len; | ||
1053 | cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val)); | ||
1054 | break; | ||
1055 | case CMD_ACT_MESH_CONFIG_STOP: | ||
1056 | break; | ||
1057 | default: | ||
1058 | return -1; | ||
1014 | } | 1059 | } |
1015 | lbs_deb_cmd("mesh config enable %d TLV %x channel %d SSID %s\n", | 1060 | lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n", |
1016 | enable, priv->mesh_tlv, chan, | 1061 | action, priv->mesh_tlv, chan, |
1017 | escape_essid(priv->mesh_ssid, priv->mesh_ssid_len)); | 1062 | escape_essid(priv->mesh_ssid, priv->mesh_ssid_len)); |
1018 | return lbs_cmd_with_response(priv, CMD_MESH_CONFIG, &cmd); | 1063 | |
1064 | return lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv); | ||
1019 | } | 1065 | } |
1020 | 1066 | ||
1021 | static int lbs_cmd_bcn_ctrl(struct lbs_private * priv, | 1067 | static int lbs_cmd_bcn_ctrl(struct lbs_private * priv, |
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index f4019c22adfc..00d290e2818f 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h | |||
@@ -39,6 +39,9 @@ int lbs_set_data_rate(struct lbs_private *priv, u8 rate); | |||
39 | int lbs_get_channel(struct lbs_private *priv); | 39 | int lbs_get_channel(struct lbs_private *priv); |
40 | int lbs_set_channel(struct lbs_private *priv, u8 channel); | 40 | int lbs_set_channel(struct lbs_private *priv, u8 channel); |
41 | 41 | ||
42 | int lbs_mesh_config_send(struct lbs_private *priv, | ||
43 | struct cmd_ds_mesh_config *cmd, | ||
44 | uint16_t action, uint16_t type); | ||
42 | int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan); | 45 | int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan); |
43 | 46 | ||
44 | int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria); | 47 | int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria); |
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index d39520111062..3793cb92296a 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h | |||
@@ -170,6 +170,16 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in | |||
170 | 170 | ||
171 | #define MARVELL_MESH_IE_LENGTH 9 | 171 | #define MARVELL_MESH_IE_LENGTH 9 |
172 | 172 | ||
173 | /* Values used to populate the struct mrvl_mesh_ie. The only time you need this | ||
174 | * is when enabling the mesh using CMD_MESH_CONFIG. | ||
175 | */ | ||
176 | #define MARVELL_MESH_IE_TYPE 4 | ||
177 | #define MARVELL_MESH_IE_SUBTYPE 0 | ||
178 | #define MARVELL_MESH_IE_VERSION 0 | ||
179 | #define MARVELL_MESH_PROTO_ID_HWMP 0 | ||
180 | #define MARVELL_MESH_METRIC_ID 0 | ||
181 | #define MARVELL_MESH_CAPABILITY 0 | ||
182 | |||
173 | /** INT status Bit Definition*/ | 183 | /** INT status Bit Definition*/ |
174 | #define MRVDRV_TX_DNLD_RDY 0x0001 | 184 | #define MRVDRV_TX_DNLD_RDY 0x0001 |
175 | #define MRVDRV_RX_UPLD_RDY 0x0002 | 185 | #define MRVDRV_RX_UPLD_RDY 0x0002 |
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 3915c3144fad..c92e41b4faf4 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h | |||
@@ -256,6 +256,23 @@ enum cmd_mesh_access_opts { | |||
256 | CMD_ACT_MESH_GET_AUTOSTART_ENABLED, | 256 | CMD_ACT_MESH_GET_AUTOSTART_ENABLED, |
257 | }; | 257 | }; |
258 | 258 | ||
259 | /* Define actions and types for CMD_MESH_CONFIG */ | ||
260 | enum cmd_mesh_config_actions { | ||
261 | CMD_ACT_MESH_CONFIG_STOP = 0, | ||
262 | CMD_ACT_MESH_CONFIG_START, | ||
263 | CMD_ACT_MESH_CONFIG_SET, | ||
264 | CMD_ACT_MESH_CONFIG_GET, | ||
265 | }; | ||
266 | |||
267 | enum cmd_mesh_config_types { | ||
268 | CMD_TYPE_MESH_SET_BOOTFLAG = 1, | ||
269 | CMD_TYPE_MESH_SET_BOOTTIME, | ||
270 | CMD_TYPE_MESH_SET_DEF_CHANNEL, | ||
271 | CMD_TYPE_MESH_SET_MESH_IE, | ||
272 | CMD_TYPE_MESH_GET_DEFAULTS, | ||
273 | CMD_TYPE_MESH_GET_MESH_IE, /* GET_DEFAULTS is superset of GET_MESHIE */ | ||
274 | }; | ||
275 | |||
259 | /** Card Event definition */ | 276 | /** Card Event definition */ |
260 | #define MACREG_INT_CODE_TX_PPA_FREE 0 | 277 | #define MACREG_INT_CODE_TX_PPA_FREE 0 |
261 | #define MACREG_INT_CODE_TX_DMA_DONE 1 | 278 | #define MACREG_INT_CODE_TX_DMA_DONE 1 |
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index a87febad8c29..01299c8ed27c 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c | |||
@@ -344,14 +344,15 @@ static ssize_t lbs_mesh_set(struct device *dev, | |||
344 | { | 344 | { |
345 | struct lbs_private *priv = to_net_dev(dev)->priv; | 345 | struct lbs_private *priv = to_net_dev(dev)->priv; |
346 | int enable; | 346 | int enable; |
347 | int ret; | 347 | int ret, action = CMD_ACT_MESH_CONFIG_STOP; |
348 | 348 | ||
349 | sscanf(buf, "%x", &enable); | 349 | sscanf(buf, "%x", &enable); |
350 | enable = !!enable; | 350 | enable = !!enable; |
351 | if (enable == !!priv->mesh_dev) | 351 | if (enable == !!priv->mesh_dev) |
352 | return count; | 352 | return count; |
353 | 353 | if (enable) | |
354 | ret = lbs_mesh_config(priv, enable, priv->curbssparams.channel); | 354 | action = CMD_ACT_MESH_CONFIG_START; |
355 | ret = lbs_mesh_config(priv, action, priv->curbssparams.channel); | ||
355 | if (ret) | 356 | if (ret) |
356 | return ret; | 357 | return ret; |
357 | 358 | ||
@@ -1257,9 +1258,11 @@ int lbs_start_card(struct lbs_private *priv) | |||
1257 | useful */ | 1258 | useful */ |
1258 | 1259 | ||
1259 | priv->mesh_tlv = 0x100 + 291; | 1260 | priv->mesh_tlv = 0x100 + 291; |
1260 | if (lbs_mesh_config(priv, 1, priv->curbssparams.channel)) { | 1261 | if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, |
1262 | priv->curbssparams.channel)) { | ||
1261 | priv->mesh_tlv = 0x100 + 37; | 1263 | priv->mesh_tlv = 0x100 + 37; |
1262 | if (lbs_mesh_config(priv, 1, priv->curbssparams.channel)) | 1264 | if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, |
1265 | priv->curbssparams.channel)) | ||
1263 | priv->mesh_tlv = 0; | 1266 | priv->mesh_tlv = 0; |
1264 | } | 1267 | } |
1265 | if (priv->mesh_tlv) { | 1268 | if (priv->mesh_tlv) { |
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index 4031be420862..e0c2599da92f 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h | |||
@@ -6,6 +6,8 @@ | |||
6 | 6 | ||
7 | #include <linux/if_ether.h> | 7 | #include <linux/if_ether.h> |
8 | #include <asm/byteorder.h> | 8 | #include <asm/byteorder.h> |
9 | #include <linux/wireless.h> | ||
10 | #include <net/ieee80211.h> | ||
9 | 11 | ||
10 | struct ieeetypes_cfparamset { | 12 | struct ieeetypes_cfparamset { |
11 | u8 elementid; | 13 | u8 elementid; |
@@ -252,4 +254,32 @@ struct mrvlietypes_ledbhv { | |||
252 | struct led_bhv ledbhv[1]; | 254 | struct led_bhv ledbhv[1]; |
253 | } __attribute__ ((packed)); | 255 | } __attribute__ ((packed)); |
254 | 256 | ||
257 | /* Meant to be packed as the value member of a struct ieee80211_info_element. | ||
258 | * Note that the len member of the ieee80211_info_element varies depending on | ||
259 | * the mesh_id_len */ | ||
260 | struct mrvl_meshie_val { | ||
261 | uint8_t oui[P80211_OUI_LEN]; | ||
262 | uint8_t type; | ||
263 | uint8_t subtype; | ||
264 | uint8_t version; | ||
265 | uint8_t active_protocol_id; | ||
266 | uint8_t active_metric_id; | ||
267 | uint8_t mesh_capability; | ||
268 | uint8_t mesh_id_len; | ||
269 | uint8_t mesh_id[IW_ESSID_MAX_SIZE]; | ||
270 | } __attribute__ ((packed)); | ||
271 | |||
272 | struct mrvl_meshie { | ||
273 | struct ieee80211_info_element hdr; | ||
274 | struct mrvl_meshie_val val; | ||
275 | } __attribute__ ((packed)); | ||
276 | |||
277 | struct mrvl_mesh_defaults { | ||
278 | __le32 bootflag; | ||
279 | uint8_t boottime; | ||
280 | uint8_t reserved; | ||
281 | __le16 channel; | ||
282 | struct mrvl_meshie meshie; | ||
283 | } __attribute__ ((packed)); | ||
284 | |||
255 | #endif | 285 | #endif |
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 0973d015a520..d4b19f11b785 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c | |||
@@ -1002,7 +1002,7 @@ static int lbs_mesh_set_freq(struct net_device *dev, | |||
1002 | else if (priv->mode == IW_MODE_ADHOC) | 1002 | else if (priv->mode == IW_MODE_ADHOC) |
1003 | lbs_stop_adhoc_network(priv); | 1003 | lbs_stop_adhoc_network(priv); |
1004 | } | 1004 | } |
1005 | lbs_mesh_config(priv, 1, fwrq->m); | 1005 | lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m); |
1006 | lbs_update_channel(priv); | 1006 | lbs_update_channel(priv); |
1007 | ret = 0; | 1007 | ret = 0; |
1008 | 1008 | ||
@@ -2011,7 +2011,8 @@ static int lbs_mesh_set_essid(struct net_device *dev, | |||
2011 | priv->mesh_ssid_len = dwrq->length; | 2011 | priv->mesh_ssid_len = dwrq->length; |
2012 | } | 2012 | } |
2013 | 2013 | ||
2014 | lbs_mesh_config(priv, 1, priv->curbssparams.channel); | 2014 | lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, |
2015 | priv->curbssparams.channel); | ||
2015 | out: | 2016 | out: |
2016 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); | 2017 | lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); |
2017 | return ret; | 2018 | return ret; |