Commit edaea5ce authored by Javier Cardona's avatar Javier Cardona Committed by John W. Linville

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: default avatarJavier Cardona <javier@cozybit.com>
Signed-off-by: default avatarDavid Woodhouse <dwmw2@infradead.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 75bf45a7
......@@ -603,7 +603,8 @@ static int assoc_helper_channel(struct lbs_private *priv,
/* Change mesh channel first; 21.p21 firmware won't let
you change channel otherwise (even though it'll return
an error to this */
lbs_mesh_config(priv, 0, assoc_req->channel);
lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
assoc_req->channel);
}
lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
......@@ -642,7 +643,8 @@ static int assoc_helper_channel(struct lbs_private *priv,
restore_mesh:
if (priv->mesh_dev)
lbs_mesh_config(priv, 1, priv->curbssparams.channel);
lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
priv->curbssparams.channel);
done:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
......
......@@ -4,6 +4,7 @@
*/
#include <net/iw_handler.h>
#include <net/ieee80211.h>
#include <linux/kfifo.h>
#include "host.h"
#include "hostcmd.h"
......@@ -998,24 +999,69 @@ int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
return ret;
}
int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan)
int lbs_mesh_config_send(struct lbs_private *priv,
struct cmd_ds_mesh_config *cmd,
uint16_t action, uint16_t type)
{
int ret;
lbs_deb_enter(LBS_DEB_CMD);
cmd->hdr.command = cpu_to_le16(CMD_MESH_CONFIG);
cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
cmd->hdr.result = 0;
cmd->type = cpu_to_le16(type);
cmd->action = cpu_to_le16(action);
ret = lbs_cmd_with_response(priv, CMD_MESH_CONFIG, cmd);
lbs_deb_leave(LBS_DEB_CMD);
return ret;
}
/* This function is the CMD_MESH_CONFIG legacy function. It only handles the
* START and STOP actions. The extended actions supported by CMD_MESH_CONFIG
* are all handled by preparing a struct cmd_ds_mesh_config and passing it to
* lbs_mesh_config_send.
*/
int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
{
struct cmd_ds_mesh_config cmd;
struct mrvl_meshie *ie;
memset(&cmd, 0, sizeof(cmd));
cmd.action = cpu_to_le16(enable);
cmd.channel = cpu_to_le16(chan);
cmd.type = cpu_to_le16(priv->mesh_tlv);
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
if (enable) {
cmd.length = cpu_to_le16(priv->mesh_ssid_len);
memcpy(cmd.data, priv->mesh_ssid, priv->mesh_ssid_len);
ie = (struct mrvl_meshie *)cmd.data;
switch (action) {
case CMD_ACT_MESH_CONFIG_START:
ie->hdr.id = MFIE_TYPE_GENERIC;
ie->val.oui[0] = 0x00;
ie->val.oui[1] = 0x50;
ie->val.oui[2] = 0x43;
ie->val.type = MARVELL_MESH_IE_TYPE;
ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
ie->val.version = MARVELL_MESH_IE_VERSION;
ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
ie->val.mesh_id_len = priv->mesh_ssid_len;
memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
ie->hdr.len = sizeof(struct mrvl_meshie_val) -
IW_ESSID_MAX_SIZE + priv->mesh_ssid_len;
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
break;
case CMD_ACT_MESH_CONFIG_STOP:
break;
default:
return -1;
}
lbs_deb_cmd("mesh config enable %d TLV %x channel %d SSID %s\n",
enable, priv->mesh_tlv, chan,
lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
action, priv->mesh_tlv, chan,
escape_essid(priv->mesh_ssid, priv->mesh_ssid_len));
return lbs_cmd_with_response(priv, CMD_MESH_CONFIG, &cmd);
return lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
}
static int lbs_cmd_bcn_ctrl(struct lbs_private * priv,
......
......@@ -39,6 +39,9 @@ int lbs_set_data_rate(struct lbs_private *priv, u8 rate);
int lbs_get_channel(struct lbs_private *priv);
int lbs_set_channel(struct lbs_private *priv, u8 channel);
int lbs_mesh_config_send(struct lbs_private *priv,
struct cmd_ds_mesh_config *cmd,
uint16_t action, uint16_t type);
int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria);
......
......@@ -170,6 +170,16 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
#define MARVELL_MESH_IE_LENGTH 9
/* Values used to populate the struct mrvl_mesh_ie. The only time you need this
* is when enabling the mesh using CMD_MESH_CONFIG.
*/
#define MARVELL_MESH_IE_TYPE 4
#define MARVELL_MESH_IE_SUBTYPE 0
#define MARVELL_MESH_IE_VERSION 0
#define MARVELL_MESH_PROTO_ID_HWMP 0
#define MARVELL_MESH_METRIC_ID 0
#define MARVELL_MESH_CAPABILITY 0
/** INT status Bit Definition*/
#define MRVDRV_TX_DNLD_RDY 0x0001
#define MRVDRV_RX_UPLD_RDY 0x0002
......
......@@ -256,6 +256,23 @@ enum cmd_mesh_access_opts {
CMD_ACT_MESH_GET_AUTOSTART_ENABLED,
};
/* Define actions and types for CMD_MESH_CONFIG */
enum cmd_mesh_config_actions {
CMD_ACT_MESH_CONFIG_STOP = 0,
CMD_ACT_MESH_CONFIG_START,
CMD_ACT_MESH_CONFIG_SET,
CMD_ACT_MESH_CONFIG_GET,
};
enum cmd_mesh_config_types {
CMD_TYPE_MESH_SET_BOOTFLAG = 1,
CMD_TYPE_MESH_SET_BOOTTIME,
CMD_TYPE_MESH_SET_DEF_CHANNEL,
CMD_TYPE_MESH_SET_MESH_IE,
CMD_TYPE_MESH_GET_DEFAULTS,
CMD_TYPE_MESH_GET_MESH_IE, /* GET_DEFAULTS is superset of GET_MESHIE */
};
/** Card Event definition */
#define MACREG_INT_CODE_TX_PPA_FREE 0
#define MACREG_INT_CODE_TX_DMA_DONE 1
......
......@@ -344,14 +344,15 @@ static ssize_t lbs_mesh_set(struct device *dev,
{
struct lbs_private *priv = to_net_dev(dev)->priv;
int enable;
int ret;
int ret, action = CMD_ACT_MESH_CONFIG_STOP;
sscanf(buf, "%x", &enable);
enable = !!enable;
if (enable == !!priv->mesh_dev)
return count;
ret = lbs_mesh_config(priv, enable, priv->curbssparams.channel);
if (enable)
action = CMD_ACT_MESH_CONFIG_START;
ret = lbs_mesh_config(priv, action, priv->curbssparams.channel);
if (ret)
return ret;
......@@ -1257,9 +1258,11 @@ int lbs_start_card(struct lbs_private *priv)
useful */
priv->mesh_tlv = 0x100 + 291;
if (lbs_mesh_config(priv, 1, priv->curbssparams.channel)) {
if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
priv->curbssparams.channel)) {
priv->mesh_tlv = 0x100 + 37;
if (lbs_mesh_config(priv, 1, priv->curbssparams.channel))
if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
priv->curbssparams.channel))
priv->mesh_tlv = 0;
}
if (priv->mesh_tlv) {
......
......@@ -6,6 +6,8 @@
#include <linux/if_ether.h>
#include <asm/byteorder.h>
#include <linux/wireless.h>
#include <net/ieee80211.h>
struct ieeetypes_cfparamset {
u8 elementid;
......@@ -252,4 +254,32 @@ struct mrvlietypes_ledbhv {
struct led_bhv ledbhv[1];
} __attribute__ ((packed));
/* Meant to be packed as the value member of a struct ieee80211_info_element.
* Note that the len member of the ieee80211_info_element varies depending on
* the mesh_id_len */
struct mrvl_meshie_val {
uint8_t oui[P80211_OUI_LEN];
uint8_t type;
uint8_t subtype;
uint8_t version;
uint8_t active_protocol_id;
uint8_t active_metric_id;
uint8_t mesh_capability;
uint8_t mesh_id_len;
uint8_t mesh_id[IW_ESSID_MAX_SIZE];
} __attribute__ ((packed));
struct mrvl_meshie {
struct ieee80211_info_element hdr;
struct mrvl_meshie_val val;
} __attribute__ ((packed));
struct mrvl_mesh_defaults {
__le32 bootflag;
uint8_t boottime;
uint8_t reserved;
__le16 channel;
struct mrvl_meshie meshie;
} __attribute__ ((packed));
#endif
......@@ -1002,7 +1002,7 @@ static int lbs_mesh_set_freq(struct net_device *dev,
else if (priv->mode == IW_MODE_ADHOC)
lbs_stop_adhoc_network(priv);
}
lbs_mesh_config(priv, 1, fwrq->m);
lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m);
lbs_update_channel(priv);
ret = 0;
......@@ -2011,7 +2011,8 @@ static int lbs_mesh_set_essid(struct net_device *dev,
priv->mesh_ssid_len = dwrq->length;
}
lbs_mesh_config(priv, 1, priv->curbssparams.channel);
lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
priv->curbssparams.channel);
out:
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment