Merge branch 'for-linville' of git://github.com/lucacoelho/wl12xx

This commit is contained in:
John W. Linville 2011-10-11 15:56:29 -04:00
commit 5dde8e1749
9 changed files with 158 additions and 24 deletions

View File

@ -777,7 +777,23 @@ int wl1271_acx_sta_rate_policies(struct wl1271 *wl)
acx->rate_policy.long_retry_limit = c->long_retry_limit; acx->rate_policy.long_retry_limit = c->long_retry_limit;
acx->rate_policy.aflags = c->aflags; acx->rate_policy.aflags = c->aflags;
ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("Setting of rate policies failed: %d", ret);
goto out;
}
/*
* configure one rate class for basic p2p operations.
* (p2p packets should always go out with OFDM rates, even
* if we are currently connected to 11b AP)
*/
acx->rate_policy_idx = cpu_to_le32(ACX_TX_BASIC_RATE_P2P);
acx->rate_policy.enabled_rates =
cpu_to_le32(CONF_TX_RATE_MASK_BASIC_P2P);
acx->rate_policy.short_retry_limit = c->short_retry_limit;
acx->rate_policy.long_retry_limit = c->long_retry_limit;
acx->rate_policy.aflags = c->aflags;
ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
if (ret < 0) { if (ret < 0) {

View File

@ -656,6 +656,7 @@ struct acx_rate_class {
#define ACX_TX_BASIC_RATE 0 #define ACX_TX_BASIC_RATE 0
#define ACX_TX_AP_FULL_RATE 1 #define ACX_TX_AP_FULL_RATE 1
#define ACX_TX_BASIC_RATE_P2P 2
#define ACX_TX_AP_MODE_MGMT_RATE 4 #define ACX_TX_AP_MODE_MGMT_RATE 4
#define ACX_TX_AP_MODE_BCST_RATE 5 #define ACX_TX_AP_MODE_BCST_RATE 5
struct acx_rate_policy { struct acx_rate_policy {

View File

@ -503,7 +503,8 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
BA_SESSION_RX_CONSTRAINT_EVENT_ID | BA_SESSION_RX_CONSTRAINT_EVENT_ID |
REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID | REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID |
INACTIVE_STA_EVENT_ID | INACTIVE_STA_EVENT_ID |
MAX_TX_RETRY_EVENT_ID; MAX_TX_RETRY_EVENT_ID |
CHANNEL_SWITCH_COMPLETE_EVENT_ID;
ret = wl1271_event_unmask(wl); ret = wl1271_event_unmask(wl);
if (ret < 0) { if (ret < 0) {
@ -769,9 +770,6 @@ int wl1271_load_firmware(struct wl1271 *wl)
clk |= (wl->ref_clock << 1) << 4; clk |= (wl->ref_clock << 1) << 4;
} }
if (wl->quirks & WL12XX_QUIRK_LPD_MODE)
clk |= SCRATCH_ENABLE_LPD;
wl1271_write32(wl, DRPW_SCRATCH_START, clk); wl1271_write32(wl, DRPW_SCRATCH_START, clk);
wl1271_set_partition(wl, &part_table[PART_WORK]); wl1271_set_partition(wl, &part_table[PART_WORK]);

View File

@ -134,11 +134,6 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
/* Override the REF CLK from the NVS with the one from platform data */ /* Override the REF CLK from the NVS with the one from platform data */
gen_parms->general_params.ref_clock = wl->ref_clock; gen_parms->general_params.ref_clock = wl->ref_clock;
/* LPD mode enable (bits 6-7) in WL1271 AP mode only */
if (wl->quirks & WL12XX_QUIRK_LPD_MODE)
gen_parms->general_params.general_settings |=
GENERAL_SETTINGS_DRPW_LPD;
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
if (ret < 0) { if (ret < 0) {
wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
@ -1700,3 +1695,61 @@ int wl12xx_croc(struct wl1271 *wl, u8 role_id)
out: out:
return ret; return ret;
} }
int wl12xx_cmd_channel_switch(struct wl1271 *wl,
struct ieee80211_channel_switch *ch_switch)
{
struct wl12xx_cmd_channel_switch *cmd;
int ret;
wl1271_debug(DEBUG_ACX, "cmd channel switch");
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}
cmd->channel = ch_switch->channel->hw_value;
cmd->switch_time = ch_switch->count;
cmd->tx_suspend = ch_switch->block_tx;
cmd->flush = 0; /* this value is ignored by the FW */
ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("failed to send channel switch command");
goto out_free;
}
out_free:
kfree(cmd);
out:
return ret;
}
int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl)
{
struct wl12xx_cmd_stop_channel_switch *cmd;
int ret;
wl1271_debug(DEBUG_ACX, "cmd stop channel switch");
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}
ret = wl1271_cmd_send(wl, CMD_STOP_CHANNEL_SWICTH, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("failed to stop channel switch command");
goto out_free;
}
out_free:
kfree(cmd);
out:
return ret;
}

View File

@ -79,6 +79,9 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid);
int wl12xx_cmd_config_fwlog(struct wl1271 *wl); int wl12xx_cmd_config_fwlog(struct wl1271 *wl);
int wl12xx_cmd_start_fwlog(struct wl1271 *wl); int wl12xx_cmd_start_fwlog(struct wl1271 *wl);
int wl12xx_cmd_stop_fwlog(struct wl1271 *wl); int wl12xx_cmd_stop_fwlog(struct wl1271 *wl);
int wl12xx_cmd_channel_switch(struct wl1271 *wl,
struct ieee80211_channel_switch *ch_switch);
int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl);
enum wl1271_commands { enum wl1271_commands {
CMD_INTERROGATE = 1, /*use this to read information elements*/ CMD_INTERROGATE = 1, /*use this to read information elements*/
@ -677,4 +680,21 @@ struct wl12xx_cmd_stop_fwlog {
struct wl1271_cmd_header header; struct wl1271_cmd_header header;
} __packed; } __packed;
struct wl12xx_cmd_channel_switch {
struct wl1271_cmd_header header;
/* The new serving channel */
u8 channel;
/* Relative time of the serving channel switch in TBTT units */
u8 switch_time;
/* 1: Suspend TX till switch time; 0: Do not suspend TX */
u8 tx_suspend;
/* 1: Flush TX at switch time; 0: Do not flush */
u8 flush;
} __packed;
struct wl12xx_cmd_stop_channel_switch {
struct wl1271_cmd_header header;
} __packed;
#endif /* __WL1271_CMD_H__ */ #endif /* __WL1271_CMD_H__ */

View File

@ -416,13 +416,17 @@ struct conf_rx_settings {
u8 queue_type; u8 queue_type;
}; };
#define CONF_TX_MAX_RATE_CLASSES 8 #define CONF_TX_MAX_RATE_CLASSES 10
#define CONF_TX_RATE_MASK_UNSPECIFIED 0 #define CONF_TX_RATE_MASK_UNSPECIFIED 0
#define CONF_TX_RATE_MASK_BASIC (CONF_HW_BIT_RATE_1MBPS | \ #define CONF_TX_RATE_MASK_BASIC (CONF_HW_BIT_RATE_1MBPS | \
CONF_HW_BIT_RATE_2MBPS) CONF_HW_BIT_RATE_2MBPS)
#define CONF_TX_RATE_RETRY_LIMIT 10 #define CONF_TX_RATE_RETRY_LIMIT 10
/* basic rates for p2p operations (probe req/resp, etc.) */
#define CONF_TX_RATE_MASK_BASIC_P2P (CONF_HW_BIT_RATE_6MBPS | \
CONF_HW_BIT_RATE_12MBPS | CONF_HW_BIT_RATE_24MBPS)
/* /*
* Rates supported for data packets when operating as AP. Note the absence * Rates supported for data packets when operating as AP. Note the absence
* of the 22Mbps rate. There is a FW limitation on 12 rates so we must drop * of the 22Mbps rate. There is a FW limitation on 12 rates so we must drop

View File

@ -300,6 +300,21 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
wl1271_stop_ba_event(wl); wl1271_stop_ba_event(wl);
} }
if ((vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) && !is_ap) {
wl1271_debug(DEBUG_EVENT, "CHANNEL_SWITCH_COMPLETE_EVENT_ID. "
"status = 0x%x",
mbox->channel_switch_status);
/*
* That event uses for two cases:
* 1) channel switch complete with status=0
* 2) channel switch failed status=1
*/
if (test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags) &&
(wl->vif))
ieee80211_chswitch_done(wl->vif,
mbox->channel_switch_status ? false : true);
}
if ((vector & DUMMY_PACKET_EVENT_ID)) { if ((vector & DUMMY_PACKET_EVENT_ID)) {
wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
if (wl->vif) if (wl->vif)

View File

@ -1333,14 +1333,6 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
wl->chip.id); wl->chip.id);
/*
* 'end-of-transaction flag' and 'LPD mode flag'
* should be set in wl127x AP mode only
*/
if (wl->bss_type == BSS_TYPE_AP_BSS)
wl->quirks |= (WL12XX_QUIRK_END_OF_TRANSACTION |
WL12XX_QUIRK_LPD_MODE);
ret = wl1271_setup(wl); ret = wl1271_setup(wl);
if (ret < 0) if (ret < 0)
goto out; goto out;
@ -2222,6 +2214,11 @@ static int wl1271_unjoin(struct wl1271 *wl)
{ {
int ret; int ret;
if (test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags)) {
wl12xx_cmd_stop_channel_switch(wl);
ieee80211_chswitch_done(wl->vif, false);
}
/* to stop listening to a channel, we disconnect */ /* to stop listening to a channel, we disconnect */
ret = wl12xx_cmd_role_stop_sta(wl); ret = wl12xx_cmd_role_stop_sta(wl);
if (ret < 0) if (ret < 0)
@ -4130,6 +4127,37 @@ static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
return 0; return 0;
} }
static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
struct ieee80211_channel_switch *ch_switch)
{
struct wl1271 *wl = hw->priv;
int ret;
wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
mutex_lock(&wl->mutex);
if (unlikely(wl->state == WL1271_STATE_OFF)) {
mutex_unlock(&wl->mutex);
ieee80211_chswitch_done(wl->vif, false);
return;
}
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
ret = wl12xx_cmd_channel_switch(wl, ch_switch);
if (!ret)
set_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags);
wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
}
static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
{ {
struct wl1271 *wl = hw->priv; struct wl1271 *wl = hw->priv;
@ -4406,6 +4434,7 @@ static const struct ieee80211_ops wl1271_ops = {
.ampdu_action = wl1271_op_ampdu_action, .ampdu_action = wl1271_op_ampdu_action,
.tx_frames_pending = wl1271_tx_frames_pending, .tx_frames_pending = wl1271_tx_frames_pending,
.set_bitrate_mask = wl12xx_set_bitrate_mask, .set_bitrate_mask = wl12xx_set_bitrate_mask,
.channel_switch = wl12xx_op_channel_switch,
CFG80211_TESTMODE_CMD(wl1271_tm_cmd) CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
}; };
@ -4679,6 +4708,9 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE - wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
sizeof(struct ieee80211_header); sizeof(struct ieee80211_header);
wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
sizeof(struct ieee80211_header);
wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
/* make sure all our channels fit in the scanned_ch bitmask */ /* make sure all our channels fit in the scanned_ch bitmask */

View File

@ -348,6 +348,7 @@ enum wl12xx_flags {
WL1271_FLAG_SOFT_GEMINI, WL1271_FLAG_SOFT_GEMINI,
WL1271_FLAG_RX_STREAMING_STARTED, WL1271_FLAG_RX_STREAMING_STARTED,
WL1271_FLAG_RECOVERY_IN_PROGRESS, WL1271_FLAG_RECOVERY_IN_PROGRESS,
WL1271_FLAG_CS_PROGRESS,
}; };
struct wl1271_link { struct wl1271_link {
@ -671,12 +672,6 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen);
/* WL128X requires aggregated packets to be aligned to the SDIO block size */ /* WL128X requires aggregated packets to be aligned to the SDIO block size */
#define WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT BIT(2) #define WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT BIT(2)
/*
* WL127X AP mode requires Low Power DRPw (LPD) enable to reduce power
* consumption
*/
#define WL12XX_QUIRK_LPD_MODE BIT(3)
/* Older firmwares did not implement the FW logger over bus feature */ /* Older firmwares did not implement the FW logger over bus feature */
#define WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED BIT(4) #define WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED BIT(4)