Implemented rate adaptation support via 'iwconfig rate' API. It is now possible to specify a bit-rate value and append 'auto'. That will configure rate adaptation to use all bit-rates equal or lower than than selected value.
Made lbs_cmd_802_11_rate_adapt_rateset a direct command. This patch is made against olpc/stable so testing can start right away. If feedback is good, I'll adapt to libertas-2.6 and resubmit to libertas-dev. Signed-off-by: Javier Cardona <[EMAIL PROTECTED]> --- drivers/net/wireless/libertas/cmd.c | 69 ++++++++++++++++++++++-------- drivers/net/wireless/libertas/cmd.h | 2 + drivers/net/wireless/libertas/cmdresp.c | 20 --------- drivers/net/wireless/libertas/dev.h | 5 +- drivers/net/wireless/libertas/hostcmd.h | 2 +- drivers/net/wireless/libertas/join.c | 2 +- drivers/net/wireless/libertas/main.c | 2 +- drivers/net/wireless/libertas/rx.c | 4 +- drivers/net/wireless/libertas/wext.c | 27 ++++++++---- 9 files changed, 77 insertions(+), 56 deletions(-) diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 0ae9851..02f62a0 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -706,26 +706,62 @@ static int lbs_cmd_802_11_monitor_mode(struct lbs_private *priv, return 0; } -static int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv, - struct cmd_ds_command *cmd, - u16 cmd_action) +static __le16 lbs_rate_to_fw_bitmap(int rate, int lower_rates_ok) { - struct cmd_ds_802_11_rate_adapt_rateset - *rateadapt = &cmd->params.rateset; +/* Bit Rate +* 15:13 Reserved +* 12 54 Mbps +* 11 48 Mbps +* 10 36 Mbps +* 9 24 Mbps +* 8 18 Mbps +* 7 12 Mbps +* 6 9 Mbps +* 5 6 Mbps +* 4 Reserved +* 3 11 Mbps +* 2 5.5 Mbps +* 1 2 Mbps +* 0 1 Mbps +**/ + + uint16_t ratemask; + int i = lbs_data_rate_to_fw_index(rate); + if (lower_rates_ok) + ratemask = (0x1fef >> (12 - i)); + else + ratemask = (1 << i); + return cpu_to_le16(ratemask); +} + +int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv, + uint16_t cmd_action) +{ + struct cmd_ds_802_11_rate_adapt_rateset cmd; + int ret; lbs_deb_enter(LBS_DEB_CMD); - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset) - + S_DS_GEN); - cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET); - rateadapt->action = cpu_to_le16(cmd_action); - rateadapt->enablehwauto = cpu_to_le16(priv->enablehwauto); - rateadapt->bitmap = cpu_to_le16(priv->ratebitmap); + if (!priv->cur_rate && !priv->enablehwauto) + return -EINVAL; - lbs_deb_leave(LBS_DEB_CMD); - return 0; + cmd.hdr.size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset)); + + cmd.action = cpu_to_le16(cmd_action); + cmd.enablehwauto = cpu_to_le16(priv->enablehwauto); + cmd.bitmap = lbs_rate_to_fw_bitmap(priv->cur_rate, priv->enablehwauto); + ret = lbs_cmd_with_response(priv, CMD_802_11_RATE_ADAPT_RATESET, + &cmd); + if (!ret && cmd_action == CMD_ACT_GET) { + priv->ratebitmap = le16_to_cpu(cmd.bitmap); + priv->enablehwauto = le16_to_cpu(cmd.enablehwauto); + } + + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + return ret; } +EXPORT_SYMBOL_GPL(lbs_cmd_802_11_rate_adapt_rateset); /** * @brief Get the current data rate @@ -1471,11 +1507,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = lbs_cmd_802_11_radio_control(priv, cmdptr, cmd_action); break; - case CMD_802_11_RATE_ADAPT_RATESET: - ret = lbs_cmd_802_11_rate_adapt_rateset(priv, - cmdptr, cmd_action); - break; - case CMD_MAC_MULTICAST_ADR: ret = lbs_cmd_mac_multicast_adr(priv, cmdptr, cmd_action); break; diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index e334f0e..b4100b7 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -46,5 +46,7 @@ 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); int lbs_suspend(struct lbs_private *priv); int lbs_resume(struct lbs_private *priv); +int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv, + uint16_t cmd_action); #endif /* _LBS_CMD_H */ diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 0cd9662..d515ceb 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -310,22 +310,6 @@ static int lbs_ret_802_11_rf_tx_power(struct lbs_private *priv, return 0; } -static int lbs_ret_802_11_rate_adapt_rateset(struct lbs_private *priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_rate_adapt_rateset *rates = &resp->params.rateset; - - lbs_deb_enter(LBS_DEB_CMD); - - if (rates->action == CMD_ACT_GET) { - priv->enablehwauto = le16_to_cpu(rates->enablehwauto); - priv->ratebitmap = le16_to_cpu(rates->bitmap); - } - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - static int lbs_ret_802_11_rssi(struct lbs_private *priv, struct cmd_ds_command *resp) { @@ -524,10 +508,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, ret = lbs_ret_802_11_enable_rsn(priv, resp); break; - case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET): - ret = lbs_ret_802_11_rate_adapt_rateset(priv, resp); - break; - case CMD_RET(CMD_802_11_RSSI): ret = lbs_ret_802_11_rssi(priv, resp); break; diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 1c6ec4d..c339b71 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -236,8 +236,8 @@ struct lbs_private { /** 802.11 statistics */ // struct cmd_DS_802_11_GET_STAT wlan802_11Stat; - u16 enablehwauto; - u16 ratebitmap; + uint16_t enablehwauto; + uint16_t ratebitmap; u32 fragthsd; u32 rtsthsd; @@ -298,7 +298,6 @@ struct lbs_private { /** data rate stuff */ u8 cur_rate; - u8 auto_rate; /** sleep_params */ struct sleep_params sp; diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index b38502f..ac20b39 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -483,6 +483,7 @@ struct cmd_ds_802_11_data_rate { }; struct cmd_ds_802_11_rate_adapt_rateset { + struct cmd_header hdr; __le16 action; __le16 enablehwauto; __le16 bitmap; @@ -694,7 +695,6 @@ struct cmd_ds_command { struct cmd_ds_802_11_rf_tx_power txp; struct cmd_ds_802_11_rf_antenna rant; struct cmd_ds_802_11_monitor_mode monitor; - struct cmd_ds_802_11_rate_adapt_rateset rateset; struct cmd_ds_mac_multicast_adr madr; struct cmd_ds_802_11_ad_hoc_join adj; struct cmd_ds_802_11_radio_control radio; diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index 2d45080..936c464 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -59,7 +59,7 @@ static int get_common_rates(struct lbs_private *priv, lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size); lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate); - if (!priv->auto_rate) { + if (!priv->enablehwauto) { for (i = 0; i < tmp_size; i++) { if (tmp[i] == priv->cur_rate) goto done; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index e012d08..0b35b38 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1019,7 +1019,7 @@ static int lbs_init_adapter(struct lbs_private *priv) priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; priv->currentpacketfilter = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; priv->radioon = RADIO_ON; - priv->auto_rate = 1; + priv->enablehwauto = 1; priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; priv->psmode = LBS802_11POWERMODECAM; priv->psstate = PS_STATE_FULL_POWER; diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 6332fd4..04aa0e7 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -237,7 +237,7 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) /* Take the data rate from the rxpd structure * only if the rate is auto */ - if (priv->auto_rate) + if (priv->enablehwauto) priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate); lbs_compute_rssi(priv, p_rx_pd); @@ -380,7 +380,7 @@ static int process_rxed_802_11_packet(struct lbs_private *priv, /* Take the data rate from the rxpd structure * only if the rate is auto */ - if (priv->auto_rate) + if (priv->enablehwauto) priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate); lbs_compute_rssi(priv, prxpd); diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 271db96..be513de 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -1026,29 +1026,38 @@ static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); lbs_deb_wext("vwrq->value %d\n", vwrq->value); + lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed); + + if (vwrq->fixed && vwrq->value == -1) + goto out; /* Auto rate? */ - if (vwrq->value == -1) { - priv->auto_rate = 1; + priv->enablehwauto = !vwrq->fixed; + + if (vwrq->value == -1) priv->cur_rate = 0; - } else { + else { if (vwrq->value % 100000) goto out; + new_rate = vwrq->value / 500000; + priv->cur_rate = new_rate; + /* the rest is only needed for lbs_set_data_rate() */ memset(rates, 0, sizeof(rates)); copy_active_data_rates(priv, rates); - new_rate = vwrq->value / 500000; if (!memchr(rates, new_rate, sizeof(rates))) { lbs_pr_alert("fixed data rate 0x%X out of range\n", new_rate); goto out; } - - priv->cur_rate = new_rate; - priv->auto_rate = 0; } - ret = lbs_set_data_rate(priv, new_rate); + /* Try the newer command first (Firmware Spec 5.1 and above) */ + ret = lbs_cmd_802_11_rate_adapt_rateset(priv, CMD_ACT_SET); + + /* Fallback to older version */ + if (ret) + ret = lbs_set_data_rate(priv, new_rate); out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); @@ -1065,7 +1074,7 @@ static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info, if (priv->connect_status == LBS_CONNECTED) { vwrq->value = priv->cur_rate * 500000; - if (priv->auto_rate) + if (priv->enablehwauto) vwrq->fixed = 0; else vwrq->fixed = 1; -- 1.5.2.4 _______________________________________________ Devel mailing list Devel@lists.laptop.org http://lists.laptop.org/listinfo/devel