aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas
diff options
context:
space:
mode:
authorBing Zhao <bzhao@marvell.com>2009-03-25 12:51:16 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-04-22 16:54:26 -0400
commit684d6b360222f31b6b9be9a63aa5c6ed5674c890 (patch)
tree65e91de4f3e3617b5ecb24ef6ec5bb4b4d697f9c /drivers/net/wireless/libertas
parent5e3af1d2d3e6c0011b4c22514d39c73dcbc6674f (diff)
libertas: support mesh for various firmware versions
CMD_MESH_CONFIG command ID and a couple of structure members in TxPD, RxPD have been changed in firmware version 10.x.y.z and newer. Signed-off-by: Kiran Divekar <dkiran@marvell.com> Signed-off-by: Bing Zhao <bzhao@marvell.com> Acked-by: Dan Williams <dcbw@redhat.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/libertas')
-rw-r--r--drivers/net/wireless/libertas/cmd.c26
-rw-r--r--drivers/net/wireless/libertas/defs.h21
-rw-r--r--drivers/net/wireless/libertas/dev.h1
-rw-r--r--drivers/net/wireless/libertas/host.h3
-rw-r--r--drivers/net/wireless/libertas/hostcmd.h28
-rw-r--r--drivers/net/wireless/libertas/main.c44
-rw-r--r--drivers/net/wireless/libertas/rx.c33
-rw-r--r--drivers/net/wireless/libertas/tx.c8
-rw-r--r--drivers/net/wireless/libertas/types.h2
9 files changed, 116 insertions, 50 deletions
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 8c3605cdc64c..c455b9abbfc0 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -119,6 +119,19 @@ int lbs_update_hw_spec(struct lbs_private *priv)
119 lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n", 119 lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
120 cmd.hwifversion, cmd.version); 120 cmd.hwifversion, cmd.version);
121 121
122 /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
123 /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
124 /* 5.110.22 have mesh command with 0xa3 command id */
125 /* 10.0.0.p0 FW brings in mesh config command with different id */
126 /* Check FW version MSB and initialize mesh_fw_ver */
127 if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5)
128 priv->mesh_fw_ver = MESH_FW_OLD;
129 else if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
130 (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK))
131 priv->mesh_fw_ver = MESH_FW_NEW;
132 else
133 priv->mesh_fw_ver = MESH_NONE;
134
122 /* Clamp region code to 8-bit since FW spec indicates that it should 135 /* Clamp region code to 8-bit since FW spec indicates that it should
123 * only ever be 8-bit, even though the field size is 16-bit. Some firmware 136 * only ever be 8-bit, even though the field size is 16-bit. Some firmware
124 * returns non-zero high 8 bits here. 137 * returns non-zero high 8 bits here.
@@ -1036,17 +1049,26 @@ static int __lbs_mesh_config_send(struct lbs_private *priv,
1036 uint16_t action, uint16_t type) 1049 uint16_t action, uint16_t type)
1037{ 1050{
1038 int ret; 1051 int ret;
1052 u16 command = CMD_MESH_CONFIG_OLD;
1039 1053
1040 lbs_deb_enter(LBS_DEB_CMD); 1054 lbs_deb_enter(LBS_DEB_CMD);
1041 1055
1042 cmd->hdr.command = cpu_to_le16(CMD_MESH_CONFIG); 1056 /*
1057 * Command id is 0xac for v10 FW along with mesh interface
1058 * id in bits 14-13-12.
1059 */
1060 if (priv->mesh_fw_ver == MESH_FW_NEW)
1061 command = CMD_MESH_CONFIG |
1062 (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
1063
1064 cmd->hdr.command = cpu_to_le16(command);
1043 cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config)); 1065 cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
1044 cmd->hdr.result = 0; 1066 cmd->hdr.result = 0;
1045 1067
1046 cmd->type = cpu_to_le16(type); 1068 cmd->type = cpu_to_le16(type);
1047 cmd->action = cpu_to_le16(action); 1069 cmd->action = cpu_to_le16(action);
1048 1070
1049 ret = lbs_cmd_with_response(priv, CMD_MESH_CONFIG, cmd); 1071 ret = lbs_cmd_with_response(priv, command, cmd);
1050 1072
1051 lbs_deb_leave(LBS_DEB_CMD); 1073 lbs_deb_leave(LBS_DEB_CMD);
1052 return ret; 1074 return ret;
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index e8dfde39abfc..48da157d6cda 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -227,6 +227,20 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
227#define TxPD_CONTROL_WDS_FRAME (1<<17) 227#define TxPD_CONTROL_WDS_FRAME (1<<17)
228#define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME 228#define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME
229 229
230/** Mesh interface ID */
231#define MESH_IFACE_ID 0x0001
232/** Mesh id should be in bits 14-13-12 */
233#define MESH_IFACE_BIT_OFFSET 0x000c
234/** Mesh enable bit in FW capability */
235#define MESH_CAPINFO_ENABLE_MASK (1<<16)
236
237/** FW definition from Marvell v5 */
238#define MRVL_FW_V5 (0x05)
239/** FW definition from Marvell v10 */
240#define MRVL_FW_V10 (0x0a)
241/** FW major revision definition */
242#define MRVL_FW_MAJOR_REV(x) ((x)>>24)
243
230/** RxPD status */ 244/** RxPD status */
231 245
232#define MRVDRV_RXPD_STATUS_OK 0x0001 246#define MRVDRV_RXPD_STATUS_OK 0x0001
@@ -380,6 +394,13 @@ enum KEY_INFO_WPA {
380 KEY_INFO_WPA_ENABLED = 0x04 394 KEY_INFO_WPA_ENABLED = 0x04
381}; 395};
382 396
397/** mesh_fw_ver */
398enum _mesh_fw_ver {
399 MESH_NONE = 0, /* MESH is not supported */
400 MESH_FW_OLD, /* MESH is supported in FW V5 */
401 MESH_FW_NEW, /* MESH is supported in FW V10 and newer */
402};
403
383/* Default values for fwt commands. */ 404/* Default values for fwt commands. */
384#define FWT_DEFAULT_METRIC 0 405#define FWT_DEFAULT_METRIC 0
385#define FWT_DEFAULT_DIR 1 406#define FWT_DEFAULT_DIR 1
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 27e81fd97c94..cbaafa653b6a 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -101,6 +101,7 @@ struct lbs_mesh_stats {
101/** Private structure for the MV device */ 101/** Private structure for the MV device */
102struct lbs_private { 102struct lbs_private {
103 int mesh_open; 103 int mesh_open;
104 int mesh_fw_ver;
104 int infra_open; 105 int infra_open;
105 int mesh_autostart_enabled; 106 int mesh_autostart_enabled;
106 107
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index d4457ef808a6..8ff8ac9d817e 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -83,7 +83,8 @@
83#define CMD_FWT_ACCESS 0x0095 83#define CMD_FWT_ACCESS 0x0095
84#define CMD_802_11_MONITOR_MODE 0x0098 84#define CMD_802_11_MONITOR_MODE 0x0098
85#define CMD_MESH_ACCESS 0x009b 85#define CMD_MESH_ACCESS 0x009b
86#define CMD_MESH_CONFIG 0x00a3 86#define CMD_MESH_CONFIG_OLD 0x00a3
87#define CMD_MESH_CONFIG 0x00ac
87#define CMD_SET_BOOT2_VER 0x00a5 88#define CMD_SET_BOOT2_VER 0x00a5
88#define CMD_802_11_BEACON_CTRL 0x00b0 89#define CMD_802_11_BEACON_CTRL 0x00b0
89 90
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
index a899aeb676bb..391c54ab2b09 100644
--- a/drivers/net/wireless/libertas/hostcmd.h
+++ b/drivers/net/wireless/libertas/hostcmd.h
@@ -13,8 +13,19 @@
13 13
14/* TxPD descriptor */ 14/* TxPD descriptor */
15struct txpd { 15struct txpd {
16 /* Current Tx packet status */ 16 /* union to cope up with later FW revisions */
17 __le32 tx_status; 17 union {
18 /* Current Tx packet status */
19 __le32 tx_status;
20 struct {
21 /* BSS type: client, AP, etc. */
22 u8 bss_type;
23 /* BSS number */
24 u8 bss_num;
25 /* Reserved */
26 __le16 reserved;
27 } bss;
28 } u;
18 /* Tx control */ 29 /* Tx control */
19 __le32 tx_control; 30 __le32 tx_control;
20 __le32 tx_packet_location; 31 __le32 tx_packet_location;
@@ -36,8 +47,17 @@ struct txpd {
36 47
37/* RxPD Descriptor */ 48/* RxPD Descriptor */
38struct rxpd { 49struct rxpd {
39 /* Current Rx packet status */ 50 /* union to cope up with later FW revisions */
40 __le16 status; 51 union {
52 /* Current Rx packet status */
53 __le16 status;
54 struct {
55 /* BSS type: client, AP, etc. */
56 u8 bss_type;
57 /* BSS number */
58 u8 bss_num;
59 } bss;
60 } u;
41 61
42 /* SNR */ 62 /* SNR */
43 u8 snr; 63 u8 snr;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 8ae935ac32f1..89575e448015 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -1307,8 +1307,10 @@ int lbs_start_card(struct lbs_private *priv)
1307 1307
1308 lbs_update_channel(priv); 1308 lbs_update_channel(priv);
1309 1309
1310 /* 5.0.16p0 is known to NOT support any mesh */ 1310 /* Check mesh FW version and appropriately send the mesh start
1311 if (priv->fwrelease > 0x05001000) { 1311 * command
1312 */
1313 if (priv->mesh_fw_ver == MESH_FW_OLD) {
1312 /* Enable mesh, if supported, and work out which TLV it uses. 1314 /* Enable mesh, if supported, and work out which TLV it uses.
1313 0x100 + 291 is an unofficial value used in 5.110.20.pXX 1315 0x100 + 291 is an unofficial value used in 5.110.20.pXX
1314 0x100 + 37 is the official value used in 5.110.21.pXX 1316 0x100 + 37 is the official value used in 5.110.21.pXX
@@ -1322,27 +1324,35 @@ int lbs_start_card(struct lbs_private *priv)
1322 It's just that 5.110.20.pXX will not have done anything 1324 It's just that 5.110.20.pXX will not have done anything
1323 useful */ 1325 useful */
1324 1326
1325 priv->mesh_tlv = 0x100 + 291; 1327 priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
1326 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1328 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
1327 priv->curbssparams.channel)) { 1329 priv->curbssparams.channel)) {
1328 priv->mesh_tlv = 0x100 + 37; 1330 priv->mesh_tlv = TLV_TYPE_MESH_ID;
1329 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1331 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
1330 priv->curbssparams.channel)) 1332 priv->curbssparams.channel))
1331 priv->mesh_tlv = 0; 1333 priv->mesh_tlv = 0;
1332 } 1334 }
1333 if (priv->mesh_tlv) { 1335 } else if (priv->mesh_fw_ver == MESH_FW_NEW) {
1334 lbs_add_mesh(priv); 1336 /* 10.0.0.pXX new firmwares should succeed with TLV
1335 1337 * 0x100+37; Do not invoke command with old TLV.
1336 if (device_create_file(&dev->dev, &dev_attr_lbs_mesh)) 1338 */
1337 lbs_pr_err("cannot register lbs_mesh attribute\n"); 1339 priv->mesh_tlv = TLV_TYPE_MESH_ID;
1338 1340 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
1339 /* While rtap isn't related to mesh, only mesh-enabled 1341 priv->curbssparams.channel))
1340 * firmware implements the rtap functionality via 1342 priv->mesh_tlv = 0;
1341 * CMD_802_11_MONITOR_MODE. 1343 }
1342 */ 1344 if (priv->mesh_tlv) {
1343 if (device_create_file(&dev->dev, &dev_attr_lbs_rtap)) 1345 lbs_add_mesh(priv);
1344 lbs_pr_err("cannot register lbs_rtap attribute\n"); 1346
1345 } 1347 if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
1348 lbs_pr_err("cannot register lbs_mesh attribute\n");
1349
1350 /* While rtap isn't related to mesh, only mesh-enabled
1351 * firmware implements the rtap functionality via
1352 * CMD_802_11_MONITOR_MODE.
1353 */
1354 if (device_create_file(&dev->dev, &dev_attr_lbs_rtap))
1355 lbs_pr_err("cannot register lbs_rtap attribute\n");
1346 } 1356 }
1347 1357
1348 lbs_debugfs_init_one(priv, dev); 1358 lbs_debugfs_init_one(priv, dev);
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
index 8e669775cb5d..820c22d9220f 100644
--- a/drivers/net/wireless/libertas/rx.c
+++ b/drivers/net/wireless/libertas/rx.c
@@ -160,8 +160,15 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
160 160
161 p_rx_pkt = (struct rxpackethdr *) skb->data; 161 p_rx_pkt = (struct rxpackethdr *) skb->data;
162 p_rx_pd = &p_rx_pkt->rx_pd; 162 p_rx_pd = &p_rx_pkt->rx_pd;
163 if (priv->mesh_dev && (p_rx_pd->rx_control & RxPD_MESH_FRAME)) 163 if (priv->mesh_dev) {
164 dev = priv->mesh_dev; 164 if (priv->mesh_fw_ver == MESH_FW_OLD) {
165 if (p_rx_pd->rx_control & RxPD_MESH_FRAME)
166 dev = priv->mesh_dev;
167 } else if (priv->mesh_fw_ver == MESH_FW_NEW) {
168 if (p_rx_pd->u.bss.bss_num == MESH_IFACE_ID)
169 dev = priv->mesh_dev;
170 }
171 }
165 172
166 lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, 173 lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data,
167 min_t(unsigned int, skb->len, 100)); 174 min_t(unsigned int, skb->len, 100));
@@ -174,18 +181,6 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
174 goto done; 181 goto done;
175 } 182 }
176 183
177 /*
178 * Check rxpd status and update 802.3 stat,
179 */
180 if (!(p_rx_pd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) {
181 lbs_deb_rx("rx err: frame received with bad status\n");
182 lbs_pr_alert("rxpd not ok\n");
183 dev->stats.rx_errors++;
184 ret = 0;
185 dev_kfree_skb(skb);
186 goto done;
187 }
188
189 lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n", 184 lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n",
190 skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd)); 185 skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
191 186
@@ -334,14 +329,6 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
334 goto done; 329 goto done;
335 } 330 }
336 331
337 /*
338 * Check rxpd status and update 802.3 stat,
339 */
340 if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) {
341 //lbs_deb_rx("rx err: frame received with bad status\n");
342 dev->stats.rx_errors++;
343 }
344
345 lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n", 332 lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n",
346 skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd)); 333 skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
347 334
@@ -353,8 +340,6 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
353 radiotap_hdr.hdr.it_pad = 0; 340 radiotap_hdr.hdr.it_pad = 0;
354 radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr)); 341 radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr));
355 radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT); 342 radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT);
356 if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK)))
357 radiotap_hdr.flags |= IEEE80211_RADIOTAP_F_BADFCS;
358 radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate); 343 radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate);
359 /* XXX must check no carryout */ 344 /* XXX must check no carryout */
360 radiotap_hdr.antsignal = prxpd->snr + prxpd->nf; 345 radiotap_hdr.antsignal = prxpd->snr + prxpd->nf;
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
index f10aa39a6b68..160cfd8311c0 100644
--- a/drivers/net/wireless/libertas/tx.c
+++ b/drivers/net/wireless/libertas/tx.c
@@ -132,8 +132,12 @@ int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
132 txpd->tx_packet_length = cpu_to_le16(pkt_len); 132 txpd->tx_packet_length = cpu_to_le16(pkt_len);
133 txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd)); 133 txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));
134 134
135 if (dev == priv->mesh_dev) 135 if (dev == priv->mesh_dev) {
136 txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME); 136 if (priv->mesh_fw_ver == MESH_FW_OLD)
137 txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
138 else if (priv->mesh_fw_ver == MESH_FW_NEW)
139 txpd->u.bss.bss_num = MESH_IFACE_ID;
140 }
137 141
138 lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) &txpd, sizeof(struct txpd)); 142 lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) &txpd, sizeof(struct txpd));
139 143
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
index fb7a2d1a2525..de03b9c9c204 100644
--- a/drivers/net/wireless/libertas/types.h
+++ b/drivers/net/wireless/libertas/types.h
@@ -94,6 +94,8 @@ struct ieeetypes_assocrsp {
94#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19) 94#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19)
95#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22) 95#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22)
96#define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23) 96#define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23)
97#define TLV_TYPE_MESH_ID (PROPRIETARY_TLV_BASE_ID + 37)
98#define TLV_TYPE_OLD_MESH_ID (PROPRIETARY_TLV_BASE_ID + 291)
97 99
98/** TLV related data structures*/ 100/** TLV related data structures*/
99struct mrvlietypesheader { 101struct mrvlietypesheader {