Commit 1e5023c7 authored by John W. Linville's avatar John W. Linville

Merge branch 'for-linville' of git://github.com/kvalo/ath6kl

parents dfbebe14 ff7e6867
...@@ -30,3 +30,12 @@ config ATH6KL_DEBUG ...@@ -30,3 +30,12 @@ config ATH6KL_DEBUG
depends on ATH6KL depends on ATH6KL
---help--- ---help---
Enables debug support Enables debug support
config ATH6KL_REGDOMAIN
bool "Atheros ath6kl regdomain support"
depends on ATH6KL
depends on CFG80211_CERTIFICATION_ONUS
---help---
Enabling this makes it possible to change the regdomain in
the firmware. This can be only enabled if regulatory requirements
are taken into account.
...@@ -34,6 +34,7 @@ ath6kl_core-y += main.o ...@@ -34,6 +34,7 @@ ath6kl_core-y += main.o
ath6kl_core-y += txrx.o ath6kl_core-y += txrx.o
ath6kl_core-y += wmi.o ath6kl_core-y += wmi.o
ath6kl_core-y += core.o ath6kl_core-y += core.o
ath6kl_core-y += recovery.o
ath6kl_core-$(CONFIG_NL80211_TESTMODE) += testmode.o ath6kl_core-$(CONFIG_NL80211_TESTMODE) += testmode.o
obj-$(CONFIG_ATH6KL_SDIO) += ath6kl_sdio.o obj-$(CONFIG_ATH6KL_SDIO) += ath6kl_sdio.o
......
This diff is collapsed.
...@@ -22,7 +22,6 @@ enum ath6kl_cfg_suspend_mode { ...@@ -22,7 +22,6 @@ enum ath6kl_cfg_suspend_mode {
ATH6KL_CFG_SUSPEND_DEEPSLEEP, ATH6KL_CFG_SUSPEND_DEEPSLEEP,
ATH6KL_CFG_SUSPEND_CUTPOWER, ATH6KL_CFG_SUSPEND_CUTPOWER,
ATH6KL_CFG_SUSPEND_WOW, ATH6KL_CFG_SUSPEND_WOW,
ATH6KL_CFG_SUSPEND_SCHED_SCAN,
}; };
struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name, struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name,
......
...@@ -33,6 +33,8 @@ static unsigned int wow_mode; ...@@ -33,6 +33,8 @@ static unsigned int wow_mode;
static unsigned int uart_debug; static unsigned int uart_debug;
static unsigned int ath6kl_p2p; static unsigned int ath6kl_p2p;
static unsigned int testmode; static unsigned int testmode;
static unsigned int recovery_enable;
static unsigned int heart_beat_poll;
module_param(debug_mask, uint, 0644); module_param(debug_mask, uint, 0644);
module_param(suspend_mode, uint, 0644); module_param(suspend_mode, uint, 0644);
...@@ -40,6 +42,12 @@ module_param(wow_mode, uint, 0644); ...@@ -40,6 +42,12 @@ module_param(wow_mode, uint, 0644);
module_param(uart_debug, uint, 0644); module_param(uart_debug, uint, 0644);
module_param(ath6kl_p2p, uint, 0644); module_param(ath6kl_p2p, uint, 0644);
module_param(testmode, uint, 0644); module_param(testmode, uint, 0644);
module_param(recovery_enable, uint, 0644);
module_param(heart_beat_poll, uint, 0644);
MODULE_PARM_DESC(recovery_enable, "Enable recovery from firmware error");
MODULE_PARM_DESC(heart_beat_poll, "Enable fw error detection periodic" \
"polling. This also specifies the polling interval in" \
"msecs. Set reocvery_enable for this to be effective");
void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb) void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb)
{ {
...@@ -202,6 +210,17 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) ...@@ -202,6 +210,17 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type)
ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n", ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n",
__func__, wdev->netdev->name, wdev->netdev, ar); __func__, wdev->netdev->name, wdev->netdev, ar);
ar->fw_recovery.enable = !!recovery_enable;
if (!ar->fw_recovery.enable)
return ret;
if (heart_beat_poll &&
test_bit(ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL,
ar->fw_capabilities))
ar->fw_recovery.hb_poll = heart_beat_poll;
ath6kl_recovery_init(ar);
return ret; return ret;
err_rxbuf_cleanup: err_rxbuf_cleanup:
...@@ -291,6 +310,8 @@ void ath6kl_core_cleanup(struct ath6kl *ar) ...@@ -291,6 +310,8 @@ void ath6kl_core_cleanup(struct ath6kl *ar)
{ {
ath6kl_hif_power_off(ar); ath6kl_hif_power_off(ar);
ath6kl_recovery_cleanup(ar);
destroy_workqueue(ar->ath6kl_wq); destroy_workqueue(ar->ath6kl_wq);
if (ar->htc_target) if (ar->htc_target)
......
...@@ -115,6 +115,27 @@ enum ath6kl_fw_capability { ...@@ -115,6 +115,27 @@ enum ath6kl_fw_capability {
*/ */
ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST, ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST,
/* Firmware supports filtering BSS results by RSSI */
ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD,
/* FW sets mac_addr[4] ^= 0x80 for newly created interfaces */
ATH6KL_FW_CAPABILITY_CUSTOM_MAC_ADDR,
/* Firmware supports TX error rate notification */
ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY,
/* supports WMI_SET_REGDOMAIN_CMDID command */
ATH6KL_FW_CAPABILITY_REGDOMAIN,
/* Firmware supports sched scan decoupled from host sleep */
ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2,
/*
* Firmware capability for hang detection through heart beat
* challenge messages.
*/
ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL,
/* this needs to be last */ /* this needs to be last */
ATH6KL_FW_CAPABILITY_MAX, ATH6KL_FW_CAPABILITY_MAX,
}; };
...@@ -128,11 +149,15 @@ struct ath6kl_fw_ie { ...@@ -128,11 +149,15 @@ struct ath6kl_fw_ie {
}; };
enum ath6kl_hw_flags { enum ath6kl_hw_flags {
ATH6KL_HW_FLAG_64BIT_RATES = BIT(0), ATH6KL_HW_64BIT_RATES = BIT(0),
ATH6KL_HW_AP_INACTIVITY_MINS = BIT(1),
ATH6KL_HW_MAP_LP_ENDPOINT = BIT(2),
ATH6KL_HW_SDIO_CRC_ERROR_WAR = BIT(3),
}; };
#define ATH6KL_FW_API2_FILE "fw-2.bin" #define ATH6KL_FW_API2_FILE "fw-2.bin"
#define ATH6KL_FW_API3_FILE "fw-3.bin" #define ATH6KL_FW_API3_FILE "fw-3.bin"
#define ATH6KL_FW_API4_FILE "fw-4.bin"
/* AR6003 1.0 definitions */ /* AR6003 1.0 definitions */
#define AR6003_HW_1_0_VERSION 0x300002ba #define AR6003_HW_1_0_VERSION 0x300002ba
...@@ -186,6 +211,13 @@ enum ath6kl_hw_flags { ...@@ -186,6 +211,13 @@ enum ath6kl_hw_flags {
#define AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE \ #define AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE \
AR6004_HW_1_2_FW_DIR "/bdata.bin" AR6004_HW_1_2_FW_DIR "/bdata.bin"
/* AR6004 1.3 definitions */
#define AR6004_HW_1_3_VERSION 0x31c8088a
#define AR6004_HW_1_3_FW_DIR "ath6k/AR6004/hw1.3"
#define AR6004_HW_1_3_FIRMWARE_FILE "fw.ram.bin"
#define AR6004_HW_1_3_BOARD_DATA_FILE "ath6k/AR6004/hw1.3/bdata.bin"
#define AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE "ath6k/AR6004/hw1.3/bdata.bin"
/* Per STA data, used in AP mode */ /* Per STA data, used in AP mode */
#define STA_PS_AWAKE BIT(0) #define STA_PS_AWAKE BIT(0)
#define STA_PS_SLEEP BIT(1) #define STA_PS_SLEEP BIT(1)
...@@ -536,6 +568,7 @@ enum ath6kl_vif_state { ...@@ -536,6 +568,7 @@ enum ath6kl_vif_state {
HOST_SLEEP_MODE_CMD_PROCESSED, HOST_SLEEP_MODE_CMD_PROCESSED,
NETDEV_MCAST_ALL_ON, NETDEV_MCAST_ALL_ON,
NETDEV_MCAST_ALL_OFF, NETDEV_MCAST_ALL_OFF,
SCHED_SCANNING,
}; };
struct ath6kl_vif { struct ath6kl_vif {
...@@ -580,11 +613,13 @@ struct ath6kl_vif { ...@@ -580,11 +613,13 @@ struct ath6kl_vif {
u16 assoc_bss_beacon_int; u16 assoc_bss_beacon_int;
u16 listen_intvl_t; u16 listen_intvl_t;
u16 bmiss_time_t; u16 bmiss_time_t;
u32 txe_intvl;
u16 bg_scan_period; u16 bg_scan_period;
u8 assoc_bss_dtim_period; u8 assoc_bss_dtim_period;
struct net_device_stats net_stats; struct net_device_stats net_stats;
struct target_stats target_stats; struct target_stats target_stats;
struct wmi_connect_cmd profile; struct wmi_connect_cmd profile;
u16 rsn_capab;
struct list_head mc_filter; struct list_head mc_filter;
}; };
...@@ -609,6 +644,7 @@ enum ath6kl_dev_state { ...@@ -609,6 +644,7 @@ enum ath6kl_dev_state {
SKIP_SCAN, SKIP_SCAN,
ROAM_TBL_PEND, ROAM_TBL_PEND,
FIRST_BOOT, FIRST_BOOT,
RECOVERY_CLEANUP,
}; };
enum ath6kl_state { enum ath6kl_state {
...@@ -619,7 +655,16 @@ enum ath6kl_state { ...@@ -619,7 +655,16 @@ enum ath6kl_state {
ATH6KL_STATE_DEEPSLEEP, ATH6KL_STATE_DEEPSLEEP,
ATH6KL_STATE_CUTPOWER, ATH6KL_STATE_CUTPOWER,
ATH6KL_STATE_WOW, ATH6KL_STATE_WOW,
ATH6KL_STATE_SCHED_SCAN, ATH6KL_STATE_RECOVERY,
};
/* Fw error recovery */
#define ATH6KL_HB_RESP_MISS_THRES 5
enum ath6kl_fw_err {
ATH6KL_FW_ASSERT,
ATH6KL_FW_HB_RESP_FAILURE,
ATH6KL_FW_EP_FULL,
}; };
struct ath6kl { struct ath6kl {
...@@ -679,6 +724,7 @@ struct ath6kl { ...@@ -679,6 +724,7 @@ struct ath6kl {
struct ath6kl_req_key ap_mode_bkey; struct ath6kl_req_key ap_mode_bkey;
struct sk_buff_head mcastpsq; struct sk_buff_head mcastpsq;
u32 want_ch_switch; u32 want_ch_switch;
u16 last_ch;
/* /*
* FIXME: protects access to mcastpsq but is actually useless as * FIXME: protects access to mcastpsq but is actually useless as
...@@ -764,6 +810,17 @@ struct ath6kl { ...@@ -764,6 +810,17 @@ struct ath6kl {
bool wiphy_registered; bool wiphy_registered;
struct ath6kl_fw_recovery {
struct work_struct recovery_work;
unsigned long err_reason;
unsigned long hb_poll;
struct timer_list hb_timer;
u32 seq_num;
bool hb_pending;
u8 hb_misscnt;
bool enable;
} fw_recovery;
#ifdef CONFIG_ATH6KL_DEBUG #ifdef CONFIG_ATH6KL_DEBUG
struct { struct {
struct sk_buff_head fwlog_queue; struct sk_buff_head fwlog_queue;
...@@ -899,4 +956,12 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type); ...@@ -899,4 +956,12 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type);
void ath6kl_core_cleanup(struct ath6kl *ar); void ath6kl_core_cleanup(struct ath6kl *ar);
void ath6kl_core_destroy(struct ath6kl *ar); void ath6kl_core_destroy(struct ath6kl *ar);
/* Fw error recovery */
void ath6kl_init_hw_restart(struct ath6kl *ar);
void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason);
void ath6kl_recovery_hb_event(struct ath6kl *ar, u32 cookie);
void ath6kl_recovery_init(struct ath6kl *ar);
void ath6kl_recovery_cleanup(struct ath6kl *ar);
void ath6kl_recovery_suspend(struct ath6kl *ar);
void ath6kl_recovery_resume(struct ath6kl *ar);
#endif /* CORE_H */ #endif /* CORE_H */
...@@ -44,6 +44,7 @@ enum ATH6K_DEBUG_MASK { ...@@ -44,6 +44,7 @@ enum ATH6K_DEBUG_MASK {
ATH6KL_DBG_SUSPEND = BIT(20), ATH6KL_DBG_SUSPEND = BIT(20),
ATH6KL_DBG_USB = BIT(21), ATH6KL_DBG_USB = BIT(21),
ATH6KL_DBG_USB_BULK = BIT(22), ATH6KL_DBG_USB_BULK = BIT(22),
ATH6KL_DBG_RECOVERY = BIT(23),
ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */ ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */
}; };
......
...@@ -136,6 +136,7 @@ static int ath6kl_hif_proc_dbg_intr(struct ath6kl_device *dev) ...@@ -136,6 +136,7 @@ static int ath6kl_hif_proc_dbg_intr(struct ath6kl_device *dev)
ath6kl_hif_dump_fw_crash(dev->ar); ath6kl_hif_dump_fw_crash(dev->ar);
ath6kl_read_fwlogs(dev->ar); ath6kl_read_fwlogs(dev->ar);
ath6kl_recovery_err_notify(dev->ar, ATH6KL_FW_ASSERT);
return ret; return ret;
} }
...@@ -693,11 +694,6 @@ int ath6kl_hif_setup(struct ath6kl_device *dev) ...@@ -693,11 +694,6 @@ int ath6kl_hif_setup(struct ath6kl_device *dev)
ath6kl_dbg(ATH6KL_DBG_HIF, "hif block size %d mbox addr 0x%x\n", ath6kl_dbg(ATH6KL_DBG_HIF, "hif block size %d mbox addr 0x%x\n",
dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr); dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr);
/* usb doesn't support enabling interrupts */
/* FIXME: remove check once USB support is implemented */
if (dev->ar->hif_type == ATH6KL_HIF_TYPE_USB)
return 0;
status = ath6kl_hif_disable_intrs(dev); status = ath6kl_hif_disable_intrs(dev);
fail_setup: fail_setup:
......
...@@ -2492,7 +2492,8 @@ static int ath6kl_htc_mbox_conn_service(struct htc_target *target, ...@@ -2492,7 +2492,8 @@ static int ath6kl_htc_mbox_conn_service(struct htc_target *target,
max_msg_sz = le16_to_cpu(resp_msg->max_msg_sz); max_msg_sz = le16_to_cpu(resp_msg->max_msg_sz);
} }
if (assigned_ep >= ENDPOINT_MAX || !max_msg_sz) { if (WARN_ON_ONCE(assigned_ep == ENDPOINT_UNUSED ||
assigned_ep >= ENDPOINT_MAX || !max_msg_sz)) {
status = -ENOMEM; status = -ENOMEM;
goto fail_tx; goto fail_tx;
} }
...@@ -2655,12 +2656,6 @@ static int ath6kl_htc_mbox_wait_target(struct htc_target *target) ...@@ -2655,12 +2656,6 @@ static int ath6kl_htc_mbox_wait_target(struct htc_target *target)
struct htc_service_connect_resp resp; struct htc_service_connect_resp resp;
int status; int status;
/* FIXME: remove once USB support is implemented */
if (target->dev->ar->hif_type == ATH6KL_HIF_TYPE_USB) {
ath6kl_err("HTC doesn't support USB yet. Patience!\n");
return -EOPNOTSUPP;
}
/* we should be getting 1 control message that the target is ready */ /* we should be getting 1 control message that the target is ready */
packet = htc_wait_for_ctrl_msg(target); packet = htc_wait_for_ctrl_msg(target);
...@@ -2890,9 +2885,7 @@ static void ath6kl_htc_mbox_cleanup(struct htc_target *target) ...@@ -2890,9 +2885,7 @@ static void ath6kl_htc_mbox_cleanup(struct htc_target *target)
{ {
struct htc_packet *packet, *tmp_packet; struct htc_packet *packet, *tmp_packet;
/* FIXME: remove check once USB support is implemented */ ath6kl_hif_cleanup_scatter(target->dev->ar);
if (target->dev->ar->hif_type != ATH6KL_HIF_TYPE_USB)
ath6kl_hif_cleanup_scatter(target->dev->ar);
list_for_each_entry_safe(packet, tmp_packet, list_for_each_entry_safe(packet, tmp_packet,
&target->free_ctrl_txbuf, list) { &target->free_ctrl_txbuf, list) {
......
...@@ -374,9 +374,8 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target, ...@@ -374,9 +374,8 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target,
packet = list_first_entry(txq, packet = list_first_entry(txq,
struct htc_packet, struct htc_packet,
list); list);
list_del(&packet->list); /* move to local queue */
/* insert into local queue */ list_move_tail(&packet->list, &send_queue);
list_add_tail(&packet->list, &send_queue);
} }
/* /*
...@@ -399,11 +398,10 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target, ...@@ -399,11 +398,10 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target,
* for cleanup */ * for cleanup */
} else { } else {
/* callback wants to keep this packet, /* callback wants to keep this packet,
* remove from caller's queue */ * move from caller's queue to the send
list_del(&packet->list); * queue */
/* put it in the send queue */ list_move_tail(&packet->list,
list_add_tail(&packet->list, &send_queue);
&send_queue);
} }
} }
......
...@@ -42,7 +42,7 @@ static const struct ath6kl_hw hw_list[] = { ...@@ -42,7 +42,7 @@ static const struct ath6kl_hw hw_list[] = {
.reserved_ram_size = 6912, .reserved_ram_size = 6912,
.refclk_hz = 26000000, .refclk_hz = 26000000,
.uarttx_pin = 8, .uarttx_pin = 8,
.flags = 0, .flags = ATH6KL_HW_SDIO_CRC_ERROR_WAR,
/* hw2.0 needs override address hardcoded */ /* hw2.0 needs override address hardcoded */
.app_start_override_addr = 0x944C00, .app_start_override_addr = 0x944C00,
...@@ -68,7 +68,7 @@ static const struct ath6kl_hw hw_list[] = { ...@@ -68,7 +68,7 @@ static const struct ath6kl_hw hw_list[] = {
.refclk_hz = 26000000, .refclk_hz = 26000000,
.uarttx_pin = 8, .uarttx_pin = 8,
.testscript_addr = 0x57ef74, .testscript_addr = 0x57ef74,
.flags = 0, .flags = ATH6KL_HW_SDIO_CRC_ERROR_WAR,
.fw = { .fw = {
.dir = AR6003_HW_2_1_1_FW_DIR, .dir = AR6003_HW_2_1_1_FW_DIR,
...@@ -93,7 +93,8 @@ static const struct ath6kl_hw hw_list[] = { ...@@ -93,7 +93,8 @@ static const struct ath6kl_hw hw_list[] = {
.board_addr = 0x433900, .board_addr = 0x433900,
.refclk_hz = 26000000, .refclk_hz = 26000000,
.uarttx_pin = 11, .uarttx_pin = 11,
.flags = ATH6KL_HW_FLAG_64BIT_RATES, .flags = ATH6KL_HW_64BIT_RATES |
ATH6KL_HW_AP_INACTIVITY_MINS,
.fw = { .fw = {
.dir = AR6004_HW_1_0_FW_DIR, .dir = AR6004_HW_1_0_FW_DIR,
...@@ -113,8 +114,8 @@ static const struct ath6kl_hw hw_list[] = { ...@@ -113,8 +114,8 @@ static const struct ath6kl_hw hw_list[] = {
.board_addr = 0x43d400, .board_addr = 0x43d400,
.refclk_hz = 40000000, .refclk_hz = 40000000,
.uarttx_pin = 11, .uarttx_pin = 11,
.flags = ATH6KL_HW_FLAG_64BIT_RATES, .flags = ATH6KL_HW_64BIT_RATES |
ATH6KL_HW_AP_INACTIVITY_MINS,
.fw = { .fw = {
.dir = AR6004_HW_1_1_FW_DIR, .dir = AR6004_HW_1_1_FW_DIR,
.fw = AR6004_HW_1_1_FIRMWARE_FILE, .fw = AR6004_HW_1_1_FIRMWARE_FILE,
...@@ -133,7 +134,8 @@ static const struct ath6kl_hw hw_list[] = { ...@@ -133,7 +134,8 @@ static const struct ath6kl_hw hw_list[] = {
.board_addr = 0x435c00, .board_addr = 0x435c00,
.refclk_hz = 40000000, .refclk_hz = 40000000,
.uarttx_pin = 11, .uarttx_pin = 11,
.flags = ATH6KL_HW_FLAG_64BIT_RATES, .flags = ATH6KL_HW_64BIT_RATES |
ATH6KL_HW_AP_INACTIVITY_MINS,
.fw = { .fw = {
.dir = AR6004_HW_1_2_FW_DIR, .dir = AR6004_HW_1_2_FW_DIR,
...@@ -142,6 +144,28 @@ static const struct ath6kl_hw hw_list[] = { ...@@ -142,6 +144,28 @@ static const struct ath6kl_hw hw_list[] = {
.fw_board = AR6004_HW_1_2_BOARD_DATA_FILE, .fw_board = AR6004_HW_1_2_BOARD_DATA_FILE,
.fw_default_board = AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE, .fw_default_board = AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE,
}, },
{
.id = AR6004_HW_1_3_VERSION,
.name = "ar6004 hw 1.3",
.dataset_patch_addr = 0x437860,
.app_load_addr = 0x1234,
.board_ext_data_addr = 0x437000,
.reserved_ram_size = 7168,
.board_addr = 0x436400,
.refclk_hz = 40000000,
.uarttx_pin = 11,
.flags = ATH6KL_HW_64BIT_RATES |
ATH6KL_HW_AP_INACTIVITY_MINS |
ATH6KL_HW_MAP_LP_ENDPOINT,
.fw = {
.dir = AR6004_HW_1_3_FW_DIR,
.fw = AR6004_HW_1_3_FIRMWARE_FILE,
},
.fw_board = AR6004_HW_1_3_BOARD_DATA_FILE,
.fw_default_board = AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE,
},
}; };
/* /*
...@@ -337,7 +361,7 @@ static int ath6kl_init_service_ep(struct ath6kl *ar) ...@@ -337,7 +361,7 @@ static int ath6kl_init_service_ep(struct ath6kl *ar)
if (ath6kl_connectservice(ar, &connect, "WMI DATA BK")) if (ath6kl_connectservice(ar, &connect, "WMI DATA BK"))
return -EIO; return -EIO;
/* connect to Video service, map this to to HI PRI */ /* connect to Video service, map this to HI PRI */
connect.svc_id = WMI_DATA_VI_SVC; connect.svc_id = WMI_DATA_VI_SVC;
if (ath6kl_connectservice(ar, &connect, "WMI DATA VI")) if (ath6kl_connectservice(ar, &connect, "WMI DATA VI"))
return -EIO; return -EIO;
...@@ -1088,6 +1112,12 @@ int ath6kl_init_fetch_firmwares(struct ath6kl *ar) ...@@ -1088,6 +1112,12 @@ int ath6kl_init_fetch_firmwares(struct ath6kl *ar)
if (ret) if (ret)
return ret; return ret;
ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API4_FILE);
if (ret == 0) {
ar->fw_api = 4;
goto out;
}
ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API3_FILE); ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API3_FILE);
if (ret == 0) { if (ret == 0) {
ar->fw_api = 3; ar->fw_api = 3;
...@@ -1401,8 +1431,7 @@ static int ath6kl_init_upload(struct ath6kl *ar) ...@@ -1401,8 +1431,7 @@ static int ath6kl_init_upload(struct ath6kl *ar)
return status; return status;
/* WAR to avoid SDIO CRC err */ /* WAR to avoid SDIO CRC err */
if (ar->version.target_ver == AR6003_HW_2_0_VERSION || if (ar->hw.flags & ATH6KL_HW_SDIO_CRC_ERROR_WAR) {
ar->version.target_ver == AR6003_HW_2_1_1_VERSION) {
ath6kl_err("temporary war to avoid sdio crc error\n"); ath6kl_err("temporary war to avoid sdio crc error\n");
param = 0x28; param = 0x28;
...@@ -1520,7 +1549,7 @@ static const char *ath6kl_init_get_hif_name(enum ath6kl_hif_type type) ...@@ -1520,7 +1549,7 @@ static const char *ath6kl_init_get_hif_name(enum ath6kl_hif_type type)
return NULL; return NULL;
} }
int ath6kl_init_hw_start(struct ath6kl *ar) static int __ath6kl_init_hw_start(struct ath6kl *ar)
{ {
long timeleft; long timeleft;
int ret, i; int ret, i;
...@@ -1616,8 +1645,6 @@ int ath6kl_init_hw_start(struct ath6kl *ar) ...@@ -1616,8 +1645,6 @@ int ath6kl_init_hw_start(struct ath6kl *ar)
goto err_htc_stop; goto err_htc_stop;
} }
ar->state = ATH6KL_STATE_ON;
return 0; return 0;
err_htc_stop: err_htc_stop:
...@@ -1630,7 +1657,18 @@ int ath6kl_init_hw_start(struct ath6kl *ar) ...@@ -1630,7 +1657,18 @@ int ath6kl_init_hw_start(struct ath6kl *ar)
return ret; return ret;
} }
int ath6kl_init_hw_stop(struct ath6kl *ar) int ath6kl_init_hw_start(struct ath6kl *ar)
{
int err;
err = __ath6kl_init_hw_start(ar);
if (err)
return err;
ar->state = ATH6KL_STATE_ON;
return 0;
}
static int __ath6kl_init_hw_stop(struct ath6kl *ar)
{ {
int ret; int ret;
...@@ -1646,11 +1684,37 @@ int ath6kl_init_hw_stop(struct ath6kl *ar) ...@@ -1646,11 +1684,37 @@ int ath6kl_init_hw_stop(struct ath6kl *ar)
if (ret) if (ret)
ath6kl_warn("failed to power off hif: %d\n", ret); ath6kl_warn("failed to power off hif: %d\n", ret);
ar->state = ATH6KL_STATE_OFF; return 0;
}
int ath6kl_init_hw_stop(struct ath6kl *ar)
{
int err;
err = __ath6kl_init_hw_stop(ar);
if (err)
return err;
ar->state = ATH6KL_STATE_OFF;
return 0; return 0;
} }
void ath6kl_init_hw_restart(struct ath6kl *ar)
{
clear_bit(WMI_READY, &ar->flag);
ath6kl_cfg80211_stop_all(ar);
if (__ath6kl_init_hw_stop(ar)) {
ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Failed to stop during fw error recovery\n");
return;
}
if (__ath6kl_init_hw_start(ar)) {
ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Failed to restart during fw error recovery\n");
return;
}
}
/* FIXME: move this to cfg80211.c and rename to ath6kl_cfg80211_vif_stop() */ /* FIXME: move this to cfg80211.c and rename to ath6kl_cfg80211_vif_stop() */
void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready) void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready)
{ {
......
...@@ -293,13 +293,17 @@ int ath6kl_read_fwlogs(struct ath6kl *ar) ...@@ -293,13 +293,17 @@ int ath6kl_read_fwlogs(struct ath6kl *ar)
} }
address = TARG_VTOP(ar->target_type, debug_hdr_addr); address = TARG_VTOP(ar->target_type, debug_hdr_addr);
ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr)); ret = ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr));
if (ret)
goto out;
address = TARG_VTOP(ar->target_type, address = TARG_VTOP(ar->target_type,
le32_to_cpu(debug_hdr.dbuf_addr)); le32_to_cpu(debug_hdr.dbuf_addr));
firstbuf = address; firstbuf = address;
dropped = le32_to_cpu(debug_hdr.dropped); dropped = le32_to_cpu(debug_hdr.dropped);
ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf)); ret = ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf));
if (ret)
goto out;
loop = 100; loop = 100;
...@@ -322,7 +326,8 @@ int ath6kl_read_fwlogs(struct ath6kl *ar) ...@@ -322,7 +326,8 @@ int ath6kl_read_fwlogs(struct ath6kl *ar)
address = TARG_VTOP(ar->target_type, address = TARG_VTOP(ar->target_type,
le32_to_cpu(debug_buf.next)); le32_to_cpu(debug_buf.next));
ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf)); ret = ath6kl_diag_read(ar, address, &debug_buf,
sizeof(debug_buf));
if (ret) if (ret)
goto out; goto out;
...@@ -436,12 +441,9 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel) ...@@ -436,12 +441,9 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel)
break; break;
} }
if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) { if (ar->last_ch != channel)
ar->want_ch_switch &= ~(1 << vif->fw_vif_idx);
/* we actually don't know the phymode, default to HT20 */ /* we actually don't know the phymode, default to HT20 */
ath6kl_cfg80211_ch_switch_notify(vif, channel, ath6kl_cfg80211_ch_switch_notify(vif, channel, WMI_11G_HT20);
WMI_11G_HT20);
}
ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, NONE_BSS_FILTER, 0); ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, NONE_BSS_FILTER, 0);
set_bit(CONNECTED, &vif->flags); set_bit(CONNECTED, &vif->flags);
...@@ -606,6 +608,18 @@ static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel) ...@@ -606,6 +608,18 @@ static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel)
switch (vif->nw_type) { switch (vif->nw_type) {
case AP_NETWORK: case AP_NETWORK:
/*
* reconfigure any saved RSN IE capabilites in the beacon /
* probe response to stay in sync with the supplicant.
*/
if (vif->rsn_capab &&
test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
ar->fw_capabilities))
ath6kl_wmi_set_ie_cmd(ar->wmi, vif->fw_vif_idx,
WLAN_EID_RSN, WMI_RSN_IE_CAPB,
(const u8 *) &vif->rsn_capab,
sizeof(vif->rsn_capab));
return ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, return ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx,
&vif->profile); &vif->profile);
default: default:
...@@ -628,6 +642,9 @@ static void ath6kl_check_ch_switch(struct ath6kl *ar, u16 channel) ...@@ -628,6 +642,9 @@ static void ath6kl_check_ch_switch(struct ath6kl *ar, u16 channel)
if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) if (ar->want_ch_switch & (1 << vif->fw_vif_idx))
res = ath6kl_commit_ch_switch(vif, channel); res = ath6kl_commit_ch_switch(vif, channel);
/* if channel switch failed, oh well we tried */
ar->want_ch_switch &= ~(1 << vif->fw_vif_idx);
if (res) if (res)
ath6kl_err("channel switch failed nw_type %d res %d\n", ath6kl_err("channel switch failed nw_type %d res %d\n",
vif->nw_type, res); vif->nw_type, res);
...@@ -981,8 +998,25 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, ...@@ -981,8 +998,25 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid,
if (vif->nw_type == AP_NETWORK) { if (vif->nw_type == AP_NETWORK) {
/* disconnect due to other STA vif switching channels */ /* disconnect due to other STA vif switching channels */
if (reason == BSS_DISCONNECTED && if (reason == BSS_DISCONNECTED &&
prot_reason_status == WMI_AP_REASON_STA_ROAM) prot_reason_status == WMI_AP_REASON_STA_ROAM) {
ar->want_ch_switch |= 1 << vif->fw_vif_idx; ar->want_ch_switch |= 1 << vif->fw_vif_idx;
/* bail back to this channel if STA vif fails connect */
ar->last_ch = le16_to_cpu(vif->profile.ch);
}
if (prot_reason_status == WMI_AP_REASON_MAX_STA) {
/* send max client reached notification to user space */
cfg80211_conn_failed(vif->ndev, bssid,
NL80211_CONN_FAIL_MAX_CLIENTS,
GFP_KERNEL);
}
if (prot_reason_status == WMI_AP_REASON_ACL) {
/* send blocked client notification to user space */
cfg80211_conn_failed(vif->ndev, bssid,
NL80211_CONN_FAIL_BLOCKED_CLIENT,
GFP_KERNEL);
}
if (!ath6kl_remove_sta(ar, bssid, prot_reason_status)) if (!ath6kl_remove_sta(ar, bssid, prot_reason_status))
return; return;
...@@ -1041,6 +1075,9 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, ...@@ -1041,6 +1075,9 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid,
} }
} }
/* restart disconnected concurrent vifs waiting for new channel */
ath6kl_check_ch_switch(ar, ar->last_ch);
/* update connect & link status atomically */ /* update connect & link status atomically */
spin_lock_bh(&vif->if_lock); spin_lock_bh(&vif->if_lock);
clear_bit(CONNECTED, &vif->flags); clear_bit(CONNECTED, &vif->flags);
......
/*
* Copyright (c) 2012 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "core.h"
#include "cfg80211.h"
#include "debug.h"
static void ath6kl_recovery_work(struct work_struct *work)
{
struct ath6kl *ar = container_of(work, struct ath6kl,
fw_recovery.recovery_work);
ar->state = ATH6KL_STATE_RECOVERY;
del_timer_sync(&ar->fw_recovery.hb_timer);
ath6kl_init_hw_restart(ar);
ar->state = ATH6KL_STATE_ON;
clear_bit(WMI_CTRL_EP_FULL, &ar->flag);
ar->fw_recovery.err_reason = 0;
if (ar->fw_recovery.hb_poll)
mod_timer(&ar->fw_recovery.hb_timer, jiffies +
msecs_to_jiffies(ar->fw_recovery.hb_poll));
}
void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason)
{
if (!ar->fw_recovery.enable)
return;
ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Fw error detected, reason:%d\n",
reason);
set_bit(reason, &ar->fw_recovery.err_reason);
if (!test_bit(RECOVERY_CLEANUP, &ar->flag) &&
ar->state != ATH6KL_STATE_RECOVERY)
queue_work(ar->ath6kl_wq, &ar->fw_recovery.recovery_work);
}
void ath6kl_recovery_hb_event(struct ath6kl *ar, u32 cookie)
{
if (cookie == ar->fw_recovery.seq_num)
ar->fw_recovery.hb_pending = false;
}
static void ath6kl_recovery_hb_timer(unsigned long data)
{
struct ath6kl *ar = (struct ath6kl *) data;
int err;
if (test_bit(RECOVERY_CLEANUP, &ar->flag) ||
(ar->state == ATH6KL_STATE_RECOVERY))
return;
if (ar->fw_recovery.hb_pending)
ar->fw_recovery.hb_misscnt++;
else
ar->fw_recovery.hb_misscnt = 0;
if (ar->fw_recovery.hb_misscnt > ATH6KL_HB_RESP_MISS_THRES) {
ar->fw_recovery.hb_misscnt = 0;
ar->fw_recovery.seq_num = 0;
ar->fw_recovery.hb_pending = false;
ath6kl_recovery_err_notify(ar, ATH6KL_FW_HB_RESP_FAILURE);
return;
}
ar->fw_recovery.seq_num++;
ar->fw_recovery.hb_pending = true;
err = ath6kl_wmi_get_challenge_resp_cmd(ar->wmi,
ar->fw_recovery.seq_num, 0);
if (err)
ath6kl_warn("Failed to send hb challenge request, err:%d\n",
err);
mod_timer(&ar->fw_recovery.hb_timer, jiffies +
msecs_to_jiffies(ar->fw_recovery.hb_poll));
}
void ath6kl_recovery_init(struct ath6kl *ar)
{
struct ath6kl_fw_recovery *recovery = &ar->fw_recovery;
clear_bit(RECOVERY_CLEANUP, &ar->flag);
INIT_WORK(&recovery->recovery_work, ath6kl_recovery_work);
recovery->seq_num = 0;
recovery->hb_misscnt = 0;
ar->fw_recovery.hb_pending = false;
ar->fw_recovery.hb_timer.function = ath6kl_recovery_hb_timer;
ar->fw_recovery.hb_timer.data = (unsigned long) ar;
init_timer_deferrable(&ar->fw_recovery.hb_timer);
if (ar->fw_recovery.hb_poll)
mod_timer(&ar->fw_recovery.hb_timer, jiffies +
msecs_to_jiffies(ar->fw_recovery.hb_poll));
}
void ath6kl_recovery_cleanup(struct ath6kl *ar)
{
if (!ar->fw_recovery.enable)
return;
set_bit(RECOVERY_CLEANUP, &ar->flag);
del_timer_sync(&ar->fw_recovery.hb_timer);
cancel_work_sync(&ar->fw_recovery.recovery_work);
}
void ath6kl_recovery_suspend(struct ath6kl *ar)
{
if (!ar->fw_recovery.enable)
return;
ath6kl_recovery_cleanup(ar);
if (!ar->fw_recovery.err_reason)
return;
/* Process pending fw error detection */
ar->fw_recovery.err_reason = 0;
WARN_ON(ar->state != ATH6KL_STATE_ON);
ar->state = ATH6KL_STATE_RECOVERY;
ath6kl_init_hw_restart(ar);
ar->state = ATH6KL_STATE_ON;
}
void ath6kl_recovery_resume(struct ath6kl *ar)
{
if (!ar->fw_recovery.enable)
return;
clear_bit(RECOVERY_CLEANUP, &ar->flag);
if (!ar->fw_recovery.hb_poll)
return;
ar->fw_recovery.hb_pending = false;
ar->fw_recovery.seq_num = 0;
ar->fw_recovery.hb_misscnt = 0;
mod_timer(&ar->fw_recovery.hb_timer,
jiffies + msecs_to_jiffies(ar->fw_recovery.hb_poll));
}
...@@ -709,7 +709,7 @@ static int ath6kl_sdio_enable_scatter(struct ath6kl *ar) ...@@ -709,7 +709,7 @@ static int ath6kl_sdio_enable_scatter(struct ath6kl *ar)
{ {
struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
struct htc_target *target = ar->htc_target; struct htc_target *target = ar->htc_target;
int ret; int ret = 0;
bool virt_scat = false; bool virt_scat = false;
if (ar_sdio->scatter_enabled) if (ar_sdio->scatter_enabled)
...@@ -844,22 +844,6 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) ...@@ -844,22 +844,6 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
bool try_deepsleep = false; bool try_deepsleep = false;
int ret; int ret;
if (ar->state == ATH6KL_STATE_SCHED_SCAN) {
ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sched scan is in progress\n");
ret = ath6kl_set_sdio_pm_caps(ar);
if (ret)
goto cut_pwr;
ret = ath6kl_cfg80211_suspend(ar,
ATH6KL_CFG_SUSPEND_SCHED_SCAN,
NULL);
if (ret)
goto cut_pwr;
return 0;
}
if (ar->suspend_mode == WLAN_POWER_STATE_WOW || if (ar->suspend_mode == WLAN_POWER_STATE_WOW ||
(!ar->suspend_mode && wow)) { (!ar->suspend_mode && wow)) {
...@@ -942,14 +926,14 @@ static int ath6kl_sdio_resume(struct ath6kl *ar) ...@@ -942,14 +926,14 @@ static int ath6kl_sdio_resume(struct ath6kl *ar)
case ATH6KL_STATE_WOW: case ATH6KL_STATE_WOW:
break; break;
case ATH6KL_STATE_SCHED_SCAN:
break;
case ATH6KL_STATE_SUSPENDING: case ATH6KL_STATE_SUSPENDING:
break; break;
case ATH6KL_STATE_RESUMING: case ATH6KL_STATE_RESUMING:
break; break;
case ATH6KL_STATE_RECOVERY:
break;
} }
ath6kl_cfg80211_resume(ar); ath6kl_cfg80211_resume(ar);
...@@ -1462,3 +1446,6 @@ MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE); ...@@ -1462,3 +1446,6 @@ MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_2_FW_DIR "/" AR6004_HW_1_2_FIRMWARE_FILE); MODULE_FIRMWARE(AR6004_HW_1_2_FW_DIR "/" AR6004_HW_1_2_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_3_FW_DIR "/" AR6004_HW_1_3_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6004_HW_1_3_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE);
...@@ -288,8 +288,16 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb, ...@@ -288,8 +288,16 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb,
int status = 0; int status = 0;
struct ath6kl_cookie *cookie = NULL; struct ath6kl_cookie *cookie = NULL;
if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW)) if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW)) {
dev_kfree_skb(skb);
return -EACCES; return -EACCES;
}
if (WARN_ON_ONCE(eid == ENDPOINT_UNUSED ||
eid >= ENDPOINT_MAX)) {
status = -EINVAL;
goto fail_ctrl_tx;
}
spin_lock_bh(&ar->lock); spin_lock_bh(&ar->lock);
...@@ -591,6 +599,7 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, ...@@ -591,6 +599,7 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
*/ */
set_bit(WMI_CTRL_EP_FULL, &ar->flag); set_bit(WMI_CTRL_EP_FULL, &ar->flag);
ath6kl_err("wmi ctrl ep is full\n"); ath6kl_err("wmi ctrl ep is full\n");
ath6kl_recovery_err_notify(ar, ATH6KL_FW_EP_FULL);
return action; return action;
} }
...@@ -695,22 +704,31 @@ void ath6kl_tx_complete(struct htc_target *target, ...@@ -695,22 +704,31 @@ void ath6kl_tx_complete(struct htc_target *target,
list); list);
list_del(&packet->list); list_del(&packet->list);
if (WARN_ON_ONCE(packet->endpoint == ENDPOINT_UNUSED ||
packet->endpoint >= ENDPOINT_MAX))
continue;
ath6kl_cookie = (struct ath6kl_cookie *)packet->pkt_cntxt; ath6kl_cookie = (struct ath6kl_cookie *)packet->pkt_cntxt;
if (!ath6kl_cookie) if (WARN_ON_ONCE(!ath6kl_cookie))
goto fatal; continue;
status = packet->status; status = packet->status;
skb = ath6kl_cookie->skb; skb = ath6kl_cookie->skb;
eid = packet->endpoint; eid = packet->endpoint;
map_no = ath6kl_cookie->map_no; map_no = ath6kl_cookie->map_no;
if (!skb || !skb->data) if (WARN_ON_ONCE(!skb || !skb->data)) {
goto fatal; dev_kfree_skb(skb);
ath6kl_free_cookie(ar, ath6kl_cookie);
continue;
}
__skb_queue_tail(&skb_queue, skb); __skb_queue_tail(&skb_queue, skb);
if (!status && (packet->act_len != skb->len)) if (WARN_ON_ONCE(!status && (packet->act_len != skb->len))) {
goto fatal; ath6kl_free_cookie(ar, ath6kl_cookie);
continue;
}
ar->tx_pending[eid]--; ar->tx_pending[eid]--;
...@@ -792,11 +810,6 @@ void ath6kl_tx_complete(struct htc_target *target, ...@@ -792,11 +810,6 @@ void ath6kl_tx_complete(struct htc_target *target,
wake_up(&ar->event_wq); wake_up(&ar->event_wq);
return; return;
fatal:
WARN_ON(1);
spin_unlock_bh(&ar->lock);
return;
} }
void ath6kl_tx_data_cleanup(struct ath6kl *ar) void ath6kl_tx_data_cleanup(struct ath6kl *ar)
...@@ -885,8 +898,11 @@ void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint) ...@@ -885,8 +898,11 @@ void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint)
break; break;
packet = (struct htc_packet *) skb->head; packet = (struct htc_packet *) skb->head;
if (!IS_ALIGNED((unsigned long) skb->data, 4)) if (!IS_ALIGNED((unsigned long) skb->data, 4)) {
size_t len = skb_headlen(skb);
skb->data = PTR_ALIGN(skb->data - 4, 4); skb->data = PTR_ALIGN(skb->data - 4, 4);
skb_set_tail_pointer(skb, len);
}
set_htc_rxpkt_info(packet, skb, skb->data, set_htc_rxpkt_info(packet, skb, skb->data,
ATH6KL_BUFFER_SIZE, endpoint); ATH6KL_BUFFER_SIZE, endpoint);
packet->skb = skb; packet->skb = skb;
...@@ -908,8 +924,11 @@ void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count) ...@@ -908,8 +924,11 @@ void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count)
return; return;
packet = (struct htc_packet *) skb->head; packet = (struct htc_packet *) skb->head;
if (!IS_ALIGNED((unsigned long) skb->data, 4)) if (!IS_ALIGNED((unsigned long) skb->data, 4)) {
size_t len = skb_headlen(skb);
skb->data = PTR_ALIGN(skb->data - 4, 4); skb->data = PTR_ALIGN(skb->data - 4, 4);
skb_set_tail_pointer(skb, len);
}
set_htc_rxpkt_info(packet, skb, skb->data, set_htc_rxpkt_info(packet, skb, skb->data,
ATH6KL_AMSDU_BUFFER_SIZE, 0); ATH6KL_AMSDU_BUFFER_SIZE, 0);
packet->skb = skb; packet->skb = skb;
......
...@@ -185,9 +185,10 @@ static int ath6kl_usb_alloc_pipe_resources(struct ath6kl_usb_pipe *pipe, ...@@ -185,9 +185,10 @@ static int ath6kl_usb_alloc_pipe_resources(struct ath6kl_usb_pipe *pipe,
for (i = 0; i < urb_cnt; i++) { for (i = 0; i < urb_cnt; i++) {
urb_context = kzalloc(sizeof(struct ath6kl_urb_context), urb_context = kzalloc(sizeof(struct ath6kl_urb_context),
GFP_KERNEL); GFP_KERNEL);
if (urb_context == NULL) if (urb_context == NULL) {
/* FIXME: set status to -ENOMEM */ status = -ENOMEM;
break; goto fail_alloc_pipe_resources;
}
urb_context->pipe = pipe; urb_context->pipe = pipe;
...@@ -204,6 +205,7 @@ static int ath6kl_usb_alloc_pipe_resources(struct ath6kl_usb_pipe *pipe, ...@@ -204,6 +205,7 @@ static int ath6kl_usb_alloc_pipe_resources(struct ath6kl_usb_pipe *pipe,
pipe->logical_pipe_num, pipe->usb_pipe_handle, pipe->logical_pipe_num, pipe->usb_pipe_handle,
pipe->urb_alloc); pipe->urb_alloc);
fail_alloc_pipe_resources:
return status; return status;
} }
...@@ -803,7 +805,11 @@ static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id, ...@@ -803,7 +805,11 @@ static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id,
*dl_pipe = ATH6KL_USB_PIPE_RX_DATA; *dl_pipe = ATH6KL_USB_PIPE_RX_DATA;
break; break;
case WMI_DATA_VI_SVC: case WMI_DATA_VI_SVC:
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP;
if (ar->hw.flags & ATH6KL_HW_MAP_LP_ENDPOINT)
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP;
else
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP;
/* /*
* Disable rxdata2 directly, it will be enabled * Disable rxdata2 directly, it will be enabled
* if FW enable rxdata2 * if FW enable rxdata2
...@@ -811,7 +817,11 @@ static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id, ...@@ -811,7 +817,11 @@ static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id,
*dl_pipe = ATH6KL_USB_PIPE_RX_DATA; *dl_pipe = ATH6KL_USB_PIPE_RX_DATA;
break; break;
case WMI_DATA_VO_SVC: case WMI_DATA_VO_SVC:
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_HP;
if (ar->hw.flags & ATH6KL_HW_MAP_LP_ENDPOINT)
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP;
else
*ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP;
/* /*
* Disable rxdata2 directly, it will be enabled * Disable rxdata2 directly, it will be enabled
* if FW enable rxdata2 * if FW enable rxdata2
...@@ -1196,7 +1206,14 @@ static struct usb_driver ath6kl_usb_driver = { ...@@ -1196,7 +1206,14 @@ static struct usb_driver ath6kl_usb_driver = {
static int ath6kl_usb_init(void) static int ath6kl_usb_init(void)
{ {
usb_register(&ath6kl_usb_driver); int ret;
ret = usb_register(&ath6kl_usb_driver);
if (ret) {
ath6kl_err("usb registration failed: %d\n", ret);
return ret;
}
return 0; return 0;
} }
...@@ -1220,3 +1237,6 @@ MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE); ...@@ -1220,3 +1237,6 @@ MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_2_FIRMWARE_FILE); MODULE_FIRMWARE(AR6004_HW_1_2_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_3_FW_DIR "/" AR6004_HW_1_3_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6004_HW_1_3_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE);
This diff is collapsed.
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
#define A_BAND_24GHZ 0 #define A_BAND_24GHZ 0
#define A_BAND_5GHZ 1 #define A_BAND_5GHZ 1
#define A_NUM_BANDS 2 #define ATH6KL_NUM_BANDS 2
/* in ms */ /* in ms */
#define WMI_IMPLICIT_PSTREAM_INACTIVITY_INT 5000 #define WMI_IMPLICIT_PSTREAM_INACTIVITY_INT 5000
...@@ -628,6 +628,20 @@ enum wmi_cmd_id { ...@@ -628,6 +628,20 @@ enum wmi_cmd_id {
WMI_SET_MCASTRATE, WMI_SET_MCASTRATE,
WMI_STA_BMISS_ENHANCE_CMDID, WMI_STA_BMISS_ENHANCE_CMDID,
WMI_SET_REGDOMAIN_CMDID,
WMI_SET_RSSI_FILTER_CMDID,
WMI_SET_KEEP_ALIVE_EXT,
WMI_VOICE_DETECTION_ENABLE_CMDID,
WMI_SET_TXE_NOTIFY_CMDID,
WMI_SET_RECOVERY_TEST_PARAMETER_CMDID, /*0xf094*/
WMI_ENABLE_SCHED_SCAN_CMDID,
}; };
enum wmi_mgmt_frame_type { enum wmi_mgmt_frame_type {
...@@ -843,7 +857,7 @@ struct wmi_begin_scan_cmd { ...@@ -843,7 +857,7 @@ struct wmi_begin_scan_cmd {
u8 scan_type; u8 scan_type;
/* Supported rates to advertise in the probe request frames */ /* Supported rates to advertise in the probe request frames */
struct wmi_supp_rates supp_rates[IEEE80211_NUM_BANDS]; struct wmi_supp_rates supp_rates[ATH6KL_NUM_BANDS];
/* how many channels follow */ /* how many channels follow */
u8 num_ch; u8 num_ch;
...@@ -941,6 +955,11 @@ struct wmi_scan_params_cmd { ...@@ -941,6 +955,11 @@ struct wmi_scan_params_cmd {
__le32 max_dfsch_act_time; __le32 max_dfsch_act_time;
} __packed; } __packed;
/* WMI_ENABLE_SCHED_SCAN_CMDID */
struct wmi_enable_sched_scan_cmd {
u8 enable;
} __packed;
/* WMI_SET_BSS_FILTER_CMDID */ /* WMI_SET_BSS_FILTER_CMDID */
enum wmi_bss_filter { enum wmi_bss_filter {
/* no beacons forwarded */ /* no beacons forwarded */
...@@ -1032,6 +1051,11 @@ struct wmi_sta_bmiss_enhance_cmd { ...@@ -1032,6 +1051,11 @@ struct wmi_sta_bmiss_enhance_cmd {
u8 enable; u8 enable;
} __packed; } __packed;
struct wmi_set_regdomain_cmd {
u8 length;
u8 iso_name[2];
} __packed;
/* WMI_SET_POWER_MODE_CMDID */ /* WMI_SET_POWER_MODE_CMDID */
enum wmi_power_mode { enum wmi_power_mode {
REC_POWER = 0x01, REC_POWER = 0x01,
...@@ -1276,6 +1300,11 @@ struct wmi_snr_threshold_params_cmd { ...@@ -1276,6 +1300,11 @@ struct wmi_snr_threshold_params_cmd {
u8 reserved[3]; u8 reserved[3];
} __packed; } __packed;
/* Don't report BSSs with signal (RSSI) below this threshold */
struct wmi_set_rssi_filter_cmd {
s8 rssi;
} __packed;
enum wmi_preamble_policy { enum wmi_preamble_policy {
WMI_IGNORE_BARKER_IN_ERP = 0, WMI_IGNORE_BARKER_IN_ERP = 0,
WMI_FOLLOW_BARKER_IN_ERP, WMI_FOLLOW_BARKER_IN_ERP,
...@@ -1455,6 +1484,20 @@ enum wmi_event_id { ...@@ -1455,6 +1484,20 @@ enum wmi_event_id {
WMI_P2P_CAPABILITIES_EVENTID, WMI_P2P_CAPABILITIES_EVENTID,
WMI_RX_ACTION_EVENTID, WMI_RX_ACTION_EVENTID,
WMI_P2P_INFO_EVENTID, WMI_P2P_INFO_EVENTID,
/* WPS Events */
WMI_WPS_GET_STATUS_EVENTID,
WMI_WPS_PROFILE_EVENTID,
/* more P2P events */
WMI_NOA_INFO_EVENTID,
WMI_OPPPS_INFO_EVENTID,
WMI_PORT_STATUS_EVENTID,
/* 802.11w */
WMI_GET_RSN_CAP_EVENTID,
WMI_TXE_NOTIFY_EVENTID,
}; };
struct wmi_ready_event_2 { struct wmi_ready_event_2 {
...@@ -1749,6 +1792,9 @@ struct rx_stats { ...@@ -1749,6 +1792,9 @@ struct rx_stats {
a_sle32 ucast_rate; a_sle32 ucast_rate;
} __packed; } __packed;
#define RATE_INDEX_WITHOUT_SGI_MASK 0x7f
#define RATE_INDEX_MSB 0x80
struct tkip_ccmp_stats { struct tkip_ccmp_stats {
__le32 tkip_local_mic_fail; __le32 tkip_local_mic_fail;
__le32 tkip_cnter_measures_invoked; __le32 tkip_cnter_measures_invoked;
...@@ -2019,7 +2065,6 @@ struct wmi_set_ie_cmd { ...@@ -2019,7 +2065,6 @@ struct wmi_set_ie_cmd {
#define WOW_MAX_FILTERS_PER_LIST 4 #define WOW_MAX_FILTERS_PER_LIST 4
#define WOW_PATTERN_SIZE 64 #define WOW_PATTERN_SIZE 64
#define WOW_MASK_SIZE 64
#define MAC_MAX_FILTERS_PER_LIST 4 #define MAC_MAX_FILTERS_PER_LIST 4
...@@ -2028,7 +2073,7 @@ struct wow_filter { ...@@ -2028,7 +2073,7 @@ struct wow_filter {
u8 wow_filter_id; u8 wow_filter_id;
u8 wow_filter_size; u8 wow_filter_size;
u8 wow_filter_offset; u8 wow_filter_offset;
u8 wow_filter_mask[WOW_MASK_SIZE]; u8 wow_filter_mask[WOW_PATTERN_SIZE];
u8 wow_filter_pattern[WOW_PATTERN_SIZE]; u8 wow_filter_pattern[WOW_PATTERN_SIZE];
} __packed; } __packed;
...@@ -2087,6 +2132,19 @@ struct wmi_del_wow_pattern_cmd { ...@@ -2087,6 +2132,19 @@ struct wmi_del_wow_pattern_cmd {
__le16 filter_id; __le16 filter_id;
} __packed; } __packed;
/* WMI_SET_TXE_NOTIFY_CMDID */
struct wmi_txe_notify_cmd {
__le32 rate;
__le32 pkts;
__le32 intvl;
} __packed;
/* WMI_TXE_NOTIFY_EVENTID */
struct wmi_txe_notify_event {
__le32 rate;
__le32 pkts;
} __packed;
/* WMI_SET_AKMP_PARAMS_CMD */ /* WMI_SET_AKMP_PARAMS_CMD */
struct wmi_pmkid { struct wmi_pmkid {
...@@ -2505,11 +2563,6 @@ int ath6kl_wmi_connect_cmd(struct wmi *wmi, u8 if_idx, ...@@ -2505,11 +2563,6 @@ int ath6kl_wmi_connect_cmd(struct wmi *wmi, u8 if_idx,
int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 if_idx, u8 *bssid, int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 if_idx, u8 *bssid,
u16 channel); u16 channel);
int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx); int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx);
int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx,
enum wmi_scan_type scan_type,
u32 force_fgscan, u32 is_legacy,
u32 home_dwell_time, u32 force_scan_interval,
s8 num_chan, u16 *ch_list);
int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
enum wmi_scan_type scan_type, enum wmi_scan_type scan_type,
...@@ -2517,6 +2570,7 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, ...@@ -2517,6 +2570,7 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
u32 home_dwell_time, u32 force_scan_interval, u32 home_dwell_time, u32 force_scan_interval,
s8 num_chan, u16 *ch_list, u32 no_cck, s8 num_chan, u16 *ch_list, u32 no_cck,
u32 *rates); u32 *rates);
int ath6kl_wmi_enable_sched_scan_cmd(struct wmi *wmi, u8 if_idx, bool enable);
int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u8 if_idx, u16 fg_start_sec, int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u8 if_idx, u16 fg_start_sec,
u16 fg_end_sec, u16 bg_sec, u16 fg_end_sec, u16 bg_sec,
...@@ -2592,6 +2646,7 @@ int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, ...@@ -2592,6 +2646,7 @@ int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
const u8 *mask); const u8 *mask);
int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
u16 list_id, u16 filter_id); u16 list_id, u16 filter_id);
int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi);
int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi); int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi);
int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period); int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period);
int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid); int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid);
...@@ -2600,6 +2655,9 @@ int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on); ...@@ -2600,6 +2655,9 @@ int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on);
int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx,
u8 *filter, bool add_filter); u8 *filter, bool add_filter);
int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enable); int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enable);
int ath6kl_wmi_set_txe_notify(struct wmi *wmi, u8 idx,
u32 rate, u32 pkts, u32 intvl);
int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2);
/* AP mode uAPSD */ /* AP mode uAPSD */
int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable); int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable);
...@@ -2658,6 +2716,8 @@ int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout); ...@@ -2658,6 +2716,8 @@ int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout);
void ath6kl_wmi_sscan_timer(unsigned long ptr); void ath6kl_wmi_sscan_timer(unsigned long ptr);
int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source);
struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx); struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx);
void *ath6kl_wmi_init(struct ath6kl *devt); void *ath6kl_wmi_init(struct ath6kl *devt);
void ath6kl_wmi_shutdown(struct wmi *wmi); void ath6kl_wmi_shutdown(struct wmi *wmi);
......
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