diff options
Diffstat (limited to 'drivers/net/wireless/libertas')
-rw-r--r-- | drivers/net/wireless/libertas/cmd.c | 64 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/cmd.h | 6 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/defs.h | 9 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/host.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/hostcmd.h | 24 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/main.c | 20 | ||||
-rw-r--r-- | drivers/net/wireless/libertas/wext.c | 31 |
7 files changed, 147 insertions, 8 deletions
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 802547e79671..5fef05f3cd00 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1971,6 +1971,70 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv) } +/** + * @brief Configures the transmission power control functionality. + * + * @param priv A pointer to struct lbs_private structure + * @param enable Transmission power control enable + * @param p0 Power level when link quality is good (dBm). + * @param p1 Power level when link quality is fair (dBm). + * @param p2 Power level when link quality is poor (dBm). + * @param usesnr Use Signal to Noise Ratio in TPC + * + * @return 0 on success + */ +int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, + int8_t p2, int usesnr) +{ + struct cmd_ds_802_11_tpc_cfg cmd; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_SET); + cmd.enable = !!enable; + cmd.usesnr = !!enable; + cmd.P0 = p0; + cmd.P1 = p1; + cmd.P2 = p2; + + ret = lbs_cmd_with_response(priv, CMD_802_11_TPC_CFG, &cmd); + + return ret; +} + +/** + * @brief Configures the power adaptation settings. + * + * @param priv A pointer to struct lbs_private structure + * @param enable Power adaptation enable + * @param p0 Power level for 1, 2, 5.5 and 11 Mbps (dBm). + * @param p1 Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm). + * @param p2 Power level for 48 and 54 Mbps (dBm). + * + * @return 0 on Success + */ + +int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, + int8_t p1, int8_t p2) +{ + struct cmd_ds_802_11_pa_cfg cmd; + int ret; + + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_SET); + cmd.enable = !!enable; + cmd.P0 = p0; + cmd.P1 = p1; + cmd.P2 = p2; + + ret = lbs_cmd_with_response(priv, CMD_802_11_PA_CFG , &cmd); + + return ret; +} + + static struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, uint16_t command, struct cmd_header *in_cmd, int in_cmd_size, int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index 11ac996e895e..336a181d857a 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -26,6 +26,12 @@ int __lbs_cmd(struct lbs_private *priv, uint16_t command, int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), unsigned long callback_arg); +int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, + int8_t p1, int8_t p2); + +int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, + int8_t p2, int usesnr); + int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra, struct cmd_header *resp); diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 4b2428ac2223..c89d7a1041a8 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -189,6 +189,15 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define MRVDRV_CMD_UPLD_RDY 0x0008 #define MRVDRV_CARDEVENT 0x0010 + +/* Automatic TX control default levels */ +#define POW_ADAPT_DEFAULT_P0 13 +#define POW_ADAPT_DEFAULT_P1 15 +#define POW_ADAPT_DEFAULT_P2 18 +#define TPC_DEFAULT_P0 5 +#define TPC_DEFAULT_P1 10 +#define TPC_DEFAULT_P2 13 + /** TxPD status */ /* Station firmware use TxPD status field to report final Tx transmit diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index da618fc997ce..a916bb9bd5da 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -83,6 +83,7 @@ #define CMD_802_11_INACTIVITY_TIMEOUT 0x0067 #define CMD_802_11_SLEEP_PERIOD 0x0068 #define CMD_802_11_TPC_CFG 0x0072 +#define CMD_802_11_PA_CFG 0x0073 #define CMD_802_11_FW_WAKE_METHOD 0x0074 #define CMD_802_11_SUBSCRIBE_EVENT 0x0075 #define CMD_802_11_RATE_ADAPT_RATESET 0x0076 diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index d27c276b2191..630b79967560 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -607,14 +607,28 @@ struct cmd_ds_802_11_eeprom_access { } __attribute__ ((packed)); struct cmd_ds_802_11_tpc_cfg { + struct cmd_header hdr; + __le16 action; - u8 enable; - s8 P0; - s8 P1; - s8 P2; - u8 usesnr; + uint8_t enable; + int8_t P0; + int8_t P1; + int8_t P2; + uint8_t usesnr; } __attribute__ ((packed)); + +struct cmd_ds_802_11_pa_cfg { + struct cmd_header hdr; + + __le16 action; + uint8_t enable; + int8_t P0; + int8_t P1; + int8_t P2; +} __attribute__ ((packed)); + + struct cmd_ds_802_11_led_ctrl { __le16 action; __le16 numled; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 2436634b6b7e..73dc8c72402a 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1205,7 +1205,13 @@ void lbs_remove_card(struct lbs_private *priv) cancel_delayed_work_sync(&priv->scan_work); cancel_delayed_work_sync(&priv->assoc_work); cancel_work_sync(&priv->mcast_work); + + /* worker thread destruction blocks on the in-flight command which + * should have been cleared already in lbs_stop_card(). + */ + lbs_deb_main("destroying worker thread\n"); destroy_workqueue(priv->work_thread); + lbs_deb_main("done destroying worker thread\n"); if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { priv->psmode = LBS802_11POWERMODECAM; @@ -1323,14 +1329,26 @@ void lbs_stop_card(struct lbs_private *priv) device_remove_file(&dev->dev, &dev_attr_lbs_rtap); } - /* Flush pending command nodes */ + /* Delete the timeout of the currently processing command */ del_timer_sync(&priv->command_timer); + + /* Flush pending command nodes */ spin_lock_irqsave(&priv->driver_lock, flags); + lbs_deb_main("clearing pending commands\n"); list_for_each_entry(cmdnode, &priv->cmdpendingq, list) { cmdnode->result = -ENOENT; cmdnode->cmdwaitqwoken = 1; wake_up_interruptible(&cmdnode->cmdwait_q); } + + /* Flush the command the card is currently processing */ + if (priv->cur_cmd) { + lbs_deb_main("clearing current command\n"); + priv->cur_cmd->result = -ENOENT; + priv->cur_cmd->cmdwaitqwoken = 1; + wake_up_interruptible(&priv->cur_cmd->cmdwait_q); + } + lbs_deb_main("done clearing commands\n"); spin_unlock_irqrestore(&priv->driver_lock, flags); unregister_netdev(dev); diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 426f1fe3bb42..e8cadad2c863 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -1820,7 +1820,21 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, } if (vwrq->fixed == 0) { - /* Auto power control */ + /* User requests automatic tx power control, however there are + * many auto tx settings. For now use firmware defaults until + * we come up with a good way to expose these to the user. */ + if (priv->fwrelease < 0x09000000) { + ret = lbs_set_power_adapt_cfg(priv, 1, + POW_ADAPT_DEFAULT_P0, + POW_ADAPT_DEFAULT_P1, + POW_ADAPT_DEFAULT_P2); + if (ret) + goto out; + } + ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1, + TPC_DEFAULT_P2, 1); + if (ret) + goto out; dbm = priv->txpower_max; } else { /* Userspace check in iwrange if it should use dBm or mW, @@ -1830,7 +1844,8 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, goto out; } - /* Validate requested power level against firmware allowed levels */ + /* Validate requested power level against firmware allowed + * levels */ if (priv->txpower_min && (dbm < priv->txpower_min)) { ret = -EINVAL; goto out; @@ -1840,6 +1855,18 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, ret = -EINVAL; goto out; } + if (priv->fwrelease < 0x09000000) { + ret = lbs_set_power_adapt_cfg(priv, 0, + POW_ADAPT_DEFAULT_P0, + POW_ADAPT_DEFAULT_P1, + POW_ADAPT_DEFAULT_P2); + if (ret) + goto out; + } + ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1, + TPC_DEFAULT_P2, 1); + if (ret) + goto out; } /* If the radio was off, turn it on */ |